From 58c9af02562d145106103539e6e6f0b88439f42a Mon Sep 17 00:00:00 2001 From: Falko Habel Date: Tue, 10 Sep 2024 19:51:03 +0200 Subject: [PATCH 1/3] preview added but badly --- src/extension.ts | 72 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 17 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 12078e7..a738fc5 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -53,13 +53,19 @@ function createFIMPrompt(prefix: string, language: string): string { return `${prefix}${language}\n`; } +const previewDecorationType = vscode.window.createTextEditorDecorationType({ + after: { + color: '#888888', // Grayed-out preview text + fontStyle: 'italic', + }, + isWholeLine: true, // Support multiline properly +}); async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationToken?: vscode.CancellationToken) { const document = textEditor.document; const position = textEditor.selection.active; const context = getContextLines(document, position); - const fimPrompt = createFIMPrompt(context, document.languageId); vscode.window.withProgress( @@ -102,27 +108,58 @@ async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationTo progress.report({ message: "Generating..." }); let completionText = response.data.response; - // Remove any FIM tags and leading/trailing whitespace completionText = completionText.replace(/||/g, '').trim(); - // Remove the context lines - const startLine = Math.max(0, position.line - 1); - const endLine = position.line; - const rangeToReplace = new vscode.Range( - new vscode.Position(startLine, 0), - new vscode.Position(endLine, document.lineAt(endLine).text.length) - ); + // Handle multiline text by splitting it into lines + const lines = completionText.split('\n'); + const previewRanges = lines.map((line: string, idx: number) => { + const linePos = new vscode.Position(position.line + idx, 0); + const range = new vscode.Range(linePos, linePos); + return { + range, + renderOptions: { + after: { + contentText: line, // Show each line + } + } + }; + }); - // Apply the edit - const edit = new vscode.WorkspaceEdit(); - edit.replace(document.uri, rangeToReplace, completionText); - await vscode.workspace.applyEdit(edit); + textEditor.setDecorations(previewDecorationType, previewRanges); - // Move the cursor to the end of the inserted text - const newPosition = new vscode.Position(startLine + completionText.split('\n').length - 1, completionText.split('\n').pop()!.length); - textEditor.selection = new vscode.Selection(newPosition, newPosition); + const disposable = vscode.workspace.onDidChangeTextDocument(async (event) => { + if (event.document.uri.toString() === document.uri.toString()) { + const change = event.contentChanges[0]; - progress.report({ message: "Fabelous completion finished." }); + // Handle Backspace to decline the preview + if (change && change.text === '' && change.rangeLength === 1) { + textEditor.setDecorations(previewDecorationType, []); + disposable.dispose(); + } + + // Handle Ctrl + Enter (or Cmd + Enter on macOS) to accept the preview + const isCtrlOrCmdPressed = event.contentChanges.some( + (change) => { + const isMac = process.platform === 'darwin'; + const isCtrlOrCmd = isMac ? change.text.includes('\u0010') : change.text.includes('\n'); + return isCtrlOrCmd; + } + ); + + if (isCtrlOrCmdPressed) { + const edit = new vscode.WorkspaceEdit(); + const insertPosition = new vscode.Position(position.line, 0); + edit.insert(document.uri, insertPosition, '\n' + completionText); + await vscode.workspace.applyEdit(edit); + + const newPosition = new vscode.Position(position.line + lines.length, lines[lines.length - 1].length); + textEditor.selection = new vscode.Selection(newPosition, newPosition); + + textEditor.setDecorations(previewDecorationType, []); + disposable.dispose(); + } + } + }); } catch (err: any) { vscode.window.showErrorMessage( @@ -135,6 +172,7 @@ async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationTo } + async function provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, cancellationToken: vscode.CancellationToken) { const item = new vscode.CompletionItem("Fabelous autocompletion"); item.insertText = new vscode.SnippetString('${1:}'); From 916ea8ca4a1560c37cbddb9c96623ea41011bcaf Mon Sep 17 00:00:00 2001 From: Falko Habel Date: Tue, 10 Sep 2024 20:34:10 +0200 Subject: [PATCH 2/3] new code with partically work preview --- src/extension.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index a738fc5..02fd31d 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -53,12 +53,13 @@ function createFIMPrompt(prefix: string, language: string): string { return `${prefix}${language}\n`; } + const previewDecorationType = vscode.window.createTextEditorDecorationType({ after: { color: '#888888', // Grayed-out preview text fontStyle: 'italic', }, - isWholeLine: true, // Support multiline properly + isWholeLine: true, // Ensure it handles multiline properly }); async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationToken?: vscode.CancellationToken) { @@ -119,12 +120,13 @@ async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationTo range, renderOptions: { after: { - contentText: line, // Show each line + contentText: line, // Show each line properly } } }; }); + // Set decorations for each line textEditor.setDecorations(previewDecorationType, previewRanges); const disposable = vscode.workspace.onDidChangeTextDocument(async (event) => { @@ -150,7 +152,11 @@ async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationTo const edit = new vscode.WorkspaceEdit(); const insertPosition = new vscode.Position(position.line, 0); edit.insert(document.uri, insertPosition, '\n' + completionText); - await vscode.workspace.applyEdit(edit); + + // Ensure response is added only once + if (!document.getText().includes(completionText)) { + await vscode.workspace.applyEdit(edit); + } const newPosition = new vscode.Position(position.line + lines.length, lines[lines.length - 1].length); textEditor.selection = new vscode.Selection(newPosition, newPosition); @@ -173,6 +179,7 @@ async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationTo + async function provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, cancellationToken: vscode.CancellationToken) { const item = new vscode.CompletionItem("Fabelous autocompletion"); item.insertText = new vscode.SnippetString('${1:}'); From 0450a222e23b91adb6debd9d5d5f572d3881491b Mon Sep 17 00:00:00 2001 From: Falko Habel Date: Wed, 11 Sep 2024 09:41:59 +0200 Subject: [PATCH 3/3] added semi working preview --- src/extension.ts | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 02fd31d..1106a6c 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -53,13 +53,10 @@ function createFIMPrompt(prefix: string, language: string): string { return `${prefix}${language}\n`; } - const previewDecorationType = vscode.window.createTextEditorDecorationType({ - after: { - color: '#888888', // Grayed-out preview text - fontStyle: 'italic', - }, - isWholeLine: true, // Ensure it handles multiline properly + color: '#888888', // Grayed-out preview text + fontStyle: 'italic', + rangeBehavior: vscode.DecorationRangeBehavior.ClosedOpen, // Ensure proper handling of multiline decorations }); async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationToken?: vscode.CancellationToken) { @@ -111,22 +108,26 @@ async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationTo let completionText = response.data.response; completionText = completionText.replace(/||/g, '').trim(); - // Handle multiline text by splitting it into lines + // Split the completion text by new lines const lines = completionText.split('\n'); + + // Create a decoration for each line of the response const previewRanges = lines.map((line: string, idx: number) => { const linePos = new vscode.Position(position.line + idx, 0); - const range = new vscode.Range(linePos, linePos); + const range = new vscode.Range(linePos, linePos); // Set range at the start of each new line return { range, renderOptions: { - after: { - contentText: line, // Show each line properly + before: { + contentText: line, + color: '#888888', + fontStyle: 'italic', } } }; }); - // Set decorations for each line + // Apply the decorations for multiline preview textEditor.setDecorations(previewDecorationType, previewRanges); const disposable = vscode.workspace.onDidChangeTextDocument(async (event) => { @@ -135,7 +136,7 @@ async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationTo // Handle Backspace to decline the preview if (change && change.text === '' && change.rangeLength === 1) { - textEditor.setDecorations(previewDecorationType, []); + textEditor.setDecorations(previewDecorationType, []); // Remove preview decorations disposable.dispose(); } @@ -149,20 +150,22 @@ async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationTo ); if (isCtrlOrCmdPressed) { + // Remove the preview decoration before applying the final completion + textEditor.setDecorations(previewDecorationType, []); + const edit = new vscode.WorkspaceEdit(); const insertPosition = new vscode.Position(position.line, 0); - edit.insert(document.uri, insertPosition, '\n' + completionText); - // Ensure response is added only once + // Insert the completion only once if (!document.getText().includes(completionText)) { + edit.insert(document.uri, insertPosition, '\n' + completionText); await vscode.workspace.applyEdit(edit); } const newPosition = new vscode.Position(position.line + lines.length, lines[lines.length - 1].length); textEditor.selection = new vscode.Selection(newPosition, newPosition); - textEditor.setDecorations(previewDecorationType, []); - disposable.dispose(); + disposable.dispose(); // Clean up the listener after accepting the completion } } }); @@ -179,7 +182,6 @@ async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationTo - async function provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, cancellationToken: vscode.CancellationToken) { const item = new vscode.CompletionItem("Fabelous autocompletion"); item.insertText = new vscode.SnippetString('${1:}');