diff --git a/extensions/void/src/DisplayChangesProvider.ts b/extensions/void/src/DisplayChangesProvider.ts index 31c2a28a..2b6bed37 100644 --- a/extensions/void/src/DisplayChangesProvider.ts +++ b/extensions/void/src/DisplayChangesProvider.ts @@ -1,13 +1,8 @@ import * as vscode from 'vscode'; import { SuggestedEdit } from './getDiffedLines'; +import { Diff, DiffArea } from './shared_types'; + -// each diff on the user's screen right now -type DiffType = { - diffid: number, - lenses: vscode.CodeLens[], - greenRange: vscode.Range, - originalCode: string, // If a revert happens, we replace the greenRange with this content. -} // TODO in theory this should be disposed const greenDecoration = vscode.window.createTextEditorDecorationType({ @@ -19,7 +14,9 @@ const greenDecoration = vscode.window.createTextEditorDecorationType({ // responsible for displaying diffs and showing accept/reject buttons export class ApplyChangesProvider implements vscode.CodeLensProvider { - private _diffsOfDocument: { [docUriStr: string]: DiffType[] } = {}; + private _diffAreasOfDocument: { [docUriStr: string]: DiffArea[] } = {} + private _diffsOfDocument: { [docUriStr: string]: Diff[] } = {} + private _computedLensesOfDocument: { [docUriStr: string]: vscode.CodeLens[] } = {} // computed from diffsOfDocument[docUriStr].lenses private _diffidPool = 0 private _weAreEditing: boolean = false @@ -32,7 +29,7 @@ export class ApplyChangesProvider implements vscode.CodeLensProvider { // used internally by vscode public provideCodeLenses(document: vscode.TextDocument, token: vscode.CancellationToken): vscode.ProviderResult { const docUriStr = document.uri.toString() - return this._computedLensesOfDocument[docUriStr] + return this._diffsOfDocument[docUriStr].flatMap(diff => diff.lenses) } // declared by us, registered with vscode.languages.registerCodeLensProvider() @@ -51,7 +48,6 @@ export class ApplyChangesProvider implements vscode.CodeLensProvider { this._diffsOfDocument[docUriStr].splice(0) // clear diffs editor.setDecorations(greenDecoration, []) // clear decorations - this._computedLensesOfDocument[docUriStr] = this._diffsOfDocument[docUriStr].flatMap(diff => diff.lenses) // recompute codelenses this._onDidChangeCodeLenses.fire() // rerender codelenses }) } @@ -59,7 +55,7 @@ export class ApplyChangesProvider implements vscode.CodeLensProvider { // used by us only private refreshLenses = (editor: vscode.TextEditor, docUriStr: string) => { editor.setDecorations(greenDecoration, this._diffsOfDocument[docUriStr].map(diff => diff.greenRange)) // refresh highlighting - this._computedLensesOfDocument[docUriStr] = this._diffsOfDocument[docUriStr].flatMap(diff => diff.lenses) // recompute _computedLensesOfDocument (can optimize this later) + this._onDidChangeCodeLenses.fire() // fire event for vscode to refresh lenses } @@ -72,9 +68,6 @@ export class ApplyChangesProvider implements vscode.CodeLensProvider { // if no diffs, set diffs to [] if (!this._diffsOfDocument[docUriStr]) this._diffsOfDocument[docUriStr] = [] - // if no codelenses, set codelenses to [] - if (!this._computedLensesOfDocument[docUriStr]) - this._computedLensesOfDocument[docUriStr] = [] // 1. convert suggested edits (which are described using line numbers) into actual edits (described using vscode.Range, vscode.Uri) diff --git a/extensions/void/src/extension.ts b/extensions/void/src/extension.ts index ab12b252..b85a9b7d 100644 --- a/extensions/void/src/extension.ts +++ b/extensions/void/src/extension.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode'; -import { WebviewMessage } from './shared_types'; +import { DiffArea, WebviewMessage } from './shared_types'; import { CtrlKCodeLensProvider } from './CtrlKCodeLensProvider'; import { getDiffedLines } from './getDiffedLines'; import { ApplyChangesProvider as DisplayChangesProvider } from './DisplayChangesProvider'; @@ -121,12 +121,28 @@ export function activate(context: vscode.ExtensionContext) { return } - const beforeCode = await readFileContentOfUri(editor.document.uri) + const diffArea: DiffArea = { + startLine: 0, // in ctrl+L the start and end lines are the full document + endLine: editor.document.lineCount, + originalCode: undefined, + } - // TODO change this to be animated - const suggestedEdits = getDiffedLines(beforeCode, m.code) + // save the original code + diffArea.originalCode = await readFileContentOfUri(editor.document.uri) - // when changes have been created + // write the new code `m.code` to the document + // TODO make this animated + editor.edit(editBuilder => { + editBuilder.replace(new vscode.Range(diffArea.startLine, 0, diffArea.endLine, 0), m.code); + }); + + + // rediff the changes based on the diffArea (start, end, original code, current code) + + + + // TODO!!! put this logic in `displayChangesProvider.displayChanges(diffArea)` function + const suggestedEdits = getDiffedLines(diffArea.originalCode, m.code) await displayChangesProvider.addNewChanges(editor, suggestedEdits) } else if (m.type === 'getApiConfig') { diff --git a/extensions/void/src/shared_types.ts b/extensions/void/src/shared_types.ts index 81efbe71..da4381ea 100644 --- a/extensions/void/src/shared_types.ts +++ b/extensions/void/src/shared_types.ts @@ -3,14 +3,29 @@ import * as vscode from 'vscode'; import { ApiConfig } from './common/sendLLMMessage'; // a selection is a frozen snapshot -type Selection = { selectionStr: string, selectionRange: vscode.Range, filePath: vscode.Uri } +type CodeSelection = { selectionStr: string, selectionRange: vscode.Range, filePath: vscode.Uri } type File = { filepath: vscode.Uri, content: string } +// an area that is currently being diffed +type DiffArea = { + startLine: number, + endLine: number, + originalCode: string | undefined +} + +// each diff on the user's screen right now +type Diff = { + diffid: number, + lenses: vscode.CodeLens[], + greenRange: vscode.Range, + originalCode: string, // If a revert happens, we replace the greenRange with this content. +} + type WebviewMessage = ( // editor -> sidebar - | { type: 'ctrl+l', selection: Selection } // user presses ctrl+l in the editor + | { type: 'ctrl+l', selection: CodeSelection } // user presses ctrl+l in the editor // sidebar -> editor | { type: 'applyChanges', code: string } // user clicks "apply" in the sidebar @@ -32,8 +47,9 @@ type WebviewMessage = ( type Command = WebviewMessage['type'] export { - Selection, + CodeSelection, File, WebviewMessage, Command, + Diff, DiffArea, } diff --git a/extensions/void/src/sidebar/Sidebar.tsx b/extensions/void/src/sidebar/Sidebar.tsx index 5cb9f9c8..cfa8d3a7 100644 --- a/extensions/void/src/sidebar/Sidebar.tsx +++ b/extensions/void/src/sidebar/Sidebar.tsx @@ -1,6 +1,6 @@ import React, { useState, ChangeEvent, useEffect, useRef, useCallback, FormEvent } from "react" import { ApiConfig, LLMMessage, sendLLMMessage } from "../common/sendLLMMessage" -import { Command, File, Selection, WebviewMessage } from "../shared_types" +import { Command, File, CodeSelection, WebviewMessage } from "../shared_types" import { awaitVSCodeResponse, getVSCodeAPI, resolveAwaitingVSCodeResponse } from "./getVscodeApi" import { marked } from 'marked'; @@ -18,7 +18,7 @@ ${content} \`\`\``).join('\n') } -const userInstructionsStr = (instructions: string, files: File[], selection: Selection | null) => { +const userInstructionsStr = (instructions: string, files: File[], selection: CodeSelection | null) => { return ` ${filesStr(files)} @@ -110,7 +110,7 @@ type ChatMessage = { role: 'user' content: string, // content sent to the llm displayContent: string, // content displayed to user - selection: Selection | null, // the user's selection + selection: CodeSelection | null, // the user's selection files: vscode.Uri[], // the files sent in the message } | { role: 'assistant', @@ -136,7 +136,7 @@ const useInstantState = (initVal: T) => { const Sidebar = () => { // state of current message - const [selection, setSelection] = useState(null) // the code the user is selecting + const [selection, setSelection] = useState(null) // the code the user is selecting const [files, setFiles] = useState([]) // the names of the files in the chat const [instructions, setInstructions] = useState('') // the user's instructions