diff --git a/CHANGELOG.md b/CHANGELOG.md index 095b87fd..a2eb17d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Support for code editing and commit message generation with Deepseek R1 model [#835](https://github.com/carlrobertoh/CodeGPT/issues/835) -- Avatar images for registered CodeGPT users -- Support for disabling system prompts - `o3-mini` model (CodeGPT, OpenAI) +- Support for code editing and commit message generation with Deepseek R1 model [#835](https://github.com/carlrobertoh/CodeGPT/issues/835) - Kotlin dependency analyzer for code completions [#829](https://github.com/carlrobertoh/CodeGPT/pull/829) +- Status toolbar completion progress for all core actions +- Support for disabling system prompts +- Avatar images for registered CodeGPT users ### Fixed diff --git a/src/main/java/ee/carlrobert/codegpt/CodeGPTKeys.java b/src/main/java/ee/carlrobert/codegpt/CodeGPTKeys.java index cc842eeb..0ccdb3c2 100644 --- a/src/main/java/ee/carlrobert/codegpt/CodeGPTKeys.java +++ b/src/main/java/ee/carlrobert/codegpt/CodeGPTKeys.java @@ -15,12 +15,13 @@ public class CodeGPTKeys { Key.create("codegpt.userDetails"); public static final Key REMAINING_EDITOR_COMPLETION = Key.create("codegpt.editorCompletionLines"); - public static final Key IS_FETCHING_COMPLETION = - Key.create("codegpt.isFetchingCompletion"); + public static final Key PENDING_PREDICTION_CALL = + Key.create("codegpt.editorPendingPredictionCall"); + public static final Key COMPLETION_IN_PROGRESS = + Key.create("codegpt.completionInProgress"); public static final Key IS_PROMPT_TEXT_FIELD_DOCUMENT = Key.create("codegpt.isPromptTextFieldDocument"); public static final Key EDITOR_PREDICTION_DIFF_VIEWER = Key.create("codegpt.editorPredictionDiffViewer"); - public static final Key PENDING_PREDICTION_CALL = - Key.create("codegpt.editorPendingPredictionCall"); + } diff --git a/src/main/java/ee/carlrobert/codegpt/completions/ChatCompletionEventListener.java b/src/main/java/ee/carlrobert/codegpt/completions/ChatCompletionEventListener.java index b2b7ce9f..dc8aeb92 100644 --- a/src/main/java/ee/carlrobert/codegpt/completions/ChatCompletionEventListener.java +++ b/src/main/java/ee/carlrobert/codegpt/completions/ChatCompletionEventListener.java @@ -2,6 +2,8 @@ package ee.carlrobert.codegpt.completions; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.intellij.openapi.project.Project; +import ee.carlrobert.codegpt.codecompletions.CompletionProgressNotifier; import ee.carlrobert.codegpt.events.CodeGPTEvent; import ee.carlrobert.codegpt.telemetry.TelemetryAction; import ee.carlrobert.llm.client.openai.completion.ErrorDetails; @@ -10,13 +12,16 @@ import okhttp3.sse.EventSource; public class ChatCompletionEventListener implements CompletionEventListener { + private final Project project; private final ChatCompletionParameters callParameters; private final CompletionResponseEventListener eventListener; private final StringBuilder messageBuilder = new StringBuilder(); public ChatCompletionEventListener( + Project project, ChatCompletionParameters callParameters, CompletionResponseEventListener eventListener) { + this.project = project; this.callParameters = callParameters; this.eventListener = eventListener; } @@ -64,6 +69,7 @@ public class ChatCompletionEventListener implements CompletionEventListener { + CompletionProgressNotifier.Companion.getCOMPLETION_PROGRESS_TOPIC(), + (CompletionProgressNotifier) () -> { CodeGPTStatusBarWidget widget = findWidget(project); if (widget != null && widget.myStatusBar != null) { widget.update(() -> widget.myStatusBar.updateWidget(ID)); @@ -43,12 +42,9 @@ public class CodeGPTStatusBarWidget extends EditorBasedStatusBarPopup { @Override protected @NotNull WidgetState getWidgetState(@Nullable VirtualFile file) { + var completionInProgress = COMPLETION_IN_PROGRESS.get(getProject()); + var loading = (completionInProgress != null && completionInProgress); var state = new WidgetState(CodeGPTBundle.get("statusBar.widget.tooltip"), "", true); - var fetchingCompletion = IS_FETCHING_COMPLETION.get(getEditor()); - var pendingPredicationCall = PENDING_PREDICTION_CALL.get(getEditor()); - var loading = - (fetchingCompletion != null && fetchingCompletion) || pendingPredicationCall != null; - state.setIcon(loading ? Icons.StatusBarCompletionInProgress : Icons.DefaultSmall); return state; } diff --git a/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabPanel.java b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabPanel.java index 3eff4275..527af42f 100644 --- a/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabPanel.java +++ b/src/main/java/ee/carlrobert/codegpt/toolwindow/chat/ChatToolWindowTabPanel.java @@ -287,6 +287,7 @@ public class ChatToolWindowTabPanel implements Disposable { } requestHandler = new ToolwindowChatCompletionRequestHandler( + project, new ToolWindowCompletionResponseEventListener( conversationService, userMessagePanel, diff --git a/src/main/kotlin/ee/carlrobert/codegpt/actions/BaseCommitWorkflowAction.kt b/src/main/kotlin/ee/carlrobert/codegpt/actions/BaseCommitWorkflowAction.kt index a3ca7e98..e8ad0f72 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/actions/BaseCommitWorkflowAction.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/actions/BaseCommitWorkflowAction.kt @@ -18,6 +18,7 @@ import com.intellij.openapi.vcs.VcsDataKeys import com.intellij.openapi.vcs.changes.Change import com.intellij.vcs.commit.CommitWorkflowUi import ee.carlrobert.codegpt.EncodingManager +import ee.carlrobert.codegpt.codecompletions.CompletionProgressNotifier import ee.carlrobert.codegpt.completions.CompletionRequestService import ee.carlrobert.codegpt.toolwindow.chat.ThinkingOutputParser import ee.carlrobert.codegpt.ui.OverlayUtil @@ -72,7 +73,6 @@ abstract class BaseCommitWorkflowAction : DumbAwareAction() { return ActionUpdateThread.EDT } - private fun getDiff(event: AnActionEvent, project: Project): String { val commitWorkflowUi = event.getData(VcsDataKeys.COMMIT_WORKFLOW_UI) ?: throw IllegalStateException("Could not retrieve commit workflow ui.") @@ -141,14 +141,7 @@ class CommitMessageEventListener( if (messageBuilder.isEmpty()) { updateCommitMessage(result.toString()) } - } - - private fun updateCommitMessage(message: String?) { - ApplicationManager.getApplication().invokeLater { - WriteCommandAction.runWriteCommandAction(project) { - commitWorkflowUi.commitMessageUi.setText(message) - } - } + stopLoading() } override fun onError(error: ErrorDetails, ex: Throwable) { @@ -160,5 +153,18 @@ class CommitMessageEventListener( NotificationType.ERROR ) ) + stopLoading() + } + + private fun stopLoading() { + CompletionProgressNotifier.update(project, false) + } + + private fun updateCommitMessage(message: String?) { + ApplicationManager.getApplication().invokeLater { + WriteCommandAction.runWriteCommandAction(project) { + commitWorkflowUi.commitMessageUi.setText(message) + } + } } } \ No newline at end of file diff --git a/src/main/kotlin/ee/carlrobert/codegpt/actions/GenerateCommitMessageAction.kt b/src/main/kotlin/ee/carlrobert/codegpt/actions/GenerateCommitMessageAction.kt index 0e4656dc..f4246725 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/actions/GenerateCommitMessageAction.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/actions/GenerateCommitMessageAction.kt @@ -2,6 +2,7 @@ package ee.carlrobert.codegpt.actions import com.intellij.openapi.project.Project import com.intellij.vcs.commit.CommitWorkflowUi +import ee.carlrobert.codegpt.codecompletions.CompletionProgressNotifier import ee.carlrobert.codegpt.completions.CommitMessageCompletionParameters import ee.carlrobert.codegpt.completions.CompletionRequestService import ee.carlrobert.codegpt.settings.prompts.CommitMessageTemplate @@ -17,6 +18,7 @@ class GenerateCommitMessageAction : BaseCommitWorkflowAction() { commitWorkflowUi: CommitWorkflowUi, gitDiff: String ) { + CompletionProgressNotifier.update(project, true) CompletionRequestService.getInstance().getCommitMessageAsync( CommitMessageCompletionParameters( gitDiff, diff --git a/src/main/kotlin/ee/carlrobert/codegpt/actions/editor/EditCodeCompletionListener.kt b/src/main/kotlin/ee/carlrobert/codegpt/actions/editor/EditCodeCompletionListener.kt index 94268e77..6d494b33 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/actions/editor/EditCodeCompletionListener.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/actions/editor/EditCodeCompletionListener.kt @@ -14,6 +14,7 @@ import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.PsiDocumentManager import com.intellij.psi.codeStyle.CodeStyleManager import com.intellij.ui.JBColor +import ee.carlrobert.codegpt.codecompletions.CompletionProgressNotifier import ee.carlrobert.codegpt.toolwindow.chat.ThinkingOutputParser import ee.carlrobert.codegpt.ui.ObservableProperties import ee.carlrobert.codegpt.ui.OverlayUtil @@ -45,12 +46,10 @@ class EditCodeCompletionListener( } cleanupAndFormat() } - observableProperties.loading.set(false) + stopLoading() } override fun onError(error: ErrorDetails, ex: Throwable) { - observableProperties.loading.set(false) - OverlayUtil.showNotification( error.message, NotificationType.ERROR, @@ -58,6 +57,14 @@ class EditCodeCompletionListener( BrowserUtil.open("https://codegpt.ee/#pricing") }, ) + stopLoading() + } + + private fun stopLoading() { + observableProperties.loading.set(false) + editor.project?.let { + CompletionProgressNotifier.update(it, false) + } } private fun updateHighlighter(editor: Editor) { diff --git a/src/main/kotlin/ee/carlrobert/codegpt/actions/editor/EditCodeSubmissionHandler.kt b/src/main/kotlin/ee/carlrobert/codegpt/actions/editor/EditCodeSubmissionHandler.kt index 0e56479e..e21c24f5 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/actions/editor/EditCodeSubmissionHandler.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/actions/editor/EditCodeSubmissionHandler.kt @@ -8,6 +8,7 @@ import com.intellij.openapi.editor.Editor import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.text.StringUtil import com.jetbrains.rd.util.AtomicReference +import ee.carlrobert.codegpt.codecompletions.CompletionProgressNotifier import ee.carlrobert.codegpt.completions.CompletionRequestService import ee.carlrobert.codegpt.completions.EditCodeCompletionParameters import ee.carlrobert.codegpt.ui.ObservableProperties @@ -20,6 +21,10 @@ class EditCodeSubmissionHandler( private val previousSourceRef = AtomicReference(null) suspend fun handleSubmit(userPrompt: String) { + editor.project?.let { + CompletionProgressNotifier.update(it, true) + } + observableProperties.loading.set(true) observableProperties.submitted.set(true) diff --git a/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/CodeCompletionEventListener.kt b/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/CodeCompletionEventListener.kt index 864a638a..b61c0907 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/CodeCompletionEventListener.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/CodeCompletionEventListener.kt @@ -8,7 +8,6 @@ import com.intellij.openapi.components.service import com.intellij.openapi.diagnostic.thisLogger import com.intellij.openapi.editor.Editor import com.intellij.openapi.util.TextRange -import ee.carlrobert.codegpt.CodeGPTKeys.IS_FETCHING_COMPLETION import ee.carlrobert.codegpt.CodeGPTKeys.REMAINING_EDITOR_COMPLETION import ee.carlrobert.codegpt.codecompletions.CompletionUtil.formatCompletion import ee.carlrobert.codegpt.settings.GeneralSettings @@ -61,10 +60,9 @@ abstract class CodeCompletionEventListener( } private fun setLoading(loading: Boolean) { - IS_FETCHING_COMPLETION.set(editor, loading) - editor.project?.messageBus - ?.syncPublisher(CodeCompletionProgressNotifier.CODE_COMPLETION_PROGRESS_TOPIC) - ?.loading(loading) + editor.project?.let { + CompletionProgressNotifier.update(it, loading) + } } } diff --git a/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/CodeCompletionProgressNotifier.kt b/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/CodeCompletionProgressNotifier.kt deleted file mode 100644 index 3908651a..00000000 --- a/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/CodeCompletionProgressNotifier.kt +++ /dev/null @@ -1,30 +0,0 @@ -package ee.carlrobert.codegpt.codecompletions - -import com.intellij.openapi.project.Project -import com.intellij.util.messages.Topic - -interface CodeCompletionProgressNotifier { - - fun loading(loading: Boolean) - - companion object { - @JvmStatic - val CODE_COMPLETION_PROGRESS_TOPIC = - Topic.create("codeCompletionProgressTopic", CodeCompletionProgressNotifier::class.java) - - fun startLoading(project: Project) { - handleLoading(project, true) - } - - fun stopLoading(project: Project) { - handleLoading(project, false) - } - - private fun handleLoading(project: Project, loading: Boolean) { - if (project.isDisposed) return - project.messageBus - .syncPublisher(CODE_COMPLETION_PROGRESS_TOPIC) - ?.loading(loading) - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/CompletionProgressNotifier.kt b/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/CompletionProgressNotifier.kt new file mode 100644 index 00000000..17e62dd7 --- /dev/null +++ b/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/CompletionProgressNotifier.kt @@ -0,0 +1,24 @@ +package ee.carlrobert.codegpt.codecompletions + +import com.intellij.openapi.project.Project +import com.intellij.util.messages.Topic +import ee.carlrobert.codegpt.CodeGPTKeys + +interface CompletionProgressNotifier { + + fun update() + + companion object { + @JvmStatic + val COMPLETION_PROGRESS_TOPIC = + Topic.create("completionProgressTopic", CompletionProgressNotifier::class.java) + + fun update(project: Project, loading: Boolean) { + if (project.isDisposed) return + + CodeGPTKeys.COMPLETION_IN_PROGRESS.set(project, loading) + + project.messageBus.syncPublisher(COMPLETION_PROGRESS_TOPIC)?.update() + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/DebouncedCodeCompletionProvider.kt b/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/DebouncedCodeCompletionProvider.kt index abbf57cb..b1d81cda 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/DebouncedCodeCompletionProvider.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/codecompletions/DebouncedCodeCompletionProvider.kt @@ -8,7 +8,6 @@ import com.intellij.openapi.components.service import com.intellij.openapi.diagnostic.thisLogger import com.intellij.openapi.project.Project import com.intellij.openapi.util.TextRange -import ee.carlrobert.codegpt.CodeGPTKeys.IS_FETCHING_COMPLETION import ee.carlrobert.codegpt.CodeGPTKeys.REMAINING_EDITOR_COMPLETION import ee.carlrobert.codegpt.settings.GeneralSettings import ee.carlrobert.codegpt.settings.configuration.ConfigurationSettings @@ -111,10 +110,8 @@ class DebouncedCodeCompletionProvider : DebouncedInlineCompletionProvider() { return InlineCompletionSuggestion.Default(emptyFlow()) } - IS_FETCHING_COMPLETION.set(request.editor, true) - request.editor.project?.let { - CodeCompletionProgressNotifier.startLoading(it) + CompletionProgressNotifier.update(it, true) } return InlineCompletionSuggestion.Default(channelFlow { diff --git a/src/main/kotlin/ee/carlrobert/codegpt/predictions/PredictionService.kt b/src/main/kotlin/ee/carlrobert/codegpt/predictions/PredictionService.kt index f5acdcfe..8d75b693 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/predictions/PredictionService.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/predictions/PredictionService.kt @@ -12,9 +12,8 @@ import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.testFramework.LightVirtualFile import ee.carlrobert.codegpt.CodeGPTKeys -import ee.carlrobert.codegpt.CodeGPTKeys.IS_FETCHING_COMPLETION import ee.carlrobert.codegpt.CodeGPTKeys.PENDING_PREDICTION_CALL -import ee.carlrobert.codegpt.codecompletions.CodeCompletionProgressNotifier +import ee.carlrobert.codegpt.codecompletions.CompletionProgressNotifier import ee.carlrobert.codegpt.completions.CompletionClientProvider import ee.carlrobert.codegpt.conversations.ConversationsState import ee.carlrobert.codegpt.settings.prompts.PromptsSettings @@ -101,7 +100,7 @@ class PredictionService { private fun getPrediction(editor: Editor, request: Request): PredictionResponse? { editor.project?.let { - CodeCompletionProgressNotifier.startLoading(it) + CompletionProgressNotifier.update(it, true) } val pendingCall = PENDING_PREDICTION_CALL.get(editor) @@ -129,10 +128,9 @@ class PredictionService { } return null } finally { - IS_FETCHING_COMPLETION.set(editor, false) PENDING_PREDICTION_CALL.set(editor, null) editor.project?.let { - CodeCompletionProgressNotifier.stopLoading(it) + CompletionProgressNotifier.update(it, false) } } } diff --git a/src/test/kotlin/ee/carlrobert/codegpt/completions/DefaultToolwindowChatCompletionRequestHandlerTest.kt b/src/test/kotlin/ee/carlrobert/codegpt/completions/DefaultToolwindowChatCompletionRequestHandlerTest.kt index cd21f97b..5576eb72 100644 --- a/src/test/kotlin/ee/carlrobert/codegpt/completions/DefaultToolwindowChatCompletionRequestHandlerTest.kt +++ b/src/test/kotlin/ee/carlrobert/codegpt/completions/DefaultToolwindowChatCompletionRequestHandlerTest.kt @@ -49,7 +49,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() { ) }) val requestHandler = - ToolwindowChatCompletionRequestHandler(getRequestEventListener(message)) + ToolwindowChatCompletionRequestHandler(project, getRequestEventListener(message)) requestHandler.call(ChatCompletionParameters.builder(conversation, message).build()) @@ -94,7 +94,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() { }) val message = Message("TEST_PROMPT") val requestHandler = - ToolwindowChatCompletionRequestHandler(getRequestEventListener(message)) + ToolwindowChatCompletionRequestHandler(project, getRequestEventListener(message)) requestHandler.call(ChatCompletionParameters.builder(conversation, message).build()) @@ -135,7 +135,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() { ) }) val requestHandler = - ToolwindowChatCompletionRequestHandler(getRequestEventListener(message)) + ToolwindowChatCompletionRequestHandler(project, getRequestEventListener(message)) requestHandler.call(ChatCompletionParameters.builder(conversation, message).build()) @@ -175,7 +175,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() { ) }) val requestHandler = - ToolwindowChatCompletionRequestHandler(getRequestEventListener(message)) + ToolwindowChatCompletionRequestHandler(project, getRequestEventListener(message)) requestHandler.call(ChatCompletionParameters.builder(conversation, message).build()) @@ -220,7 +220,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() { ) }) val requestHandler = - ToolwindowChatCompletionRequestHandler(getRequestEventListener(message)) + ToolwindowChatCompletionRequestHandler(project, getRequestEventListener(message)) requestHandler.call(ChatCompletionParameters.builder(conversation, message).build()) @@ -259,7 +259,7 @@ class DefaultToolwindowChatCompletionRequestHandlerTest : IntegrationTest() { ) }) val requestHandler = - ToolwindowChatCompletionRequestHandler(getRequestEventListener(message)) + ToolwindowChatCompletionRequestHandler(project, getRequestEventListener(message)) requestHandler.call(ChatCompletionParameters.builder(conversation, message).build())