mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
keep-conflicts on apply
This commit is contained in:
parent
9ab3ec3c11
commit
b305fc5034
5 changed files with 209 additions and 200 deletions
|
|
@ -512,11 +512,11 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
const buttonsWidget = new AcceptAllRejectAllWidget({
|
||||
editor,
|
||||
onAcceptAll: () => {
|
||||
this.removeDiffAreas({ uri, behavior: 'accept', removeCtrlKs: false })
|
||||
this.acceptOrRejectDiffAreas({ uri, behavior: 'accept', removeCtrlKs: false, _addToHistory: true })
|
||||
this._metricsService.capture('Accept All', {})
|
||||
},
|
||||
onRejectAll: () => {
|
||||
this.removeDiffAreas({ uri, behavior: 'reject', removeCtrlKs: false })
|
||||
this.acceptOrRejectDiffAreas({ uri, behavior: 'reject', removeCtrlKs: false, _addToHistory: true })
|
||||
this._metricsService.capture('Reject All', {})
|
||||
},
|
||||
instantiationService: this._instantiationService,
|
||||
|
|
@ -1297,74 +1297,47 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
|
||||
|
||||
|
||||
private async _initializeWriteoverStream(opts: StartApplyingOpts): Promise<[DiffZone, Promise<void>] | undefined> {
|
||||
|
||||
const { from, } = opts
|
||||
|
||||
let startLine: number
|
||||
let endLine: number
|
||||
let uri: URI
|
||||
let currentFileStr: string
|
||||
|
||||
if (from === 'ClickApply') {
|
||||
const uri_ = this._getActiveEditorURI()
|
||||
if (!uri_) return
|
||||
uri = uri_
|
||||
await this._voidModelService.initializeModel(uri)
|
||||
const { model } = this._voidModelService.getModel(uri)
|
||||
if (!model) return
|
||||
|
||||
currentFileStr = model.getValue(EndOfLinePreference.LF)
|
||||
const numLines = model.getLineCount()
|
||||
|
||||
// remove all diffZones on this URI, adding to history (there can't possibly be overlap after this)
|
||||
const behavior: 'accept' | 'reject' = opts.startBehavior === 'accept-conflicts' ? 'accept' : 'reject'
|
||||
this.removeDiffAreas({ uri, behavior, removeCtrlKs: true })
|
||||
|
||||
// in ctrl+L the start and end lines are the full document
|
||||
startLine = 1
|
||||
endLine = numLines
|
||||
}
|
||||
else if (from === 'QuickEdit') {
|
||||
const { diffareaid } = opts
|
||||
const ctrlKZone = this.diffAreaOfId[diffareaid]
|
||||
if (ctrlKZone.type !== 'CtrlKZone') return
|
||||
|
||||
const { startLine: startLine_, endLine: endLine_, _URI } = ctrlKZone
|
||||
uri = _URI
|
||||
await this._voidModelService.initializeModel(uri)
|
||||
const { model } = this._voidModelService.getModel(uri)
|
||||
if (!model) return
|
||||
currentFileStr = model.getValue(EndOfLinePreference.LF)
|
||||
|
||||
startLine = startLine_
|
||||
endLine = endLine_
|
||||
}
|
||||
else {
|
||||
throw new Error(`Void: diff.type not recognized on: ${from}`)
|
||||
}
|
||||
|
||||
private _startStreamingDiffZone({
|
||||
uri,
|
||||
startRange,
|
||||
startBehavior,
|
||||
streamRequestIdRef,
|
||||
onUndo,
|
||||
}: {
|
||||
uri: URI,
|
||||
startRange: 'fullFile' | [number, number],
|
||||
startBehavior: 'accept-conflicts' | 'reject-conflicts' | 'keep-conflicts',
|
||||
streamRequestIdRef: { current: string | null },
|
||||
onUndo: () => void,
|
||||
}) {
|
||||
const { model } = this._voidModelService.getModel(uri)
|
||||
if (!model) return
|
||||
|
||||
const originalCode = currentFileStr.split('\n').slice((startLine - 1), (endLine - 1) + 1).join('\n')
|
||||
const language = model.getLanguageId()
|
||||
const startLine = startRange === 'fullFile' ? 1 : startRange[0]
|
||||
const endLine = startRange === 'fullFile' ? model.getLineCount() : startRange[1]
|
||||
let originalCode = startRange === 'fullFile' ? model.getValue(EndOfLinePreference.LF) : model.getValue(EndOfLinePreference.LF).split('\n').slice((startLine - 1), (endLine - 1) + 1).join('\n')
|
||||
|
||||
let streamRequestIdRef: { current: string | null } = { current: null }
|
||||
const diffZones = this._getDiffZonesOnURI(uri)
|
||||
|
||||
// promise that resolves when the apply is done
|
||||
let resApplyPromise: () => void
|
||||
let rejApplyPromise: (e: any) => void
|
||||
const applyPromise = new Promise<void>((res_, rej_) => { resApplyPromise = res_; rejApplyPromise = rej_ })
|
||||
// clear diffZones so no conflict
|
||||
if (startBehavior === 'keep-conflicts' && diffZones.length !== 0) {
|
||||
// delete them then re-apply their change
|
||||
this.acceptOrRejectDiffAreas({ uri, removeCtrlKs: true, behavior: 'reject', _addToHistory: false })
|
||||
const originalCodeReplacement = model.getValue(EndOfLinePreference.LF) // use this as original code
|
||||
this._writeURIText(uri, originalCode, 'wholeFileRange', { shouldRealignDiffAreas: false }) // un-revert
|
||||
originalCode = originalCodeReplacement
|
||||
}
|
||||
else {
|
||||
const behavior = startBehavior === 'accept-conflicts' ? 'accept'
|
||||
: startBehavior === 'reject-conflicts' ? 'reject'
|
||||
: startBehavior === 'keep-conflicts' ? null // do nothing
|
||||
: null
|
||||
|
||||
|
||||
// add to history
|
||||
const { onFinishEdit } = this._addToHistory(uri, {
|
||||
onUndo: () => { if (diffZone._streamState.isStreaming) rejApplyPromise(new Error('Edit was interrupted by pressing undo.')) }
|
||||
})
|
||||
|
||||
// TODO!!! let users customize modelFimTags
|
||||
const quickEditFIMTags = defaultQuickEditFimTags
|
||||
if (behavior)
|
||||
this.acceptOrRejectDiffAreas({ uri, removeCtrlKs: true, behavior: behavior, _addToHistory: false })
|
||||
}
|
||||
|
||||
const adding: Omit<DiffZone, 'diffareaid'> = {
|
||||
type: 'DiffZone',
|
||||
|
|
@ -1380,24 +1353,75 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
_diffOfId: {}, // added later
|
||||
_removeStylesFns: new Set(),
|
||||
}
|
||||
|
||||
const diffZone = this._addDiffArea(adding)
|
||||
this._onDidChangeDiffZoneStreaming.fire({ uri, diffareaid: diffZone.diffareaid })
|
||||
this._onDidAddOrDeleteDiffZones.fire({ uri })
|
||||
|
||||
// add to history
|
||||
const { onFinishEdit } = this._addToHistory(uri, { onUndo })
|
||||
return { diffZone, onFinishEdit }
|
||||
}
|
||||
|
||||
|
||||
if (from === 'QuickEdit') {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private async _initializeWriteoverStream(opts: StartApplyingOpts): Promise<[DiffZone, Promise<void>] | undefined> {
|
||||
|
||||
const { from, } = opts
|
||||
|
||||
let uri: URI
|
||||
let startRange: 'fullFile' | [number, number]
|
||||
|
||||
if (from === 'ClickApply') {
|
||||
const uri_ = this._getActiveEditorURI()
|
||||
if (!uri_) return
|
||||
uri = uri_
|
||||
startRange = 'fullFile'
|
||||
}
|
||||
else if (from === 'QuickEdit') {
|
||||
const { diffareaid } = opts
|
||||
const ctrlKZone = this.diffAreaOfId[diffareaid]
|
||||
if (ctrlKZone.type !== 'CtrlKZone') return
|
||||
|
||||
ctrlKZone._linkedStreamingDiffZone = diffZone.diffareaid
|
||||
this._onDidChangeCtrlKZoneStreaming.fire({ uri, diffareaid: ctrlKZone.diffareaid })
|
||||
const { startLine: startLine_, endLine: endLine_, _URI } = ctrlKZone
|
||||
uri = _URI
|
||||
startRange = [startLine_, endLine_]
|
||||
}
|
||||
else {
|
||||
throw new Error(`Void: diff.type not recognized on: ${from}`)
|
||||
}
|
||||
|
||||
// now handle messages
|
||||
let messages: LLMChatMessage[]
|
||||
await this._voidModelService.initializeModel(uri)
|
||||
const { model } = this._voidModelService.getModel(uri)
|
||||
if (!model) return
|
||||
|
||||
|
||||
// promise that resolves when the apply is done
|
||||
let resApplyPromise: () => void
|
||||
let rejApplyPromise: (e: any) => void
|
||||
const applyPromise = new Promise<void>((res_, rej_) => { resApplyPromise = res_; rejApplyPromise = rej_ })
|
||||
let streamRequestIdRef: { current: string | null } = { current: null } // can use this as a proxy to set the diffArea's stream state requestId
|
||||
|
||||
// start diffzone
|
||||
const res = this._startStreamingDiffZone({
|
||||
uri,
|
||||
streamRequestIdRef,
|
||||
startRange,
|
||||
startBehavior: opts.startBehavior,
|
||||
onUndo: () => { if (diffZone._streamState.isStreaming) rejApplyPromise(new Error('Edit was interrupted by pressing undo.')) },
|
||||
})
|
||||
if (!res) return
|
||||
const { diffZone, onFinishEdit } = res
|
||||
|
||||
// build messages
|
||||
const quickEditFIMTags = defaultQuickEditFimTags // TODO can eventually let users customize modelFimTags
|
||||
const originalFileCode = model.getValue(EndOfLinePreference.LF)
|
||||
const originalCode = startRange === 'fullFile' ? originalFileCode : originalFileCode.split('\n').slice((startRange[0] - 1), (startRange[1] - 1) + 1).join('\n')
|
||||
const language = model.getLanguageId()
|
||||
let messages: LLMChatMessage[]
|
||||
if (from === 'ClickApply') {
|
||||
const userContent = rewriteCode_userMessage({ originalCode, applyStr: opts.applyStr, language })
|
||||
messages = [
|
||||
|
|
@ -1412,7 +1436,9 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
const { _mountInfo } = ctrlKZone
|
||||
const instructions = _mountInfo?.textAreaRef.current?.value ?? ''
|
||||
|
||||
const { prefix, suffix } = voidPrefixAndSuffix({ fullFileStr: currentFileStr, startLine, endLine })
|
||||
const startLine = startRange === 'fullFile' ? 1 : startRange[0]
|
||||
const endLine = startRange === 'fullFile' ? model.getLineCount() : startRange[1]
|
||||
const { prefix, suffix } = voidPrefixAndSuffix({ fullFileStr: originalFileCode, startLine, endLine })
|
||||
const userContent = ctrlKStream_userMessage({ selection: originalCode, instructions: instructions, prefix, suffix, isOllamaFIM: false, fimTags: quickEditFIMTags, language })
|
||||
// type: 'messages',
|
||||
messages = [
|
||||
|
|
@ -1423,6 +1449,17 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
else { throw new Error(`featureName ${from} is invalid`) }
|
||||
|
||||
|
||||
// a few items related to writeover streams and quickEdits
|
||||
if (from === 'QuickEdit') {
|
||||
const { diffareaid } = opts
|
||||
const ctrlKZone = this.diffAreaOfId[diffareaid]
|
||||
if (ctrlKZone.type !== 'CtrlKZone') return
|
||||
|
||||
ctrlKZone._linkedStreamingDiffZone = diffZone.diffareaid
|
||||
this._onDidChangeCtrlKZoneStreaming.fire({ uri, diffareaid: ctrlKZone.diffareaid })
|
||||
}
|
||||
|
||||
// helpers
|
||||
const onDone = () => {
|
||||
console.log('called onDone')
|
||||
diffZone._streamState = { isStreaming: false, }
|
||||
|
|
@ -1439,10 +1476,6 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
onFinishEdit()
|
||||
}
|
||||
|
||||
// refresh now in case onText takes a while to get 1st message
|
||||
this._refreshStylesAndDiffsInURI(uri)
|
||||
|
||||
|
||||
const extractText = (fullText: string, recentlyAddedTextLen: number) => {
|
||||
if (from === 'QuickEdit') {
|
||||
return extractCodeFromFIM({ text: fullText, recentlyAddedTextLen, midTag: quickEditFIMTags.midTag })
|
||||
|
|
@ -1453,76 +1486,82 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
throw new Error('Void 1')
|
||||
}
|
||||
|
||||
const latestStreamInfoMutable: StreamLocationMutable = { line: diffZone.startLine, addedSplitYet: false, col: 1, originalCodeStartLine: 1 }
|
||||
|
||||
// refresh now in case onText takes a while to get 1st message
|
||||
this._refreshStylesAndDiffsInURI(uri)
|
||||
|
||||
const latestStreamLocationMutable: StreamLocationMutable = { line: diffZone.startLine, addedSplitYet: false, col: 1, originalCodeStartLine: 1 }
|
||||
|
||||
const featureName: FeatureName = opts.from === 'ClickApply' ? 'Apply' : 'Ctrl+K'
|
||||
const modelSelection = this._settingsService.state.modelSelectionOfFeature[featureName]
|
||||
const modelSelectionOptions = modelSelection ? this._settingsService.state.optionsOfModelSelection[modelSelection.providerName]?.[modelSelection.modelName] : undefined
|
||||
|
||||
const writeover = async () => {
|
||||
let shouldSendAnotherMessage = true
|
||||
while (shouldSendAnotherMessage) {
|
||||
shouldSendAnotherMessage = false
|
||||
|
||||
let resMessageDonePromise: () => void = () => { }
|
||||
const messageDonePromise = new Promise<void>((res_) => { resMessageDonePromise = res_ })
|
||||
let resMessageDonePromise: () => void = () => { }
|
||||
const messageDonePromise = new Promise<void>((res_) => { resMessageDonePromise = res_ })
|
||||
|
||||
// state used in onText:
|
||||
let fullTextSoFar = '' // so far (INCLUDING ignored suffix)
|
||||
let prevIgnoredSuffix = ''
|
||||
let aborted = false
|
||||
// state used in onText:
|
||||
let fullTextSoFar = '' // so far (INCLUDING ignored suffix)
|
||||
let prevIgnoredSuffix = ''
|
||||
let aborted = false
|
||||
|
||||
streamRequestIdRef.current = this._llmMessageService.sendLLMMessage({
|
||||
messagesType: 'chatMessages',
|
||||
logging: { loggingName: `Edit (Writeover) - ${from}` },
|
||||
messages,
|
||||
modelSelection,
|
||||
modelSelectionOptions,
|
||||
onText: (params) => {
|
||||
const { fullText: fullText_ } = params
|
||||
const newText_ = fullText_.substring(fullTextSoFar.length, Infinity)
|
||||
streamRequestIdRef.current = this._llmMessageService.sendLLMMessage({
|
||||
messagesType: 'chatMessages',
|
||||
logging: { loggingName: `Edit (Writeover) - ${from}` },
|
||||
messages,
|
||||
modelSelection,
|
||||
modelSelectionOptions,
|
||||
onText: (params) => {
|
||||
const { fullText: fullText_ } = params
|
||||
const newText_ = fullText_.substring(fullTextSoFar.length, Infinity)
|
||||
|
||||
const newText = prevIgnoredSuffix + newText_ // add the previously ignored suffix because it's no longer the suffix!
|
||||
fullTextSoFar += newText // full text, including ```, etc
|
||||
const newText = prevIgnoredSuffix + newText_ // add the previously ignored suffix because it's no longer the suffix!
|
||||
fullTextSoFar += newText // full text, including ```, etc
|
||||
|
||||
const [croppedText, deltaCroppedText, croppedSuffix] = extractText(fullTextSoFar, newText.length)
|
||||
const { endLineInLlmTextSoFar } = this._writeStreamedDiffZoneLLMText(uri, originalCode, croppedText, deltaCroppedText, latestStreamInfoMutable)
|
||||
diffZone._streamState.line = (diffZone.startLine - 1) + endLineInLlmTextSoFar // change coordinate systems from originalCode to full file
|
||||
const [croppedText, deltaCroppedText, croppedSuffix] = extractText(fullTextSoFar, newText.length)
|
||||
const { endLineInLlmTextSoFar } = this._writeStreamedDiffZoneLLMText(uri, originalCode, croppedText, deltaCroppedText, latestStreamLocationMutable)
|
||||
diffZone._streamState.line = (diffZone.startLine - 1) + endLineInLlmTextSoFar // change coordinate systems from originalCode to full file
|
||||
|
||||
this._refreshStylesAndDiffsInURI(uri)
|
||||
this._refreshStylesAndDiffsInURI(uri)
|
||||
|
||||
prevIgnoredSuffix = croppedSuffix
|
||||
},
|
||||
onFinalMessage: (params) => {
|
||||
const { fullText } = params
|
||||
// console.log('DONE! FULL TEXT\n', extractText(fullText), diffZone.startLine, diffZone.endLine)
|
||||
// at the end, re-write whole thing to make sure no sync errors
|
||||
const [croppedText, _1, _2] = extractText(fullText, 0)
|
||||
this._writeURIText(uri, croppedText,
|
||||
{ startLineNumber: diffZone.startLine, startColumn: 1, endLineNumber: diffZone.endLine, endColumn: Number.MAX_SAFE_INTEGER }, // 1-indexed
|
||||
{ shouldRealignDiffAreas: true }
|
||||
)
|
||||
prevIgnoredSuffix = croppedSuffix
|
||||
},
|
||||
onFinalMessage: (params) => {
|
||||
const { fullText } = params
|
||||
// console.log('DONE! FULL TEXT\n', extractText(fullText), diffZone.startLine, diffZone.endLine)
|
||||
// at the end, re-write whole thing to make sure no sync errors
|
||||
const [croppedText, _1, _2] = extractText(fullText, 0)
|
||||
this._writeURIText(uri, croppedText,
|
||||
{ startLineNumber: diffZone.startLine, startColumn: 1, endLineNumber: diffZone.endLine, endColumn: Number.MAX_SAFE_INTEGER }, // 1-indexed
|
||||
{ shouldRealignDiffAreas: true }
|
||||
)
|
||||
|
||||
onDone()
|
||||
resMessageDonePromise()
|
||||
},
|
||||
onError: (e) => {
|
||||
this._notifyError(e)
|
||||
onDone()
|
||||
this._undoHistory(uri)
|
||||
resMessageDonePromise()
|
||||
},
|
||||
onAbort: () => {
|
||||
// stop the loop to free up the promise, but don't modify state (already handled by whatever stopped it)
|
||||
resMessageDonePromise()
|
||||
aborted = true
|
||||
},
|
||||
})
|
||||
// should never happen, just for safety
|
||||
if (streamRequestIdRef.current === null) { return }
|
||||
onDone()
|
||||
resMessageDonePromise()
|
||||
},
|
||||
onError: (e) => {
|
||||
this._notifyError(e)
|
||||
onDone()
|
||||
this._undoHistory(uri)
|
||||
resMessageDonePromise()
|
||||
},
|
||||
onAbort: () => {
|
||||
// stop the loop to free up the promise, but don't modify state (already handled by whatever stopped it)
|
||||
resMessageDonePromise()
|
||||
aborted = true
|
||||
},
|
||||
})
|
||||
// should never happen, just for safety
|
||||
if (streamRequestIdRef.current === null) { return }
|
||||
|
||||
await messageDonePromise
|
||||
if (aborted) { return }
|
||||
|
||||
}
|
||||
await messageDonePromise
|
||||
if (aborted) { return }
|
||||
} // end while
|
||||
} // end writeover
|
||||
|
||||
writeover().then(() => {
|
||||
resApplyPromise()
|
||||
|
|
@ -1549,70 +1588,39 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
}
|
||||
|
||||
await this._voidModelService.initializeModel(uri)
|
||||
|
||||
const { model } = this._voidModelService.getModel(uri)
|
||||
if (!model) return
|
||||
|
||||
// generate search/replace block text
|
||||
// promise that resolves when the apply is done
|
||||
let resApplyDonePromise: () => void
|
||||
let rejApplyDonePromise: (e: any) => void
|
||||
const applyDonePromise = new Promise<void>((res_, rej_) => { resApplyDonePromise = res_; rejApplyDonePromise = rej_ })
|
||||
let streamRequestIdRef: { current: string | null } = { current: null } // can use this as a proxy to set the diffArea's stream state requestId
|
||||
|
||||
// start diffzone
|
||||
const res = this._startStreamingDiffZone({
|
||||
uri,
|
||||
streamRequestIdRef,
|
||||
startRange: 'fullFile',
|
||||
startBehavior: opts.startBehavior,
|
||||
onUndo: () => { if (diffZone._streamState.isStreaming) rejApplyDonePromise(new Error('Edit was interrupted by user pressing undo.')) },
|
||||
})
|
||||
if (!res) return
|
||||
const { diffZone, onFinishEdit } = res
|
||||
|
||||
// build messages - ask LLM to generate search/replace block text
|
||||
const originalFileCode = model.getValue(EndOfLinePreference.LF)
|
||||
const numLines = model.getLineCount()
|
||||
|
||||
// Only reject diffZones if we're not using keep-conflicts
|
||||
if (opts.startBehavior !== 'keep-conflicts') {
|
||||
// reject all diffZones on this URI, adding to history (there can't possibly be overlap after this)
|
||||
this.removeDiffAreas({ uri, behavior: 'reject', removeCtrlKs: true })
|
||||
}
|
||||
|
||||
const startLine = 1
|
||||
const endLine = numLines
|
||||
|
||||
const userMessageContent = searchReplace_userMessage({ originalCode: originalFileCode, applyStr: applyStr })
|
||||
const messages: LLMChatMessage[] = [
|
||||
{ role: 'system', content: searchReplace_systemMessage },
|
||||
{ role: 'user', content: userMessageContent },
|
||||
]
|
||||
|
||||
// can use this as a proxy to set the diffArea's stream state requestId
|
||||
let streamRequestIdRef: { current: string | null } = { current: null }
|
||||
|
||||
|
||||
// promise that resolves when the apply is done
|
||||
let resApplyDonePromise: () => void
|
||||
let rejApplyDonePromise: (e: any) => void
|
||||
const applyDonePromise = new Promise<void>((res_, rej_) => { resApplyDonePromise = res_; rejApplyDonePromise = rej_ })
|
||||
|
||||
// add to history
|
||||
const { onFinishEdit } = this._addToHistory(uri, {
|
||||
onUndo: () => { if (diffZone._streamState.isStreaming) rejApplyDonePromise(new Error('Edit was interrupted by pressing undo.')) }
|
||||
})
|
||||
|
||||
// TODO replace these with whatever block we're on initially if already started (if add caching of apply S/R blocks)
|
||||
|
||||
// helpers
|
||||
type SearchReplaceDiffAreaMetadata = {
|
||||
originalBounds: [number, number], // 1-indexed
|
||||
originalCode: string,
|
||||
}
|
||||
|
||||
|
||||
const adding: Omit<DiffZone, 'diffareaid'> = {
|
||||
type: 'DiffZone',
|
||||
originalCode: originalFileCode,
|
||||
startLine,
|
||||
endLine,
|
||||
_URI: uri,
|
||||
_streamState: {
|
||||
isStreaming: true,
|
||||
streamRequestIdRef,
|
||||
line: startLine,
|
||||
},
|
||||
_diffOfId: {}, // added later
|
||||
_removeStylesFns: new Set(),
|
||||
}
|
||||
const diffZone = this._addDiffArea(adding)
|
||||
this._onDidChangeDiffZoneStreaming.fire({ uri, diffareaid: diffZone.diffareaid })
|
||||
this._onDidAddOrDeleteDiffZones.fire({ uri })
|
||||
|
||||
|
||||
const convertOriginalRangeToFinalRange = (originalRange: readonly [number, number]): [number, number] => {
|
||||
// adjust based on the changes by computing line offset
|
||||
const [originalStart, originalEnd] = originalRange
|
||||
|
|
@ -1651,7 +1659,6 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
|
||||
}
|
||||
|
||||
|
||||
const onDone = () => {
|
||||
diffZone._streamState = { isStreaming: false, }
|
||||
this._onDidChangeDiffZoneStreaming.fire({ uri, diffareaid: diffZone.diffareaid })
|
||||
|
|
@ -1667,21 +1674,16 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
// refresh now in case onText takes a while to get 1st message
|
||||
this._refreshStylesAndDiffsInURI(uri)
|
||||
|
||||
// stateful
|
||||
const addedTrackingZoneOfBlockNum: TrackingZone<SearchReplaceDiffAreaMetadata>[] = []
|
||||
|
||||
// stream style related
|
||||
// stream style related - TODO replace these with whatever block we're on initially if already started (if add caching of apply S/R blocks)
|
||||
let latestStreamLocationMutable: StreamLocationMutable | null = null
|
||||
let shouldUpdateOrigStreamStyle = true
|
||||
|
||||
let oldBlocks: ExtractedSearchReplaceBlock[] = []
|
||||
|
||||
const addedTrackingZoneOfBlockNum: TrackingZone<SearchReplaceDiffAreaMetadata>[] = []
|
||||
|
||||
const featureName: FeatureName = 'Apply'
|
||||
const modelSelection = this._settingsService.state.modelSelectionOfFeature[featureName]
|
||||
const modelSelectionOptions = modelSelection ? this._settingsService.state.optionsOfModelSelection[modelSelection.providerName]?.[modelSelection.modelName] : undefined
|
||||
|
||||
|
||||
const retryLoop = async () => {
|
||||
// this generates >>>>>>> ORIGINAL <<<<<<< REPLACE blocks and and simultaneously applies it
|
||||
let shouldSendAnotherMessage = true
|
||||
|
|
@ -1692,7 +1694,6 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
while (shouldSendAnotherMessage) {
|
||||
shouldSendAnotherMessage = false
|
||||
nMessagesSent += 1
|
||||
|
||||
if (nMessagesSent >= 5) {
|
||||
this._notifyError({ message: 'Tried to Fast Apply 5 times but failed. Please try again with a smarter model or disable Fast Apply.', fullError: null })
|
||||
onDone()
|
||||
|
|
@ -1922,7 +1923,7 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
|
||||
retryLoop().then(() => {
|
||||
console.log('resolving Apply Done')
|
||||
resApplyDonePromise();
|
||||
resApplyDonePromise()
|
||||
// this._noLongerNeedModelReference(uri)
|
||||
}).catch((e) => rejApplyDonePromise(e))
|
||||
|
||||
|
|
@ -1983,14 +1984,18 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
getURIStreamState = ({ uri }: { uri: URI | null }) => {
|
||||
if (uri === null) return 'idle'
|
||||
|
||||
private _getDiffZonesOnURI(uri: URI) {
|
||||
const diffZones = [...this.diffAreasOfURI[uri.fsPath]?.values() ?? []]
|
||||
.map(diffareaid => this.diffAreaOfId[diffareaid])
|
||||
.filter(diffArea => !!diffArea && diffArea.type === 'DiffZone')
|
||||
|
||||
return diffZones
|
||||
}
|
||||
|
||||
getURIStreamState = ({ uri }: { uri: URI | null }) => {
|
||||
if (uri === null) return 'idle'
|
||||
const diffZones = this._getDiffZonesOnURI(uri)
|
||||
|
||||
const isStreaming = diffZones.find(diffZone => !!diffZone._streamState.isStreaming)
|
||||
|
||||
const state: URIStreamState = isStreaming ? 'streaming' : (diffZones.length === 0 ? 'idle' : 'acceptRejectAll')
|
||||
|
|
@ -2032,12 +2037,12 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
|
||||
|
||||
// remove a batch of diffareas all at once (and handle accept/reject of their diffs)
|
||||
public removeDiffAreas({ uri, removeCtrlKs, behavior }: { uri: URI, removeCtrlKs: boolean, behavior: 'reject' | 'accept' }) {
|
||||
public acceptOrRejectDiffAreas: IEditCodeService['acceptOrRejectDiffAreas'] = async ({ uri, behavior, removeCtrlKs, _addToHistory }) => {
|
||||
|
||||
const diffareaids = this.diffAreasOfURI[uri.fsPath]
|
||||
if ((diffareaids?.size ?? 0) === 0) return // do nothing
|
||||
|
||||
const { onFinishEdit } = this._addToHistory(uri)
|
||||
const { onFinishEdit } = _addToHistory === false ? { onFinishEdit: () => { } } : this._addToHistory(uri)
|
||||
|
||||
for (const diffareaid of diffareaids ?? []) {
|
||||
const diffArea = this.diffAreaOfId[diffareaid]
|
||||
|
|
@ -2061,6 +2066,8 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
// called on void.acceptDiff
|
||||
public async acceptDiff({ diffid }: { diffid: number }) {
|
||||
|
||||
// TODO could use an ITextModelto do this instead, would be much simpler
|
||||
|
||||
const diff = this.diffOfId[diffid]
|
||||
if (!diff) return
|
||||
|
||||
|
|
|
|||
|
|
@ -11,15 +11,17 @@ import { Diff, DiffArea } from './editCodeService.js';
|
|||
|
||||
|
||||
|
||||
export type StartBehavior = 'accept-conflicts' | 'reject-conflicts' | 'keep-conflicts'
|
||||
|
||||
export type StartApplyingOpts = ({
|
||||
from: 'QuickEdit';
|
||||
diffareaid: number; // id of the CtrlK area (contains text selection)
|
||||
startBehavior: StartBehavior;
|
||||
} | {
|
||||
from: 'ClickApply';
|
||||
applyStr: string;
|
||||
uri: 'current' | URI;
|
||||
startBehavior: 'accept-conflicts' | 'reject-conflicts' | 'keep-conflicts';
|
||||
startBehavior: StartBehavior;
|
||||
})
|
||||
|
||||
|
||||
|
|
@ -50,7 +52,7 @@ export interface IEditCodeService {
|
|||
addCtrlKZone(opts: AddCtrlKOpts): number | undefined;
|
||||
|
||||
removeCtrlKZone(opts: { diffareaid: number }): void;
|
||||
removeDiffAreas(opts: { uri: URI, removeCtrlKs: boolean, behavior: 'reject' | 'accept' }): void;
|
||||
acceptOrRejectDiffAreas(opts: { uri: URI, removeCtrlKs: boolean, behavior: 'reject' | 'accept', _addToHistory?: boolean }): void;
|
||||
|
||||
onDidAddOrDeleteDiffZones: Event<{ uri: URI }>;
|
||||
onDidAddOrDeleteDiffInDiffZone: Event<{ uri: URI }>;
|
||||
|
|
|
|||
|
|
@ -177,12 +177,12 @@ export const useApplyButtonHTML = ({ codeStr, applyBoxId, uri }: { codeStr: stri
|
|||
|
||||
const onAccept = useCallback(() => {
|
||||
const uri = getUriBeingApplied()
|
||||
if (uri) editCodeService.removeDiffAreas({ uri, behavior: 'accept', removeCtrlKs: false })
|
||||
if (uri) editCodeService.acceptOrRejectDiffAreas({ uri, behavior: 'accept', removeCtrlKs: false })
|
||||
}, [getUriBeingApplied, editCodeService])
|
||||
|
||||
const onReject = useCallback(() => {
|
||||
const uri = getUriBeingApplied()
|
||||
if (uri) editCodeService.removeDiffAreas({ uri, behavior: 'reject', removeCtrlKs: false })
|
||||
if (uri) editCodeService.acceptOrRejectDiffAreas({ uri, behavior: 'reject', removeCtrlKs: false })
|
||||
}, [getUriBeingApplied, editCodeService])
|
||||
|
||||
const onReapply = useCallback(() => {
|
||||
|
|
|
|||
|
|
@ -1118,7 +1118,7 @@ const toolNameToDesc = (toolName: ToolName, _toolParams: ToolCallParams[ToolName
|
|||
return getBasename(toolParams.uri.fsPath);
|
||||
} else if (toolName === 'list_dir') {
|
||||
const toolParams = _toolParams as ToolCallParams['list_dir']
|
||||
return `${getBasename(toolParams.rootURI.fsPath)}/`;
|
||||
return `${getFolderName(toolParams.rootURI.fsPath)}`;
|
||||
} else if (toolName === 'pathname_search') {
|
||||
const toolParams = _toolParams as ToolCallParams['pathname_search']
|
||||
return `"${toolParams.queryStr}"`;
|
||||
|
|
|
|||
|
|
@ -533,7 +533,7 @@ export const FeaturesTab = () => {
|
|||
<div className='flex items-start mt-4 mb-8'>
|
||||
<div className='w-full'>
|
||||
<h4 className={`text-base`}>Tools</h4>
|
||||
<div className='text-sm italic text-void-fg-3 mt-1 mb-4'>Settings that control Tool behavior.</div>
|
||||
<div className='text-sm italic text-void-fg-3 mt-1 mb-4'>Tools that can modify files on your computer require approval by default.</div>
|
||||
|
||||
<div className='my-2'>
|
||||
{/* Auto Accept Switch */}
|
||||
|
|
|
|||
Loading…
Reference in a new issue