diff --git a/.changes/next-release/feature-fd316552-7161-43bf-aaa5-e1ac1330b939.json b/.changes/next-release/feature-fd316552-7161-43bf-aaa5-e1ac1330b939.json new file mode 100644 index 00000000000..0a086fe911b --- /dev/null +++ b/.changes/next-release/feature-fd316552-7161-43bf-aaa5-e1ac1330b939.json @@ -0,0 +1,4 @@ +{ + "type" : "feature", + "description" : "Loosen inline completion support limitations for YAML/JSON" +} \ No newline at end of file diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/editor/CodeWhispererEditorUtil.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/editor/CodeWhispererEditorUtil.kt index e699e97e856..a2fa515d2fe 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/editor/CodeWhispererEditorUtil.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/editor/CodeWhispererEditorUtil.kt @@ -12,13 +12,14 @@ import com.intellij.openapi.util.TextRange import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.psi.PsiFile import com.intellij.ui.popup.AbstractPopup -import software.aws.toolkits.jetbrains.services.codewhisperer.language.languages.CodeWhispererJson -import software.aws.toolkits.jetbrains.services.codewhisperer.language.languages.CodeWhispererYaml import software.aws.toolkits.jetbrains.services.codewhisperer.language.programmingLanguage import software.aws.toolkits.jetbrains.services.codewhisperer.model.CaretContext import software.aws.toolkits.jetbrains.services.codewhisperer.model.CaretPosition import software.aws.toolkits.jetbrains.services.codewhisperer.model.FileContextInfo import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants +import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.AWSTemplateCaseInsensitiveKeyWordsRegex +import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.AWSTemplateKeyWordsRegex +import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.JsonConfigFileNamingConvention import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants.LEFT_CONTEXT_ON_CURRENT_LINE import java.awt.Point import java.util.Locale @@ -106,16 +107,12 @@ object CodeWhispererEditorUtil { } /** - * Checks if the language is json or yaml and checks if left context contains keywords + * Check if left context contains keywords or file name follow config json file naming pattern */ - fun checkLeftContextKeywordsForJsonAndYaml(leftContext: String, language: String): Boolean = ( - (language == CodeWhispererJson.INSTANCE.languageId) || - (language == CodeWhispererYaml.INSTANCE.languageId) - ) && - ( - (!CodeWhispererConstants.AWSTemplateKeyWordsRegex.containsMatchIn(leftContext)) && - (!CodeWhispererConstants.AWSTemplateCaseInsensitiveKeyWordsRegex.containsMatchIn(leftContext.lowercase(Locale.getDefault()))) - ) + fun isSupportedJsonFormat(fileName: String, leftContext: String): Boolean = + JsonConfigFileNamingConvention.contains(fileName.lowercase()) || + AWSTemplateKeyWordsRegex.containsMatchIn(leftContext) || + AWSTemplateCaseInsensitiveKeyWordsRegex.containsMatchIn(leftContext.lowercase(Locale.getDefault())) /** * Checks if the [otherRange] overlaps this TextRange. Note that the comparison is `<` because the endOffset of TextRange is exclusive. diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererService.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererService.kt index e9d1cf26527..bdfb45cd57c 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererService.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererService.kt @@ -55,10 +55,11 @@ import software.aws.toolkits.jetbrains.core.credentials.pinning.CodeWhispererCon import software.aws.toolkits.jetbrains.services.codewhisperer.credentials.CodeWhispererClientAdaptor import software.aws.toolkits.jetbrains.services.codewhisperer.customization.CodeWhispererModelConfigurator import software.aws.toolkits.jetbrains.services.codewhisperer.editor.CodeWhispererEditorManager -import software.aws.toolkits.jetbrains.services.codewhisperer.editor.CodeWhispererEditorUtil.checkLeftContextKeywordsForJsonAndYaml import software.aws.toolkits.jetbrains.services.codewhisperer.editor.CodeWhispererEditorUtil.getCaretPosition +import software.aws.toolkits.jetbrains.services.codewhisperer.editor.CodeWhispererEditorUtil.isSupportedJsonFormat import software.aws.toolkits.jetbrains.services.codewhisperer.explorer.CodeWhispererExplorerActionManager import software.aws.toolkits.jetbrains.services.codewhisperer.explorer.isCodeWhispererEnabled +import software.aws.toolkits.jetbrains.services.codewhisperer.language.languages.CodeWhispererJson import software.aws.toolkits.jetbrains.services.codewhisperer.model.CaretPosition import software.aws.toolkits.jetbrains.services.codewhisperer.model.DetailContext import software.aws.toolkits.jetbrains.services.codewhisperer.model.FileContextInfo @@ -171,7 +172,13 @@ class CodeWhispererService(private val cs: CoroutineScope) : Disposable { val language = requestContext.fileContextInfo.programmingLanguage val leftContext = requestContext.fileContextInfo.caretContext.leftFileContext - if (!language.isCodeCompletionSupported() || (checkLeftContextKeywordsForJsonAndYaml(leftContext, language.languageId))) { + if (!language.isCodeCompletionSupported() || ( + language is CodeWhispererJson && !isSupportedJsonFormat( + requestContext.fileContextInfo.filename, + leftContext + ) + ) + ) { LOG.debug { "Programming language $language is not supported by CodeWhisperer" } if (triggerTypeInfo.triggerType == CodewhispererTriggerType.OnDemand) { showCodeWhispererInfoHint( diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util/CodeWhispererConstants.kt b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util/CodeWhispererConstants.kt index 0b7259e3f2e..ba1a3ba6851 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util/CodeWhispererConstants.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util/CodeWhispererConstants.kt @@ -36,6 +36,20 @@ object CodeWhispererConstants { val AWSTemplateKeyWordsRegex = Regex("(AWSTemplateFormatVersion|Resources|AWS::|Description)") val AWSTemplateCaseInsensitiveKeyWordsRegex = Regex("(cloudformation|cfn|template|description)") + val JsonConfigFileNamingConvention = setOf( + "app.json", + "appsettings.json", + "bower.json", + "composer.json", + "db.json", + "manifest.json", + "package.json", + "schema.json", + "settings.json", + "tsconfig.json", + "vcpkg.json" + ) + // TODO: this is currently set to 2050 to account for the server side 0.5 TPS and and extra 50 ms buffer to // avoid ThrottlingException as much as possible. const val INVOCATION_INTERVAL: Long = 2050 @@ -131,6 +145,7 @@ object CodeWhispererConstants { } } } + object CrossFile { const val CHUNK_SIZE = 60 const val NUMBER_OF_LINE_IN_CHUNK = 50 @@ -145,7 +160,7 @@ object CodeWhispererConstants { object TryExampleFileContent { private const val AUTO_TRIGGER_CONTENT_JAVA = -"""import java.util.ArrayList; + """import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -167,7 +182,7 @@ public class Main { }""" private const val MANUAL_TRIGGER_CONTENT_JAVA = -"""// TODO: Press either Option + C on MacOS or Alt + C on Windows on a new line. + """// TODO: Press either Option + C on MacOS or Alt + C on Windows on a new line. public class S3Uploader { @@ -178,7 +193,7 @@ public class S3Uploader { }""" private const val UNIT_TEST_CONTENT_JAVA = -"""// TODO: Ask Amazon Q to write unit tests. + """// TODO: Ask Amazon Q to write unit tests. // Write a test case for the sum function. diff --git a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererEditorUtilTest.kt b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererEditorUtilTest.kt index c2098b61329..84332655d74 100644 --- a/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererEditorUtilTest.kt +++ b/plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererEditorUtilTest.kt @@ -11,10 +11,11 @@ import org.assertj.core.api.Assertions.assertThat import org.junit.Before import org.junit.Rule import org.junit.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource import software.aws.toolkits.jetbrains.services.codewhisperer.CodeWhispererTestUtil.leftContext_success_Iac import software.aws.toolkits.jetbrains.services.codewhisperer.CodeWhispererTestUtil.pythonFileName import software.aws.toolkits.jetbrains.services.codewhisperer.CodeWhispererTestUtil.pythonTestLeftContext -import software.aws.toolkits.jetbrains.services.codewhisperer.CodeWhispererTestUtil.yaml_langauge import software.aws.toolkits.jetbrains.services.codewhisperer.editor.CodeWhispererEditorUtil import software.aws.toolkits.jetbrains.services.codewhisperer.language.languages.CodeWhispererPython import software.aws.toolkits.jetbrains.utils.rules.PythonCodeInsightTestFixtureRule @@ -76,12 +77,36 @@ class CodeWhispererEditorUtilTest { assertThat(caretContext.leftContextOnCurrentLine).isEqualTo(pythonTestLeftContext) } - /** - * Test for keyword checks for json and yaml - */ @Test - fun `test for keyword check for json and yaml`() { - val result = CodeWhispererEditorUtil.checkLeftContextKeywordsForJsonAndYaml(leftContext_success_Iac, yaml_langauge) + fun `test for keyword check for json`() { + val result = CodeWhispererEditorUtil.isSupportedJsonFormat("foo.json", leftContext_success_Iac) + assertThat(result).isEqualTo(true) + } + + @ParameterizedTest + @ValueSource( + strings = [ + "app.json", + "appsettings.json", + "bower.json", + "composer.json", + "db.json", + "manifest.json", + "package.json", + "schema.json", + "settings.json", + "tsconfig.json", + "vcpkg.json" + ] + ) + fun `isSupportedJsonFormat should return true by file name`(fileName: String) { + val result = CodeWhispererEditorUtil.isSupportedJsonFormat(fileName, "") + assertThat(result).isEqualTo(true) + } + + @Test + fun `isSupportedJsonFormat should return false due to no match`() { + val result = CodeWhispererEditorUtil.isSupportedJsonFormat("foo.json", "") assertThat(result).isEqualTo(false) } }