From 7f278aafcb26ae0454941a95a1f37873e2607437 Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Tue, 4 Mar 2025 01:18:10 -0800 Subject: [PATCH] fix SEARCH/REPLACE detection --- .../void/browser/autocompleteService.ts | 7 +++++- .../contrib/void/browser/editCodeService.ts | 3 +++ .../browser/helpers/extractCodeFromResult.ts | 22 +++++++------------ .../contrib/void/common/voidFileService.ts | 21 +++--------------- 4 files changed, 20 insertions(+), 33 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/autocompleteService.ts b/src/vs/workbench/contrib/void/browser/autocompleteService.ts index f9cbec7b..40746fe9 100644 --- a/src/vs/workbench/contrib/void/browser/autocompleteService.ts +++ b/src/vs/workbench/contrib/void/browser/autocompleteService.ts @@ -18,9 +18,14 @@ import { IModelService } from '../../../../editor/common/services/model.js'; import { extractCodeFromRegular } from './helpers/extractCodeFromResult.js'; import { registerWorkbenchContribution2, WorkbenchPhase } from '../../../common/contributions.js'; import { ILLMMessageService } from '../common/llmMessageService.js'; -import { _ln, allLinebreakSymbols } from '../common/voidFileService.js'; +import { isWindows } from '../../../../base/common/platform.js'; // import { IContextGatheringService } from './contextGatheringService.js'; + + +const allLinebreakSymbols = ['\r\n', '\n'] +const _ln = isWindows ? allLinebreakSymbols[0] : allLinebreakSymbols[1] + // The extension this was called from is here - https://github.com/voideditor/void/blob/autocomplete/extensions/void/src/extension/extension.ts diff --git a/src/vs/workbench/contrib/void/browser/editCodeService.ts b/src/vs/workbench/contrib/void/browser/editCodeService.ts index 9b55b75e..e8637609 100644 --- a/src/vs/workbench/contrib/void/browser/editCodeService.ts +++ b/src/vs/workbench/contrib/void/browser/editCodeService.ts @@ -1588,6 +1588,7 @@ class EditCodeService extends Disposable implements IEditCodeService { // if error if (typeof originalBounds === 'string') { + console.error('Error in originalBounds, retrying.', originalBounds) messages.push( { role: 'assistant', content: fullText }, // latest output { role: 'user', content: errMsgOfInvalidStr(originalBounds) } // user explanation of what's wrong @@ -1663,6 +1664,8 @@ class EditCodeService extends Disposable implements IEditCodeService { this._notificationService.info(`Void: We ran Apply, but the LLM didn't output any changes.`) } + await new Promise(resolve => setTimeout(resolve, 500)) + // writeover the whole file let newCode = originalFileCode for (let blockNum = addedTrackingZoneOfBlockNum.length - 1; blockNum >= 0; blockNum -= 1) { diff --git a/src/vs/workbench/contrib/void/browser/helpers/extractCodeFromResult.ts b/src/vs/workbench/contrib/void/browser/helpers/extractCodeFromResult.ts index e24bc232..5a492cd2 100644 --- a/src/vs/workbench/contrib/void/browser/helpers/extractCodeFromResult.ts +++ b/src/vs/workbench/contrib/void/browser/helpers/extractCodeFromResult.ts @@ -182,10 +182,9 @@ const endsWithAnyPrefixOf = (str: string, anyPrefix: string) => { // guarantees if you keep adding text, array length will strictly grow and state will progress without going back export const extractSearchReplaceBlocks = (str: string) => { - const ORIGINAL_ = ORIGINAL + `\n` - const DIVIDER_ = '\n' + DIVIDER + `\n` - // logic for FINAL_ is slightly more complicated - should be '\n' + FINAL, but that ignores if the final output is empty + const DIVIDER_ = DIVIDER + `\n` + // we only check FINAL, we don't care about FINAL + '\n' because the string is over const blocks: ExtractedSearchReplaceBlock[] = [] @@ -196,7 +195,7 @@ export const extractSearchReplaceBlocks = (str: string) => { if (origStart === -1) { return blocks } origStart += ORIGINAL_.length i = origStart - // wrote <<<< ORIGINAL + // wrote <<<< ORIGINAL\n let dividerStart = str.indexOf(DIVIDER_, i) if (dividerStart === -1) { // if didnt find DIVIDER_, either writing originalStr or DIVIDER_ right now @@ -211,17 +210,13 @@ export const extractSearchReplaceBlocks = (str: string) => { const origStrDone = str.substring(origStart, dividerStart) dividerStart += DIVIDER_.length i = dividerStart - // wrote ===== + // wrote \n=====\n - const finalStartA = str.indexOf(FINAL, i) - const finalStartB = str.indexOf('\n' + FINAL, i) // go with B if possible, else fallback to A, it's more permissive - const FINAL_ = finalStartB !== -1 ? '\n' + FINAL : FINAL - let finalStart = finalStartB !== -1 ? finalStartB : finalStartA - - if (finalStart === -1) { // if didnt find FINAL_, either writing finalStr or FINAL_ right now - const isWritingFINAL = endsWithAnyPrefixOf(str, FINAL_) + const finalStart = str.indexOf(FINAL, i) + if (finalStart === -1) { // if didnt find FINAL, either writing finalStr or FINAL right now + const isWritingFINAL = endsWithAnyPrefixOf(str, FINAL) blocks.push({ orig: origStrDone, final: str.substring(dividerStart, str.length - (isWritingFINAL?.length ?? 0)), @@ -230,8 +225,7 @@ export const extractSearchReplaceBlocks = (str: string) => { return blocks } const finalStrDone = str.substring(dividerStart, finalStart) - finalStart += FINAL_.length - i = finalStart + i = finalStart + FINAL.length // wrote >>>>> FINAL blocks.push({ diff --git a/src/vs/workbench/contrib/void/common/voidFileService.ts b/src/vs/workbench/contrib/void/common/voidFileService.ts index a7c25631..cebad454 100644 --- a/src/vs/workbench/contrib/void/common/voidFileService.ts +++ b/src/vs/workbench/contrib/void/common/voidFileService.ts @@ -3,7 +3,6 @@ * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information. *--------------------------------------------------------------------------------------*/ -import { isWindows } from '../../../../base/common/platform.js'; import { URI } from '../../../../base/common/uri.js'; import { EndOfLinePreference } from '../../../../editor/common/model.js'; import { IModelService } from '../../../../editor/common/services/model.js'; @@ -11,11 +10,6 @@ import { IFileService } from '../../../../platform/files/common/files.js'; import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js'; import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; - -// linebreak symbols -export const allLinebreakSymbols = ['\r\n', '\n'] -export const _ln = isWindows ? allLinebreakSymbols[0] : allLinebreakSymbols[1] - export interface IVoidFileService { readonly _serviceBrand: undefined; @@ -52,19 +46,10 @@ export class VoidFileService implements IVoidFileService { _readFileRaw = async (uri: URI, range?: { startLineNumber: number, endLineNumber: number }): Promise => { try { // this throws an error if no file exists (eg it was deleted) - const res = await this.fileService.readFile(uri); - - if (range) { - return res.value.toString() - .split(_ln) - .slice(range.startLineNumber - 1, range.endLineNumber) - .join(_ln) - } - - return res.value.toString(); - - + const str = res.value.toString().replace(/\r\n/g, '\n'); // even if not on Windows, might read a file with \r\n + if (range) return str.split('\n').slice(range.startLineNumber - 1, range.endLineNumber).join('\n') + return str; } catch (e) { return null; }