diff --git a/src/extension.ts b/src/extension.ts index 53614c6..0b3c6b4 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -61,6 +61,7 @@ const previewDecorationType = vscode.window.createTextEditorDecorationType({ textDecoration: 'none; display: none;', // Hide the original text }); + async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationToken?: vscode.CancellationToken) { const document = textEditor.document; const position = textEditor.selection.active; @@ -116,40 +117,42 @@ async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationTo let previewInserted = false; let originalContent: string; let previewStartLine: number; - + let previewEndLine: number; const storeAndInsertPreview = async () => { - previewStartLine = startLine; - const endLine = document.lineCount - 1; - const endCharacter = document.lineAt(endLine).text.length; - const fullRange = new vscode.Range(startLine, 0, endLine, endCharacter); + const currentLine = position.line; + previewStartLine = currentLine; + const previewLines = completionText.split('\n'); + previewEndLine = previewStartLine + previewLines.length; + + // Ensure the previewEndLine doesn't exceed the document's line count + const documentEndLine = document.lineCount - 1; + previewEndLine = Math.min(previewEndLine, documentEndLine + 1); + + // Store original content + const fullRange = new vscode.Range(previewStartLine, 0, previewEndLine, document.lineAt(previewEndLine - 1).text.length); originalContent = document.getText(fullRange); - - const previewContent = completionText + '\n'.repeat(1); + + // Prepare the new content + const newContent = previewLines.join('\n'); + const edit = new vscode.WorkspaceEdit(); - edit.replace(document.uri, fullRange, previewContent); // Overwrite the content + edit.replace(document.uri, fullRange, newContent); await vscode.workspace.applyEdit(edit); - - // Split the preview content into lines - const previewLines = previewContent.split('\n'); - - - // Set decorations on the newly inserted lines - const previewRanges: vscode.DecorationOptions[] = []; - for (let i = 0; i < previewLines.length; i++) { - const range = new vscode.Range(previewStartLine + i, 0, previewStartLine + i, previewLines[i].length); - previewRanges.push({ - range, - renderOptions: { - after: { - contentText: previewLines[i], - } + + // Highlight only the new lines + const previewRanges: vscode.DecorationOptions[] = previewLines.map((line: string, index: number) => ({ + range: new vscode.Range(previewStartLine + index, 0, previewStartLine + index, line.length), + renderOptions: { + after: { + contentText: line, } - }); - } + } + })); textEditor.setDecorations(previewDecorationType, previewRanges); previewInserted = true; }; + const disposable = vscode.window.onDidChangeTextEditorSelection(async (event) => { const textEditor = vscode.window.activeTextEditor; if (!textEditor || !previewInserted || isHandlingChange) { @@ -162,7 +165,6 @@ async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationTo const activeSelection = textEditor.selection; const changeStartLine = activeSelection.active.line; - // Detect Tab key press by checking the active selection if (event.kind === vscode.TextEditorSelectionChangeKind.Keyboard && changeStartLine >= previewStartLine) { const changeText = textEditor.document.getText(activeSelection); @@ -176,7 +178,6 @@ async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationTo } }); - // Handles Enter key separately vscode.workspace.onDidChangeTextDocument(async (event) => { const textEditor = vscode.window.activeTextEditor; if (!textEditor || event.document.uri.toString() !== textEditor.document.uri.toString() || !previewInserted || isHandlingChange) { @@ -190,15 +191,12 @@ async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationTo const changeStartLine = change.range.start.line; if (change.text.includes('\n') && changeStartLine >= previewStartLine) { - // Accept the preview and move to the next line await acceptPreview(textEditor, textEditor.document, startLine, textEditor.selection.active, completionText); await vscode.commands.executeCommand('default:type', { text: '\n' }); break; } - // Handle Backspace if (change.text === '' && change.rangeLength === 1 && changeStartLine >= previewStartLine) { - // Discard the preview if Backspace is pressed await restoreOriginalContent(); break; } @@ -208,72 +206,46 @@ async function autocompleteCommand(textEditor: vscode.TextEditor, cancellationTo } }); - vscode.window.onDidChangeTextEditorSelection(async (event) => { - const textEditor = vscode.window.activeTextEditor; - if (!textEditor || !previewInserted || isHandlingChange) { - return; - } - - isHandlingChange = true; - - try { - // Handle arrow keys or any other navigation keys - const currentSelection = event.selections[0]; - const { document } = textEditor; - - // Detect unwanted acceptance from simple navigation - if (currentSelection.start.line < previewStartLine) { - await restoreOriginalContent(); - } - } finally { - isHandlingChange = false; - } - }); - - - - - // Restore original content if Backspace is pressed (decline the preview) const restoreOriginalContent = async () => { if (!previewInserted) return; - - const endLine = document.lineCount - 1; - const fullRange = new vscode.Range(previewStartLine, 0, endLine, document.lineAt(endLine).text.length); + + const fullRange = new vscode.Range(previewStartLine, 0, previewEndLine, 0); const edit = new vscode.WorkspaceEdit(); - + edit.replace(document.uri, fullRange, originalContent); await vscode.workspace.applyEdit(edit); - + textEditor.setDecorations(previewDecorationType, []); previewInserted = false; disposable.dispose(); // Cancel listener when preview is discarded }; - - // Accept the preview when Tab is pressed + const acceptPreview = async (textEditor: vscode.TextEditor, document: vscode.TextDocument, startLine: number, position: vscode.Position, completionText: string) => { textEditor.setDecorations(previewDecorationType, []); const edit = new vscode.WorkspaceEdit(); - - // Adjust the insertion logic to avoid duplicate newlines - const insertText = completionText; - - // Replace the range from the start of the context to the current position - const replaceRange = new vscode.Range(startLine, 0, position.line, position.character); - edit.replace(document.uri, replaceRange, insertText); - + + const previewLines = completionText.split('\n'); + const endLine = startLine + previewLines.length; + + // Ensure that endLine does not exceed document bounds + const documentEndLine = document.lineCount - 1; + const finalEndLine = Math.min(endLine, documentEndLine + 1); + + // Prepare the new content + const newContent = previewLines.join('\n'); + + // Replace the range with the new content + const replaceRange = new vscode.Range(startLine, 0, finalEndLine, document.lineAt(finalEndLine - 1).text.length); + edit.replace(document.uri, replaceRange, newContent.trim()); + await vscode.workspace.applyEdit(edit); await document.save(); - + disposable.dispose(); // Cancel listener when preview is accepted previewInserted = false; }; - - // Call this function to initiate the preview + await storeAndInsertPreview(); - - - - } catch (err: any) { vscode.window.showErrorMessage( "Fabelous Autocoder encountered an error: " + err.message