diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f4f131f2..c6226702 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,7 +43,7 @@ jobs: workflow: node.js.yml workflow_search: true repo: smallcloudai/refact-chat-js - branch: main + branch: alpha name: refact-chat-js-latest path: ./src/main/resources/webview/dist diff --git a/refact_lsp b/refact_lsp index a6eeb03f..88d050b1 100644 --- a/refact_lsp +++ b/refact_lsp @@ -1 +1 @@ -v0.10.5 \ No newline at end of file +main \ No newline at end of file diff --git a/src/main/kotlin/com/smallcloud/refactai/Initializer.kt b/src/main/kotlin/com/smallcloud/refactai/Initializer.kt index 64620cee..ce32be75 100644 --- a/src/main/kotlin/com/smallcloud/refactai/Initializer.kt +++ b/src/main/kotlin/com/smallcloud/refactai/Initializer.kt @@ -40,44 +40,6 @@ class Initializer : ProjectActivity, Disposable { PluginInstaller.addStateListener(UninstallListener()) UpdateChecker.instance - ApplicationManager.getApplication() - .messageBus - .connect(PluginState.instance) - .subscribe(KeymapManagerListener.TOPIC, object : KeymapManagerListener { - override fun shortcutsChanged( - keymap: Keymap, - actionIds: MutableCollection, - fromSettings: Boolean - ) { - if (Thread.currentThread().stackTrace.count { it.className.startsWith("com.smallcloud.refactai.Initializer") } > 1) { - return - } - for (id in actionIds) { - if (!listOf(IdeActions.ACTION_INSERT_INLINE_COMPLETION, ACTION_ID_).contains(id)) { - continue - } - val shortcuts = keymap.getShortcuts(id) - if (id == IdeActions.ACTION_INSERT_INLINE_COMPLETION) { - keymap.removeAllActionShortcuts(ACTION_ID_) - for (shortcut in shortcuts) { - keymap.addShortcut( - ACTION_ID_, - shortcut - ) - } - } else if (id == ACTION_ID_) { - keymap.removeAllActionShortcuts(IdeActions.ACTION_INSERT_INLINE_COMPLETION) - for (shortcut in shortcuts) { - keymap.addShortcut( - IdeActions.ACTION_INSERT_INLINE_COMPLETION, - shortcut - ) - } - } - } - } - }) - ApplicationManager.getApplication().getService(CloudMessageService::class.java) if (!isJcefCanStart()) { emitInfo(RefactAIBundle.message("notifications.chatCanNotStartWarning"), false) diff --git a/src/main/kotlin/com/smallcloud/refactai/Resources.kt b/src/main/kotlin/com/smallcloud/refactai/Resources.kt index bc23e020..e71a7cda 100644 --- a/src/main/kotlin/com/smallcloud/refactai/Resources.kt +++ b/src/main/kotlin/com/smallcloud/refactai/Resources.kt @@ -65,6 +65,7 @@ object Resources { val defaultCodeCompletionUrlSuffix = URI("v1/code-completion") val cloudUserMessage: URI = defaultCloudUrl.resolve("/v1/user-message") val defaultReportUrlSuffix: URI = URI("v1/telemetry-network") + val defaultChatReportUrlSuffix: URI = URI("v1/telemetry-chat") val defaultSnippetAcceptedUrlSuffix: URI = URI("v1/snippet-accepted") val version: String = getVersion() const val client: String = "jetbrains" diff --git a/src/main/kotlin/com/smallcloud/refactai/code_lens/CodeLensAction.kt b/src/main/kotlin/com/smallcloud/refactai/code_lens/CodeLensAction.kt index 52c58d0a..a4fde2ba 100644 --- a/src/main/kotlin/com/smallcloud/refactai/code_lens/CodeLensAction.kt +++ b/src/main/kotlin/com/smallcloud/refactai/code_lens/CodeLensAction.kt @@ -2,6 +2,7 @@ package com.smallcloud.refactai.code_lens import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.components.service import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.LogicalPosition import com.intellij.openapi.project.DumbAwareAction @@ -9,6 +10,8 @@ import com.intellij.openapi.roots.ProjectRootManager import com.intellij.openapi.wm.ToolWindowManager import com.smallcloud.refactai.Resources import com.smallcloud.refactai.panes.RefactAIToolboxPaneFactory +import com.smallcloud.refactai.statistic.UsageStatistic +import com.smallcloud.refactai.statistic.UsageStats import java.util.concurrent.atomic.AtomicBoolean import kotlin.io.path.relativeTo @@ -50,6 +53,7 @@ class CodeLensAction( chat?.activate { RefactAIToolboxPaneFactory.chat?.requestFocus() RefactAIToolboxPaneFactory.chat?.executeCodeLensCommand(formatMessage(), sendImmediately, openNewTab) + editor.project?.service()?.addChatStatistic(true, UsageStatistic("openChatByCodelens"), "") } // If content is empty, then it's "Open Chat" instruction, selecting range of code in active tab diff --git a/src/main/kotlin/com/smallcloud/refactai/codecompletion/RefactAICompletionProvider.kt b/src/main/kotlin/com/smallcloud/refactai/codecompletion/RefactAICompletionProvider.kt index c9791cdb..6117b8c5 100644 --- a/src/main/kotlin/com/smallcloud/refactai/codecompletion/RefactAICompletionProvider.kt +++ b/src/main/kotlin/com/smallcloud/refactai/codecompletion/RefactAICompletionProvider.kt @@ -18,6 +18,7 @@ import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.editor.Document import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Key import com.intellij.ui.components.JBLabel import com.intellij.util.application import com.intellij.util.ui.JBFont @@ -50,6 +51,9 @@ import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds import com.smallcloud.refactai.io.InferenceGlobalContext.Companion.instance as InferenceGlobalContext +val EditorRefactLastSnippetTelemetryIdKey = Key.create("refact.snippetTelemetryId") +val EditorRefactLastCompletionIsMultilineKey = Key.create("refact.lastCompletion.isMultiline") + private class Default : InlineCompletionSuggestionUpdateManager.Adapter { override fun onDocumentChange( event: InlineCompletionEvent.DocumentChange, @@ -144,17 +148,16 @@ class RefactAICompletionProvider : DebouncedInlineCompletionProvider() { override fun restartOn(event: InlineCompletionEvent): Boolean = false - private fun getActiveFile(document: Document, project: Project?): String? { - val projectPath = project?.basePath ?: return null + private fun getActiveFile(document: Document): String? { val file = FileDocumentManager.getInstance().getFile(document) ?: return null - return Path(file.path).toUri().toString().replace(Path(projectPath).toUri().toString(), "") + return Path(file.path).toString() } private class Context(val request: SMCRequest, val editorState: EditorTextState, val force: Boolean = false) private fun makeContext(request: InlineCompletionRequest): Context? { - val fileName = getActiveFile(request.document, request.editor.project) ?: return null + val fileName = getActiveFile(request.document) ?: return null if (PrivacyService.instance.getPrivacy(FileDocumentManager.getInstance().getFile(request.document)) == Privacy.DISABLED && !InferenceGlobalContext.isSelfHosted ) return null @@ -253,10 +256,11 @@ class RefactAICompletionProvider : DebouncedInlineCompletionProvider() { send(it) delay(2) } + EditorRefactLastSnippetTelemetryIdKey[request.editor] = completion.snippetTelemetryId + EditorRefactLastCompletionIsMultilineKey[request.editor] = completion.multiline } } awaitClose() - }) private fun getSingleLineElements( diff --git a/src/main/kotlin/com/smallcloud/refactai/codecompletion/RefactAIContinuousEvent.kt b/src/main/kotlin/com/smallcloud/refactai/codecompletion/RefactAIContinuousEvent.kt index 00fb7f5d..0adfbe95 100644 --- a/src/main/kotlin/com/smallcloud/refactai/codecompletion/RefactAIContinuousEvent.kt +++ b/src/main/kotlin/com/smallcloud/refactai/codecompletion/RefactAIContinuousEvent.kt @@ -22,17 +22,21 @@ class RefactAIContinuousEvent(val editor: Editor, val offset: Int) : InlineCompl @RequiresBlockingContext private fun getPsiFile(editor: Editor, project: Project): PsiFile? { return runReadAction { - val file = - PsiDocumentManager.getInstance(project).getPsiFile(editor.document) ?: return@runReadAction null - // * [PsiUtilBase] takes into account injected [PsiFile] (like in Jupyter Notebooks) - // * However, it loads a file into the memory, which is expensive - // * Some tests forbid loading a file when tearing down - // * On tearing down, Lookup Cancellation happens, which causes the event - // * Existence of [treeElement] guarantees that it's in the memory - if (file.isLoadedInMemory()) { - PsiUtilBase.getPsiFileInEditor(editor, project) - } else { - file + try { + val file = + PsiDocumentManager.getInstance(project).getPsiFile(editor.document) ?: return@runReadAction null + // * [PsiUtilBase] takes into account injected [PsiFile] (like in Jupyter Notebooks) + // * However, it loads a file into the memory, which is expensive + // * Some tests forbid loading a file when tearing down + // * On tearing down, Lookup Cancellation happens, which causes the event + // * Existence of [treeElement] guarantees that it's in the memory + if (file.isLoadedInMemory()) { + PsiUtilBase.getPsiFileInEditor(editor, project) + } else { + file + } + } catch (e: Exception) { + return@runReadAction null } } } diff --git a/src/main/kotlin/com/smallcloud/refactai/io/InferenceGlobalContext.kt b/src/main/kotlin/com/smallcloud/refactai/io/InferenceGlobalContext.kt index 8a835e99..0973eda7 100644 --- a/src/main/kotlin/com/smallcloud/refactai/io/InferenceGlobalContext.kt +++ b/src/main/kotlin/com/smallcloud/refactai/io/InferenceGlobalContext.kt @@ -126,16 +126,6 @@ class InferenceGlobalContext : Disposable { .astFileLimitChanged(newValue) } - var astLightMode: Boolean - get() = AppSettingsState.astLightMode - set(newValue) { - if (newValue == astLightMode) return - messageBus - .syncPublisher(InferenceGlobalContextChangedNotifier.TOPIC) - .astLightModeChanged(newValue) - } - - var vecdbIsEnabled: Boolean get() = AppSettingsState.vecdbIsEnabled set(newValue) { diff --git a/src/main/kotlin/com/smallcloud/refactai/io/InferenceGlobalContextChangedNotifier.kt b/src/main/kotlin/com/smallcloud/refactai/io/InferenceGlobalContextChangedNotifier.kt index 18b91eb8..ca0a5a7d 100644 --- a/src/main/kotlin/com/smallcloud/refactai/io/InferenceGlobalContextChangedNotifier.kt +++ b/src/main/kotlin/com/smallcloud/refactai/io/InferenceGlobalContextChangedNotifier.kt @@ -15,7 +15,6 @@ interface InferenceGlobalContextChangedNotifier { fun deploymentModeChanged(newMode: DeploymentMode) {} fun astFlagChanged(newValue: Boolean) {} fun astFileLimitChanged(newValue: Int) {} - fun astLightModeChanged(newValue: Boolean) {} fun vecdbFlagChanged(newValue: Boolean) {} fun vecdbFileLimitChanged(newValue: Int) {} fun xDebugLSPPortChanged(newPort: Int?) {} diff --git a/src/main/kotlin/com/smallcloud/refactai/listeners/AcceptAction.kt b/src/main/kotlin/com/smallcloud/refactai/listeners/AcceptAction.kt index 7956f5a3..c6259b8a 100644 --- a/src/main/kotlin/com/smallcloud/refactai/listeners/AcceptAction.kt +++ b/src/main/kotlin/com/smallcloud/refactai/listeners/AcceptAction.kt @@ -5,30 +5,39 @@ import com.intellij.codeInsight.hint.HintManagerImpl.ActionToIgnore import com.intellij.codeInsight.inline.completion.InlineCompletion import com.intellij.codeInsight.inline.completion.session.InlineCompletionContext import com.intellij.openapi.actionSystem.DataContext +import com.intellij.openapi.components.service import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.editor.Caret import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.actionSystem.EditorAction import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler import com.smallcloud.refactai.Resources +import com.smallcloud.refactai.codecompletion.EditorRefactLastCompletionIsMultilineKey +import com.smallcloud.refactai.codecompletion.EditorRefactLastSnippetTelemetryIdKey import com.smallcloud.refactai.codecompletion.InlineCompletionGrayTextElementCustom import com.smallcloud.refactai.modes.ModeProvider +import com.smallcloud.refactai.statistic.UsageStats const val ACTION_ID_ = "TabPressedAction" -class TabPressedAction : EditorAction(InlineCompletionHandler()), ActionToIgnore { +class TabPressedAction : EditorAction(InsertInlineCompletionHandler()), ActionToIgnore { val ACTION_ID = ACTION_ID_ init { this.templatePresentation.icon = Resources.Icons.LOGO_RED_16x16 } - class InlineCompletionHandler : EditorWriteActionHandler() { + class InsertInlineCompletionHandler : EditorWriteActionHandler() { override fun executeWriteAction(editor: Editor, caret: Caret?, dataContext: DataContext) { Logger.getInstance("RefactTabPressedAction").debug("executeWriteAction") val provider = ModeProvider.getOrCreateModeProvider(editor) if (provider.isInCompletionMode()) { InlineCompletion.getHandlerOrNull(editor)?.insert() + EditorRefactLastSnippetTelemetryIdKey[editor]?.also { + editor.project?.service()?.snippetAccepted(it) + EditorRefactLastSnippetTelemetryIdKey[editor] = null + EditorRefactLastCompletionIsMultilineKey[editor] = null + } } else { provider.onTabPressed(editor, caret, dataContext) } @@ -42,10 +51,12 @@ class TabPressedAction : EditorAction(InlineCompletionHandler()), ActionToIgnore val provider = ModeProvider.getOrCreateModeProvider(editor) if (provider.isInCompletionMode()) { val ctx = InlineCompletionContext.getOrNull(editor) ?: return false - if (ctx.state.elements.size != 1) return false + if (ctx.state.elements.isEmpty()) return false val elem = ctx.state.elements.first() - if (elem !is InlineCompletionGrayTextElementCustom.Presentable) return false - return elem.delta == caret.logicalPosition.column + val isMultiline = EditorRefactLastCompletionIsMultilineKey[editor] + if (isMultiline && elem is InlineCompletionGrayTextElementCustom.Presentable) + return elem.delta == caret.logicalPosition.column + return true } else { return ModeProvider.getOrCreateModeProvider(editor).modeInActiveState() } diff --git a/src/main/kotlin/com/smallcloud/refactai/listeners/AcceptActionPromoter.kt b/src/main/kotlin/com/smallcloud/refactai/listeners/AcceptActionPromoter.kt index f525988d..ffa46641 100644 --- a/src/main/kotlin/com/smallcloud/refactai/listeners/AcceptActionPromoter.kt +++ b/src/main/kotlin/com/smallcloud/refactai/listeners/AcceptActionPromoter.kt @@ -1,5 +1,6 @@ package com.smallcloud.refactai.listeners +import com.intellij.codeInsight.inline.completion.session.InlineCompletionContext import com.intellij.openapi.actionSystem.ActionPromoter import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.CommonDataKeys @@ -10,9 +11,12 @@ class AcceptActionsPromoter : ActionPromoter { private fun getEditor(dataContext: DataContext): Editor? { return CommonDataKeys.EDITOR.getData(dataContext) } - override fun promote(actions: MutableList, context: DataContext): MutableList { - if (getEditor(context) == null) - return actions.toMutableList() - return actions.filterIsInstance().toMutableList() + override fun promote(actions: MutableList, context: DataContext): List { + val editor = getEditor(context) ?: return emptyList() + if (InlineCompletionContext.getOrNull(editor) == null) { + return emptyList() + } + actions.filterIsInstance().takeIf { it.isNotEmpty() }?.let { return it } + return emptyList() } } \ No newline at end of file diff --git a/src/main/kotlin/com/smallcloud/refactai/listeners/GenerateGitCommitMessageAction.kt b/src/main/kotlin/com/smallcloud/refactai/listeners/GenerateGitCommitMessageAction.kt index 33e51cdb..140ea980 100644 --- a/src/main/kotlin/com/smallcloud/refactai/listeners/GenerateGitCommitMessageAction.kt +++ b/src/main/kotlin/com/smallcloud/refactai/listeners/GenerateGitCommitMessageAction.kt @@ -37,7 +37,7 @@ class GenerateGitCommitMessageAction : AnAction( val lspService = event.project?.service() ?: return@invokeLater - val isEnabled = lspService.isWorking && (commitWorkflowUi.getIncludedChanges().isNotEmpty() && commitWorkflowUi.getIncludedUnversionedFiles().isNotEmpty()) + val isEnabled = lspService.isWorking && (commitWorkflowUi.getIncludedChanges().isNotEmpty() || commitWorkflowUi.getIncludedUnversionedFiles().isNotEmpty()) event.presentation.isEnabled = isEnabled event.presentation.text = if (lspService.isWorking) { @@ -54,7 +54,6 @@ class GenerateGitCommitMessageAction : AnAction( return } - val gitDiff = getDiff(event, project) ?: return val commitWorkflowUi = event.getData(VcsDataKeys.COMMIT_WORKFLOW_UI) if (commitWorkflowUi != null) { @@ -87,7 +86,6 @@ class GenerateGitCommitMessageAction : AnAction( try { val includedChanges = commitWorkflowUi.getIncludedChanges() - commitWorkflowUi.getIncludedUnversionedFiles() val filePatches = IdeaTextPatchBuilder.buildPatch( project, includedChanges, projectFileVcsRoot.toNioPath(), false, true ) diff --git a/src/main/kotlin/com/smallcloud/refactai/lsp/LSPConfig.kt b/src/main/kotlin/com/smallcloud/refactai/lsp/LSPConfig.kt index 9adec101..aed2bacb 100644 --- a/src/main/kotlin/com/smallcloud/refactai/lsp/LSPConfig.kt +++ b/src/main/kotlin/com/smallcloud/refactai/lsp/LSPConfig.kt @@ -11,7 +11,6 @@ data class LSPConfig( var deployment: DeploymentMode = DeploymentMode.CLOUD, var ast: Boolean = true, var astFileLimit: Int? = null, - var astLightMode: Boolean = false, var vecdb: Boolean = true, var vecdbFileLimit: Int? = null, var insecureSSL: Boolean = false, @@ -44,9 +43,6 @@ data class LSPConfig( params.add("--ast-max-files") params.add("$astFileLimit") } - if (ast && astLightMode) { - params.add("--ast-light-mode") - } if (vecdb) { params.add("--vecdb") } @@ -72,7 +68,6 @@ data class LSPConfig( if (useTelemetry != other.useTelemetry) return false if (deployment != other.deployment) return false if (ast != other.ast) return false - if (astLightMode != other.astLightMode) return false if (vecdb != other.vecdb) return false if (astFileLimit != other.astFileLimit) return false if (vecdbFileLimit != other.vecdbFileLimit) return false diff --git a/src/main/kotlin/com/smallcloud/refactai/lsp/LSPProcessHolder.kt b/src/main/kotlin/com/smallcloud/refactai/lsp/LSPProcessHolder.kt index 91925eb7..3b0ed00a 100644 --- a/src/main/kotlin/com/smallcloud/refactai/lsp/LSPProcessHolder.kt +++ b/src/main/kotlin/com/smallcloud/refactai/lsp/LSPProcessHolder.kt @@ -118,12 +118,6 @@ class LSPProcessHolder(val project: Project) : Disposable { } } - override fun astLightModeChanged(newValue: Boolean) { - AppExecutorUtil.getAppScheduledExecutorService().submit { - settingsChanged() - } - } - override fun vecdbFlagChanged(newValue: Boolean) { AppExecutorUtil.getAppScheduledExecutorService().submit { settingsChanged() @@ -192,7 +186,6 @@ class LSPProcessHolder(val project: Project) : Disposable { deployment = InferenceGlobalContext.deploymentMode, ast = InferenceGlobalContext.astIsEnabled, astFileLimit = InferenceGlobalContext.astFileLimit, - astLightMode = InferenceGlobalContext.astLightMode, vecdb = InferenceGlobalContext.vecdbIsEnabled, vecdbFileLimit = InferenceGlobalContext.vecdbFileLimit, insecureSSL = InferenceGlobalContext.insecureSSL, diff --git a/src/main/kotlin/com/smallcloud/refactai/panes/sharedchat/ChatPaneInvokeAction.kt b/src/main/kotlin/com/smallcloud/refactai/panes/sharedchat/ChatPaneInvokeAction.kt index a9799221..860dac4b 100644 --- a/src/main/kotlin/com/smallcloud/refactai/panes/sharedchat/ChatPaneInvokeAction.kt +++ b/src/main/kotlin/com/smallcloud/refactai/panes/sharedchat/ChatPaneInvokeAction.kt @@ -2,9 +2,12 @@ package com.smallcloud.refactai.panes.sharedchat import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.components.service import com.intellij.openapi.wm.ToolWindowManager import com.smallcloud.refactai.Resources import com.smallcloud.refactai.panes.RefactAIToolboxPaneFactory +import com.smallcloud.refactai.statistic.UsageStatistic +import com.smallcloud.refactai.statistic.UsageStats import com.smallcloud.refactai.utils.getLastUsedProject class ChatPaneInvokeAction: AnAction(Resources.Icons.LOGO_RED_16x16) { @@ -14,8 +17,9 @@ class ChatPaneInvokeAction: AnAction(Resources.Icons.LOGO_RED_16x16) { fun actionPerformed() { val chat = ToolWindowManager.getInstance(getLastUsedProject()).getToolWindow("Refact") - chat?.activate{ + chat?.activate { RefactAIToolboxPaneFactory.focusChat() + getLastUsedProject().service().addChatStatistic(true, UsageStatistic("openChatByShortcut"), "") } } } \ No newline at end of file diff --git a/src/main/kotlin/com/smallcloud/refactai/panes/sharedchat/SharedChatPane.kt b/src/main/kotlin/com/smallcloud/refactai/panes/sharedchat/SharedChatPane.kt index 5b648fc0..5a796dcf 100644 --- a/src/main/kotlin/com/smallcloud/refactai/panes/sharedchat/SharedChatPane.kt +++ b/src/main/kotlin/com/smallcloud/refactai/panes/sharedchat/SharedChatPane.kt @@ -509,7 +509,7 @@ class SharedChatPane(val project: Project) : JPanel(), Disposable { } val webView by lazy { - System.setProperty("ide.browser.jcef.log.level", "info") +// System.setProperty("ide.browser.jcef.log.level", "info") browser.webView } diff --git a/src/main/kotlin/com/smallcloud/refactai/settings/AppSettingsComponent.kt b/src/main/kotlin/com/smallcloud/refactai/settings/AppSettingsComponent.kt index f5e02769..7edd84f4 100644 --- a/src/main/kotlin/com/smallcloud/refactai/settings/AppSettingsComponent.kt +++ b/src/main/kotlin/com/smallcloud/refactai/settings/AppSettingsComponent.kt @@ -48,7 +48,6 @@ class AppSettingsComponent { private val myContrastUrlText = JBTextField() private val myModelText = JBTextField() private val myAstFileLimitText = JBTextField() - private val myAstLightMode = JCheckBox(RefactAIBundle.message("advancedSettings.useASTLightMode")) private val myVecdbFileLimitText = JBTextField() private val insecureSSLCheckBox = JCheckBox(RefactAIBundle.message("advancedSettings.insecureSSL")) private val telemetrySnippetCheckBox = JCheckBox(RefactAIBundle.message("advancedSettings.telemetryCodeSnippets")) @@ -175,15 +174,6 @@ class AppSettingsComponent { UIUtil.ComponentStyle.SMALL, UIUtil.FontColor.BRIGHTER ), 0 ) - addComponent(myAstLightMode, UIUtil.LARGE_VGAP) - addComponent( - JBLabel( - RefactAIBundle.message("advancedSettings.useASTLightModeDescription"), - UIUtil.ComponentStyle.SMALL, UIUtil.FontColor.BRIGHTER - ).apply { - setCopyable(true) - }, 0 - ) addComponent(vecdbCheckbox, UIUtil.LARGE_VGAP) addComponent( @@ -257,11 +247,6 @@ class AppSettingsComponent { set(newVal) { myAstFileLimitText.text = newVal.toString() } - var astLightMode: Boolean - get() = myAstLightMode.isSelected - set(newVal) { - myAstLightMode.isSelected = newVal - } var vecdbIsEnabled: Boolean get() = vecdbCheckbox.isSelected set(newVal) { diff --git a/src/main/kotlin/com/smallcloud/refactai/settings/AppSettingsConfigurable.kt b/src/main/kotlin/com/smallcloud/refactai/settings/AppSettingsConfigurable.kt index 9a5c28fd..46672d64 100644 --- a/src/main/kotlin/com/smallcloud/refactai/settings/AppSettingsConfigurable.kt +++ b/src/main/kotlin/com/smallcloud/refactai/settings/AppSettingsConfigurable.kt @@ -61,7 +61,6 @@ class AppSettingsConfigurable : Configurable { modified = modified || mySettingsComponent!!.astIsEnabled != InferenceGlobalContext.astIsEnabled modified = modified || mySettingsComponent!!.astFileLimit != InferenceGlobalContext.astFileLimit - modified = modified || mySettingsComponent!!.astLightMode != InferenceGlobalContext.astLightMode modified = modified || mySettingsComponent!!.vecdbIsEnabled != InferenceGlobalContext.vecdbIsEnabled modified = modified || mySettingsComponent!!.vecdbFileLimit != InferenceGlobalContext.vecdbFileLimit @@ -83,7 +82,6 @@ class AppSettingsConfigurable : Configurable { InferenceGlobalContext.xDebugLSPPort = mySettingsComponent!!.xDebugLSPPort InferenceGlobalContext.astIsEnabled = mySettingsComponent!!.astIsEnabled InferenceGlobalContext.astFileLimit = mySettingsComponent!!.astFileLimit - InferenceGlobalContext.astLightMode = mySettingsComponent!!.astLightMode InferenceGlobalContext.vecdbIsEnabled = mySettingsComponent!!.vecdbIsEnabled InferenceGlobalContext.vecdbFileLimit = mySettingsComponent!!.vecdbFileLimit InferenceGlobalContext.insecureSSL = mySettingsComponent!!.insecureSSL @@ -101,7 +99,6 @@ class AppSettingsConfigurable : Configurable { mySettingsComponent!!.xDebugLSPPort = InferenceGlobalContext.xDebugLSPPort mySettingsComponent!!.astIsEnabled = InferenceGlobalContext.astIsEnabled mySettingsComponent!!.astFileLimit = InferenceGlobalContext.astFileLimit - mySettingsComponent!!.astLightMode = InferenceGlobalContext.astLightMode mySettingsComponent!!.vecdbIsEnabled = InferenceGlobalContext.vecdbIsEnabled mySettingsComponent!!.vecdbFileLimit = InferenceGlobalContext.vecdbFileLimit mySettingsComponent!!.inferenceModel = InferenceGlobalContext.model diff --git a/src/main/kotlin/com/smallcloud/refactai/settings/AppSettingsState.kt b/src/main/kotlin/com/smallcloud/refactai/settings/AppSettingsState.kt index a9084c9c..ef8cbe89 100644 --- a/src/main/kotlin/com/smallcloud/refactai/settings/AppSettingsState.kt +++ b/src/main/kotlin/com/smallcloud/refactai/settings/AppSettingsState.kt @@ -50,7 +50,6 @@ class AppSettingsState : PersistentStateComponent { var vecdbIsEnabledDefaultChanged: Boolean = false var astFileLimit: Int = 15000 var vecdbFileLimit: Int = 15000 - var astLightMode: Boolean = false var completionMaxTokens: Int = 0 var insecureSSL: Boolean = false var telemetrySnippetsEnabled: Boolean = false @@ -110,9 +109,6 @@ class AppSettingsState : PersistentStateComponent { override fun astFileLimitChanged(newValue: Int) { instance.astFileLimit = newValue } - override fun astLightModeChanged(newValue: Boolean) { - instance.astLightMode = newValue - } override fun vecdbFileLimitChanged(newValue: Int) { instance.vecdbFileLimit = newValue } diff --git a/src/main/kotlin/com/smallcloud/refactai/statistic/UsageStats.kt b/src/main/kotlin/com/smallcloud/refactai/statistic/UsageStats.kt index 6873c5fe..acb91422 100644 --- a/src/main/kotlin/com/smallcloud/refactai/statistic/UsageStats.kt +++ b/src/main/kotlin/com/smallcloud/refactai/statistic/UsageStats.kt @@ -7,6 +7,7 @@ import com.intellij.openapi.components.service import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.project.Project import com.intellij.util.concurrency.AppExecutorUtil +import com.smallcloud.refactai.Resources.defaultChatReportUrlSuffix import com.smallcloud.refactai.Resources.defaultReportUrlSuffix import com.smallcloud.refactai.Resources.defaultSnippetAcceptedUrlSuffix import com.smallcloud.refactai.io.sendRequest @@ -93,6 +94,48 @@ class UsageStats(private val project: Project): Disposable { } } } + + fun addChatStatistic( + positive: Boolean, + stat: UsageStatistic, + errorMessage: Any + ) { + var errorMessageStr = errorMessage.toString() + val gson = Gson() + if (errorMessageStr.length > 200) { + errorMessageStr = errorMessageStr.substring(0, 200) + "…" + } + + val errorMessageJson = gson.toJson(errorMessageStr) + var scope = stat.scope + if (stat.subScope.isNotEmpty()) { + scope += ":" + stat.subScope + } + + val scopeJson = gson.toJson(scope) + val body = gson.toJson( + mapOf( + "success" to positive, + "error_message" to errorMessageJson, + "scope" to scopeJson, + ) + ) + val url = getLSPProcessHolder(project)!!.url.resolve(defaultChatReportUrlSuffix) + execService.submit { + try { + val res = sendRequest(url, "POST", body=body) + if (res.body.isNullOrEmpty()) return@submit + + val json = gson.fromJson(res.body, JsonObject::class.java) + val success = if (json.has("success")) json.get("success").asInt else null + if (success != null && success != 1) { + throw Exception(json.get("human_readable_message").asString) + } + } catch (e: Exception) { + Logger.getInstance(UsageStats::class.java).warn("report to $url failed: $e") + } + } + } companion object { @JvmStatic diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 05ef895b..4bb36ad9 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -148,9 +148,11 @@ integrated into a single package that follows your privacy settings.

+ - - - - - - + + + + bundles.RefactAI