add files to make native insets work! #124

This commit is contained in:
Andrew 2024-11-01 21:23:38 -07:00
parent d7c00addd5
commit 5acc53311d
8 changed files with 323 additions and 3 deletions

View file

@ -25,6 +25,13 @@ declare module 'vscode' {
}
}
// this comes from vscode.d.ts
declare module 'vscode' {
export namespace languages {
export function addInlineDiff(editor: vscode.TextEditor, originalText: string, modifiedRange: Range): void;
}
}
const roundRangeToLines = (selection: vscode.Selection) => {
let endLine = selection.end.character === 0 ? selection.end.line - 1 : selection.end.line // e.g. if the user triple clicks, it selects column=0, line=line -> column=0, line=line+1
return new vscode.Range(selection.start.line, 0, endLine, Number.MAX_SAFE_INTEGER)
@ -62,6 +69,9 @@ export function activate(context: vscode.ExtensionContext) {
const { selectionStr, filePath } = getSelection(editor)
vscode.languages.addInlineDiff(editor, 'oldText', editor.selection)
// send message to the webview (Sidebar.tsx)
sidebarWebviewProvider.webview.then(webview => webview.postMessage({ type: 'ctrl+l', selection: { selectionStr, filePath } } satisfies MessageToSidebar));
})

View file

@ -0,0 +1,115 @@
// This file was added by the Void team
// src/vs/editor/browser/services/inlineDiffService.ts
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 { IModelDecorationOptions, IModelDeltaDecoration } from '../../common/model.js';
import { ICodeEditor, IViewZone } from '../editorBrowser.js';
import { IRange } from '../../common/core/range.js';
export interface IInlineDiffService {
readonly _serviceBrand: undefined;
addDiff(editor: ICodeEditor, originalText: string, modifiedRange: IRange): void;
removeDiffs(editor: ICodeEditor): void;
}
export const IInlineDiffService = createDecorator<IInlineDiffService>('inlineDiffService');
class InlineDiffService extends Disposable implements IInlineDiffService {
private readonly _diffDecorations = new Map<ICodeEditor, string[]>();
private readonly _diffZones = new Map<ICodeEditor, string[]>();
_serviceBrand: undefined;
private static readonly ADDED_DECORATION: IModelDecorationOptions = {
className: 'inline-diff-added',
description: 'inline-diff-added',
isWholeLine: false,
minimap: {
color: { id: 'minimapGutter.addedBackground' },
position: 2
},
overviewRuler: {
color: { id: 'editorOverviewRuler.addedForeground' },
position: 7
}
};
constructor(
) {
super();
}
public addDiff: IInlineDiffService['addDiff'] = (editor, originalText, modifiedRange) => {
// Clear existing diffs
this.removeDiffs(editor);
// Add decoration for modified text
const decorations: IModelDeltaDecoration[] = [{
range: modifiedRange,
options: InlineDiffService.ADDED_DECORATION
}];
const newDecorations = editor.deltaDecorations([], decorations);
this._diffDecorations.set(editor, newDecorations);
// Add view zone for original text
editor.changeViewZones(accessor => {
const domNode = document.createElement('div');
domNode.className = 'inline-diff-deleted monaco-editor';
// Create inner container for proper padding
const innerContainer = document.createElement('div');
innerContainer.className = 'view-line';
innerContainer.textContent = originalText;
domNode.appendChild(innerContainer);
const viewZone: IViewZone = {
afterLineNumber: modifiedRange.startLineNumber - 1,
heightInLines: originalText.split('\n').length,
domNode: domNode,
suppressMouseDown: true,
marginDomNode: this.createGutterElement(editor)
};
const zoneId = accessor.addZone(viewZone);
this._diffZones.set(editor, [zoneId]);
});
}
private createGutterElement(editor: ICodeEditor): HTMLElement {
const gutterDiv = document.createElement('div');
gutterDiv.className = 'inline-diff-gutter';
gutterDiv.innerHTML = '<div class="inline-diff-deleted-gutter">-</div>';
return gutterDiv;
}
public removeDiffs(editor: ICodeEditor): void {
// Clear decorations
const decorationIds = this._diffDecorations.get(editor) || [];
editor.deltaDecorations(decorationIds, []);
this._diffDecorations.delete(editor);
// Clear view zones
editor.changeViewZones(accessor => {
const zoneIds = this._diffZones.get(editor) || [];
zoneIds.forEach(id => accessor.removeZone(id));
});
this._diffZones.delete(editor);
}
override dispose(): void {
super.dispose();
this._diffDecorations.clear();
this._diffZones.clear();
}
}
// Register the service
registerSingleton(IInlineDiffService, InlineDiffService, InstantiationType.Eager);

View file

@ -425,3 +425,27 @@
margin: 0 4px;
}
}
/* Void added this: */
.inline-diff-deleted {
background-color: var(--vscode-diffEditor-removedTextBackground);
text-decoration: line-through;
}
.inline-diff-added {
background-color: var(--vscode-diffEditor-insertedTextBackground);
}
.inline-diff-gutter {
width: 100%;
height: 100%;
}
.inline-diff-deleted-gutter {
opacity: 0.7;
padding-left: 4px;
}
.view-line {
padding: 0 4px;
}

View file

@ -0,0 +1,82 @@
// Void created this file
// it comes from mainThreadCodeInsets.ts
import { Disposable } from '../../../base/common/lifecycle.js';
import { ICodeEditorService } from '../../../editor/browser/services/codeEditorService.js';
import { MainContext, MainThreadInlineDiffShape } from '../common/extHost.protocol.js';
import { IInlineDiffService } from '../../../editor/browser/services/inlineDiffService.js';
import { ICodeEditor } from '../../../editor/browser/editorBrowser.js';
import { IRange } from '../../../editor/common/core/range.js';
import { extHostNamedCustomer, IExtHostContext } from '../../services/extensions/common/extHostCustomers.js';
@extHostNamedCustomer(MainContext.MainThreadInlineDiff)
export class MainThreadInlineDiff extends Disposable implements MainThreadInlineDiffShape {
// private readonly _proxy: ExtHostEditorInsetsShape;
// private readonly _disposables = new DisposableStore();
constructor(
context: IExtHostContext,
@IInlineDiffService private readonly _inlineDiff: IInlineDiffService,
@ICodeEditorService private readonly _editorService: ICodeEditorService,
) {
super();
}
// this._proxy = context.getProxy(ExtHostContext.ExtHostEditorInsets);
// dispose(): void {
// this._disposables.dispose();
// }
$addDiff(editorId: string, originalText: string, range: IRange): void {
let editor: ICodeEditor | undefined;
editorId = editorId.substr(0, editorId.indexOf(',')); //todo@jrieken HACK
for (const candidate of this._editorService.listCodeEditors()) {
if (candidate.getId() === editorId
// && candidate.hasModel() && isEqual(candidate.getModel().uri, URI.revive(uri))
) {
editor = candidate;
break;
}
}
if (!editor) {
// setTimeout(() => this._proxy.$onDidDispose(editorId));
return;
}
this._inlineDiff.addDiff(editor, originalText, range)
// return editor
// const disposables = new DisposableStore();
// const remove = () => {
// disposables.dispose();
// this._proxy.$onDidDispose(handle);
// this._insets.delete(handle);
// };
// disposables.add(editor.onDidChangeModel(remove));
// disposables.add(editor.onDidDispose(remove));
}
// $disposeEditorInset(handle: number): void {
// const inset = this.getInset(handle);
// this._insets.delete(handle);
// inset.dispose();
// }
// private getInset(handle: number): EditorWebviewZone {
// const inset = this._insets.get(handle);
// if (!inset) {
// throw new Error('Unknown inset');
// }
// return inset;
// }
}

View file

@ -109,6 +109,7 @@ import { ProxyIdentifier } from '../../services/extensions/common/proxyIdentifie
import { ExcludeSettingOptions, TextSearchCompleteMessageType, TextSearchContextNew, TextSearchMatchNew } from '../../services/search/common/searchExtTypes.js';
import type * as vscode from 'vscode';
import { ExtHostCodeMapper } from './extHostCodeMapper.js';
import { ExtHostInlineDiff } from './extHostInlineDiff.js';
export interface IExtensionRegistries {
mine: ExtensionDescriptionRegistry;
@ -221,6 +222,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostSpeech = rpcProtocol.set(ExtHostContext.ExtHostSpeech, new ExtHostSpeech(rpcProtocol));
const extHostEmbeddings = rpcProtocol.set(ExtHostContext.ExtHostEmbeddings, new ExtHostEmbeddings(rpcProtocol));
// Void added this:
const extHostInlineDiff = rpcProtocol.set(ExtHostContext.ExtHostInlineDiff, new ExtHostInlineDiff(rpcProtocol.getProxy(MainContext.MainThreadInlineDiff), extHostEditors));
// Check that no named customers are missing
const expected = Object.values<ProxyIdentifier<any>>(ExtHostContext);
rpcProtocol.assertRegistered(expected);
@ -519,6 +523,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
// namespace: languages
const languages: typeof vscode.languages = {
createDiagnosticCollection(name?: string): vscode.DiagnosticCollection {
return extHostDiagnostics.createDiagnosticCollection(extension.identifier, name);
},
@ -553,6 +558,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostLanguageFeatures.registerCodeLensProvider(extension, checkSelector(selector), provider);
},
// Void added addInlineDiff here:
addInlineDiff(editor: vscode.TextEditor, originalText: string, modifiedRange: vscode.Range): void {
extHostInlineDiff.addDiff(editor, originalText, modifiedRange)
},
// Void added this (I think will need to add this back when add ctrl+K)
// registerVoidCtrlKProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable {
// return extHostLanguageFeatures.registerCodeLensProvider(extension, checkSelector(selector), provider);

View file

@ -2984,7 +2984,10 @@ export const MainContext = {
MainThreadTesting: createProxyIdentifier<MainThreadTestingShape>('MainThreadTesting'),
MainThreadLocalization: createProxyIdentifier<MainThreadLocalizationShape>('MainThreadLocalizationShape'),
MainThreadAiRelatedInformation: createProxyIdentifier<MainThreadAiRelatedInformationShape>('MainThreadAiRelatedInformation'),
MainThreadAiEmbeddingVector: createProxyIdentifier<MainThreadAiEmbeddingVectorShape>('MainThreadAiEmbeddingVector')
MainThreadAiEmbeddingVector: createProxyIdentifier<MainThreadAiEmbeddingVectorShape>('MainThreadAiEmbeddingVector'),
// Void added this:
MainThreadInlineDiff: createProxyIdentifier<MainThreadInlineDiffShape>('MainThreadInlineDiff'),
};
export const ExtHostContext = {
@ -3055,5 +3058,17 @@ export const ExtHostContext = {
ExtHostTimeline: createProxyIdentifier<ExtHostTimelineShape>('ExtHostTimeline'),
ExtHostTesting: createProxyIdentifier<ExtHostTestingShape>('ExtHostTesting'),
ExtHostTelemetry: createProxyIdentifier<ExtHostTelemetryShape>('ExtHostTelemetry'),
ExtHostLocalization: createProxyIdentifier<ExtHostLocalizationShape>('ExtHostLocalization')
ExtHostLocalization: createProxyIdentifier<ExtHostLocalizationShape>('ExtHostLocalization'),
// Void added this:
ExtHostInlineDiff: createProxyIdentifier<ExtHostInlineDiffShape>('ExtHostInlineDiff'), // Void added this
};
// Void added these:
export interface ExtHostInlineDiffShape {
$onDidDispose(handle: number): void;
}
export interface MainThreadInlineDiffShape {
$addDiff(editorId: string, originalText: string, range: IRange): void;
}

View file

@ -0,0 +1,62 @@
// This file was created by Void
// reference extHostCodeInsets.ts
import { Emitter } from '../../../base/common/event.js';
import { DisposableStore } from '../../../base/common/lifecycle.js';
import { ExtHostInlineDiffShape, MainThreadInlineDiffShape } from './extHost.protocol.js';
import * as vscode from 'vscode'
import { ExtHostTextEditor } from './extHostTextEditor.js';
import { ExtHostEditors } from './extHostTextEditors.js';
import { Range } from '../../../workbench/api/common/extHostTypeConverters.js'
export class ExtHostInlineDiff implements ExtHostInlineDiffShape {
private readonly _disposables = new DisposableStore();
private _insets = new Map<number, { editor: vscode.TextEditor; inset: vscode.WebviewEditorInset; onDidReceiveMessage: Emitter<any> }>();
constructor(
private readonly _proxy: MainThreadInlineDiffShape,
private readonly _editors: ExtHostEditors,
) { }
dispose(): void {
this._insets.forEach(value => value.inset.dispose());
this._disposables.dispose();
}
addDiff(editor: vscode.TextEditor, originalText: string, modifiedRange: vscode.Range) {
let apiEditor: ExtHostTextEditor | undefined;
for (const candidate of this._editors.getVisibleTextEditors(true)) {
if (candidate.value === editor) {
apiEditor = <ExtHostTextEditor>candidate;
break;
}
}
if (!apiEditor) {
throw new Error('not a visible editor');
}
const id = apiEditor.id;
// let uri = apiEditor.value.document.uri;
// convert to IRange
const range = Range.from(modifiedRange)
this._proxy.$addDiff(id, originalText, range)
}
// main thread calls this when disposes diff with this particular handle
$onDidDispose(handle: number): void {
const value = this._insets.get(handle);
if (value) {
value.inset.dispose();
}
}
}

View file

@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
declare module 'vscode' {
/**
* The version of the editor.
*/
@ -14074,6 +14073,9 @@ declare module 'vscode' {
*/
export namespace languages {
/** Void added this: */
export function addInlineDiff(editor: TextEditor, originalText: string, modifiedRange: Range): void;
/**
* Return the identifiers of all known languages.
* @returns Promise resolving to an array of identifier strings.