This commit is contained in:
Andrew 2024-10-25 01:22:10 -07:00
parent 4b5e09c124
commit d4a2ac2796
4 changed files with 323 additions and 96 deletions

View file

@ -1,8 +0,0 @@
class Diff {
constructor(){
}
}

View file

@ -0,0 +1,115 @@
import * as vscode from 'vscode';
import { SuggestedEdit } from './findDiffs';
const greenDecoration = vscode.window.createTextEditorDecorationType({
backgroundColor: 'rgba(0 255 51 / 0.2)',
isWholeLine: false, // after: { contentText: ' [original]', color: 'rgba(0 255 60 / 0.5)' } // hoverMessage: originalText // this applies to hovering over after:...
})
export class DiffProvider {
originalCodeOfDocument: { [docUri: string]: string }
diffsOfDocument: {
[docUri: string]: {
startLine,
startCol,
endLine,
endCol,
originalText,
inset,
diffid,
}
}
// sweep
currentLine: { [docUri: string]: undefined | number }
weAreEditing: boolean = false
constructor() {
vscode.workspace.onDidChangeTextDocument((e) => {
// on user change, grow/shrink/merge/delete diff AREAS
// you dont have to do anything to the diffs here bc they all get recomputed in refresh()
// user changes only get highlighted if theyre in a diffarea
// go thru all diff areas and adjust line numbers based on the user's change
this.refreshStyles(e.document.uri.toString())
})
}
// refreshes styles on page
refreshStyles(docUriStr: string) {
if (this.weAreEditing) return
// recompute all diffs on the page
// run inset.dispose() on all diffs
// original and current code -> diffs
// originalCodeOfDocument[docUriStr]
// create new diffs
const inset = vscode.window.createWebviewTextEditorInset(editor, lineStart, height, {})
inset.webview.html = `
<html>
<body style="pointer-events:none;">Hello World!</body>
</html>
`;
}
// called on void.acceptDiff
public async acceptDiff({ diffid }: { diffid: number }) {
// update original based on the diff
// refresh()
}
// called on void.rejectDiff
public async rejectDiff({ diffid }: { diffid: number }) {
// get diffs[diffid]
// revert current file based on diff
// refresh()
}
// sweep
initializeSweep({ startLine }) {
// reject all diffs on the page
// store original code
// currentLine=start of sweep
}
onUpdateSweep(addedText) {
// update final
// refresh() ?
// currentLine += number of newlines in addedText
}
onAbortSweep() {
}
}

View file

@ -1,10 +1,12 @@
import * as vscode from 'vscode';
import { DisplayChangesProvider } from './DisplayChangesProvider';
import { BaseDiffArea, ChatThreads, MessageFromSidebar, MessageToSidebar } from './common/shared_types';
import { ApprovalCodeLensProvider } from './ApprovalCodeLensProvider';
import { ChatThreads, MessageFromSidebar, MessageToSidebar } from './common/shared_types';
import { SidebarWebviewProvider } from './SidebarWebviewProvider';
import { v4 as uuidv4 } from 'uuid'
import { applyDiffLazily } from './common/ctrlL';
import { getVoidConfig } from './sidebar/contextForConfig';
import { DiffProvider } from './DiffProvider';
// import { getVoidConfig } from './sidebar/contextForConfig';
// this comes from vscode.proposed.editorInsets.d.ts
declare module 'vscode' {
@ -88,7 +90,8 @@ export function activate(context: vscode.ExtensionContext) {
);
// 3. Show an approve/reject
const displayChangesProvider = new DisplayChangesProvider();
const displayChangesProvider = new DiffProvider();
// context.subscriptions.push(vscode.languages.registerCodeLensProvider('*', displayChangesProvider));
// 4. Add approve/reject commands
context.subscriptions.push(vscode.commands.registerCommand('void.acceptDiff', async (params) => {
@ -135,16 +138,15 @@ export function activate(context: vscode.ExtensionContext) {
return
}
// create an area to show diffs
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)
// // create an area to show diffs
// const diffArea = {
// 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)
// write new code `m.code` to the document
@ -168,7 +170,7 @@ export function activate(context: vscode.ExtensionContext) {
// });
// rediff the changes based on the diffAreas
displayChangesProvider.refreshDiffAreas(editor.document.uri)
displayChangesProvider.refreshLenses(editor, editor.document.uri.toString())
}
else if (m.type === 'getPartialVoidConfig') {

View file

@ -1,9 +1,121 @@
import * as vscode from 'vscode';
// import { diffLines, Change } from 'diff';
import { diff_match_patch } from 'diff-match-patch';
import { diffLines } from 'diff';
import { BaseDiff } from './common/shared_types';
import { diffLines, Change } from 'diff';
export type SuggestedEdit = {
// start/end of current file
startLine: number;
startCol: number;
endLine: number;
endCol: number;
// start/end of original file
originalStartLine: number,
originalStartCol: number,
originalEndLine: number,
originalEndCol: number,
type: 'insertion' | 'deletion' | 'edit',
originalContent: string, // original content (originalfile[originalStart...originalEnd])
newContent: string,
}
export function findDiffs(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)
const lineByLineChanges: Change[] = diffLines(oldStr, newStr);
lineByLineChanges.push({ value: '' }) // add a dummy so we flush any streaks we haven't yet at the very end (!line.added && !line.removed)
let oldFileLineNum: number = 0;
let newFileLineNum: number = 0;
let streakStartInNewFile: number | undefined = undefined
let streakStartInOldFile: number | undefined = undefined
let oldStrLines = oldStr.split('\n')
let newStrLines = newStr.split('\n')
const replacements: SuggestedEdit[] = []
for (let line of lineByLineChanges) {
// no change on this line
if (!line.added && !line.removed) {
// do nothing
// if we were on a streak of +s and -s, end it
if (streakStartInNewFile !== undefined) {
let type: 'edit' | 'insertion' | 'deletion' = 'edit'
let startLine = streakStartInNewFile
let endLine = newFileLineNum - 1 // don't include current line, the edit was up to this line but not including it
let startCol = 0
let endCol = Number.MAX_SAFE_INTEGER
let originalStartLine = streakStartInOldFile!
let originalEndLine = oldFileLineNum - 1 // don't include current line, the edit was up to this line but not including it
let originalStartCol = 0
let originalEndCol = Number.MAX_SAFE_INTEGER
let newContent = newStrLines.slice(startLine, endLine + 1).join('\n')
let originalContent = oldStrLines.slice(originalStartLine, originalEndLine + 1).join('\n')
// if the range is empty, mark it as a deletion / insertion (both won't be true at once)
// DELETION
if (endLine === startLine - 1) {
type = 'deletion'
endLine = startLine
startCol = 0
endCol = 0
newContent += '\n'
}
// INSERTION
else if (originalEndLine === originalStartLine - 1) {
type = 'insertion'
originalEndLine = originalStartLine
originalStartCol = 0
originalEndCol = 0
}
const replacement: SuggestedEdit = {
type,
startLine, startCol, endLine, endCol, newContent,
originalStartLine, originalStartCol, originalEndLine, originalEndCol, originalContent
} as SuggestedEdit
replacements.push(replacement)
streakStartInNewFile = undefined
streakStartInOldFile = undefined
}
oldFileLineNum += line.count ?? 0;
newFileLineNum += line.count ?? 0;
}
// line was removed from old file
else if (line.removed) {
// if we weren't on a streak, start one on this current line num
if (streakStartInNewFile === undefined) {
streakStartInNewFile = newFileLineNum
streakStartInOldFile = oldFileLineNum
}
oldFileLineNum += line.count ?? 0 // we processed the line so add 1
}
// line was added to new file
else if (line.added) {
// if we weren't on a streak, start one on this current line num
if (streakStartInNewFile === undefined) {
streakStartInNewFile = newFileLineNum
streakStartInOldFile = oldFileLineNum
}
newFileLineNum += line.count ?? 0; // we processed the line so add 1
}
} // end for
console.debug('Replacements', replacements)
return replacements
}
// const diffLinesOld = (text1: string, text2: string) => {
@ -98,86 +210,92 @@ import { BaseDiff } from './common/shared_types';
// };
export const findDiffs = (oldText: string, newText: string): BaseDiff[] => {
let diffs = diffLines(oldText, newText)
.map(diff => {
const operation = diff.added ? 1 : diff.removed ? -1 : 0;
const text = diff.value;
return [operation, text] as const;
})
const blocks: BaseDiff[] = [];
let reprBlock: string[] = [];
let deletedBlock: string[] = [];
let insertedBlock: string[] = [];
let newFileLine = 0;
let oldFileLine = 0;
let insertedStart = 0;
let deletedStart = 0;
diffs.forEach(([operation, text]) => {
const lines = text.split('\n');
switch (operation) {
// insertion
case 1:
if (reprBlock.length === 0) { reprBlock.push('@@@@'); }
if (insertedBlock.length === 0) insertedStart = newFileLine;
newFileLine += lines.length - 1; // update the line count for new text
insertedBlock.push(text);
reprBlock.push(lines.map(line => `+ ${line}`).join('\n'));
break;
// export const findDiffs = (oldText: string, newText: string): BaseDiff[] => {
// deletion
case -1:
if (reprBlock.length === 0) { reprBlock.push('@@@@'); }
if (deletedBlock.length === 0) deletedStart = oldFileLine;
oldFileLine += lines.length - 1; // update the line count for old text
deletedBlock.push(text);
reprBlock.push(lines.map(line => `- ${line}`).join('\n'));
break;
// let diffs = diffLines(oldText, newText)
// .map(diff => {
// const operation = diff.added ? 1 : diff.removed ? -1 : 0;
// const text = diff.value;
// return [operation, text] as const;
// })
// no change
case 0:
// add pending block to the blocks array
if (insertedBlock.length > 0 || deletedBlock.length > 0) {
blocks.push({
code: reprBlock.join(''),
deletedCode: deletedBlock.join(''),
insertedCode: insertedBlock.join(''),
deletedRange: new vscode.Range(deletedStart, 0, oldFileLine, Number.MAX_SAFE_INTEGER),
insertedRange: new vscode.Range(insertedStart, 0, newFileLine, Number.MAX_SAFE_INTEGER),
});
}
// update variables
reprBlock = [];
deletedBlock = [];
insertedBlock = [];
deletedStart += lines.length - 1;
insertedStart += lines.length - 1;
newFileLine += lines.length - 1;
oldFileLine += lines.length - 1;
// const blocks: BaseDiff[] = [];
// let reprBlock: string[] = [];
// let deletedBlock: string[] = [];
// let insertedBlock: string[] = [];
// let newFileLine = 0;
// let oldFileLine = 0;
// let insertedStart = 0;
// let deletedStart = 0;
break;
}
});
// diffs.forEach(([operation, text]) => {
// Add any remaining blocks after the loop ends
if (insertedBlock.length > 0 || deletedBlock.length > 0) {
blocks.push({
code: reprBlock.join(''),
deletedCode: deletedBlock.join(''),
insertedCode: insertedBlock.join(''),
deletedRange: new vscode.Range(deletedStart, 0, oldFileLine, Number.MAX_SAFE_INTEGER),
insertedRange: new vscode.Range(insertedStart, 0, newFileLine, Number.MAX_SAFE_INTEGER),
});
}
// const lines = text.split('\n');
return blocks;
};
// switch (operation) {
// // insertion
// case 1:
// if (reprBlock.length === 0) { reprBlock.push('@@@@'); }
// if (insertedBlock.length === 0) insertedStart = newFileLine;
// newFileLine += lines.length - 1; // update the line count for new text
// insertedBlock.push(text);
// reprBlock.push(lines.map(line => `+ ${line}`).join('\n'));
// break;
// // deletion
// case -1:
// if (reprBlock.length === 0) { reprBlock.push('@@@@'); }
// if (deletedBlock.length === 0) deletedStart = oldFileLine;
// oldFileLine += lines.length - 1; // update the line count for old text
// deletedBlock.push(text);
// reprBlock.push(lines.map(line => `- ${line}`).join('\n'));
// break;
// // no change
// case 0:
// // add pending block to the blocks array
// if (insertedBlock.length > 0 || deletedBlock.length > 0) {
// blocks.push({
// code: reprBlock.join(''),
// deletedCode: deletedBlock.join(''),
// insertedCode: insertedBlock.join(''),
// deletedRange: new vscode.Range(deletedStart, 0, oldFileLine, Number.MAX_SAFE_INTEGER),
// insertedRange: new vscode.Range(insertedStart, 0, newFileLine, Number.MAX_SAFE_INTEGER),
// });
// }
// // update variables
// reprBlock = [];
// deletedBlock = [];
// insertedBlock = [];
// deletedStart += lines.length - 1;
// insertedStart += lines.length - 1;
// newFileLine += lines.length - 1;
// oldFileLine += lines.length - 1;
// break;
// }
// });
// // Add any remaining blocks after the loop ends
// if (insertedBlock.length > 0 || deletedBlock.length > 0) {
// blocks.push({
// code: reprBlock.join(''),
// deletedCode: deletedBlock.join(''),
// insertedCode: insertedBlock.join(''),
// deletedRange: new vscode.Range(deletedStart, 0, oldFileLine, Number.MAX_SAFE_INTEGER),
// insertedRange: new vscode.Range(insertedStart, 0, newFileLine, Number.MAX_SAFE_INTEGER),
// });
// }
// return blocks;
// };