generated from JetBrains/intellij-platform-plugin-template
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Revert "refactor: clean inlay model"
This reverts commit e5d0905.
- Loading branch information
1 parent
8d66903
commit 93aa5a8
Showing
15 changed files
with
1,099 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
119 changes: 119 additions & 0 deletions
119
src/main/kotlin/cc/unitmesh/devti/actions/LLMApplyInlaysAction.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
package cc.unitmesh.devti.actions | ||
|
||
import cc.unitmesh.devti.editor.inlay.LLMInlayManager | ||
import com.intellij.temporary.inlay.presentation.EditorUtilCopy | ||
import com.intellij.application.options.CodeStyle | ||
import com.intellij.codeInsight.lookup.LookupManager | ||
import com.intellij.codeInsight.template.TemplateManager | ||
import com.intellij.openapi.actionSystem.AnActionEvent | ||
import com.intellij.openapi.actionSystem.DataContext | ||
import com.intellij.openapi.diagnostic.logger | ||
import com.intellij.openapi.editor.Caret | ||
import com.intellij.openapi.editor.Document | ||
import com.intellij.openapi.editor.Editor | ||
import com.intellij.openapi.editor.actionSystem.EditorAction | ||
import com.intellij.openapi.editor.actionSystem.EditorActionHandler | ||
import com.intellij.openapi.project.DumbAware | ||
import com.intellij.openapi.util.TextRange | ||
import java.awt.event.KeyEvent | ||
|
||
class LLMApplyInlaysAction : EditorAction(ApplyInlaysHandler()), DumbAware { | ||
init { | ||
setInjectedContext(true) | ||
} | ||
|
||
override fun update(e: AnActionEvent) { | ||
if (isIgnoredKeyboardEvent(e)) { | ||
e.presentation.isEnabled = false | ||
return | ||
} | ||
|
||
super.update(e) | ||
} | ||
|
||
private fun isIgnoredKeyboardEvent(e: AnActionEvent): Boolean { | ||
if (e.inputEvent !is KeyEvent) return false | ||
if ((e.inputEvent as KeyEvent).keyChar != '\t') return false | ||
|
||
val project = e.project ?: return false | ||
val editor = getEditor(e.dataContext) ?: return false | ||
|
||
val document = editor.document | ||
val blockIndent = CodeStyle.getIndentOptions(project, document).INDENT_SIZE | ||
val caretOffset = editor.caretModel.offset | ||
val line = document.getLineNumber(caretOffset) | ||
|
||
val caretOffsetAfterTab = EditorUtilCopy.indentLine(project, editor, line, blockIndent, caretOffset) | ||
// if (isNonEmptyLinePrefix(document, line, caretOffset) || caretOffsetAfterTab < caretOffset) { | ||
// return false | ||
// } | ||
|
||
val instance = LLMInlayManager.getInstance() | ||
val tabRange = TextRange.create(caretOffset, caretOffsetAfterTab) | ||
|
||
if (instance.countCompletionInlays(editor, tabRange) > 0) { | ||
return false | ||
} | ||
|
||
return true | ||
} | ||
|
||
|
||
private class ApplyInlaysHandler : EditorActionHandler() { | ||
override fun isEnabledForCaret(editor: Editor, caret: Caret, dataContext: DataContext): Boolean { | ||
return isSupported(editor) | ||
} | ||
|
||
override fun executeInCommand(editor: Editor, dataContext: DataContext): Boolean { | ||
return false | ||
} | ||
|
||
override fun doExecute(editor: Editor, caret: Caret?, dataContext: DataContext) { | ||
if (editor.isDisposed) return | ||
val project = editor.project ?: return | ||
if (project.isDisposed) return | ||
|
||
|
||
// todo: update this to use the new API | ||
logger.info("doExecute for applyInlays") | ||
LLMInlayManager.getInstance().applyCompletion(project, editor) | ||
} | ||
} | ||
|
||
companion object { | ||
const val ID = "llm.applyInlays" | ||
|
||
val logger = logger<LLMApplyInlaysAction>() | ||
|
||
private fun isSpaceOrTab(c: Char, withNewline: Boolean): Boolean { | ||
return c == ' ' || c == '\t' || withNewline && c == '\n' | ||
} | ||
|
||
private fun isSpacesOrTabs(text: CharSequence, withNewlines: Boolean): Boolean { | ||
for (element in text) { | ||
if (!isSpaceOrTab(element, withNewlines)) { | ||
return false | ||
} | ||
} | ||
return true | ||
} | ||
|
||
private fun isNonEmptyLinePrefix(document: Document, lineNumber: Int, caretOffset: Int): Boolean { | ||
val lineStartOffset = document.getLineStartOffset(lineNumber) | ||
if (lineStartOffset == caretOffset) { | ||
return false | ||
} | ||
val linePrefix = document.getText(TextRange.create(lineStartOffset, caretOffset)) | ||
return !isSpacesOrTabs(linePrefix, false) | ||
} | ||
|
||
fun isSupported(editor: Editor): Boolean { | ||
val project = editor.project | ||
return project != null && editor | ||
.caretModel.caretCount == 1 && (LookupManager.getActiveLookup(editor) == null) && TemplateManager.getInstance( | ||
project | ||
) | ||
.getActiveTemplate(editor) == null | ||
} | ||
} | ||
} |
60 changes: 60 additions & 0 deletions
60
src/main/kotlin/cc/unitmesh/devti/editor/inlay/AutoDevEditorListener.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package cc.unitmesh.devti.editor.inlay | ||
|
||
import com.intellij.openapi.command.CommandProcessor | ||
import com.intellij.openapi.editor.Editor | ||
import com.intellij.openapi.editor.event.* | ||
import com.intellij.openapi.editor.ex.util.EditorUtil | ||
import com.intellij.openapi.util.Disposer | ||
|
||
class AutoDevEditorListener : EditorFactoryListener { | ||
override fun editorCreated(event: EditorFactoryEvent) { | ||
val editor = event.editor | ||
val project = editor.project ?: return | ||
if (project.isDisposed) return | ||
|
||
val editorDisposable = Disposer.newDisposable("autoDevEditorListener") | ||
EditorUtil.disposeWithEditor(editor, editorDisposable) | ||
|
||
editor.document.addDocumentListener(AutoDevDocumentListener(editor), editorDisposable) | ||
editor.caretModel.addCaretListener(AutoDevCaretListener(editor), editorDisposable) | ||
} | ||
|
||
class AutoDevCaretListener(val editor: Editor) : CaretListener { | ||
override fun caretPositionChanged(event: CaretEvent) { | ||
val project = editor.project | ||
if (project == null || project.isDisposed) return | ||
|
||
val llmInlayManager = LLMInlayManager.getInstance() | ||
|
||
val wasTypeOver = TypeOverHandler.getPendingTypeOverAndReset(editor) | ||
if (wasTypeOver) { | ||
llmInlayManager.editorModified(editor) | ||
return | ||
} | ||
|
||
if (CommandProcessor.getInstance().currentCommand != null) { | ||
return | ||
} | ||
|
||
llmInlayManager.disposeInlays(editor, InlayDisposeContext.CaretChange) | ||
} | ||
} | ||
|
||
class AutoDevDocumentListener(val editor: Editor) : BulkAwareDocumentListener { | ||
override fun documentChangedNonBulk(event: DocumentEvent) { | ||
val project = editor.project | ||
if (project == null || project.isDisposed) return | ||
|
||
val commandProcessor = CommandProcessor.getInstance() | ||
if (commandProcessor.isUndoTransparentActionInProgress) return | ||
if (commandProcessor.currentCommandName != null) return | ||
|
||
val changeOffset = event.offset + event.newLength | ||
if (editor.caretModel.offset != changeOffset) return | ||
|
||
val llmInlayManager = LLMInlayManager.getInstance() | ||
llmInlayManager | ||
.editorModified(editor, changeOffset) | ||
} | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
src/main/kotlin/cc/unitmesh/devti/editor/inlay/InlayDisposeContext.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package cc.unitmesh.devti.editor.inlay | ||
|
||
enum class InlayDisposeContext { | ||
UserAction, | ||
IdeCompletion, | ||
CaretChange, | ||
SelectionChange, | ||
SettingsChange, | ||
Cycling, | ||
TypingAsSuggested, | ||
Typing, | ||
Applied, | ||
; | ||
|
||
val isResetLastRequest: Boolean | ||
get() = this == SettingsChange || this == Applied | ||
val isSendRejectedTelemetry: Boolean | ||
get() = this == UserAction | ||
} |
115 changes: 115 additions & 0 deletions
115
src/main/kotlin/cc/unitmesh/devti/editor/inlay/LLMCommandListener.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package cc.unitmesh.devti.editor.inlay | ||
|
||
import com.intellij.openapi.command.CommandEvent | ||
import com.intellij.openapi.command.CommandListener | ||
import com.intellij.openapi.diagnostic.logger | ||
import com.intellij.openapi.editor.Document | ||
import com.intellij.openapi.editor.Editor | ||
import com.intellij.openapi.editor.VisualPosition | ||
import com.intellij.openapi.editor.ex.DocumentEx | ||
import com.intellij.openapi.fileEditor.FileEditorManager | ||
import com.intellij.openapi.project.Project | ||
import com.intellij.openapi.util.Key | ||
import java.util.concurrent.atomic.AtomicBoolean | ||
import java.util.concurrent.atomic.AtomicInteger | ||
import java.util.concurrent.atomic.AtomicReference | ||
|
||
private class UndoTransparentActionState(val editor: Editor, val modificationStamp: Long) | ||
private class CommandEditorState(val modificationStamp: Long, val visualPosition: VisualPosition) | ||
|
||
class LLMCommandListener(private val project: Project) : CommandListener { | ||
private val activeCommands = AtomicInteger() | ||
private val startedWithEditor = AtomicBoolean(false) | ||
private val undoTransparentActionStamp = AtomicReference<UndoTransparentActionState?>() | ||
|
||
override fun commandStarted(event: CommandEvent) { | ||
if (activeCommands.getAndIncrement() > 0) { | ||
logger.debug("Skipping nested commandStarted. Event: $event") | ||
return | ||
} | ||
|
||
val editor = getSelectedEditorSafely(project) | ||
if (editor != null) { | ||
startedWithEditor.set(true) | ||
COMMAND_STATE_KEY[editor] = createCommandState(editor) | ||
} else { | ||
startedWithEditor.set(false) | ||
} | ||
} | ||
|
||
|
||
override fun commandFinished(event: CommandEvent) { | ||
if (activeCommands.decrementAndGet() > 0) { | ||
logger.debug("Skipping nested commandFinished. Event: $event") | ||
return | ||
} | ||
|
||
if (!startedWithEditor.get()) return | ||
|
||
val editor = getSelectedEditorSafely(project) ?: return | ||
val editorManager = LLMInlayManager.getInstance() | ||
|
||
if (!editorManager.isAvailable(editor)) return | ||
|
||
val commandStartState = COMMAND_STATE_KEY[editor] ?: return | ||
val commandEndState = createCommandState(editor) | ||
if (isDocumentModification(commandStartState, commandEndState)) { | ||
logger.debug("command modified document: " + event.commandName) | ||
editorManager.editorModified(editor) | ||
} else if (isCaretPositionChange(commandStartState, commandEndState)) { | ||
editorManager.disposeInlays(editor, InlayDisposeContext.CaretChange) | ||
} | ||
} | ||
|
||
override fun undoTransparentActionStarted() { | ||
val editor = getSelectedEditorSafely(project) | ||
undoTransparentActionStamp.set(if (editor != null) createUndoTransparentState(editor) else null) | ||
} | ||
|
||
override fun undoTransparentActionFinished() { | ||
val currentEditorStamp = undoTransparentActionStamp.get() | ||
undoTransparentActionStamp.set(null) | ||
val editor = getSelectedEditorSafely(project) ?: return | ||
|
||
if (currentEditorStamp == null || editor !== currentEditorStamp.editor) return | ||
if (getDocumentStamp(editor.document) == currentEditorStamp.modificationStamp) return | ||
|
||
val editorManager = LLMInlayManager.getInstance() | ||
if (editorManager.isAvailable(editor)) { | ||
editorManager.editorModified(editor) | ||
} | ||
} | ||
|
||
private fun getSelectedEditorSafely(project: Project): Editor? { | ||
return try { | ||
FileEditorManager.getInstance(project)?.selectedTextEditor | ||
} catch (e: Exception) { | ||
null | ||
} | ||
} | ||
|
||
companion object { | ||
private val logger = logger<LLMCommandListener>() | ||
private val COMMAND_STATE_KEY = Key.create<CommandEditorState>("llm.commandState") | ||
} | ||
|
||
private fun createCommandState(editor: Editor): CommandEditorState { | ||
return CommandEditorState(getDocumentStamp(editor.document), editor.caretModel.visualPosition) | ||
} | ||
|
||
private fun createUndoTransparentState(editor: Editor): UndoTransparentActionState { | ||
return UndoTransparentActionState(editor, getDocumentStamp(editor.document)) | ||
} | ||
|
||
private fun getDocumentStamp(document: Document): Long { | ||
return if (document is DocumentEx) document.modificationSequence.toLong() else document.modificationStamp | ||
} | ||
|
||
private fun isDocumentModification(first: CommandEditorState, second: CommandEditorState): Boolean { | ||
return first.modificationStamp != second.modificationStamp | ||
} | ||
|
||
private fun isCaretPositionChange(first: CommandEditorState, second: CommandEditorState): Boolean { | ||
return first.visualPosition != second.visualPosition | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/main/kotlin/cc/unitmesh/devti/editor/inlay/LLMEditorSaveVetoer.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package cc.unitmesh.devti.editor.inlay | ||
|
||
import com.intellij.openapi.editor.Document | ||
import com.intellij.openapi.fileEditor.FileDocumentSynchronizationVetoer | ||
import com.intellij.openapi.util.UserDataHolder | ||
|
||
class LLMEditorSaveVetoer : FileDocumentSynchronizationVetoer() { | ||
override fun maySaveDocument(document: Document, isSaveExplicit: Boolean): Boolean { | ||
return !LLMInlayManagerImpl.KEY_DOCUMENT_SAVE_VETO.isIn(document as UserDataHolder) | ||
} | ||
} |
Oops, something went wrong.