diff --git a/extensions/void/src/DisplayChangesProvider.ts b/extensions/void/src/DisplayChangesProvider.ts index 36012174..306b262d 100644 --- a/extensions/void/src/DisplayChangesProvider.ts +++ b/extensions/void/src/DisplayChangesProvider.ts @@ -1,5 +1,5 @@ import * as vscode from 'vscode'; -import { SuggestedEdit } from './getDiffedLines'; +import { getDiffedLines, SuggestedDiff } from './getDiffedLines'; import { Diff, DiffArea } from './shared_types'; @@ -24,7 +24,6 @@ export class ApplyChangesProvider implements vscode.CodeLensProvider { private _onDidChangeCodeLenses: vscode.EventEmitter = new vscode.EventEmitter(); // signals a UI refresh on .fire() events public readonly onDidChangeCodeLenses: vscode.Event = this._onDidChangeCodeLenses.event; - // used internally by vscode public provideCodeLenses(document: vscode.TextDocument, token: vscode.CancellationToken): vscode.ProviderResult { const docUriStr = document.uri.toString() @@ -33,6 +32,9 @@ export class ApplyChangesProvider implements vscode.CodeLensProvider { // declared by us, registered with vscode.languages.registerCodeLensProvider() constructor() { + + console.log('Creating DisplayChangesProvider') + // this acts as a useEffect. Every time text changes, clear the diffs in this editor vscode.workspace.onDidChangeTextDocument((e) => { const editor = vscode.window.activeTextEditor @@ -43,25 +45,82 @@ export class ApplyChangesProvider implements vscode.CodeLensProvider { return const docUri = editor.document.uri - const docUriStr = docUri.toString() - this._diffsOfDocument[docUriStr].splice(0) // clear diffs - editor.setDecorations(greenDecoration, []) // clear decorations + this.refreshDiffAreas(docUri) + + // const docUriStr = docUri.toString() + // this._diffAreasOfDocument[docUriStr].splice(0) // clear diff areas + // this._diffsOfDocument[docUriStr].splice(0) // clear diffs + // editor.setDecorations(greenDecoration, []) // clear decorations + // this._onDidChangeCodeLenses.fire() // rerender codelenses + - this._onDidChangeCodeLenses.fire() // rerender codelenses }) } - // used by us only - private refreshLenses = (editor: vscode.TextEditor, docUriStr: string) => { - editor.setDecorations(greenDecoration, this._diffsOfDocument[docUriStr].map(diff => diff.greenRange)) // refresh highlighting - this._onDidChangeCodeLenses.fire() // fire event for vscode to refresh lenses + // used by us only + public addDiffArea(uri: vscode.Uri, diffArea: DiffArea) { + + const uriStr = uri.toString() + + // make sure array is defined + if (!this._diffAreasOfDocument[uriStr]) + this._diffAreasOfDocument[uriStr] = [] + + // TODO!!! replace all areas that it is overlapping with + + + + // add diffArea to storage + this._diffAreasOfDocument[uriStr].push(diffArea) + + } + + + // used by us only + public refreshDiffAreas(docUri: vscode.Uri) { + + const editor = vscode.window.activeTextEditor // TODO the editor should be that of `docUri` and not necessarily the current editor + if (!editor) { + console.log('Error: No active editor!') + return; + } + + const docUriStr = docUri.toString() + const diffAreas = this._diffAreasOfDocument[docUriStr] || [] + + // reset all diffs (we update them below) + this._diffsOfDocument[docUriStr] = [] + + // for each diffArea + console.log('diffAreas.length:', diffAreas.length) + for (const diffArea of diffAreas) { + + // get code inside of diffArea + const currentCode = editor.document.getText(new vscode.Range(diffArea.startLine, 0, diffArea.endLine, Number.MAX_SAFE_INTEGER)) + + // compute the diffs + const diffs = getDiffedLines(diffArea.originalCode, currentCode) + + console.log('originalCode:', diffArea.originalCode) + console.log('currentCode:', currentCode) + + // add the diffs to `this._diffsOfDocument[docUriStr]` + this.addDiffs(editor.document.uri, diffs) + + } + + // update highlighting + editor.setDecorations(greenDecoration, this._diffsOfDocument[docUriStr].map(diff => diff.greenRange)) + + // update code lenses + this._onDidChangeCodeLenses.fire() + } // used by us only - public async addNewChanges(editor: vscode.TextEditor, suggestedEdits: SuggestedEdit[]) { + public addDiffs(docUri: vscode.Uri, diffs: SuggestedDiff[]) { - const docUri = editor.document.uri const docUriStr = docUri.toString() // if no diffs, set diffs to [] @@ -69,39 +128,39 @@ export class ApplyChangesProvider implements vscode.CodeLensProvider { this._diffsOfDocument[docUriStr] = [] - // 1. convert suggested edits (which are described using line numbers) into actual edits (described using vscode.Range, vscode.Uri) + // 1. convert suggested diffs (which are described using line numbers) into actual diffs (described using vscode.Range, vscode.Uri) // must do this before adding codelenses or highlighting so that codelens and highlights will apply to the fresh code and not the old code // apply changes in reverse order so additions don't push down the line numbers of the next edit let workspaceEdit = new vscode.WorkspaceEdit(); - for (let i = suggestedEdits.length - 1; i > -1; i -= 1) { - let suggestedEdit = suggestedEdits[i] + for (let i = diffs.length - 1; i > -1; i -= 1) { + let suggestedDiff = diffs[i] let greenRange: vscode.Range // INSERTIONS (e.g. {originalStartLine: 0, originalEndLine: -1}) - if (suggestedEdit.originalStartLine > suggestedEdit.originalEndLine) { - const originalPosition = new vscode.Position(suggestedEdit.originalStartLine, 0) - workspaceEdit.insert(docUri, originalPosition, suggestedEdit.afterCode + '\n') // add back in the line we deleted when we made the startline->endline range go negative - greenRange = new vscode.Range(suggestedEdit.startLine, 0, suggestedEdit.endLine + 1, 0) + if (suggestedDiff.originalStartLine > suggestedDiff.originalEndLine) { + const originalPosition = new vscode.Position(suggestedDiff.originalStartLine, 0) + workspaceEdit.insert(docUri, originalPosition, suggestedDiff.afterCode + '\n') // add back in the line we deleted when we made the startline->endline range go negative + greenRange = new vscode.Range(suggestedDiff.startLine, 0, suggestedDiff.endLine + 1, 0) } // DELETIONS - else if (suggestedEdit.startLine > suggestedEdit.endLine) { - const deleteRange = new vscode.Range(suggestedEdit.originalStartLine, 0, suggestedEdit.originalEndLine + 1, 0) + else if (suggestedDiff.startLine > suggestedDiff.endLine) { + const deleteRange = new vscode.Range(suggestedDiff.originalStartLine, 0, suggestedDiff.originalEndLine + 1, 0) workspaceEdit.delete(docUri, deleteRange) - greenRange = new vscode.Range(suggestedEdit.startLine, 0, suggestedEdit.startLine, 0) - suggestedEdit.beforeCode += '\n' // add back in the line we deleted when we made the startline->endline range go negative + greenRange = new vscode.Range(suggestedDiff.startLine, 0, suggestedDiff.startLine, 0) + suggestedDiff.beforeCode += '\n' // add back in the line we deleted when we made the startline->endline range go negative } // REPLACEMENTS else { - const originalRange = new vscode.Range(suggestedEdit.originalStartLine, 0, suggestedEdit.originalEndLine, Number.MAX_SAFE_INTEGER) - workspaceEdit.replace(docUri, originalRange, suggestedEdit.afterCode) - greenRange = new vscode.Range(suggestedEdit.startLine, 0, suggestedEdit.endLine, Number.MAX_SAFE_INTEGER) + const originalRange = new vscode.Range(suggestedDiff.originalStartLine, 0, suggestedDiff.originalEndLine, Number.MAX_SAFE_INTEGER) + workspaceEdit.replace(docUri, originalRange, suggestedDiff.afterCode) + greenRange = new vscode.Range(suggestedDiff.startLine, 0, suggestedDiff.endLine, Number.MAX_SAFE_INTEGER) } this._diffsOfDocument[docUriStr].push({ diffid: this._diffidPool, greenRange: greenRange, - originalCode: suggestedEdit.beforeCode, + originalCode: suggestedDiff.beforeCode, lenses: [ new vscode.CodeLens(greenRange, { title: 'Accept', command: 'void.acceptDiff', arguments: [{ diffid: this._diffidPool }] }), new vscode.CodeLens(greenRange, { title: 'Reject', command: 'void.rejectDiff', arguments: [{ diffid: this._diffidPool }] }) @@ -110,15 +169,7 @@ export class ApplyChangesProvider implements vscode.CodeLensProvider { this._diffidPool += 1 } - this._weAreEditing = true - await vscode.workspace.applyEdit(workspaceEdit) - await vscode.workspace.save(docUri) - this._weAreEditing = false - - // refresh - this.refreshLenses(editor, docUriStr) - - console.log('diffs after added:', this._diffsOfDocument[docUriStr]) + console.log('diffs:', this._diffsOfDocument[docUriStr]) } // called on void.acceptDiff @@ -142,7 +193,7 @@ export class ApplyChangesProvider implements vscode.CodeLensProvider { this._diffsOfDocument[docUriStr].splice(index, 1) // refresh - this.refreshLenses(editor, docUriStr) + this.refreshDiffAreas(docUri) } @@ -179,6 +230,6 @@ export class ApplyChangesProvider implements vscode.CodeLensProvider { this._weAreEditing = false // refresh - this.refreshLenses(editor, docUriStr) + this.refreshDiffAreas(docUri) } } diff --git a/extensions/void/src/extension.ts b/extensions/void/src/extension.ts index b85a9b7d..2c45415d 100644 --- a/extensions/void/src/extension.ts +++ b/extensions/void/src/extension.ts @@ -115,35 +115,38 @@ export function activate(context: vscode.ExtensionContext) { } else if (m.type === 'applyChanges') { + console.log('Applying changes') + const editor = vscode.window.activeTextEditor if (!editor) { vscode.window.showInformationMessage('No active editor!') return } + // create an area to show diffs const diffArea: DiffArea = { startLine: 0, // in ctrl+L the start and end lines are the full document endLine: editor.document.lineCount, - originalCode: undefined, + originalCode: await readFileContentOfUri(editor.document.uri), } + displayChangesProvider.addDiffArea(editor.document.uri, diffArea) - // save the original code - diffArea.originalCode = await readFileContentOfUri(editor.document.uri) - // write the new code `m.code` to the document - // TODO make this animated - editor.edit(editBuilder => { + // write new code `m.code` to the document + // TODO update like this: + // this._weAreEditing = true + // await vscode.workspace.applyEdit(workspaceEdit) + // await vscode.workspace.save(docUri) + // this._weAreEditing = false + await 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) + // rediff the changes based on the diffArea (start, end, original code, [current code]) + displayChangesProvider.refreshDiffAreas(editor.document.uri) - - // 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/getDiffedLines.ts b/extensions/void/src/getDiffedLines.ts index 7533b20e..04d5bb7b 100644 --- a/extensions/void/src/getDiffedLines.ts +++ b/extensions/void/src/getDiffedLines.ts @@ -1,6 +1,6 @@ import { diffLines, Change } from 'diff'; -export type SuggestedEdit = { +export type SuggestedDiff = { // start/end of current file startLine: number, endLine: number, @@ -16,6 +16,11 @@ export type SuggestedEdit = { export function getDiffedLines(oldStr: string, newStr: string) { // an ordered list of every original line, line added to the new file, and line removed from the old file (order is unambiguous, think about it) + + // replace \r\n with \n + oldStr = oldStr.replace(/\r\n/g, '\n') + newStr = newStr.replace(/\r\n/g, '\n') + const lineByLineChanges: Change[] = diffLines(oldStr, newStr); console.debug('Line by line changes', lineByLineChanges) @@ -30,7 +35,7 @@ export function getDiffedLines(oldStr: string, newStr: string) { let oldStrLines = oldStr.split('\n') let newStrLines = newStr.split('\n') - const replacements: SuggestedEdit[] = [] + const replacements: SuggestedDiff[] = [] for (let line of lineByLineChanges) { // no change on this line @@ -46,7 +51,7 @@ export function getDiffedLines(oldStr: string, newStr: string) { const originalEndLine = oldFileLineNum - 1 // don't include current line, the edit was up to this line but not including it const originalContent = oldStrLines.slice(originalStartLine, originalEndLine + 1).join('\n') - const replacement: SuggestedEdit = { beforeCode: originalContent, afterCode: newContent, startLine, endLine, originalStartLine, originalEndLine, } + const replacement: SuggestedDiff = { beforeCode: originalContent, afterCode: newContent, startLine, endLine, originalStartLine, originalEndLine, } replacements.push(replacement) streakStartInNewFile = undefined diff --git a/extensions/void/src/shared_types.ts b/extensions/void/src/shared_types.ts index da4381ea..f16fa3f5 100644 --- a/extensions/void/src/shared_types.ts +++ b/extensions/void/src/shared_types.ts @@ -11,7 +11,7 @@ type File = { filepath: vscode.Uri, content: string } type DiffArea = { startLine: number, endLine: number, - originalCode: string | undefined + originalCode: string } // each diff on the user's screen right now