mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
finally bg edits seem to actually work
This commit is contained in:
parent
9350c0dcdf
commit
35eb93d829
5 changed files with 69 additions and 58 deletions
|
|
@ -594,6 +594,7 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
|||
|
||||
const errorMessage = this.errMsgs.rejected
|
||||
this._addMessageToThread(threadId, { role: 'tool', name: name, paramsStr: paramsStr, id, content: errorMessage, result: { type: 'rejected', params: params }, })
|
||||
this._setStreamState(threadId, {}, 'set')
|
||||
}
|
||||
stopRunning(threadId: string) {
|
||||
const thread = this.state.allThreads[threadId]
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ import { IEditCodeService, URIStreamState, AddCtrlKOpts, StartApplyingOpts } fro
|
|||
import { IVoidSettingsService } from '../common/voidSettingsService.js';
|
||||
import { FeatureName } from '../common/voidSettingsTypes.js';
|
||||
import { IVoidModelService } from '../common/voidModelService.js';
|
||||
import { ITextFileService } from '../../../services/textfile/common/textfiles.js';
|
||||
import { deepClone } from '../../../../base/common/objects.js';
|
||||
|
||||
const configOfBG = (color: Color) => {
|
||||
return { dark: color, light: color, hcDark: color, hcLight: color, }
|
||||
|
|
@ -277,6 +279,7 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
@IVoidSettingsService private readonly _settingsService: IVoidSettingsService,
|
||||
// @IFileService private readonly _fileService: IFileService,
|
||||
@IVoidModelService private readonly _voidModelService: IVoidModelService,
|
||||
@ITextFileService private readonly _textFileService: ITextFileService,
|
||||
) {
|
||||
super();
|
||||
|
||||
|
|
@ -784,7 +787,10 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
weAreWriting = false
|
||||
private _writeURIText(uri: URI, text: string, range_: IRange | 'wholeFileRange', { shouldRealignDiffAreas, }: { shouldRealignDiffAreas: boolean, }) {
|
||||
const { model } = this._voidModelService.getModel(uri)
|
||||
if (!model) return // TODO!!!! make sure this works
|
||||
if (!model) {
|
||||
this._refreshStylesAndDiffsInURI(uri) // at the end of a write, we still expect to refresh all styles. e.g. sometimes we expect to restore all the decorations even if no edits were made when _writeText is used
|
||||
return
|
||||
}
|
||||
|
||||
const range: IRange = range_ === 'wholeFileRange' ?
|
||||
{ startLineNumber: 1, startColumn: 1, endLineNumber: model.getLineCount(), endColumn: Number.MAX_SAFE_INTEGER } // whole file
|
||||
|
|
@ -817,8 +823,8 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
|
||||
private _addToHistory(uri: URI, opts?: { onUndo?: () => void }) {
|
||||
|
||||
const getCurrentSnapshot = async (): Promise<HistorySnapshot> => {
|
||||
await this._voidModelService.initializeModel(uri)
|
||||
const getCurrentSnapshot = (): HistorySnapshot => {
|
||||
|
||||
const { model } = this._voidModelService.getModel(uri)
|
||||
const snapshottedDiffAreaOfId: Record<string, DiffAreaSnapshot> = {}
|
||||
|
||||
|
|
@ -827,7 +833,7 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
|
||||
if (diffArea._URI.fsPath !== uri.fsPath) continue
|
||||
|
||||
snapshottedDiffAreaOfId[diffareaid] = structuredClone( // a structured clone must be on a JSON object
|
||||
snapshottedDiffAreaOfId[diffareaid] = deepClone(
|
||||
Object.fromEntries(diffAreaSnapshotKeys.map(key => [key, diffArea[key]]))
|
||||
) as DiffAreaSnapshot
|
||||
}
|
||||
|
|
@ -841,8 +847,7 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
}
|
||||
}
|
||||
|
||||
const restoreDiffAreas = async (snapshotPromise: Promise<HistorySnapshot>) => {
|
||||
const snapshot = await snapshotPromise
|
||||
const restoreDiffAreas = async (snapshot: HistorySnapshot) => {
|
||||
|
||||
// for each diffarea in this uri, stop streaming if currently streaming
|
||||
for (const diffareaid in this.diffAreaOfId) {
|
||||
|
|
@ -855,7 +860,7 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
this._deleteAllDiffAreas(uri)
|
||||
this.diffAreasOfURI[uri.fsPath]?.clear()
|
||||
|
||||
const { snapshottedDiffAreaOfId, entireFileCode: entireModelCode } = structuredClone(snapshot) // don't want to destroy the snapshot
|
||||
const { snapshottedDiffAreaOfId, entireFileCode: entireModelCode } = deepClone(snapshot) // don't want to destroy the snapshot
|
||||
|
||||
// restore diffAreaOfId and diffAreasOfModelId
|
||||
for (const diffareaid in snapshottedDiffAreaOfId) {
|
||||
|
|
@ -885,7 +890,6 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
}
|
||||
this._onDidAddOrDeleteDiffZones.fire({ uri })
|
||||
|
||||
await this._voidModelService.initializeModel(uri)
|
||||
// restore file content
|
||||
this._writeURIText(uri, entireModelCode,
|
||||
'wholeFileRange',
|
||||
|
|
@ -894,8 +898,8 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
// this._noLongerNeedModelReference(uri)
|
||||
}
|
||||
|
||||
const beforeSnapshot: Promise<HistorySnapshot> = getCurrentSnapshot()
|
||||
let afterSnapshot: Promise<HistorySnapshot> | null = null
|
||||
const beforeSnapshot: HistorySnapshot = getCurrentSnapshot()
|
||||
let afterSnapshot: HistorySnapshot | null = null
|
||||
|
||||
const elt: IUndoRedoElement = {
|
||||
type: UndoRedoElementType.Resource,
|
||||
|
|
@ -907,7 +911,12 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
}
|
||||
this._undoRedoService.pushElement(elt)
|
||||
|
||||
const onFinishEdit = () => { afterSnapshot = getCurrentSnapshot() }
|
||||
const onFinishEdit = async () => {
|
||||
afterSnapshot = getCurrentSnapshot()
|
||||
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)
|
||||
})
|
||||
}
|
||||
return { onFinishEdit }
|
||||
}
|
||||
|
||||
|
|
@ -1298,7 +1307,6 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
let currentFileStr: string
|
||||
|
||||
if (from === 'ClickApply') {
|
||||
|
||||
const uri_ = this._getActiveEditorURI()
|
||||
if (!uri_) return
|
||||
uri = uri_
|
||||
|
|
@ -1492,8 +1500,6 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
{ shouldRealignDiffAreas: true }
|
||||
)
|
||||
|
||||
const { editorModel } = this._voidModelService.getModel(uri)
|
||||
editorModel?.save() // save the file
|
||||
onDone()
|
||||
resMessageDonePromise()
|
||||
},
|
||||
|
|
@ -1534,6 +1540,9 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
else {
|
||||
uri = givenURI
|
||||
}
|
||||
|
||||
await this._voidModelService.initializeModel(uri)
|
||||
|
||||
const { model } = this._voidModelService.getModel(uri)
|
||||
if (!model) return
|
||||
|
||||
|
|
@ -1823,8 +1832,6 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
{ shouldRealignDiffAreas: true }
|
||||
)
|
||||
|
||||
const { editorModel } = this._voidModelService.getModel(uri)
|
||||
editorModel?.save() // save the file // TODO!!! make sure this works
|
||||
onDone()
|
||||
resMessageDonePromise()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -138,6 +138,9 @@ export const useApplyButtonHTML = ({ codeStr, applyBoxId, uri }: { codeStr: stri
|
|||
uri: uri,
|
||||
startBehavior: 'reject-conflicts',
|
||||
}) ?? []
|
||||
|
||||
if (!newApplyingUri) console.log('NOT new applying')
|
||||
|
||||
applyingURIOfApplyBoxIdRef.current[applyBoxId] = newApplyingUri ?? undefined
|
||||
|
||||
rerender(c => c + 1)
|
||||
|
|
@ -291,7 +294,6 @@ export const BlockCodeApplyWrapper = ({
|
|||
uri: URI | 'current',
|
||||
}) => {
|
||||
|
||||
|
||||
const { statusIndicatorHTML, buttonsHTML } = useApplyButtonHTML({ codeStr: initValue, applyBoxId, uri })
|
||||
const accessor = useAccessor()
|
||||
const commandService = accessor.get('ICommandService')
|
||||
|
|
@ -301,7 +303,6 @@ export const BlockCodeApplyWrapper = ({
|
|||
name={<span className='not-italic'>{getBasename(uri.fsPath)}</span>}
|
||||
isSmall={true}
|
||||
showDot={false}
|
||||
// TODO!!! this uri is not correct, it is not recognized as an actual file for some stupid reason
|
||||
onClick={() => { commandService.executeCommand('vscode.open', uri, { preview: true }) }}
|
||||
/>
|
||||
: <span>{language}</span>
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ import './chatThreadService.js'
|
|||
import './metricsPollService.js'
|
||||
|
||||
|
||||
|
||||
// ---------- common (unclear if these actually need to be imported, because they're already imported wherever they're used) ----------
|
||||
|
||||
// llmMessage
|
||||
|
|
@ -62,3 +61,5 @@ import '../common/metricsService.js'
|
|||
// updates
|
||||
import '../common/voidUpdateService.js'
|
||||
|
||||
// model service
|
||||
import '../common/voidModelService.js'
|
||||
|
|
|
|||
|
|
@ -1,68 +1,69 @@
|
|||
/*--------------------------------------------------------------------------------------
|
||||
* Copyright 2025 Glass Devtools, Inc. All rights reserved.
|
||||
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
|
||||
*--------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Disposable } from '../../../../base/common/lifecycle.js';
|
||||
import { Disposable, IReference } from '../../../../base/common/lifecycle.js';
|
||||
import { URI } from '../../../../base/common/uri.js';
|
||||
import { ITextModel } from '../../../../editor/common/model.js';
|
||||
import { IResolvedTextEditorModel, ITextModelService } from '../../../../editor/common/services/resolverService.js';
|
||||
import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js';
|
||||
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
|
||||
import { ITextFileEditorModel, ITextFileService } from '../../../services/textfile/common/textfiles.js';
|
||||
|
||||
type VoidModelType = {
|
||||
model: ITextModel | null;
|
||||
editorModel: IResolvedTextEditorModel | null;
|
||||
};
|
||||
|
||||
type VoidModelType = { model: ITextModel | null, editorModel: ITextFileEditorModel | null }
|
||||
export interface IVoidModelService {
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
initializeModel(uri: URI): Promise<void>
|
||||
getModel(uri: URI): VoidModelType
|
||||
getModelSafe(uri: URI): Promise<VoidModelType>
|
||||
initializeModel(uri: URI): Promise<void>;
|
||||
getModel(uri: URI): VoidModelType;
|
||||
getModelSafe(uri: URI): Promise<VoidModelType>;
|
||||
}
|
||||
|
||||
export const IVoidModelService = createDecorator<IVoidModelService>('voidVoidModelService');
|
||||
|
||||
class VoidModelService extends Disposable implements IVoidModelService {
|
||||
_serviceBrand: undefined;
|
||||
|
||||
static readonly ID = 'voidVoidModelService';
|
||||
|
||||
private readonly _modelRefOfURI: Record<string, ITextFileEditorModel> = {}
|
||||
private readonly _modelRefOfURI: Record<string, IReference<IResolvedTextEditorModel>> = {};
|
||||
|
||||
constructor(
|
||||
@ITextFileService private readonly _textFileService: ITextFileService,
|
||||
@ITextModelService private readonly _textModelService: ITextModelService,
|
||||
) {
|
||||
super()
|
||||
super();
|
||||
}
|
||||
|
||||
initializeModel = async (uri: URI) => {
|
||||
if (uri.fsPath in this._modelRefOfURI) return
|
||||
if (uri.scheme !== 'file') return
|
||||
const model = await this._textFileService.files.resolve(uri)
|
||||
if (uri.fsPath in this._modelRefOfURI) return;
|
||||
const editorModelRef = await this._textModelService.createModelReference(uri);
|
||||
// Keep a strong reference to prevent disposal
|
||||
this._modelRefOfURI[uri.fsPath] = editorModelRef;
|
||||
};
|
||||
|
||||
this._modelRefOfURI[uri.fsPath] = model
|
||||
}
|
||||
getModel = (uri: URI) => {
|
||||
const editorModel = this._modelRefOfURI[uri.fsPath]
|
||||
if (!editorModel) return { model: null, editorModel: null }
|
||||
const model = editorModel.textEditorModel
|
||||
if (!model)
|
||||
return { model: null, editorModel }
|
||||
return { model, editorModel }
|
||||
}
|
||||
getModel = (uri: URI): VoidModelType => {
|
||||
const editorModelRef = this._modelRefOfURI[uri.fsPath];
|
||||
if (!editorModelRef) {
|
||||
return { model: null, editorModel: null };
|
||||
}
|
||||
|
||||
getModelSafe = async (uri: URI) => {
|
||||
if (!(uri.fsPath in this._modelRefOfURI)) await this.initializeModel(uri)
|
||||
return this.getModel(uri)
|
||||
}
|
||||
const model = editorModelRef.object.textEditorModel;
|
||||
|
||||
if (!model) {
|
||||
return { model: null, editorModel: editorModelRef.object };
|
||||
}
|
||||
|
||||
return { model, editorModel: editorModelRef.object };
|
||||
};
|
||||
|
||||
getModelSafe = async (uri: URI): Promise<VoidModelType> => {
|
||||
if (!(uri.fsPath in this._modelRefOfURI)) await this.initializeModel(uri);
|
||||
return this.getModel(uri);
|
||||
|
||||
};
|
||||
|
||||
override dispose() {
|
||||
super.dispose()
|
||||
for (const [_, reference] of Object.entries(this._modelRefOfURI)) {
|
||||
reference?.dispose()
|
||||
super.dispose();
|
||||
for (const ref of Object.values(this._modelRefOfURI)) {
|
||||
ref.dispose(); // release reference to allow disposal
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
registerSingleton(IVoidModelService, VoidModelService, InstantiationType.Eager);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue