Fix accept/reject diff

This commit is contained in:
Mathew P 2024-10-13 17:47:13 -07:00
parent 1557a44934
commit 20056f209e
4 changed files with 109 additions and 56 deletions

View file

@ -1,6 +1,6 @@
import * as vscode from 'vscode';
import { findDiffs } from './findDiffs';
import { Diff, DiffArea, DiffBlock } from './shared_types';
import { Diff, BaseDiffArea, BaseDiff, DiffArea } from './shared_types';
@ -17,6 +17,7 @@ export class DisplayChangesProvider implements vscode.CodeLensProvider {
private _diffAreasOfDocument: { [docUriStr: string]: DiffArea[] } = {}
private _diffsOfDocument: { [docUriStr: string]: Diff[] } = {}
private _diffareaidPool = 0
private _diffidPool = 0
private _weAreEditing: boolean = false
@ -37,6 +38,7 @@ export class DisplayChangesProvider implements vscode.CodeLensProvider {
// this acts as a useEffect. Every time text changes, clear the diffs in this editor
vscode.workspace.onDidChangeTextDocument((e) => {
const editor = vscode.window.activeTextEditor
if (!editor)
@ -97,7 +99,7 @@ export class DisplayChangesProvider implements vscode.CodeLensProvider {
// used by us only
public addDiffArea(uri: vscode.Uri, diffArea: DiffArea) {
public addDiffArea(uri: vscode.Uri, diffArea: BaseDiffArea) {
const uriStr = uri.toString()
@ -107,16 +109,20 @@ export class DisplayChangesProvider implements vscode.CodeLensProvider {
// remove all diffAreas that the new `diffArea` is overlapping with
this._diffAreasOfDocument[uriStr] = this._diffAreasOfDocument[uriStr].filter(da => {
// condition for no overlap
const noOverlap = da.startLine > diffArea.endLine || da.endLine < diffArea.startLine
// if there is overlap (ie there is `not noOverlap`), remove `da`
if (!noOverlap) return false
return true
})
// add `diffArea` to storage
this._diffAreasOfDocument[uriStr].push(diffArea)
this._diffAreasOfDocument[uriStr].push({
...diffArea,
diffareaid: this._diffareaidPool
})
this._diffareaidPool += 1
}
@ -149,7 +155,7 @@ export class DisplayChangesProvider implements vscode.CodeLensProvider {
console.log('!CODEAfter:', JSON.stringify(currentCode))
// add the diffs to `this._diffsOfDocument[docUriStr]`
this.addDiffs(editor.document.uri, diffs)
this.addDiffs(editor.document.uri, diffs, diffArea)
for (const diff of this._diffsOfDocument[docUriStr]) {
console.log('------------')
@ -180,7 +186,7 @@ export class DisplayChangesProvider implements vscode.CodeLensProvider {
}
// used by us only
public addDiffs(docUri: vscode.Uri, diffs: DiffBlock[]) {
public addDiffs(docUri: vscode.Uri, diffs: BaseDiff[], diffArea: DiffArea) {
const docUriStr = docUri.toString()
@ -197,8 +203,8 @@ export class DisplayChangesProvider implements vscode.CodeLensProvider {
diffid: this._diffidPool,
// originalCode: suggestedDiff.deletedText,
lenses: [
new vscode.CodeLens(suggestedDiff.insertedRange, { title: 'Accept', command: 'void.acceptDiff', arguments: [{ diffid: this._diffidPool }] }),
new vscode.CodeLens(suggestedDiff.insertedRange, { title: 'Reject', command: 'void.rejectDiff', arguments: [{ diffid: this._diffidPool }] })
new vscode.CodeLens(suggestedDiff.insertedRange, { title: 'Accept', command: 'void.acceptDiff', arguments: [{ diffid: this._diffidPool, diffareaid: diffArea.diffareaid }] }),
new vscode.CodeLens(suggestedDiff.insertedRange, { title: 'Reject', command: 'void.rejectDiff', arguments: [{ diffid: this._diffidPool, diffareaid: diffArea.diffareaid }] })
]
});
this._diffidPool += 1
@ -207,7 +213,7 @@ export class DisplayChangesProvider implements vscode.CodeLensProvider {
}
// called on void.acceptDiff
public async acceptDiff({ diffid }: { diffid: number }) {
public async acceptDiff({ diffid, diffareaid }: { diffid: number, diffareaid: number }) {
const editor = vscode.window.activeTextEditor
if (!editor)
return
@ -216,54 +222,94 @@ export class DisplayChangesProvider implements vscode.CodeLensProvider {
const docUri = editor.document.uri
const docUriStr = docUri.toString()
// get index of this diff in diffsOfDocument
const index = this._diffsOfDocument[docUriStr].findIndex(diff => diff.diffid === diffid);
if (index === -1) {
console.error('Error: DiffID could not be found: ', diffid, this._diffsOfDocument[docUriStr])
return
// get relevant diff
// TODO speed up with hashmap
const diffIdx = this._diffsOfDocument[docUriStr].findIndex(diff => diff.diffid === diffid);
if (diffIdx === -1) {
console.error('Error: DiffID could not be found: ', diffid, diffareaid, this._diffsOfDocument[docUriStr], this._diffAreasOfDocument[docUriStr]); return;
}
// remove this diff from the diffsOfDocument[docStr] (can change this behavior in future if add something like history)
this._diffsOfDocument[docUriStr].splice(index, 1)
// get relevant diffArea
const diffareaIdx = this._diffAreasOfDocument[docUriStr].findIndex(diff => diff.diffareaid === diffareaid);
if (diffareaIdx === -1) {
console.error('Error: DiffAreaID could not be found: ', diffid, diffareaid, this._diffsOfDocument[docUriStr], this._diffAreasOfDocument[docUriStr]); return;
}
// refresh
const diff = this._diffsOfDocument[docUriStr][diffIdx]
const diffArea = this._diffAreasOfDocument[docUriStr][diffareaIdx]
// replace `originalCode[diff.deletedRange]` with diff.insertedCode
// TODO add a history event to undo this change
const originalLines = diffArea.originalCode.split('\n');
const relativeStart = diff.deletedRange.start.line - diffArea.originalStartLine
const relativeEnd = diff.deletedRange.end.line - diffArea.originalStartLine
diffArea.originalCode = [
...originalLines.slice(0, relativeStart), // lines before the deleted range
...diff.insertedCode.split('\n'), // inserted lines
...originalLines.slice(relativeEnd + 1) // lines after the deleted range
].join('\n')
// if the diffArea has no changes, remove it
const currentDiffAreaCode = editor.document.getText()
.replace(/\r\n/g, '\n')
.split('\n')
.slice(diffArea.startLine, diffArea.endLine + 1)
.join('\n')
if (diffArea.originalCode === currentDiffAreaCode) { // if the currentDiffAreaCode === diffArea.originalCode, remove the diffArea
const index = this._diffAreasOfDocument[docUriStr].findIndex(da => da.diffareaid === diffArea.diffareaid)
this._diffAreasOfDocument[docUriStr].splice(index, 1)
}
// refresh the diff area
this.refreshDiffAreas(docUri)
}
// called on void.rejectDiff
public async rejectDiff({ diffid }: { diffid: number }) {
public async rejectDiff({ diffid, diffareaid }: { diffid: number, diffareaid: number }) {
const editor = vscode.window.activeTextEditor
if (!editor)
return
// get document uri
const docUri = editor.document.uri
const docUriStr = docUri.toString()
// get index of this diff in diffsOfDocument
const index = this._diffsOfDocument[docUriStr].findIndex(diff => diff.diffid === diffid);
if (index === -1) {
console.error('Void error: DiffID could not be found: ', diffid, this._diffsOfDocument[docUriStr])
return
// get relevant diff
// TODO speed up with hashmap
const diffIdx = this._diffsOfDocument[docUriStr].findIndex(diff => diff.diffid === diffid);
if (diffIdx === -1) {
console.error('Error: DiffID could not be found: ', diffid, diffareaid, this._diffsOfDocument[docUriStr], this._diffAreasOfDocument[docUriStr]); return;
}
const { insertedRange: range, lenses, deletedCode } = this._diffsOfDocument[docUriStr][index] // do this before we splice and mess up index
// get relevant diffArea
const diffareaIdx = this._diffAreasOfDocument[docUriStr].findIndex(diff => diff.diffareaid === diffareaid);
if (diffareaIdx === -1) {
console.error('Error: DiffAreaID could not be found: ', diffid, diffareaid, this._diffsOfDocument[docUriStr], this._diffAreasOfDocument[docUriStr]); return;
}
// remove this diff from the diffsOfDocument[docStr] (can change this behavior in future if add something like history)
this._diffsOfDocument[docUriStr].splice(index, 1)
const diff = this._diffsOfDocument[docUriStr][diffIdx]
const diffArea = this._diffAreasOfDocument[docUriStr][diffareaIdx]
// clear the decoration in this diffs range
// editor.setDecorations(greenDecoration, this._diffsOfDocument[docUriStr].map(diff => diff.insertionRange))
// REVERT THE CHANGE (this is the only part that's different from acceptDiff)
let workspaceEdit = new vscode.WorkspaceEdit();
// workspaceEdit.replace(docUri, range, deletedCode);
// replace `editorCode[diff.insertedRange]` with diff.deletedCode
const workspaceEdit = new vscode.WorkspaceEdit();
workspaceEdit.replace(docUri, diff.insertedRange, diff.deletedCode)
this._weAreEditing = true
await vscode.workspace.applyEdit(workspaceEdit)
await vscode.workspace.save(docUri)
this._weAreEditing = false
// refresh
// if the diffArea has no changes, remove it
const currentDiffAreaCode = editor.document.getText()
.replace(/\r\n/g, '\n')
.split('\n')
.slice(diffArea.startLine, diffArea.endLine + 1)
.join('\n')
if (diffArea.originalCode === currentDiffAreaCode) { // if the currentDiffAreaCode === diffArea.originalCode, remove the diffArea
const index = this._diffAreasOfDocument[docUriStr].findIndex(da => da.diffareaid === diffArea.diffareaid)
this._diffAreasOfDocument[docUriStr].splice(index, 1)
}
// refresh the diff area
this.refreshDiffAreas(docUri)
}
}

View file

@ -1,5 +1,5 @@
import * as vscode from 'vscode';
import { DiffArea, WebviewMessage } from './shared_types';
import { BaseDiffArea, WebviewMessage } from './shared_types';
import { CtrlKCodeLensProvider } from './CtrlKCodeLensProvider';
import { DisplayChangesProvider } from './DisplayChangesProvider';
import { SidebarWebviewProvider } from './SidebarWebviewProvider';
@ -57,7 +57,7 @@ export function activate(context: vscode.ExtensionContext) {
// vscode.commands.executeCommand('vscode.moveViewToPanel', CustomViewProvider.viewId); // move to aux bar
// get the text the user is selecting
const selectionStr = editor.document.getText(editor.selection);5
const selectionStr = editor.document.getText(editor.selection); 5
// get the range of the selection
const selectionRange = editor.selection;
@ -124,9 +124,11 @@ export function activate(context: vscode.ExtensionContext) {
}
// create an area to show diffs
const diffArea: DiffArea = {
const diffArea: BaseDiffArea = {
startLine: 0, // in ctrl+L the start and end lines are the full document
endLine: editor.document.lineCount,
originalStartLine: 0,
originalEndLine: editor.document.lineCount,
originalCode: await readFileContentOfUri(editor.document.uri),
}
displayChangesProvider.addDiffArea(editor.document.uri, diffArea)
@ -139,12 +141,10 @@ export function activate(context: vscode.ExtensionContext) {
// 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);
editBuilder.replace(new vscode.Range(diffArea.startLine, 0, diffArea.endLine, Number.MAX_SAFE_INTEGER), m.code);
});
// rediff the changes based on the diffArea (start, end, original code, [current code])
// rediff the changes based on the diffAreas
displayChangesProvider.refreshDiffAreas(editor.document.uri)
}

View file

@ -1,7 +1,7 @@
import * as vscode from 'vscode';
// import { diffLines, Change } from 'diff';
import { DiffBlock } from './shared_types';
import { BaseDiff } from './shared_types';
import { diff_match_patch } from 'diff-match-patch';
@ -20,11 +20,11 @@ const diffLines = (text1: string, text2: string) => {
// TODO use a better diff algorithm
export const findDiffs = (oldText: string, newText: string): DiffBlock[] => {
export const findDiffs = (oldText: string, newText: string): BaseDiff[] => {
const diffs = diffLines(oldText, newText);
const blocks: DiffBlock[] = [];
const blocks: BaseDiff[] = [];
let reprBlock: string[] = [];
let deletedBlock: string[] = [];
let insertedBlock: string[] = [];

View file

@ -10,18 +10,25 @@ type CodeSelection = { selectionStr: string, selectionRange: vscode.Range, fileP
type File = { filepath: vscode.Uri, content: string }
// an area that is currently being diffed
type DiffArea = {
startLine: number,
endLine: number,
originalCode: string
type BaseDiffArea = {
// use `startLine` and `endLine` instead of `range` for mutibility
// bounds are relative to the file, inclusive
startLine: number;
endLine: number;
originalStartLine: number,
originalEndLine: number,
originalCode: string, // the original chunk of code (not necessarily the whole file)
// `newCode: string,` is not included because it is the code in the actual file, `document.text()[startline: endLine + 1]`
}
type DiffArea = BaseDiffArea & { diffareaid: number }
// the return type of diff creator
type DiffBlock = {
code: string;
deletedRange: vscode.Range;
deletedCode: string;
type BaseDiff = {
code: string; // representation of the diff in text
deletedRange: vscode.Range; // relative to the file, inclusive
insertedRange: vscode.Range;
deletedCode: string;
insertedCode: string;
}
@ -29,7 +36,7 @@ type DiffBlock = {
type Diff = {
diffid: number,
lenses: vscode.CodeLens[],
} & DiffBlock
} & BaseDiff
type WebviewMessage = (
@ -57,7 +64,7 @@ type WebviewMessage = (
type Command = WebviewMessage['type']
export {
DiffBlock,
BaseDiff, BaseDiffArea,
CodeSelection,
File,
WebviewMessage,