Skip to content

Commit

Permalink
Scaffold using floating content widgets
Browse files Browse the repository at this point in the history
  • Loading branch information
alexdima committed Dec 16, 2024
1 parent d3bd083 commit ae9d01c
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 3 deletions.
27 changes: 26 additions & 1 deletion src/vs/editor/browser/observableCodeEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { Selection } from '../common/core/selection.js';
import { ICursorSelectionChangedEvent } from '../common/cursorEvents.js';
import { IModelDeltaDecoration, ITextModel } from '../common/model.js';
import { IModelContentChangedEvent } from '../common/textModelEvents.js';
import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IOverlayWidget, IOverlayWidgetPosition } from './editorBrowser.js';
import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition, IOverlayWidget, IOverlayWidgetPosition } from './editorBrowser.js';
import { Point } from './point.js';

/**
Expand Down Expand Up @@ -265,6 +265,25 @@ export class ObservableCodeEditor extends Disposable {
});
}

public createContentWidget(widget: IObservableContentWidget): IDisposable {
const overlayWidgetId = 'observableContentWidget' + (this._widgetCounter++);
const w: IContentWidget = {
getDomNode: () => widget.domNode,
getPosition: () => widget.position.get(),
getId: () => overlayWidgetId,
allowEditorOverflow: widget.allowEditorOverflow,
};
this.editor.addContentWidget(w);
const d = autorun(reader => {
widget.position.read(reader);
this.editor.layoutContentWidget(w);
});
return toDisposable(() => {
d.dispose();
this.editor.removeContentWidget(w);
});
}

public observePosition(position: IObservable<Position | null>, store: DisposableStore): IObservable<Point | null> {
const result = observableValueOpts<Point | null>({ owner: this, equalsFn: equalsIfDefined(Point.equals) }, new Point(0, 0));
const contentWidgetId = `observablePositionWidget` + (this._widgetCounter++);
Expand Down Expand Up @@ -299,3 +318,9 @@ interface IObservableOverlayWidget {
readonly minContentWidthInPx: IObservable<number>;
get allowEditorOverflow(): boolean;
}

interface IObservableContentWidget {
get domNode(): HTMLElement;
readonly position: IObservable<IContentWidgetPosition | null>;
get allowEditorOverflow(): boolean;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/


import { Disposable } from '../../../../../../base/common/lifecycle.js';
import { IObservable } from '../../../../../../base/common/observable.js';
import { ContentWidgetPositionPreference } from '../../../../../browser/editorBrowser.js';
import { ObservableCodeEditor } from '../../../../../browser/observableCodeEditor.js';
import { SingleTextEdit } from '../../../../../common/core/textEdit.js';
import { n } from './utils.js';
import './view.css';


export class FloatingReplacement extends Disposable {
static _widgetCounter = 0;

private readonly _domNode = n.div({
class: 'floatingReplacement',
}, [
this._edit.map(edit => edit.text)
]).keepUpdated(this._store);

constructor(
private readonly _editorObs: ObservableCodeEditor,
private readonly _edit: IObservable<SingleTextEdit>,
) {
super();
this._register(this._editorObs.createContentWidget({
domNode: this._domNode.element,
position: this._edit.map(edit => ({
preference: [ContentWidgetPositionPreference.ABOVE],
position: edit.range.getStartPosition()
})),
allowEditorOverflow: false
}));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,8 @@
.inlineCompletions-char-insert.diff-range-empty {
border-left: solid var(--vscode-inlineEdit-modifiedChangedTextBackground) 3px;
}

.floatingReplacement {
background: var(--vscode-inlineEdit-modifiedChangedTextBackground);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@
*--------------------------------------------------------------------------------------------*/

import { Disposable } from '../../../../../../base/common/lifecycle.js';
import { derived, IObservable, IReader } from '../../../../../../base/common/observable.js';
import { constObservable, derived, IObservable, IReader, mapObservableArrayCached } from '../../../../../../base/common/observable.js';
import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js';
import { ICodeEditor } from '../../../../../browser/editorBrowser.js';
import { observableCodeEditor } from '../../../../../browser/observableCodeEditor.js';
import { EditorOption } from '../../../../../common/config/editorOptions.js';
import { LineRange } from '../../../../../common/core/lineRange.js';
import { Position } from '../../../../../common/core/position.js';
import { StringText } from '../../../../../common/core/textEdit.js';
import { SingleTextEdit, StringText } from '../../../../../common/core/textEdit.js';
import { DetailedLineRangeMapping, lineRangeMappingFromRangeMappings, RangeMapping } from '../../../../../common/diff/rangeMapping.js';
import { TextModel } from '../../../../../common/model/textModel.js';
import { InlineCompletionsModel } from '../../model/inlineCompletionsModel.js';
import { FloatingReplacement } from './floatingReplacement.js';
import { IInlineEditsIndicatorState, InlineEditsIndicator } from './indicatorView.js';
import { IOriginalEditorInlineDiffViewState, OriginalEditorInlineDiffView } from './inlineDiffView.js';
import { InlineEditsSideBySideDiff } from './sideBySideDiff.js';
Expand Down Expand Up @@ -116,6 +117,15 @@ export class InlineEditsView extends Disposable {
};
});

protected readonly _floatingReplacements = mapObservableArrayCached(
this,
this._uiState.map(state => state?.diff.flatMap(d => d.innerChanges!) ?? []),
(diff, store) => {
const edit = constObservable(new SingleTextEdit(diff.originalRange, this._previewTextModel.getValueInRange(diff.modifiedRange)));
store.add(new FloatingReplacement(this._editorObs, edit));
}
).recomputeInitiallyAndOnChange(this._store);

protected readonly _inlineDiffView = this._register(new OriginalEditorInlineDiffView(this._editor, this._inlineDiffViewState, this._previewTextModel));

protected readonly _indicator = this._register(new InlineEditsIndicator(
Expand Down

0 comments on commit ae9d01c

Please sign in to comment.