From 1c1ab88effbf46ae83c4c7e97cd185bf8f1c5e68 Mon Sep 17 00:00:00 2001 From: liuk Date: Sat, 21 Dec 2024 23:23:09 +0800 Subject: [PATCH 1/4] refactor: Adjust inlay rendering and improve completion logic - Replace `ContinueCustomElementRenderer` and `ContinueMultilineCustomElementRenderer` with `ContinueInlayRenderer`. - Add `Editor.addInlayElement` to handle inline and block inlay elements. - Refactor `AutocompleteService` to use new inlay renderer and improve completion rendering conditions. - Update `AcceptAutocompleteAction` to match new changes. --- .../autocomplete/AcceptAutocompleteAction.kt | 2 +- .../autocomplete/AutocompleteService.kt | 92 ++++++++++--------- .../ContinueCustomElementRenderer.kt | 45 --------- .../autocomplete/ContinueInlayRenderer.kt | 58 ++++++++++++ .../ContinueMultilineCustomElementRenderer.kt | 81 ---------------- 5 files changed, 107 insertions(+), 171 deletions(-) delete mode 100644 extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/ContinueCustomElementRenderer.kt create mode 100644 extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/ContinueInlayRenderer.kt delete mode 100644 extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/ContinueMultilineCustomElementRenderer.kt diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AcceptAutocompleteAction.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AcceptAutocompleteAction.kt index 45fb3b597d..03b91e87c7 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AcceptAutocompleteAction.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AcceptAutocompleteAction.kt @@ -22,4 +22,4 @@ class AcceptAutocompleteAction : EditorAction(object : EditorActionHandler() { && autocompleteService.pendingCompletion?.text != null return enabled } -}) {} \ No newline at end of file +}) \ No newline at end of file diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteService.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteService.kt index 6279e03f74..8be92742cd 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteService.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteService.kt @@ -10,8 +10,10 @@ import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.components.service import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.InlayProperties +import com.intellij.openapi.editor.impl.EditorImpl import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.project.Project +import com.intellij.openapi.util.TextRange import com.intellij.openapi.wm.WindowManager import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement @@ -32,9 +34,24 @@ fun PsiElement.isInjectedText(): Boolean { return false } +fun Editor.addInlayElement( + lines: List, + offset: Int, + properties: InlayProperties +) { + if (this is EditorImpl) { + if (lines[0].isNotEmpty()) { + inlayModel.addInlineElement(offset, properties, ContinueInlayRenderer(listOf(lines[0]))) + } + if (lines.size > 1) { + inlayModel.addBlockElement(offset, properties, ContinueInlayRenderer(lines.drop(1))) + } + } +} + @Service(Service.Level.PROJECT) class AutocompleteService(private val project: Project) { - var pendingCompletion: PendingCompletion? = null; + var pendingCompletion: PendingCompletion? = null private val autocompleteLookupListener = project.service() private var widget: AutocompleteSpinnerWidget? = null @@ -66,12 +83,13 @@ class AutocompleteService(private val project: Project) { // Request a completion from the core val virtualFile = FileDocumentManager.getInstance().getFile(editor.document) + val line = editor.caretModel.primaryCaret.logicalPosition.line val column = editor.caretModel.primaryCaret.logicalPosition.column val input = mapOf( "completionId" to completionId, - "filepath" to virtualFile?.url, + "filepath" to virtualFile?.path, "pos" to mapOf( - "line" to editor.caretModel.primaryCaret.logicalPosition.line, + "line" to line, "character" to column ), "recentlyEditedFiles" to emptyList(), @@ -79,10 +97,6 @@ class AutocompleteService(private val project: Project) { "clipboardText" to "" ) - val lineStart = editor.document.getLineStartOffset(editor.caretModel.primaryCaret.logicalPosition.line) - val lineEnd = editor.document.getLineEndOffset(editor.caretModel.primaryCaret.logicalPosition.line) - val lineLength = lineEnd - lineStart - project.service().coreMessenger?.request( "autocomplete/complete", input, @@ -95,9 +109,8 @@ class AutocompleteService(private val project: Project) { val completion = completions[0].toString() val finalTextToInsert = deduplicateCompletion(editor, offset, completion) - if (shouldRenderCompletion(finalTextToInsert, column, lineLength, editor)) { + if (shouldRenderCompletion(finalTextToInsert, offset, line, editor)) { renderCompletion(editor, offset, finalTextToInsert) - pendingCompletion = PendingCompletion(editor, offset, completionId, finalTextToInsert) // Hide auto-popup // AutoPopupController.getInstance(project).cancelAllRequests() } @@ -106,13 +119,19 @@ class AutocompleteService(private val project: Project) { ) } - private fun shouldRenderCompletion(completion: String, column: Int, lineLength: Int, editor: Editor): Boolean { - if (completion.isEmpty()) { + private fun shouldRenderCompletion(completion: String, offset: Int, line: Int, editor: Editor): Boolean { + if (completion.isEmpty() || runReadAction { offset != editor.caretModel.offset }) { return false } + if (completion.lines().size == 1) { + return true + } + + val endOffset = editor.document.getLineEndOffset(line) + // Do not render if completion is multi-line and caret is in middle of line - return !(completion.lines().size > 1 && column < lineLength) + return offset <= endOffset && editor.document.getText(TextRange(offset, endOffset)).isBlank() } private fun deduplicateCompletion(editor: Editor, offset: Int, completion: String): String { @@ -122,9 +141,9 @@ class AutocompleteService(private val project: Project) { val caretOffset = editor.caretModel.offset val N = 10 var textAfterCursor = if (caretOffset + N <= document.textLength) { - document.getText(com.intellij.openapi.util.TextRange(caretOffset, caretOffset + N)) + document.getText(TextRange(caretOffset, caretOffset + N)) } else { - document.getText(com.intellij.openapi.util.TextRange(caretOffset, document.textLength)) + document.getText(TextRange(caretOffset, document.textLength)) } // Determine the index of a newline character within the text following the cursor. @@ -164,19 +183,9 @@ class AutocompleteService(private val project: Project) { properties.relatesToPrecedingText(true) properties.disableSoftWrapping(true) - if (completion.lines().size > 1) { - editor.inlayModel.addBlockElement( - offset, - properties, - ContinueMultilineCustomElementRenderer(editor, completion) - ) - } else { - editor.inlayModel.addInlineElement( - offset, - properties, - ContinueCustomElementRenderer(editor, completion) - ) - } + val lines = completion.lines() + pendingCompletion = pendingCompletion?.copy(text = lines.joinToString("\n")) + editor.addInlayElement(lines, offset, properties) // val attributes = TextAttributes().apply { // backgroundColor = JBColor.GREEN @@ -204,7 +213,7 @@ class AutocompleteService(private val project: Project) { ({}) ) invokeLater { - clearCompletions(editor) + clearCompletions(editor, completion) } } @@ -267,23 +276,14 @@ class AutocompleteService(private val project: Project) { project.service().coreMessenger?.request("autocomplete/cancel", null, null, ({})) } - fun clearCompletions(editor: Editor) { + fun clearCompletions(editor: Editor, completion: PendingCompletion? = pendingCompletion) { if (isInjectedFile(editor)) return - if (pendingCompletion != null) { - cancelCompletion(pendingCompletion!!) - pendingCompletion = null - } - editor.inlayModel.getInlineElementsInRange(0, editor.document.textLength).forEach { - if (it.renderer is ContinueCustomElementRenderer) { - it.dispose() - } - } - editor.inlayModel.getBlockElementsInRange(0, editor.document.textLength).forEach { - if (it.renderer is ContinueMultilineCustomElementRenderer) { - it.dispose() - } + if (completion != null) { + cancelCompletion(completion) + if (completion.completionId == pendingCompletion?.completionId) pendingCompletion = null } + disposeInlayRenderer(editor) } private fun isInjectedFile(editor: Editor): Boolean { @@ -298,13 +298,17 @@ class AutocompleteService(private val project: Project) { fun hideCompletions(editor: Editor) { if (isInjectedFile(editor)) return + disposeInlayRenderer(editor) + } + + private fun disposeInlayRenderer(editor: Editor) { editor.inlayModel.getInlineElementsInRange(0, editor.document.textLength).forEach { - if (it.renderer is ContinueCustomElementRenderer) { + if (it.renderer is ContinueInlayRenderer) { it.dispose() } } editor.inlayModel.getBlockElementsInRange(0, editor.document.textLength).forEach { - if (it.renderer is ContinueMultilineCustomElementRenderer) { + if (it.renderer is ContinueInlayRenderer) { it.dispose() } } diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/ContinueCustomElementRenderer.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/ContinueCustomElementRenderer.kt deleted file mode 100644 index bfaeedb2d3..0000000000 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/ContinueCustomElementRenderer.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.github.continuedev.continueintellijextension.autocomplete - -import com.intellij.openapi.editor.Editor -import com.intellij.openapi.editor.EditorCustomElementRenderer -import com.intellij.openapi.editor.Inlay -import com.intellij.openapi.editor.colors.EditorFontType -import com.intellij.openapi.editor.impl.EditorImpl -import com.intellij.openapi.editor.impl.FontInfo -import com.intellij.openapi.editor.markup.TextAttributes -import com.intellij.ui.JBColor -import com.intellij.util.ui.UIUtil -import java.awt.Font -import java.awt.Graphics -import java.awt.Rectangle -import kotlin.math.ceil - -class ContinueCustomElementRenderer( - val editor: Editor, - val text: String, -) : EditorCustomElementRenderer { - override fun calcWidthInPixels(inlay: Inlay<*>): Int { - val width = (inlay.editor as EditorImpl).getFontMetrics(Font.PLAIN).stringWidth(this.text) - return width - } - - private fun font(editor: Editor): Font { - val editorFont = editor.colorsScheme.getFont(EditorFontType.PLAIN) - return UIUtil.getFontWithFallbackIfNeeded(editorFont, text).deriveFont(editor.colorsScheme.editorFontSize) - } - - private fun offsetY(editor: Editor): Int { - val metrics = - FontInfo.getFontMetrics(font(editor), FontInfo.getFontRenderContext(editor.contentComponent)) - val fontHeight = - font(editor).createGlyphVector(metrics.fontRenderContext, text).visualBounds.height - val height = (editor.lineHeight + fontHeight) / 2 - return ceil(height).toInt() - } - - override fun paint(inlay: Inlay<*>, g: Graphics, targetRegion: Rectangle, textAttributes: TextAttributes) { - g.color = JBColor.GRAY - g.font = font(inlay.editor) - g.drawString(this.text, targetRegion.x, targetRegion.y + inlay.editor.ascent) - } -} \ No newline at end of file diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/ContinueInlayRenderer.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/ContinueInlayRenderer.kt new file mode 100644 index 0000000000..bcf37fa20d --- /dev/null +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/ContinueInlayRenderer.kt @@ -0,0 +1,58 @@ +package com.github.continuedev.continueintellijextension.autocomplete + +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.editor.EditorCustomElementRenderer +import com.intellij.openapi.editor.Inlay +import com.intellij.openapi.editor.colors.EditorFontType +import com.intellij.openapi.editor.impl.EditorImpl +import com.intellij.openapi.editor.markup.TextAttributes +import com.intellij.ui.JBColor +import com.intellij.util.ui.UIUtil +import java.awt.Font +import java.awt.Graphics +import java.awt.Rectangle + +/** + * The `ContinueInlayRenderer` class is responsible for rendering custom inlay elements within an editor. + * It implements the [EditorCustomElementRenderer] interface to provide custom rendering logic for inlays. + * + * This renderer is designed to display a list of text lines (`lines`) within the editor, calculating the + * necessary width and height based on the content and rendering each line with appropriate font and color. + * + * @author lk + */ +class ContinueInlayRenderer(val lines: List) : EditorCustomElementRenderer { + override fun calcWidthInPixels(inlay: Inlay<*>): Int { + var maxLen = 0; + for (line in lines) { + val len = (inlay.editor as EditorImpl).getFontMetrics(Font.PLAIN).stringWidth(line) + if (len > maxLen) { + maxLen = len + } + } + return maxLen + } + + override fun calcHeightInPixels(inlay: Inlay<*>): Int { + return (inlay.editor as EditorImpl).lineHeight * lines.size + } + + private fun font(editor: Editor): Font { + val editorFont = editor.colorsScheme.getFont(EditorFontType.PLAIN) + return UIUtil.getFontWithFallbackIfNeeded(editorFont, lines.joinToString("\n")) + .deriveFont(editor.colorsScheme.editorFontSize) + } + + override fun paint(inlay: Inlay<*>, g: Graphics, targetRegion: Rectangle, textAttributes: TextAttributes) { + val editor = inlay.editor + g.color = JBColor.GRAY + g.font = font(editor) + var additionalYOffset = 0 + val ascent = editor.ascent + val lineHeight = editor.lineHeight + for (line in lines) { + g.drawString(line, targetRegion.x, targetRegion.y + ascent + additionalYOffset) + additionalYOffset += lineHeight + } + } +} \ No newline at end of file diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/ContinueMultilineCustomElementRenderer.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/ContinueMultilineCustomElementRenderer.kt deleted file mode 100644 index a24b2453a5..0000000000 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/ContinueMultilineCustomElementRenderer.kt +++ /dev/null @@ -1,81 +0,0 @@ -package com.github.continuedev.continueintellijextension.autocomplete - -import com.intellij.openapi.editor.Editor -import com.intellij.openapi.editor.EditorCustomElementRenderer -import com.intellij.openapi.editor.Inlay -import com.intellij.openapi.editor.colors.EditorFontType -import com.intellij.openapi.editor.impl.EditorImpl -import com.intellij.openapi.editor.impl.FontInfo -import com.intellij.openapi.editor.markup.TextAttributes -import com.intellij.ui.JBColor -import com.intellij.util.ui.UIUtil -import java.awt.Font -import java.awt.Graphics -import java.awt.Rectangle -import kotlin.math.ceil -import kotlin.math.max - -class ContinueMultilineCustomElementRenderer( - val editor: Editor, - val text: String, -) : EditorCustomElementRenderer { - override fun calcWidthInPixels(inlay: Inlay<*>): Int { - val lines = text.lines() - var maxLen = 0; - for (line in lines) { - val len = (inlay.editor as EditorImpl).getFontMetrics(Font.PLAIN).stringWidth(line) - if (len > maxLen) { - maxLen = len - } - } - return maxLen - } - - override fun calcHeightInPixels(inlay: Inlay<*>): Int { - return (inlay.editor as EditorImpl).lineHeight * text.lines().size - } - - protected val font: Font - get() { - val editorFont = editor.colorsScheme.getFont(EditorFontType.PLAIN) - return UIUtil.getFontWithFallbackIfNeeded(editorFont, text).deriveFont(editor.colorsScheme.editorFontSize) - } - - private fun offsetY(): Int { - val metrics = - FontInfo.getFontMetrics(font, FontInfo.getFontRenderContext(editor.contentComponent)) - val fontHeight = - font.createGlyphVector(metrics.fontRenderContext, text).visualBounds.height - val height = (editor.lineHeight + fontHeight) / 2 - return ceil(height).toInt() - } - - private fun offsetX(): Int { - val currentLine = editor.caretModel.primaryCaret.logicalPosition.line - val currentColumn = editor.caretModel.primaryCaret.logicalPosition.column - val metrics = - FontInfo.getFontMetrics(font, FontInfo.getFontRenderContext(editor.contentComponent)) - val fontWidth = - font.createGlyphVector(metrics.fontRenderContext, text).visualBounds.width - val widthBeforeCaret = (editor as EditorImpl).getFontMetrics(Font.PLAIN).stringWidth( - text.substring(0, minOf(currentColumn, text.length)) - ) - return max(0, widthBeforeCaret - (editor as EditorImpl).scrollingModel.horizontalScrollOffset) - } - - override fun paint(inlay: Inlay<*>, g: Graphics, targetRegion: Rectangle, textAttributes: TextAttributes) { - g.color = JBColor.GRAY - g.font = font - var additionalYOffset = -editor.lineHeight; - var isFirstLine = true - for (line in text.lines()) { - g.drawString( - line, - if (isFirstLine) targetRegion.x + offsetX() else targetRegion.x, - targetRegion.y + inlay.editor.ascent + additionalYOffset - ) - additionalYOffset += editor.lineHeight - isFirstLine = false - } - } -} \ No newline at end of file From 3df34b725e873fcd42058474d83ef634e21d5cad Mon Sep 17 00:00:00 2001 From: liuk Date: Wed, 25 Dec 2024 01:11:38 +0800 Subject: [PATCH 2/4] fix: Revert filepath changes --- .../autocomplete/AutocompleteService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteService.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteService.kt index 8be92742cd..e7a1fb8305 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteService.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteService.kt @@ -87,7 +87,7 @@ class AutocompleteService(private val project: Project) { val column = editor.caretModel.primaryCaret.logicalPosition.column val input = mapOf( "completionId" to completionId, - "filepath" to virtualFile?.path, + "filepath" to virtualFile?.url, "pos" to mapOf( "line" to line, "character" to column From 0a7da2067e8d8567084d05f69038b7ca95464d1f Mon Sep 17 00:00:00 2001 From: liuk Date: Thu, 26 Dec 2024 19:46:53 +0800 Subject: [PATCH 3/4] fix: Resolved errors related to incorrect URIs --- .../activities/ContinuePluginStartupActivity.kt | 8 ++++---- .../autocomplete/AutocompleteService.kt | 6 +++++- .../continue/IdeProtocolClient.kt | 14 ++++++++------ .../continue/IntelliJIde.kt | 13 +++++++------ .../continueintellijextension/utils/Utils.kt | 5 ++++- 5 files changed, 28 insertions(+), 18 deletions(-) diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/activities/ContinuePluginStartupActivity.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/activities/ContinuePluginStartupActivity.kt index facc894245..72819421ac 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/activities/ContinuePluginStartupActivity.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/activities/ContinuePluginStartupActivity.kt @@ -10,7 +10,7 @@ import com.github.continuedev.continueintellijextension.listeners.ContinuePlugin import com.github.continuedev.continueintellijextension.services.ContinueExtensionSettings import com.github.continuedev.continueintellijextension.services.ContinuePluginService import com.github.continuedev.continueintellijextension.services.SettingsListener -import com.intellij.openapi.Disposable +import com.github.continuedev.continueintellijextension.utils.toUriOrNull import com.intellij.openapi.actionSystem.KeyboardShortcut import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationNamesInfo @@ -162,7 +162,7 @@ class ContinuePluginStartupActivity : StartupActivity, DumbAware { override fun after(events: List) { // Collect all relevant URIs for deletions val deletedURIs = events.filterIsInstance() - .map { event -> event.file.url } + .mapNotNull { event -> event.file.toUriOrNull() } // Send "files/deleted" message if there are any deletions if (deletedURIs.isNotEmpty()) { @@ -172,7 +172,7 @@ class ContinuePluginStartupActivity : StartupActivity, DumbAware { // Collect all relevant URIs for content changes val changedURIs = events.filterIsInstance() - .map { event -> event.file.url } + .mapNotNull { event -> event.file.toUriOrNull() } // Send "files/changed" message if there are any content changes if (changedURIs.isNotEmpty()) { @@ -220,7 +220,7 @@ class ContinuePluginStartupActivity : StartupActivity, DumbAware { // Reload the WebView continuePluginService?.let { pluginService -> val allModulePaths = ModuleManager.getInstance(project).modules - .flatMap { module -> ModuleRootManager.getInstance(module).contentRoots.map { it.url } } + .flatMap { module -> ModuleRootManager.getInstance(module).contentRoots.mapNotNull { it.toUriOrNull() } } val topLevelModulePaths = allModulePaths .filter { modulePath -> allModulePaths.none { it != modulePath && modulePath.startsWith(it) } } diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteService.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteService.kt index e7a1fb8305..2941aae8ef 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteService.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteService.kt @@ -2,6 +2,7 @@ package com.github.continuedev.continueintellijextension.autocomplete import com.github.continuedev.continueintellijextension.services.ContinueExtensionSettings import com.github.continuedev.continueintellijextension.services.ContinuePluginService +import com.github.continuedev.continueintellijextension.utils.toUriOrNull import com.github.continuedev.continueintellijextension.utils.uuid import com.intellij.injected.editor.VirtualFileWindow import com.intellij.openapi.application.* @@ -83,11 +84,14 @@ class AutocompleteService(private val project: Project) { // Request a completion from the core val virtualFile = FileDocumentManager.getInstance().getFile(editor.document) + + val uri = virtualFile?.toUriOrNull() ?: return + val line = editor.caretModel.primaryCaret.logicalPosition.line val column = editor.caretModel.primaryCaret.logicalPosition.column val input = mapOf( "completionId" to completionId, - "filepath" to virtualFile?.url, + "filepath" to uri, "pos" to mapOf( "line" to line, "character" to column diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/continue/IdeProtocolClient.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/continue/IdeProtocolClient.kt index 69e06e89e6..43ee85e290 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/continue/IdeProtocolClient.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/continue/IdeProtocolClient.kt @@ -546,12 +546,14 @@ class IdeProtocolClient( val startChar = startOffset - document.getLineStartOffset(startLine) val endChar = endOffset - document.getLineStartOffset(endLine) - return@runReadAction RangeInFileWithContents( - virtualFile.url, Range( - Position(startLine, startChar), - Position(endLine, endChar) - ), selectedText - ) + return@runReadAction virtualFile.toUriOrNull()?.let { + RangeInFileWithContents( + it, Range( + Position(startLine, startChar), + Position(endLine, endChar) + ), selectedText + ) + } } return result diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/continue/IntelliJIde.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/continue/IntelliJIde.kt index 154476f5e0..39d7b36812 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/continue/IntelliJIde.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/continue/IntelliJIde.kt @@ -5,6 +5,7 @@ import com.github.continuedev.continueintellijextension.services.ContinuePluginS import com.github.continuedev.continueintellijextension.utils.OS import com.github.continuedev.continueintellijextension.utils.getMachineUniqueID import com.github.continuedev.continueintellijextension.utils.getOS +import com.github.continuedev.continueintellijextension.utils.toUriOrNull import com.intellij.codeInsight.daemon.impl.HighlightInfo import com.intellij.execution.configurations.GeneralCommandLine import com.intellij.execution.util.ExecUtil @@ -180,7 +181,7 @@ class IntelliJIDE( for (workspaceDir in workspaceDirs) { val dir = VirtualFileManager.getInstance().findFileByUrl(workspaceDir) if (dir != null) { - val contents = dir.children.map { it.url } + val contents = dir.children.mapNotNull { it.toUriOrNull() } // Find any .continuerc.json files for (file in contents) { @@ -307,16 +308,16 @@ class IntelliJIDE( override suspend fun getOpenFiles(): List { val fileEditorManager = FileEditorManager.getInstance(project) - return fileEditorManager.openFiles.map { it.url }.toList() + return fileEditorManager.openFiles.mapNotNull { it.toUriOrNull() }.toList() } override suspend fun getCurrentFile(): Map? { val fileEditorManager = FileEditorManager.getInstance(project) val editor = fileEditorManager.selectedTextEditor val virtualFile = editor?.document?.let { FileDocumentManager.getInstance().getFile(it) } - return virtualFile?.let { + return virtualFile?.toUriOrNull()?.let { mapOf( - "path" to it.url, + "path" to it, "contents" to editor.document.text, "isUntitled" to false ) @@ -382,7 +383,7 @@ class IntelliJIDE( problems.add( Problem( - filepath = psiFile.virtualFile?.url ?: "", + filepath = psiFile.virtualFile?.toUriOrNull() ?: "", range = Range( start = Position( line = startLineNumber, @@ -561,6 +562,6 @@ class IntelliJIDE( return dirs } - return listOfNotNull(project.guessProjectDir()?.url).toTypedArray() + return listOfNotNull(project.guessProjectDir()?.toUriOrNull()).toTypedArray() } } \ No newline at end of file diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/utils/Utils.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/utils/Utils.kt index fe29b6235e..7e90ba99e9 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/utils/Utils.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/utils/Utils.kt @@ -1,5 +1,6 @@ package com.github.continuedev.continueintellijextension.utils +import com.intellij.openapi.vfs.VirtualFile import java.net.NetworkInterface import java.util.* import java.awt.event.KeyEvent.* @@ -77,4 +78,6 @@ fun getMachineUniqueID(): String { fun uuid(): String { return UUID.randomUUID().toString() -} \ No newline at end of file +} + +fun VirtualFile.toUriOrNull(): String? = fileSystem.getNioPath(this)?.toUri()?.toString()?.removeSuffix("/") \ No newline at end of file From 79736c3108313204184bb7d833ac21e23341354f Mon Sep 17 00:00:00 2001 From: liuk Date: Wed, 1 Jan 2025 00:25:18 +0800 Subject: [PATCH 4/4] fix: Add directory checks and optimize token usage - Added check to skip directories when reading file content. - Optimized token usage by removing unnecessary `\r` characters. --- .../continueintellijextension/continue/IntelliJIde.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/continue/IntelliJIde.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/continue/IntelliJIde.kt index 39d7b36812..d304e8a027 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/continue/IntelliJIde.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/continue/IntelliJIde.kt @@ -262,7 +262,7 @@ class IntelliJIDE( content } else { val file = File(URI(filepath)) - if (!file.exists()) return "" + if (!file.exists() || file.isDirectory) return "" withContext(Dispatchers.IO) { FileInputStream(file).use { fis -> val sizeToRead = minOf(100000, file.length()).toInt() @@ -270,6 +270,8 @@ class IntelliJIDE( val bytesRead = fis.read(buffer, 0, sizeToRead) if (bytesRead <= 0) return@use "" String(buffer, 0, bytesRead, Charset.forName("UTF-8")) + // `\r` takes up unnecessary tokens + .lineSequence().joinToString("\n") } } }