nightly progress

This commit is contained in:
Andrew Pareles 2024-12-24 23:45:58 -05:00
parent ef9d0daef4
commit dfbd729fa4
3 changed files with 272 additions and 246 deletions

View file

@ -17,14 +17,14 @@ export type LLMMessage = {
content: string;
}
export type LLMFeatureSelection = {
featureName: 'Ctrl+K',
range: IRange
export type ServiceSendLLMFeatureParams = {
featureName: 'Ctrl+K';
range: IRange;
} | {
featureName: 'Ctrl+L',
featureName: 'Ctrl+L';
} | {
featureName: 'Autocomplete',
range: IRange
featureName: 'Autocomplete';
range: IRange;
}
// params to the true sendLLMMessage function
@ -54,7 +54,7 @@ export type ServiceSendLLMMessageParams = {
logging: {
loggingName: string,
};
} & LLMFeatureSelection
} & ServiceSendLLMFeatureParams
// can't send functions across a proxy, use listeners instead
export type BlockedMainLLMMessageParams = 'onText' | 'onFinalMessage' | 'onError' | 'abortRef'

View file

@ -5,7 +5,7 @@
import { Disposable } from '../../../../base/common/lifecycle.js';
import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js';
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
import { createDecorator, IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { ICodeEditor, IOverlayWidget, IViewZone } from '../../../../editor/browser/editorBrowser.js';
// import { IUndoRedoService } from '../../../../platform/undoRedo/common/undoRedo.js';
@ -26,11 +26,14 @@ import { ILanguageService } from '../../../../editor/common/languages/language.j
import * as dom from '../../../../base/browser/dom.js';
import { Widget } from '../../../../base/browser/ui/widget.js';
import { URI } from '../../../../base/common/uri.js';
import { LLMFeatureSelection, ServiceSendLLMMessageParams } from '../../../../platform/void/common/llmMessageTypes.js';
import { ServiceSendLLMFeatureParams } from '../../../../platform/void/common/llmMessageTypes.js';
import { IConsistentItemService } from './helperServices/consistentItemService.js';
import { inlineDiff_systemMessage } from './prompt/prompts.js';
import { ILLMMessageService } from '../../../../platform/void/common/llmMessageService.js';
import { IPosition } from '../../../../editor/common/core/position.js';
import { mountCtrlK } from '../browser/react/out/ctrl-k-tsx/index.js'
import { QuickEditPropsType } from './quickEditActions.js';
const configOfBG = (color: Color) => {
return { dark: color, light: color, hcDark: color, hcLight: color, }
@ -52,62 +55,99 @@ const sweepIdxBG = new Color(new RGBA(100, 100, 100, .5));
registerColor('void.sweepIdxBG', configOfBG(sweepIdxBG), '', true);
// similar to ServiceLLM
export type StartStreamingOpts = {
featureName: 'Ctrl+K';
diffareaid: string; // id of the CtrlK area
} | {
featureName: 'Ctrl+L';
} | {
featureName: 'Autocomplete';
range: IRange;
}
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 DiffArea = {
type CommonZoneProps = {
diffareaid: number;
originalCode: string;
startLine: number;
endLine: number;
shouldHighlight: boolean; // should visually highlight this DiffArea
_URI: URI; // typically we get the URI from model
_diffOfId: Record<string, Diff>; // diffid -> diff in this DiffArea
} & ({
_removeStylesFns: Set<Function>; // these don't remove diffs or this diffArea, only their styles
}
type CtrlKZone = {
type: 'CtrlKZone';
originalCode?: undefined;
userText: string;
} & CommonZoneProps
type DiffZone = {
type: 'DiffZone',
originalCode: string;
_diffOfId: Record<string, Diff>; // diffid -> diff in this DiffArea
_sweepState: {
isStreaming: true;
streamRequestIdRef: { current: string | null };
line: number;
} | {
isStreaming: false;
streamRequestIdRef?: undefined;
line: null;
};
})
userText?: undefined;
} & CommonZoneProps
// called DiffArea for historical purposes, we can rename to something like TextRegion if we want
type DiffArea = CtrlKZone | DiffZone
const diffAreaSnapshotKeys = [
'type',
'diffareaid',
'originalCode',
'startLine',
'endLine',
'shouldHighlight',
'userText',
] as const satisfies (keyof DiffArea)[]
type DiffAreaSnapshot = Pick<DiffArea, typeof diffAreaSnapshotKeys[number]>
type DiffAreaSnapshot<DiffAreaType extends DiffArea = DiffArea> = Pick<DiffAreaType, typeof diffAreaSnapshotKeys[number]>
type HistorySnapshot = {
snapshottedDiffAreaOfId: Record<string, DiffAreaSnapshot>;
entireFileCode: string;
} &
({
type: 'Ctrl+K';
ctrlKText: string;
} | {
type: 'Ctrl+L';
})
} & ({
type: 'Ctrl+K';
ctrlKText: string;
} | {
type: 'Ctrl+L';
})
export interface IInlineDiffsService {
readonly _serviceBrand: undefined;
startStreaming(params: LLMFeatureSelection, str: string): void;
startStreaming(params: , str: string): void;
}
export const IInlineDiffsService = createDecorator<IInlineDiffsService>('inlineDiffAreasService');
@ -117,12 +157,13 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
// URI <--> model
removeStylesFnsOfURI: Record<string, Set<Function>> = {} // functions that remove the styles of this uri
diffAreasOfURI: Record<string, Set<string>> = {}
diffAreaOfId: Record<string, DiffArea> = {};
diffOfId: Record<string, Diff> = {}; // redundant with diffArea._diffs
_diffareaidPool = 0 // each diffarea has an id
_diffidPool = 0 // each diff has an id
@ -134,6 +175,7 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
@ILanguageService private readonly _langService: ILanguageService,
@ILLMMessageService private readonly _llmMessageService: ILLMMessageService,
@IConsistentItemService private readonly _zoneStyleService: IConsistentItemService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
) {
super();
@ -142,9 +184,6 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
if (!(model.uri.fsPath in this.diffAreasOfURI)) {
this.diffAreasOfURI[model.uri.fsPath] = new Set();
}
if (!(model.uri.fsPath in this.removeStylesFnsOfURI)) {
this.removeStylesFnsOfURI[model.uri.fsPath] = new Set();
}
// when the user types, realign diff areas and re-render them
this._register(
@ -178,19 +217,10 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
let initializeEditor = (editor: ICodeEditor) => {
const uri = editor.getModel()?.uri ?? null
if (uri) this._refreshDiffsInURI(uri)
// this isn't relevant anymore because consistentItemService takes care of it
// called when the user switches tabs (typically there's only 1 editor on the screen, it switches between models, make sure you understand this)
// this._register(editor.onDidChangeModel((e) => {
// if (e.newModelUrl) this._refreshDiffsInURI(e.newModelUrl)
// if (e.oldModelUrl) this._clearAllDiffsAndStyles(e.oldModelUrl)
// }))
}
// add listeners for all existing editors + listen for editor being added
for (let editor of this._editorService.listCodeEditors()) { initializeEditor(editor) }
this._register(this._editorService.onCodeEditorAdd(editor => { initializeEditor(editor) }))
// this._register(this._editorService.onCodeEditorRemove(editor => { console.log('REMOVE EDITOR'); initializeEditor(editor) }))
}
@ -221,18 +251,61 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
for (const diffareaid of this.diffAreasOfURI[uri.fsPath]) {
const diffArea = this.diffAreaOfId[diffareaid]
// add sweep styles to the diffArea
if (diffArea._sweepState.isStreaming) {
// sweepLine ... sweepLine
const fn1 = this._addLineDecoration(model, diffArea._sweepState.line, diffArea._sweepState.line, 'void-sweepIdxBG')
// sweepLine+1 ... endLine
const fn2 = this._addLineDecoration(model, diffArea._sweepState.line + 1, diffArea.endLine, 'void-sweepBG')
this.removeStylesFnsOfURI[uri.fsPath].add(() => { fn1?.(); fn2?.(); })
if (diffArea.type === 'DiffZone') {
// add sweep styles to the diffZone
if (diffArea._sweepState.isStreaming) {
// sweepLine ... sweepLine
const fn1 = this._addLineDecoration(model, diffArea._sweepState.line, diffArea._sweepState.line, 'void-sweepIdxBG')
// sweepLine+1 ... endLine
const fn2 = this._addLineDecoration(model, diffArea._sweepState.line + 1, diffArea.endLine, 'void-sweepBG')
diffArea._removeStylesFns.add(() => { fn1?.(); fn2?.(); })
}
}
// highlight the diffArea
if (diffArea.shouldHighlight) {
// highlight the ctrlK zone
if (diffArea.type === 'CtrlKZone') {
const consistentZoneId = this._zoneStyleService.addConsistentItemToURI({
uri,
fn: (editor) => {
const domNode = document.createElement('div');
domNode.style.zIndex = '1'
// domNode.className = 'void-redBG'
const viewZone: IViewZone = {
// afterLineNumber: computedDiff.startLine - 1,
afterLineNumber: 1,
heightInPx: 100,
// heightInLines: 1,
// minWidthInPx: 200,
domNode: domNode,
suppressMouseDown: false,
};
let zoneId: string | null = null
editor.changeViewZones(accessor => { zoneId = accessor.addZone(viewZone) })
const fn1 = () => editor.changeViewZones(accessor => { if (zoneId) accessor.removeZone(zoneId) })
// on resize
domNode.onresize = () => {
viewZone.heightInPx = domNode.clientHeight
editor.changeViewZones(accessor => { if (zoneId) accessor.layoutZone(zoneId) })
}
this._instantiationService.invokeFunction(accessor => {
const props: QuickEditPropsType = {
quickEditId: diffArea.diffareaid,
}
mountCtrlK(domNode, accessor, props)
})
return () => { fn1(); }
},
})
diffArea._removeStylesFns.add(() => this._zoneStyleService.removeConsistentItemFromURI(consistentZoneId));
const fn = this._addLineDecoration(model, diffArea.startLine, diffArea.endLine, 'void-highlightBG')
this.removeStylesFnsOfURI[uri.fsPath].add(() => fn?.());
diffArea._removeStylesFns.add(() => fn?.());
}
}
}
@ -377,20 +450,38 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
const { snapshottedDiffAreaOfId, entireFileCode: entireModelCode } = structuredClone(snapshot) // don't want to destroy the snapshot
// delete all current decorations (diffs, sweep styles) so we don't have any unwanted leftover decorations
this._clearAllDiffsAndAllStyles(uri)
this._clearAllEffects(uri)
// __TODO__ stop streaming if currently streaming
// restore diffAreaOfId and diffAreasOfModelId
this.diffAreaOfId = {}
this.diffAreasOfURI[uri.fsPath].clear()
for (const diffareaid in snapshottedDiffAreaOfId) {
this.diffAreaOfId[diffareaid] = {
...snapshottedDiffAreaOfId[diffareaid],
_diffOfId: {},
_URI: uri,
_sweepState: {
isStreaming: false,
line: null,
},
const snapshottedDiffArea = snapshottedDiffAreaOfId[diffareaid]
if (snapshottedDiffArea.type === 'DiffZone') {
this.diffAreaOfId[diffareaid] = {
...snapshottedDiffArea as DiffAreaSnapshot<DiffZone>,
type: 'DiffZone',
_diffOfId: {},
_URI: uri,
_sweepState: {
isStreaming: false,
line: null,
} as const,
_removeStylesFns: new Set(),
}
}
else if (snapshottedDiffArea.type === 'CtrlKZone') {
this.diffAreaOfId[diffareaid] = {
...snapshottedDiffArea as DiffAreaSnapshot<CtrlKZone>,
_URI: uri,
_removeStylesFns: new Set(),
}
}
this.diffAreasOfURI[uri.fsPath].add(diffareaid)
}
@ -425,34 +516,43 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
// delete diffOfId and diffArea._diffOfId
private _deleteDiff(diff: Diff) {
const diffArea = this.diffAreaOfId[diff.diffareaid]
if (diffArea.type !== 'DiffZone') return
delete diffArea._diffOfId[diff.diffid]
delete this.diffOfId[diff.diffid]
}
private _deleteDiffs(diffArea: DiffArea) {
for (const diffid in diffArea._diffOfId) {
const diff = diffArea._diffOfId[diffid]
private _deleteDiffs(diffZone: DiffZone) {
for (const diffid in diffZone._diffOfId) {
const diff = diffZone._diffOfId[diffid]
this._deleteDiff(diff)
}
}
// clears styles of DiffAreas too
private _clearAllDiffsAndAllStyles(uri: URI) {
private _deleteEffects(diffArea: DiffArea) {
// clear diffZone effects (diffs)
if (diffArea.type === 'DiffZone')
this._deleteDiffs(diffArea)
else if (diffArea.type === 'CtrlKZone') {
}
diffArea._removeStylesFns.forEach(removeStyles => removeStyles())
}
// clears all Diffs (and their styles) and all styles of DiffAreas
private _clearAllEffects(uri: URI) {
for (let diffareaid of this.diffAreasOfURI[uri.fsPath]) {
const diffArea = this.diffAreaOfId[diffareaid]
this._deleteDiffs(diffArea)
this._deleteEffects(diffArea)
diffArea._removeStylesFns.clear()
}
for (const removeStyleFn of this.removeStylesFnsOfURI[uri.fsPath]) {
removeStyleFn()
}
this.removeStylesFnsOfURI[uri.fsPath].clear()
}
// delete all diffs, update diffAreaOfId, update diffAreasOfModelId
private _deleteDiffArea(diffArea: DiffArea) {
this._deleteDiffs(diffArea)
// we had clear all diffs, but not really needed
delete this.diffAreaOfId[diffArea.diffareaid]
this.diffAreasOfURI[diffArea._URI.fsPath].delete(diffArea.diffareaid.toString())
}
@ -530,9 +630,10 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
if (content === null) return
// 1. clear Diffs and styles
this._clearAllDiffsAndAllStyles(uri)
this._clearAllEffects(uri)
// 2. recompute all diffs on each editor with this URI
const fullFileText = this._readURI(uri) ?? ''
@ -540,25 +641,28 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
for (let diffareaid of this.diffAreasOfURI[uri.fsPath]) {
const diffArea = this.diffAreaOfId[diffareaid]
console.log('DA start and end:', diffArea.startLine, diffArea.endLine)
const newDiffAreaCode = fullFileText.split('\n').slice((diffArea.startLine - 1), (diffArea.endLine - 1) + 1).join('\n')
const computedDiffs = findDiffs(diffArea.originalCode, newDiffAreaCode)
if (diffArea.type === 'DiffZone') {
for (let computedDiff of computedDiffs) {
const diffid = this._diffidPool++
console.log('DA start and end:', diffArea.startLine, diffArea.endLine)
const newDiffAreaCode = fullFileText.split('\n').slice((diffArea.startLine - 1), (diffArea.endLine - 1) + 1).join('\n')
const computedDiffs = findDiffs(diffArea.originalCode, newDiffAreaCode)
// create a Diff of it
const newDiff: Diff = {
...computedDiff,
diffid: diffid,
diffareaid: diffArea.diffareaid,
for (let computedDiff of computedDiffs) {
const diffid = this._diffidPool++
// create a Diff of it
const newDiff: Diff = {
...computedDiff,
diffid: diffid,
diffareaid: diffArea.diffareaid,
}
const fn = this._addDiffStylesToURI(uri, newDiff)
diffArea._removeStylesFns.add(fn)
this.diffOfId[diffid] = newDiff
diffArea._diffOfId[diffid] = newDiff
}
const fn = this._addDiffStylesToURI(uri, newDiff)
this.removeStylesFnsOfURI[uri.fsPath].add(fn)
this.diffOfId[diffid] = newDiff
diffArea._diffOfId[diffid] = newDiff
}
// update styles on this DiffArea
@ -570,16 +674,17 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
// @throttle(100)
private _writeDiffAreaLLMText(diffArea: DiffArea, newCodeSoFar: string) {
private _writeDiffZoneLLMText(diffArea: DiffArea, llmText: string, latestCurrentFileEnd: IPosition, newPosition: IPosition) {
if (diffArea.type !== 'DiffZone') return
// ----------- 1. Write the new code to the document -----------
// figure out where to highlight based on where the AI is in the stream right now, use the last diff to figure that out
const uri = diffArea._URI
const computedDiffs = findDiffs(diffArea.originalCode, newCodeSoFar)
const computedDiffs = findDiffs(diffArea.originalCode, llmText)
// if not streaming, just write the new code
if (!diffArea._sweepState.isStreaming) {
this._writeText(uri, newCodeSoFar,
this._writeText(uri, llmText,
{ startLineNumber: diffArea.startLine, startColumn: 1, endLineNumber: diffArea.endLine, endColumn: Number.MAX_SAFE_INTEGER, } // 1-indexed
)
}
@ -617,7 +722,7 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
diffArea._sweepState.line = newFileEndLine
// lines are 1-indexed
const newFileTop = newCodeSoFar.split('\n').slice(0, (newFileEndLine - 1)).join('\n')
const newFileTop = llmText.split('\n').slice(0, (newFileEndLine - 1)).join('\n')
const oldFileBottom = diffArea.originalCode.split('\n').slice((oldFileStartLine - 1), Infinity).join('\n')
const newCode = `${newFileTop}\n${oldFileBottom}`
@ -635,7 +740,7 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
private async _initializeStream(opts: LLMFeatureSelection, diffRepr: string, uri: URI,) {
private _initializeStream(featureParams: ServiceSendLLMFeatureParams, diffRepr: string, uri: URI,): DiffZone | undefined {
// diff area begin and end line
const numLines = this._getNumLines(uri)
@ -660,6 +765,10 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
if (currentFileStr === null) return
const originalCode = currentFileStr.split('\n').slice((beginLine - 1), (endLine - 1) + 1).join('\n')
let streamRequestIdRef: { current: string | null } = { current: null }
// add to history
const { onFinishEdit } = this._addToHistory(uri)
@ -667,20 +776,22 @@ class InlineDiffsService extends Disposable implements IInlineDiffsService {
const diffareaid = this._diffareaidPool++
// in ctrl+L the start and end lines are the full document
const diffArea: DiffArea = {
const diffArea: DiffZone = {
type: 'DiffZone',
diffareaid: diffareaid,
// originalStartLine: beginLine,
// originalEndLine: endLine,
originalCode: originalCode,
startLine: beginLine,
endLine: endLine, // starts out the same as the current file
shouldHighlight: false,
_URI: uri,
_sweepState: {
isStreaming: true,
streamRequestIdRef,
line: 1,
},
_diffOfId: {}, // added later
_removeStylesFns: new Set(),
}
// console.log('adding uri.fspath', uri.fsPath, diffArea.diffareaid.toString())
@ -704,45 +815,42 @@ Please finish writing the new file by applying the diff to the original file. Re
`
await new Promise<void>((resolve, reject) => {
const latestCurrentFileEnd: IPosition = { lineNumber: 1, column: 1 }
const latestOriginalFileStart: IPosition = { lineNumber: 1, column: 1 }
let streamRequestId: string | null = null
streamRequestIdRef.current = this._llmMessageService.sendLLMMessage({
logging: { loggingName: 'streamChunk' },
messages: [
{ role: 'system', content: inlineDiff_systemMessage, },
// TODO include more context too
{ role: 'user', content: promptContent, }
],
onText: ({ newText, fullText }) => {
this._writeDiffZoneLLMText(diffArea, fullText, latestCurrentFileEnd, latestOriginalFileStart)
this._refreshDiffsInURI(uri)
},
onFinalMessage: ({ fullText }) => {
this._writeText(uri, fullText,
{ startLineNumber: diffArea.startLine, startColumn: 1, endLineNumber: diffArea.endLine, endColumn: Number.MAX_SAFE_INTEGER }, // 1-indexed
)
diffArea._sweepState = { isStreaming: false, line: null }
this._refreshDiffsInURI(uri)
onFinishEdit()
},
onError: (e) => {
console.error('Error rewriting file with diff', e);
// TODO indicate there was an error
if (streamRequestIdRef.current)
this._llmMessageService.abort(streamRequestIdRef.current)
const object: ServiceSendLLMMessageParams = {
logging: { loggingName: 'streamChunk' },
messages: [
{ role: 'system', content: inlineDiff_systemMessage, },
// TODO include more context too
{ role: 'user', content: promptContent, }
],
onText: ({ newText, fullText }) => {
this._writeDiffAreaLLMText(diffArea, fullText)
this._refreshDiffsInURI(uri)
},
onFinalMessage: ({ fullText }) => {
this._writeText(uri, fullText,
{ startLineNumber: diffArea.startLine, startColumn: 1, endLineNumber: diffArea.endLine, endColumn: Number.MAX_SAFE_INTEGER }, // 1-indexed
)
diffArea._sweepState = { isStreaming: false, line: null }
this._refreshDiffsInURI(uri)
resolve();
},
onError: (e: any) => {
console.error('Error rewriting file with diff', e);
// TODO indicate there was an error
if (streamRequestId)
this._llmMessageService.abort(streamRequestId)
diffArea._sweepState = { isStreaming: false, line: null }
resolve();
},
...opts
}
streamRequestId = this._llmMessageService.sendLLMMessage(object)
diffArea._sweepState = { isStreaming: false, line: null }
onFinishEdit()
},
...featureParams
})
onFinishEdit()
return diffArea
}
@ -751,49 +859,50 @@ Please finish writing the new file by applying the diff to the original file. Re
async startStreaming(opts: LLMFeatureSelection, userMessage: string) {
async startStreaming(opts: StartStreamingOpts, userMessage: string) {
const editor = this._editorService.getActiveCodeEditor()
if (!editor) return
const uri = editor.getModel()?.uri
if (!uri) return
// TODO reject all diffs in the diff area
// TODO deselect user's cursor
this._initializeStream(opts, userMessage, uri)
const addedDiffZone = this._initializeStream(opts, userMessage, uri)
return addedDiffZone?.diffareaid
}
interruptStreaming() {
// TODO add abort
private _stopIfStreaming(diffZone: DiffZone) {
}
addDiffArea({ uri, startLine, endLine, originalCode }: { uri: URI, startLine: number, endLine: number, originalCode: string }) {
const diffareaid = this._diffareaidPool++
interruptStreaming(diffareaid: string) {
const diffArea = this.diffAreaOfId[diffareaid]
const diffArea: DiffArea = {
diffareaid: diffareaid,
originalCode,
startLine,
endLine,
shouldHighlight: true,
_URI: uri,
_sweepState: {
isStreaming: false,
line: null,
},
_diffOfId: {},
}
if (!diffArea) return
if (diffArea.type !== 'DiffZone') return
if (!diffArea._sweepState.isStreaming) return
this.diffAreasOfURI[uri.fsPath].add(diffArea.diffareaid.toString())
this.diffAreaOfId[diffArea.diffareaid] = diffArea
const streamRequestId = diffArea._sweepState.streamRequestIdRef.current
if (streamRequestId)
this._llmMessageService.abort(streamRequestId)
// __TODO__ update diffArea streamState here + don't elsewhere
// call undo - __TODO__ make this get called in undo and redo too
this._undoRedoService.undo(diffArea._URI)
}
addCtrlK({ uri, range }: { uri: URI, range: IRange, }) {
// TODO check if intersects with a current ctrl K, if so focus it
this._refreshDiffsInURI(uri)
}
@ -810,6 +919,8 @@ Please finish writing the new file by applying the diff to the original file. Re
const diffArea = this.diffAreaOfId[diffareaid]
if (!diffArea) return
if (diffArea.type !== 'DiffZone') return
const uri = diffArea._URI
// add to history
@ -877,6 +988,8 @@ Please finish writing the new file by applying the diff to the original file. Re
const diffArea = this.diffAreaOfId[diffareaid]
if (!diffArea) return
if (diffArea.type !== 'DiffZone') return
const uri = diffArea._URI
// add to history

View file

@ -1,20 +1,11 @@
import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js';
import { ICodeEditor, IViewZone } from '../../../../editor/browser/editorBrowser.js';
import { Action2, registerAction2 } from '../../../../platform/actions/common/actions.js';
import { createDecorator, IInstantiationService, ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';
import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';
import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';
import { IMetricsService } from '../../../../platform/void/common/metricsService.js';
import { Emitter, Event } from '../../../../base/common/event.js';
// import { IInlineDiffService } from '../../../../editor/browser/services/inlineDiffService/inlineDiffService.js';
import { Disposable } from '../../../../base/common/lifecycle.js';
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
import { mountCtrlK } from './react/out/ctrl-k-tsx/index.js';
import { URI } from '../../../../base/common/uri.js';
type InitialZone = { uri: URI, startLine: number, selectedText: string, }
export type QuickEditPropsType = {
quickEditId: number,
}
@ -28,83 +19,6 @@ export type QuickEdit = {
}
export interface IQuickEditService {
readonly _serviceBrand: undefined;
readonly onDidChangeState: Event<void>;
addZone(zone: InitialZone): void;
}
export const IQuickEditService = createDecorator<IQuickEditService>('voidQuickEditService');
class VoidQuickEditService extends Disposable implements IQuickEditService {
_serviceBrand: undefined;
quickEditId: number = 0
private readonly _onDidChangeState = new Emitter<void>();
readonly onDidChangeState: Event<void> = this._onDidChangeState.event;
// state
// state: {}
constructor(
// @IInlineDiffService private readonly _inlineDiffService: IInlineDiffService,
@ICodeEditorService private readonly _editorService: ICodeEditorService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
) {
super();
}
addZone(zone: InitialZone) {
const addZoneToEditor = (editor: ICodeEditor) => {
const model = editor.getModel()
if (!model) return
editor.changeViewZones(accessor => {
const domNode = document.createElement('div');
domNode.style.zIndex = '1'
// domNode.className = 'void-redBG'
const viewZone: IViewZone = {
// afterLineNumber: computedDiff.startLine - 1,
afterLineNumber: 1,
heightInPx: 100,
// heightInLines: 1,
// minWidthInPx: 200,
domNode: domNode,
// marginDomNode: document.createElement('div'), // displayed to left
suppressMouseDown: false,
};
// const zoneId =
accessor.addZone(viewZone)
this._instantiationService.invokeFunction(accessor => {
const props: QuickEditPropsType = {
quickEditId: this.quickEditId++,
}
mountCtrlK(domNode, accessor, props)
})
// disposeInThisEditorFns.push(() => { editor.changeViewZones(accessor => { if (zoneId) accessor.removeZone(zoneId) }) })
})
}
const editors = this._editorService.listCodeEditors().filter(editor => editor.getModel()?.uri.fsPath === zone.uri.fsPath)
for (const editor of editors) {
addZoneToEditor(editor)
}
}
}
registerSingleton(IQuickEditService, VoidQuickEditService, InstantiationType.Eager);
export const VOID_CTRL_K_ACTION_ID = 'void.ctrlKAction'
registerAction2(class extends Action2 {
constructor() {
@ -112,7 +26,6 @@ registerAction2(class extends Action2 {
}
async run(accessor: ServicesAccessor): Promise<void> {
const quickEditService = accessor.get(IQuickEditService)
const editorService = accessor.get(ICodeEditorService)
const metricsService = accessor.get(IMetricsService)
@ -125,11 +38,11 @@ registerAction2(class extends Action2 {
const selection = editor.getSelection()
if (!selection) return;
const uri = model.uri
const startLine = selection.startLineNumber
const selectedText = model.getValueInRange(selection)
// const uri = model.uri
// const startLine = selection.startLineNumber
// const selectedText = model.getValueInRange(selection)
quickEditService.addZone({ uri, startLine, selectedText, })
// quickEditService.addZone({ uri, startLine, selectedText, })
}
});