From 097f279ecbf6d96ba77c4212814357c52c9aa31f Mon Sep 17 00:00:00 2001 From: mp Date: Thu, 24 Oct 2024 19:48:31 -0700 Subject: [PATCH] Throttle edit requests, refactor --- extensions/void/package-lock.json | 14 + extensions/void/package.json | 2 + extensions/void/src/DisplayChangesProvider.ts | 20 +- extensions/void/src/common/ctrlL.ts | 187 +++++----- extensions/void/src/extension.ts | 2 +- extensions/void/src/findDiffs.ts | 322 +++++++----------- 6 files changed, 252 insertions(+), 295 deletions(-) diff --git a/extensions/void/package-lock.json b/extensions/void/package-lock.json index 7fdfd06f..987e3892 100644 --- a/extensions/void/package-lock.json +++ b/extensions/void/package-lock.json @@ -19,6 +19,7 @@ "@types/diff": "^5.2.2", "@types/diff-match-patch": "^1.0.36", "@types/jest": "^29.5.12", + "@types/lodash": "^4.17.12", "@types/mocha": "^10.0.8", "@types/node": "^22.5.1", "@types/react": "^18.3.4", @@ -37,6 +38,7 @@ "eslint-plugin-react": "^7.35.1", "eslint-plugin-react-hooks": "^4.6.2", "globals": "^15.9.0", + "lodash": "^4.17.21", "marked": "^14.1.0", "ollama": "^0.5.9", "postcss": "^8.4.41", @@ -710,6 +712,12 @@ "pretty-format": "^29.0.0" } }, + "node_modules/@types/lodash": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.12.tgz", + "integrity": "sha512-sviUmCE8AYdaF/KIHLDJBQgeYzPBI0vf/17NaYehBJfYD1j6/L95Slh07NlyK2iNyBNaEkb3En2jRt+a8y3xZQ==", + "dev": true + }, "node_modules/@types/mdast": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", @@ -4549,6 +4557,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", diff --git a/extensions/void/package.json b/extensions/void/package.json index 96af35ef..bed26b5f 100644 --- a/extensions/void/package.json +++ b/extensions/void/package.json @@ -112,6 +112,7 @@ "@types/diff": "^5.2.2", "@types/diff-match-patch": "^1.0.36", "@types/jest": "^29.5.12", + "@types/lodash": "^4.17.12", "@types/mocha": "^10.0.8", "@types/node": "^22.5.1", "@types/react": "^18.3.4", @@ -130,6 +131,7 @@ "eslint-plugin-react": "^7.35.1", "eslint-plugin-react-hooks": "^4.6.2", "globals": "^15.9.0", + "lodash": "^4.17.21", "marked": "^14.1.0", "ollama": "^0.5.9", "postcss": "^8.4.41", diff --git a/extensions/void/src/DisplayChangesProvider.ts b/extensions/void/src/DisplayChangesProvider.ts index 99962f56..4410f998 100644 --- a/extensions/void/src/DisplayChangesProvider.ts +++ b/extensions/void/src/DisplayChangesProvider.ts @@ -154,16 +154,16 @@ export class DisplayChangesProvider implements vscode.CodeLensProvider { this.addDiffs(editor.document.uri, diffs, diffArea) // // print diffs - // console.log('!CodeBefore:', JSON.stringify(diffArea.originalCode)) - // console.log('!CodeAfter:', JSON.stringify(currentCode)) - // for (const diff of this._diffsOfDocument[docUriStr]) { - // console.log('------------') - // console.log('deletedCode:', JSON.stringify(diff.deletedCode)) - // console.log('insertedCode:', JSON.stringify(diff.insertedCode)) - // console.log('deletedRange:', diff.deletedRange.start.line, diff.deletedRange.end.line,) - // console.log('insertedRange:', diff.insertedRange.start.line, diff.insertedRange.end.line,) - // } - + console.log('!CodeBefore:', JSON.stringify(diffArea.originalCode)) + console.log('!CodeAfter:', JSON.stringify(currentCode)) + console.log('DiffRepr: ', diffs.map(diff => diff.code).join('\n')) + for (const diff of this._diffsOfDocument[docUriStr]) { + console.log('------------') + console.log('deletedCode:', JSON.stringify(diff.deletedCode)) + console.log('insertedCode:', JSON.stringify(diff.insertedCode)) + console.log('deletedRange:', diff.deletedRange.start.line, diff.deletedRange.end.line,) + console.log('insertedRange:', diff.insertedRange.start.line, diff.insertedRange.end.line,) + } } diff --git a/extensions/void/src/common/ctrlL.ts b/extensions/void/src/common/ctrlL.ts index 35b4329c..02b0723d 100644 --- a/extensions/void/src/common/ctrlL.ts +++ b/extensions/void/src/common/ctrlL.ts @@ -3,16 +3,53 @@ import { OnFinalMessage, OnText, sendLLMMessage, SetAbort } from "./sendLLMMessa import { VoidConfig } from '../sidebar/contextForConfig'; import { findDiffs } from '../findDiffs'; import { searchDiffChunkInstructions, writeFileWithDiffInstructions } from './systemPrompts'; +import { throttle } from 'lodash'; +const readFileContentOfUri = async (uri: vscode.Uri) => { + return Buffer.from(await vscode.workspace.fs.readFile(uri)).toString('utf8') + .replace(/\r\n/g, '\n') // replace windows \r\n with \n +} type Res = ((value: T) => void) -const writeFileWithDiffUntilMatchup = ({ fileUri, originalFileStr, unfinishedFileStr, diffStr, voidConfig, setAbort }: { fileUri: vscode.Uri, originalFileStr: string, unfinishedFileStr: string, diffStr: string, voidConfig: VoidConfig, setAbort: SetAbort }) => { +const THRTOTLE_TIME = 100 // minimum time between edits +const LINES_PER_CHUNK = 20 // number of lines to search at a time + +const applyCtrlLChangesToFile = throttle( + ({ fileUri, newCurrentLine, oldCurrentLine, fullCompletedStr, oldFileStr, debug }: { fileUri: vscode.Uri, newCurrentLine: number, oldCurrentLine: number, fullCompletedStr: string, oldFileStr: string, debug?: string }) => { + + console.log('DEBUG: ', debug) + console.log('oldNext: ', oldCurrentLine) + console.log('newNext: ', newCurrentLine) + console.log('WRITE_TO_FILE1: ', fullCompletedStr.split('\n').slice(0, newCurrentLine + 1).join('\n')) + console.log('WRITE_TO_FILE2: ', oldFileStr.split('\n').slice(oldCurrentLine + 1).join('\n')) + + // write the change to the file + const WRITE_TO_FILE = ( + fullCompletedStr.split('\n').slice(0, newCurrentLine + 1).join('\n') // newFile[:newCurrentLine+1] + + oldFileStr.split('\n').slice(oldCurrentLine + 1).join('\n') // oldFile[oldCurrentLine+1:] + ) + const workspaceEdit = new vscode.WorkspaceEdit() + workspaceEdit.replace(fileUri, new vscode.Range(0, 0, Number.MAX_SAFE_INTEGER, 0), WRITE_TO_FILE) + vscode.workspace.applyEdit(workspaceEdit) + + // highlight the `newCurrentLine` in white + // highlight the remaining part of the file in gray + + }, + THRTOTLE_TIME, { trailing: true } +) + + +// `next` is the line after the completed text +// `oldNext` is the same line but in the original file +type CompetedReturn = { isFinished: true, next?: undefined, oldNext?: undefined, } | { isFinished?: undefined, next: number, oldNext: number, } +const generateFileUsingDiffUntilMatchup = ({ fileUri, oldFileStr, completedStr, oldNext, next, diffStr, voidConfig, setAbort }: { fileUri: vscode.Uri, oldFileStr: string, completedStr: string, oldNext: number, next: number, diffStr: string, voidConfig: VoidConfig, setAbort: SetAbort }) => { const NUM_MATCHUP_TOKENS = 20 const promptContent = `ORIGINAL_FILE \`\`\` -${originalFileStr} +${oldFileStr} \`\`\` DIFF @@ -25,83 +62,80 @@ Please finish writing the new file \`NEW_FILE\`. Return ONLY the completion of t NEW_FILE \`\`\` -${unfinishedFileStr} +${completedStr} \`\`\` ` // create a promise that can be awaited - let res: Res<{ deltaStr: string, matchupLine: number | undefined }> = () => { } - const promise = new Promise<{ deltaStr: string, matchupLine: number | undefined }>((resolve, reject) => { res = resolve }) + let res: Res = () => { } + const promise = new Promise((resolve, reject) => { res = resolve }) // get the abort method let _abort = () => { } + let did_abort = false // make LLM complete the file to include the diff sendLLMMessage({ messages: [{ role: 'system', content: writeFileWithDiffInstructions, }, { role: 'user', content: promptContent, }], onText: (tokenStr, deltaStr) => { - const newFileStr = unfinishedFileStr + deltaStr + if (did_abort) return; - // 1. Apply the edit and modify highlighting - - console.log('EDIT START') - - const workspaceEdit = new vscode.WorkspaceEdit() - workspaceEdit.replace(fileUri, new vscode.Range(0, 0, Number.MAX_SAFE_INTEGER, 0), newFileStr) - vscode.workspace.applyEdit(workspaceEdit) - - // 2. Check for matchup with original file + const fullCompletedStr = completedStr + deltaStr // diff `originalFileStr` and `newFileStr` - const diffs = findDiffs(originalFileStr, newFileStr) + const diffs = findDiffs(oldFileStr, fullCompletedStr) const lastDiff = diffs[diffs.length - 1] const oldLineAfterLastDiff = lastDiff.deletedRange.end.line + 1 const newLineAfterLastDiff = lastDiff.insertedRange.end.line + 1 - // create a representation of both files with all spaces removed from each line - const oldFileAfterLastDiff = originalFileStr.split('\n').slice(oldLineAfterLastDiff).map(line => line.replace(/\s/g, '')).join('\n') - const newFileAfterLastDiff = newFileStr.split('\n').slice(newLineAfterLastDiff).map(line => line.replace(/\s/g, '')).join('\n') - // find where the matchup starts in `oldLinesAfterLastDiff` - const targetStr = newFileAfterLastDiff.slice(-NUM_MATCHUP_TOKENS) + // check if we've generated a diff + const didGenerateDiff = newLineAfterLastDiff > next - // return if not enough tokens to match - if (targetStr.length < NUM_MATCHUP_TOKENS) return; - // return if no matchup found - const matchupIdx = oldFileAfterLastDiff.indexOf(targetStr) - if (matchupIdx === -1) return; + // get the line we are currently generating `newCurrentLine`; make sure it never goes past the last diff we've generated + // - if `deltaStr` contains a diff, then _next = newLineAfterLastDiff - 1 + // - if it does not contain a diff, then _next = next + deltaStr.split('\n').length - 1 + const newCurrentLine = didGenerateDiff ? newLineAfterLastDiff - 1 : next + deltaStr.split('\n').length - 1 + const oldCurrentLine = didGenerateDiff ? oldLineAfterLastDiff - 1 : oldNext + (newCurrentLine - next) - console.log('MATCHUP') + // 1. Apply the changes and modify highlighting + + applyCtrlLChangesToFile({ fileUri, newCurrentLine, oldCurrentLine, fullCompletedStr, oldFileStr }) + + // 2. Check for early stopping + // the conditions for early stopping are: + // - we have generated a diff + // - there is matchup with the original file after the diff + const isMatchupAfterDiff = fullCompletedStr.split('\n').slice(newLineAfterLastDiff).join('\n').length > NUM_MATCHUP_TOKENS + if (didGenerateDiff && isMatchupAfterDiff) { + + // resolve the promise + res({ next: newCurrentLine + 1, oldNext: oldCurrentLine + 1, }); + + // abort the LLM call + _abort() + did_abort = true + + } else { + + } - // resolve the promise with the delta, up to first matchup - res({ - matchupLine: oldLineAfterLastDiff, - deltaStr: newFileStr.split('\n').splice(0, newLineAfterLastDiff).join('\n'), - }); - // abort the LLM call - _abort() }, - onFinalMessage: (finalMessage) => { + onFinalMessage: (deltaStr) => { - const newFileStr = unfinishedFileStr + finalMessage + const newCompletedStr = completedStr + deltaStr - const workspaceEdit = new vscode.WorkspaceEdit() - workspaceEdit.replace(fileUri, new vscode.Range(0, 0, Number.MAX_SAFE_INTEGER, 0), newFileStr) - vscode.workspace.applyEdit(workspaceEdit) + applyCtrlLChangesToFile({ fileUri, newCurrentLine: Number.MAX_SAFE_INTEGER, oldCurrentLine: Number.MAX_SAFE_INTEGER, fullCompletedStr: newCompletedStr, oldFileStr, debug: 'FINAL' }) - - console.log('FINAL MESSAGE', finalMessage) - - - res({ deltaStr: finalMessage, matchupLine: undefined }); + res({ isFinished: true }); }, onError: (e) => { - res({ deltaStr: '', matchupLine: undefined }); + res({ isFinished: true }); console.error('Error rewriting file with diff', e); }, voidConfig, - setAbort: (a) => { setAbort(a); _abort = a }, + setAbort: (a) => { setAbort(a); _abort = a; }, }) return promise @@ -163,57 +197,58 @@ Return \`true\` if ANY part of the chunk should be modified, and \`false\` if it // lazily applies the diff to the file // we chunk the text in the file, and ask an LLM whether it should edit each chunk -const applyDiffLazily = async ({ fileUri, fileStr, diffStr, voidConfig, setAbort }: { fileUri: vscode.Uri, fileStr: string, diffStr: string, voidConfig: VoidConfig, setAbort: SetAbort }) => { +const applyDiffLazily = async ({ fileUri, oldFileStr, diffStr, voidConfig, setAbort }: { fileUri: vscode.Uri, oldFileStr: string, diffStr: string, voidConfig: VoidConfig, setAbort: SetAbort }) => { - console.log('apply diff lazily') - const LINES_PER_CHUNK = 20 // number of lines to search at a time + // stateful variables + let next = 0 + let oldNext = 0 - // read file content - const fileLines = fileStr.split('\n') - const completedLines = [] + while (next < oldFileStr.split('\n').length) { - // search the file chunk-by-chunk - let chunkStart: number | undefined = 0 - while (chunkStart !== undefined && chunkStart < fileLines.length) { - - console.log('chunkStartLine: ', chunkStart) + console.log('next line: ', next) // get the chunk - const chunkLines = fileLines.slice(chunkStart, chunkStart + LINES_PER_CHUNK) - const chunkStr = chunkLines.join('\n'); - + const chunkStr = oldFileStr.split('\n').slice(next, next + LINES_PER_CHUNK).join('\n') // ask LLM if we should apply the diff to the chunk const __start = new Date().getTime() - let shouldApplyDiff = await shouldApplyDiffFn({ fileStr, speculationStr: chunkStr, diffStr, voidConfig, setAbort }) + + let shouldApplyDiff = await shouldApplyDiffFn({ fileStr: oldFileStr, speculationStr: chunkStr, diffStr, voidConfig, setAbort }) + const __end = new Date().getTime() + if (!shouldApplyDiff) { // should not change the chunk console.log('KEEP CHUNK time: ', __end - __start) - completedLines.push(chunkStr); - chunkStart += chunkLines.length - // TODO update highlighting here + + next += LINES_PER_CHUNK + oldNext += LINES_PER_CHUNK + continue; } // ask LLM to rewrite file with diff (if there is significant matchup with the original file, we stop rewriting) + // make vscode read uri = 'asdasd' + const ___start = new Date().getTime() - const { deltaStr, matchupLine } = await writeFileWithDiffUntilMatchup({ - originalFileStr: fileStr, - unfinishedFileStr: completedLines.join('\n'), - diffStr, - fileUri, - voidConfig, - // TODO! update highlighting here - setAbort, - }) + + + const completedStr = (await readFileContentOfUri(fileUri)).split('\n').slice(0, next).join('\n'); + const result = await generateFileUsingDiffUntilMatchup({ fileUri, oldFileStr, completedStr, oldNext, next, diffStr, voidConfig, setAbort, }) + const ___end = new Date().getTime() - console.log('EDIT CHUNK time: ', ___end - ___start) + console.log('EDIT CHUNK time: ', ___end - ___start); + + // if we are finished, stop the loop + if (result.isFinished) { + break; + } + + next = result.next + oldNext = result.oldNext - completedLines.push(deltaStr) - chunkStart = matchupLine } diff --git a/extensions/void/src/extension.ts b/extensions/void/src/extension.ts index c26cea42..1267d22f 100644 --- a/extensions/void/src/extension.ts +++ b/extensions/void/src/extension.ts @@ -117,7 +117,7 @@ export function activate(context: vscode.ExtensionContext) { let abort = () => { } // TODO this is unused // apply the change - applyDiffLazily({ fileUri, fileStr, diffStr: m.code, voidConfig, setAbort: (a) => { abort = a } }) + applyDiffLazily({ fileUri, oldFileStr: fileStr, diffStr: m.code, voidConfig, setAbort: (a) => { abort = a } }) // set the file equal to the change // await editor.edit(editBuilder => { diff --git a/extensions/void/src/findDiffs.ts b/extensions/void/src/findDiffs.ts index ee432200..e504e520 100644 --- a/extensions/void/src/findDiffs.ts +++ b/extensions/void/src/findDiffs.ts @@ -2,34 +2,118 @@ import * as vscode from 'vscode'; // import { diffLines, Change } from 'diff'; import { BaseDiff } from './shared_types'; - import { diff_match_patch } from 'diff-match-patch'; +import { diffLines } from 'diff'; -const diffLines = (text1: string, text2: string) => { - var dmp = new diff_match_patch(); - var a = dmp.diff_linesToChars_(text1, text2); - var lineText1 = a.chars1; - var lineText2 = a.chars2; - var lineArray = a.lineArray; - var diffs = dmp.diff_main(lineText1, lineText2, false); - dmp.diff_charsToLines_(diffs, lineArray); - // dmp.diff_cleanupSemantic(diffs); - return diffs; -} +// const diffLinesOld = (text1: string, text2: string) => { +// var dmp = new diff_match_patch(); +// var a = dmp.diff_linesToChars_(text1, text2); +// var lineText1 = a.chars1; +// var lineText2 = a.chars2; +// var lineArray = a.lineArray; +// var diffs = dmp.diff_main(lineText1, lineText2, false); +// dmp.diff_charsToLines_(diffs, lineArray); +// // dmp.diff_cleanupSemantic(diffs); +// return diffs; +// } + + +// // TODO use a better diff algorithm +// export const findDiffsOld = (oldText: string, newText: string): BaseDiff[] => { + +// const diffs = diffLinesOld(oldText, newText); + +// const blocks: BaseDiff[] = []; +// let reprBlock: string[] = []; +// let deletedBlock: string[] = []; +// let insertedBlock: string[] = []; +// let insertedLine = 0; +// let deletedLine = 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 = insertedLine; +// insertedLine += lines.length - 1; // Update only 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 = deletedLine; +// deletedLine += lines.length - 1; // Update only the line count for old text +// deletedBlock.push(text); +// reprBlock.push(lines.map(line => `- ${line}`).join('\n')); +// break; + +// // no change +// case 0: +// // If we have a pending block, add it 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, deletedLine, Number.MAX_SAFE_INTEGER), +// insertedRange: new vscode.Range(insertedStart, 0, insertedLine, Number.MAX_SAFE_INTEGER), +// }); +// } + +// // Reset the block variables +// reprBlock = []; +// deletedBlock = []; +// insertedBlock = []; + +// // Update line counts for unchanged text +// insertedLine += lines.length - 1; +// deletedLine += 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, deletedLine, Number.MAX_SAFE_INTEGER), +// insertedRange: new vscode.Range(insertedStart, 0, insertedLine, Number.MAX_SAFE_INTEGER), +// }); +// } + +// return blocks; +// }; -// TODO use a better diff algorithm export const findDiffs = (oldText: string, newText: string): BaseDiff[] => { - const diffs = diffLines(oldText, newText); + 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 insertedLine = 0; - let deletedLine = 0; + let newFileLine = 0; + let oldFileLine = 0; let insertedStart = 0; let deletedStart = 0; @@ -42,8 +126,8 @@ export const findDiffs = (oldText: string, newText: string): BaseDiff[] => { // insertion case 1: if (reprBlock.length === 0) { reprBlock.push('@@@@'); } - if (insertedBlock.length === 0) insertedStart = insertedLine; - insertedLine += lines.length - 1; // Update only the line count for new text + 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; @@ -51,33 +135,33 @@ export const findDiffs = (oldText: string, newText: string): BaseDiff[] => { // deletion case -1: if (reprBlock.length === 0) { reprBlock.push('@@@@'); } - if (deletedBlock.length === 0) deletedStart = deletedLine; - deletedLine += lines.length - 1; // Update only the line count for old text + 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: - // If we have a pending block, add it to the blocks array + // 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, deletedLine, Number.MAX_SAFE_INTEGER), - insertedRange: new vscode.Range(insertedStart, 0, insertedLine, Number.MAX_SAFE_INTEGER), + deletedRange: new vscode.Range(deletedStart, 0, oldFileLine, Number.MAX_SAFE_INTEGER), + insertedRange: new vscode.Range(insertedStart, 0, newFileLine, Number.MAX_SAFE_INTEGER), }); } - // Reset the block variables + // update variables reprBlock = []; deletedBlock = []; insertedBlock = []; - - // Update line counts for unchanged text - insertedLine += lines.length - 1; - deletedLine += lines.length - 1; + deletedStart += lines.length - 1; + insertedStart += lines.length - 1; + newFileLine += lines.length - 1; + oldFileLine += lines.length - 1; break; } @@ -89,189 +173,11 @@ export const findDiffs = (oldText: string, newText: string): BaseDiff[] => { code: reprBlock.join(''), deletedCode: deletedBlock.join(''), insertedCode: insertedBlock.join(''), - deletedRange: new vscode.Range(deletedStart, 0, deletedLine, Number.MAX_SAFE_INTEGER), - insertedRange: new vscode.Range(insertedStart, 0, insertedLine, Number.MAX_SAFE_INTEGER), + deletedRange: new vscode.Range(deletedStart, 0, oldFileLine, Number.MAX_SAFE_INTEGER), + insertedRange: new vscode.Range(insertedStart, 0, newFileLine, Number.MAX_SAFE_INTEGER), }); } return blocks; }; - - -// export const findDiffs = (oldText: string, newText: string): DiffBlock[] => { - -// const diffs = diffLines(oldText, newText); - -// const blocks: DiffBlock[] = []; - -// let reprBlock: string[] = []; -// let deletedBlock: string[] = []; -// let insertedBlock: string[] = []; - -// let insertedEnd = 0; -// let deletedEnd = 0; -// let insertedStart = 0; -// let deletedStart = 0; - -// diffs.forEach(part => { - -// part.count = part.count ?? 0 - -// // if the part is an addition or deletion, add it to the current block -// if (part.added || part.removed) { -// if (reprBlock.length === 0) { reprBlock.push('@@@@'); } -// if (part.added) { -// if (insertedBlock.length === 0) insertedStart = insertedEnd; -// insertedEnd += part.count -// insertedBlock.push(part.value); -// reprBlock.push(part.value.split('\n').map(line => `+ ${line}`).join('\n')); -// } -// if (part.removed) { -// if (deletedBlock.length === 0) deletedStart = deletedEnd; -// deletedEnd += part.count -// deletedBlock.push(part.value); -// reprBlock.push(part.value.split('\n').map(line => `- ${line}`).join('\n')); -// } -// } - -// // if the part is unchanged, finalize the block and add it to the array -// else { -// // if the block is not null, add it to the array -// if (insertedBlock.length > 0 || deletedBlock.length > 0) { -// blocks.push({ -// code: reprBlock.join('\n'), -// deletedCode: deletedBlock.join(''), -// insertedCode: insertedBlock.join(''), -// deletedRange: new vscode.Range(deletedStart, 0, deletedEnd, Number.MAX_SAFE_INTEGER), -// insertedRange: new vscode.Range(insertedStart, 0, insertedEnd, Number.MAX_SAFE_INTEGER), -// }); -// } - -// // update block variables -// reprBlock = []; -// deletedBlock = []; -// insertedBlock = []; -// insertedEnd += part.count; -// deletedEnd += part.count; - -// } - -// }) - -// // finally, add the last block to the array -// if (insertedBlock.length > 0 || deletedBlock.length > 0) { -// blocks.push({ -// code: reprBlock.join('\n'), -// deletedCode: deletedBlock.join(''), -// insertedCode: insertedBlock.join(''), -// deletedRange: new vscode.Range(deletedStart, 0, deletedEnd, Number.MAX_SAFE_INTEGER), -// insertedRange: new vscode.Range(insertedStart, 0, insertedEnd, Number.MAX_SAFE_INTEGER), -// }); -// } - -// return blocks; - -// } - - - - - - - - - - - -// import { diffLines, Change } from 'diff'; - -// export type SuggestedEdit = { -// // start/end of current file -// startLine: number; -// endLine: number; - -// // start/end of original file -// originalStartLine: number, -// originalEndLine: number, - -// // original content (originalfile[originalStart...originalEnd]) -// originalContent: string; -// newContent: string; -// } - -// 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) -// const lineByLineChanges: Change[] = diffLines(oldStr, newStr); -// console.debug('Line by line changes', lineByLineChanges) - -// 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) { -// // if we were on a streak, add it -// if (streakStartInNewFile !== undefined) { - -// const startLine = streakStartInNewFile -// const endLine = newFileLineNum - 1 // don't include current line, the edit was up to this line but not including it -// const newContent = newStrLines.slice(startLine, endLine + 1).join('\n') - -// const originalStartLine = streakStartInOldFile! -// 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 = { startLine, endLine, newContent, originalStartLine, originalEndLine, originalContent } - -// 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 - -// } \ No newline at end of file