Skip to content

Commit

Permalink
optimize code editor insertion
Browse files Browse the repository at this point in the history
  • Loading branch information
nighca committed Feb 6, 2025
1 parent b6ceff3 commit abd3570
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 11 deletions.
12 changes: 6 additions & 6 deletions spx-gui/src/components/editor/code-editor/code-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ import {
type CommandArgs,
getTextDocumentId,
containsPosition,
makeBasicMarkdownString,
type WorkspaceDiagnostics,
type TextDocumentDiagnostics,
fromLSPDiagnostic
Expand Down Expand Up @@ -273,6 +272,11 @@ class CompletionProvider implements ICompletionProvider {
documentation: null
}

if (item.insertText != null) {
result.insertText = item.insertText
result.insertTextFormat = this.getInsertTextFormat(item.insertTextFormat)
}

const defId = item.data?.definition
const definition = defId != null ? await this.documentBase.getDocumentation(defId) : null

Expand All @@ -284,18 +288,14 @@ class CompletionProvider implements ICompletionProvider {
result.kind = definition.kind
result.insertText = definition.insertText
result.insertTextFormat = InsertTextFormat.Snippet
result.documentation = makeBasicMarkdownString(definition.overview)
result.documentation = definition.detail
}

if (item.documentation != null) {
const docStr = lsp.MarkupContent.is(item.documentation) ? item.documentation.value : item.documentation
result.documentation = makeAdvancedMarkdownString(docStr)
}

if (item.insertText != null) {
result.insertText = item.insertText
result.insertTextFormat = this.getInsertTextFormat(item.insertTextFormat)
}
return result
})
)
Expand Down
4 changes: 4 additions & 0 deletions spx-gui/src/components/editor/code-editor/text-document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ export class TextDocument
return this.monacoTextModel.getValueInRange(toMonacoRange(range))
}

getLineContent(line: number): string {
return this.monacoTextModel.getLineContent(line)
}

getWordAtPosition(position: Position): WordAtPosition | null {
return this.monacoTextModel.getWordAtPosition(toMonacoPosition(position))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script setup lang="ts">
import { useMessageHandle } from '@/utils/exception'
import { UITooltip } from '@/components/ui'
import { DefinitionKind } from '../../common'
import DefinitionOverviewWrapper from '../definition/DefinitionOverviewWrapper.vue'
import DefinitionDetailWrapper from '../definition/DefinitionDetailWrapper.vue'
import MarkdownView from '../markdown/MarkdownView.vue'
Expand All @@ -14,10 +15,21 @@ const props = defineProps<{
const codeEditorCtx = useCodeEditorUICtx()
const handleInsert = useMessageHandle(() => codeEditorCtx.ui.insertSnippet(props.item.insertText), {
en: 'Failed to insert',
zh: '插入失败'
}).fn
const blockDefinitionKinds = [DefinitionKind.Command, DefinitionKind.Listen, DefinitionKind.Statement]
const handleInsert = useMessageHandle(
() => {
if (blockDefinitionKinds.includes(props.item.kind)) {
codeEditorCtx.ui.insertBlockSnippet(props.item.insertText)
} else {
codeEditorCtx.ui.insertInlineSnippet(props.item.insertText)
}
},
{
en: 'Failed to insert',
zh: '插入失败'
}
).fn
const handleExplain = useMessageHandle(
() =>
Expand Down
76 changes: 76 additions & 0 deletions spx-gui/src/components/editor/code-editor/ui/code-editor-ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,78 @@ export class CodeEditorUI extends Disposable implements ICodeEditorUI {
this.editor.focus()
}

private ensureEOLLast(textDocument: TextDocument, position: Position) {
const offset = textDocument.getOffsetAt(position)
const value = textDocument.getValue()
if (offset === value.length && value[offset - 1] !== '\n') {
this.insertText('\n', { start: position, end: position })
}
}

private async insertInlineContent(
content: string,
range: Range = this.getSelectionRange(),
insertFn: typeof this.insertText
) {
const textDocument = this.activeTextDocument
if (textDocument == null) return
const insertContent = async (cnt: string, rg: Range) => {
await insertFn(cnt, rg)
this.ensureEOLLast(textDocument, rg.end)
}
if (!isRangeEmpty(range)) return insertContent(content, range)
const position = range.start
const line = textDocument.getLineContent(position.line)
if (isEmptyText(line)) return insertContent(content, range)
const word = textDocument.getWordAtPosition(position)
if (word == null) return insertContent(content, range)
const isPositionInWord = position.column >= word.startColumn && position.column <= word.endColumn
if (isPositionInWord) {
const wordEnd = { line: position.line, column: word.endColumn }
this.editor.setPosition(toMonacoPosition(wordEnd))
return insertContent(' ' + content, { start: wordEnd, end: wordEnd })
}
return insertContent(content, range)
}

private async insertBlockContent(
content: string,
range: Range = this.getSelectionRange(),
insertFn: typeof this.insertText
) {
const textDocument = this.activeTextDocument
if (textDocument == null) return
const insertContent = async (cnt: string, rg: Range) => {
await insertFn(cnt, rg)
this.ensureEOLLast(textDocument, rg.end)
}
let position = range.end
const line = textDocument.getLineContent(position.line)
if (isEmptyText(line)) return insertContent(content, range)
const lineHead = { line: position.line, column: 1 }
const beforePosition = textDocument.getValueInRange({ start: lineHead, end: position })
if (isEmptyText(beforePosition)) return insertContent(content + '\n', range)
position = { line: position.line, column: line.length + 1 }
this.editor.setPosition(toMonacoPosition(position))
return insertContent('\n' + content, { start: position, end: position }) // proper indentation needed here
}

async insertInlineText(text: string, range: Range = this.getSelectionRange()) {
return this.insertInlineContent(text, range, this.insertText.bind(this))
}

async insertInlineSnippet(snippet: string, range: Range = this.getSelectionRange()) {
return this.insertInlineContent(snippet, range, this.insertSnippet.bind(this))
}

async insertBlockText(text: string, range: Range = this.getSelectionRange()) {
return this.insertBlockContent(text, range, this.insertText.bind(this))
}

async insertBlockSnippet(snippet: string, range: Range = this.getSelectionRange()) {
return this.insertBlockContent(snippet, range, this.insertSnippet.bind(this))
}

private cursorPositionRef = shallowRef<Position | null>(null)
/** Cursor position (in current active text document) */
get cursorPosition() {
Expand Down Expand Up @@ -478,3 +550,7 @@ export class CodeEditorUI extends Disposable implements ICodeEditorUI {
super.dispose()
}
}

function isEmptyText(s: string) {
return /^\s*$/.test(s)
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const code = useSlotText()
const handleInsert = useMessageHandle(
() =>
editorCtx.project.history.doAction({ name: { en: 'Insert code', zh: '插入代码' } }, () =>
codeEditorUICtx.ui.insertText(code.value)
codeEditorUICtx.ui.insertBlockText(code.value)
),
{ en: 'Failed to insert code', zh: '插入代码失败' }
).fn
Expand Down

0 comments on commit abd3570

Please sign in to comment.