diff --git a/extensions/void/src/common/ctrlL.ts b/extensions/void/src/common/ctrlL.ts index 255371bf..636b0f7d 100644 --- a/extensions/void/src/common/ctrlL.ts +++ b/extensions/void/src/common/ctrlL.ts @@ -63,78 +63,79 @@ ${completedStr} \`\`\` ` // create a promise that can be awaited - let res: Res = () => { } - const promise = new Promise((resolve, reject) => { res = resolve }) + const promise = new Promise((resolve, reject) => { - // get the abort method - let _abort = () => { } - let did_abort = false + // 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) => { - if (did_abort) return; + sendLLMMessage({ + messages: [{ role: 'system', content: writeFileWithDiffInstructions, }, { role: 'user', content: promptContent, }], + onText: (tokenStr, deltaStr) => { - const fullCompletedStr = completedStr + deltaStr + if (did_abort) return; - // diff `originalFileStr` and `newFileStr` - const diffs = findDiffs(oldFileStr, fullCompletedStr) - const lastDiff = diffs[diffs.length - 1] - const oldLineAfterLastDiff = lastDiff.originalRange.end.line + 1 - const newLineAfterLastDiff = lastDiff.range.end.line + 1 + // diff `originalFileStr` and `newFileStr` + const diffs = findDiffs(oldFileStr, fullCompletedStr) + const lastDiff = diffs[diffs.length - 1] + const oldLineAfterLastDiff = lastDiff.originalEndLine + 1 + const newLineAfterLastDiff = lastDiff.endLine + 1 - // check if we've generated a diff - const didGenerateDiff = newLineAfterLastDiff > next + // check if we've generated a diff + const didGenerateDiff = newLineAfterLastDiff > next - // 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) + // 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) - // 1. Apply the changes and modify highlighting + // 1. Apply the changes and modify highlighting - applyCtrlLChangesToFile({ fileUri, newCurrentLine, oldCurrentLine, fullCompletedStr, oldFileStr }) + 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) { + // 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, }); + // resolve the promise + resolve({ next: newCurrentLine + 1, oldNext: oldCurrentLine + 1, }); - // abort the LLM call - _abort() - did_abort = true + // abort the LLM call + _abort() + did_abort = true - } else { + } else { - } + } - }, - onFinalMessage: (deltaStr) => { + }, + onFinalMessage: (deltaStr) => { - const newCompletedStr = completedStr + deltaStr + const newCompletedStr = completedStr + deltaStr - applyCtrlLChangesToFile({ fileUri, newCurrentLine: Number.MAX_SAFE_INTEGER, oldCurrentLine: Number.MAX_SAFE_INTEGER, fullCompletedStr: newCompletedStr, oldFileStr, debug: 'FINAL' }) + applyCtrlLChangesToFile({ fileUri, newCurrentLine: Number.MAX_SAFE_INTEGER, oldCurrentLine: Number.MAX_SAFE_INTEGER, fullCompletedStr: newCompletedStr, oldFileStr, debug: 'FINAL' }) - res({ isFinished: true }); - }, - onError: (e) => { - res({ isFinished: true }); - console.error('Error rewriting file with diff', e); - }, - voidConfig, - setAbort: (a) => { setAbort(a); _abort = a; }, + resolve({ isFinished: true }); + }, + onError: (e) => { + resolve({ isFinished: true }); + console.error('Error rewriting file with diff', e); + }, + voidConfig, + setAbort: (a) => { setAbort(a); _abort = a; }, + }) }) + + + return promise } @@ -161,28 +162,27 @@ Return \`true\` if ANY part of the chunk should be modified, and \`false\` if it ` // create new promise - let res: Res = () => { } - const promise = new Promise((resolve, reject) => { res = resolve }) + const promise = new Promise((resolve, reject) => { + // send message to LLM + sendLLMMessage({ + messages: [{ role: 'system', content: searchDiffChunkInstructions, }, { role: 'user', content: promptContent, }], + onFinalMessage: (finalMessage) => { - // send message to LLM - sendLLMMessage({ - messages: [{ role: 'system', content: searchDiffChunkInstructions, }, { role: 'user', content: promptContent, }], - onFinalMessage: (finalMessage) => { + const containsTrue = finalMessage + .slice(-10) // check for `true` in last 10 characters + .toLowerCase() + .includes('true') - const containsTrue = finalMessage - .slice(-10) // check for `true` in last 10 characters - .toLowerCase() - .includes('true') - - res(containsTrue) - }, - onError: (e) => { - res(false); - console.error('Error in shouldApplyDiff: ', e) - }, - onText: () => { }, - voidConfig, - setAbort, + resolve(containsTrue) + }, + onError: (e) => { + resolve(false); + console.error('Error in shouldApplyDiff: ', e) + }, + onText: () => { }, + voidConfig, + setAbort, + }) }) // return the promise diff --git a/extensions/void/src/extension/findDiffs.ts b/extensions/void/src/extension/findDiffs.ts index 755b4fe3..b151a965 100644 --- a/extensions/void/src/extension/findDiffs.ts +++ b/extensions/void/src/extension/findDiffs.ts @@ -6,6 +6,138 @@ import { diffLines } from 'diff'; import { BaseDiff } from '../common/shared_types'; +// Andrew diff algo: +// 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) => { // var dmp = new diff_match_patch();