mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
checkpoints revert/restore diffareas!!!
This commit is contained in:
parent
bde51106a1
commit
a2a9cdba60
10 changed files with 290 additions and 269 deletions
|
|
@ -30,6 +30,8 @@ import { IVoidModelService } from '../common/voidModelService.js';
|
||||||
import { IEditorService } from '../../../services/editor/common/editorService.js';
|
import { IEditorService } from '../../../services/editor/common/editorService.js';
|
||||||
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
|
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
|
||||||
import { findLastIdx } from '../../../../base/common/arraysFind.js';
|
import { findLastIdx } from '../../../../base/common/arraysFind.js';
|
||||||
|
import { IEditCodeService } from './editCodeServiceInterface.js';
|
||||||
|
import { VoidFileSnapshot } from '../common/editCodeServiceTypes.js';
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -238,6 +240,7 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
||||||
@IMetricsService private readonly _metricsService: IMetricsService,
|
@IMetricsService private readonly _metricsService: IMetricsService,
|
||||||
@IEditorService private readonly _editorService: IEditorService,
|
@IEditorService private readonly _editorService: IEditorService,
|
||||||
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
|
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
|
||||||
|
@IEditCodeService private readonly _editCodeService: IEditCodeService,
|
||||||
// @IModelService private readonly _modelService: IModelService,
|
// @IModelService private readonly _modelService: IModelService,
|
||||||
|
|
||||||
) {
|
) {
|
||||||
|
|
@ -787,13 +790,13 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
||||||
const { model } = this._voidModelService.getModel(uri)
|
const { model } = this._voidModelService.getModel(uri)
|
||||||
if (!model) return // should never happen
|
if (!model) return // should never happen
|
||||||
|
|
||||||
const currValue = model.getValue() // afterStr = the value of the file right after the edit
|
const diffAreasSnapshot = this._editCodeService.getVoidFileSnapshot(uri)
|
||||||
|
|
||||||
this._addCheckpoint(threadId, {
|
this._addCheckpoint(threadId, {
|
||||||
role: 'checkpoint',
|
role: 'checkpoint',
|
||||||
type: 'tool_edit',
|
type: 'tool_edit',
|
||||||
beforeStrOfURI: { [uri.fsPath]: currValue, },
|
voidFileSnapshotOfURI: { [uri.fsPath]: diffAreasSnapshot },
|
||||||
userModifications: { beforeStrOfURI: {} },
|
userModifications: { voidFileSnapshotOfURI: {} },
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -821,13 +824,13 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private _computeNeededCheckpointChanges({ threadId }: { threadId: string }) {
|
private _computeCheckpointInfo({ threadId }: { threadId: string }) {
|
||||||
const thread = this.state.allThreads[threadId]
|
const thread = this.state.allThreads[threadId]
|
||||||
if (!thread) return
|
if (!thread) return
|
||||||
const { currCheckpointIdx } = thread.state
|
const { currCheckpointIdx } = thread.state
|
||||||
if (currCheckpointIdx === null) return
|
if (currCheckpointIdx === null) return
|
||||||
|
|
||||||
const currStrOfFsPath: { [fsPath: string]: string | undefined } = {}
|
const voidFileSnapshotOfURI: { [fsPath: string]: VoidFileSnapshot | undefined } = {}
|
||||||
|
|
||||||
// add a change for all the URIs in the checkpoint history
|
// add a change for all the URIs in the checkpoint history
|
||||||
const { lastIdxOfURI } = this._getCheckpointsBetween({ threadId, loIdx: 0, hiIdx: currCheckpointIdx, }) ?? {}
|
const { lastIdxOfURI } = this._getCheckpointsBetween({ threadId, loIdx: 0, hiIdx: currCheckpointIdx, }) ?? {}
|
||||||
|
|
@ -837,10 +840,14 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
||||||
const checkpoint2 = thread.messages[lastIdxOfURI[fsPath]] || null
|
const checkpoint2 = thread.messages[lastIdxOfURI[fsPath]] || null
|
||||||
if (!checkpoint2) continue
|
if (!checkpoint2) continue
|
||||||
if (checkpoint2.role !== 'checkpoint') continue
|
if (checkpoint2.role !== 'checkpoint') continue
|
||||||
const oldStr = this._getBeforeStrAtCheckpoint(checkpoint2, fsPath, { includeUserModifiedChanges: false })
|
const res = this._getCheckpointInfo(checkpoint2, fsPath, { includeUserModifiedChanges: false })
|
||||||
const currStr = model.getValue()
|
if (!res) continue
|
||||||
if (oldStr === currStr) continue
|
const { voidFileSnapshot: oldVoidFileSnapshot } = res
|
||||||
currStrOfFsPath[fsPath] = currStr
|
|
||||||
|
// if there was any change to the str or diffAreaSnapshot, update. rough approximation of equality, oldDiffAreasSnapshot === diffAreasSnapshot is not perfect
|
||||||
|
const voidFileSnapshot = this._editCodeService.getVoidFileSnapshot(URI.file(fsPath))
|
||||||
|
if (oldVoidFileSnapshot === voidFileSnapshot) continue
|
||||||
|
voidFileSnapshotOfURI[fsPath] = voidFileSnapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
// // add a change for all user-edited files (that aren't in the history)
|
// // add a change for all user-edited files (that aren't in the history)
|
||||||
|
|
@ -851,27 +858,30 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
||||||
// currStrOfFsPath[fsPath] = model.getValue()
|
// currStrOfFsPath[fsPath] = model.getValue()
|
||||||
// }
|
// }
|
||||||
|
|
||||||
return currStrOfFsPath
|
return { voidFileSnapshotOfURI }
|
||||||
}
|
}
|
||||||
|
|
||||||
// call this right before user sends message or reverts
|
// call this right before user sends message or reverts
|
||||||
private _addUserCheckpoint({ threadId }: { threadId: string }) {
|
private _addUserCheckpoint({ threadId }: { threadId: string }) {
|
||||||
const changes = this._computeNeededCheckpointChanges({ threadId })
|
const { voidFileSnapshotOfURI } = this._computeCheckpointInfo({ threadId }) ?? {}
|
||||||
this._addCheckpoint(threadId, {
|
this._addCheckpoint(threadId, {
|
||||||
role: 'checkpoint',
|
role: 'checkpoint',
|
||||||
type: 'user_edit',
|
type: 'user_edit',
|
||||||
beforeStrOfURI: changes ?? {},
|
voidFileSnapshotOfURI: voidFileSnapshotOfURI ?? {},
|
||||||
userModifications: { beforeStrOfURI: {} },
|
userModifications: {
|
||||||
|
voidFileSnapshotOfURI: {},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
private _addUserModificationsToCurrCheckpoint({ threadId }: { threadId: string }) {
|
private _addUserModificationsToCurrCheckpoint({ threadId }: { threadId: string }) {
|
||||||
const changes = this._computeNeededCheckpointChanges({ threadId })
|
const { voidFileSnapshotOfURI } = this._computeCheckpointInfo({ threadId }) ?? {}
|
||||||
|
|
||||||
const res = this._getCurrentCheckpoint(threadId)
|
const res = this._getCurrentCheckpoint(threadId)
|
||||||
if (!res) return
|
if (!res) return
|
||||||
const [checkpoint, checkpointIdx] = res
|
const [checkpoint, checkpointIdx] = res
|
||||||
this._editMessageInThread(threadId, checkpointIdx, {
|
this._editMessageInThread(threadId, checkpointIdx, {
|
||||||
...checkpoint,
|
...checkpoint,
|
||||||
userModifications: { beforeStrOfURI: changes ?? {} },
|
userModifications: { voidFileSnapshotOfURI: voidFileSnapshotOfURI ?? {}, },
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -908,29 +918,30 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
||||||
for (let i = loIdx; i <= hiIdx; i += 1) {
|
for (let i = loIdx; i <= hiIdx; i += 1) {
|
||||||
const message = thread.messages[i]
|
const message = thread.messages[i]
|
||||||
if (message.role !== 'checkpoint') continue
|
if (message.role !== 'checkpoint') continue
|
||||||
for (const fsPath in message.beforeStrOfURI) { // do not include userModified.beforeStrOfURI here, jumping should not include those changes
|
for (const fsPath in message.voidFileSnapshotOfURI) { // do not include userModified.beforeStrOfURI here, jumping should not include those changes
|
||||||
lastIdxOfURI[fsPath] = i
|
lastIdxOfURI[fsPath] = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { lastIdxOfURI }
|
return { lastIdxOfURI }
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getBeforeStrAtCheckpoint = (checkpointMessage: ChatMessage & { role: 'checkpoint' }, fsPath: string, opts: { includeUserModifiedChanges: boolean }) => {
|
private _getCheckpointInfo = (checkpointMessage: ChatMessage & { role: 'checkpoint' }, fsPath: string, opts: { includeUserModifiedChanges: boolean }) => {
|
||||||
const beforeStr = fsPath in checkpointMessage.beforeStrOfURI ? checkpointMessage.beforeStrOfURI[fsPath] ?? null : null
|
const voidFileSnapshot = checkpointMessage.voidFileSnapshotOfURI ? checkpointMessage.voidFileSnapshotOfURI[fsPath] ?? null : null
|
||||||
if (!opts.includeUserModifiedChanges) return beforeStr
|
if (!opts.includeUserModifiedChanges) { return { voidFileSnapshot, } }
|
||||||
const userModifiedBeforeStr = fsPath in checkpointMessage.userModifications.beforeStrOfURI ? checkpointMessage.userModifications.beforeStrOfURI[fsPath] ?? null : null
|
|
||||||
return userModifiedBeforeStr ?? beforeStr
|
const userModifiedVoidFileSnapshot = fsPath in checkpointMessage.userModifications.voidFileSnapshotOfURI ? checkpointMessage.userModifications.voidFileSnapshotOfURI[fsPath] ?? null : null
|
||||||
|
return { voidFileSnapshot: userModifiedVoidFileSnapshot ?? voidFileSnapshot, }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private _writeFullFile = ({ fsPath, text }: { fsPath: string, text: string }) => {
|
// private _writeFullFile = ({ fsPath, text }: { fsPath: string, text: string }) => {
|
||||||
const { model } = this._voidModelService.getModelFromFsPath(fsPath)
|
// const { model } = this._voidModelService.getModelFromFsPath(fsPath)
|
||||||
if (!model) return // should never happen
|
// if (!model) return // should never happen
|
||||||
model.applyEdits([{
|
// model.applyEdits([{
|
||||||
range: { startLineNumber: 1, startColumn: 1, endLineNumber: model.getLineCount(), endColumn: Number.MAX_SAFE_INTEGER }, // whole file
|
// range: { startLineNumber: 1, startColumn: 1, endLineNumber: model.getLineCount(), endColumn: Number.MAX_SAFE_INTEGER }, // whole file
|
||||||
text
|
// text
|
||||||
}])
|
// }])
|
||||||
}
|
// }
|
||||||
|
|
||||||
jumpToCheckpointBeforeMessageIdx({ threadId, messageIdx, jumpToUserModified }: { threadId: string, messageIdx: number, jumpToUserModified: boolean }) {
|
jumpToCheckpointBeforeMessageIdx({ threadId, messageIdx, jumpToUserModified }: { threadId: string, messageIdx: number, jumpToUserModified: boolean }) {
|
||||||
const thread = this.state.allThreads[threadId]
|
const thread = this.state.allThreads[threadId]
|
||||||
|
|
@ -978,11 +989,12 @@ We only need to do it for files that were edited since `to`, ie files between to
|
||||||
for (let k = toIdx; k >= 0; k -= 1) {
|
for (let k = toIdx; k >= 0; k -= 1) {
|
||||||
const message = thread.messages[k]
|
const message = thread.messages[k]
|
||||||
if (message.role !== 'checkpoint') continue
|
if (message.role !== 'checkpoint') continue
|
||||||
const beforeStr = this._getBeforeStrAtCheckpoint(message, fsPath, { includeUserModifiedChanges: jumpToUserModified })
|
const res = this._getCheckpointInfo(message, fsPath, { includeUserModifiedChanges: jumpToUserModified })
|
||||||
if (beforeStr !== null) {
|
if (!res) continue
|
||||||
this._writeFullFile({ fsPath, text: beforeStr })
|
const { voidFileSnapshot } = res
|
||||||
break
|
if (!voidFileSnapshot) continue
|
||||||
}
|
this._editCodeService.restoreVoidFileSnapshot(URI.file(fsPath), voidFileSnapshot)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1011,11 +1023,13 @@ We only need to do it for files that were edited since `from`, ie files between
|
||||||
for (let k = toIdx; k >= fromIdx + 1; k -= 1) {
|
for (let k = toIdx; k >= fromIdx + 1; k -= 1) {
|
||||||
const message = thread.messages[k]
|
const message = thread.messages[k]
|
||||||
if (message.role !== 'checkpoint') continue
|
if (message.role !== 'checkpoint') continue
|
||||||
const beforeStr = this._getBeforeStrAtCheckpoint(message, fsPath, { includeUserModifiedChanges: jumpToUserModified })
|
const res = this._getCheckpointInfo(message, fsPath, { includeUserModifiedChanges: jumpToUserModified })
|
||||||
if (beforeStr !== null) {
|
if (!res) continue
|
||||||
this._writeFullFile({ fsPath, text: beforeStr })
|
const { voidFileSnapshot } = res
|
||||||
break
|
if (!voidFileSnapshot) continue
|
||||||
}
|
|
||||||
|
this._editCodeService.restoreVoidFileSnapshot(URI.file(fsPath), voidFileSnapshot)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import { ICodeEditor, IOverlayWidget, IViewZone } from '../../../../editor/brows
|
||||||
// import { IUndoRedoService } from '../../../../platform/undoRedo/common/undoRedo.js';
|
// import { IUndoRedoService } from '../../../../platform/undoRedo/common/undoRedo.js';
|
||||||
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
|
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
|
||||||
// import { throttle } from '../../../../base/common/decorators.js';
|
// import { throttle } from '../../../../base/common/decorators.js';
|
||||||
import { ComputedDiff, findDiffs } from './helpers/findDiffs.js';
|
import { findDiffs } from './helpers/findDiffs.js';
|
||||||
import { EndOfLinePreference, IModelDecorationOptions, ITextModel } from '../../../../editor/common/model.js';
|
import { EndOfLinePreference, IModelDecorationOptions, ITextModel } from '../../../../editor/common/model.js';
|
||||||
import { IRange } from '../../../../editor/common/core/range.js';
|
import { IRange } from '../../../../editor/common/core/range.js';
|
||||||
import { registerColor } from '../../../../platform/theme/common/colorUtils.js';
|
import { registerColor } from '../../../../platform/theme/common/colorUtils.js';
|
||||||
|
|
@ -40,13 +40,14 @@ import { ICommandService } from '../../../../platform/commands/common/commands.j
|
||||||
import { ILLMMessageService } from '../common/sendLLMMessageService.js';
|
import { ILLMMessageService } from '../common/sendLLMMessageService.js';
|
||||||
import { LLMChatMessage, OnError, errorDetails } from '../common/sendLLMMessageTypes.js';
|
import { LLMChatMessage, OnError, errorDetails } from '../common/sendLLMMessageTypes.js';
|
||||||
import { IMetricsService } from '../common/metricsService.js';
|
import { IMetricsService } from '../common/metricsService.js';
|
||||||
import { IEditCodeService, AddCtrlKOpts, StartApplyingOpts, CallBeforeStartApplyingOpts } from './editCodeServiceInterface.js';
|
import { IEditCodeService, AddCtrlKOpts, StartApplyingOpts, CallBeforeStartApplyingOpts, } from './editCodeServiceInterface.js';
|
||||||
import { IVoidSettingsService } from '../common/voidSettingsService.js';
|
import { IVoidSettingsService } from '../common/voidSettingsService.js';
|
||||||
import { FeatureName } from '../common/voidSettingsTypes.js';
|
import { FeatureName } from '../common/voidSettingsTypes.js';
|
||||||
import { IVoidModelService } from '../common/voidModelService.js';
|
import { IVoidModelService } from '../common/voidModelService.js';
|
||||||
import { ITextFileService } from '../../../services/textfile/common/textfiles.js';
|
import { ITextFileService } from '../../../services/textfile/common/textfiles.js';
|
||||||
import { deepClone } from '../../../../base/common/objects.js';
|
import { deepClone } from '../../../../base/common/objects.js';
|
||||||
import { acceptBg, acceptBorder, buttonFontSize, buttonTextColor, rejectBg, rejectBorder } from '../common/helpers/colors.js';
|
import { acceptBg, acceptBorder, buttonFontSize, buttonTextColor, rejectBg, rejectBorder } from '../common/helpers/colors.js';
|
||||||
|
import { DiffArea, Diff, CtrlKZone, VoidFileSnapshot, DiffAreaSnapshotEntry, diffAreaSnapshotKeys, DiffZone, TrackingZone, ComputedDiff } from '../common/editCodeServiceTypes.js';
|
||||||
|
|
||||||
const configOfBG = (color: Color) => {
|
const configOfBG = (color: Color) => {
|
||||||
return { dark: color, light: color, hcDark: color, hcLight: color, }
|
return { dark: color, light: color, hcDark: color, hcLight: color, }
|
||||||
|
|
@ -107,7 +108,6 @@ const getLeadingWhitespacePx = (editor: ICodeEditor, startLine: number): number
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// finds block.orig in fileContents and return its range in file
|
// finds block.orig in fileContents and return its range in file
|
||||||
// startingAtLine is 1-indexed and inclusive
|
// startingAtLine is 1-indexed and inclusive
|
||||||
const findTextInCode = (text: string, fileContents: string, startingAtLine?: number) => {
|
const findTextInCode = (text: string, fileContents: string, startingAtLine?: number) => {
|
||||||
|
|
@ -127,108 +127,6 @@ const findTextInCode = (text: string, fileContents: string, startingAtLine?: num
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// // TODO diffArea should be removed if we just discovered it has no more diffs in it
|
|
||||||
// for (const diffareaid of this.diffAreasOfURI[uri.fsPath] || []) {
|
|
||||||
// const diffArea = this.diffAreaOfId[diffareaid]
|
|
||||||
// if (Object.keys(diffArea._diffOfId).length === 0 && !diffArea._sweepState.isStreaming) {
|
|
||||||
// const { onFinishEdit } = this._addToHistory(uri)
|
|
||||||
// this._deleteDiffArea(diffArea)
|
|
||||||
// onFinishEdit()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
export type Diff = {
|
|
||||||
diffid: number;
|
|
||||||
diffareaid: number; // the diff area this diff belongs to, "computed"
|
|
||||||
} & ComputedDiff
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// _ means anything we don't include if we clone it
|
|
||||||
// DiffArea.originalStartLine is the line in originalCode (not the file)
|
|
||||||
|
|
||||||
type CommonZoneProps = {
|
|
||||||
diffareaid: number;
|
|
||||||
startLine: number;
|
|
||||||
endLine: number;
|
|
||||||
|
|
||||||
_URI: URI; // typically we get the URI from model
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
type CtrlKZone = {
|
|
||||||
type: 'CtrlKZone';
|
|
||||||
originalCode?: undefined;
|
|
||||||
|
|
||||||
editorId: string; // the editor the input lives on
|
|
||||||
|
|
||||||
_mountInfo: null | {
|
|
||||||
textAreaRef: { current: HTMLTextAreaElement | null }
|
|
||||||
dispose: () => void;
|
|
||||||
refresh: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
_linkedStreamingDiffZone: number | null; // diffareaid of the diffZone currently streaming here
|
|
||||||
_removeStylesFns: Set<Function> // these don't remove diffs or this diffArea, only their styles
|
|
||||||
|
|
||||||
} & CommonZoneProps
|
|
||||||
|
|
||||||
|
|
||||||
export type DiffZone = {
|
|
||||||
type: 'DiffZone',
|
|
||||||
originalCode: string;
|
|
||||||
_diffOfId: Record<string, Diff>; // diffid -> diff in this DiffArea
|
|
||||||
_streamState: {
|
|
||||||
isStreaming: true;
|
|
||||||
streamRequestIdRef: { current: string | null };
|
|
||||||
line: number;
|
|
||||||
} | {
|
|
||||||
isStreaming: false;
|
|
||||||
streamRequestIdRef?: undefined;
|
|
||||||
line?: undefined;
|
|
||||||
};
|
|
||||||
editorId?: undefined;
|
|
||||||
linkedStreamingDiffZone?: undefined;
|
|
||||||
_removeStylesFns: Set<Function> // these don't remove diffs or this diffArea, only their styles
|
|
||||||
} & CommonZoneProps
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
type TrackingZone<T> = {
|
|
||||||
type: 'TrackingZone';
|
|
||||||
metadata: T;
|
|
||||||
originalCode?: undefined;
|
|
||||||
editorId?: undefined;
|
|
||||||
_removeStylesFns?: undefined;
|
|
||||||
} & CommonZoneProps
|
|
||||||
|
|
||||||
|
|
||||||
// called DiffArea for historical purposes, we can rename to something like TextRegion if we want
|
|
||||||
export type DiffArea = CtrlKZone | DiffZone | TrackingZone<any>
|
|
||||||
|
|
||||||
const diffAreaSnapshotKeys = [
|
|
||||||
'type',
|
|
||||||
'diffareaid',
|
|
||||||
'originalCode',
|
|
||||||
'startLine',
|
|
||||||
'endLine',
|
|
||||||
'editorId',
|
|
||||||
|
|
||||||
] as const satisfies (keyof DiffArea)[]
|
|
||||||
|
|
||||||
type DiffAreaSnapshot<DiffAreaType extends DiffArea = DiffArea> = Pick<DiffAreaType, typeof diffAreaSnapshotKeys[number]>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
type HistorySnapshot = {
|
|
||||||
snapshottedDiffAreaOfId: Record<string, DiffAreaSnapshot>;
|
|
||||||
entireFileCode: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// line/col is the location, originalCodeStartLine is the start line of the original code being displayed
|
// line/col is the location, originalCodeStartLine is the start line of the original code being displayed
|
||||||
type StreamLocationMutable = { line: number, col: number, addedSplitYet: boolean, originalCodeStartLine: number }
|
type StreamLocationMutable = { line: number, col: number, addedSplitYet: boolean, originalCodeStartLine: number }
|
||||||
|
|
||||||
|
|
@ -259,7 +157,7 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
||||||
|
|
||||||
// ctrlKZone: [uri], isStreaming // listen on change streaming
|
// ctrlKZone: [uri], isStreaming // listen on change streaming
|
||||||
private readonly _onDidChangeStreamingInCtrlKZone = new Emitter<{ uri: URI; diffareaid: number }>();
|
private readonly _onDidChangeStreamingInCtrlKZone = new Emitter<{ uri: URI; diffareaid: number }>();
|
||||||
onDidChangeStreamingInCtrlKZone = this._onDidChangeStreamingInCtrlKZone.event
|
onDidChangeStreamingInCtrlKZone = this._onDidChangeStreamingInCtrlKZone.event;
|
||||||
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
|
@ -722,98 +620,98 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private _getCurrentVoidFileSnapshot = (uri: URI): VoidFileSnapshot => {
|
||||||
|
const { model } = this._voidModelService.getModel(uri)
|
||||||
|
const snapshottedDiffAreaOfId: Record<string, DiffAreaSnapshotEntry> = {}
|
||||||
|
|
||||||
|
for (const diffareaid in this.diffAreaOfId) {
|
||||||
|
const diffArea = this.diffAreaOfId[diffareaid]
|
||||||
|
|
||||||
|
if (diffArea._URI.fsPath !== uri.fsPath) continue
|
||||||
|
|
||||||
|
snapshottedDiffAreaOfId[diffareaid] = deepClone(
|
||||||
|
Object.fromEntries(diffAreaSnapshotKeys.map(key => [key, diffArea[key]]))
|
||||||
|
) as DiffAreaSnapshotEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
const entireFileCode = model ? model.getValue(EndOfLinePreference.LF) : ''
|
||||||
|
|
||||||
|
// this._noLongerNeedModelReference(uri)
|
||||||
|
return {
|
||||||
|
snapshottedDiffAreaOfId,
|
||||||
|
entireFileCode, // the whole file's code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private _restoreVoidFileSnapshot = async (uri: URI, snapshot: VoidFileSnapshot) => {
|
||||||
|
// for each diffarea in this uri, stop streaming if currently streaming
|
||||||
|
for (const diffareaid in this.diffAreaOfId) {
|
||||||
|
const diffArea = this.diffAreaOfId[diffareaid]
|
||||||
|
if (diffArea.type === 'DiffZone')
|
||||||
|
this._stopIfStreaming(diffArea)
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete all diffareas on this uri (clearing their styles)
|
||||||
|
this._deleteAllDiffAreas(uri)
|
||||||
|
|
||||||
|
const { snapshottedDiffAreaOfId, entireFileCode: entireModelCode } = deepClone(snapshot) // don't want to destroy the snapshot
|
||||||
|
|
||||||
|
// restore diffAreaOfId and diffAreasOfModelId
|
||||||
|
for (const diffareaid in snapshottedDiffAreaOfId) {
|
||||||
|
|
||||||
|
const snapshottedDiffArea = snapshottedDiffAreaOfId[diffareaid]
|
||||||
|
|
||||||
|
if (snapshottedDiffArea.type === 'DiffZone') {
|
||||||
|
this.diffAreaOfId[diffareaid] = {
|
||||||
|
...snapshottedDiffArea as DiffAreaSnapshotEntry<DiffZone>,
|
||||||
|
type: 'DiffZone',
|
||||||
|
_diffOfId: {},
|
||||||
|
_URI: uri,
|
||||||
|
_streamState: { isStreaming: false }, // when restoring, we will never be streaming
|
||||||
|
_removeStylesFns: new Set(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (snapshottedDiffArea.type === 'CtrlKZone') {
|
||||||
|
this.diffAreaOfId[diffareaid] = {
|
||||||
|
...snapshottedDiffArea as DiffAreaSnapshotEntry<CtrlKZone>,
|
||||||
|
_URI: uri,
|
||||||
|
_removeStylesFns: new Set<Function>(),
|
||||||
|
_mountInfo: null,
|
||||||
|
_linkedStreamingDiffZone: null, // when restoring, we will never be streaming
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._addOrInitializeDiffAreaAtURI(uri, diffareaid)
|
||||||
|
}
|
||||||
|
this._onDidAddOrDeleteDiffZones.fire({ uri })
|
||||||
|
|
||||||
|
// restore file content
|
||||||
|
this._writeURIText(uri, entireModelCode,
|
||||||
|
'wholeFileRange',
|
||||||
|
{ shouldRealignDiffAreas: false }
|
||||||
|
)
|
||||||
|
// this._noLongerNeedModelReference(uri)
|
||||||
|
}
|
||||||
|
|
||||||
private _addToHistory(uri: URI, opts?: { onWillUndo?: () => void }) {
|
private _addToHistory(uri: URI, opts?: { onWillUndo?: () => void }) {
|
||||||
|
const beforeSnapshot: VoidFileSnapshot = this._getCurrentVoidFileSnapshot(uri)
|
||||||
const getCurrentSnapshot = (): HistorySnapshot => {
|
let afterSnapshot: VoidFileSnapshot | null = null
|
||||||
|
|
||||||
const { model } = this._voidModelService.getModel(uri)
|
|
||||||
const snapshottedDiffAreaOfId: Record<string, DiffAreaSnapshot> = {}
|
|
||||||
|
|
||||||
for (const diffareaid in this.diffAreaOfId) {
|
|
||||||
const diffArea = this.diffAreaOfId[diffareaid]
|
|
||||||
|
|
||||||
if (diffArea._URI.fsPath !== uri.fsPath) continue
|
|
||||||
|
|
||||||
snapshottedDiffAreaOfId[diffareaid] = deepClone(
|
|
||||||
Object.fromEntries(diffAreaSnapshotKeys.map(key => [key, diffArea[key]]))
|
|
||||||
) as DiffAreaSnapshot
|
|
||||||
}
|
|
||||||
|
|
||||||
const entireFileCode = model ? model.getValue(EndOfLinePreference.LF) : ''
|
|
||||||
|
|
||||||
// this._noLongerNeedModelReference(uri)
|
|
||||||
return {
|
|
||||||
snapshottedDiffAreaOfId,
|
|
||||||
entireFileCode, // the whole file's code
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const restoreDiffAreas = async (snapshot: HistorySnapshot) => {
|
|
||||||
|
|
||||||
// for each diffarea in this uri, stop streaming if currently streaming
|
|
||||||
for (const diffareaid in this.diffAreaOfId) {
|
|
||||||
const diffArea = this.diffAreaOfId[diffareaid]
|
|
||||||
if (diffArea.type === 'DiffZone')
|
|
||||||
this._stopIfStreaming(diffArea)
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete all diffareas on this uri (clearing their styles)
|
|
||||||
this._deleteAllDiffAreas(uri)
|
|
||||||
this.diffAreasOfURI[uri.fsPath]?.clear()
|
|
||||||
|
|
||||||
const { snapshottedDiffAreaOfId, entireFileCode: entireModelCode } = deepClone(snapshot) // don't want to destroy the snapshot
|
|
||||||
|
|
||||||
// restore diffAreaOfId and diffAreasOfModelId
|
|
||||||
for (const diffareaid in snapshottedDiffAreaOfId) {
|
|
||||||
|
|
||||||
const snapshottedDiffArea = snapshottedDiffAreaOfId[diffareaid]
|
|
||||||
|
|
||||||
if (snapshottedDiffArea.type === 'DiffZone') {
|
|
||||||
this.diffAreaOfId[diffareaid] = {
|
|
||||||
...snapshottedDiffArea as DiffAreaSnapshot<DiffZone>,
|
|
||||||
type: 'DiffZone',
|
|
||||||
_diffOfId: {},
|
|
||||||
_URI: uri,
|
|
||||||
_streamState: { isStreaming: false }, // when restoring, we will never be streaming
|
|
||||||
_removeStylesFns: new Set(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (snapshottedDiffArea.type === 'CtrlKZone') {
|
|
||||||
this.diffAreaOfId[diffareaid] = {
|
|
||||||
...snapshottedDiffArea as DiffAreaSnapshot<CtrlKZone>,
|
|
||||||
_URI: uri,
|
|
||||||
_removeStylesFns: new Set<Function>(),
|
|
||||||
_mountInfo: null,
|
|
||||||
_linkedStreamingDiffZone: null, // when restoring, we will never be streaming
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this._addOrInitializeDiffAreaAtURI(uri, diffareaid)
|
|
||||||
}
|
|
||||||
this._onDidAddOrDeleteDiffZones.fire({ uri })
|
|
||||||
|
|
||||||
// restore file content
|
|
||||||
this._writeURIText(uri, entireModelCode,
|
|
||||||
'wholeFileRange',
|
|
||||||
{ shouldRealignDiffAreas: false }
|
|
||||||
)
|
|
||||||
// this._noLongerNeedModelReference(uri)
|
|
||||||
}
|
|
||||||
|
|
||||||
const beforeSnapshot: HistorySnapshot = getCurrentSnapshot()
|
|
||||||
let afterSnapshot: HistorySnapshot | null = null
|
|
||||||
|
|
||||||
const elt: IUndoRedoElement = {
|
const elt: IUndoRedoElement = {
|
||||||
type: UndoRedoElementType.Resource,
|
type: UndoRedoElementType.Resource,
|
||||||
resource: uri,
|
resource: uri,
|
||||||
label: 'Void Agent',
|
label: 'Void Agent',
|
||||||
code: 'undoredo.editCode',
|
code: 'undoredo.editCode',
|
||||||
undo: () => { opts?.onWillUndo?.(); restoreDiffAreas(beforeSnapshot); },
|
undo: () => { opts?.onWillUndo?.(); this._restoreVoidFileSnapshot(uri, beforeSnapshot); },
|
||||||
redo: () => { if (afterSnapshot) restoreDiffAreas(afterSnapshot) }
|
redo: () => { if (afterSnapshot) this._restoreVoidFileSnapshot(uri, afterSnapshot) }
|
||||||
}
|
}
|
||||||
this._undoRedoService.pushElement(elt)
|
this._undoRedoService.pushElement(elt)
|
||||||
|
|
||||||
const onFinishEdit = async () => {
|
const onFinishEdit = async () => {
|
||||||
afterSnapshot = getCurrentSnapshot()
|
afterSnapshot = this._getCurrentVoidFileSnapshot(uri)
|
||||||
await this._textFileService.save(uri, { // we want [our change] -> [save] so it's all treated as one change.
|
await this._textFileService.save(uri, { // we want [our change] -> [save] so it's all treated as one change.
|
||||||
skipSaveParticipants: true // avoid triggering extensions etc (if they reformat the page, it will add another item to the undo stack)
|
skipSaveParticipants: true // avoid triggering extensions etc (if they reformat the page, it will add another item to the undo stack)
|
||||||
})
|
})
|
||||||
|
|
@ -822,6 +720,16 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public getVoidFileSnapshot(uri: URI) {
|
||||||
|
return this._getCurrentVoidFileSnapshot(uri)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public restoreVoidFileSnapshot(uri: URI, snapshot: VoidFileSnapshot): void {
|
||||||
|
this._restoreVoidFileSnapshot(uri, snapshot)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// delete diffOfId and diffArea._diffOfId
|
// delete diffOfId and diffArea._diffOfId
|
||||||
private _deleteDiff(diff: Diff) {
|
private _deleteDiff(diff: Diff) {
|
||||||
const diffArea = this.diffAreaOfId[diff.diffareaid]
|
const diffArea = this.diffAreaOfId[diff.diffareaid]
|
||||||
|
|
@ -886,6 +794,7 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
||||||
else if (diffArea.type === 'CtrlKZone')
|
else if (diffArea.type === 'CtrlKZone')
|
||||||
this._deleteCtrlKZone(diffArea)
|
this._deleteCtrlKZone(diffArea)
|
||||||
})
|
})
|
||||||
|
this.diffAreasOfURI[uri.fsPath]?.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
private _addOrInitializeDiffAreaAtURI = (uri: URI, diffareaid: string | number) => {
|
private _addOrInitializeDiffAreaAtURI = (uri: URI, diffareaid: string | number) => {
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,7 @@ import { Event } from '../../../../base/common/event.js';
|
||||||
import { URI } from '../../../../base/common/uri.js';
|
import { URI } from '../../../../base/common/uri.js';
|
||||||
import { ICodeEditor } from '../../../../editor/browser/editorBrowser.js';
|
import { ICodeEditor } from '../../../../editor/browser/editorBrowser.js';
|
||||||
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
|
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
|
||||||
import { Diff, DiffArea } from './editCodeService.js';
|
import { Diff, DiffArea, VoidFileSnapshot } from '../common/editCodeServiceTypes.js';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export type StartBehavior = 'accept-conflicts' | 'reject-conflicts' | 'keep-conflicts'
|
export type StartBehavior = 'accept-conflicts' | 'reject-conflicts' | 'keep-conflicts'
|
||||||
|
|
@ -32,8 +31,6 @@ export type StartApplyingOpts = {
|
||||||
startBehavior: StartBehavior;
|
startBehavior: StartBehavior;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export type AddCtrlKOpts = {
|
export type AddCtrlKOpts = {
|
||||||
startLine: number,
|
startLine: number,
|
||||||
endLine: number,
|
endLine: number,
|
||||||
|
|
@ -70,4 +67,6 @@ export interface IEditCodeService {
|
||||||
interruptURIStreaming(opts: { uri: URI }): void;
|
interruptURIStreaming(opts: { uri: URI }): void;
|
||||||
|
|
||||||
// testDiffs(): void;
|
// testDiffs(): void;
|
||||||
|
getVoidFileSnapshot(uri: URI): VoidFileSnapshot;
|
||||||
|
restoreVoidFileSnapshot(uri: URI, snapshot: VoidFileSnapshot): void;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,34 +3,9 @@
|
||||||
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
|
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
|
||||||
*--------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { ComputedDiff } from '../../common/editCodeServiceTypes.js';
|
||||||
import { diffLines } from '../react/out/diff/index.js'
|
import { diffLines } from '../react/out/diff/index.js'
|
||||||
|
|
||||||
export type ComputedDiff = {
|
|
||||||
type: 'edit';
|
|
||||||
originalCode: string;
|
|
||||||
originalStartLine: number;
|
|
||||||
originalEndLine: number;
|
|
||||||
code: string;
|
|
||||||
startLine: number; // 1-indexed
|
|
||||||
endLine: number;
|
|
||||||
} | {
|
|
||||||
type: 'insertion';
|
|
||||||
// originalCode: string;
|
|
||||||
originalStartLine: number; // insertion starts on column 0 of this
|
|
||||||
// originalEndLine: number;
|
|
||||||
code: string;
|
|
||||||
startLine: number;
|
|
||||||
endLine: number;
|
|
||||||
} | {
|
|
||||||
type: 'deletion';
|
|
||||||
originalCode: string;
|
|
||||||
originalStartLine: number;
|
|
||||||
originalEndLine: number;
|
|
||||||
// code: string;
|
|
||||||
startLine: number; // deletion starts on column 0 of this
|
|
||||||
// endLine: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function findDiffs(oldStr: string, newStr: string) {
|
export function findDiffs(oldStr: string, newStr: string) {
|
||||||
|
|
||||||
// this makes it so the end of the file always ends with a \n (if you don't have this, then diffing E vs E\n gives an "edit". With it, you end up diffing E\n vs E\n\n which now properly gives an insertion)
|
// this makes it so the end of the file always ends with a \n (if you don't have this, then diffing E vs E\n gives an "edit". With it, you end up diffing E\n vs E\n\n which now properly gives an insertion)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,8 @@
|
||||||
|
/*--------------------------------------------------------------------------------------
|
||||||
|
* Copyright 2025 Glass Devtools, Inc. All rights reserved.
|
||||||
|
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
|
||||||
|
*--------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { useState, useEffect, useCallback } from 'react'
|
import { useState, useEffect, useCallback } from 'react'
|
||||||
import { useAccessor, useCommandBarState, useCommandBarURIListener, useSettingsState } from '../util/services.js'
|
import { useAccessor, useCommandBarState, useCommandBarURIListener, useSettingsState } from '../util/services.js'
|
||||||
import { usePromise, useRefState } from '../util/helpers.js'
|
import { usePromise, useRefState } from '../util/helpers.js'
|
||||||
|
|
@ -144,7 +149,6 @@ export const useApplyButtonState = ({ applyBoxId, uri }: { applyBoxId: string, u
|
||||||
|
|
||||||
const getStreamState = useCallback(() => {
|
const getStreamState = useCallback(() => {
|
||||||
const uri = getUriBeingApplied(applyBoxId)
|
const uri = getUriBeingApplied(applyBoxId)
|
||||||
console.log('uri',uri?.fsPath)
|
|
||||||
if (!uri) return 'idle-no-changes'
|
if (!uri) return 'idle-no-changes'
|
||||||
return voidCommandBarService.getStreamState(uri)
|
return voidCommandBarService.getStreamState(uri)
|
||||||
}, [voidCommandBarService, applyBoxId])
|
}, [voidCommandBarService, applyBoxId])
|
||||||
|
|
@ -162,7 +166,6 @@ export const useApplyButtonState = ({ applyBoxId, uri }: { applyBoxId: string, u
|
||||||
}, [applyBoxId, applyBoxId, uri]))
|
}, [applyBoxId, applyBoxId, uri]))
|
||||||
|
|
||||||
const currStreamState = getStreamState()
|
const currStreamState = getStreamState()
|
||||||
console.log('curr stream state', currStreamState)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getStreamState,
|
getStreamState,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,3 @@
|
||||||
//!!!! merged
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------------------
|
/*--------------------------------------------------------------------------------------
|
||||||
* Copyright 2025 Glass Devtools, Inc. All rights reserved.
|
* Copyright 2025 Glass Devtools, Inc. All rights reserved.
|
||||||
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
|
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
|
||||||
|
|
@ -1821,12 +1817,12 @@ const toolNameToComponent: { [T in ToolName]: ToolComponent<T> } = {
|
||||||
const Checkpoint = ({ threadId, messageIdx }: { threadId: string; messageIdx: number }) => {
|
const Checkpoint = ({ threadId, messageIdx }: { threadId: string; messageIdx: number }) => {
|
||||||
const accessor = useAccessor()
|
const accessor = useAccessor()
|
||||||
const chatThreadService = accessor.get('IChatThreadService')
|
const chatThreadService = accessor.get('IChatThreadService')
|
||||||
const commandBarService = accessor.get('IVoidCommandBarService')
|
// const commandBarService = accessor.get('IVoidCommandBarService')
|
||||||
return <div
|
return <div
|
||||||
className='pointer-events-auto cursor-pointer select-none hover:brightness-125 flex items-center justify-center'
|
className='pointer-events-auto cursor-pointer select-none hover:brightness-125 flex items-center justify-center'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
// reject all current changes and then jump back
|
// reject all current changes and then jump back
|
||||||
commandBarService.acceptOrRejectAllFiles({ behavior: 'accept' })
|
// commandBarService.acceptOrRejectAllFiles({ behavior: 'accept' })
|
||||||
chatThreadService.jumpToCheckpointBeforeMessageIdx({ threadId, messageIdx, jumpToUserModified: true })
|
chatThreadService.jumpToCheckpointBeforeMessageIdx({ threadId, messageIdx, jumpToUserModified: true })
|
||||||
}}>
|
}}>
|
||||||
<div className='bg-void-border-1 h-[1px] flex-grow'></div>
|
<div className='bg-void-border-1 h-[1px] flex-grow'></div>
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import { IThemeService } from '../../../../../../../platform/theme/common/themeS
|
||||||
import { ILLMMessageService } from '../../../../common/sendLLMMessageService.js';
|
import { ILLMMessageService } from '../../../../common/sendLLMMessageService.js';
|
||||||
import { IRefreshModelService } from '../../../../../../../workbench/contrib/void/common/refreshModelService.js';
|
import { IRefreshModelService } from '../../../../../../../workbench/contrib/void/common/refreshModelService.js';
|
||||||
import { IVoidSettingsService } from '../../../../../../../workbench/contrib/void/common/voidSettingsService.js';
|
import { IVoidSettingsService } from '../../../../../../../workbench/contrib/void/common/voidSettingsService.js';
|
||||||
import { IEditCodeService } from '../../../editCodeServiceInterface.js'
|
|
||||||
|
|
||||||
import { ISidebarStateService } from '../../../sidebarStateService.js';
|
import { ISidebarStateService } from '../../../sidebarStateService.js';
|
||||||
import { IInstantiationService } from '../../../../../../../platform/instantiation/common/instantiation.js'
|
import { IInstantiationService } from '../../../../../../../platform/instantiation/common/instantiation.js'
|
||||||
|
|
@ -47,6 +46,7 @@ import { IVoidModelService } from '../../../../common/voidModelService.js'
|
||||||
import { IWorkspaceContextService } from '../../../../../../../platform/workspace/common/workspace.js'
|
import { IWorkspaceContextService } from '../../../../../../../platform/workspace/common/workspace.js'
|
||||||
import { IVoidCommandBarService } from '../../../voidCommandBarService.js'
|
import { IVoidCommandBarService } from '../../../voidCommandBarService.js'
|
||||||
import { INativeHostService } from '../../../../../../../platform/native/common/native.js';
|
import { INativeHostService } from '../../../../../../../platform/native/common/native.js';
|
||||||
|
import { IEditCodeService } from '../../../editCodeServiceInterface.js'
|
||||||
|
|
||||||
|
|
||||||
// normally to do this you'd use a useEffect that calls .onDidChangeState(), but useEffect mounts too late and misses initial state changes
|
// normally to do this you'd use a useEffect that calls .onDidChangeState(), but useEffect mounts too late and misses initial state changes
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
|
/*--------------------------------------------------------------------------------------
|
||||||
|
* Copyright 2025 Glass Devtools, Inc. All rights reserved.
|
||||||
|
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
|
||||||
|
*--------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
import { URI } from '../../../../base/common/uri.js';
|
import { URI } from '../../../../base/common/uri.js';
|
||||||
import { IRange } from '../../../../editor/common/core/range.js';
|
import { IRange } from '../../../../editor/common/core/range.js';
|
||||||
|
import { VoidFileSnapshot } from './editCodeServiceTypes.js';
|
||||||
import { AnthropicReasoning } from './sendLLMMessageTypes.js';
|
import { AnthropicReasoning } from './sendLLMMessageTypes.js';
|
||||||
import { ToolName, ToolCallParams, ToolResultType } from './toolsServiceTypes.js';
|
import { ToolName, ToolCallParams, ToolResultType } from './toolsServiceTypes.js';
|
||||||
|
|
||||||
|
|
@ -29,11 +35,11 @@ export type ToolRequestApproval<T extends ToolName> = {
|
||||||
export type CheckpointEntry = {
|
export type CheckpointEntry = {
|
||||||
role: 'checkpoint';
|
role: 'checkpoint';
|
||||||
type: 'user_edit' | 'tool_edit';
|
type: 'user_edit' | 'tool_edit';
|
||||||
beforeStrOfURI: { [fsPath: string]: string | undefined };
|
voidFileSnapshotOfURI: { [fsPath: string]: VoidFileSnapshot | undefined };
|
||||||
|
|
||||||
userModifications: {
|
userModifications: {
|
||||||
beforeStrOfURI: { [fsPath: string]: string | undefined };
|
voidFileSnapshotOfURI: { [fsPath: string]: VoidFileSnapshot | undefined };
|
||||||
};
|
};
|
||||||
// diffAreas: null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
119
src/vs/workbench/contrib/void/common/editCodeServiceTypes.ts
Normal file
119
src/vs/workbench/contrib/void/common/editCodeServiceTypes.ts
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
/*--------------------------------------------------------------------------------------
|
||||||
|
* Copyright 2025 Glass Devtools, Inc. All rights reserved.
|
||||||
|
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
|
||||||
|
*--------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { URI } from '../../../../base/common/uri.js';
|
||||||
|
|
||||||
|
export type ComputedDiff = {
|
||||||
|
type: 'edit';
|
||||||
|
originalCode: string;
|
||||||
|
originalStartLine: number;
|
||||||
|
originalEndLine: number;
|
||||||
|
code: string;
|
||||||
|
startLine: number; // 1-indexed
|
||||||
|
endLine: number;
|
||||||
|
} | {
|
||||||
|
type: 'insertion';
|
||||||
|
// originalCode: string;
|
||||||
|
originalStartLine: number; // insertion starts on column 0 of this
|
||||||
|
// originalEndLine: number;
|
||||||
|
code: string;
|
||||||
|
startLine: number;
|
||||||
|
endLine: number;
|
||||||
|
} | {
|
||||||
|
type: 'deletion';
|
||||||
|
originalCode: string;
|
||||||
|
originalStartLine: number;
|
||||||
|
originalEndLine: number;
|
||||||
|
// code: string;
|
||||||
|
startLine: number; // deletion starts on column 0 of this
|
||||||
|
// endLine: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- Diff types ----------
|
||||||
|
|
||||||
|
export type CommonZoneProps = {
|
||||||
|
diffareaid: number;
|
||||||
|
startLine: number;
|
||||||
|
endLine: number;
|
||||||
|
|
||||||
|
_URI: URI; // typically we get the URI from model
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type CtrlKZone = {
|
||||||
|
type: 'CtrlKZone';
|
||||||
|
originalCode?: undefined;
|
||||||
|
|
||||||
|
editorId: string; // the editor the input lives on
|
||||||
|
|
||||||
|
// _ means anything we don't include if we clone it
|
||||||
|
_mountInfo: null | {
|
||||||
|
textAreaRef: { current: HTMLTextAreaElement | null }
|
||||||
|
dispose: () => void;
|
||||||
|
refresh: () => void;
|
||||||
|
}
|
||||||
|
_linkedStreamingDiffZone: number | null; // diffareaid of the diffZone currently streaming here
|
||||||
|
_removeStylesFns: Set<Function> // these don't remove diffs or this diffArea, only their styles
|
||||||
|
} & CommonZoneProps
|
||||||
|
|
||||||
|
|
||||||
|
export type TrackingZone<T> = {
|
||||||
|
type: 'TrackingZone';
|
||||||
|
metadata: T;
|
||||||
|
originalCode?: undefined;
|
||||||
|
editorId?: undefined;
|
||||||
|
_removeStylesFns?: undefined;
|
||||||
|
} & CommonZoneProps
|
||||||
|
|
||||||
|
|
||||||
|
// called DiffArea for historical purposes, we can rename to something like TextRegion if we want
|
||||||
|
export type DiffArea = CtrlKZone | DiffZone | TrackingZone<any>
|
||||||
|
|
||||||
|
|
||||||
|
export type Diff = {
|
||||||
|
diffid: number;
|
||||||
|
diffareaid: number; // the diff area this diff belongs to, "computed"
|
||||||
|
} & ComputedDiff
|
||||||
|
|
||||||
|
|
||||||
|
export type DiffZone = {
|
||||||
|
type: 'DiffZone',
|
||||||
|
originalCode: string;
|
||||||
|
_diffOfId: Record<string, Diff>; // diffid -> diff in this DiffArea
|
||||||
|
_streamState: {
|
||||||
|
isStreaming: true;
|
||||||
|
streamRequestIdRef: { current: string | null };
|
||||||
|
line: number;
|
||||||
|
} | {
|
||||||
|
isStreaming: false;
|
||||||
|
streamRequestIdRef?: undefined;
|
||||||
|
line?: undefined;
|
||||||
|
};
|
||||||
|
editorId?: undefined;
|
||||||
|
linkedStreamingDiffZone?: undefined;
|
||||||
|
_removeStylesFns: Set<Function> // these don't remove diffs or this diffArea, only their styles
|
||||||
|
} & CommonZoneProps
|
||||||
|
|
||||||
|
|
||||||
|
export const diffAreaSnapshotKeys = [
|
||||||
|
'type',
|
||||||
|
'diffareaid',
|
||||||
|
'originalCode',
|
||||||
|
'startLine',
|
||||||
|
'endLine',
|
||||||
|
'editorId',
|
||||||
|
|
||||||
|
] as const satisfies (keyof DiffArea)[]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export type DiffAreaSnapshotEntry<DiffAreaType extends DiffArea = DiffArea> = Pick<DiffAreaType, typeof diffAreaSnapshotKeys[number]>
|
||||||
|
|
||||||
|
export type VoidFileSnapshot = {
|
||||||
|
snapshottedDiffAreaOfId: Record<string, DiffAreaSnapshotEntry>;
|
||||||
|
entireFileCode: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -128,7 +128,7 @@ Here's an example of a good description:\n${editToolDescription}.`
|
||||||
name: 'terminal_command',
|
name: 'terminal_command',
|
||||||
description: `Executes a terminal command.`,
|
description: `Executes a terminal command.`,
|
||||||
params: {
|
params: {
|
||||||
command: { type: 'string', description: 'The terminal command to execute.' },
|
command: { type: 'string', description: 'The terminal command to execute. Typically you should pipe to cat to avoid pagination.' },
|
||||||
waitForCompletion: { type: 'string', description: `Whether or not to await the command to complete and get the final result. Default is true. Make this value false when you want a command to run indefinitely without waiting for it.` },
|
waitForCompletion: { type: 'string', description: `Whether or not to await the command to complete and get the final result. Default is true. Make this value false when you want a command to run indefinitely without waiting for it.` },
|
||||||
terminalId: { type: 'string', description: 'Optional (value must be an integer >= 1, or empty which will go with the default). This is the ID of the terminal instance to execute the command in. The primary purpose of this is to start a new terminal for background processes or tasks that run indefinitely (e.g. if you want to run a server locally). Fails gracefully if a terminal ID does not exist, by creating a new terminal instance. Defaults to the preferred terminal ID.' },
|
terminalId: { type: 'string', description: 'Optional (value must be an integer >= 1, or empty which will go with the default). This is the ID of the terminal instance to execute the command in. The primary purpose of this is to start a new terminal for background processes or tasks that run indefinitely (e.g. if you want to run a server locally). Fails gracefully if a terminal ID does not exist, by creating a new terminal instance. Defaults to the preferred terminal ID.' },
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue