mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
Fix accept/reject diff
This commit is contained in:
parent
1557a44934
commit
20056f209e
4 changed files with 109 additions and 56 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { findDiffs } from './findDiffs';
|
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 _diffAreasOfDocument: { [docUriStr: string]: DiffArea[] } = {}
|
||||||
private _diffsOfDocument: { [docUriStr: string]: Diff[] } = {}
|
private _diffsOfDocument: { [docUriStr: string]: Diff[] } = {}
|
||||||
|
|
||||||
|
private _diffareaidPool = 0
|
||||||
private _diffidPool = 0
|
private _diffidPool = 0
|
||||||
private _weAreEditing: boolean = false
|
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
|
// this acts as a useEffect. Every time text changes, clear the diffs in this editor
|
||||||
vscode.workspace.onDidChangeTextDocument((e) => {
|
vscode.workspace.onDidChangeTextDocument((e) => {
|
||||||
|
|
||||||
const editor = vscode.window.activeTextEditor
|
const editor = vscode.window.activeTextEditor
|
||||||
|
|
||||||
if (!editor)
|
if (!editor)
|
||||||
|
|
@ -97,7 +99,7 @@ export class DisplayChangesProvider implements vscode.CodeLensProvider {
|
||||||
|
|
||||||
|
|
||||||
// used by us only
|
// used by us only
|
||||||
public addDiffArea(uri: vscode.Uri, diffArea: DiffArea) {
|
public addDiffArea(uri: vscode.Uri, diffArea: BaseDiffArea) {
|
||||||
|
|
||||||
const uriStr = uri.toString()
|
const uriStr = uri.toString()
|
||||||
|
|
||||||
|
|
@ -107,16 +109,20 @@ export class DisplayChangesProvider implements vscode.CodeLensProvider {
|
||||||
|
|
||||||
// remove all diffAreas that the new `diffArea` is overlapping with
|
// remove all diffAreas that the new `diffArea` is overlapping with
|
||||||
this._diffAreasOfDocument[uriStr] = this._diffAreasOfDocument[uriStr].filter(da => {
|
this._diffAreasOfDocument[uriStr] = this._diffAreasOfDocument[uriStr].filter(da => {
|
||||||
// condition for no overlap
|
|
||||||
const noOverlap = da.startLine > diffArea.endLine || da.endLine < diffArea.startLine
|
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
|
if (!noOverlap) return false
|
||||||
|
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
// add `diffArea` to storage
|
// 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))
|
console.log('!CODEAfter:', JSON.stringify(currentCode))
|
||||||
|
|
||||||
// add the diffs to `this._diffsOfDocument[docUriStr]`
|
// 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]) {
|
for (const diff of this._diffsOfDocument[docUriStr]) {
|
||||||
console.log('------------')
|
console.log('------------')
|
||||||
|
|
@ -180,7 +186,7 @@ export class DisplayChangesProvider implements vscode.CodeLensProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
// used by us only
|
// used by us only
|
||||||
public addDiffs(docUri: vscode.Uri, diffs: DiffBlock[]) {
|
public addDiffs(docUri: vscode.Uri, diffs: BaseDiff[], diffArea: DiffArea) {
|
||||||
|
|
||||||
const docUriStr = docUri.toString()
|
const docUriStr = docUri.toString()
|
||||||
|
|
||||||
|
|
@ -197,8 +203,8 @@ export class DisplayChangesProvider implements vscode.CodeLensProvider {
|
||||||
diffid: this._diffidPool,
|
diffid: this._diffidPool,
|
||||||
// originalCode: suggestedDiff.deletedText,
|
// originalCode: suggestedDiff.deletedText,
|
||||||
lenses: [
|
lenses: [
|
||||||
new vscode.CodeLens(suggestedDiff.insertedRange, { title: 'Accept', command: 'void.acceptDiff', 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 }] })
|
new vscode.CodeLens(suggestedDiff.insertedRange, { title: 'Reject', command: 'void.rejectDiff', arguments: [{ diffid: this._diffidPool, diffareaid: diffArea.diffareaid }] })
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
this._diffidPool += 1
|
this._diffidPool += 1
|
||||||
|
|
@ -207,7 +213,7 @@ export class DisplayChangesProvider implements vscode.CodeLensProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
// called on void.acceptDiff
|
// called on void.acceptDiff
|
||||||
public async acceptDiff({ diffid }: { diffid: number }) {
|
public async acceptDiff({ diffid, diffareaid }: { diffid: number, diffareaid: number }) {
|
||||||
const editor = vscode.window.activeTextEditor
|
const editor = vscode.window.activeTextEditor
|
||||||
if (!editor)
|
if (!editor)
|
||||||
return
|
return
|
||||||
|
|
@ -216,54 +222,94 @@ export class DisplayChangesProvider implements vscode.CodeLensProvider {
|
||||||
const docUri = editor.document.uri
|
const docUri = editor.document.uri
|
||||||
const docUriStr = docUri.toString()
|
const docUriStr = docUri.toString()
|
||||||
|
|
||||||
// get index of this diff in diffsOfDocument
|
// get relevant diff
|
||||||
const index = this._diffsOfDocument[docUriStr].findIndex(diff => diff.diffid === diffid);
|
// TODO speed up with hashmap
|
||||||
if (index === -1) {
|
const diffIdx = this._diffsOfDocument[docUriStr].findIndex(diff => diff.diffid === diffid);
|
||||||
console.error('Error: DiffID could not be found: ', diffid, this._diffsOfDocument[docUriStr])
|
if (diffIdx === -1) {
|
||||||
return
|
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)
|
// get relevant diffArea
|
||||||
this._diffsOfDocument[docUriStr].splice(index, 1)
|
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)
|
this.refreshDiffAreas(docUri)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// called on void.rejectDiff
|
// called on void.rejectDiff
|
||||||
public async rejectDiff({ diffid }: { diffid: number }) {
|
public async rejectDiff({ diffid, diffareaid }: { diffid: number, diffareaid: number }) {
|
||||||
const editor = vscode.window.activeTextEditor
|
const editor = vscode.window.activeTextEditor
|
||||||
if (!editor)
|
if (!editor)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
// get document uri
|
||||||
const docUri = editor.document.uri
|
const docUri = editor.document.uri
|
||||||
const docUriStr = docUri.toString()
|
const docUriStr = docUri.toString()
|
||||||
|
|
||||||
// get index of this diff in diffsOfDocument
|
// get relevant diff
|
||||||
const index = this._diffsOfDocument[docUriStr].findIndex(diff => diff.diffid === diffid);
|
// TODO speed up with hashmap
|
||||||
if (index === -1) {
|
const diffIdx = this._diffsOfDocument[docUriStr].findIndex(diff => diff.diffid === diffid);
|
||||||
console.error('Void error: DiffID could not be found: ', diffid, this._diffsOfDocument[docUriStr])
|
if (diffIdx === -1) {
|
||||||
return
|
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)
|
const diff = this._diffsOfDocument[docUriStr][diffIdx]
|
||||||
this._diffsOfDocument[docUriStr].splice(index, 1)
|
const diffArea = this._diffAreasOfDocument[docUriStr][diffareaIdx]
|
||||||
|
|
||||||
// clear the decoration in this diffs range
|
// replace `editorCode[diff.insertedRange]` with diff.deletedCode
|
||||||
// editor.setDecorations(greenDecoration, this._diffsOfDocument[docUriStr].map(diff => diff.insertionRange))
|
const workspaceEdit = new vscode.WorkspaceEdit();
|
||||||
|
workspaceEdit.replace(docUri, diff.insertedRange, diff.deletedCode)
|
||||||
// REVERT THE CHANGE (this is the only part that's different from acceptDiff)
|
|
||||||
let workspaceEdit = new vscode.WorkspaceEdit();
|
|
||||||
// workspaceEdit.replace(docUri, range, deletedCode);
|
|
||||||
this._weAreEditing = true
|
this._weAreEditing = true
|
||||||
await vscode.workspace.applyEdit(workspaceEdit)
|
await vscode.workspace.applyEdit(workspaceEdit)
|
||||||
await vscode.workspace.save(docUri)
|
|
||||||
this._weAreEditing = false
|
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)
|
this.refreshDiffAreas(docUri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { DiffArea, WebviewMessage } from './shared_types';
|
import { BaseDiffArea, WebviewMessage } from './shared_types';
|
||||||
import { CtrlKCodeLensProvider } from './CtrlKCodeLensProvider';
|
import { CtrlKCodeLensProvider } from './CtrlKCodeLensProvider';
|
||||||
import { DisplayChangesProvider } from './DisplayChangesProvider';
|
import { DisplayChangesProvider } from './DisplayChangesProvider';
|
||||||
import { SidebarWebviewProvider } from './SidebarWebviewProvider';
|
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
|
// vscode.commands.executeCommand('vscode.moveViewToPanel', CustomViewProvider.viewId); // move to aux bar
|
||||||
|
|
||||||
// get the text the user is selecting
|
// 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
|
// get the range of the selection
|
||||||
const selectionRange = editor.selection;
|
const selectionRange = editor.selection;
|
||||||
|
|
@ -124,9 +124,11 @@ export function activate(context: vscode.ExtensionContext) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create an area to show diffs
|
// 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
|
startLine: 0, // in ctrl+L the start and end lines are the full document
|
||||||
endLine: editor.document.lineCount,
|
endLine: editor.document.lineCount,
|
||||||
|
originalStartLine: 0,
|
||||||
|
originalEndLine: editor.document.lineCount,
|
||||||
originalCode: await readFileContentOfUri(editor.document.uri),
|
originalCode: await readFileContentOfUri(editor.document.uri),
|
||||||
}
|
}
|
||||||
displayChangesProvider.addDiffArea(editor.document.uri, diffArea)
|
displayChangesProvider.addDiffArea(editor.document.uri, diffArea)
|
||||||
|
|
@ -139,12 +141,10 @@ export function activate(context: vscode.ExtensionContext) {
|
||||||
// await vscode.workspace.save(docUri)
|
// await vscode.workspace.save(docUri)
|
||||||
// this._weAreEditing = false
|
// this._weAreEditing = false
|
||||||
await editor.edit(editBuilder => {
|
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 diffAreas
|
||||||
|
|
||||||
// rediff the changes based on the diffArea (start, end, original code, [current code])
|
|
||||||
displayChangesProvider.refreshDiffAreas(editor.document.uri)
|
displayChangesProvider.refreshDiffAreas(editor.document.uri)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
// import { diffLines, Change } from 'diff';
|
// import { diffLines, Change } from 'diff';
|
||||||
import { DiffBlock } from './shared_types';
|
import { BaseDiff } from './shared_types';
|
||||||
|
|
||||||
import { diff_match_patch } from 'diff-match-patch';
|
import { diff_match_patch } from 'diff-match-patch';
|
||||||
|
|
||||||
|
|
@ -20,11 +20,11 @@ const diffLines = (text1: string, text2: string) => {
|
||||||
|
|
||||||
|
|
||||||
// TODO use a better diff algorithm
|
// 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 diffs = diffLines(oldText, newText);
|
||||||
|
|
||||||
const blocks: DiffBlock[] = [];
|
const blocks: BaseDiff[] = [];
|
||||||
let reprBlock: string[] = [];
|
let reprBlock: string[] = [];
|
||||||
let deletedBlock: string[] = [];
|
let deletedBlock: string[] = [];
|
||||||
let insertedBlock: string[] = [];
|
let insertedBlock: string[] = [];
|
||||||
|
|
|
||||||
|
|
@ -10,18 +10,25 @@ type CodeSelection = { selectionStr: string, selectionRange: vscode.Range, fileP
|
||||||
type File = { filepath: vscode.Uri, content: string }
|
type File = { filepath: vscode.Uri, content: string }
|
||||||
|
|
||||||
// an area that is currently being diffed
|
// an area that is currently being diffed
|
||||||
type DiffArea = {
|
type BaseDiffArea = {
|
||||||
startLine: number,
|
// use `startLine` and `endLine` instead of `range` for mutibility
|
||||||
endLine: number,
|
// bounds are relative to the file, inclusive
|
||||||
originalCode: string
|
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
|
// the return type of diff creator
|
||||||
type DiffBlock = {
|
type BaseDiff = {
|
||||||
code: string;
|
code: string; // representation of the diff in text
|
||||||
deletedRange: vscode.Range;
|
deletedRange: vscode.Range; // relative to the file, inclusive
|
||||||
deletedCode: string;
|
|
||||||
insertedRange: vscode.Range;
|
insertedRange: vscode.Range;
|
||||||
|
deletedCode: string;
|
||||||
insertedCode: string;
|
insertedCode: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -29,7 +36,7 @@ type DiffBlock = {
|
||||||
type Diff = {
|
type Diff = {
|
||||||
diffid: number,
|
diffid: number,
|
||||||
lenses: vscode.CodeLens[],
|
lenses: vscode.CodeLens[],
|
||||||
} & DiffBlock
|
} & BaseDiff
|
||||||
|
|
||||||
type WebviewMessage = (
|
type WebviewMessage = (
|
||||||
|
|
||||||
|
|
@ -57,7 +64,7 @@ type WebviewMessage = (
|
||||||
type Command = WebviewMessage['type']
|
type Command = WebviewMessage['type']
|
||||||
|
|
||||||
export {
|
export {
|
||||||
DiffBlock,
|
BaseDiff, BaseDiffArea,
|
||||||
CodeSelection,
|
CodeSelection,
|
||||||
File,
|
File,
|
||||||
WebviewMessage,
|
WebviewMessage,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue