diff --git a/src/vs/base/common/arrays.ts b/src/vs/base/common/arrays.ts index d4a409034430b..66efbcd8b82b5 100644 --- a/src/vs/base/common/arrays.ts +++ b/src/vs/base/common/arrays.ts @@ -702,12 +702,14 @@ export function compareUndefinedSmallest(comparator: Comparator): Comparat export class ArrayQueue { private firstIdx = 0; - private lastIdx = this.items.length - 1; + private lastIdx: number; /** * Constructs a queue that is backed by the given array. Runtime is O(1). */ - constructor(private readonly items: readonly T[]) { } + constructor(private readonly items: readonly T[]) { + this.lastIdx = this.items.length - 1; + } get length(): number { return this.lastIdx - this.firstIdx + 1; diff --git a/src/vs/base/parts/ipc/common/ipc.mp.ts b/src/vs/base/parts/ipc/common/ipc.mp.ts index 4fc2f0b6dac6d..367480a3d0796 100644 --- a/src/vs/base/parts/ipc/common/ipc.mp.ts +++ b/src/vs/base/parts/ipc/common/ipc.mp.ts @@ -41,15 +41,17 @@ export interface MessagePort { */ export class Protocol implements IMessagePassingProtocol { - readonly onMessage = Event.fromDOMEventEmitter(this.port, 'message', (e: MessageEvent) => { - if (e.data) { - return VSBuffer.wrap(e.data); - } - return VSBuffer.alloc(0); - }); + readonly onMessage: Event; constructor(private port: MessagePort) { + this.onMessage = Event.fromDOMEventEmitter(this.port, 'message', (e: MessageEvent) => { + if (e.data) { + return VSBuffer.wrap(e.data); + } + return VSBuffer.alloc(0); + }); + // we must call start() to ensure messages are flowing port.start(); } diff --git a/src/vs/base/parts/ipc/node/ipc.mp.ts b/src/vs/base/parts/ipc/node/ipc.mp.ts index 87e1016f045f2..a6c03be319fad 100644 --- a/src/vs/base/parts/ipc/node/ipc.mp.ts +++ b/src/vs/base/parts/ipc/node/ipc.mp.ts @@ -15,15 +15,17 @@ import { assertType } from '../../../common/types.js'; */ class Protocol implements IMessagePassingProtocol { - readonly onMessage = Event.fromNodeEventEmitter(this.port, 'message', (e: MessageEvent) => { - if (e.data) { - return VSBuffer.wrap(e.data); - } - return VSBuffer.alloc(0); - }); + readonly onMessage: Event; constructor(private port: MessagePortMain) { + this.onMessage = Event.fromNodeEventEmitter(this.port, 'message', (e: MessageEvent) => { + if (e.data) { + return VSBuffer.wrap(e.data); + } + return VSBuffer.alloc(0); + }); + // we must call start() to ensure messages are flowing port.start(); } diff --git a/src/vs/base/parts/storage/node/storage.ts b/src/vs/base/parts/storage/node/storage.ts index 2def700f2b056..67283a0deaa6a 100644 --- a/src/vs/base/parts/storage/node/storage.ts +++ b/src/vs/base/parts/storage/node/storage.ts @@ -38,13 +38,19 @@ export class SQLiteStorageDatabase implements IStorageDatabase { private static readonly BUSY_OPEN_TIMEOUT = 2000; // timeout in ms to retry when opening DB fails with SQLITE_BUSY private static readonly MAX_HOST_PARAMETERS = 256; // maximum number of parameters within a statement - private readonly name = basename(this.path); + private readonly name: string; - private readonly logger = new SQLiteStorageDatabaseLogger(this.options.logging); + private readonly logger: SQLiteStorageDatabaseLogger; - private readonly whenConnected = this.connect(this.path); + private readonly whenConnected: Promise; - constructor(private readonly path: string, private readonly options: ISQLiteStorageDatabaseOptions = Object.create(null)) { } + constructor(private readonly path: string, private readonly options: ISQLiteStorageDatabaseOptions = Object.create(null)) { + this.name = basename(this.path); + + this.logger = new SQLiteStorageDatabaseLogger(this.options.logging); + + this.whenConnected = this.connect(this.path); + } async getItems(): Promise> { const connection = await this.whenConnected; diff --git a/src/vs/code/electron-utility/sharedProcess/contrib/codeCacheCleaner.ts b/src/vs/code/electron-utility/sharedProcess/contrib/codeCacheCleaner.ts index 7560b8fac32c4..1018ee1891563 100644 --- a/src/vs/code/electron-utility/sharedProcess/contrib/codeCacheCleaner.ts +++ b/src/vs/code/electron-utility/sharedProcess/contrib/codeCacheCleaner.ts @@ -14,9 +14,7 @@ import { IProductService } from '../../../../platform/product/common/productServ export class CodeCacheCleaner extends Disposable { - private readonly _DataMaxAge = this.productService.quality !== 'stable' - ? 1000 * 60 * 60 * 24 * 7 // roughly 1 week (insiders) - : 1000 * 60 * 60 * 24 * 30 * 3; // roughly 3 months (stable) + private readonly _DataMaxAge: number; constructor( currentCodeCachePath: string | undefined, @@ -25,6 +23,10 @@ export class CodeCacheCleaner extends Disposable { ) { super(); + this._DataMaxAge = this.productService.quality !== 'stable' + ? 1000 * 60 * 60 * 24 * 7 // roughly 1 week (insiders) + : 1000 * 60 * 60 * 24 * 30 * 3; // roughly 3 months (stable) + // Cached data is stored as user data and we run a cleanup task every time // the editor starts. The strategy is to delete all files that are older than // 3 months (1 week respectively) diff --git a/src/vs/code/electron-utility/sharedProcess/contrib/languagePackCachedDataCleaner.ts b/src/vs/code/electron-utility/sharedProcess/contrib/languagePackCachedDataCleaner.ts index 0c70b33f15c2c..ab48432bfbf71 100644 --- a/src/vs/code/electron-utility/sharedProcess/contrib/languagePackCachedDataCleaner.ts +++ b/src/vs/code/electron-utility/sharedProcess/contrib/languagePackCachedDataCleaner.ts @@ -33,9 +33,7 @@ interface ILanguagePackFile { export class LanguagePackCachedDataCleaner extends Disposable { - private readonly _DataMaxAge = this.productService.quality !== 'stable' - ? 1000 * 60 * 60 * 24 * 7 // roughly 1 week (insiders) - : 1000 * 60 * 60 * 24 * 30 * 3; // roughly 3 months (stable) + private readonly _DataMaxAge: number; constructor( @INativeEnvironmentService private readonly environmentService: INativeEnvironmentService, @@ -44,6 +42,10 @@ export class LanguagePackCachedDataCleaner extends Disposable { ) { super(); + this._DataMaxAge = this.productService.quality !== 'stable' + ? 1000 * 60 * 60 * 24 * 7 // roughly 1 week (insiders) + : 1000 * 60 * 60 * 24 * 30 * 3; // roughly 3 months (stable) + // We have no Language pack support for dev version (run from source) // So only cleanup when we have a build version. if (this.environmentService.isBuilt) { diff --git a/src/vs/editor/browser/controller/editContext/textArea/textAreaEditContextInput.ts b/src/vs/editor/browser/controller/editContext/textArea/textAreaEditContextInput.ts index fc2dc0dd5ea16..ebc7b4607bfdf 100644 --- a/src/vs/editor/browser/controller/editContext/textArea/textAreaEditContextInput.ts +++ b/src/vs/editor/browser/controller/editContext/textArea/textAreaEditContextInput.ts @@ -619,19 +619,19 @@ export class TextAreaInput extends Disposable { export class TextAreaWrapper extends Disposable implements ICompleteTextAreaWrapper { - public readonly onKeyDown = this._register(new DomEmitter(this._actual, 'keydown')).event; - public readonly onKeyPress = this._register(new DomEmitter(this._actual, 'keypress')).event; - public readonly onKeyUp = this._register(new DomEmitter(this._actual, 'keyup')).event; - public readonly onCompositionStart = this._register(new DomEmitter(this._actual, 'compositionstart')).event; - public readonly onCompositionUpdate = this._register(new DomEmitter(this._actual, 'compositionupdate')).event; - public readonly onCompositionEnd = this._register(new DomEmitter(this._actual, 'compositionend')).event; - public readonly onBeforeInput = this._register(new DomEmitter(this._actual, 'beforeinput')).event; - public readonly onInput = >this._register(new DomEmitter(this._actual, 'input')).event; - public readonly onCut = this._register(new DomEmitter(this._actual, 'cut')).event; - public readonly onCopy = this._register(new DomEmitter(this._actual, 'copy')).event; - public readonly onPaste = this._register(new DomEmitter(this._actual, 'paste')).event; - public readonly onFocus = this._register(new DomEmitter(this._actual, 'focus')).event; - public readonly onBlur = this._register(new DomEmitter(this._actual, 'blur')).event; + public readonly onKeyDown: Event; + public readonly onKeyPress: Event; + public readonly onKeyUp: Event; + public readonly onCompositionStart: Event; + public readonly onCompositionUpdate: Event; + public readonly onCompositionEnd: Event; + public readonly onBeforeInput: Event; + public readonly onInput: Event; + public readonly onCut: Event; + public readonly onCopy: Event; + public readonly onPaste: Event; + public readonly onFocus: Event; + public readonly onBlur: Event; public get ownerDocument(): Document { return this._actual.ownerDocument; @@ -646,6 +646,21 @@ export class TextAreaWrapper extends Disposable implements ICompleteTextAreaWrap private readonly _actual: HTMLTextAreaElement ) { super(); + + this.onKeyDown = this._register(new DomEmitter(this._actual, 'keydown')).event; + this.onKeyPress = this._register(new DomEmitter(this._actual, 'keypress')).event; + this.onKeyUp = this._register(new DomEmitter(this._actual, 'keyup')).event; + this.onCompositionStart = this._register(new DomEmitter(this._actual, 'compositionstart')).event; + this.onCompositionUpdate = this._register(new DomEmitter(this._actual, 'compositionupdate')).event; + this.onCompositionEnd = this._register(new DomEmitter(this._actual, 'compositionend')).event; + this.onBeforeInput = this._register(new DomEmitter(this._actual, 'beforeinput')).event; + this.onInput = >this._register(new DomEmitter(this._actual, 'input')).event; + this.onCut = this._register(new DomEmitter(this._actual, 'cut')).event; + this.onCopy = this._register(new DomEmitter(this._actual, 'copy')).event; + this.onPaste = this._register(new DomEmitter(this._actual, 'paste')).event; + this.onFocus = this._register(new DomEmitter(this._actual, 'focus')).event; + this.onBlur = this._register(new DomEmitter(this._actual, 'blur')).event; + this._ignoreSelectionChangeTime = 0; this._register(this.onKeyDown(() => inputLatency.onKeyDown())); diff --git a/src/vs/editor/browser/observableCodeEditor.ts b/src/vs/editor/browser/observableCodeEditor.ts index eb5172693cef8..6a45f1e6bcd0f 100644 --- a/src/vs/editor/browser/observableCodeEditor.ts +++ b/src/vs/editor/browser/observableCodeEditor.ts @@ -5,8 +5,8 @@ import { equalsIfDefined, itemsEquals } from '../../base/common/equals.js'; import { Disposable, DisposableStore, IDisposable, toDisposable } from '../../base/common/lifecycle.js'; -import { IObservable, IObservableWithChange, ITransaction, TransactionImpl, autorun, autorunOpts, derived, derivedOpts, derivedWithSetter, observableFromEvent, observableSignal, observableValue, observableValueOpts } from '../../base/common/observable.js'; -import { EditorOption, FindComputedEditorOptionValueById } from '../common/config/editorOptions.js'; +import { IObservable, IObservableWithChange, ISettableObservable, ITransaction, TransactionImpl, autorun, autorunOpts, derived, derivedOpts, derivedWithSetter, observableFromEvent, observableSignal, observableValue, observableValueOpts } from '../../base/common/observable.js'; +import { EditorLayoutInfo, EditorMinimapLayoutInfo, EditorOption, FindComputedEditorOptionValueById } from '../common/config/editorOptions.js'; import { LineRange } from '../common/core/lineRange.js'; import { OffsetRange } from '../common/core/offsetRange.js'; import { Position } from '../common/core/position.js'; @@ -71,6 +71,32 @@ export class ObservableCodeEditor extends Disposable { private constructor(public readonly editor: ICodeEditor) { super(); + this._model = observableValue(this, this.editor.getModel()); + this.model = this._model; + + this.isReadonly = observableFromEvent(this, this.editor.onDidChangeConfiguration, () => this.editor.getOption(EditorOption.readOnly)); + + this._versionId = observableValueOpts({ owner: this, lazy: true }, this.editor.getModel()?.getVersionId() ?? null); + this.versionId = this._versionId; + + this._selections = observableValueOpts( + { owner: this, equalsFn: equalsIfDefined(itemsEquals(Selection.selectionsEqual)), lazy: true }, + this.editor.getSelections() ?? null + ); + this.selections = this._selections; + + this.scrollTop = observableFromEvent(this.editor.onDidScrollChange, () => this.editor.getScrollTop()); + this.scrollLeft = observableFromEvent(this.editor.onDidScrollChange, () => this.editor.getScrollLeft()); + + this.layoutInfo = observableFromEvent(this.editor.onDidLayoutChange, () => this.editor.getLayoutInfo()); + this.layoutInfoContentLeft = this.layoutInfo.map(l => l.contentLeft); + this.layoutInfoDecorationsLeft = this.layoutInfo.map(l => l.decorationsLeft); + this.layoutInfoWidth = this.layoutInfo.map(l => l.width); + this.layoutInfoMinimap = this.layoutInfo.map(l => l.minimap); + this.layoutInfoVerticalScrollbarWidth = this.layoutInfo.map(l => l.verticalScrollbarWidth); + + this.contentWidth = observableFromEvent(this.editor.onDidContentSizeChange, () => this.editor.getContentWidth()); + this._register(this.editor.onBeginUpdate(() => this._beginUpdate())); this._register(this.editor.onEndUpdate(() => this._endUpdate())); @@ -149,19 +175,16 @@ export class ObservableCodeEditor extends Disposable { } } - private readonly _model = observableValue(this, this.editor.getModel()); - public readonly model: IObservable = this._model; + private readonly _model: ISettableObservable; + public readonly model: IObservable; - public readonly isReadonly = observableFromEvent(this, this.editor.onDidChangeConfiguration, () => this.editor.getOption(EditorOption.readOnly)); + public readonly isReadonly: IObservable; - private readonly _versionId = observableValueOpts({ owner: this, lazy: true }, this.editor.getModel()?.getVersionId() ?? null); - public readonly versionId: IObservableWithChange = this._versionId; + private readonly _versionId: ISettableObservable; + public readonly versionId: IObservableWithChange; - private readonly _selections = observableValueOpts( - { owner: this, equalsFn: equalsIfDefined(itemsEquals(Selection.selectionsEqual)), lazy: true }, - this.editor.getSelections() ?? null - ); - public readonly selections: IObservableWithChange = this._selections; + private readonly _selections: ISettableObservable; + public readonly selections: IObservableWithChange; public readonly positions = derivedOpts( @@ -225,17 +248,17 @@ export class ObservableCodeEditor extends Disposable { public readonly onDidType = observableSignal(this); public readonly onDidPaste = observableSignal(this); - public readonly scrollTop = observableFromEvent(this.editor.onDidScrollChange, () => this.editor.getScrollTop()); - public readonly scrollLeft = observableFromEvent(this.editor.onDidScrollChange, () => this.editor.getScrollLeft()); + public readonly scrollTop: IObservable; + public readonly scrollLeft: IObservable; - public readonly layoutInfo = observableFromEvent(this.editor.onDidLayoutChange, () => this.editor.getLayoutInfo()); - public readonly layoutInfoContentLeft = this.layoutInfo.map(l => l.contentLeft); - public readonly layoutInfoDecorationsLeft = this.layoutInfo.map(l => l.decorationsLeft); - public readonly layoutInfoWidth = this.layoutInfo.map(l => l.width); - public readonly layoutInfoMinimap = this.layoutInfo.map(l => l.minimap); - public readonly layoutInfoVerticalScrollbarWidth = this.layoutInfo.map(l => l.verticalScrollbarWidth); + public readonly layoutInfo: IObservable; + public readonly layoutInfoContentLeft: IObservable; + public readonly layoutInfoDecorationsLeft: IObservable; + public readonly layoutInfoWidth: IObservable; + public readonly layoutInfoMinimap: IObservable; + public readonly layoutInfoVerticalScrollbarWidth: IObservable; - public readonly contentWidth = observableFromEvent(this.editor.onDidContentSizeChange, () => this.editor.getContentWidth()); + public readonly contentWidth: IObservable; public getOption(id: T): IObservable> { return observableFromEvent(this, cb => this.editor.onDidChangeConfiguration(e => { diff --git a/src/vs/editor/browser/view/viewLayer.ts b/src/vs/editor/browser/view/viewLayer.ts index 4058205be2feb..aab7abca3b178 100644 --- a/src/vs/editor/browser/view/viewLayer.ts +++ b/src/vs/editor/browser/view/viewLayer.ts @@ -252,11 +252,12 @@ export class RenderedLinesCollection { export class VisibleLinesCollection { public readonly domNode: FastDomNode = this._createDomNode(); - private readonly _linesCollection: RenderedLinesCollection = new RenderedLinesCollection(this._lineFactory); + private readonly _linesCollection: RenderedLinesCollection; constructor( private readonly _lineFactory: ILineFactory ) { + this._linesCollection = new RenderedLinesCollection(this._lineFactory); } private _createDomNode(): FastDomNode { diff --git a/src/vs/editor/browser/widget/codeEditor/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditor/codeEditorWidget.ts index 7e325a7f888bd..f7517c1c2eb57 100644 --- a/src/vs/editor/browser/widget/codeEditor/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditor/codeEditorWidget.ts @@ -2029,11 +2029,11 @@ const enum BooleanEventValue { } export class BooleanEventEmitter extends Disposable { - private readonly _onDidChangeToTrue: Emitter = this._register(new Emitter(this._emitterOptions)); - public readonly onDidChangeToTrue: Event = this._onDidChangeToTrue.event; + private readonly _onDidChangeToTrue: Emitter; + public readonly onDidChangeToTrue: Event; - private readonly _onDidChangeToFalse: Emitter = this._register(new Emitter(this._emitterOptions)); - public readonly onDidChangeToFalse: Event = this._onDidChangeToFalse.event; + private readonly _onDidChangeToFalse: Emitter; + public readonly onDidChangeToFalse: Event; private _value: BooleanEventValue; @@ -2041,6 +2041,12 @@ export class BooleanEventEmitter extends Disposable { private readonly _emitterOptions: EmitterOptions ) { super(); + this._onDidChangeToTrue = this._register(new Emitter(this._emitterOptions)); + this.onDidChangeToTrue = this._onDidChangeToTrue.event; + + this._onDidChangeToFalse = this._register(new Emitter(this._emitterOptions)); + this.onDidChangeToFalse = this._onDidChangeToFalse.event; + this._value = BooleanEventValue.NotSet; } diff --git a/src/vs/editor/browser/widget/diffEditor/components/diffEditorEditors.ts b/src/vs/editor/browser/widget/diffEditor/components/diffEditorEditors.ts index 638c9fe8bd5b8..6f949777966ca 100644 --- a/src/vs/editor/browser/widget/diffEditor/components/diffEditorEditors.ts +++ b/src/vs/editor/browser/widget/diffEditor/components/diffEditorEditors.ts @@ -5,44 +5,46 @@ import { Emitter } from '../../../../../base/common/event.js'; import { Disposable } from '../../../../../base/common/lifecycle.js'; -import { IReader, autorunHandleChanges, derived, derivedOpts, observableFromEvent } from '../../../../../base/common/observable.js'; +import { IObservable, IReader, autorunHandleChanges, derived, derivedOpts, observableFromEvent } from '../../../../../base/common/observable.js'; import { IEditorConstructionOptions } from '../../../config/editorConfiguration.js'; import { IDiffEditorConstructionOptions } from '../../../editorBrowser.js'; -import { observableCodeEditor } from '../../../observableCodeEditor.js'; +import { ObservableCodeEditor, observableCodeEditor } from '../../../observableCodeEditor.js'; import { CodeEditorWidget, ICodeEditorWidgetOptions } from '../../codeEditor/codeEditorWidget.js'; import { IDiffCodeEditorWidgetOptions } from '../diffEditorWidget.js'; import { OverviewRulerFeature } from '../features/overviewRulerFeature.js'; import { EditorOptions, IEditorOptions } from '../../../../common/config/editorOptions.js'; import { Position } from '../../../../common/core/position.js'; +import { Selection } from '../../../../common/core/selection.js'; import { IContentSizeChangedEvent } from '../../../../common/editorCommon.js'; import { localize } from '../../../../../nls.js'; import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; import { IKeybindingService } from '../../../../../platform/keybinding/common/keybinding.js'; import { DiffEditorOptions } from '../diffEditorOptions.js'; import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js'; +import { ITextModel } from '../../../../common/model.js'; export class DiffEditorEditors extends Disposable { - public readonly original = this._register(this._createLeftHandSideEditor(this._options.editorOptions.get(), this._argCodeEditorWidgetOptions.originalEditor || {})); - public readonly modified = this._register(this._createRightHandSideEditor(this._options.editorOptions.get(), this._argCodeEditorWidgetOptions.modifiedEditor || {})); + public readonly original: CodeEditorWidget; + public readonly modified: CodeEditorWidget; private readonly _onDidContentSizeChange = this._register(new Emitter()); public get onDidContentSizeChange() { return this._onDidContentSizeChange.event; } - public readonly modifiedScrollTop = observableFromEvent(this, this.modified.onDidScrollChange, () => /** @description modified.getScrollTop */ this.modified.getScrollTop()); - public readonly modifiedScrollHeight = observableFromEvent(this, this.modified.onDidScrollChange, () => /** @description modified.getScrollHeight */ this.modified.getScrollHeight()); + public readonly modifiedScrollTop: IObservable; + public readonly modifiedScrollHeight: IObservable; - public readonly modifiedObs = observableCodeEditor(this.modified); - public readonly originalObs = observableCodeEditor(this.original); + public readonly modifiedObs: ObservableCodeEditor; + public readonly originalObs: ObservableCodeEditor; - public readonly modifiedModel = this.modifiedObs.model; + public readonly modifiedModel: IObservable; - public readonly modifiedSelections = observableFromEvent(this, this.modified.onDidChangeCursorSelection, () => this.modified.getSelections() ?? []); + public readonly modifiedSelections: IObservable; public readonly modifiedCursor = derivedOpts({ owner: this, equalsFn: Position.equals }, reader => this.modifiedSelections.read(reader)[0]?.getPosition() ?? new Position(1, 1)); - public readonly originalCursor = observableFromEvent(this, this.original.onDidChangeCursorPosition, () => this.original.getPosition() ?? new Position(1, 1)); + public readonly originalCursor: IObservable; - public readonly isOriginalFocused = observableCodeEditor(this.original).isFocused; - public readonly isModifiedFocused = observableCodeEditor(this.modified).isFocused; + public readonly isOriginalFocused: IObservable; + public readonly isModifiedFocused: IObservable; public readonly isFocused = derived(this, reader => this.isOriginalFocused.read(reader) || this.isModifiedFocused.read(reader)); @@ -58,6 +60,24 @@ export class DiffEditorEditors extends Disposable { ) { super(); + this.original = this._register(this._createLeftHandSideEditor(this._options.editorOptions.get(), this._argCodeEditorWidgetOptions.originalEditor || {})); + this.modified = this._register(this._createRightHandSideEditor(this._options.editorOptions.get(), this._argCodeEditorWidgetOptions.modifiedEditor || {})); + + this.modifiedScrollTop = observableFromEvent(this, this.modified.onDidScrollChange, () => /** @description modified.getScrollTop */ this.modified.getScrollTop()); + this.modifiedScrollHeight = observableFromEvent(this, this.modified.onDidScrollChange, () => /** @description modified.getScrollHeight */ this.modified.getScrollHeight()); + + this.modifiedObs = observableCodeEditor(this.modified); + this.originalObs = observableCodeEditor(this.original); + + this.modifiedModel = this.modifiedObs.model; + + this.modifiedSelections = observableFromEvent(this, this.modified.onDidChangeCursorSelection, () => this.modified.getSelections() ?? []); + + this.originalCursor = observableFromEvent(this, this.original.onDidChangeCursorPosition, () => this.original.getPosition() ?? new Position(1, 1)); + + this.isOriginalFocused = observableCodeEditor(this.original).isFocused; + this.isModifiedFocused = observableCodeEditor(this.modified).isFocused; + this._argCodeEditorWidgetOptions = null as any; this._register(autorunHandleChanges({ diff --git a/src/vs/editor/browser/widget/diffEditor/components/diffEditorSash.ts b/src/vs/editor/browser/widget/diffEditor/components/diffEditorSash.ts index 468e6323c7f60..1483d1a47ff72 100644 --- a/src/vs/editor/browser/widget/diffEditor/components/diffEditorSash.ts +++ b/src/vs/editor/browser/widget/diffEditor/components/diffEditorSash.ts @@ -50,11 +50,7 @@ export class SashLayout { } export class DiffEditorSash extends Disposable { - private readonly _sash = this._register(new Sash(this._domNode, { - getVerticalSashTop: (_sash: Sash): number => 0, - getVerticalSashLeft: (_sash: Sash): number => this.sashLeft.get(), - getVerticalSashHeight: (_sash: Sash): number => this._dimensions.height.get(), - }, { orientation: Orientation.VERTICAL })); + private readonly _sash: Sash; private _startSashPosition: number | undefined = undefined; @@ -68,6 +64,12 @@ export class DiffEditorSash extends Disposable { ) { super(); + this._sash = this._register(new Sash(this._domNode, { + getVerticalSashTop: (_sash: Sash): number => 0, + getVerticalSashLeft: (_sash: Sash): number => this.sashLeft.get(), + getVerticalSashHeight: (_sash: Sash): number => this._dimensions.height.get(), + }, { orientation: Orientation.VERTICAL })); + this._register(this._sash.onDidStart(() => { this._startSashPosition = this.sashLeft.get(); })); diff --git a/src/vs/editor/browser/widget/diffEditor/components/diffEditorViewZones/diffEditorViewZones.ts b/src/vs/editor/browser/widget/diffEditor/components/diffEditorViewZones/diffEditorViewZones.ts index 634939aacee81..09604b0a49649 100644 --- a/src/vs/editor/browser/widget/diffEditor/components/diffEditorViewZones/diffEditorViewZones.ts +++ b/src/vs/editor/browser/widget/diffEditor/components/diffEditorViewZones/diffEditorViewZones.ts @@ -43,12 +43,12 @@ export class DiffEditorViewZones extends Disposable { private readonly _originalTopPadding = observableValue(this, 0); private readonly _originalScrollTop: IObservable; private readonly _originalScrollOffset = observableValue(this, 0); - private readonly _originalScrollOffsetAnimated = animatedObservable(this._targetWindow, this._originalScrollOffset, this._store); + private readonly _originalScrollOffsetAnimated: IObservable; private readonly _modifiedTopPadding = observableValue(this, 0); private readonly _modifiedScrollTop: IObservable; private readonly _modifiedScrollOffset = observableValue(this, 0); - private readonly _modifiedScrollOffsetAnimated = animatedObservable(this._targetWindow, this._modifiedScrollOffset, this._store); + private readonly _modifiedScrollOffsetAnimated: IObservable; public readonly viewZones: IObservable<{ orig: IObservableViewZone[]; mod: IObservableViewZone[] }>; @@ -66,6 +66,10 @@ export class DiffEditorViewZones extends Disposable { ) { super(); + this._originalScrollOffsetAnimated = animatedObservable(this._targetWindow, this._originalScrollOffset, this._store); + + this._modifiedScrollOffsetAnimated = animatedObservable(this._targetWindow, this._modifiedScrollOffset, this._store); + const state = observableValue('invalidateAlignmentsState', 0); const updateImmediately = this._register(new RunOnceScheduler(() => { diff --git a/src/vs/editor/browser/widget/diffEditor/diffEditorOptions.ts b/src/vs/editor/browser/widget/diffEditor/diffEditorOptions.ts index 3d2e483ca1543..fd7bfeb23fa1d 100644 --- a/src/vs/editor/browser/widget/diffEditor/diffEditorOptions.ts +++ b/src/vs/editor/browser/widget/diffEditor/diffEditorOptions.ts @@ -19,7 +19,7 @@ export class DiffEditorOptions { private readonly _diffEditorWidth = observableValue(this, 0); - private readonly _screenReaderMode = observableFromEvent(this, this._accessibilityService.onDidChangeScreenReaderOptimized, () => this._accessibilityService.isScreenReaderOptimized()); + private readonly _screenReaderMode: IObservable; constructor( options: Readonly, @@ -27,6 +27,8 @@ export class DiffEditorOptions { ) { const optionsCopy = { ...options, ...validateDiffEditorOptions(options, diffEditorDefaultOptions) }; this._options = observableValue(this, optionsCopy); + + this._screenReaderMode = observableFromEvent(this, this._accessibilityService.onDidChangeScreenReaderOptimized, () => this._accessibilityService.isScreenReaderOptimized()); } public readonly couldShowInlineViewBecauseOfSize = derived(this, reader => diff --git a/src/vs/editor/browser/widget/diffEditor/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditor/diffEditorWidget.ts index 046f825dfe887..fc9c2de293c19 100644 --- a/src/vs/editor/browser/widget/diffEditor/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditor/diffEditorWidget.ts @@ -11,7 +11,7 @@ import { readHotReloadableExport } from '../../../../base/common/hotReloadHelper import { toDisposable } from '../../../../base/common/lifecycle.js'; import { IObservable, ITransaction, autorun, autorunWithStore, derived, derivedDisposable, disposableObservableValue, observableFromEvent, observableValue, recomputeInitiallyAndOnChange, subtransaction, transaction } from '../../../../base/common/observable.js'; import { AccessibilitySignal, IAccessibilitySignalService } from '../../../../platform/accessibilitySignal/browser/accessibilitySignalService.js'; -import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; +import { IContextKeyService, IScopedContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; import { ServiceCollection } from '../../../../platform/instantiation/common/serviceCollection.js'; import { bindContextKey } from '../../../../platform/observable/common/platformObservableUtils.js'; @@ -67,10 +67,8 @@ export class DiffEditorWidget extends DelegatingEditor implements IDiffEditor { public get onDidContentSizeChange() { return this._editors.onDidContentSizeChange; } - private readonly _contextKeyService = this._register(this._parentContextKeyService.createScoped(this._domElement)); - private readonly _instantiationService = this._register(this._parentInstantiationService.createChild( - new ServiceCollection([IContextKeyService, this._contextKeyService]) - )); + private readonly _contextKeyService: IScopedContextKeyService; + private readonly _instantiationService: IInstantiationService; private readonly _rootSizeObserver: ObservableElementSizeObserver; @@ -108,6 +106,11 @@ export class DiffEditorWidget extends DelegatingEditor implements IDiffEditor { super(); codeEditorService.willCreateDiffEditor(); + this._contextKeyService = this._register(this._parentContextKeyService.createScoped(this._domElement)); + this._instantiationService = this._register(this._parentInstantiationService.createChild( + new ServiceCollection([IContextKeyService, this._contextKeyService]) + )); + this._contextKeyService.createKey('isInDiffEditor', true); this._domElement.appendChild(this.elements.root); diff --git a/src/vs/editor/browser/widget/diffEditor/features/gutterFeature.ts b/src/vs/editor/browser/widget/diffEditor/features/gutterFeature.ts index a9aaeab304d54..31761011372f8 100644 --- a/src/vs/editor/browser/widget/diffEditor/features/gutterFeature.ts +++ b/src/vs/editor/browser/widget/diffEditor/features/gutterFeature.ts @@ -12,7 +12,7 @@ import { Disposable } from '../../../../../base/common/lifecycle.js'; import { IObservable, autorun, autorunWithStore, derived, derivedDisposable, derivedWithSetter, observableFromEvent, observableValue } from '../../../../../base/common/observable.js'; import { URI } from '../../../../../base/common/uri.js'; import { HiddenItemStrategy, MenuWorkbenchToolBar } from '../../../../../platform/actions/browser/toolbar.js'; -import { IMenuService, MenuId } from '../../../../../platform/actions/common/actions.js'; +import { IMenu, IMenuService, MenuId, MenuItemAction, SubmenuItemAction } from '../../../../../platform/actions/common/actions.js'; import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js'; import { WorkbenchHoverDelegate } from '../../../../../platform/hover/browser/hover.js'; import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; @@ -35,9 +35,9 @@ const emptyArr: never[] = []; const width = 35; export class DiffEditorGutter extends Disposable { - private readonly _menu = this._register(this._menuService.createMenu(MenuId.DiffEditorHunkToolbar, this._contextKeyService)); - private readonly _actions = observableFromEvent(this, this._menu.onDidChange, () => this._menu.getActions()); - private readonly _hasActions = this._actions.map(a => a.length > 0); + private readonly _menu: IMenu; + private readonly _actions: IObservable<[string, Array][]>; + private readonly _hasActions: IObservable; private readonly _showSash = derived(this, reader => this._options.renderSideBySide.read(reader) && this._hasActions.read(reader)); public readonly width = derived(this, reader => this._hasActions.read(reader) ? width : 0); @@ -57,6 +57,10 @@ export class DiffEditorGutter extends Disposable { ) { super(); + this._menu = this._register(this._menuService.createMenu(MenuId.DiffEditorHunkToolbar, this._contextKeyService)); + this._actions = observableFromEvent(this, this._menu.onDidChange, () => this._menu.getActions()); + this._hasActions = this._actions.map(a => a.length > 0); + this._register(prependRemoveOnDispose(diffEditorRoot, this.elements.root)); this._register(addDisposableListener(this.elements.root, 'click', () => { @@ -202,8 +206,8 @@ class DiffToolBar extends Disposable implements IGutterItemView { h('div.buttons@buttons', {}, []), ]); - private readonly _showAlways = this._item.map(this, item => item.showAlways); - private readonly _menuId = this._item.map(this, item => item.menuId); + private readonly _showAlways: IObservable; + private readonly _menuId: IObservable; private readonly _isSmall = observableValue(this, false); @@ -215,6 +219,9 @@ class DiffToolBar extends Disposable implements IGutterItemView { ) { super(); + this._showAlways = this._item.map(this, item => item.showAlways); + this._menuId = this._item.map(this, item => item.menuId); + const hoverDelegate = this._register(instantiationService.createInstance( WorkbenchHoverDelegate, 'element', diff --git a/src/vs/editor/browser/widget/diffEditor/features/movedBlocksLinesFeature.ts b/src/vs/editor/browser/widget/diffEditor/features/movedBlocksLinesFeature.ts index a06947da06d2f..ce33553aa3f75 100644 --- a/src/vs/editor/browser/widget/diffEditor/features/movedBlocksLinesFeature.ts +++ b/src/vs/editor/browser/widget/diffEditor/features/movedBlocksLinesFeature.ts @@ -26,9 +26,9 @@ export class MovedBlocksLinesFeature extends Disposable { public static readonly movedCodeBlockPadding = 4; private readonly _element: SVGElement; - private readonly _originalScrollTop = observableFromEvent(this, this._editors.original.onDidScrollChange, () => this._editors.original.getScrollTop()); - private readonly _modifiedScrollTop = observableFromEvent(this, this._editors.modified.onDidScrollChange, () => this._editors.modified.getScrollTop()); - private readonly _viewZonesChanged = observableSignalFromEvent('onDidChangeViewZones', this._editors.modified.onDidChangeViewZones); + private readonly _originalScrollTop: IObservable; + private readonly _modifiedScrollTop: IObservable; + private readonly _viewZonesChanged: IObservable; public readonly width = observableValue(this, 0); @@ -41,6 +41,13 @@ export class MovedBlocksLinesFeature extends Disposable { ) { super(); + this._originalScrollTop = observableFromEvent(this, this._editors.original.onDidScrollChange, () => this._editors.original.getScrollTop()); + this._modifiedScrollTop = observableFromEvent(this, this._editors.modified.onDidScrollChange, () => this._editors.modified.getScrollTop()); + this._viewZonesChanged = observableSignalFromEvent('onDidChangeViewZones', this._editors.modified.onDidChangeViewZones); + + this._modifiedViewZonesChangedSignal = observableSignalFromEvent('modified.onDidChangeViewZones', this._editors.modified.onDidChangeViewZones); + this._originalViewZonesChangedSignal = observableSignalFromEvent('original.onDidChangeViewZones', this._editors.original.onDidChangeViewZones); + this._element = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); this._element.setAttribute('class', 'moved-blocks-lines'); this._rootElement.appendChild(this._element); @@ -133,8 +140,8 @@ export class MovedBlocksLinesFeature extends Disposable { })); } - private readonly _modifiedViewZonesChangedSignal = observableSignalFromEvent('modified.onDidChangeViewZones', this._editors.modified.onDidChangeViewZones); - private readonly _originalViewZonesChangedSignal = observableSignalFromEvent('original.onDidChangeViewZones', this._editors.original.onDidChangeViewZones); + private readonly _modifiedViewZonesChangedSignal: IObservable; + private readonly _originalViewZonesChangedSignal: IObservable; private readonly _state = derivedWithStore(this, (reader, store) => { /** @description state */ diff --git a/src/vs/editor/browser/widget/diffEditor/features/revertButtonsFeature.ts b/src/vs/editor/browser/widget/diffEditor/features/revertButtonsFeature.ts index 2d94b6e065744..3cf076b23bfdc 100644 --- a/src/vs/editor/browser/widget/diffEditor/features/revertButtonsFeature.ts +++ b/src/vs/editor/browser/widget/diffEditor/features/revertButtonsFeature.ts @@ -111,13 +111,7 @@ export class RevertButton extends Disposable implements IGlyphMarginWidget { getId(): string { return this._id; } - private readonly _domNode = h('div.revertButton', { - title: this._revertSelection - ? localize('revertSelectedChanges', 'Revert Selected Changes') - : localize('revertChange', 'Revert Change') - }, - [renderIcon(Codicon.arrowRight)] - ).root; + private readonly _domNode: HTMLDivElement; constructor( private readonly _lineNumber: number, @@ -127,6 +121,13 @@ export class RevertButton extends Disposable implements IGlyphMarginWidget { ) { super(); + this._domNode = h('div.revertButton', { + title: this._revertSelection + ? localize('revertSelectedChanges', 'Revert Selected Changes') + : localize('revertChange', 'Revert Change') + }, + [renderIcon(Codicon.arrowRight)] + ).root; this._register(addDisposableListener(this._domNode, EventType.MOUSE_DOWN, e => { // don't prevent context menu from showing up diff --git a/src/vs/editor/browser/widget/diffEditor/utils.ts b/src/vs/editor/browser/widget/diffEditor/utils.ts index 47faca2f8cf2a..2b1ea9db6a847 100644 --- a/src/vs/editor/browser/widget/diffEditor/utils.ts +++ b/src/vs/editor/browser/widget/diffEditor/utils.ts @@ -231,12 +231,13 @@ export class PlaceholderViewZone implements IObservableViewZone { public get afterLineNumber(): number { return this._afterLineNumber.get(); } - public readonly onChange?: IObservable = this._afterLineNumber; + public readonly onChange?: IObservable; constructor( private readonly _afterLineNumber: IObservable, public readonly heightInPx: number, ) { + this.onChange = this._afterLineNumber; } onDomNodeTop = (top: number) => { diff --git a/src/vs/editor/browser/widget/diffEditor/utils/editorGutter.ts b/src/vs/editor/browser/widget/diffEditor/utils/editorGutter.ts index bc149ec17ead7..690e63c8d6390 100644 --- a/src/vs/editor/browser/widget/diffEditor/utils/editorGutter.ts +++ b/src/vs/editor/browser/widget/diffEditor/utils/editorGutter.ts @@ -11,18 +11,12 @@ import { LineRange } from '../../../../common/core/lineRange.js'; import { OffsetRange } from '../../../../common/core/offsetRange.js'; export class EditorGutter extends Disposable { - private readonly scrollTop = observableFromEvent(this, - this._editor.onDidScrollChange, - (e) => /** @description editor.onDidScrollChange */ this._editor.getScrollTop() - ); - private readonly isScrollTopZero = this.scrollTop.map((scrollTop) => /** @description isScrollTopZero */ scrollTop === 0); - private readonly modelAttached = observableFromEvent(this, - this._editor.onDidChangeModel, - (e) => /** @description editor.onDidChangeModel */ this._editor.hasModel() - ); - - private readonly editorOnDidChangeViewZones = observableSignalFromEvent('onDidChangeViewZones', this._editor.onDidChangeViewZones); - private readonly editorOnDidContentSizeChange = observableSignalFromEvent('onDidContentSizeChange', this._editor.onDidContentSizeChange); + private readonly scrollTop: IObservable; + private readonly isScrollTopZero: IObservable; + private readonly modelAttached: IObservable; + + private readonly editorOnDidChangeViewZones: IObservable; + private readonly editorOnDidContentSizeChange: IObservable; private readonly domNodeSizeChanged = observableSignal('domNodeSizeChanged'); constructor( @@ -31,6 +25,20 @@ export class EditorGutter extends D private readonly itemProvider: IGutterItemProvider ) { super(); + + this.scrollTop = observableFromEvent(this, + this._editor.onDidScrollChange, + (e) => /** @description editor.onDidScrollChange */ this._editor.getScrollTop() + ); + this.isScrollTopZero = this.scrollTop.map((scrollTop) => /** @description isScrollTopZero */ scrollTop === 0); + this.modelAttached = observableFromEvent(this, + this._editor.onDidChangeModel, + (e) => /** @description editor.onDidChangeModel */ this._editor.hasModel() + ); + + this.editorOnDidChangeViewZones = observableSignalFromEvent('onDidChangeViewZones', this._editor.onDidChangeViewZones); + this.editorOnDidContentSizeChange = observableSignalFromEvent('onDidContentSizeChange', this._editor.onDidContentSizeChange); + this._domNode.className = 'gutter monaco-editor'; const scrollDecoration = this._domNode.appendChild( h('div.scroll-decoration', { role: 'presentation', ariaHidden: 'true', style: { width: '100%' } }) diff --git a/src/vs/editor/browser/widget/multiDiffEditor/diffEditorItemTemplate.ts b/src/vs/editor/browser/widget/multiDiffEditor/diffEditorItemTemplate.ts index 48ac35815d4c9..3291c3d0f50c5 100644 --- a/src/vs/editor/browser/widget/multiDiffEditor/diffEditorItemTemplate.ts +++ b/src/vs/editor/browser/widget/multiDiffEditor/diffEditorItemTemplate.ts @@ -6,7 +6,7 @@ import { h } from '../../../../base/browser/dom.js'; import { Button } from '../../../../base/browser/ui/button/button.js'; import { Codicon } from '../../../../base/common/codicons.js'; import { Disposable, DisposableStore } from '../../../../base/common/lifecycle.js'; -import { autorun, derived, globalTransaction, observableValue } from '../../../../base/common/observable.js'; +import { IObservable, autorun, derived, globalTransaction, observableValue } from '../../../../base/common/observable.js'; import { createActionViewItem } from '../../../../platform/actions/browser/menuEntryActionViewItem.js'; import { MenuWorkbenchToolBar } from '../../../../platform/actions/browser/toolbar.js'; import { MenuId } from '../../../../platform/actions/common/actions.js'; @@ -20,7 +20,7 @@ import { DiffEditorWidget } from '../diffEditor/diffEditorWidget.js'; import { DocumentDiffItemViewModel } from './multiDiffEditorViewModel.js'; import { IObjectData, IPooledObject } from './objectPool.js'; import { ActionRunnerWithContext } from './utils.js'; -import { IWorkbenchUIElementFactory } from './workbenchUIElementFactory.js'; +import { IResourceLabel, IWorkbenchUIElementFactory } from './workbenchUIElementFactory.js'; export class TemplateData implements IObjectData { constructor( @@ -78,21 +78,14 @@ export class DiffEditorItemTemplate extends Disposable implements IPooledObject< ]) ]) as Record; - public readonly editor = this._register(this._instantiationService.createInstance(DiffEditorWidget, this._elements.editor, { - overflowWidgetsDomNode: this._overflowWidgetsDomNode, - }, {})); + public readonly editor: DiffEditorWidget; - private readonly isModifedFocused = observableCodeEditor(this.editor.getModifiedEditor()).isFocused; - private readonly isOriginalFocused = observableCodeEditor(this.editor.getOriginalEditor()).isFocused; - public readonly isFocused = derived(this, reader => this.isModifedFocused.read(reader) || this.isOriginalFocused.read(reader)); + private readonly isModifedFocused: IObservable; + private readonly isOriginalFocused: IObservable; + public readonly isFocused: IObservable; - private readonly _resourceLabel = this._workbenchUIElementFactory.createResourceLabel - ? this._register(this._workbenchUIElementFactory.createResourceLabel(this._elements.primaryPath)) - : undefined; - - private readonly _resourceLabel2 = this._workbenchUIElementFactory.createResourceLabel - ? this._register(this._workbenchUIElementFactory.createResourceLabel(this._elements.secondaryPath)) - : undefined; + private readonly _resourceLabel: IResourceLabel | undefined; + private readonly _resourceLabel2: IResourceLabel | undefined; private readonly _outerEditorHeight: number; private readonly _contextKeyService: IScopedContextKeyService; @@ -106,6 +99,21 @@ export class DiffEditorItemTemplate extends Disposable implements IPooledObject< ) { super(); + this.editor = this._register(this._instantiationService.createInstance(DiffEditorWidget, this._elements.editor, { + overflowWidgetsDomNode: this._overflowWidgetsDomNode, + }, {})); + + this.isModifedFocused = observableCodeEditor(this.editor.getModifiedEditor()).isFocused; + this.isOriginalFocused = observableCodeEditor(this.editor.getOriginalEditor()).isFocused; + this.isFocused = derived(this, reader => this.isModifedFocused.read(reader) || this.isOriginalFocused.read(reader)); + + this._resourceLabel = this._workbenchUIElementFactory.createResourceLabel + ? this._register(this._workbenchUIElementFactory.createResourceLabel(this._elements.primaryPath)) + : undefined; + this._resourceLabel2 = this._workbenchUIElementFactory.createResourceLabel + ? this._register(this._workbenchUIElementFactory.createResourceLabel(this._elements.secondaryPath)) + : undefined; + const btn = new Button(this._elements.collapseButton, {}); this._register(autorun(reader => { diff --git a/src/vs/editor/browser/widget/multiDiffEditor/multiDiffEditorViewModel.ts b/src/vs/editor/browser/widget/multiDiffEditor/multiDiffEditorViewModel.ts index 49c674d04779a..d72648a9a8ada 100644 --- a/src/vs/editor/browser/widget/multiDiffEditor/multiDiffEditorViewModel.ts +++ b/src/vs/editor/browser/widget/multiDiffEditor/multiDiffEditorViewModel.ts @@ -18,21 +18,13 @@ import { RefCounted } from '../diffEditor/utils.js'; import { IDocumentDiffItem, IMultiDiffEditorModel } from './model.js'; export class MultiDiffEditorViewModel extends Disposable { - private readonly _documents: IObservable[] | 'loading'> = observableFromValueWithChangeEvent(this.model, this.model.documents); + private readonly _documents: IObservable[] | 'loading'>; - private readonly _documentsArr = derived(this, reader => { - const result = this._documents.read(reader); - if (result === 'loading') { return []; } - return result; - }); + private readonly _documentsArr: IObservable[]>; public readonly isLoading = derived(this, reader => this._documents.read(reader) === 'loading'); - public readonly items: IObservable = mapObservableArrayCached( - this, - this._documentsArr, - (d, store) => store.add(this._instantiationService.createInstance(DocumentDiffItemViewModel, d, this)) - ).recomputeInitiallyAndOnChange(this._store); + public readonly items: IObservable; public readonly focusedDiffItem = derived(this, reader => this.items.read(reader).find(i => i.isFocused.read(reader))); public readonly activeDiffItem = derivedObservableWithWritableCache(this, @@ -70,6 +62,20 @@ export class MultiDiffEditorViewModel extends Disposable { private readonly _instantiationService: IInstantiationService, ) { super(); + + this._documents = observableFromValueWithChangeEvent(this.model, this.model.documents); + + this._documentsArr = derived(this, reader => { + const result = this._documents.read(reader); + if (result === 'loading') { return []; } + return result; + }); + + this.items = mapObservableArrayCached( + this, + this._documentsArr, + (d, store) => store.add(this._instantiationService.createInstance(DocumentDiffItemViewModel, d, this)) + ).recomputeInitiallyAndOnChange(this._store); } } diff --git a/src/vs/editor/browser/widget/multiDiffEditor/multiDiffEditorWidgetImpl.ts b/src/vs/editor/browser/widget/multiDiffEditor/multiDiffEditorWidgetImpl.ts index ec0bf3cf64ced..f5ae1727f9805 100644 --- a/src/vs/editor/browser/widget/multiDiffEditor/multiDiffEditorWidgetImpl.ts +++ b/src/vs/editor/browser/widget/multiDiffEditor/multiDiffEditorWidgetImpl.ts @@ -13,7 +13,7 @@ import { IObservable, IReader, ITransaction, autorun, autorunWithStore, derived, import { Scrollable, ScrollbarVisibility } from '../../../../base/common/scrollable.js'; import { URI } from '../../../../base/common/uri.js'; import { localize } from '../../../../nls.js'; -import { ContextKeyValue, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; +import { ContextKeyValue, IContextKeyService, IScopedContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; import { ITextEditorOptions } from '../../../../platform/editor/common/editor.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; import { ServiceCollection } from '../../../../platform/instantiation/common/serviceCollection.js'; @@ -60,7 +60,7 @@ export class MultiDiffEditorWidgetImpl extends Disposable { h('div.placeholder@placeholder', {}, [h('div')]), ]); - private readonly _sizeObserver = this._register(new ObservableElementSizeObserver(this._element, undefined)); + private readonly _sizeObserver: ObservableElementSizeObserver; private readonly _objectPool = this._register(new ObjectPool((data) => { const template = this._instantiationService.createInstance( @@ -113,10 +113,8 @@ export class MultiDiffEditorWidgetImpl extends Disposable { return viewItem.template.read(reader)?.editor; }); - private readonly _contextKeyService = this._register(this._parentContextKeyService.createScoped(this._element)); - private readonly _instantiationService = this._register(this._parentInstantiationService.createChild( - new ServiceCollection([IContextKeyService, this._contextKeyService]) - )); + private readonly _contextKeyService: IScopedContextKeyService; + private readonly _instantiationService: IInstantiationService; constructor( private readonly _element: HTMLElement, @@ -128,6 +126,13 @@ export class MultiDiffEditorWidgetImpl extends Disposable { ) { super(); + this._sizeObserver = this._register(new ObservableElementSizeObserver(this._element, undefined)); + + this._contextKeyService = this._register(this._parentContextKeyService.createScoped(this._element)); + this._instantiationService = this._register(this._parentInstantiationService.createChild( + new ServiceCollection([IContextKeyService, this._contextKeyService]) + )); + this._register(autorunWithStore((reader, store) => { const viewModel = this._viewModel.read(reader); if (viewModel && viewModel.contextKeys) { diff --git a/src/vs/editor/common/core/textEdit.ts b/src/vs/editor/common/core/textEdit.ts index 83baa3bff439e..75c0c303d785d 100644 --- a/src/vs/editor/common/core/textEdit.ts +++ b/src/vs/editor/common/core/textEdit.ts @@ -384,10 +384,12 @@ export class ArrayText extends LineBasedText { } export class StringText extends AbstractText { - private readonly _t = new PositionOffsetTransformer(this.value); + private readonly _t: PositionOffsetTransformer; constructor(public readonly value: string) { super(); + + this._t = new PositionOffsetTransformer(this.value); } getValueOfRange(range: Range): string { diff --git a/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/bracketPairsTree.ts b/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/bracketPairsTree.ts index 42a40e9979717..98c5f684940f0 100644 --- a/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/bracketPairsTree.ts +++ b/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/bracketPairsTree.ts @@ -40,7 +40,7 @@ export class BracketPairsTree extends Disposable { private astWithTokens: AstNode | undefined; private readonly denseKeyProvider = new DenseKeyProvider(); - private readonly brackets = new LanguageAgnosticBracketTokens(this.denseKeyProvider, this.getLanguageConfiguration); + private readonly brackets: LanguageAgnosticBracketTokens; public didLanguageChange(languageId: string): boolean { return this.brackets.didLanguageChange(languageId); @@ -56,6 +56,8 @@ export class BracketPairsTree extends Disposable { ) { super(); + this.brackets = new LanguageAgnosticBracketTokens(this.denseKeyProvider, this.getLanguageConfiguration); + if (!textModel.tokenization.hasTokens) { const brackets = this.brackets.getSingleLanguageBracketTokens(this.textModel.getLanguageId()); const tokenizer = new FastTokenizer(this.textModel.getValue(), brackets); diff --git a/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/tokenizer.ts b/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/tokenizer.ts index ae8cce61d564f..c82429176b117 100644 --- a/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/tokenizer.ts +++ b/src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/tokenizer.ts @@ -64,7 +64,7 @@ export class TextBufferTokenizer implements Tokenizer { private readonly textBufferLineCount: number; private readonly textBufferLastLineLength: number; - private readonly reader = new NonPeekableTextBufferTokenizer(this.textModel, this.bracketTokens); + private readonly reader: NonPeekableTextBufferTokenizer; constructor( private readonly textModel: ITokenizerSource, @@ -72,6 +72,8 @@ export class TextBufferTokenizer implements Tokenizer { ) { this.textBufferLineCount = textModel.getLineCount(); this.textBufferLastLineLength = textModel.getLineLength(this.textBufferLineCount); + + this.reader = new NonPeekableTextBufferTokenizer(this.textModel, this.bracketTokens); // rebuild here } private _offset: Length = lengthZero; diff --git a/src/vs/editor/common/model/textModelTokens.ts b/src/vs/editor/common/model/textModelTokens.ts index b3253f37b4dd6..5b5fb5e2cb719 100644 --- a/src/vs/editor/common/model/textModelTokens.ts +++ b/src/vs/editor/common/model/textModelTokens.ts @@ -25,7 +25,7 @@ const enum Constants { } export class TokenizerWithStateStore { - private readonly initialState = this.tokenizationSupport.getInitialState() as TState; + private readonly initialState: TState; public readonly store: TrackingTokenizationStateStore; @@ -33,6 +33,7 @@ export class TokenizerWithStateStore { lineCount: number, public readonly tokenizationSupport: ITokenizationSupport ) { + this.initialState = this.tokenizationSupport.getInitialState() as TState; this.store = new TrackingTokenizationStateStore(lineCount); } diff --git a/src/vs/editor/common/model/tokenizationTextModelPart.ts b/src/vs/editor/common/model/tokenizationTextModelPart.ts index 84dea7fdba62e..449b38257f98a 100644 --- a/src/vs/editor/common/model/tokenizationTextModelPart.ts +++ b/src/vs/editor/common/model/tokenizationTextModelPart.ts @@ -34,7 +34,7 @@ import { SparseTokensStore } from '../tokens/sparseTokensStore.js'; import { IInstantiationService } from '../../../platform/instantiation/common/instantiation.js'; export class TokenizationTextModelPart extends TextModelPart implements ITokenizationTextModelPart { - private readonly _semanticTokens: SparseTokensStore = new SparseTokensStore(this._languageService.languageIdCodec); + private readonly _semanticTokens: SparseTokensStore; private readonly _onDidChangeLanguage: Emitter = this._register(new Emitter()); public readonly onDidChangeLanguage: Event = this._onDidChangeLanguage.event; @@ -59,6 +59,8 @@ export class TokenizationTextModelPart extends TextModelPart implements ITokeniz ) { super(); + this._semanticTokens = new SparseTokensStore(this._languageService.languageIdCodec); + // We just look at registry changes to determine whether to use tree sitter. // This means that removing a language from the setting will not cause a switch to textmate and will require a reload. // Adding a language to the setting will not need a reload, however. diff --git a/src/vs/editor/contrib/colorPicker/browser/colorDetector.ts b/src/vs/editor/contrib/colorPicker/browser/colorDetector.ts index 3a00c1d8f96d1..c31db41b917ea 100644 --- a/src/vs/editor/contrib/colorPicker/browser/colorDetector.ts +++ b/src/vs/editor/contrib/colorPicker/browser/colorDetector.ts @@ -15,7 +15,7 @@ import { DynamicCssRules } from '../../../browser/editorDom.js'; import { EditorOption } from '../../../common/config/editorOptions.js'; import { Position } from '../../../common/core/position.js'; import { Range } from '../../../common/core/range.js'; -import { IEditorContribution } from '../../../common/editorCommon.js'; +import { IEditorContribution, IEditorDecorationsCollection } from '../../../common/editorCommon.js'; import { IModelDecoration, IModelDeltaDecoration } from '../../../common/model.js'; import { ModelDecorationOptions } from '../../../common/model/textModel.js'; import { IFeatureDebounceInformation, ILanguageFeatureDebounceService } from '../../../common/services/languageFeatureDebounce.js'; @@ -40,12 +40,12 @@ export class ColorDetector extends Disposable implements IEditorContribution { private _decorationsIds: string[] = []; private _colorDatas = new Map(); - private readonly _colorDecoratorIds = this._editor.createDecorationsCollection(); + private readonly _colorDecoratorIds: IEditorDecorationsCollection; private _isColorDecoratorsEnabled: boolean; private _defaultColorDecoratorsEnablement: 'auto' | 'always' | 'never'; - private readonly _ruleFactory = new DynamicCssRules(this._editor); + private readonly _ruleFactory: DynamicCssRules; private readonly _decoratorLimitReporter = new DecoratorLimitReporter(); @@ -56,6 +56,10 @@ export class ColorDetector extends Disposable implements IEditorContribution { @ILanguageFeatureDebounceService languageFeatureDebounceService: ILanguageFeatureDebounceService, ) { super(); + + this._colorDecoratorIds = this._editor.createDecorationsCollection(); + this._ruleFactory = new DynamicCssRules(this._editor); + this._debounceInformation = languageFeatureDebounceService.for(_languageFeaturesService.colorProvider, 'Document Colors', { min: ColorDetector.RECOMPUTE_TIME }); this._register(_editor.onDidChangeModel(() => { this._isColorDecoratorsEnabled = this.isEnabled(); diff --git a/src/vs/editor/contrib/inlayHints/browser/inlayHintsController.ts b/src/vs/editor/contrib/inlayHints/browser/inlayHintsController.ts index 913e8075b3caf..f47ed5bf3e866 100644 --- a/src/vs/editor/contrib/inlayHints/browser/inlayHintsController.ts +++ b/src/vs/editor/contrib/inlayHints/browser/inlayHintsController.ts @@ -111,7 +111,7 @@ export class InlayHintsController implements IEditorContribution { private readonly _sessionDisposables = new DisposableStore(); private readonly _debounceInfo: IFeatureDebounceInformation; private readonly _decorationsMetadata = new Map(); - private readonly _ruleFactory = new DynamicCssRules(this._editor); + private readonly _ruleFactory: DynamicCssRules; private _cursorInfo?: { position: Position; notEarlierThan: number }; private _activeRenderMode = RenderMode.Normal; @@ -127,6 +127,7 @@ export class InlayHintsController implements IEditorContribution { @IInstantiationService private readonly _instaService: IInstantiationService, ) { this._debounceInfo = _featureDebounce.for(_languageFeaturesService.inlayHintsProvider, 'InlayHint', { min: 25 }); + this._ruleFactory = new DynamicCssRules(this._editor); this._disposables.add(_languageFeaturesService.inlayHintsProvider.onDidChange(() => this._update())); this._disposables.add(_editor.onDidChangeModel(() => this._update())); this._disposables.add(_editor.onDidChangeModelLanguage(() => this._update())); diff --git a/src/vs/editor/contrib/inlineCompletions/browser/controller/inlineCompletionsController.ts b/src/vs/editor/contrib/inlineCompletions/browser/controller/inlineCompletionsController.ts index bc5d723722fcc..e015160ecf4f6 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/controller/inlineCompletionsController.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/controller/inlineCompletionsController.ts @@ -8,7 +8,7 @@ import { timeout } from '../../../../../base/common/async.js'; import { cancelOnDispose } from '../../../../../base/common/cancellation.js'; import { createHotClass } from '../../../../../base/common/hotReloadHelpers.js'; import { Disposable, toDisposable } from '../../../../../base/common/lifecycle.js'; -import { ITransaction, autorun, derived, derivedDisposable, derivedObservableWithCache, observableFromEvent, observableSignal, observableValue, runOnChange, runOnChangeWithStore, transaction, waitForState } from '../../../../../base/common/observable.js'; +import { IObservable, ITransaction, autorun, derived, derivedDisposable, derivedObservableWithCache, observableFromEvent, observableSignal, observableValue, runOnChange, runOnChangeWithStore, transaction, waitForState } from '../../../../../base/common/observable.js'; import { isUndefined } from '../../../../../base/common/types.js'; import { localize } from '../../../../../nls.js'; import { IAccessibilityService } from '../../../../../platform/accessibility/common/accessibility.js'; @@ -21,13 +21,13 @@ import { IKeybindingService } from '../../../../../platform/keybinding/common/ke import { hotClassGetOriginalInstance } from '../../../../../platform/observable/common/wrapInHotClass.js'; import { CoreEditingCommands } from '../../../../browser/coreCommands.js'; import { ICodeEditor } from '../../../../browser/editorBrowser.js'; -import { observableCodeEditor } from '../../../../browser/observableCodeEditor.js'; +import { ObservableCodeEditor, observableCodeEditor } from '../../../../browser/observableCodeEditor.js'; import { getOuterEditor } from '../../../../browser/widget/codeEditor/embeddedCodeEditorWidget.js'; import { EditorOption } from '../../../../common/config/editorOptions.js'; import { Position } from '../../../../common/core/position.js'; import { Range } from '../../../../common/core/range.js'; import { CursorChangeReason } from '../../../../common/cursorEvents.js'; -import { ILanguageFeatureDebounceService } from '../../../../common/services/languageFeatureDebounce.js'; +import { IFeatureDebounceInformation, ILanguageFeatureDebounceService } from '../../../../common/services/languageFeatureDebounce.js'; import { ILanguageFeaturesService } from '../../../../common/services/languageFeatures.js'; import { InlineSuggestionHintsContentWidget } from '../hintsWidget/inlineCompletionsHintsWidget.js'; import { TextModelChangeRecorder } from '../model/changeRecorder.js'; @@ -59,28 +59,17 @@ export class InlineCompletionsController extends Disposable { return hotClassGetOriginalInstance(editor.getContribution(InlineCompletionsController.ID)); } - private readonly _editorObs = observableCodeEditor(this.editor); - private readonly _positions = derived(this, reader => this._editorObs.selections.read(reader)?.map(s => s.getEndPosition()) ?? [new Position(1, 1)]); - - private readonly _suggestWidgetAdapter = this._register(new ObservableSuggestWidgetAdapter( - this._editorObs, - item => this.model.get()?.handleSuggestAccepted(item), - () => this.model.get()?.selectedInlineCompletion.get()?.toSingleTextEdit(undefined), - )); - - private readonly _enabledInConfig = observableFromEvent(this, this.editor.onDidChangeConfiguration, () => this.editor.getOption(EditorOption.inlineSuggest).enabled); - private readonly _isScreenReaderEnabled = observableFromEvent(this, this._accessibilityService.onDidChangeScreenReaderOptimized, () => this._accessibilityService.isScreenReaderOptimized()); - private readonly _editorDictationInProgress = observableFromEvent(this, - this._contextKeyService.onDidChangeContext, - () => this._contextKeyService.getContext(this.editor.getDomNode()).getValue('editorDictation.inProgress') === true - ); - private readonly _enabled = derived(this, reader => this._enabledInConfig.read(reader) && (!this._isScreenReaderEnabled.read(reader) || !this._editorDictationInProgress.read(reader))); - - private readonly _debounceValue = this._debounceService.for( - this._languageFeaturesService.inlineCompletionsProvider, - 'InlineCompletionsDebounce', - { min: 50, max: 50 } - ); + private readonly _editorObs: ObservableCodeEditor; + private readonly _positions: IObservable; + + private readonly _suggestWidgetAdapter: ObservableSuggestWidgetAdapter; + + private readonly _enabledInConfig: IObservable; + private readonly _isScreenReaderEnabled: IObservable; + private readonly _editorDictationInProgress: IObservable; + private readonly _enabled: IObservable = derived(this, reader => this._enabledInConfig.read(reader) && (!this._isScreenReaderEnabled.read(reader) || !this._editorDictationInProgress.read(reader))); + + private readonly _debounceValue: IFeatureDebounceInformation; private readonly _focusIsInMenu = observableValue(this, false); private readonly _focusIsInEditorOrMenu = derived(this, reader => { @@ -99,29 +88,13 @@ export class InlineCompletionsController extends Disposable { return cursorPos.column <= indentMaxColumn; }); - public readonly model = derivedDisposable(this, reader => { - if (this._editorObs.isReadonly.read(reader)) { return undefined; } - const textModel = this._editorObs.model.read(reader); - if (!textModel) { return undefined; } - - const model: InlineCompletionsModel = this._instantiationService.createInstance( - InlineCompletionsModel, - textModel, - this._suggestWidgetAdapter.selectedItem, - this._editorObs.versionId, - this._positions, - this._debounceValue, - this._enabled, - this.editor, - ); - return model; - }).recomputeInitiallyAndOnChange(this._store); + public readonly model: IObservable; private readonly _playAccessibilitySignal = observableSignal(this); - private readonly _hideInlineEditOnSelectionChange = this._editorObs.getOption(EditorOption.inlineSuggest).map(val => true); + private readonly _hideInlineEditOnSelectionChange: IObservable; - protected readonly _view = this._register(this._instantiationService.createInstance(InlineCompletionsView, this.editor, this.model, this._focusIsInMenu)); + protected readonly _view: InlineCompletionsView; constructor( public readonly editor: ICodeEditor, @@ -137,6 +110,51 @@ export class InlineCompletionsController extends Disposable { ) { super(); + this._editorObs = observableCodeEditor(this.editor); + this._positions = derived(this, reader => this._editorObs.selections.read(reader)?.map(s => s.getEndPosition()) ?? [new Position(1, 1)]); + + this._suggestWidgetAdapter = this._register(new ObservableSuggestWidgetAdapter( + this._editorObs, + item => this.model.get()?.handleSuggestAccepted(item), + () => this.model.get()?.selectedInlineCompletion.get()?.toSingleTextEdit(undefined), + )); + + this._enabledInConfig = observableFromEvent(this, this.editor.onDidChangeConfiguration, () => this.editor.getOption(EditorOption.inlineSuggest).enabled); + this._isScreenReaderEnabled = observableFromEvent(this, this._accessibilityService.onDidChangeScreenReaderOptimized, () => this._accessibilityService.isScreenReaderOptimized()); + this._editorDictationInProgress = observableFromEvent(this, + this._contextKeyService.onDidChangeContext, + () => this._contextKeyService.getContext(this.editor.getDomNode()).getValue('editorDictation.inProgress') === true + ); + this._enabled = derived(this, reader => this._enabledInConfig.read(reader) && (!this._isScreenReaderEnabled.read(reader) || !this._editorDictationInProgress.read(reader))); + + this._debounceValue = this._debounceService.for( + this._languageFeaturesService.inlineCompletionsProvider, + 'InlineCompletionsDebounce', + { min: 50, max: 50 } + ); + + this.model = derivedDisposable(this, reader => { + if (this._editorObs.isReadonly.read(reader)) { return undefined; } + const textModel = this._editorObs.model.read(reader); + if (!textModel) { return undefined; } + + const model: InlineCompletionsModel = this._instantiationService.createInstance( + InlineCompletionsModel, + textModel, + this._suggestWidgetAdapter.selectedItem, + this._editorObs.versionId, + this._positions, + this._debounceValue, + this._enabled, + this.editor, + ); + return model; + }).recomputeInitiallyAndOnChange(this._store); + + this._hideInlineEditOnSelectionChange = this._editorObs.getOption(EditorOption.inlineSuggest).map(val => true); + + this._view = this._register(this._instantiationService.createInstance(InlineCompletionsView, this.editor, this.model, this._focusIsInMenu)); + InlineCompletionsController._instances.add(this); this._register(toDisposable(() => InlineCompletionsController._instances.delete(this))); diff --git a/src/vs/editor/contrib/inlineCompletions/browser/hintsWidget/inlineCompletionsHintsWidget.ts b/src/vs/editor/contrib/inlineCompletions/browser/hintsWidget/inlineCompletionsHintsWidget.ts index 0847159047028..807d6d77f8be1 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/hintsWidget/inlineCompletionsHintsWidget.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/hintsWidget/inlineCompletionsHintsWidget.ts @@ -19,7 +19,7 @@ import { ThemeIcon } from '../../../../../base/common/themables.js'; import { localize } from '../../../../../nls.js'; import { MenuEntryActionViewItem, getActionBarActions } from '../../../../../platform/actions/browser/menuEntryActionViewItem.js'; import { IMenuWorkbenchToolBarOptions, WorkbenchToolBar } from '../../../../../platform/actions/browser/toolbar.js'; -import { IMenuService, MenuId, MenuItemAction } from '../../../../../platform/actions/common/actions.js'; +import { IMenu, IMenuService, MenuId, MenuItemAction } from '../../../../../platform/actions/common/actions.js'; import { ICommandService } from '../../../../../platform/commands/common/commands.js'; import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js'; import { IContextMenuService } from '../../../../../platform/contextview/browser/contextView.js'; @@ -37,7 +37,7 @@ import { InlineCompletionsModel } from '../model/inlineCompletionsModel.js'; import './inlineCompletionsHintsWidget.css'; export class InlineCompletionsHintsWidget extends Disposable { - private readonly alwaysShowToolbar = observableFromEvent(this, this.editor.onDidChangeConfiguration, () => this.editor.getOption(EditorOption.inlineSuggest).showToolbar === 'always'); + private readonly alwaysShowToolbar: IObservable; private sessionPosition: Position | undefined = undefined; @@ -66,6 +66,8 @@ export class InlineCompletionsHintsWidget extends Disposable { ) { super(); + this.alwaysShowToolbar = observableFromEvent(this, this.editor.onDidChangeConfiguration, () => this.editor.getOption(EditorOption.inlineSuggest).showToolbar === 'always'); + this._register(autorunWithStore((reader, store) => { /** @description setup content widget */ const model = this.model.read(reader); @@ -150,10 +152,7 @@ export class InlineSuggestionHintsContentWidget extends Disposable implements IC this._warningMessageContentNode, ]).keepUpdated(this._store); - private readonly nodes = h('div.inlineSuggestionsHints', { className: this.withBorder ? 'monaco-hover monaco-hover-content' : '' }, [ - this._warningMessageNode.element, - h('div@toolBar'), - ]); + private readonly nodes: { toolBar: HTMLDivElement; root: HTMLDivElement }; private createCommandAction(commandId: string, label: string, iconClassName: string): Action { const action = new Action( @@ -179,10 +178,7 @@ export class InlineSuggestionHintsContentWidget extends Disposable implements IC private readonly toolBar: CustomizedMenuWorkbenchToolBar; // TODO@hediet: deprecate MenuId.InlineCompletionsActions - private readonly inlineCompletionsActionsMenus = this._register(this._menuService.createMenu( - MenuId.InlineCompletionsActions, - this._contextKeyService - )); + private readonly inlineCompletionsActionsMenus: IMenu; private readonly clearAvailableSuggestionCountLabelDebounced = this._register(new RunOnceScheduler(() => { this.availableSuggestionCountAction.label = ''; @@ -209,6 +205,16 @@ export class InlineSuggestionHintsContentWidget extends Disposable implements IC ) { super(); + this.nodes = h('div.inlineSuggestionsHints', { className: this.withBorder ? 'monaco-hover monaco-hover-content' : '' }, [ + this._warningMessageNode.element, + h('div@toolBar'), + ]); + + this.inlineCompletionsActionsMenus = this._register(this._menuService.createMenu( + MenuId.InlineCompletionsActions, + this._contextKeyService + )); + this._register(autorun(reader => { this._warningMessageContentNode.read(reader); this._warningMessageNode.readEffect(reader); @@ -356,7 +362,7 @@ class StatusBarViewItem extends MenuEntryActionViewItem { } export class CustomizedMenuWorkbenchToolBar extends WorkbenchToolBar { - private readonly menu = this._store.add(this.menuService.createMenu(this.menuId, this.contextKeyService, { emitEventsForSubmenuChanges: true })); + private readonly menu: IMenu; private additionalActions: IAction[] = []; private prependedPrimaryActions: IAction[] = []; private additionalPrimaryActions: IAction[] = []; @@ -374,6 +380,8 @@ export class CustomizedMenuWorkbenchToolBar extends WorkbenchToolBar { ) { super(container, { resetMenu: menuId, ...options2 }, menuService, contextKeyService, contextMenuService, keybindingService, commandService, telemetryService); + this.menu = this._store.add(this.menuService.createMenu(this.menuId, this.contextKeyService, { emitEventsForSubmenuChanges: true })); + this._store.add(this.menu.onDidChange(() => this.updateToolbar())); this.updateToolbar(); } diff --git a/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsAccessibleView.ts b/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsAccessibleView.ts index 0a4e864d2c67f..0320f516a9e9c 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsAccessibleView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsAccessibleView.ts @@ -44,11 +44,13 @@ class InlineCompletionsAccessibleViewContentProvider extends Disposable implemen private readonly _model: InlineCompletionsModel, ) { super(); + + this.options = { language: this._editor.getModel()?.getLanguageId() ?? undefined, type: AccessibleViewType.View }; } public readonly id = AccessibleViewProviderId.InlineCompletions; public readonly verbositySettingKey = 'accessibility.verbosity.inlineCompletions'; - public readonly options = { language: this._editor.getModel()?.getLanguageId() ?? undefined, type: AccessibleViewType.View }; + public readonly options: { language: string | undefined; type: AccessibleViewType }; public provideContent(): string { const state = this._model.inlineCompletionState.get(); diff --git a/src/vs/editor/contrib/inlineCompletions/browser/model/changeRecorder.ts b/src/vs/editor/contrib/inlineCompletions/browser/model/changeRecorder.ts index 2e91840d292bb..cb765cd42a8bb 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/model/changeRecorder.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/model/changeRecorder.ts @@ -11,15 +11,18 @@ import { CodeEditorWidget } from '../../../../browser/widget/codeEditor/codeEdit import { IRecordableEditorLogEntry, StructuredLogger } from './inlineCompletionsSource.js'; export class TextModelChangeRecorder extends Disposable { - private readonly _structuredLogger = this._register(this._instantiationService.createInstance(StructuredLogger.cast(), - 'editor.inlineSuggest.logChangeReason.commandId' - )); + private readonly _structuredLogger: StructuredLogger; constructor( private readonly _editor: ICodeEditor, @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { super(); + + this._structuredLogger = this._register(this._instantiationService.createInstance(StructuredLogger.cast(), + 'editor.inlineSuggest.logChangeReason.commandId' + )); + this._register(autorunWithStore((reader, store) => { if (!(this._editor instanceof CodeEditorWidget)) { return; } if (!this._structuredLogger.isEnabled.read(reader)) { return; } diff --git a/src/vs/editor/contrib/inlineCompletions/browser/model/ghostText.ts b/src/vs/editor/contrib/inlineCompletions/browser/model/ghostText.ts index 40411f027ef74..2ea2211e56182 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/model/ghostText.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/model/ghostText.ts @@ -78,12 +78,13 @@ export class GhostTextPart { readonly preview: boolean, private _inlineDecorations: InlineDecoration[] = [], ) { + this.lines = splitLines(this.text).map((line, i) => ({ + line, + lineDecorations: LineDecoration.filter(this._inlineDecorations, i + 1, 1, line.length + 1) + })); } - readonly lines: IGhostTextLine[] = splitLines(this.text).map((line, i) => ({ - line, - lineDecorations: LineDecoration.filter(this._inlineDecorations, i + 1, 1, line.length + 1) - })); + readonly lines: IGhostTextLine[]; equals(other: GhostTextPart): boolean { return this.column === other.column && @@ -96,22 +97,25 @@ export class GhostTextPart { } export class GhostTextReplacement { - public readonly parts: ReadonlyArray = [ - new GhostTextPart( - this.columnRange.endColumnExclusive, - this.text, - false - ), - ]; + public readonly parts: ReadonlyArray; constructor( readonly lineNumber: number, readonly columnRange: ColumnRange, readonly text: string, public readonly additionalReservedLineCount: number = 0, - ) { } + ) { + this.parts = [ + new GhostTextPart( + this.columnRange.endColumnExclusive, + this.text, + false + ), + ]; + this.newLines = splitLines(this.text); + } - readonly newLines = splitLines(this.text); + readonly newLines: string[]; renderForScreenReader(_lineText: string): string { return this.newLines.join('\n'); diff --git a/src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsModel.ts b/src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsModel.ts index efcbda1a33d9a..88397f456c276 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsModel.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsModel.ts @@ -14,7 +14,7 @@ import { IAccessibilityService } from '../../../../../platform/accessibility/com import { ICommandService } from '../../../../../platform/commands/common/commands.js'; import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; import { ICodeEditor } from '../../../../browser/editorBrowser.js'; -import { observableCodeEditor } from '../../../../browser/observableCodeEditor.js'; +import { ObservableCodeEditor, observableCodeEditor } from '../../../../browser/observableCodeEditor.js'; import { EditorOption } from '../../../../common/config/editorOptions.js'; import { CursorColumns } from '../../../../common/core/cursorColumns.js'; import { EditOperation } from '../../../../common/core/editOperation.js'; @@ -43,7 +43,7 @@ import { singleTextEditAugments, singleTextRemoveCommonPrefix } from './singleTe import { SuggestItemInfo } from './suggestWidgetAdapter.js'; export class InlineCompletionsModel extends Disposable { - private readonly _source = this._register(this._instantiationService.createInstance(InlineCompletionsSource, this.textModel, this._textModelVersionId, this._debounceValue)); + private readonly _source: InlineCompletionsSource; private readonly _isActive = observableValue(this, false); private readonly _onlyRequestInlineEditsSignal = observableSignal(this); private readonly _forceUpdateExplicitlySignal = observableSignal(this); @@ -56,13 +56,13 @@ export class InlineCompletionsModel extends Disposable { private _isAcceptingPartially = false; public get isAcceptingPartially() { return this._isAcceptingPartially; } - private readonly _editorObs = observableCodeEditor(this._editor); + private readonly _editorObs: ObservableCodeEditor; - private readonly _suggestPreviewEnabled = this._editorObs.getOption(EditorOption.suggest).map(v => v.preview); - private readonly _suggestPreviewMode = this._editorObs.getOption(EditorOption.suggest).map(v => v.previewMode); - private readonly _inlineSuggestMode = this._editorObs.getOption(EditorOption.inlineSuggest).map(v => v.mode); - private readonly _inlineEditsEnabled = this._editorObs.getOption(EditorOption.inlineSuggest).map(v => !!v.edits.enabled); - private readonly _inlineEditsShowCollapsed = this._editorObs.getOption(EditorOption.inlineSuggest).map(s => s.edits.showCollapsed); + private readonly _suggestPreviewEnabled: IObservable; + private readonly _suggestPreviewMode: IObservable<'prefix' | 'subword' | 'subwordSmart'>; + private readonly _inlineSuggestMode: IObservable<'prefix' | 'subword' | 'subwordSmart'>; + private readonly _inlineEditsEnabled: IObservable; + private readonly _inlineEditsShowCollapsed: IObservable; constructor( public readonly textModel: ITextModel, @@ -79,6 +79,18 @@ export class InlineCompletionsModel extends Disposable { ) { super(); + this._source = this._register(this._instantiationService.createInstance(InlineCompletionsSource, this.textModel, this._textModelVersionId, this._debounceValue)); + + this._editorObs = observableCodeEditor(this._editor); + + this._suggestPreviewEnabled = this._editorObs.getOption(EditorOption.suggest).map(v => v.preview); + this._suggestPreviewMode = this._editorObs.getOption(EditorOption.suggest).map(v => v.previewMode); + this._inlineSuggestMode = this._editorObs.getOption(EditorOption.inlineSuggest).map(v => v.mode); + this._inlineEditsEnabled = this._editorObs.getOption(EditorOption.inlineSuggest).map(v => !!v.edits.enabled); + this._inlineEditsShowCollapsed = this._editorObs.getOption(EditorOption.inlineSuggest).map(s => s.edits.showCollapsed); + + this.lastTriggerKind = this._source.inlineCompletions.map(this, v => v?.request.context.triggerKind); + this._register(recomputeInitiallyAndOnChange(this._fetchInlineCompletionsPromise)); let lastItem: InlineCompletionWithUpdatedRange | undefined = undefined; @@ -330,8 +342,7 @@ export class InlineCompletionsModel extends Disposable { r => this.selectedInlineCompletion.read(r)?.source.inlineCompletions.commands ?? [] ); - public readonly lastTriggerKind: IObservable - = this._source.inlineCompletions.map(this, v => v?.request.context.triggerKind); + public readonly lastTriggerKind: IObservable; public readonly inlineCompletionsCount = derived(this, reader => { if (this.lastTriggerKind.read(reader) === InlineCompletionTriggerKind.Explicit) { diff --git a/src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsSource.ts b/src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsSource.ts index d9d9f0e099122..3976fbf6ef799 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsSource.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/model/inlineCompletionsSource.ts @@ -42,14 +42,12 @@ export class InlineCompletionsSource extends Disposable { public readonly inlineCompletions = this._register(disposableObservableValue('inlineCompletions', undefined)); public readonly suggestWidgetInlineCompletions = this._register(disposableObservableValue('suggestWidgetInlineCompletions', undefined)); - private readonly _loggingEnabled = observableConfigValue('editor.inlineSuggest.logFetch', false, this._configurationService).recomputeInitiallyAndOnChange(this._store); + private readonly _loggingEnabled: IObservable; - private readonly _structuredFetchLogger = this._register(this._instantiationService.createInstance(StructuredLogger.cast< + private readonly _structuredFetchLogger: StructuredLogger< { kind: 'start'; requestId: number; context: unknown } & IRecordableEditorLogEntry | { kind: 'end'; error: any; durationMs: number; result: unknown; requestId: number } & IRecordableLogEntry - >(), - 'editor.inlineSuggest.logFetch.commandId' - )); + >; constructor( private readonly _textModel: ITextModel, @@ -63,6 +61,15 @@ export class InlineCompletionsSource extends Disposable { ) { super(); + this._loggingEnabled = observableConfigValue('editor.inlineSuggest.logFetch', false, this._configurationService).recomputeInitiallyAndOnChange(this._store); + + this._structuredFetchLogger = this._register(this._instantiationService.createInstance(StructuredLogger.cast< + { kind: 'start'; requestId: number; context: unknown } & IRecordableEditorLogEntry + | { kind: 'end'; error: any; durationMs: number; result: unknown; requestId: number } & IRecordableLogEntry + >(), + 'editor.inlineSuggest.logFetch.commandId' + )); + this._register(this._textModel.onDidChangeContent((e) => { this._updateOperation.clear(); })); @@ -308,11 +315,7 @@ export class UpToDateInlineCompletions implements IDisposable { } export class InlineCompletionWithUpdatedRange extends Disposable { - public readonly semanticId = JSON.stringify([ - this.inlineCompletion.filterText, - this.inlineCompletion.insertText, - this.inlineCompletion.range.getStartPosition().toString() - ]); + public readonly semanticId: string; public get forwardStable() { return this.source.inlineCompletions.enableForwardStability ?? false; @@ -347,6 +350,12 @@ export class InlineCompletionWithUpdatedRange extends Disposable { ) { super(); + this.semanticId = JSON.stringify([ + this.inlineCompletion.filterText, + this.inlineCompletion.insertText, + this.inlineCompletion.range.getStartPosition().toString() + ]); + this._updatedEdit = this._register(this._toUpdatedEdit(updatedRange ?? this.inlineCompletion.range, this.inlineCompletion.insertText)); } @@ -759,7 +768,7 @@ export class StructuredLogger extends Disposable return this as typeof StructuredLogger; } - private readonly _contextKeyValue = observableContextKey(this._contextKey, this._contextKeyService).recomputeInitiallyAndOnChange(this._store); + private readonly _contextKeyValue: IObservable; constructor( private readonly _contextKey: string, @@ -767,9 +776,13 @@ export class StructuredLogger extends Disposable @ICommandService private readonly _commandService: ICommandService, ) { super(); + + this._contextKeyValue = observableContextKey(this._contextKey, this._contextKeyService).recomputeInitiallyAndOnChange(this._store); + + this.isEnabled = this._contextKeyValue.map(v => v !== undefined); } - public readonly isEnabled = this._contextKeyValue.map(v => v !== undefined); + public readonly isEnabled: IObservable; public log(data: T): boolean { const commandId = this._contextKeyValue.get(); diff --git a/src/vs/editor/contrib/inlineCompletions/browser/model/suggestWidgetAdapter.ts b/src/vs/editor/contrib/inlineCompletions/browser/model/suggestWidgetAdapter.ts index 88df0a98a528e..5413b50ae3528 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/model/suggestWidgetAdapter.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/model/suggestWidgetAdapter.ts @@ -240,17 +240,7 @@ function suggestItemInfoEquals(a: SuggestItemInfo | undefined, b: SuggestItemInf } export class ObservableSuggestWidgetAdapter extends Disposable { - private readonly _suggestWidgetAdaptor = this._register(new SuggestWidgetAdaptor( - this._editorObs.editor, - () => { - this._editorObs.forceUpdate(); - return this._suggestControllerPreselector(); - }, - (item) => this._editorObs.forceUpdate(_tx => { - /** @description InlineCompletionsController.handleSuggestAccepted */ - this._handleSuggestAccepted(item); - }) - )); + private readonly _suggestWidgetAdaptor: SuggestWidgetAdaptor; public readonly selectedItem = observableFromEvent(this, cb => this._suggestWidgetAdaptor.onDidSelectedItemChange(() => { this._editorObs.forceUpdate(_tx => cb(undefined)); @@ -263,6 +253,18 @@ export class ObservableSuggestWidgetAdapter extends Disposable { private readonly _suggestControllerPreselector: () => SingleTextEdit | undefined, ) { super(); + + this._suggestWidgetAdaptor = this._register(new SuggestWidgetAdaptor( + this._editorObs.editor, + () => { + this._editorObs.forceUpdate(); + return this._suggestControllerPreselector(); + }, + (item) => this._editorObs.forceUpdate(_tx => { + /** @description InlineCompletionsController.handleSuggestAccepted */ + this._handleSuggestAccepted(item); + }) + )); } public stopForceRenderingAbove(): void { diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/ghostText/ghostTextView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/ghostText/ghostTextView.ts index fb04686f119f3..d84a01b6bd15c 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/ghostText/ghostTextView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/ghostText/ghostTextView.ts @@ -13,7 +13,7 @@ import { IObservable, autorun, autorunWithStore, constObservable, derived, obser import * as strings from '../../../../../../base/common/strings.js'; import { applyFontInfo } from '../../../../../browser/config/domFontInfo.js'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidgetPosition, IViewZoneChangeAccessor, MouseTargetType } from '../../../../../browser/editorBrowser.js'; -import { observableCodeEditor } from '../../../../../browser/observableCodeEditor.js'; +import { ObservableCodeEditor, observableCodeEditor } from '../../../../../browser/observableCodeEditor.js'; import { EditorFontLigatures, EditorOption, IComputedEditorOptions } from '../../../../../common/config/editorOptions.js'; import { OffsetEdit, SingleOffsetEdit } from '../../../../../common/core/offsetEdit.js'; import { Position } from '../../../../../common/core/position.js'; @@ -44,7 +44,7 @@ const GHOST_TEXT_CLASS_NAME = 'ghost-text'; export class GhostTextView extends Disposable { private readonly _isDisposed = observableValue(this, false); - private readonly _editorObs = observableCodeEditor(this._editor); + private readonly _editorObs: ObservableCodeEditor; public static hot = createHotClass(GhostTextView); private _warningState = derived(reader => { @@ -71,6 +71,33 @@ export class GhostTextView extends Disposable { ) { super(); + this._editorObs = observableCodeEditor(this._editor); + + this._useSyntaxHighlighting = this._options.map(o => o.syntaxHighlightingEnabled); + + this._additionalLinesWidget = this._register( + new AdditionalLinesWidget( + this._editor, + derived(reader => { + /** @description lines */ + const uiState = this.uiState.read(reader); + return uiState ? { + lineNumber: uiState.lineNumber, + additionalLines: uiState.additionalLines, + minReservedLineCount: uiState.additionalReservedLineCount, + targetTextModel: uiState.targetTextModel, + } : undefined; + }), + this._shouldKeepCursorStable, + this._isClickable + ) + ); + + this._isInlineTextHovered = this._editorObs.isTargetHovered( + p => p.target.type === MouseTargetType.CONTENT_TEXT && p.target.detail.injectedText?.options.attachedData instanceof GhostTextAttachedData, + this._store + ); + this._register(toDisposable(() => { this._isDisposed.set(true, undefined); })); this._register(this._editorObs.setDecorations(this.decorations)); @@ -144,7 +171,7 @@ export class GhostTextView extends Disposable { return undefined; } - private readonly _useSyntaxHighlighting = this._options.map(o => o.syntaxHighlightingEnabled); + private readonly _useSyntaxHighlighting: IObservable; private readonly _extraClassNames = derived(this, reader => { const extraClasses = [...this._options.read(reader).extraClasses ?? []]; @@ -236,28 +263,9 @@ export class GhostTextView extends Disposable { return decorations; }); - private readonly _additionalLinesWidget = this._register( - new AdditionalLinesWidget( - this._editor, - derived(reader => { - /** @description lines */ - const uiState = this.uiState.read(reader); - return uiState ? { - lineNumber: uiState.lineNumber, - additionalLines: uiState.additionalLines, - minReservedLineCount: uiState.additionalReservedLineCount, - targetTextModel: uiState.targetTextModel, - } : undefined; - }), - this._shouldKeepCursorStable, - this._isClickable - ) - ); - - private readonly _isInlineTextHovered = this._editorObs.isTargetHovered( - p => p.target.type === MouseTargetType.CONTENT_TEXT && p.target.detail.injectedText?.options.attachedData instanceof GhostTextAttachedData, - this._store - ); + private readonly _additionalLinesWidget: AdditionalLinesWidget; + + private readonly _isInlineTextHovered: IObservable; public readonly isHovered = derived(this, reader => { if (this._isDisposed.read(reader)) { return false; } @@ -356,26 +364,14 @@ export class AdditionalLinesWidget extends Disposable { private _viewZoneHeight = observableValue('viewZoneHeight', undefined); public get viewZoneHeight(): IObservable { return this._viewZoneHeight; } - private readonly editorOptionsChanged = observableSignalFromEvent('editorOptionChanged', Event.filter( - this._editor.onDidChangeConfiguration, - e => e.hasChanged(EditorOption.disableMonospaceOptimizations) - || e.hasChanged(EditorOption.stopRenderingLineAfter) - || e.hasChanged(EditorOption.renderWhitespace) - || e.hasChanged(EditorOption.renderControlCharacters) - || e.hasChanged(EditorOption.fontLigatures) - || e.hasChanged(EditorOption.fontInfo) - || e.hasChanged(EditorOption.lineHeight) - )); + private readonly editorOptionsChanged: IObservable; private readonly _onDidClick = this._register(new Emitter()); public readonly onDidClick = this._onDidClick.event; private readonly _viewZoneListener = this._register(new MutableDisposable()); - readonly isHovered = observableCodeEditor(this._editor).isTargetHovered( - p => isTargetGhostText(p.target.element), - this._store - ); + readonly isHovered: IObservable; constructor( private readonly _editor: ICodeEditor, @@ -390,6 +386,22 @@ export class AdditionalLinesWidget extends Disposable { ) { super(); + this.editorOptionsChanged = observableSignalFromEvent('editorOptionChanged', Event.filter( + this._editor.onDidChangeConfiguration, + e => e.hasChanged(EditorOption.disableMonospaceOptimizations) + || e.hasChanged(EditorOption.stopRenderingLineAfter) + || e.hasChanged(EditorOption.renderWhitespace) + || e.hasChanged(EditorOption.renderControlCharacters) + || e.hasChanged(EditorOption.fontLigatures) + || e.hasChanged(EditorOption.fontInfo) + || e.hasChanged(EditorOption.lineHeight) + )); + + this.isHovered = observableCodeEditor(this._editor).isTargetHovered( + p => isTargetGhostText(p.target.element), + this._store + ); + this._register(autorun(reader => { /** @description update view zone */ const lines = this._lines.read(reader); diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineCompletionsView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineCompletionsView.ts index 04afc6a88f392..8e61c5678a4ba 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineCompletionsView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineCompletionsView.ts @@ -8,53 +8,29 @@ import { Disposable } from '../../../../../base/common/lifecycle.js'; import { derived, mapObservableArrayCached, derivedDisposable, constObservable, derivedObservableWithCache, IObservable, ISettableObservable } 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 { ObservableCodeEditor, observableCodeEditor } from '../../../../browser/observableCodeEditor.js'; import { EditorOption } from '../../../../common/config/editorOptions.js'; import { InlineCompletionsHintsWidget } from '../hintsWidget/inlineCompletionsHintsWidget.js'; +import { GhostTextOrReplacement } from '../model/ghostText.js'; import { InlineCompletionsModel } from '../model/inlineCompletionsModel.js'; +import { InlineEdit } from '../model/inlineEdit.js'; import { convertItemsToStableObservables } from '../utils.js'; import { GhostTextView } from './ghostText/ghostTextView.js'; import { InlineEditsViewAndDiffProducer } from './inlineEdits/viewAndDiffProducer.js'; export class InlineCompletionsView extends Disposable { - private readonly _ghostTexts = derived(this, (reader) => { - const model = this._model.read(reader); - return model?.ghostTexts.read(reader) ?? []; - }); + private readonly _ghostTexts: IObservable; - private readonly _stablizedGhostTexts = convertItemsToStableObservables(this._ghostTexts, this._store); - private readonly _editorObs = observableCodeEditor(this._editor); + private readonly _stablizedGhostTexts: IObservable[]>; + private readonly _editorObs: ObservableCodeEditor; - private readonly _ghostTextWidgets = mapObservableArrayCached(this, this._stablizedGhostTexts, (ghostText, store) => derivedDisposable((reader) => this._instantiationService.createInstance( - GhostTextView.hot.read(reader), - this._editor, - { - ghostText: ghostText, - warning: this._model.map((m, reader) => { - const warning = m?.warning?.read(reader); - return warning ? { icon: warning.icon } : undefined; - }), - minReservedLineCount: constObservable(0), - targetTextModel: this._model.map(v => v?.textModel), - }, - this._editorObs.getOption(EditorOption.inlineSuggest).map(v => ({ syntaxHighlightingEnabled: v.syntaxHighlightingEnabled })), - false, - false - ) - ).recomputeInitiallyAndOnChange(store) - ).recomputeInitiallyAndOnChange(this._store); + private readonly _ghostTextWidgets: IObservable[]>; - private readonly _inlineEdit = derived(this, reader => this._model.read(reader)?.inlineEditState.read(reader)?.inlineEdit); - private readonly _everHadInlineEdit = derivedObservableWithCache(this, (reader, last) => last || !!this._inlineEdit.read(reader) || !!this._model.read(reader)?.inlineCompletionState.read(reader)?.inlineCompletion?.sourceInlineCompletion.showInlineEditMenu); - protected readonly _inlineEditWidget = derivedDisposable(reader => { - if (!this._everHadInlineEdit.read(reader)) { - return undefined; - } - return this._instantiationService.createInstance(InlineEditsViewAndDiffProducer.hot.read(reader), this._editor, this._inlineEdit, this._model, this._focusIsInMenu); - }) - .recomputeInitiallyAndOnChange(this._store); + private readonly _inlineEdit: IObservable; + private readonly _everHadInlineEdit: IObservable; + protected readonly _inlineEditWidget: IObservable; - private readonly _fontFamily = this._editorObs.getOption(EditorOption.inlineSuggest).map(val => val.fontFamily); + private readonly _fontFamily: IObservable; constructor( private readonly _editor: ICodeEditor, @@ -64,6 +40,45 @@ export class InlineCompletionsView extends Disposable { ) { super(); + this._ghostTexts = derived(this, (reader) => { + const model = this._model.read(reader); + return model?.ghostTexts.read(reader) ?? []; + }); + + this._stablizedGhostTexts = convertItemsToStableObservables(this._ghostTexts, this._store); + this._editorObs = observableCodeEditor(this._editor); + + this._ghostTextWidgets = mapObservableArrayCached(this, this._stablizedGhostTexts, (ghostText, store) => derivedDisposable((reader) => this._instantiationService.createInstance( + GhostTextView.hot.read(reader), + this._editor, + { + ghostText: ghostText, + warning: this._model.map((m, reader) => { + const warning = m?.warning?.read(reader); + return warning ? { icon: warning.icon } : undefined; + }), + minReservedLineCount: constObservable(0), + targetTextModel: this._model.map(v => v?.textModel), + }, + this._editorObs.getOption(EditorOption.inlineSuggest).map(v => ({ syntaxHighlightingEnabled: v.syntaxHighlightingEnabled })), + false, + false + ) + ).recomputeInitiallyAndOnChange(store) + ).recomputeInitiallyAndOnChange(this._store); + + this._inlineEdit = derived(this, reader => this._model.read(reader)?.inlineEditState.read(reader)?.inlineEdit); + this._everHadInlineEdit = derivedObservableWithCache(this, (reader, last) => last || !!this._inlineEdit.read(reader) || !!this._model.read(reader)?.inlineCompletionState.read(reader)?.inlineCompletion?.sourceInlineCompletion.showInlineEditMenu); + this._inlineEditWidget = derivedDisposable(reader => { + if (!this._everHadInlineEdit.read(reader)) { + return undefined; + } + return this._instantiationService.createInstance(InlineEditsViewAndDiffProducer.hot.read(reader), this._editor, this._inlineEdit, this._model, this._focusIsInMenu); + }) + .recomputeInitiallyAndOnChange(this._store); + + this._fontFamily = this._editorObs.getOption(EditorOption.inlineSuggest).map(val => val.fontFamily); + this._register(createStyleSheetFromObservable(derived(reader => { const fontFamily = this._fontFamily.read(reader); if (fontFamily === '' || fontFamily === 'default') { return ''; } diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/components/gutterIndicatorMenu.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/components/gutterIndicatorMenu.ts index 6624abea5fa59..ca7834120fa17 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/components/gutterIndicatorMenu.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/components/gutterIndicatorMenu.ts @@ -27,7 +27,7 @@ import { FirstFnArg, InlineEditTabAction } from '../utils/utils.js'; export class GutterIndicatorMenuContent { - private readonly _inlineEditsShowCollapsed = this._editorObs.getOption(EditorOption.inlineSuggest).map(s => s.edits.showCollapsed); + private readonly _inlineEditsShowCollapsed: IObservable; constructor( private readonly _host: IInlineEditsViewHost, @@ -37,6 +37,7 @@ export class GutterIndicatorMenuContent { @IKeybindingService private readonly _keybindingService: IKeybindingService, @ICommandService private readonly _commandService: ICommandService, ) { + this._inlineEditsShowCollapsed = this._editorObs.getOption(EditorOption.inlineSuggest).map(s => s.edits.showCollapsed); } public toDisposableLiveElement(): LiveElement { diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/components/gutterIndicatorView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/components/gutterIndicatorView.ts index e737ff7aa25fe..60f1663c757cd 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/components/gutterIndicatorView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/components/gutterIndicatorView.ts @@ -20,7 +20,7 @@ import { HoverWidget } from '../../../../../../browser/services/hoverService/hov import { EditorOption } from '../../../../../../common/config/editorOptions.js'; import { LineRange } from '../../../../../../common/core/lineRange.js'; import { OffsetRange } from '../../../../../../common/core/offsetRange.js'; -import { StickyScrollController } from '../../../../../stickyScroll/browser/stickyScrollController.js'; +import { IStickyScrollController, StickyScrollController } from '../../../../../stickyScroll/browser/stickyScrollController.js'; import { IInlineEditsViewHost } from '../inlineEditsViewInterface.js'; import { inlineEditIndicatorBackground, inlineEditIndicatorPrimaryBackground, inlineEditIndicatorPrimaryForeground, inlineEditIndicatorSecondaryBackground, inlineEditIndicatorSecondaryForeground, inlineEditIndicatorsuccessfulBackground, inlineEditIndicatorsuccessfulForeground } from '../theme.js'; import { InlineEditTabAction, mapOutFalsy, rectToProps } from '../utils/utils.js'; @@ -40,6 +40,14 @@ export class InlineEditsGutterIndicator extends Disposable { ) { super(); + this._originalRangeObs = mapOutFalsy(this._originalRange); + + this._stickyScrollController = StickyScrollController.get(this._editorObs.editor); + + this._stickyScrollHeight = this._stickyScrollController + ? observableFromEvent(this._stickyScrollController.onDidChangeStickyScrollHeight, () => this._stickyScrollController!.stickyScrollWidgetHeight) + : constObservable(0); + this._register(this._editorObs.createOverlayWidget({ domNode: this._indicator.element, position: constObservable(null), @@ -65,7 +73,7 @@ export class InlineEditsGutterIndicator extends Disposable { } } - private readonly _originalRangeObs = mapOutFalsy(this._originalRange); + private readonly _originalRangeObs: IObservable | undefined>; private readonly _state = derived(reader => { const range = this._originalRangeObs.read(reader); @@ -76,10 +84,8 @@ export class InlineEditsGutterIndicator extends Disposable { }; }); - private readonly _stickyScrollController = StickyScrollController.get(this._editorObs.editor); - private readonly _stickyScrollHeight = this._stickyScrollController - ? observableFromEvent(this._stickyScrollController.onDidChangeStickyScrollHeight, () => this._stickyScrollController!.stickyScrollWidgetHeight) - : constObservable(0); + private readonly _stickyScrollController: IStickyScrollController | null; + private readonly _stickyScrollHeight: IObservable; private readonly _layout = derived(this, reader => { const s = this._state.read(reader); diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditWithChanges.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditWithChanges.ts index 7a31b034666a4..5e36d197e4503 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditWithChanges.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditWithChanges.ts @@ -4,16 +4,17 @@ *--------------------------------------------------------------------------------------------*/ import { SingleLineEdit } from '../../../../../common/core/lineEdit.js'; +import { LineRange } from '../../../../../common/core/lineRange.js'; import { Position } from '../../../../../common/core/position.js'; import { AbstractText, TextEdit } from '../../../../../common/core/textEdit.js'; import { Command } from '../../../../../common/languages.js'; import { InlineCompletionItem } from '../../model/provideInlineCompletions.js'; export class InlineEditWithChanges { - public readonly lineEdit = SingleLineEdit.fromSingleTextEdit(this.edit.toSingle(this.originalText), this.originalText); + public readonly lineEdit: SingleLineEdit; - public readonly originalLineRange = this.lineEdit.lineRange; - public readonly modifiedLineRange = this.lineEdit.toLineEdit().getNewLineRanges()[0]; + public readonly originalLineRange: LineRange; + public readonly modifiedLineRange: LineRange; constructor( public readonly originalText: AbstractText, @@ -23,6 +24,10 @@ export class InlineEditWithChanges { public readonly commands: readonly Command[], public readonly inlineCompletion: InlineCompletionItem ) { + this.lineEdit = SingleLineEdit.fromSingleTextEdit(this.edit.toSingle(this.originalText), this.originalText); + + this.originalLineRange = this.lineEdit.lineRange; + this.modifiedLineRange = this.lineEdit.toLineEdit().getNewLineRanges()[0]; } equals(other: InlineEditWithChanges) { diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsView.ts index fe29ffa062be9..cfc3d4272ceed 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsView.ts @@ -10,7 +10,7 @@ import { autorunWithStore, derived, derivedObservableWithCache, derivedOpts, der import { localize } from '../../../../../../nls.js'; import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; import { ICodeEditor } from '../../../../../browser/editorBrowser.js'; -import { observableCodeEditor } from '../../../../../browser/observableCodeEditor.js'; +import { ObservableCodeEditor, 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'; @@ -34,14 +34,14 @@ import { applyEditToModifiedRangeMappings, createReindentEdit, InlineEditTabActi import './view.css'; export class InlineEditsView extends Disposable { - private readonly _editorObs = observableCodeEditor(this._editor); + private readonly _editorObs: ObservableCodeEditor; - private readonly _useMixedLinesDiff = this._editorObs.getOption(EditorOption.inlineSuggest).map(s => s.edits.useMixedLinesDiff); - private readonly _useInterleavedLinesDiff = this._editorObs.getOption(EditorOption.inlineSuggest).map(s => s.edits.useInterleavedLinesDiff); - private readonly _useCodeShifting = this._editorObs.getOption(EditorOption.inlineSuggest).map(s => s.edits.codeShifting); - private readonly _renderSideBySide = this._editorObs.getOption(EditorOption.inlineSuggest).map(s => s.edits.renderSideBySide); - private readonly _showCollapsed = this._editorObs.getOption(EditorOption.inlineSuggest).map(s => s.edits.showCollapsed); - private readonly _useMultiLineGhostText = this._editorObs.getOption(EditorOption.inlineSuggest).map(s => s.edits.useMultiLineGhostText); + private readonly _useMixedLinesDiff: IObservable<'never' | 'whenPossible' | 'forStableInsertions' | 'afterJumpWhenPossible'>; + private readonly _useInterleavedLinesDiff: IObservable<'always' | 'never' | 'afterJump'>; + private readonly _useCodeShifting: IObservable; + private readonly _renderSideBySide: IObservable<'never' | 'auto'>; + private readonly _showCollapsed: IObservable; + private readonly _useMultiLineGhostText: IObservable; private _previousView: { id: string; @@ -59,6 +59,99 @@ export class InlineEditsView extends Disposable { ) { super(); + this._editorObs = observableCodeEditor(this._editor); + + this._useMixedLinesDiff = this._editorObs.getOption(EditorOption.inlineSuggest).map(s => s.edits.useMixedLinesDiff); + this._useInterleavedLinesDiff = this._editorObs.getOption(EditorOption.inlineSuggest).map(s => s.edits.useInterleavedLinesDiff); + this._useCodeShifting = this._editorObs.getOption(EditorOption.inlineSuggest).map(s => s.edits.codeShifting); + this._renderSideBySide = this._editorObs.getOption(EditorOption.inlineSuggest).map(s => s.edits.renderSideBySide); + this._showCollapsed = this._editorObs.getOption(EditorOption.inlineSuggest).map(s => s.edits.showCollapsed); + this._useMultiLineGhostText = this._editorObs.getOption(EditorOption.inlineSuggest).map(s => s.edits.useMultiLineGhostText); + + this._previewTextModel = this._register(this._instantiationService.createInstance( + TextModel, + '', + this._editor.getModel()!.getLanguageId(), + { ...TextModel.DEFAULT_CREATION_OPTIONS, bracketPairColorizationOptions: { enabled: true, independentColorPoolPerBracketType: false } }, + null + )); + + // TODO: This has become messy, should it be passed in to the InlineEditsView? Maybe include in accept flow? + this._host = { + displayName: derivedObservableWithCache(this, (reader, previousDisplayName) => { + const state = this._model.read(reader)?.inlineEditState; + const item = state?.read(reader); + const completionSource = item?.inlineCompletion?.source; + // TODO: expose the provider (typed) and expose the provider the edit belongs to typing and get correct edit + return (completionSource?.inlineCompletions as any)?.edits?.[0]?.provider?.displayName ?? previousDisplayName + ?? completionSource?.provider.displayName ?? localize('inlineEdit', "Inline Edit"); + }), + tabAction: derived(this, reader => { + const m = this._model.read(reader); + if (this._editorObs.isFocused.read(reader)) { + if (m && m.tabShouldJumpToInlineEdit.read(reader)) { return InlineEditTabAction.Jump; } + if (m && m.tabShouldAcceptInlineEdit.read(reader)) { return InlineEditTabAction.Accept; } + if (m && m.inlineCompletionState.read(reader)?.inlineCompletion?.sourceInlineCompletion.showInlineEditMenu) { return InlineEditTabAction.Accept; } + } + return InlineEditTabAction.Inactive; + }), + action: this._model.map((m, r) => m?.state.read(r)?.inlineCompletion?.inlineCompletion.action), + extensionCommands: this._model.map((m, r) => m?.state.read(r)?.inlineCompletion?.source.inlineCompletions.commands ?? []), + accept: () => { + this._model.get()?.accept(); + }, + jump: () => { + this._model.get()?.jump(); + } + }; + + this._useGutterIndicator = observableCodeEditor(this._editor).getOption(EditorOption.inlineSuggest).map(s => s.edits.useGutterIndicator); + + this._sideBySide = this._register(this._instantiationService.createInstance(InlineEditsSideBySideView, + this._editor, + this._edit, + this._previewTextModel, + this._uiState.map(s => s && s.state?.kind === 'sideBySide' ? ({ + edit: s.edit, + newTextLineCount: s.newTextLineCount, + originalDisplayRange: s.originalDisplayRange, + }) : undefined), + this._host, + )); + + this._deletion = this._register(this._instantiationService.createInstance(InlineEditsDeletionView, + this._editor, + this._edit, + this._uiState.map(s => s && s.state?.kind === 'deletion' ? ({ + originalRange: s.state.originalRange, + deletions: s.state.deletions, + }) : undefined), + this._host, + )); + + this._insertion = this._register(this._instantiationService.createInstance(InlineEditsInsertionView, + this._editor, + this._uiState.map(s => s && s.state?.kind === 'insertionMultiLine' ? ({ + lineNumber: s.state.lineNumber, + startColumn: s.state.column, + text: s.state.text, + }) : undefined), + this._host, + )); + + this._inlineDiffView = this._register(new OriginalEditorInlineDiffView(this._editor, this._inlineDiffViewState, this._previewTextModel)); + + this._lineReplacementView = this._register(this._instantiationService.createInstance(InlineEditsLineReplacementView, + this._editorObs, + this._uiState.map(s => s?.state?.kind === 'lineReplacement' ? ({ + originalRange: s.state.originalRange, + modifiedRange: s.state.modifiedRange, + modifiedLines: s.state.modifiedLines, + replacements: s.state.replacements, + }) : undefined), + this._host + )); + this._register(autorunWithStore((reader, store) => { store.add( Event.any( @@ -142,44 +235,11 @@ export class InlineEditsView extends Disposable { }; }); - private readonly _previewTextModel = this._register(this._instantiationService.createInstance( - TextModel, - '', - this._editor.getModel()!.getLanguageId(), - { ...TextModel.DEFAULT_CREATION_OPTIONS, bracketPairColorizationOptions: { enabled: true, independentColorPoolPerBracketType: false } }, - null - )); - - // TODO: This has become messy, should it be passed in to the InlineEditsView? Maybe include in accept flow? - private readonly _host: IInlineEditsViewHost = { - displayName: derivedObservableWithCache(this, (reader, previousDisplayName) => { - const state = this._model.read(reader)?.inlineEditState; - const item = state?.read(reader); - const completionSource = item?.inlineCompletion?.source; - // TODO: expose the provider (typed) and expose the provider the edit belongs to typing and get correct edit - return (completionSource?.inlineCompletions as any)?.edits?.[0]?.provider?.displayName ?? previousDisplayName - ?? completionSource?.provider.displayName ?? localize('inlineEdit', "Inline Edit"); - }), - tabAction: derived(this, reader => { - const m = this._model.read(reader); - if (this._editorObs.isFocused.read(reader)) { - if (m && m.tabShouldJumpToInlineEdit.read(reader)) { return InlineEditTabAction.Jump; } - if (m && m.tabShouldAcceptInlineEdit.read(reader)) { return InlineEditTabAction.Accept; } - if (m && m.inlineCompletionState.read(reader)?.inlineCompletion?.sourceInlineCompletion.showInlineEditMenu) { return InlineEditTabAction.Accept; } - } - return InlineEditTabAction.Inactive; - }), - action: this._model.map((m, r) => m?.state.read(r)?.inlineCompletion?.inlineCompletion.action), - extensionCommands: this._model.map((m, r) => m?.state.read(r)?.inlineCompletion?.source.inlineCompletions.commands ?? []), - accept: () => { - this._model.get()?.accept(); - }, - jump: () => { - this._model.get()?.jump(); - } - }; + private readonly _previewTextModel: TextModel; + + private readonly _host: IInlineEditsViewHost; - private readonly _useGutterIndicator = observableCodeEditor(this._editor).getOption(EditorOption.inlineSuggest).map(s => s.edits.useGutterIndicator); + private readonly _useGutterIndicator: IObservable; private readonly _indicatorCyclicDependencyCircuitBreaker = observableValue(this, false); @@ -243,39 +303,13 @@ export class InlineEditsView extends Disposable { return 0; }); - private readonly _sideBySide = this._register(this._instantiationService.createInstance(InlineEditsSideBySideView, - this._editor, - this._edit, - this._previewTextModel, - this._uiState.map(s => s && s.state?.kind === 'sideBySide' ? ({ - edit: s.edit, - newTextLineCount: s.newTextLineCount, - originalDisplayRange: s.originalDisplayRange, - }) : undefined), - this._host, - )); - - protected readonly _deletion = this._register(this._instantiationService.createInstance(InlineEditsDeletionView, - this._editor, - this._edit, - this._uiState.map(s => s && s.state?.kind === 'deletion' ? ({ - originalRange: s.state.originalRange, - deletions: s.state.deletions, - }) : undefined), - this._host, - )); - - protected readonly _insertion = this._register(this._instantiationService.createInstance(InlineEditsInsertionView, - this._editor, - this._uiState.map(s => s && s.state?.kind === 'insertionMultiLine' ? ({ - lineNumber: s.state.lineNumber, - startColumn: s.state.column, - text: s.state.text, - }) : undefined), - this._host, - )); - - private readonly _inlineDiffViewState = derived(this, reader => { + private readonly _sideBySide: InlineEditsSideBySideView; + + protected readonly _deletion: InlineEditsDeletionView; + + protected readonly _insertion: InlineEditsInsertionView; + + private readonly _inlineDiffViewState: IObservable = derived(this, reader => { const e = this._uiState.read(reader); if (!e || !e.state) { return undefined; } if (e.state.kind === 'wordReplacements' || e.state.kind === 'lineReplacement' || e.state.kind === 'insertionMultiLine' || e.state.kind === 'hidden') { @@ -289,22 +323,13 @@ export class InlineEditsView extends Disposable { }; }); - protected readonly _inlineDiffView = this._register(new OriginalEditorInlineDiffView(this._editor, this._inlineDiffViewState, this._previewTextModel)); + protected readonly _inlineDiffView: OriginalEditorInlineDiffView; protected readonly _wordReplacementViews = mapObservableArrayCached(this, this._uiState.map(s => s?.state?.kind === 'wordReplacements' ? s.state.replacements : []), (e, store) => { return store.add(this._instantiationService.createInstance(InlineEditsWordReplacementView, this._editorObs, e, [e], this._host)); }); - protected readonly _lineReplacementView = this._register(this._instantiationService.createInstance(InlineEditsLineReplacementView, - this._editorObs, - this._uiState.map(s => s?.state?.kind === 'lineReplacement' ? ({ - originalRange: s.state.originalRange, - modifiedRange: s.state.modifiedRange, - modifiedLines: s.state.modifiedLines, - replacements: s.state.replacements, - }) : undefined), - this._host - )); + protected readonly _lineReplacementView: InlineEditsLineReplacementView; private getCacheId(edit: InlineEditWithChanges) { if (this._model.get()?.inAcceptPartialFlow.get()) { diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsDeletionView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsDeletionView.ts index f8c6bcf393455..c6db311ef0e0b 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsDeletionView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsDeletionView.ts @@ -9,7 +9,7 @@ import { Disposable } from '../../../../../../../base/common/lifecycle.js'; import { constObservable, derived, derivedObservableWithCache, IObservable } from '../../../../../../../base/common/observable.js'; import { asCssVariable } from '../../../../../../../platform/theme/common/colorUtils.js'; import { ICodeEditor } from '../../../../../../browser/editorBrowser.js'; -import { observableCodeEditor } from '../../../../../../browser/observableCodeEditor.js'; +import { ObservableCodeEditor, observableCodeEditor } from '../../../../../../browser/observableCodeEditor.js'; import { Point } from '../../../../../../browser/point.js'; import { LineRange } from '../../../../../../common/core/lineRange.js'; import { Position } from '../../../../../../common/core/position.js'; @@ -20,7 +20,7 @@ import { getOriginalBorderColor, originalBackgroundColor } from '../theme.js'; import { createRectangle, getPrefixTrim, mapOutFalsy, maxContentWidthInRange } from '../utils/utils.js'; export class InlineEditsDeletionView extends Disposable implements IInlineEditsView { - private readonly _editorObs = observableCodeEditor(this._editor); + private readonly _editorObs: ObservableCodeEditor; private readonly _onDidClick = this._register(new Emitter()); readonly onDidClick = this._onDidClick.event; @@ -36,6 +36,56 @@ export class InlineEditsDeletionView extends Disposable implements IInlineEditsV ) { super(); + this._editorObs = observableCodeEditor(this._editor); + + this._originalVerticalStartPosition = this._editorObs.observePosition(this._originalStartPosition, this._store).map(p => p?.y); + this._originalVerticalEndPosition = this._editorObs.observePosition(this._originalEndPosition, this._store).map(p => p?.y); + + this._originalDisplayRange = this._uiState.map(s => s?.originalRange); + + this._editorLayoutInfo = derived(this, (reader) => { + const inlineEdit = this._edit.read(reader); + if (!inlineEdit) { + return null; + } + const state = this._uiState.read(reader); + if (!state) { + return null; + } + + const editorLayout = this._editorObs.layoutInfo.read(reader); + const horizontalScrollOffset = this._editorObs.scrollLeft.read(reader); + + const left = editorLayout.contentLeft + this._editorMaxContentWidthInRange.read(reader) - horizontalScrollOffset; + + const range = inlineEdit.originalLineRange; + const selectionTop = this._originalVerticalStartPosition.read(reader) ?? this._editor.getTopForLineNumber(range.startLineNumber) - this._editorObs.scrollTop.read(reader); + const selectionBottom = this._originalVerticalEndPosition.read(reader) ?? this._editor.getTopForLineNumber(range.endLineNumberExclusive) - this._editorObs.scrollTop.read(reader); + + const codeLeft = editorLayout.contentLeft + this._maxPrefixTrim.read(reader).prefixLeftOffset; + + if (left <= codeLeft) { + return null; + } + + const code1 = new Point(left, selectionTop); + const codeStart1 = new Point(codeLeft, selectionTop); + const code2 = new Point(left, selectionBottom); + const codeStart2 = new Point(codeLeft, selectionBottom); + const codeHeight = selectionBottom - selectionTop; + + return { + code1, + codeStart1, + code2, + codeStart2, + codeHeight, + horizontalScrollOffset, + padding: 3, + borderRadius: 4, + }; + }).recomputeInitiallyAndOnChange(this._store); + this._register(this._editorObs.createOverlayWidget({ domNode: this._nonOverflowView.element, position: constObservable(null), @@ -60,10 +110,10 @@ export class InlineEditsDeletionView extends Disposable implements IInlineEditsV return inlineEdit ? new Position(inlineEdit.originalLineRange.endLineNumberExclusive, 1) : null; }); - private readonly _originalVerticalStartPosition = this._editorObs.observePosition(this._originalStartPosition, this._store).map(p => p?.y); - private readonly _originalVerticalEndPosition = this._editorObs.observePosition(this._originalEndPosition, this._store).map(p => p?.y); + private readonly _originalVerticalStartPosition: IObservable; + private readonly _originalVerticalEndPosition: IObservable; - private readonly _originalDisplayRange = this._uiState.map(s => s?.originalRange); + private readonly _originalDisplayRange: IObservable; private readonly _editorMaxContentWidthInRange = derived(this, reader => { const originalDisplayRange = this._originalDisplayRange.read(reader); if (!originalDisplayRange) { @@ -87,48 +137,16 @@ export class InlineEditsDeletionView extends Disposable implements IInlineEditsV return getPrefixTrim(state.deletions, state.originalRange, [], this._editor); }); - private readonly _editorLayoutInfo = derived(this, (reader) => { - const inlineEdit = this._edit.read(reader); - if (!inlineEdit) { - return null; - } - const state = this._uiState.read(reader); - if (!state) { - return null; - } - - const editorLayout = this._editorObs.layoutInfo.read(reader); - const horizontalScrollOffset = this._editorObs.scrollLeft.read(reader); - - const left = editorLayout.contentLeft + this._editorMaxContentWidthInRange.read(reader) - horizontalScrollOffset; - - const range = inlineEdit.originalLineRange; - const selectionTop = this._originalVerticalStartPosition.read(reader) ?? this._editor.getTopForLineNumber(range.startLineNumber) - this._editorObs.scrollTop.read(reader); - const selectionBottom = this._originalVerticalEndPosition.read(reader) ?? this._editor.getTopForLineNumber(range.endLineNumberExclusive) - this._editorObs.scrollTop.read(reader); - - const codeLeft = editorLayout.contentLeft + this._maxPrefixTrim.read(reader).prefixLeftOffset; - - if (left <= codeLeft) { - return null; - } - - const code1 = new Point(left, selectionTop); - const codeStart1 = new Point(codeLeft, selectionTop); - const code2 = new Point(left, selectionBottom); - const codeStart2 = new Point(codeLeft, selectionBottom); - const codeHeight = selectionBottom - selectionTop; - - return { - code1, - codeStart1, - code2, - codeStart2, - codeHeight, - horizontalScrollOffset, - padding: 3, - borderRadius: 4, - }; - }).recomputeInitiallyAndOnChange(this._store); + private readonly _editorLayoutInfo: IObservable<{ + code1: Point; + codeStart1: Point; + code2: Point; + codeStart2: Point; + codeHeight: number; + horizontalScrollOffset: number; + padding: number; + borderRadius: number; + } | null>; private readonly _foregroundSvg = n.svg({ transform: 'translate(-0.5 -0.5)', diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsInsertionView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsInsertionView.ts index 494210fa6c7f1..df8703ef33292 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsInsertionView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsInsertionView.ts @@ -10,7 +10,7 @@ import { constObservable, derived, derivedWithStore, IObservable, observableValu import { IInstantiationService } from '../../../../../../../platform/instantiation/common/instantiation.js'; import { asCssVariable } from '../../../../../../../platform/theme/common/colorUtils.js'; import { ICodeEditor } from '../../../../../../browser/editorBrowser.js'; -import { observableCodeEditor } from '../../../../../../browser/observableCodeEditor.js'; +import { ObservableCodeEditor, observableCodeEditor } from '../../../../../../browser/observableCodeEditor.js'; import { Rect } from '../../../../../../browser/rect.js'; import { LineSource, renderLines, RenderOptions } from '../../../../../../browser/widget/diffEditor/components/diffEditorViewZones/renderLines.js'; import { EditorOption } from '../../../../../../common/config/editorOptions.js'; @@ -28,7 +28,7 @@ import { getModifiedBorderColor, modifiedChangedLineBackgroundColor } from '../t import { createRectangle, getPrefixTrim, mapOutFalsy } from '../utils/utils.js'; export class InlineEditsInsertionView extends Disposable implements IInlineEditsView { - private readonly _editorObs = observableCodeEditor(this._editor); + private readonly _editorObs: ObservableCodeEditor; private readonly _onDidClick = this._register(new Emitter()); readonly onDidClick = this._onDidClick.event; @@ -86,18 +86,7 @@ export class InlineEditsInsertionView extends Disposable implements IInlineEdits return new GhostText(state.lineNumber, [new GhostTextPart(state.column, state.text, false, inlineDecorations)]); }); - protected readonly _ghostTextView = this._register(this._instantiationService.createInstance(GhostTextView, - this._editor, - { - ghostText: this._ghostText, - minReservedLineCount: constObservable(0), - targetTextModel: this._editorObs.model.map(model => model ?? undefined), - warning: constObservable(undefined), - }, - observableValue(this, { syntaxHighlightingEnabled: true, extraClasses: ['inline-edit'] }), - true, - true - )); + protected readonly _ghostTextView: GhostTextView; constructor( private readonly _editor: ICodeEditor, @@ -112,6 +101,62 @@ export class InlineEditsInsertionView extends Disposable implements IInlineEdits ) { super(); + this._editorObs = observableCodeEditor(this._editor); + + this._ghostTextView = this._register(this._instantiationService.createInstance(GhostTextView, + this._editor, + { + ghostText: this._ghostText, + minReservedLineCount: constObservable(0), + targetTextModel: this._editorObs.model.map(model => model ?? undefined), + warning: constObservable(undefined), + }, + observableValue(this, { syntaxHighlightingEnabled: true, extraClasses: ['inline-edit'] }), + true, + true, + )); + + this._overlayLayout = derivedWithStore(this, (reader, store) => { + this._ghostText.read(reader); + const state = this._state.read(reader); + if (!state) { + return null; + } + + // Update the overlay when the position changes + this._editorObs.observePosition(observableValue(this, new Position(state.lineNumber, state.column)), store).read(reader); + + const editorLayout = this._editorObs.layoutInfo.read(reader); + const horizontalScrollOffset = this._editorObs.scrollLeft.read(reader); + const verticalScrollbarWidth = this._editorObs.layoutInfoVerticalScrollbarWidth.read(reader); + + const right = editorLayout.contentLeft + this._editorMaxContentWidthInRange.read(reader) - horizontalScrollOffset; + const prefixLeftOffset = this._maxPrefixTrim.read(reader).prefixLeftOffset ?? 0 /* fix due to observable bug? */; + const left = editorLayout.contentLeft + prefixLeftOffset; + if (right <= left) { + return null; + } + + const { top: topTrim, bottom: bottomTrim } = this._trimVertically.read(reader); + + const scrollTop = this._editorObs.scrollTop.read(reader); + const height = this._ghostTextView.height.read(reader) - topTrim - bottomTrim; + const top = this._editor.getTopForLineNumber(state.lineNumber) - scrollTop + topTrim; + const bottom = top + height; + + const PADDING = 3; + const overlay = new Rect(left, top, right, bottom).withMargin(PADDING); + + return { + overlay, + horizontalScrollOffset, + minContentWidthRequired: prefixLeftOffset + overlay.width + verticalScrollbarWidth, + borderRadius: 4, + }; + }).recomputeInitiallyAndOnChange(this._store); + + this.isHovered = this._ghostTextView.isHovered; + this._register(this._ghostTextView.onDidClick((e) => { this._onDidClick.fire(e); })); @@ -194,44 +239,12 @@ export class InlineEditsInsertionView extends Disposable implements IInlineEdits ) : undefined ); - private readonly _overlayLayout = derivedWithStore(this, (reader, store) => { - this._ghostText.read(reader); - const state = this._state.read(reader); - if (!state) { - return null; - } - - // Update the overlay when the position changes - this._editorObs.observePosition(observableValue(this, new Position(state.lineNumber, state.column)), store).read(reader); - - const editorLayout = this._editorObs.layoutInfo.read(reader); - const horizontalScrollOffset = this._editorObs.scrollLeft.read(reader); - const verticalScrollbarWidth = this._editorObs.layoutInfoVerticalScrollbarWidth.read(reader); - - const right = editorLayout.contentLeft + this._editorMaxContentWidthInRange.read(reader) - horizontalScrollOffset; - const prefixLeftOffset = this._maxPrefixTrim.read(reader).prefixLeftOffset ?? 0 /* fix due to observable bug? */; - const left = editorLayout.contentLeft + prefixLeftOffset; - if (right <= left) { - return null; - } - - const { top: topTrim, bottom: bottomTrim } = this._trimVertically.read(reader); - - const scrollTop = this._editorObs.scrollTop.read(reader); - const height = this._ghostTextView.height.read(reader) - topTrim - bottomTrim; - const top = this._editor.getTopForLineNumber(state.lineNumber) - scrollTop + topTrim; - const bottom = top + height; - - const PADDING = 3; - const overlay = new Rect(left, top, right, bottom).withMargin(PADDING); - - return { - overlay, - horizontalScrollOffset, - minContentWidthRequired: prefixLeftOffset + overlay.width + verticalScrollbarWidth, - borderRadius: 4, - }; - }).recomputeInitiallyAndOnChange(this._store); + private readonly _overlayLayout: IObservable<{ + overlay: Rect; + horizontalScrollOffset: number; + minContentWidthRequired: number; + borderRadius: number; + } | null>; private readonly _foregroundSvg = n.svg({ transform: 'translate(-0.5 -0.5)', @@ -282,5 +295,5 @@ export class InlineEditsInsertionView extends Disposable implements IInlineEdits [this._foregroundSvg], ]).keepUpdated(this._store); - readonly isHovered = this._ghostTextView.isHovered; + readonly isHovered: IObservable; } diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsLineReplacementView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsLineReplacementView.ts index d952cda8a05b4..cfd8f90a44406 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsLineReplacementView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsLineReplacementView.ts @@ -20,6 +20,7 @@ import { EditorOption } from '../../../../../../common/config/editorOptions.js'; import { LineRange } from '../../../../../../common/core/lineRange.js'; import { OffsetRange } from '../../../../../../common/core/offsetRange.js'; import { Range } from '../../../../../../common/core/range.js'; +import { IEditorDecorationsCollection } from '../../../../../../common/editorCommon.js'; import { ILanguageService } from '../../../../../../common/languages/language.js'; import { IModelDecorationOptions, TrackedRangeStickiness } from '../../../../../../common/model.js'; import { LineTokens } from '../../../../../../common/tokens/lineTokens.js'; @@ -35,14 +36,14 @@ export class InlineEditsLineReplacementView extends Disposable implements IInlin private readonly _onDidClick = this._register(new Emitter()); readonly onDidClick = this._onDidClick.event; - private readonly _originalBubblesDecorationCollection = this._editor.editor.createDecorationsCollection(); + private readonly _originalBubblesDecorationCollection: IEditorDecorationsCollection; private readonly _originalBubblesDecorationOptions: IModelDecorationOptions = { description: 'inlineCompletions-original-bubble', className: 'inlineCompletions-original-bubble', stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges }; - private readonly _maxPrefixTrim = this._edit.map(e => e ? getPrefixTrim(e.replacements.flatMap(r => [r.originalRange, r.modifiedRange]), e.originalRange, e.modifiedLines, this._editor.editor) : undefined); + private readonly _maxPrefixTrim: IObservable<{ prefixTrim: number; prefixLeftOffset: number } | undefined>; private readonly _modifiedLineElements = derived(reader => { const lines = []; @@ -274,7 +275,7 @@ export class InlineEditsLineReplacementView extends Disposable implements IInlin }) ]).keepUpdated(this._store); - readonly isHovered = this._editor.isTargetHovered((e) => this._isMouseOverWidget(e), this._store); + readonly isHovered: IObservable; constructor( private readonly _editor: ObservableCodeEditor, @@ -289,6 +290,12 @@ export class InlineEditsLineReplacementView extends Disposable implements IInlin ) { super(); + this._originalBubblesDecorationCollection = this._editor.editor.createDecorationsCollection(); + + this._maxPrefixTrim = this._edit.map(e => e ? getPrefixTrim(e.replacements.flatMap(r => [r.originalRange, r.modifiedRange]), e.originalRange, e.modifiedLines, this._editor.editor) : undefined); + + this.isHovered = this._editor.isTargetHovered((e) => this._isMouseOverWidget(e), this._store); + this._register(toDisposable(() => this._originalBubblesDecorationCollection.clear())); this._register(toDisposable(() => this._editor.editor.changeViewZones(accessor => this.removePreviousViewZone(accessor)))); diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsSideBySideView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsSideBySideView.ts index 12648f46114c0..fec6ea2fa48b8 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsSideBySideView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsSideBySideView.ts @@ -2,7 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { $, getWindow, n } from '../../../../../../../base/browser/dom.js'; +import { $, getWindow, n, ObserverNodeWithElement } from '../../../../../../../base/browser/dom.js'; import { IMouseEvent, StandardMouseEvent } from '../../../../../../../base/browser/mouseEvent.js'; import { Color } from '../../../../../../../base/common/color.js'; import { Emitter } from '../../../../../../../base/common/event.js'; @@ -12,7 +12,7 @@ import { IInstantiationService } from '../../../../../../../platform/instantiati import { asCssVariable } from '../../../../../../../platform/theme/common/colorUtils.js'; import { IThemeService } from '../../../../../../../platform/theme/common/themeService.js'; import { ICodeEditor } from '../../../../../../browser/editorBrowser.js'; -import { observableCodeEditor } from '../../../../../../browser/observableCodeEditor.js'; +import { ObservableCodeEditor, observableCodeEditor } from '../../../../../../browser/observableCodeEditor.js'; import { Rect } from '../../../../../../browser/rect.js'; import { EmbeddedCodeEditorWidget } from '../../../../../../browser/widget/codeEditor/embeddedCodeEditorWidget.js'; import { EditorOption } from '../../../../../../common/config/editorOptions.js'; @@ -21,7 +21,7 @@ import { OffsetRange } from '../../../../../../common/core/offsetRange.js'; import { Position } from '../../../../../../common/core/position.js'; import { Range } from '../../../../../../common/core/range.js'; import { ITextModel } from '../../../../../../common/model.js'; -import { StickyScrollController } from '../../../../../stickyScroll/browser/stickyScrollController.js'; +import { IStickyScrollController, StickyScrollController } from '../../../../../stickyScroll/browser/stickyScrollController.js'; import { InlineCompletionContextKeys } from '../../../controller/inlineCompletionContextKeys.js'; import { IInlineEditsView, IInlineEditsViewHost } from '../inlineEditsViewInterface.js'; import { InlineEditWithChanges } from '../inlineEditWithChanges.js'; @@ -50,7 +50,7 @@ export class InlineEditsSideBySideView extends Disposable implements IInlineEdit return maxOriginalContent + maxModifiedContent + editorsPadding < editorWidth - editorContentLeft - editorVerticalScrollbar - minimapWidth; } - private readonly _editorObs = observableCodeEditor(this._editor); + private readonly _editorObs: ObservableCodeEditor; private readonly _onDidClick = this._register(new Emitter()); readonly onDidClick = this._onDidClick.event; @@ -70,6 +70,79 @@ export class InlineEditsSideBySideView extends Disposable implements IInlineEdit ) { super(); + this._editorObs = observableCodeEditor(this._editor); + + this._editorContainer = n.div({ + class: ['editorContainer', this._editorObs.getOption(EditorOption.inlineSuggest).map(v => !v.edits.useGutterIndicator && 'showHover')], + style: { position: 'absolute', overflow: 'hidden', cursor: 'pointer' }, + onclick: (e) => { + this._onDidClick.fire(new StandardMouseEvent(getWindow(e), e)); + } + }, [ + n.div({ class: 'preview', style: { pointerEvents: 'none' }, ref: this.previewRef }), + ]).keepUpdated(this._store); + + this.isHovered = this._editorContainer.didMouseMoveDuringHover; + + this.previewEditor = this._register(this._instantiationService.createInstance( + EmbeddedCodeEditorWidget, + this.previewRef.element, + { + glyphMargin: false, + lineNumbers: 'off', + minimap: { enabled: false }, + guides: { + indentation: false, + bracketPairs: false, + bracketPairsHorizontal: false, + highlightActiveIndentation: false, + }, + rulers: [], + padding: { top: 0, bottom: 0 }, + folding: false, + selectOnLineNumbers: false, + selectionHighlight: false, + columnSelection: false, + overviewRulerBorder: false, + overviewRulerLanes: 0, + lineDecorationsWidth: 0, + lineNumbersMinChars: 0, + revealHorizontalRightPadding: 0, + bracketPairColorization: { enabled: true, independentColorPoolPerBracketType: false }, + scrollBeyondLastLine: false, + scrollbar: { + vertical: 'hidden', + horizontal: 'hidden', + handleMouseWheel: false, + }, + readOnly: true, + wordWrap: 'off', + wordWrapOverride1: 'off', + wordWrapOverride2: 'off', + }, + { + contextKeyValues: { + [InlineCompletionContextKeys.inInlineEditsPreviewEditor.key]: true, + }, + contributions: [], + }, + this._editor + )); + + this._previewEditorObs = observableCodeEditor(this.previewEditor); + + this._originalVerticalStartPosition = this._editorObs.observePosition(this._originalStartPosition, this._store).map(p => p?.y); + this._originalVerticalEndPosition = this._editorObs.observePosition(this._originalEndPosition, this._store).map(p => p?.y); + + this._originalDisplayRange = this._uiState.map(s => s?.originalDisplayRange); + + this._stickyScrollController = StickyScrollController.get(this._editorObs.editor); + this._stickyScrollHeight = this._stickyScrollController ? observableFromEvent(this._stickyScrollController.onDidChangeStickyScrollHeight, () => this._stickyScrollController!.stickyScrollWidgetHeight) : constObservable(0); + + this._originalBackgroundColor = observableFromEvent(this, this._themeService.onDidColorThemeChange, () => { + return this._themeService.getColorTheme().getColor(originalBackgroundColor) ?? Color.transparent; + }); + this._register(this._editorObs.createOverlayWidget({ domNode: this._overflowView.element, position: constObservable({ @@ -95,6 +168,59 @@ export class InlineEditsSideBySideView extends Disposable implements IInlineEdit this.previewEditor.setModel(this._previewTextModel); + this._updatePreviewEditor = derived(reader => { + this._editorContainer.readEffect(reader); + this._previewEditorObs.model.read(reader); // update when the model is set + + // Setting this here explicitly to make sure that the preview editor is + // visible when needed, we're also checking that these fields are defined + // because of the auto run initial + // Before removing these, verify with a non-monospace font family + this._display.read(reader); + if (this._overflowView) { + this._overflowView.element.style.display = this._display.read(reader); + } + if (this._nonOverflowView) { + this._nonOverflowView.element.style.display = this._display.read(reader); + } + + const uiState = this._uiState.read(reader); + if (!uiState) { + return; + } + + const range = uiState.edit.originalLineRange; + + const hiddenAreas: Range[] = []; + if (range.startLineNumber > 1) { + hiddenAreas.push(new Range(1, 1, range.startLineNumber - 1, 1)); + } + if (range.startLineNumber + uiState.newTextLineCount < this._previewTextModel.getLineCount() + 1) { + hiddenAreas.push(new Range(range.startLineNumber + uiState.newTextLineCount, 1, this._previewTextModel.getLineCount() + 1, 1)); + } + + this.previewEditor.setHiddenAreas(hiddenAreas, undefined, true); + + // TODO: is this the proper way to handle viewzones? + const previousViewZones = [...this._activeViewZones]; + this._activeViewZones = []; + + const reducedLinesCount = (range.endLineNumberExclusive - range.startLineNumber) - uiState.newTextLineCount; + this.previewEditor.changeViewZones((changeAccessor) => { + previousViewZones.forEach(id => changeAccessor.removeZone(id)); + + if (reducedLinesCount > 0) { + this._activeViewZones.push(changeAccessor.addZone({ + afterLineNumber: range.startLineNumber + uiState.newTextLineCount - 1, + heightInLines: reducedLinesCount, + showInHiddenAreas: true, + domNode: $('div.diagonal-fill.inline-edits-view-zone'), + })); + } + }); + + }).recomputeInitiallyAndOnChange(this._store); + this._register(autorun(reader => { const layoutInfo = this._previewEditorLayoutInfo.read(reader); if (!layoutInfo) { @@ -122,118 +248,16 @@ export class InlineEditsSideBySideView extends Disposable implements IInlineEdit private readonly previewRef = n.ref(); - private readonly _editorContainer = n.div({ - class: ['editorContainer', this._editorObs.getOption(EditorOption.inlineSuggest).map(v => !v.edits.useGutterIndicator && 'showHover')], - style: { position: 'absolute', overflow: 'hidden', cursor: 'pointer' }, - onclick: (e) => { - this._onDidClick.fire(new StandardMouseEvent(getWindow(e), e)); - } - }, [ - n.div({ class: 'preview', style: { pointerEvents: 'none' }, ref: this.previewRef }), - ]).keepUpdated(this._store); - - public readonly isHovered = this._editorContainer.didMouseMoveDuringHover; - - public readonly previewEditor = this._register(this._instantiationService.createInstance( - EmbeddedCodeEditorWidget, - this.previewRef.element, - { - glyphMargin: false, - lineNumbers: 'off', - minimap: { enabled: false }, - guides: { - indentation: false, - bracketPairs: false, - bracketPairsHorizontal: false, - highlightActiveIndentation: false, - }, - rulers: [], - padding: { top: 0, bottom: 0 }, - folding: false, - selectOnLineNumbers: false, - selectionHighlight: false, - columnSelection: false, - overviewRulerBorder: false, - overviewRulerLanes: 0, - lineDecorationsWidth: 0, - lineNumbersMinChars: 0, - revealHorizontalRightPadding: 0, - bracketPairColorization: { enabled: true, independentColorPoolPerBracketType: false }, - scrollBeyondLastLine: false, - scrollbar: { - vertical: 'hidden', - horizontal: 'hidden', - handleMouseWheel: false, - }, - readOnly: true, - wordWrap: 'off', - wordWrapOverride1: 'off', - wordWrapOverride2: 'off', - }, - { - contextKeyValues: { - [InlineCompletionContextKeys.inInlineEditsPreviewEditor.key]: true, - }, - contributions: [], - }, - this._editor - )); - - private readonly _previewEditorObs = observableCodeEditor(this.previewEditor); - - private _activeViewZones: string[] = []; - private readonly _updatePreviewEditor = derived(reader => { - this._editorContainer.readEffect(reader); - this._previewEditorObs.model.read(reader); // update when the model is set - - // Setting this here explicitly to make sure that the preview editor is - // visible when needed, we're also checking that these fields are defined - // because of the auto run initial - // Before removing these, verify with a non-monospace font family - this._display.read(reader); - if (this._overflowView) { - this._overflowView.element.style.display = this._display.read(reader); - } - if (this._nonOverflowView) { - this._nonOverflowView.element.style.display = this._display.read(reader); - } - - const uiState = this._uiState.read(reader); - if (!uiState) { - return; - } + private readonly _editorContainer: ObserverNodeWithElement; - const range = uiState.edit.originalLineRange; - - const hiddenAreas: Range[] = []; - if (range.startLineNumber > 1) { - hiddenAreas.push(new Range(1, 1, range.startLineNumber - 1, 1)); - } - if (range.startLineNumber + uiState.newTextLineCount < this._previewTextModel.getLineCount() + 1) { - hiddenAreas.push(new Range(range.startLineNumber + uiState.newTextLineCount, 1, this._previewTextModel.getLineCount() + 1, 1)); - } + public readonly isHovered: IObservable; - this.previewEditor.setHiddenAreas(hiddenAreas, undefined, true); + public readonly previewEditor: EmbeddedCodeEditorWidget; - // TODO: is this the proper way to handle viewzones? - const previousViewZones = [...this._activeViewZones]; - this._activeViewZones = []; + private readonly _previewEditorObs: ObservableCodeEditor; - const reducedLinesCount = (range.endLineNumberExclusive - range.startLineNumber) - uiState.newTextLineCount; - this.previewEditor.changeViewZones((changeAccessor) => { - previousViewZones.forEach(id => changeAccessor.removeZone(id)); - - if (reducedLinesCount > 0) { - this._activeViewZones.push(changeAccessor.addZone({ - afterLineNumber: range.startLineNumber + uiState.newTextLineCount - 1, - heightInLines: reducedLinesCount, - showInHiddenAreas: true, - domNode: $('div.diagonal-fill.inline-edits-view-zone'), - })); - } - }); - - }).recomputeInitiallyAndOnChange(this._store); + private _activeViewZones: string[] = []; + private readonly _updatePreviewEditor: IObservable; private readonly _previewEditorWidth = derived(this, reader => { const edit = this._edit.read(reader); @@ -260,10 +284,10 @@ export class InlineEditsSideBySideView extends Disposable implements IInlineEdit return inlineEdit ? new Position(inlineEdit.originalLineRange.endLineNumberExclusive, 1) : null; }); - private readonly _originalVerticalStartPosition = this._editorObs.observePosition(this._originalStartPosition, this._store).map(p => p?.y); - private readonly _originalVerticalEndPosition = this._editorObs.observePosition(this._originalEndPosition, this._store).map(p => p?.y); + private readonly _originalVerticalStartPosition: IObservable; + private readonly _originalVerticalEndPosition: IObservable; - private readonly _originalDisplayRange = this._uiState.map(s => s?.originalDisplayRange); + private readonly _originalDisplayRange: IObservable; private readonly _editorMaxContentWidthInRange = derived(this, reader => { const originalDisplayRange = this._originalDisplayRange.read(reader); if (!originalDisplayRange) { @@ -380,8 +404,8 @@ export class InlineEditsSideBySideView extends Disposable implements IInlineEdit }; }); - private _stickyScrollController = StickyScrollController.get(this._editorObs.editor); - private readonly _stickyScrollHeight = this._stickyScrollController ? observableFromEvent(this._stickyScrollController.onDidChangeStickyScrollHeight, () => this._stickyScrollController!.stickyScrollWidgetHeight) : constObservable(0); + private _stickyScrollController: IStickyScrollController | null; + private readonly _stickyScrollHeight: IObservable; private readonly _shouldOverflow = derived(reader => { if (!ENABLE_OVERFLOW) { @@ -424,9 +448,7 @@ export class InlineEditsSideBySideView extends Disposable implements IInlineEdit return path.build(); }); - private readonly _originalBackgroundColor = observableFromEvent(this, this._themeService.onDidColorThemeChange, () => { - return this._themeService.getColorTheme().getColor(originalBackgroundColor) ?? Color.transparent; - }); + private readonly _originalBackgroundColor: IObservable; private readonly _backgroundSvg = n.svg({ transform: 'translate(-0.5 -0.5)', diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsWordInsertView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsWordInsertView.ts index d3ee68c60cc33..2551d8033bab5 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsWordInsertView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsWordInsertView.ts @@ -23,7 +23,7 @@ export class InlineEditsWordInsertView extends Disposable implements IInlineEdit private readonly _onDidClick = this._register(new Emitter()); readonly onDidClick = this._onDidClick.event; - private readonly _start = this._editor.observePosition(constObservable(this._edit.range.getStartPosition()), this._store); + private readonly _start: IObservable; private readonly _layout = derived(this, reader => { const start = this._start.read(reader); @@ -125,6 +125,8 @@ export class InlineEditsWordInsertView extends Disposable implements IInlineEdit ) { super(); + this._start = this._editor.observePosition(constObservable(this._edit.range.getStartPosition()), this._store); + this._register(this._editor.createOverlayWidget({ domNode: this._div.element, minContentWidthInPx: constObservable(0), diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsWordReplacementView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsWordReplacementView.ts index 6303d79558114..47faf0848ec9c 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsWordReplacementView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/inlineEditsWordReplacementView.ts @@ -7,7 +7,7 @@ import { getWindow, n, ObserverNodeWithElement } from '../../../../../../../base import { IMouseEvent, StandardMouseEvent } from '../../../../../../../base/browser/mouseEvent.js'; import { Emitter } from '../../../../../../../base/common/event.js'; import { Disposable } from '../../../../../../../base/common/lifecycle.js'; -import { constObservable, derived, observableValue } from '../../../../../../../base/common/observable.js'; +import { constObservable, derived, IObservable, observableValue } from '../../../../../../../base/common/observable.js'; import { editorBackground, editorHoverForeground, scrollbarShadow } from '../../../../../../../platform/theme/common/colorRegistry.js'; import { asCssVariable } from '../../../../../../../platform/theme/common/colorUtils.js'; import { ObservableCodeEditor } from '../../../../../../browser/observableCodeEditor.js'; @@ -33,8 +33,8 @@ export class InlineEditsWordReplacementView extends Disposable implements IInlin private readonly _onDidClick = this._register(new Emitter()); readonly onDidClick = this._onDidClick.event; - private readonly _start = this._editor.observePosition(constObservable(this._edit.range.getStartPosition()), this._store); - private readonly _end = this._editor.observePosition(constObservable(this._edit.range.getEndPosition()), this._store); + private readonly _start: IObservable; + private readonly _end: IObservable; private readonly _line = document.createElement('div'); @@ -52,6 +52,15 @@ export class InlineEditsWordReplacementView extends Disposable implements IInlin ) { super(); + this._start = this._editor.observePosition(constObservable(this._edit.range.getStartPosition()), this._store); + this._end = this._editor.observePosition(constObservable(this._edit.range.getEndPosition()), this._store); + + this._editLocations = this._innerEdits.map(edit => { + const start = this._editor.observePosition(constObservable(edit.range.getStartPosition()), this._store); + const end = this._editor.observePosition(constObservable(edit.range.getEndPosition()), this._store); + return { start, end, edit }; + }); + this._register(this._editor.createOverlayWidget({ domNode: this._root.element, minContentWidthInPx: constObservable(0), @@ -76,11 +85,11 @@ export class InlineEditsWordReplacementView extends Disposable implements IInlin renderLines(new LineSource([tokens]), RenderOptions.fromEditor(this._editor.editor).withSetWidth(false), [], this._line, true); }); - private readonly _editLocations = this._innerEdits.map(edit => { - const start = this._editor.observePosition(constObservable(edit.range.getStartPosition()), this._store); - const end = this._editor.observePosition(constObservable(edit.range.getEndPosition()), this._store); - return { start, end, edit }; - }); + private readonly _editLocations: Array<{ + start: IObservable; + end: IObservable; + edit: SingleTextEdit; + }>; private readonly _layout = derived(this, reader => { this._renderTextEffect.read(reader); diff --git a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/originalEditorInlineDiffView.ts b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/originalEditorInlineDiffView.ts index 414f455553d72..39e80e3dbbc8a 100644 --- a/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/originalEditorInlineDiffView.ts +++ b/src/vs/editor/contrib/inlineCompletions/browser/view/inlineEdits/inlineEditsViews/originalEditorInlineDiffView.ts @@ -40,12 +40,9 @@ export class OriginalEditorInlineDiffView extends Disposable implements IInlineE private readonly _onDidClick = this._register(new Emitter()); readonly onDidClick = this._onDidClick.event; - readonly isHovered = observableCodeEditor(this._originalEditor).isTargetHovered( - p => p.target.type === MouseTargetType.CONTENT_TEXT && p.target.detail.injectedText?.options.attachedData instanceof InlineEditAttachedData, - this._store - ); + readonly isHovered: IObservable; - private readonly _tokenizationFinished = modelTokenizationFinished(this._modifiedTextModel); + private readonly _tokenizationFinished: IObservable; constructor( private readonly _originalEditor: ICodeEditor, @@ -54,6 +51,13 @@ export class OriginalEditorInlineDiffView extends Disposable implements IInlineE ) { super(); + this.isHovered = observableCodeEditor(this._originalEditor).isTargetHovered( + p => p.target.type === MouseTargetType.CONTENT_TEXT && p.target.detail.injectedText?.options.attachedData instanceof InlineEditAttachedData, + this._store + ); + + this._tokenizationFinished = modelTokenizationFinished(this._modifiedTextModel); + this._register(observableCodeEditor(this._originalEditor).setDecorations(this._decorations.map(d => d?.originalDecorations ?? []))); const modifiedCodeEditor = this._state.map(s => s?.modifiedCodeEditor); diff --git a/src/vs/editor/contrib/multicursor/browser/multicursor.ts b/src/vs/editor/contrib/multicursor/browser/multicursor.ts index c3bcf55dd7ce7..195c61192cb86 100644 --- a/src/vs/editor/contrib/multicursor/browser/multicursor.ts +++ b/src/vs/editor/contrib/multicursor/browser/multicursor.ts @@ -803,7 +803,7 @@ export class CompatChangeAll extends MultiCursorSelectionControllerAction { } class SelectionHighlighterState { - private readonly _modelVersionId: number = this._model.getVersionId(); + private readonly _modelVersionId: number; private _cachedFindMatches: Range[] | null = null; constructor( @@ -813,6 +813,8 @@ class SelectionHighlighterState { private readonly _wordSeparators: string | null, prevState: SelectionHighlighterState | null ) { + this._modelVersionId = this._model.getVersionId(); + if (prevState && this._model === prevState._model && this._searchText === prevState._searchText diff --git a/src/vs/editor/contrib/placeholderText/browser/placeholderTextContribution.ts b/src/vs/editor/contrib/placeholderText/browser/placeholderTextContribution.ts index b06224c3e9d91..445322d1f2318 100644 --- a/src/vs/editor/contrib/placeholderText/browser/placeholderTextContribution.ts +++ b/src/vs/editor/contrib/placeholderText/browser/placeholderTextContribution.ts @@ -8,7 +8,7 @@ import { structuralEquals } from '../../../../base/common/equals.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; import { autorun, constObservable, DebugOwner, derivedObservableWithCache, derivedOpts, derivedWithStore, IObservable, IReader } from '../../../../base/common/observable.js'; import { ICodeEditor } from '../../../browser/editorBrowser.js'; -import { observableCodeEditor } from '../../../browser/observableCodeEditor.js'; +import { ObservableCodeEditor, observableCodeEditor } from '../../../browser/observableCodeEditor.js'; import { EditorOption } from '../../../common/config/editorOptions.js'; import { IEditorContribution } from '../../../common/editorCommon.js'; @@ -21,9 +21,9 @@ export class PlaceholderTextContribution extends Disposable implements IEditorCo } public static readonly ID = 'editor.contrib.placeholderText'; - private readonly _editorObs = observableCodeEditor(this._editor); + private readonly _editorObs: ObservableCodeEditor; - private readonly _placeholderText = this._editorObs.getOption(EditorOption.placeholder); + private readonly _placeholderText: IObservable; private readonly _state = derivedOpts<{ placeholder: string } | undefined>({ owner: this, equalsFn: structuralEquals }, reader => { const p = this._placeholderText.read(reader); @@ -68,6 +68,11 @@ export class PlaceholderTextContribution extends Disposable implements IEditorCo private readonly _editor: ICodeEditor, ) { super(); + + this._editorObs = observableCodeEditor(this._editor); + + this._placeholderText = this._editorObs.getOption(EditorOption.placeholder); + this._view.recomputeInitiallyAndOnChange(this._store); } } diff --git a/src/vs/editor/contrib/sectionHeaders/browser/sectionHeaders.ts b/src/vs/editor/contrib/sectionHeaders/browser/sectionHeaders.ts index 01b574130290d..d5b447e12f89a 100644 --- a/src/vs/editor/contrib/sectionHeaders/browser/sectionHeaders.ts +++ b/src/vs/editor/contrib/sectionHeaders/browser/sectionHeaders.ts @@ -8,7 +8,7 @@ import { Disposable } from '../../../../base/common/lifecycle.js'; import { ICodeEditor } from '../../../browser/editorBrowser.js'; import { EditorContributionInstantiation, registerEditorContribution } from '../../../browser/editorExtensions.js'; import { EditorOption, IEditorMinimapOptions } from '../../../common/config/editorOptions.js'; -import { IEditorContribution } from '../../../common/editorCommon.js'; +import { IEditorContribution, IEditorDecorationsCollection } from '../../../common/editorCommon.js'; import { StandardTokenType } from '../../../common/encodedTokenAttributes.js'; import { ILanguageConfigurationService } from '../../../common/languages/languageConfigurationRegistry.js'; import { IModelDeltaDecoration, MinimapPosition, MinimapSectionHeaderStyle, TrackedRangeStickiness } from '../../../common/model.js'; @@ -21,7 +21,7 @@ export class SectionHeaderDetector extends Disposable implements IEditorContribu public static readonly ID: string = 'editor.sectionHeaderDetector'; private options: FindSectionHeaderOptions | undefined; - private decorations = this.editor.createDecorationsCollection(); + private decorations: IEditorDecorationsCollection; private computeSectionHeaders: RunOnceScheduler; private computePromise: CancelablePromise | null; private currentOccurrences: { [decorationId: string]: SectionHeaderOccurrence }; @@ -34,6 +34,7 @@ export class SectionHeaderDetector extends Disposable implements IEditorContribu super(); this.options = this.createOptions(editor.getOption(EditorOption.minimap)); + this.decorations = this.editor.createDecorationsCollection(); this.computePromise = null; this.currentOccurrences = {}; diff --git a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts index fada2e0c7cffc..ebdeb38f0d999 100644 --- a/src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts +++ b/src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts @@ -57,7 +57,7 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget { private readonly _linesDomNode: HTMLElement = document.createElement('div'); private _previousState: StickyScrollWidgetState | undefined; - private _lineHeight: number = this._editor.getOption(EditorOption.lineHeight); + private _lineHeight: number; private _renderedStickyLines: RenderedStickyLine[] = []; private _lineNumbers: number[] = []; private _lastLineRelativePosition: number = 0; @@ -75,6 +75,8 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget { ) { super(); + this._lineHeight = this._editor.getOption(EditorOption.lineHeight); + this._lineNumbersDomNode.className = 'sticky-widget-line-numbers'; this._lineNumbersDomNode.setAttribute('role', 'none'); diff --git a/src/vs/editor/contrib/unicodeHighlighter/browser/unicodeHighlighter.ts b/src/vs/editor/contrib/unicodeHighlighter/browser/unicodeHighlighter.ts index e39eaa2eb5533..2ddca5f828f93 100644 --- a/src/vs/editor/contrib/unicodeHighlighter/browser/unicodeHighlighter.ts +++ b/src/vs/editor/contrib/unicodeHighlighter/browser/unicodeHighlighter.ts @@ -15,7 +15,7 @@ import { IActiveCodeEditor, ICodeEditor } from '../../../browser/editorBrowser.j import { EditorAction, EditorContributionInstantiation, registerEditorAction, registerEditorContribution, ServicesAccessor } from '../../../browser/editorExtensions.js'; import { InUntrustedWorkspace, inUntrustedWorkspace, EditorOption, InternalUnicodeHighlightOptions, unicodeHighlightConfigKeys } from '../../../common/config/editorOptions.js'; import { Range } from '../../../common/core/range.js'; -import { IEditorContribution } from '../../../common/editorCommon.js'; +import { IEditorContribution, IEditorDecorationsCollection } from '../../../common/editorCommon.js'; import { IModelDecoration, IModelDeltaDecoration, ITextModel, TrackedRangeStickiness } from '../../../common/model.js'; import { ModelDecorationOptions } from '../../../common/model/textModel.js'; import { UnicodeHighlighterOptions, UnicodeHighlighterReason, UnicodeHighlighterReasonKind, UnicodeTextModelHighlighter } from '../../../common/services/unicodeTextModelHighlighter.js'; @@ -212,9 +212,9 @@ function resolveOptions(trusted: boolean, options: InternalUnicodeHighlightOptio } class DocumentUnicodeHighlighter extends Disposable { - private readonly _model: ITextModel = this._editor.getModel(); + private readonly _model: ITextModel; private readonly _updateSoon: RunOnceScheduler; - private _decorations = this._editor.createDecorationsCollection(); + private _decorations: IEditorDecorationsCollection; constructor( private readonly _editor: IActiveCodeEditor, @@ -223,7 +223,9 @@ class DocumentUnicodeHighlighter extends Disposable { @IEditorWorkerService private readonly _editorWorkerService: IEditorWorkerService, ) { super(); + this._model = this._editor.getModel(); this._updateSoon = this._register(new RunOnceScheduler(() => this._update(), 250)); + this._decorations = this._editor.createDecorationsCollection(); this._register(this._editor.onDidChangeModelContent(() => { this._updateSoon.schedule(); @@ -296,9 +298,9 @@ class DocumentUnicodeHighlighter extends Disposable { class ViewportUnicodeHighlighter extends Disposable { - private readonly _model: ITextModel = this._editor.getModel(); + private readonly _model: ITextModel; private readonly _updateSoon: RunOnceScheduler; - private readonly _decorations = this._editor.createDecorationsCollection(); + private readonly _decorations: IEditorDecorationsCollection; constructor( private readonly _editor: IActiveCodeEditor, @@ -307,7 +309,9 @@ class ViewportUnicodeHighlighter extends Disposable { ) { super(); + this._model = this._editor.getModel(); this._updateSoon = this._register(new RunOnceScheduler(() => this._update(), 250)); + this._decorations = this._editor.createDecorationsCollection(); this._register(this._editor.onDidLayoutChange(() => { this._updateSoon.schedule(); diff --git a/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts b/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts index 611fcb7e21c15..2a65960d9831c 100644 --- a/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts +++ b/src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts @@ -117,13 +117,15 @@ class Arrow { private static readonly _IdGenerator = new IdGenerator('.arrow-decoration-'); private readonly _ruleName = Arrow._IdGenerator.nextId(); - private readonly _decorations = this._editor.createDecorationsCollection(); + private readonly _decorations: IEditorDecorationsCollection; private _color: string | null = null; private _height: number = -1; constructor( private readonly _editor: ICodeEditor - ) { } + ) { + this._decorations = this._editor.createDecorationsCollection(); + } dispose(): void { this.hide(); diff --git a/src/vs/editor/standalone/browser/quickInput/standaloneQuickInputService.ts b/src/vs/editor/standalone/browser/quickInput/standaloneQuickInputService.ts index 03a2821ce51be..0b0da3e8e3771 100644 --- a/src/vs/editor/standalone/browser/quickInput/standaloneQuickInputService.ts +++ b/src/vs/editor/standalone/browser/quickInput/standaloneQuickInputService.ts @@ -174,9 +174,11 @@ export class QuickInputEditorContribution implements IEditorContribution { return editor.getContribution(QuickInputEditorContribution.ID); } - readonly widget = new QuickInputEditorWidget(this.editor); + readonly widget: QuickInputEditorWidget; - constructor(private editor: ICodeEditor) { } + constructor(private editor: ICodeEditor) { + this.widget = new QuickInputEditorWidget(this.editor); + } dispose(): void { this.widget.dispose(); diff --git a/src/vs/platform/accessibilitySignal/browser/accessibilitySignalService.ts b/src/vs/platform/accessibilitySignal/browser/accessibilitySignalService.ts index 0e919686c6a24..43a2357bef906 100644 --- a/src/vs/platform/accessibilitySignal/browser/accessibilitySignalService.ts +++ b/src/vs/platform/accessibilitySignal/browser/accessibilitySignalService.ts @@ -8,7 +8,7 @@ import { getStructuralKey } from '../../../base/common/equals.js'; import { Event, IValueWithChangeEvent } from '../../../base/common/event.js'; import { Disposable, IDisposable, toDisposable } from '../../../base/common/lifecycle.js'; import { FileAccess } from '../../../base/common/network.js'; -import { derived, observableFromEvent, ValueWithChangeEventFromObservable } from '../../../base/common/observable.js'; +import { derived, IObservable, observableFromEvent, ValueWithChangeEventFromObservable } from '../../../base/common/observable.js'; import { localize } from '../../../nls.js'; import { IAccessibilityService } from '../../accessibility/common/accessibility.js'; import { IConfigurationService } from '../../configuration/common/configuration.js'; @@ -66,10 +66,7 @@ export interface IAccessbilitySignalOptions { export class AccessibilitySignalService extends Disposable implements IAccessibilitySignalService { readonly _serviceBrand: undefined; private readonly sounds: Map = new Map(); - private readonly screenReaderAttached = observableFromEvent(this, - this.accessibilityService.onDidChangeScreenReaderOptimized, - () => /** @description accessibilityService.onDidChangeScreenReaderOptimized */ this.accessibilityService.isScreenReaderOptimized() - ); + private readonly screenReaderAttached: IObservable; private readonly sentTelemetry = new Set(); constructor( @@ -78,6 +75,33 @@ export class AccessibilitySignalService extends Disposable implements IAccessibi @ITelemetryService private readonly telemetryService: ITelemetryService, ) { super(); + + this.screenReaderAttached = observableFromEvent(this, + this.accessibilityService.onDidChangeScreenReaderOptimized, + () => /** @description accessibilityService.onDidChangeScreenReaderOptimized */ this.accessibilityService.isScreenReaderOptimized() + ); + + this._signalEnabledState = new CachedFunction( + { getCacheKey: getStructuralKey }, + (arg: { signal: AccessibilitySignal; userGesture: boolean; modality?: AccessibilityModality | undefined }) => { + return derived(reader => { + /** @description sound enabled */ + const setting = this._signalConfigValue.get(arg.signal).read(reader); + + if (arg.modality === 'sound' || arg.modality === undefined) { + if (checkEnabledState(setting.sound, () => this.screenReaderAttached.read(reader), arg.userGesture)) { + return true; + } + } + if (arg.modality === 'announcement' || arg.modality === undefined) { + if (checkEnabledState(setting.announcement, () => this.screenReaderAttached.read(reader), arg.userGesture)) { + return true; + } + } + return false; + }).recomputeInitiallyAndOnChange(this._store); + } + ); } public getEnabledState(signal: AccessibilitySignal, userGesture: boolean, modality?: AccessibilityModality | undefined): IValueWithChangeEvent { @@ -203,27 +227,11 @@ export class AccessibilitySignalService extends Disposable implements IAccessibi announcement: EnabledState; }>(signal.settingsKey, { sound: 'off', announcement: 'off' }, this.configurationService)); - private readonly _signalEnabledState = new CachedFunction( - { getCacheKey: getStructuralKey }, - (arg: { signal: AccessibilitySignal; userGesture: boolean; modality?: AccessibilityModality | undefined }) => { - return derived(reader => { - /** @description sound enabled */ - const setting = this._signalConfigValue.get(arg.signal).read(reader); - - if (arg.modality === 'sound' || arg.modality === undefined) { - if (checkEnabledState(setting.sound, () => this.screenReaderAttached.read(reader), arg.userGesture)) { - return true; - } - } - if (arg.modality === 'announcement' || arg.modality === undefined) { - if (checkEnabledState(setting.announcement, () => this.screenReaderAttached.read(reader), arg.userGesture)) { - return true; - } - } - return false; - }).recomputeInitiallyAndOnChange(this._store); - } - ); + private readonly _signalEnabledState: CachedFunction<{ + signal: AccessibilitySignal; + userGesture: boolean; + modality?: AccessibilityModality | undefined; + }, IObservable>; public isAnnouncementEnabled(signal: AccessibilitySignal, userGesture?: boolean): boolean { if (!signal.announcementMessage) { diff --git a/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindow.ts b/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindow.ts index 971d5cd6b2e97..683ca26d49b83 100644 --- a/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindow.ts +++ b/src/vs/platform/auxiliaryWindow/electron-main/auxiliaryWindow.ts @@ -20,7 +20,7 @@ export interface IAuxiliaryWindow extends IBaseWindow { export class AuxiliaryWindow extends BaseWindow implements IAuxiliaryWindow { - readonly id = this.webContents.id; + readonly id: number; parentId = -1; override get win() { @@ -43,6 +43,8 @@ export class AuxiliaryWindow extends BaseWindow implements IAuxiliaryWindow { ) { super(configurationService, stateService, environmentMainService, logService); + this.id = this.webContents.id; + // Try to claim window this.tryClaimWindow(); } diff --git a/src/vs/platform/backup/electron-main/backupMainService.ts b/src/vs/platform/backup/electron-main/backupMainService.ts index 36287ebc981f7..38f9c6ee60668 100644 --- a/src/vs/platform/backup/electron-main/backupMainService.ts +++ b/src/vs/platform/backup/electron-main/backupMainService.ts @@ -27,7 +27,7 @@ export class BackupMainService implements IBackupMainService { private static readonly backupWorkspacesMetadataStorageKey = 'backupWorkspaces'; - protected backupHome = this.environmentMainService.backupHome; + protected backupHome: string; private workspaces: IWorkspaceBackupInfo[] = []; private folders: IFolderBackupInfo[] = []; @@ -45,6 +45,7 @@ export class BackupMainService implements IBackupMainService { @ILogService private readonly logService: ILogService, @IStateService private readonly stateService: IStateService ) { + this.backupHome = this.environmentMainService.backupHome; } async initialize(): Promise { diff --git a/src/vs/platform/configuration/common/configurations.ts b/src/vs/platform/configuration/common/configurations.ts index 8d2671b4de955..64ab03fd976c4 100644 --- a/src/vs/platform/configuration/common/configurations.ts +++ b/src/vs/platform/configuration/common/configurations.ts @@ -22,13 +22,15 @@ export class DefaultConfiguration extends Disposable { private readonly _onDidChangeConfiguration = this._register(new Emitter<{ defaults: ConfigurationModel; properties: string[] }>()); readonly onDidChangeConfiguration = this._onDidChangeConfiguration.event; - private _configurationModel = ConfigurationModel.createEmptyModel(this.logService); + private _configurationModel: ConfigurationModel; get configurationModel(): ConfigurationModel { return this._configurationModel; } constructor(private readonly logService: ILogService) { super(); + + this._configurationModel = ConfigurationModel.createEmptyModel(this.logService); } async initialize(): Promise { @@ -91,7 +93,7 @@ export class PolicyConfiguration extends Disposable implements IPolicyConfigurat private readonly _onDidChangeConfiguration = this._register(new Emitter()); readonly onDidChangeConfiguration = this._onDidChangeConfiguration.event; - private _configurationModel = ConfigurationModel.createEmptyModel(this.logService); + private _configurationModel: ConfigurationModel; get configurationModel() { return this._configurationModel; } constructor( @@ -100,6 +102,8 @@ export class PolicyConfiguration extends Disposable implements IPolicyConfigurat @ILogService private readonly logService: ILogService ) { super(); + + this._configurationModel = ConfigurationModel.createEmptyModel(this.logService); } async initialize(): Promise { diff --git a/src/vs/platform/contextview/browser/contextViewService.ts b/src/vs/platform/contextview/browser/contextViewService.ts index 4ee1349dcce92..734a1f3260344 100644 --- a/src/vs/platform/contextview/browser/contextViewService.ts +++ b/src/vs/platform/contextview/browser/contextViewService.ts @@ -12,13 +12,15 @@ import { getWindow } from '../../../base/browser/dom.js'; export class ContextViewHandler extends Disposable implements IContextViewProvider { private openContextView: IOpenContextView | undefined; - protected readonly contextView = this._register(new ContextView(this.layoutService.mainContainer, ContextViewDOMPosition.ABSOLUTE)); + protected readonly contextView: ContextView; constructor( @ILayoutService private readonly layoutService: ILayoutService ) { super(); + this.contextView = this._register(new ContextView(this.layoutService.mainContainer, ContextViewDOMPosition.ABSOLUTE)); + this.layout(); this._register(layoutService.onDidLayoutContainer(() => this.layout())); } diff --git a/src/vs/platform/extensionManagement/common/extensionsScannerService.ts b/src/vs/platform/extensionManagement/common/extensionsScannerService.ts index c613e0669b4e7..0218a0b4ad2bc 100644 --- a/src/vs/platform/extensionManagement/common/extensionsScannerService.ts +++ b/src/vs/platform/extensionManagement/common/extensionsScannerService.ts @@ -149,9 +149,9 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem private readonly _onDidChangeCache = this._register(new Emitter()); readonly onDidChangeCache = this._onDidChangeCache.event; - private readonly systemExtensionsCachedScanner = this._register(this.instantiationService.createInstance(CachedExtensionsScanner, this.currentProfile)); - private readonly userExtensionsCachedScanner = this._register(this.instantiationService.createInstance(CachedExtensionsScanner, this.currentProfile)); - private readonly extensionsScanner = this._register(this.instantiationService.createInstance(ExtensionsScanner)); + private readonly systemExtensionsCachedScanner: CachedExtensionsScanner; + private readonly userExtensionsCachedScanner: CachedExtensionsScanner; + private readonly extensionsScanner: ExtensionsScanner; constructor( readonly systemExtensionsLocation: URI, @@ -169,6 +169,10 @@ export abstract class AbstractExtensionsScannerService extends Disposable implem ) { super(); + this.systemExtensionsCachedScanner = this._register(this.instantiationService.createInstance(CachedExtensionsScanner, this.currentProfile)); + this.userExtensionsCachedScanner = this._register(this.instantiationService.createInstance(CachedExtensionsScanner, this.currentProfile)); + this.extensionsScanner = this._register(this.instantiationService.createInstance(ExtensionsScanner)); + this._register(this.systemExtensionsCachedScanner.onDidChangeCache(() => this._onDidChangeCache.fire(ExtensionType.System))); this._register(this.userExtensionsCachedScanner.onDidChangeCache(() => this._onDidChangeCache.fire(ExtensionType.User))); } diff --git a/src/vs/platform/files/node/diskFileSystemProviderServer.ts b/src/vs/platform/files/node/diskFileSystemProviderServer.ts index d626904949efc..e60725d804060 100644 --- a/src/vs/platform/files/node/diskFileSystemProviderServer.ts +++ b/src/vs/platform/files/node/diskFileSystemProviderServer.ts @@ -272,7 +272,7 @@ export abstract class AbstractSessionFileWatcher extends Disposable implements I // This is important because we want to ensure that we only // forward events from the watched paths for this session and // not other clients that asked to watch other paths. - private readonly fileWatcher = this._register(new DiskFileSystemProvider(this.logService)); + private readonly fileWatcher: DiskFileSystemProvider; constructor( private readonly uriTransformer: IURITransformer, @@ -282,6 +282,8 @@ export abstract class AbstractSessionFileWatcher extends Disposable implements I ) { super(); + this.fileWatcher = this._register(new DiskFileSystemProvider(this.logService)); + this.registerListeners(sessionEmitter); } diff --git a/src/vs/platform/files/node/watcher/nodejs/nodejsWatcherLib.ts b/src/vs/platform/files/node/watcher/nodejs/nodejsWatcherLib.ts index b016dde0a9ffd..d10f6d35107e1 100644 --- a/src/vs/platform/files/node/watcher/nodejs/nodejsWatcherLib.ts +++ b/src/vs/platform/files/node/watcher/nodejs/nodejsWatcherLib.ts @@ -15,9 +15,10 @@ import { joinPath } from '../../../../../base/common/resources.js'; import { URI } from '../../../../../base/common/uri.js'; import { realpath } from '../../../../../base/node/extpath.js'; import { Promises } from '../../../../../base/node/pfs.js'; -import { FileChangeType, IFileChange } from '../../../common/files.js'; +import { FileChangeFilter, FileChangeType, IFileChange } from '../../../common/files.js'; import { ILogMessage, coalesceEvents, INonRecursiveWatchRequest, parseWatcherPatterns, IRecursiveWatcherWithSubscribe, isFiltered, isWatchRequestWithCorrelation } from '../../../common/watcher.js'; import { Lazy } from '../../../../../base/common/lazy.js'; +import { ParsedPattern } from '../../../../../base/common/glob.js'; export class NodeJSFileWatcherLibrary extends Disposable { @@ -50,9 +51,9 @@ export class NodeJSFileWatcherLibrary extends Disposable { // to coalesce events and reduce spam. private readonly fileChangesAggregator = this._register(new RunOnceWorker(events => this.handleFileChanges(events), NodeJSFileWatcherLibrary.FILE_CHANGES_HANDLER_DELAY)); - private readonly excludes = parseWatcherPatterns(this.request.path, this.request.excludes); - private readonly includes = this.request.includes ? parseWatcherPatterns(this.request.path, this.request.includes) : undefined; - private readonly filter = isWatchRequestWithCorrelation(this.request) ? this.request.filter : undefined; // filtering is only enabled when correlating because watchers are otherwise potentially reused + private readonly excludes: ParsedPattern[]; + private readonly includes: ParsedPattern[] | undefined; + private readonly filter: FileChangeFilter | undefined; private readonly cts = new CancellationTokenSource(); @@ -95,6 +96,10 @@ export class NodeJSFileWatcherLibrary extends Disposable { private verboseLogging?: boolean ) { super(); + + this.excludes = parseWatcherPatterns(this.request.path, this.request.excludes); + this.includes = this.request.includes ? parseWatcherPatterns(this.request.path, this.request.includes) : undefined; + this.filter = isWatchRequestWithCorrelation(this.request) ? this.request.filter : undefined; // filtering is only enabled when correlating because watchers are otherwise potentially reused } private async watch(): Promise { diff --git a/src/vs/platform/files/node/watcher/parcel/parcelWatcher.ts b/src/vs/platform/files/node/watcher/parcel/parcelWatcher.ts index a24ef066a5f7f..70a36d3be4866 100644 --- a/src/vs/platform/files/node/watcher/parcel/parcelWatcher.ts +++ b/src/vs/platform/files/node/watcher/parcel/parcelWatcher.ts @@ -12,7 +12,7 @@ import { CancellationToken, CancellationTokenSource } from '../../../../../base/ import { toErrorMessage } from '../../../../../base/common/errorMessage.js'; import { Emitter, Event } from '../../../../../base/common/event.js'; import { randomPath, isEqual, isEqualOrParent } from '../../../../../base/common/extpath.js'; -import { GLOBSTAR, patternsEquals } from '../../../../../base/common/glob.js'; +import { GLOBSTAR, ParsedPattern, patternsEquals } from '../../../../../base/common/glob.js'; import { BaseWatcher } from '../baseWatcher.js'; import { TernarySearchTree } from '../../../../../base/common/ternarySearchTree.js'; import { normalizeNFC } from '../../../../../base/common/normalization.js'; @@ -37,8 +37,8 @@ export class ParcelWatcherInstance extends Disposable { private didStop = false; get stopped(): boolean { return this.didStop; } - private readonly includes = this.request.includes ? parseWatcherPatterns(this.request.path, this.request.includes) : undefined; - private readonly excludes = this.request.excludes ? parseWatcherPatterns(this.request.path, this.request.excludes) : undefined; + private readonly includes: ParsedPattern[] | undefined; + private readonly excludes: ParsedPattern[] | undefined; private readonly subscriptions = new Map void>>(); @@ -65,6 +65,9 @@ export class ParcelWatcherInstance extends Disposable { ) { super(); + this.includes = this.request.includes ? parseWatcherPatterns(this.request.path, this.request.includes) : undefined; + this.excludes = this.request.excludes ? parseWatcherPatterns(this.request.path, this.request.excludes) : undefined; + this._register(toDisposable(() => this.subscriptions.clear())); } diff --git a/src/vs/platform/native/electron-main/nativeHostMainService.ts b/src/vs/platform/native/electron-main/nativeHostMainService.ts index c2241a9a4524e..fe6cd872bb800 100644 --- a/src/vs/platform/native/electron-main/nativeHostMainService.ts +++ b/src/vs/platform/native/electron-main/nativeHostMainService.ts @@ -73,6 +73,43 @@ export class NativeHostMainService extends Disposable implements INativeHostMain @IInstantiationService private readonly instantiationService: IInstantiationService ) { super(); + + this.onDidOpenMainWindow = Event.map(this.windowsMainService.onDidOpenWindow, window => window.id); + + this.onDidTriggerWindowSystemContextMenu = Event.any( + Event.map(this.windowsMainService.onDidTriggerSystemContextMenu, ({ window, x, y }) => ({ windowId: window.id, x, y })), + Event.map(this.auxiliaryWindowsMainService.onDidTriggerSystemContextMenu, ({ window, x, y }) => ({ windowId: window.id, x, y })) + ); + + this.onDidMaximizeWindow = Event.any( + Event.map(this.windowsMainService.onDidMaximizeWindow, window => window.id), + Event.map(this.auxiliaryWindowsMainService.onDidMaximizeWindow, window => window.id) + ); + this.onDidUnmaximizeWindow = Event.any( + Event.map(this.windowsMainService.onDidUnmaximizeWindow, window => window.id), + Event.map(this.auxiliaryWindowsMainService.onDidUnmaximizeWindow, window => window.id) + ); + + this.onDidChangeWindowFullScreen = Event.any( + Event.map(this.windowsMainService.onDidChangeFullScreen, e => ({ windowId: e.window.id, fullscreen: e.fullscreen })), + Event.map(this.auxiliaryWindowsMainService.onDidChangeFullScreen, e => ({ windowId: e.window.id, fullscreen: e.fullscreen })) + ); + + this.onDidFocusMainWindow = Event.any( + Event.map(Event.filter(Event.map(this.windowsMainService.onDidChangeWindowsCount, () => this.windowsMainService.getLastActiveWindow()), window => !!window), window => window!.id), + Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-focus', (event, window: BrowserWindow) => window.id), windowId => !!this.windowsMainService.getWindowById(windowId)) + ); + + this.onDidBlurMainOrAuxiliaryWindow = Event.any( + this.onDidBlurMainWindow, + Event.map(Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-blur', (event, window: BrowserWindow) => this.auxiliaryWindowsMainService.getWindowByWebContents(window.webContents)), window => !!window), window => window!.id) + ); + this.onDidFocusMainOrAuxiliaryWindow = Event.any( + this.onDidFocusMainWindow, + Event.map(Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-focus', (event, window: BrowserWindow) => this.auxiliaryWindowsMainService.getWindowByWebContents(window.webContents)), window => !!window), window => window!.id) + ); + + this.onDidChangeColorScheme = this.themeMainService.onDidChangeColorScheme; } @@ -85,45 +122,27 @@ export class NativeHostMainService extends Disposable implements INativeHostMain //#region Events - readonly onDidOpenMainWindow = Event.map(this.windowsMainService.onDidOpenWindow, window => window.id); + readonly onDidOpenMainWindow: Event; - readonly onDidTriggerWindowSystemContextMenu = Event.any( - Event.map(this.windowsMainService.onDidTriggerSystemContextMenu, ({ window, x, y }) => ({ windowId: window.id, x, y })), - Event.map(this.auxiliaryWindowsMainService.onDidTriggerSystemContextMenu, ({ window, x, y }) => ({ windowId: window.id, x, y })) - ); + readonly onDidTriggerWindowSystemContextMenu: Event<{ windowId: number; x: number; y: number }>; - readonly onDidMaximizeWindow = Event.any( - Event.map(this.windowsMainService.onDidMaximizeWindow, window => window.id), - Event.map(this.auxiliaryWindowsMainService.onDidMaximizeWindow, window => window.id) - ); - readonly onDidUnmaximizeWindow = Event.any( - Event.map(this.windowsMainService.onDidUnmaximizeWindow, window => window.id), - Event.map(this.auxiliaryWindowsMainService.onDidUnmaximizeWindow, window => window.id) - ); + readonly onDidMaximizeWindow: Event; + readonly onDidUnmaximizeWindow: Event; - readonly onDidChangeWindowFullScreen = Event.any( - Event.map(this.windowsMainService.onDidChangeFullScreen, e => ({ windowId: e.window.id, fullscreen: e.fullscreen })), - Event.map(this.auxiliaryWindowsMainService.onDidChangeFullScreen, e => ({ windowId: e.window.id, fullscreen: e.fullscreen })) - ); + readonly onDidChangeWindowFullScreen: Event<{ windowId: number; fullscreen: boolean }>; readonly onDidBlurMainWindow = Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-blur', (event, window: BrowserWindow) => window.id), windowId => !!this.windowsMainService.getWindowById(windowId)); - readonly onDidFocusMainWindow = Event.any( - Event.map(Event.filter(Event.map(this.windowsMainService.onDidChangeWindowsCount, () => this.windowsMainService.getLastActiveWindow()), window => !!window), window => window!.id), - Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-focus', (event, window: BrowserWindow) => window.id), windowId => !!this.windowsMainService.getWindowById(windowId)) - ); + readonly onDidFocusMainWindow: Event; readonly onDidBlurMainOrAuxiliaryWindow = Event.any( this.onDidBlurMainWindow, Event.map(Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-blur', (event, window: BrowserWindow) => this.auxiliaryWindowsMainService.getWindowByWebContents(window.webContents)), window => !!window), window => window!.id) ); - readonly onDidFocusMainOrAuxiliaryWindow = Event.any( - this.onDidFocusMainWindow, - Event.map(Event.filter(Event.fromNodeEventEmitter(app, 'browser-window-focus', (event, window: BrowserWindow) => this.auxiliaryWindowsMainService.getWindowByWebContents(window.webContents)), window => !!window), window => window!.id) - ); + readonly onDidFocusMainOrAuxiliaryWindow: Event; readonly onDidResumeOS = Event.fromNodeEventEmitter(powerMonitor, 'resume'); - readonly onDidChangeColorScheme = this.themeMainService.onDidChangeColorScheme; + readonly onDidChangeColorScheme: Event; private readonly _onDidChangePassword = this._register(new Emitter<{ account: string; service: string }>()); readonly onDidChangePassword = this._onDidChangePassword.event; diff --git a/src/vs/platform/quickinput/browser/commandsQuickAccess.ts b/src/vs/platform/quickinput/browser/commandsQuickAccess.ts index 513641b4da512..5f47a8ad141fd 100644 --- a/src/vs/platform/quickinput/browser/commandsQuickAccess.ts +++ b/src/vs/platform/quickinput/browser/commandsQuickAccess.ts @@ -49,7 +49,7 @@ export abstract class AbstractCommandsQuickAccessProvider extends PickerQuickAcc private static WORD_FILTER = or(matchesPrefix, matchesWords, matchesContiguousSubString); - private readonly commandsHistory = this._register(this.instantiationService.createInstance(CommandsHistory)); + private readonly commandsHistory: CommandsHistory; protected override readonly options: ICommandsQuickAccessOptions; @@ -63,6 +63,8 @@ export abstract class AbstractCommandsQuickAccessProvider extends PickerQuickAcc ) { super(AbstractCommandsQuickAccessProvider.PREFIX, options); + this.commandsHistory = this._register(this.instantiationService.createInstance(CommandsHistory)); + this.options = options; } diff --git a/src/vs/platform/quickinput/browser/quickInputController.ts b/src/vs/platform/quickinput/browser/quickInputController.ts index afed745b58e23..6a2e4994996ed 100644 --- a/src/vs/platform/quickinput/browser/quickInputController.ts +++ b/src/vs/platform/quickinput/browser/quickInputController.ts @@ -17,14 +17,14 @@ import { Disposable, DisposableStore, dispose } from '../../../base/common/lifec import Severity from '../../../base/common/severity.js'; import { isString } from '../../../base/common/types.js'; import { localize } from '../../../nls.js'; -import { IInputBox, IInputOptions, IKeyMods, IPickOptions, IQuickInput, IQuickInputButton, IQuickNavigateConfiguration, IQuickPick, IQuickPickItem, IQuickWidget, QuickInputHideReason, QuickPickInput, QuickPickFocus } from '../common/quickInput.js'; +import { IInputBox, IInputOptions, IKeyMods, IPickOptions, IQuickInput, IQuickInputButton, IQuickNavigateConfiguration, IQuickPick, IQuickPickItem, IQuickWidget, QuickInputHideReason, QuickPickInput, QuickPickFocus, QuickInputType } from '../common/quickInput.js'; import { QuickInputBox } from './quickInputBox.js'; import { QuickInputUI, Writeable, IQuickInputStyles, IQuickInputOptions, QuickPick, backButton, InputBox, Visibilities, QuickWidget, InQuickInputContextKey, QuickInputTypeContextKey, EndOfQuickInputBoxContextKey, QuickInputAlignmentContextKey } from './quickInput.js'; import { ILayoutService } from '../../layout/browser/layoutService.js'; import { mainWindow } from '../../../base/browser/window.js'; import { IInstantiationService } from '../../instantiation/common/instantiation.js'; import { QuickInputTree } from './quickInputTree.js'; -import { IContextKeyService } from '../../contextkey/common/contextkey.js'; +import { IContextKey, IContextKeyService } from '../../contextkey/common/contextkey.js'; import './quickInputActions.js'; import { autorun, observableValue } from '../../../base/common/observable.js'; import { StandardMouseEvent } from '../../../base/browser/mouseEvent.js'; @@ -75,9 +75,9 @@ export class QuickInputController extends Disposable { private viewState: QuickInputViewState | undefined; private dndController: QuickInputDragAndDropController | undefined; - private readonly inQuickInputContext = InQuickInputContextKey.bindTo(this.contextKeyService); - private readonly quickInputTypeContext = QuickInputTypeContextKey.bindTo(this.contextKeyService); - private readonly endOfQuickInputBoxContext = EndOfQuickInputBoxContextKey.bindTo(this.contextKeyService); + private readonly inQuickInputContext: IContextKey; + private readonly quickInputTypeContext: IContextKey; + private readonly endOfQuickInputBoxContext: IContextKey; constructor( private options: IQuickInputOptions, @@ -102,6 +102,9 @@ export class QuickInputController extends Disposable { } })); this.viewState = this.loadViewState(); + this.inQuickInputContext = InQuickInputContextKey.bindTo(this.contextKeyService); + this.quickInputTypeContext = QuickInputTypeContextKey.bindTo(this.contextKeyService); + this.endOfQuickInputBoxContext = EndOfQuickInputBoxContextKey.bindTo(this.contextKeyService); } private registerKeyModsListeners(window: Window, disposables: DisposableStore): void { @@ -911,7 +914,7 @@ class QuickInputDragAndDropController extends Disposable { private readonly _controlsOnLeft: boolean; private readonly _controlsOnRight: boolean; - private _quickInputAlignmentContext = QuickInputAlignmentContextKey.bindTo(this._contextKeyService); + private _quickInputAlignmentContext: IContextKey<'top' | 'center' | undefined>; constructor( private _container: HTMLElement, @@ -929,6 +932,7 @@ class QuickInputDragAndDropController extends Disposable { // Use CSS calculations to avoid having to force layout with `.clientWidth` this._controlsOnLeft = customTitleBar && platform === Platform.Mac; this._controlsOnRight = customTitleBar && (platform === Platform.Windows || platform === Platform.Linux); + this._quickInputAlignmentContext = QuickInputAlignmentContextKey.bindTo(this._contextKeyService); this._registerLayoutListener(); this.registerMouseListeners(); this.dndViewState.set({ ...initialViewState, done: true }, undefined); diff --git a/src/vs/platform/state/node/stateService.ts b/src/vs/platform/state/node/stateService.ts index 77f7c45bc118d..3522720644c11 100644 --- a/src/vs/platform/state/node/stateService.ts +++ b/src/vs/platform/state/node/stateService.ts @@ -25,7 +25,7 @@ export class FileStorage extends Disposable { private storage: StorageDatabase = Object.create(null); private lastSavedStorageContents = ''; - private readonly flushDelayer = this._register(new ThrottledDelayer(this.saveStrategy === SaveStrategy.IMMEDIATE ? 0 : 100 /* buffer saves over a short time */)); + private readonly flushDelayer: ThrottledDelayer; private initializing: Promise | undefined = undefined; private closing: Promise | undefined = undefined; @@ -37,6 +37,8 @@ export class FileStorage extends Disposable { private readonly fileService: IFileService, ) { super(); + + this.flushDelayer = this._register(new ThrottledDelayer(this.saveStrategy === SaveStrategy.IMMEDIATE ? 0 : 100 /* buffer saves over a short time */)); } init(): Promise { diff --git a/src/vs/platform/storage/common/storage.ts b/src/vs/platform/storage/common/storage.ts index b120f38a29634..1ed1603b1c4f3 100644 --- a/src/vs/platform/storage/common/storage.ts +++ b/src/vs/platform/storage/common/storage.ts @@ -328,11 +328,13 @@ export abstract class AbstractStorageService extends Disposable implements IStor private initializationPromise: Promise | undefined; - private readonly flushWhenIdleScheduler = this._register(new RunOnceScheduler(() => this.doFlushWhenIdle(), this.options.flushInterval)); + private readonly flushWhenIdleScheduler: RunOnceScheduler; private readonly runFlushWhenIdle = this._register(new MutableDisposable()); constructor(private readonly options: IStorageServiceOptions = { flushInterval: AbstractStorageService.DEFAULT_FLUSH_INTERVAL }) { super(); + + this.flushWhenIdleScheduler = this._register(new RunOnceScheduler(() => this.doFlushWhenIdle(), this.options.flushInterval)); } onDidChangeValue(scope: StorageScope.WORKSPACE, key: string | undefined, disposable: DisposableStore): Event; diff --git a/src/vs/platform/storage/common/storageService.ts b/src/vs/platform/storage/common/storageService.ts index c7181a897057c..b11a9bd1af1e4 100644 --- a/src/vs/platform/storage/common/storageService.ts +++ b/src/vs/platform/storage/common/storageService.ts @@ -17,16 +17,16 @@ import { IAnyWorkspaceIdentifier } from '../../workspace/common/workspace.js'; export class RemoteStorageService extends AbstractStorageService { - private readonly applicationStorageProfile = this.initialProfiles.defaultProfile; - private readonly applicationStorage = this.createApplicationStorage(); + private readonly applicationStorageProfile: IUserDataProfile; + private readonly applicationStorage: IStorage; - private profileStorageProfile = this.initialProfiles.currentProfile; + private profileStorageProfile: IUserDataProfile; private readonly profileStorageDisposables = this._register(new DisposableStore()); - private profileStorage = this.createProfileStorage(this.profileStorageProfile); + private profileStorage: IStorage; - private workspaceStorageId = this.initialWorkspace?.id; + private workspaceStorageId: string | undefined; private readonly workspaceStorageDisposables = this._register(new DisposableStore()); - private workspaceStorage = this.createWorkspaceStorage(this.initialWorkspace); + private workspaceStorage: IStorage | undefined; constructor( private readonly initialWorkspace: IAnyWorkspaceIdentifier | undefined, @@ -35,6 +35,15 @@ export class RemoteStorageService extends AbstractStorageService { private readonly environmentService: IEnvironmentService ) { super(); + + this.applicationStorageProfile = this.initialProfiles.defaultProfile; + this.applicationStorage = this.createApplicationStorage(); + + this.profileStorageProfile = this.initialProfiles.currentProfile; + this.profileStorage = this.createProfileStorage(this.profileStorageProfile); + + this.workspaceStorageId = this.initialWorkspace?.id; + this.workspaceStorage = this.createWorkspaceStorage(this.initialWorkspace); } private createApplicationStorage(): IStorage { diff --git a/src/vs/platform/storage/electron-main/storageMainService.ts b/src/vs/platform/storage/electron-main/storageMainService.ts index 94664c7eaef53..8dc07d18592d9 100644 --- a/src/vs/platform/storage/electron-main/storageMainService.ts +++ b/src/vs/platform/storage/electron-main/storageMainService.ts @@ -332,13 +332,15 @@ export class ApplicationStorageMainService extends AbstractStorageService implem declare readonly _serviceBrand: undefined; - readonly whenReady = this.storageMainService.applicationStorage.whenInit; + readonly whenReady: Promise; constructor( @IUserDataProfilesService private readonly userDataProfilesService: IUserDataProfilesService, @IStorageMainService private readonly storageMainService: IStorageMainService ) { super(); + + this.whenReady = this.storageMainService.applicationStorage.whenInit; } protected doInitialize(): Promise { diff --git a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts index 852d6a46115b3..a077daa156eb9 100644 --- a/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts +++ b/src/vs/platform/terminal/common/capabilities/commandDetectionCapability.ts @@ -28,7 +28,7 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe protected _commands: TerminalCommand[] = []; private _cwd: string | undefined; private _promptTerminator: string | undefined; - private _currentCommand: PartialTerminalCommand = new PartialTerminalCommand(this._terminal); + private _currentCommand: PartialTerminalCommand; private _commandMarkers: IMarker[] = []; private _dimensions: ITerminalDimensions; private __isCommandStorageDisabled: boolean = false; @@ -80,6 +80,8 @@ export class CommandDetectionCapability extends Disposable implements ICommandDe this._promptInputModel = this._register(new PromptInputModel(this._terminal, this.onCommandStarted, this.onCommandStartChanged, this.onCommandExecuted, this._logService)); + this._currentCommand = new PartialTerminalCommand(this._terminal); + // Pull command line from the buffer if it was not set explicitly this._register(this.onCommandExecuted(command => { if (command.commandLineConfidence !== 'high') { diff --git a/src/vs/platform/terminal/node/ptyService.ts b/src/vs/platform/terminal/node/ptyService.ts index cb01a77585de1..cb45bc552c118 100644 --- a/src/vs/platform/terminal/node/ptyService.ts +++ b/src/vs/platform/terminal/node/ptyService.ts @@ -78,7 +78,7 @@ export class PtyService extends Disposable implements IPtyService { // #region Pty service contribution RPC calls - private readonly _autoRepliesContribution = new AutoRepliesPtyServiceContribution(this._logService); + private readonly _autoRepliesContribution: AutoRepliesPtyServiceContribution; @traceRpc async installAutoReply(match: string, reply: string) { await this._autoRepliesContribution.installAutoReply(match, reply); @@ -89,10 +89,7 @@ export class PtyService extends Disposable implements IPtyService { } // #endregion - - private readonly _contributions: IPtyServiceContribution[] = [ - this._autoRepliesContribution - ]; + private readonly _contributions: IPtyServiceContribution[]; private _lastPtyId: number = 0; @@ -139,6 +136,12 @@ export class PtyService extends Disposable implements IPtyService { ) { super(); + this._autoRepliesContribution = new AutoRepliesPtyServiceContribution(this._logService); + + this._contributions = [ + this._autoRepliesContribution + ]; + this._register(toDisposable(() => { for (const pty of this._ptys.values()) { pty.shutdown(true); diff --git a/src/vs/platform/userData/common/fileUserDataProvider.ts b/src/vs/platform/userData/common/fileUserDataProvider.ts index 1cfd07ec02b22..873d17b15789f 100644 --- a/src/vs/platform/userData/common/fileUserDataProvider.ts +++ b/src/vs/platform/userData/common/fileUserDataProvider.ts @@ -2,7 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Emitter } from '../../../base/common/event.js'; +import { Emitter, Event } from '../../../base/common/event.js'; import { Disposable, IDisposable, toDisposable } from '../../../base/common/lifecycle.js'; import { IFileSystemProviderWithFileReadWriteCapability, IFileChange, IWatchOptions, IStat, IFileOverwriteOptions, FileType, IFileWriteOptions, IFileDeleteOptions, FileSystemProviderCapabilities, IFileSystemProviderWithFileReadStreamCapability, IFileReadStreamOptions, IFileSystemProviderWithFileAtomicReadCapability, hasFileFolderCopyCapability, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileOpenOptions, IFileSystemProviderWithFileAtomicWriteCapability, IFileSystemProviderWithFileAtomicDeleteCapability, IFileSystemProviderWithFileFolderCopyCapability, IFileSystemProviderWithFileCloneCapability, hasFileCloneCapability, IFileAtomicReadOptions, IFileAtomicOptions } from '../../files/common/files.js'; import { URI } from '../../../base/common/uri.js'; @@ -29,8 +29,8 @@ export class FileUserDataProvider extends Disposable implements IFileSystemProviderWithFileAtomicDeleteCapability, IFileSystemProviderWithFileCloneCapability { - readonly capabilities = this.fileSystemProvider.capabilities; - readonly onDidChangeCapabilities = this.fileSystemProvider.onDidChangeCapabilities; + readonly capabilities: FileSystemProviderCapabilities; + readonly onDidChangeCapabilities: Event; private readonly _onDidChangeFile = this._register(new Emitter()); readonly onDidChangeFile = this._onDidChangeFile.event; @@ -47,6 +47,10 @@ export class FileUserDataProvider extends Disposable implements private readonly logService: ILogService, ) { super(); + + this.capabilities = this.fileSystemProvider.capabilities; + this.onDidChangeCapabilities = this.fileSystemProvider.onDidChangeCapabilities; + this.updateAtomicReadWritesResources(); this._register(userDataProfilesService.onDidChangeProfiles(() => this.updateAtomicReadWritesResources())); this._register(this.fileSystemProvider.onDidChangeFile(e => this.handleFileChanges(e))); diff --git a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts index 54408a57abae2..f6cab004d3904 100644 --- a/src/vs/platform/userDataSync/common/abstractSynchronizer.ts +++ b/src/vs/platform/userDataSync/common/abstractSynchronizer.ts @@ -145,13 +145,13 @@ export abstract class AbstractSynchroniser extends Disposable implements IUserDa readonly onDidChangeLocal: Event = this._onDidChangeLocal.event; protected readonly lastSyncResource: URI; - private readonly lastSyncUserDataStateKey = `${this.collection ? `${this.collection}.` : ''}${this.syncResource.syncResource}.lastSyncUserData`; + private readonly lastSyncUserDataStateKey: string; private hasSyncResourceStateVersionChanged: boolean = false; protected readonly syncResourceLogLabel: string; protected syncHeaders: IHeaders = {}; - readonly resource = this.syncResource.syncResource; + readonly resource: SyncResource; constructor( readonly syncResource: IUserDataSyncResource, @@ -173,6 +173,9 @@ export abstract class AbstractSynchroniser extends Disposable implements IUserDa this.syncFolder = this.extUri.joinPath(environmentService.userDataSyncHome, ...getPathSegments(syncResource.profile.isDefault ? undefined : syncResource.profile.id, syncResource.syncResource)); this.syncPreviewFolder = this.extUri.joinPath(this.syncFolder, PREVIEW_DIR_NAME); this.lastSyncResource = getLastSyncResourceUri(syncResource.profile.isDefault ? undefined : syncResource.profile.id, syncResource.syncResource, environmentService, this.extUri); + this.lastSyncUserDataStateKey = `${this.collection ? `${this.collection}.` : ''}${this.syncResource.syncResource}.lastSyncUserData`; + this.resource = this.syncResource.syncResource; + this.currentMachineIdPromise = getServiceMachineId(environmentService, fileService, storageService); } diff --git a/src/vs/platform/utilityProcess/electron-main/utilityProcessWorkerMainService.ts b/src/vs/platform/utilityProcess/electron-main/utilityProcessWorkerMainService.ts index 9ab01b9be15db..d4019edbe29dc 100644 --- a/src/vs/platform/utilityProcess/electron-main/utilityProcessWorkerMainService.ts +++ b/src/vs/platform/utilityProcess/electron-main/utilityProcessWorkerMainService.ts @@ -99,7 +99,7 @@ class UtilityProcessWorker extends Disposable { private readonly _onDidTerminate = this._register(new Emitter()); readonly onDidTerminate = this._onDidTerminate.event; - private readonly utilityProcess = this._register(new WindowUtilityProcess(this.logService, this.windowsMainService, this.telemetryService, this.lifecycleMainService)); + private readonly utilityProcess: WindowUtilityProcess; constructor( @ILogService private readonly logService: ILogService, @@ -110,6 +110,8 @@ class UtilityProcessWorker extends Disposable { ) { super(); + this.utilityProcess = this._register(new WindowUtilityProcess(this.logService, this.windowsMainService, this.telemetryService, this.lifecycleMainService)); + this.registerListeners(); } diff --git a/src/vs/platform/windows/electron-main/windowImpl.ts b/src/vs/platform/windows/electron-main/windowImpl.ts index 7ea47d522f8e7..4ea9b81c10f48 100644 --- a/src/vs/platform/windows/electron-main/windowImpl.ts +++ b/src/vs/platform/windows/electron-main/windowImpl.ts @@ -26,7 +26,7 @@ import { IFileService } from '../../files/common/files.js'; import { ILifecycleMainService } from '../../lifecycle/electron-main/lifecycleMainService.js'; import { ILogService } from '../../log/common/log.js'; import { IProductService } from '../../product/common/productService.js'; -import { IProtocolMainService } from '../../protocol/electron-main/protocol.js'; +import { IIPCObjectUrl, IProtocolMainService } from '../../protocol/electron-main/protocol.js'; import { resolveMarketplaceHeaders } from '../../externalServices/common/marketplace.js'; import { IApplicationStorageMainService, IStorageMainService } from '../../storage/electron-main/storageMainService.js'; import { ITelemetryService } from '../../telemetry/common/telemetry.js'; @@ -536,7 +536,7 @@ export class CodeWindow extends BaseWindow implements ICodeWindow { private customZoomLevel: number | undefined = undefined; - private readonly configObjectUrl = this._register(this.protocolMainService.createIPCObjectUrl()); + private readonly configObjectUrl: IIPCObjectUrl; private pendingLoadConfig: INativeWindowConfiguration | undefined; private wasLoaded = false; @@ -565,6 +565,8 @@ export class CodeWindow extends BaseWindow implements ICodeWindow { ) { super(configurationService, stateService, environmentMainService, logService); + this.configObjectUrl = this._register(this.protocolMainService.createIPCObjectUrl()); + //#region create browser window { // Load window state diff --git a/src/vs/platform/windows/electron-main/windowsMainService.ts b/src/vs/platform/windows/electron-main/windowsMainService.ts index d2ca2f8f6c7a4..0795d00546107 100644 --- a/src/vs/platform/windows/electron-main/windowsMainService.ts +++ b/src/vs/platform/windows/electron-main/windowsMainService.ts @@ -210,7 +210,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic private readonly windows = new Map(); - private readonly windowsStateHandler = this._register(new WindowsStateHandler(this, this.stateService, this.lifecycleMainService, this.logService, this.configurationService)); + private readonly windowsStateHandler: WindowsStateHandler; constructor( private readonly machineId: string, @@ -238,6 +238,8 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic ) { super(); + this.windowsStateHandler = this._register(new WindowsStateHandler(this, this.stateService, this.lifecycleMainService, this.logService, this.configurationService)); + this.registerListeners(); } diff --git a/src/vs/platform/windows/electron-main/windowsStateHandler.ts b/src/vs/platform/windows/electron-main/windowsStateHandler.ts index bd14cdbe3f4c0..1008f8217e59f 100644 --- a/src/vs/platform/windows/electron-main/windowsStateHandler.ts +++ b/src/vs/platform/windows/electron-main/windowsStateHandler.ts @@ -55,7 +55,7 @@ export class WindowsStateHandler extends Disposable { private static readonly windowsStateStorageKey = 'windowsState'; get state() { return this._state; } - private readonly _state = restoreWindowsState(this.stateService.getItem(WindowsStateHandler.windowsStateStorageKey)); + private readonly _state: IWindowsState; private lastClosedState: IWindowState | undefined = undefined; @@ -70,6 +70,8 @@ export class WindowsStateHandler extends Disposable { ) { super(); + this._state = restoreWindowsState(this.stateService.getItem(WindowsStateHandler.windowsStateStorageKey)); + this.registerListeners(); } diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index c6e7245ba7f8e..c4be1c9ade491 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -329,7 +329,7 @@ export function isWorkspaceFolder(thing: unknown): thing is IWorkspaceFolder { export class Workspace implements IWorkspace { - private _foldersMap: TernarySearchTree = TernarySearchTree.forUris(this._ignorePathCasing, () => true); + private _foldersMap: TernarySearchTree; private _folders!: WorkspaceFolder[]; constructor( @@ -339,6 +339,7 @@ export class Workspace implements IWorkspace { private _configuration: URI | null, private _ignorePathCasing: (key: URI) => boolean, ) { + this._foldersMap = TernarySearchTree.forUris(this._ignorePathCasing, () => true); this.folders = folders; } diff --git a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts index b42bd3ad67924..7d9348df50690 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts @@ -12,6 +12,7 @@ import { IWorkspaceIdentifier } from '../../workspace/common/workspace.js'; import { IWorkspacesHistoryMainService } from './workspacesHistoryMainService.js'; import { IWorkspacesManagementMainService } from './workspacesManagementMainService.js'; import { IWorkspaceBackupInfo, IFolderBackupInfo } from '../../backup/common/backup.js'; +import { Event as CommonEvent } from '../../../base/common/event.js'; export class WorkspacesMainService implements AddFirstParameterToFunctions /* only methods, not events */, number /* window ID */> { @@ -23,6 +24,7 @@ export class WorkspacesMainService implements AddFirstParameterToFunctions; getRecentlyOpened(windowId: number): Promise { return this.workspacesHistoryMainService.getRecentlyOpened(); diff --git a/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts index 33a585bd98220..64835d8b0ebcc 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesManagementMainService.ts @@ -64,7 +64,7 @@ export class WorkspacesManagementMainService extends Disposable implements IWork private readonly _onDidEnterWorkspace = this._register(new Emitter()); readonly onDidEnterWorkspace: Event = this._onDidEnterWorkspace.event; - private readonly untitledWorkspacesHome = this.environmentMainService.untitledWorkspacesHome; // local URI that contains all untitled workspaces + private readonly untitledWorkspacesHome: URI; // local URI that contains all untitled workspaces private untitledWorkspaces: IUntitledWorkspaceInfo[] = []; @@ -76,6 +76,8 @@ export class WorkspacesManagementMainService extends Disposable implements IWork @IDialogMainService private readonly dialogMainService: IDialogMainService ) { super(); + + this.untitledWorkspacesHome = this.environmentMainService.untitledWorkspacesHome; } async initialize(): Promise { diff --git a/src/vs/server/node/remoteExtensionHostAgentServer.ts b/src/vs/server/node/remoteExtensionHostAgentServer.ts index 8323d0f13d0aa..f595090a66fe1 100644 --- a/src/vs/server/node/remoteExtensionHostAgentServer.ts +++ b/src/vs/server/node/remoteExtensionHostAgentServer.ts @@ -64,7 +64,7 @@ class RemoteExtensionHostAgentServer extends Disposable implements IServerAPI { private readonly _managementConnections: { [reconnectionToken: string]: ManagementConnection }; private readonly _allReconnectionTokens: Set; private readonly _webClientServer: WebClientServer | null; - private readonly _webEndpointOriginChecker = WebEndpointOriginChecker.create(this._productService); + private readonly _webEndpointOriginChecker: WebEndpointOriginChecker; private readonly _serverBasePath: string | undefined; private readonly _serverProductPath: string; @@ -84,6 +84,8 @@ class RemoteExtensionHostAgentServer extends Disposable implements IServerAPI { ) { super(); + this._webEndpointOriginChecker = WebEndpointOriginChecker.create(this._productService); + if (serverBasePath !== undefined && serverBasePath.charCodeAt(serverBasePath.length - 1) === CharCode.Slash) { // Remove trailing slash from base path serverBasePath = serverBasePath.substring(0, serverBasePath.length - 1); diff --git a/src/vs/workbench/api/browser/mainThreadWorkspace.ts b/src/vs/workbench/api/browser/mainThreadWorkspace.ts index dae04c793583b..dee3a8dd514af 100644 --- a/src/vs/workbench/api/browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/browser/mainThreadWorkspace.ts @@ -39,7 +39,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { private readonly _toDispose = new DisposableStore(); private readonly _activeCancelTokens: { [id: number]: CancellationTokenSource } = Object.create(null); private readonly _proxy: ExtHostWorkspaceShape; - private readonly _queryBuilder = this._instantiationService.createInstance(QueryBuilder); + private readonly _queryBuilder: QueryBuilder; constructor( extHostContext: IExtHostContext, @@ -60,6 +60,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { @ITextFileService private readonly _textFileService: ITextFileService, ) { this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostWorkspace); + this._queryBuilder = this._instantiationService.createInstance(QueryBuilder); const workspace = this._contextService.getWorkspace(); // The workspace file is provided be a unknown file system provider. It might come // from the extension host. So initialize now knowing that `rootPath` is undefined. diff --git a/src/vs/workbench/api/common/extHostApiCommands.ts b/src/vs/workbench/api/common/extHostApiCommands.ts index 1d08ef2108224..9b0c135815f95 100644 --- a/src/vs/workbench/api/common/extHostApiCommands.ts +++ b/src/vs/workbench/api/common/extHostApiCommands.ts @@ -60,7 +60,7 @@ const newCommands: ApiCommand[] = [ range!: vscode.Range; selectionRange!: vscode.Range; children!: vscode.DocumentSymbol[]; - override containerName!: string; + declare containerName: string; } return value.map(MergedInfo.to); diff --git a/src/vs/workbench/api/common/extHostFileSystemEventService.ts b/src/vs/workbench/api/common/extHostFileSystemEventService.ts index 9bacc4ae0daa6..fe9c781877126 100644 --- a/src/vs/workbench/api/common/extHostFileSystemEventService.ts +++ b/src/vs/workbench/api/common/extHostFileSystemEventService.ts @@ -243,9 +243,11 @@ interface IExtensionListener { class LazyRevivedFileSystemEvents implements FileSystemEvents { - constructor(private readonly _events: FileSystemEvents) { } + constructor(private readonly _events: FileSystemEvents) { + this.session = this._events.session; + } - readonly session = this._events.session; + readonly session: number | undefined; private _created = new Lazy(() => this._events.created.map(URI.revive) as URI[]); get created(): URI[] { return this._created.value; } diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index 4a785ef16ded7..7142bd7111e23 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -1306,7 +1306,7 @@ class InlineCompletionAdapter { items: readonly vscode.InlineCompletionItem[]; }>(); - private readonly _isAdditionsProposedApiEnabled = isProposedApiEnabled(this._extension, 'inlineCompletionsAdditions'); + private readonly _isAdditionsProposedApiEnabled: boolean; constructor( private readonly _extension: IExtensionDescription, @@ -1314,6 +1314,8 @@ class InlineCompletionAdapter { private readonly _provider: vscode.InlineCompletionItemProvider, private readonly _commands: CommandsConverter, ) { + + this._isAdditionsProposedApiEnabled = isProposedApiEnabled(this._extension, 'inlineCompletionsAdditions'); } public get supportsHandleEvents(): boolean { diff --git a/src/vs/workbench/api/common/extHostSearch.ts b/src/vs/workbench/api/common/extHostSearch.ts index fb92adb1fc9fd..4b62464bd552f 100644 --- a/src/vs/workbench/api/common/extHostSearch.ts +++ b/src/vs/workbench/api/common/extHostSearch.ts @@ -31,7 +31,7 @@ export const IExtHostSearch = createDecorator('IExtHostSearch'); export class ExtHostSearch implements IExtHostSearch { - protected readonly _proxy: MainThreadSearchShape = this.extHostRpc.getProxy(MainContext.MainThreadSearch); + protected readonly _proxy: MainThreadSearchShape; protected _handlePool: number = 0; private readonly _textSearchProvider = new Map(); @@ -49,7 +49,9 @@ export class ExtHostSearch implements IExtHostSearch { @IExtHostRpcService private extHostRpc: IExtHostRpcService, @IURITransformerService protected _uriTransformer: IURITransformerService, @ILogService protected _logService: ILogService, - ) { } + ) { + this._proxy = this.extHostRpc.getProxy(MainContext.MainThreadSearch); + } protected _transformScheme(scheme: string): string { return this._uriTransformer.transformOutgoingScheme(scheme); diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index b325f95bb0d16..84447c5878319 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -31,7 +31,7 @@ import { IExtHostTerminalShellIntegration } from '../common/extHostTerminalShell export class ExtHostDebugService extends ExtHostDebugServiceBase { - override readonly _serviceBrand: undefined; + declare readonly _serviceBrand: undefined; private _integratedTerminalInstances = new DebugTerminalCollection(); private _terminalDisposedListener: IDisposable | undefined; diff --git a/src/vs/workbench/api/node/extHostDiskFileSystemProvider.ts b/src/vs/workbench/api/node/extHostDiskFileSystemProvider.ts index 2be6ba4652fa4..732ad1056c0d5 100644 --- a/src/vs/workbench/api/node/extHostDiskFileSystemProvider.ts +++ b/src/vs/workbench/api/node/extHostDiskFileSystemProvider.ts @@ -27,9 +27,11 @@ export class ExtHostDiskFileSystemProvider { class DiskFileSystemProviderAdapter implements vscode.FileSystemProvider { - private readonly impl = new DiskFileSystemProvider(this.logService); + private readonly impl: DiskFileSystemProvider; - constructor(private readonly logService: ILogService) { } + constructor(private readonly logService: ILogService) { + this.impl = new DiskFileSystemProvider(this.logService); + } async stat(uri: vscode.Uri): Promise { const stat = await this.impl.stat(uri); diff --git a/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts b/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts index 7563b30cd4751..c120afc38f4df 100644 --- a/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts +++ b/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts @@ -33,7 +33,7 @@ export class BrowserDialogHandler extends AbstractDialogHandler { 'editor.action.clipboardPasteAction' ]; - private readonly markdownRenderer = this.instantiationService.createInstance(MarkdownRenderer, {}); + private readonly markdownRenderer: MarkdownRenderer; constructor( @ILogService private readonly logService: ILogService, @@ -45,6 +45,8 @@ export class BrowserDialogHandler extends AbstractDialogHandler { @IOpenerService private readonly openerService: IOpenerService ) { super(); + + this.markdownRenderer = this.instantiationService.createInstance(MarkdownRenderer, {}); } async prompt(prompt: IPrompt): Promise> { diff --git a/src/vs/workbench/browser/parts/editor/editorGroupWatermark.ts b/src/vs/workbench/browser/parts/editor/editorGroupWatermark.ts index 0c7e37ccc0972..203d0c7550d92 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupWatermark.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupWatermark.ts @@ -71,14 +71,14 @@ export class EditorGroupWatermark extends Disposable { private static readonly CACHED_WHEN = 'editorGroupWatermark.whenConditions'; - private readonly cachedWhen: { [when: string]: boolean } = this.storageService.getObject(EditorGroupWatermark.CACHED_WHEN, StorageScope.PROFILE, Object.create(null)); + private readonly cachedWhen: { [when: string]: boolean }; private readonly shortcuts: HTMLElement; private readonly transientDisposables = this._register(new DisposableStore()); private readonly keybindingLabels = this._register(new DisposableStore()); private enabled = false; - private workbenchState = this.contextService.getWorkbenchState(); + private workbenchState: WorkbenchState; constructor( container: HTMLElement, @@ -90,6 +90,8 @@ export class EditorGroupWatermark extends Disposable { ) { super(); + this.cachedWhen = this.storageService.getObject(EditorGroupWatermark.CACHED_WHEN, StorageScope.PROFILE, Object.create(null)); + const elements = h('.editor-group-watermark', [ h('.letterpress'), h('.shortcuts@shortcuts'), @@ -98,6 +100,8 @@ export class EditorGroupWatermark extends Disposable { append(container, elements.root); this.shortcuts = elements.shortcuts; + this.workbenchState = this.contextService.getWorkbenchState(); + this.registerListeners(); this.render(); diff --git a/src/vs/workbench/browser/parts/editor/editorPanes.ts b/src/vs/workbench/browser/parts/editor/editorPanes.ts index 68b73d9a58880..0eeff7d6cb55e 100644 --- a/src/vs/workbench/browser/parts/editor/editorPanes.ts +++ b/src/vs/workbench/browser/parts/editor/editorPanes.ts @@ -89,7 +89,7 @@ export class EditorPanes extends Disposable { private readonly activeEditorPaneDisposables = this._register(new DisposableStore()); private pagePosition: IDomNodePagePosition | undefined; private boundarySashes: IBoundarySashes | undefined; - private readonly editorOperation = this._register(new LongRunningOperation(this.editorProgressService)); + private readonly editorOperation: LongRunningOperation; private readonly editorPanesRegistry = Registry.as(EditorExtensions.EditorPane); constructor( @@ -106,6 +106,8 @@ export class EditorPanes extends Disposable { ) { super(); + this.editorOperation = this._register(new LongRunningOperation(this.editorProgressService)); + this.registerListeners(); } diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index 90254ef45be53..a80ed8e992a5a 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -170,6 +170,8 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupsView { ) { super(id, { hasTitle: false }, themeService, storageService, layoutService); + this._partOptions = getEditorPartOptions(this.configurationService, this.themeService); + this.registerListeners(); } @@ -200,7 +202,7 @@ export class EditorPart extends Part implements IEditorPart, IEditorGroupsView { private enforcedPartOptions: DeepPartial[] = []; - private _partOptions = getEditorPartOptions(this.configurationService, this.themeService); + private _partOptions: IEditorPartOptions; get partOptions(): IEditorPartOptions { return this._partOptions; } enforcePartOptions(options: DeepPartial): IDisposable { diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index a1b9bd5215c2c..8472f7a460b33 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -353,9 +353,9 @@ class EditorStatus extends Disposable { private readonly languageElement = this._register(new MutableDisposable()); private readonly metadataElement = this._register(new MutableDisposable()); - private readonly currentMarkerStatus = this._register(this.instantiationService.createInstance(ShowCurrentMarkerInStatusbarContribution)); - private readonly tabFocusMode = this._register(this.instantiationService.createInstance(TabFocusMode)); - private readonly inputMode = this._register(this.instantiationService.createInstance(StatusInputMode)); + private readonly currentMarkerStatus: ShowCurrentMarkerInStatusbarContribution; + private readonly tabFocusMode: TabFocusMode; + private readonly inputMode: StatusInputMode; private readonly state = new State(); private toRender: StateChange | undefined = undefined; @@ -375,6 +375,10 @@ class EditorStatus extends Disposable { ) { super(); + this.currentMarkerStatus = this._register(this.instantiationService.createInstance(ShowCurrentMarkerInStatusbarContribution)); + this.tabFocusMode = this._register(this.instantiationService.createInstance(TabFocusMode)); + this.inputMode = this._register(this.instantiationService.createInstance(StatusInputMode)); + this.registerCommands(); this.registerListeners(); } diff --git a/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts index b373fd8b05188..691a716cba621 100644 --- a/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts +++ b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts @@ -116,7 +116,7 @@ export class SideBySideEditor extends AbstractEditorWithViewState(SideBySideEditor.SIDE_BY_SIDE_LAYOUT_SETTING) === 'vertical' ? Orientation.VERTICAL : Orientation.HORIZONTAL; + private orientation: Orientation; private dimension = new Dimension(0, 0); private lastFocusedSide: Side.PRIMARY | Side.SECONDARY | undefined = undefined; @@ -134,6 +134,8 @@ export class SideBySideEditor extends AbstractEditorWithViewState(SideBySideEditor.SIDE_BY_SIDE_LAYOUT_SETTING) === 'vertical' ? Orientation.VERTICAL : Orientation.HORIZONTAL; + this.registerListeners(); } diff --git a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts index 85356ca85d9d8..c616d04ef1cdc 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts @@ -10,7 +10,7 @@ import { IThemeService, Themable } from '../../../../platform/theme/common/theme import { INotificationsModel, INotificationChangeEvent, NotificationChangeType, NotificationViewItemContentChangeKind } from '../../../common/notifications.js'; import { IWorkbenchLayoutService, Parts } from '../../../services/layout/browser/layoutService.js'; import { Emitter } from '../../../../base/common/event.js'; -import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; +import { IContextKey, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; import { INotificationsCenterController, NotificationActionRunner } from './notificationsCommands.js'; import { NotificationsList } from './notificationsList.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; @@ -45,7 +45,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente private notificationsList: NotificationsList | undefined; private _isVisible: boolean | undefined; private workbenchDimensions: Dimension | undefined; - private readonly notificationsCenterVisibleContextKey = NotificationsCenterVisibleContext.bindTo(this.contextKeyService); + private readonly notificationsCenterVisibleContextKey: IContextKey; private clearAllAction: ClearAllNotificationsAction | undefined; private configureDoNotDisturbAction: ConfigureDoNotDisturbAction | undefined; @@ -64,7 +64,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente ) { super(themeService); - this.notificationsCenterVisibleContextKey = NotificationsCenterVisibleContext.bindTo(contextKeyService); + this.notificationsCenterVisibleContextKey = NotificationsCenterVisibleContext.bindTo(this.contextKeyService); this.registerListeners(); } diff --git a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts index f0dda3b44cbcc..616b1dcb9ac81 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts @@ -17,7 +17,7 @@ import { IThemeService, Themable } from '../../../../platform/theme/common/theme import { widgetShadow } from '../../../../platform/theme/common/colorRegistry.js'; import { IEditorGroupsService } from '../../../services/editor/common/editorGroupsService.js'; import { INotificationsToastController } from './notificationsCommands.js'; -import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; +import { IContextKey, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; import { Severity, NotificationsFilter, NotificationPriority } from '../../../../platform/notification/common/notification.js'; import { ScrollbarVisibility } from '../../../../base/common/scrollable.js'; import { ILifecycleService, LifecyclePhase } from '../../../services/lifecycle/common/lifecycle.js'; @@ -71,7 +71,7 @@ export class NotificationsToasts extends Themable implements INotificationsToast private readonly mapNotificationToToast = new Map(); private readonly mapNotificationToDisposable = new Map(); - private readonly notificationsToastsVisibleContextKey = NotificationsToastsVisibleContext.bindTo(this.contextKeyService); + private readonly notificationsToastsVisibleContextKey: IContextKey; private readonly addedToastsIntervalCounter = new IntervalCounter(NotificationsToasts.SPAM_PROTECTION.interval); @@ -88,6 +88,8 @@ export class NotificationsToasts extends Themable implements INotificationsToast ) { super(themeService); + this.notificationsToastsVisibleContextKey = NotificationsToastsVisibleContext.bindTo(this.contextKeyService); + this.registerListeners(); } diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts index 9b8e33d5f7d0f..85316d5cca3b1 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts @@ -132,9 +132,9 @@ class StatusbarPart extends Part implements IStatusbarEntryContainer { private pendingEntries: IPendingStatusbarEntry[] = []; - private readonly viewModel = this._register(new StatusbarViewModel(this.storageService)); + private readonly viewModel: StatusbarViewModel; - readonly onDidChangeEntryVisibility = this.viewModel.onDidChangeEntryVisibility; + readonly onDidChangeEntryVisibility: Event<{ id: string; visible: boolean }>; private readonly _onWillDispose = this._register(new Emitter()); readonly onWillDispose = this._onWillDispose.event; @@ -145,14 +145,7 @@ class StatusbarPart extends Part implements IStatusbarEntryContainer { private leftItemsContainer: HTMLElement | undefined; private rightItemsContainer: HTMLElement | undefined; - private readonly hoverDelegate = this._register(this.instantiationService.createInstance(WorkbenchHoverDelegate, 'element', true, (_, focus?: boolean) => ( - { - persistence: { - hideOnKeyDown: true, - sticky: focus - } - } - ))); + private readonly hoverDelegate: WorkbenchHoverDelegate; private readonly compactEntriesDisposable = this._register(new MutableDisposable()); private readonly styleOverrides = new Set(); @@ -169,6 +162,18 @@ class StatusbarPart extends Part implements IStatusbarEntryContainer { ) { super(id, { hasTitle: false }, themeService, storageService, layoutService); + this.viewModel = this._register(new StatusbarViewModel(this.storageService)); + this.onDidChangeEntryVisibility = this.viewModel.onDidChangeEntryVisibility; + + this.hoverDelegate = this._register(this.instantiationService.createInstance(WorkbenchHoverDelegate, 'element', true, (_, focus?: boolean) => ( + { + persistence: { + hideOnKeyDown: true, + sticky: focus + } + } + ))); + this.registerListeners(); } @@ -734,7 +739,7 @@ export class StatusbarService extends MultiWindowParts implements declare readonly _serviceBrand: undefined; - readonly mainPart = this._register(this.instantiationService.createInstance(MainStatusbarPart)); + readonly mainPart: MainStatusbarPart; private readonly _onDidCreateAuxiliaryStatusbarPart = this._register(new Emitter()); private readonly onDidCreateAuxiliaryStatusbarPart = this._onDidCreateAuxiliaryStatusbarPart.event; @@ -746,6 +751,10 @@ export class StatusbarService extends MultiWindowParts implements ) { super('workbench.statusBarService', themeService, storageService); + this.mainPart = this._register(this.instantiationService.createInstance(MainStatusbarPart)); + + this.onDidChangeEntryVisibility = this.mainPart.onDidChangeEntryVisibility; + this._register(this.registerPart(this.mainPart)); } @@ -784,7 +793,7 @@ export class StatusbarService extends MultiWindowParts implements //#region Service Implementation - readonly onDidChangeEntryVisibility = this.mainPart.onDidChangeEntryVisibility; + readonly onDidChangeEntryVisibility: Event<{ id: string; visible: boolean }>; addEntry(entry: IStatusbarEntry, id: string, alignment: StatusbarAlignment, priorityOrLocation: number | IStatusbarEntryLocation | IStatusbarEntryPriority = 0): IStatusbarEntryAccessor { if (entry.showInAllWindows) { @@ -888,6 +897,8 @@ export class ScopedStatusbarService extends Disposable implements IStatusbarServ @IStatusbarService private readonly statusbarService: IStatusbarService ) { super(); + + this.onDidChangeEntryVisibility = this.statusbarEntryContainer.onDidChangeEntryVisibility; } createAuxiliaryStatusbarPart(container: HTMLElement): IAuxiliaryStatusbarPart { @@ -902,7 +913,7 @@ export class ScopedStatusbarService extends Disposable implements IStatusbarServ return this.statusbarEntryContainer; } - readonly onDidChangeEntryVisibility = this.statusbarEntryContainer.onDidChangeEntryVisibility; + readonly onDidChangeEntryVisibility: Event<{ id: string; visible: boolean }>; addEntry(entry: IStatusbarEntry, id: string, alignment: StatusbarAlignment, priorityOrLocation: number | IStatusbarEntryLocation | IStatusbarEntryPriority = 0): IStatusbarEntryAccessor { return this.statusbarEntryContainer.addEntry(entry, id, alignment, priorityOrLocation); diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index 8aa33c7897093..ce3bc2c49ff3a 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -8,7 +8,7 @@ import { localize, localize2 } from '../../../../nls.js'; import { MultiWindowParts, Part } from '../../part.js'; import { ITitleService } from '../../../services/title/browser/titleService.js'; import { getWCOTitlebarAreaRect, getZoomFactor, isWCOEnabled } from '../../../../base/browser/browser.js'; -import { MenuBarVisibility, getTitleBarStyle, getMenuBarVisibility, hasCustomTitlebar, hasNativeTitlebar, DEFAULT_CUSTOM_TITLEBAR_HEIGHT } from '../../../../platform/window/common/window.js'; +import { MenuBarVisibility, getTitleBarStyle, getMenuBarVisibility, hasCustomTitlebar, hasNativeTitlebar, DEFAULT_CUSTOM_TITLEBAR_HEIGHT, TitlebarStyle } from '../../../../platform/window/common/window.js'; import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js'; import { StandardMouseEvent } from '../../../../base/browser/mouseEvent.js'; import { IConfigurationService, IConfigurationChangeEvent } from '../../../../platform/configuration/common/configuration.js'; @@ -267,7 +267,7 @@ export class BrowserTitlebarPart extends Part implements ITitlebarPart { private readonly editorActionsChangeDisposable = this._register(new DisposableStore()); private actionToolBarElement!: HTMLElement; - private globalToolbarMenu = this._register(this.menuService.createMenu(MenuId.TitleBar, this.contextKeyService)); + private globalToolbarMenu: IMenu; private hasGlobalToolbarEntries = false; private layoutToolbarMenu: IMenu | undefined; @@ -279,7 +279,7 @@ export class BrowserTitlebarPart extends Part implements ITitlebarPart { private readonly hoverDelegate: IHoverDelegate; private readonly titleDisposables = this._register(new DisposableStore()); - private titleBarStyle = getTitleBarStyle(this.configurationService); + private titleBarStyle: TitlebarStyle; private isInactive: boolean = false; private readonly isAuxiliary: boolean; @@ -309,6 +309,10 @@ export class BrowserTitlebarPart extends Part implements ITitlebarPart { ) { super(id, { hasTitle: false }, themeService, storageService, layoutService); + this.globalToolbarMenu = this._register(this.menuService.createMenu(MenuId.TitleBar, this.contextKeyService)); + + this.titleBarStyle = getTitleBarStyle(this.configurationService); + this.isAuxiliary = editorGroupsContainer !== 'main'; this.editorService = editorService.createScoped(editorGroupsContainer, this._store); this.editorGroupsContainer = editorGroupsContainer === 'main' ? editorGroupService.mainPart : editorGroupsContainer; diff --git a/src/vs/workbench/common/editor/sideBySideEditorInput.ts b/src/vs/workbench/common/editor/sideBySideEditorInput.ts index 5b20850a87e88..3a4cb208b3048 100644 --- a/src/vs/workbench/common/editor/sideBySideEditorInput.ts +++ b/src/vs/workbench/common/editor/sideBySideEditorInput.ts @@ -60,7 +60,7 @@ export class SideBySideEditorInput extends EditorInput implements ISideBySideEdi return undefined; } - private hasIdenticalSides = this.primary.matches(this.secondary); + private hasIdenticalSides: boolean; constructor( protected readonly preferredName: string | undefined, @@ -71,6 +71,8 @@ export class SideBySideEditorInput extends EditorInput implements ISideBySideEdi ) { super(); + this.hasIdenticalSides = this.primary.matches(this.secondary); + this.registerListeners(); } diff --git a/src/vs/workbench/contrib/accessibilitySignals/browser/editorTextPropertySignalsContribution.ts b/src/vs/workbench/contrib/accessibilitySignals/browser/editorTextPropertySignalsContribution.ts index 28d6fe3edef88..4ffa4e396b946 100644 --- a/src/vs/workbench/contrib/accessibilitySignals/browser/editorTextPropertySignalsContribution.ts +++ b/src/vs/workbench/contrib/accessibilitySignals/browser/editorTextPropertySignalsContribution.ts @@ -5,9 +5,9 @@ import { disposableTimeout } from '../../../../base/common/async.js'; import { Disposable, DisposableStore } from '../../../../base/common/lifecycle.js'; -import { IReader, autorun, autorunWithStore, derived, observableFromEvent, observableFromPromise, observableFromValueWithChangeEvent, observableSignalFromEvent, wasEventTriggeredRecently } from '../../../../base/common/observable.js'; +import { IObservable, IReader, autorun, autorunWithStore, derived, observableFromEvent, observableFromPromise, observableFromValueWithChangeEvent, observableSignalFromEvent, wasEventTriggeredRecently } from '../../../../base/common/observable.js'; import { isDefined } from '../../../../base/common/types.js'; -import { ICodeEditor, isCodeEditor, isDiffEditor } from '../../../../editor/browser/editorBrowser.js'; +import { IActiveCodeEditor, ICodeEditor, isCodeEditor, isDiffEditor } from '../../../../editor/browser/editorBrowser.js'; import { Position } from '../../../../editor/common/core/position.js'; import { CursorChangeReason } from '../../../../editor/common/cursorEvents.js'; import { ITextModel } from '../../../../editor/common/model.js'; @@ -20,12 +20,7 @@ import { IEditorService } from '../../../services/editor/common/editorService.js import { IDebugService } from '../../debug/common/debug.js'; export class EditorTextPropertySignalsContribution extends Disposable implements IWorkbenchContribution { - private readonly _textProperties: TextProperty[] = [ - this._instantiationService.createInstance(MarkerTextProperty, AccessibilitySignal.errorAtPosition, AccessibilitySignal.errorOnLine, MarkerSeverity.Error), - this._instantiationService.createInstance(MarkerTextProperty, AccessibilitySignal.warningAtPosition, AccessibilitySignal.warningOnLine, MarkerSeverity.Warning), - this._instantiationService.createInstance(FoldedAreaTextProperty), - this._instantiationService.createInstance(BreakpointTextProperty), - ]; + private readonly _textProperties: TextProperty[]; private readonly _someAccessibilitySignalIsEnabled = derived(this, reader => this._textProperties @@ -34,20 +29,7 @@ export class EditorTextPropertySignalsContribution extends Disposable implements .some(signal => observableFromValueWithChangeEvent(this, this._accessibilitySignalService.getEnabledState(signal, false)).read(reader)) ); - private readonly _activeEditorObservable = observableFromEvent(this, - this._editorService.onDidActiveEditorChange, - (_) => { - const activeTextEditorControl = this._editorService.activeTextEditorControl; - - const editor = isDiffEditor(activeTextEditorControl) - ? activeTextEditorControl.getOriginalEditor() - : isCodeEditor(activeTextEditorControl) - ? activeTextEditorControl - : undefined; - - return editor && editor.hasModel() ? { editor, model: editor.getModel() } : undefined; - } - ); + private readonly _activeEditorObservable: IObservable<{ editor: IActiveCodeEditor; model: ITextModel } | undefined>; constructor( @IEditorService private readonly _editorService: IEditorService, @@ -56,6 +38,28 @@ export class EditorTextPropertySignalsContribution extends Disposable implements ) { super(); + this._textProperties = [ + this._instantiationService.createInstance(MarkerTextProperty, AccessibilitySignal.errorAtPosition, AccessibilitySignal.errorOnLine, MarkerSeverity.Error), + this._instantiationService.createInstance(MarkerTextProperty, AccessibilitySignal.warningAtPosition, AccessibilitySignal.warningOnLine, MarkerSeverity.Warning), + this._instantiationService.createInstance(FoldedAreaTextProperty), + this._instantiationService.createInstance(BreakpointTextProperty), + ]; + + this._activeEditorObservable = observableFromEvent(this, + this._editorService.onDidActiveEditorChange, + (_) => { + const activeTextEditorControl = this._editorService.activeTextEditorControl; + + const editor = isDiffEditor(activeTextEditorControl) + ? activeTextEditorControl.getOriginalEditor() + : isCodeEditor(activeTextEditorControl) + ? activeTextEditorControl + : undefined; + + return editor && editor.hasModel() ? { editor, model: editor.getModel() } : undefined; + } + ); + this._register(autorunWithStore((reader, store) => { /** @description updateSignalsEnabled */ if (!this._someAccessibilitySignalIsEnabled.read(reader)) { diff --git a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts index 61204fc1867ee..8dc56cb5c66fe 100644 --- a/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatContentParts/chatAttachmentsContentPart.ts @@ -51,7 +51,7 @@ export class ChatAttachmentsContentPart extends Disposable { private readonly attachedContextDisposables = this._register(new DisposableStore()); private readonly _onDidChangeVisibility = this._register(new Emitter()); - private readonly _contextResourceLabels = this._register(this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this._onDidChangeVisibility.event })); + private readonly _contextResourceLabels: ResourceLabels; constructor( private readonly variables: IChatRequestVariableEntry[], @@ -68,6 +68,8 @@ export class ChatAttachmentsContentPart extends Disposable { ) { super(); + this._contextResourceLabels = this._register(this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this._onDidChangeVisibility.event })); + this.initAttachedContext(domNode); if (!domNode.childElementCount) { this.domNode = undefined; diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingCodeEditorIntegration.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingCodeEditorIntegration.ts index de769b9fb747b..4e4d5ca2eba3e 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingCodeEditorIntegration.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingCodeEditorIntegration.ts @@ -38,6 +38,7 @@ import { overviewRulerModifiedForeground, minimapGutterModifiedBackground, overv import { ChatAgentLocation, IChatAgentService } from '../../common/chatAgents.js'; import { ChatEditingSessionState, IChatEditingService, IModifiedFileEntry, IModifiedFileEntryChangeHunk, IModifiedFileEntryEditorIntegration, WorkingSetEntryState } from '../../common/chatEditingService.js'; import { isTextDiffEditorForEntry } from './chatEditing.js'; +import { IEditorDecorationsCollection } from '../../../../../editor/common/editorCommon.js'; export interface IDocumentDiff2 extends IDocumentDiff { @@ -56,9 +57,9 @@ export class ChatEditingCodeEditorIntegration implements IModifiedFileEntryEdito readonly currentIndex: IObservable = this._currentIndex; private readonly _store = new DisposableStore(); - private readonly _diffLineDecorations = this._editor.createDecorationsCollection(); // tracks the line range w/o visuals (used for navigate) + private readonly _diffLineDecorations: IEditorDecorationsCollection; // tracks the line range w/o visuals (used for navigate) - private readonly _diffVisualDecorations = this._editor.createDecorationsCollection(); // tracks the real diff with character level inserts + private readonly _diffVisualDecorations: IEditorDecorationsCollection; // tracks the real diff with character level inserts private readonly _diffHunksRenderStore = this._store.add(new DisposableStore()); private readonly _diffHunkWidgets: DiffHunkWidget[] = []; private _viewZones: string[] = []; @@ -76,6 +77,8 @@ export class ChatEditingCodeEditorIntegration implements IModifiedFileEntryEdito @IInstantiationService instantiationService: IInstantiationService, ) { this._diffLineDecorations = _editor.createDecorationsCollection(); + this._diffVisualDecorations = this._editor.createDecorationsCollection(); + const codeEditorObs = observableCodeEditor(_editor); const enabledObs = derived(r => { diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts index ba88a430f4218..2f1d3086833d4 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingSession.ts @@ -212,6 +212,8 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio @IConfigurationService private readonly _configurationService: IConfigurationService, ) { super(); + + this._ignoreTrimWhitespaceObservable = observableConfigValue('diffEditor.ignoreTrimWhitespace', true, this._configurationService); } public async init(): Promise { @@ -312,7 +314,7 @@ export class ChatEditingSession extends Disposable implements IChatEditingSessio private _diffsBetweenStops = new Map>(); - private readonly _ignoreTrimWhitespaceObservable = observableConfigValue('diffEditor.ignoreTrimWhitespace', true, this._configurationService); + private readonly _ignoreTrimWhitespaceObservable: IObservable; /** * Gets diff for text entries between stops. diff --git a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts index bdd7a0d0fb44f..f13de5948f27f 100644 --- a/src/vs/workbench/contrib/chat/browser/chatInputPart.ts +++ b/src/vs/workbench/contrib/chat/browser/chatInputPart.ts @@ -225,7 +225,7 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge private _hasFileAttachmentContextKey: IContextKey; private readonly _onDidChangeVisibility = this._register(new Emitter()); - private readonly _contextResourceLabels = this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this._onDidChangeVisibility.event }); + private readonly _contextResourceLabels: ResourceLabels; private readonly inputEditorMaxHeight: number; private inputEditorHeight = 0; @@ -391,6 +391,8 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge this._hasFileAttachmentContextKey = ChatContextKeys.hasFileAttachments.bindTo(contextKeyService); + this._contextResourceLabels = this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this._onDidChangeVisibility.event }); + this.instructionAttachmentsPart = this._register( instantiationService.createInstance( PromptAttachmentsCollectionWidget, diff --git a/src/vs/workbench/contrib/chat/browser/chatSetup.ts b/src/vs/workbench/contrib/chat/browser/chatSetup.ts index f4c3c6f7b8246..97ef912791af9 100644 --- a/src/vs/workbench/contrib/chat/browser/chatSetup.ts +++ b/src/vs/workbench/contrib/chat/browser/chatSetup.ts @@ -23,7 +23,7 @@ import { localize, localize2 } from '../../../../nls.js'; import { Action2, MenuId, registerAction2 } from '../../../../platform/actions/common/actions.js'; import { ICommandService } from '../../../../platform/commands/common/commands.js'; import { ConfigurationTarget, IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; -import { ContextKeyExpr, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; +import { ContextKeyExpr, IContextKey, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js'; import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js'; import { ExtensionIdentifier } from '../../../../platform/extensions/common/extensions.js'; @@ -409,7 +409,7 @@ class ChatSetupRequests extends Disposable { return defaultChat.providerId; } - private state: IChatEntitlements = { entitlement: this.context.state.entitlement }; + private state: IChatEntitlements; private pendingResolveCts = new CancellationTokenSource(); private didResolveEntitlements = false; @@ -427,6 +427,8 @@ class ChatSetupRequests extends Disposable { ) { super(); + this.state = { entitlement: this.context.state.entitlement }; + this.registerListeners(); this.resolve(); @@ -1260,14 +1262,14 @@ class ChatSetupContext extends Disposable { private static readonly CHAT_SETUP_CONTEXT_STORAGE_KEY = 'chat.setupContext'; - private readonly canSignUpContextKey = ChatContextKeys.Setup.canSignUp.bindTo(this.contextKeyService); - private readonly signedOutContextKey = ChatContextKeys.Setup.signedOut.bindTo(this.contextKeyService); - private readonly limitedContextKey = ChatContextKeys.Setup.limited.bindTo(this.contextKeyService); - private readonly proContextKey = ChatContextKeys.Setup.pro.bindTo(this.contextKeyService); - private readonly hiddenContext = ChatContextKeys.Setup.hidden.bindTo(this.contextKeyService); - private readonly installedContext = ChatContextKeys.Setup.installed.bindTo(this.contextKeyService); + private readonly canSignUpContextKey: IContextKey; + private readonly signedOutContextKey: IContextKey; + private readonly limitedContextKey: IContextKey; + private readonly proContextKey: IContextKey; + private readonly hiddenContext: IContextKey; + private readonly installedContext: IContextKey; - private _state: IChatSetupContextState = this.storageService.getObject(ChatSetupContext.CHAT_SETUP_CONTEXT_STORAGE_KEY, StorageScope.PROFILE) ?? { entitlement: ChatEntitlement.Unknown }; + private _state: IChatSetupContextState; private suspendedState: IChatSetupContextState | undefined = undefined; get state(): IChatSetupContextState { return this.suspendedState ?? this._state; @@ -1288,6 +1290,15 @@ class ChatSetupContext extends Disposable { ) { super(); + this.canSignUpContextKey = ChatContextKeys.Setup.canSignUp.bindTo(this.contextKeyService); + this.signedOutContextKey = ChatContextKeys.Setup.signedOut.bindTo(this.contextKeyService); + this.limitedContextKey = ChatContextKeys.Setup.limited.bindTo(this.contextKeyService); + this.proContextKey = ChatContextKeys.Setup.pro.bindTo(this.contextKeyService); + this.hiddenContext = ChatContextKeys.Setup.hidden.bindTo(this.contextKeyService); + this.installedContext = ChatContextKeys.Setup.installed.bindTo(this.contextKeyService); + + this._state = this.storageService.getObject(ChatSetupContext.CHAT_SETUP_CONTEXT_STORAGE_KEY, StorageScope.PROFILE) ?? { entitlement: ChatEntitlement.Unknown }; + this.checkExtensionInstallation(); this.updateContextSync(); } diff --git a/src/vs/workbench/contrib/chat/browser/chatStatus.ts b/src/vs/workbench/contrib/chat/browser/chatStatus.ts index e70211e91c0df..4a59556835d3d 100644 --- a/src/vs/workbench/contrib/chat/browser/chatStatus.ts +++ b/src/vs/workbench/contrib/chat/browser/chatStatus.ts @@ -20,7 +20,7 @@ export class ChatStatusBarEntry extends Disposable implements IWorkbenchContribu static readonly ID = 'chat.statusBarEntry'; - private readonly treatment = this.assignmentService.getTreatment('config.chat.experimental.statusIndicator.enabled'); //TODO@bpasero remove this experiment eventually + private readonly treatment: Promise; private entry: IStatusbarEntryAccessor | undefined = undefined; @@ -34,6 +34,8 @@ export class ChatStatusBarEntry extends Disposable implements IWorkbenchContribu ) { super(); + this.treatment = this.assignmentService.getTreatment('config.chat.experimental.statusIndicator.enabled'); //TODO@bpasero remove this experiment eventually + this.create(); this.registerListeners(); } diff --git a/src/vs/workbench/contrib/chat/common/chatQuotasService.ts b/src/vs/workbench/contrib/chat/common/chatQuotasService.ts index f8b9eb23fdf34..5223d1eafb551 100644 --- a/src/vs/workbench/contrib/chat/common/chatQuotasService.ts +++ b/src/vs/workbench/contrib/chat/common/chatQuotasService.ts @@ -5,7 +5,7 @@ import { Emitter, Event } from '../../../../base/common/event.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; -import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; +import { IContextKey, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; import { ChatContextKeys } from './chatContextKeys.js'; @@ -44,8 +44,8 @@ export class ChatQuotasService extends Disposable implements IChatQuotasService private _quotas: IChatQuotas = { chatQuotaExceeded: false, completionsQuotaExceeded: false, quotaResetDate: undefined }; get quotas(): IChatQuotas { return this._quotas; } - private readonly chatQuotaExceededContextKey = ChatContextKeys.chatQuotaExceeded.bindTo(this.contextKeyService); - private readonly completionsQuotaExceededContextKey = ChatContextKeys.completionsQuotaExceeded.bindTo(this.contextKeyService); + private readonly chatQuotaExceededContextKey: IContextKey; + private readonly completionsQuotaExceededContextKey: IContextKey; private ExtensionQuotaContextKeys = { chatQuotaExceeded: 'github.copilot.chat.quotaExceeded', @@ -57,6 +57,9 @@ export class ChatQuotasService extends Disposable implements IChatQuotasService ) { super(); + this.chatQuotaExceededContextKey = ChatContextKeys.chatQuotaExceeded.bindTo(this.contextKeyService); + this.completionsQuotaExceededContextKey = ChatContextKeys.completionsQuotaExceeded.bindTo(this.contextKeyService); + this.registerListeners(); } diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/textModelContentsProvider.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/textModelContentsProvider.ts index b980da871fb52..465c745f337f9 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/textModelContentsProvider.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/contentProviders/textModelContentsProvider.ts @@ -10,6 +10,7 @@ import { PromptContentsProviderBase } from './promptContentsProviderBase.js'; import { CancellationToken } from '../../../../../../base/common/cancellation.js'; import { newWriteableStream, ReadableStream } from '../../../../../../base/common/stream.js'; import { IModelContentChangedEvent } from '../../../../../../editor/common/textModelEvents.js'; +import { URI } from '../../../../../../base/common/uri.js'; /** * Prompt contents provider for a {@linkcode ITextModel} instance. @@ -18,13 +19,15 @@ export class TextModelContentsProvider extends PromptContentsProviderBase extend export class PromptFileReference extends BasePromptParser implements IPromptFileReference { public readonly type = 'file'; - public readonly range = this.token.range; - public readonly path: string = this.token.path; - public readonly text: string = this.token.text; + public readonly range: Range; + public readonly path: string; + public readonly text: string; constructor( public readonly token: FileReference | MarkdownLink, @@ -567,6 +567,10 @@ export class PromptFileReference extends BasePromptParser([['vscode', 'code']]); - private readonly voiceChatInProgress = VoiceChatInProgress.bindTo(this.contextKeyService); + private readonly voiceChatInProgress: IContextKey; private activeVoiceChatSessions = 0; constructor( @@ -90,6 +90,8 @@ export class VoiceChatService extends Disposable implements IVoiceChatService { @IContextKeyService private readonly contextKeyService: IContextKeyService ) { super(); + + this.voiceChatInProgress = VoiceChatInProgress.bindTo(this.contextKeyService); } private createPhrases(model?: IChatModel): Map { diff --git a/src/vs/workbench/contrib/codeEditor/browser/dictation/editorDictation.ts b/src/vs/workbench/contrib/codeEditor/browser/dictation/editorDictation.ts index 6c657fb912474..a2b4bd2569cbf 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/dictation/editorDictation.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/dictation/editorDictation.ts @@ -10,7 +10,7 @@ import { CancellationTokenSource } from '../../../../../base/common/cancellation import { Disposable, DisposableStore, MutableDisposable, toDisposable } from '../../../../../base/common/lifecycle.js'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from '../../../../../editor/browser/editorBrowser.js'; import { IEditorContribution } from '../../../../../editor/common/editorCommon.js'; -import { ContextKeyExpr, IContextKeyService, RawContextKey } from '../../../../../platform/contextkey/common/contextkey.js'; +import { ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey } from '../../../../../platform/contextkey/common/contextkey.js'; import { HasSpeechProvider, ISpeechService, SpeechToTextInProgress, SpeechToTextStatus } from '../../../speech/common/speechService.js'; import { Codicon } from '../../../../../base/common/codicons.js'; import { EditorOption } from '../../../../../editor/common/config/editorOptions.js'; @@ -187,8 +187,8 @@ export class EditorDictation extends Disposable implements IEditorContribution { return editor.getContribution(EditorDictation.ID); } - private readonly widget = this._register(new DictationWidget(this.editor, this.keybindingService)); - private readonly editorDictationInProgress = EDITOR_DICTATION_IN_PROGRESS.bindTo(this.contextKeyService); + private readonly widget: DictationWidget; + private readonly editorDictationInProgress: IContextKey; private readonly sessionDisposables = this._register(new MutableDisposable()); @@ -199,6 +199,9 @@ export class EditorDictation extends Disposable implements IEditorContribution { @IKeybindingService private readonly keybindingService: IKeybindingService ) { super(); + + this.widget = this._register(new DictationWidget(this.editor, this.keybindingService)); + this.editorDictationInProgress = EDITOR_DICTATION_IN_PROGRESS.bindTo(this.contextKeyService); } async start(): Promise { diff --git a/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoLineQuickAccess.ts b/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoLineQuickAccess.ts index 972fd363b90ac..6c00563f8270f 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoLineQuickAccess.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoLineQuickAccess.ts @@ -19,10 +19,11 @@ import { KeybindingWeight } from '../../../../../platform/keybinding/common/keyb import { IQuickAccessTextEditorContext } from '../../../../../editor/contrib/quickAccess/browser/editorNavigationQuickAccess.js'; import { ITextEditorOptions } from '../../../../../platform/editor/common/editor.js'; import { IEditorGroupsService } from '../../../../services/editor/common/editorGroupsService.js'; +import { Event } from '../../../../../base/common/event.js'; export class GotoLineQuickAccessProvider extends AbstractGotoLineQuickAccessProvider { - protected readonly onDidActiveTextEditorControlChange = this.editorService.onDidActiveEditorChange; + protected readonly onDidActiveTextEditorControlChange: Event; constructor( @IEditorService private readonly editorService: IEditorService, @@ -30,6 +31,8 @@ export class GotoLineQuickAccessProvider extends AbstractGotoLineQuickAccessProv @IConfigurationService private readonly configurationService: IConfigurationService ) { super(); + + this.onDidActiveTextEditorControlChange = this.editorService.onDidActiveEditorChange; } private get configuration() { diff --git a/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess.ts b/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess.ts index 037908fa8db3c..ca1c363377ea5 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/quickaccess/gotoSymbolQuickAccess.ts @@ -34,10 +34,11 @@ import { ILanguageFeaturesService } from '../../../../../editor/common/services/ import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js'; import { accessibilityHelpIsShown, accessibleViewIsShown } from '../../../accessibility/browser/accessibilityConfiguration.js'; import { matchesFuzzyIconAware, parseLabelWithIcons } from '../../../../../base/common/iconLabels.js'; +import { Event } from '../../../../../base/common/event.js'; export class GotoSymbolQuickAccessProvider extends AbstractGotoSymbolQuickAccessProvider { - protected readonly onDidActiveTextEditorControlChange = this.editorService.onDidActiveEditorChange; + protected readonly onDidActiveTextEditorControlChange: Event; constructor( @IEditorService private readonly editorService: IEditorService, @@ -50,6 +51,8 @@ export class GotoSymbolQuickAccessProvider extends AbstractGotoSymbolQuickAccess super(languageFeaturesService, outlineModelService, { openSideBySideDirection: () => this.configuration.openSideBySideDirection }); + + this.onDidActiveTextEditorControlChange = this.editorService.onDidActiveEditorChange; } //#region DocumentSymbols (text editor required) diff --git a/src/vs/workbench/contrib/comments/browser/commentsAccessibleView.ts b/src/vs/workbench/contrib/comments/browser/commentsAccessibleView.ts index c18066cbe58ea..f28436cbbf0d6 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsAccessibleView.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsAccessibleView.ts @@ -23,6 +23,7 @@ import { isCodeEditor } from '../../../../editor/browser/editorBrowser.js'; import { URI } from '../../../../base/common/uri.js'; import { CommentThread, Comment } from '../../../../editor/common/languages.js'; import { IRange } from '../../../../editor/common/core/range.js'; +import { IAction } from '../../../../base/common/actions.js'; export class CommentsAccessibleView extends Disposable implements IAccessibleViewImplementation { readonly priority = 90; @@ -78,24 +79,26 @@ class CommentsAccessibleContentProvider extends Disposable implements IAccessibl private readonly _menus: CommentsMenus, ) { super(); + + this.actions = [...this._menus.getResourceContextActions(this._focusedCommentNode)].filter(i => i.enabled).map(action => { + return { + ...action, + run: () => { + this._commentsView.focus(); + action.run({ + thread: this._focusedCommentNode.thread, + $mid: MarshalledId.CommentThread, + commentControlHandle: this._focusedCommentNode.controllerHandle, + commentThreadHandle: this._focusedCommentNode.threadHandle, + }); + } + }; + }); } readonly id = AccessibleViewProviderId.Comments; readonly verbositySettingKey = AccessibilityVerbositySettingId.Comments; readonly options = { type: AccessibleViewType.View }; - public actions = [...this._menus.getResourceContextActions(this._focusedCommentNode)].filter(i => i.enabled).map(action => { - return { - ...action, - run: () => { - this._commentsView.focus(); - action.run({ - thread: this._focusedCommentNode.thread, - $mid: MarshalledId.CommentThread, - commentControlHandle: this._focusedCommentNode.controllerHandle, - commentThreadHandle: this._focusedCommentNode.threadHandle, - }); - } - }; - }); + public actions: IAction[]; provideContent(): string { const commentNode = this._commentsView.focusedCommentNode; const content = this._commentsView.focusedCommentInfo?.toString(); diff --git a/src/vs/workbench/contrib/comments/browser/commentsViewActions.ts b/src/vs/workbench/contrib/comments/browser/commentsViewActions.ts index 016ead15476e9..47a8848770541 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsViewActions.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsViewActions.ts @@ -47,12 +47,17 @@ export class CommentsFilters extends Disposable { constructor(options: CommentsFiltersOptions, private readonly contextKeyService: IContextKeyService) { super(); + + this._showUnresolved = CONTEXT_KEY_SHOW_UNRESOLVED.bindTo(this.contextKeyService); + this._showResolved = CONTEXT_KEY_SHOW_RESOLVED.bindTo(this.contextKeyService); + this._sortBy = CONTEXT_KEY_SORT_BY.bindTo(this.contextKeyService); + this._showResolved.set(options.showResolved); this._showUnresolved.set(options.showUnresolved); this._sortBy.set(options.sortBy); } - private readonly _showUnresolved = CONTEXT_KEY_SHOW_UNRESOLVED.bindTo(this.contextKeyService); + private readonly _showUnresolved: IContextKey; get showUnresolved(): boolean { return !!this._showUnresolved.get(); } @@ -63,7 +68,7 @@ export class CommentsFilters extends Disposable { } } - private _showResolved = CONTEXT_KEY_SHOW_RESOLVED.bindTo(this.contextKeyService); + private _showResolved: IContextKey; get showResolved(): boolean { return !!this._showResolved.get(); } @@ -74,7 +79,7 @@ export class CommentsFilters extends Disposable { } } - private _sortBy: IContextKey = CONTEXT_KEY_SORT_BY.bindTo(this.contextKeyService); + private _sortBy: IContextKey; get sortBy(): CommentsSortOrder { return this._sortBy.get() ?? CommentsSortOrder.ResourceAscending; } diff --git a/src/vs/workbench/contrib/debug/browser/callStackEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/callStackEditorContribution.ts index 9a0a631edd982..3af781f24d603 100644 --- a/src/vs/workbench/contrib/debug/browser/callStackEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/callStackEditorContribution.ts @@ -9,7 +9,7 @@ import { Disposable } from '../../../../base/common/lifecycle.js'; import { Constants } from '../../../../base/common/uint.js'; import { ICodeEditor } from '../../../../editor/browser/editorBrowser.js'; import { Range } from '../../../../editor/common/core/range.js'; -import { IEditorContribution } from '../../../../editor/common/editorCommon.js'; +import { IEditorContribution, IEditorDecorationsCollection } from '../../../../editor/common/editorCommon.js'; import { GlyphMarginLane, IModelDecorationOptions, IModelDeltaDecoration, OverviewRulerLane, TrackedRangeStickiness } from '../../../../editor/common/model.js'; import { localize } from '../../../../nls.js'; import { ILogService } from '../../../../platform/log/common/log.js'; @@ -116,7 +116,7 @@ export function createDecorationsForStackFrame(stackFrame: IStackFrame, isFocuse } export class CallStackEditorContribution extends Disposable implements IEditorContribution { - private decorations = this.editor.createDecorationsCollection(); + private decorations: IEditorDecorationsCollection; constructor( private readonly editor: ICodeEditor, @@ -126,6 +126,8 @@ export class CallStackEditorContribution extends Disposable implements IEditorCo ) { super(); + this.decorations = this.editor.createDecorationsCollection(); + const setDecorations = () => this.decorations.set(this.createCallStackDecorations()); this._register(Event.any(this.debugService.getViewModel().onDidFocusStackFrame, this.debugService.getModel().onDidChangeCallStack)(() => { setDecorations(); diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts index 277b6a907af35..5546c72fe2bbe 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorContribution.ts @@ -30,7 +30,7 @@ import { EditOperation } from '../../../../editor/common/core/editOperation.js'; import { Position } from '../../../../editor/common/core/position.js'; import { IRange, Range } from '../../../../editor/common/core/range.js'; import { DEFAULT_WORD_REGEXP } from '../../../../editor/common/core/wordHelper.js'; -import { ScrollType } from '../../../../editor/common/editorCommon.js'; +import { IEditorDecorationsCollection, ScrollType } from '../../../../editor/common/editorCommon.js'; import { StandardTokenType } from '../../../../editor/common/encodedTokenAttributes.js'; import { InlineValue, InlineValueContext } from '../../../../editor/common/languages.js'; import { IModelDeltaDecoration, ITextModel, InjectedTextCursorStops } from '../../../../editor/common/model.js'; @@ -209,7 +209,7 @@ export class DebugEditorContribution implements IDebugEditorContribution { private configurationWidget: FloatingEditorClickWidget | undefined; private readonly altListener = new MutableDisposable(); private altPressed = false; - private oldDecorations = this.editor.createDecorationsCollection(); + private oldDecorations: IEditorDecorationsCollection; private readonly displayedStore = new DisposableStore(); private editorHoverOptions: IEditorHoverOptions | undefined; private readonly debounceInfo: IFeatureDebounceInformation; @@ -229,6 +229,7 @@ export class DebugEditorContribution implements IDebugEditorContribution { @ILanguageFeaturesService private readonly languageFeaturesService: ILanguageFeaturesService, @ILanguageFeatureDebounceService featureDebounceService: ILanguageFeatureDebounceService ) { + this.oldDecorations = this.editor.createDecorationsCollection(); this.debounceInfo = featureDebounceService.for(languageFeaturesService.inlineValuesProvider, 'InlineValues', { min: DEAFULT_INLINE_DEBOUNCE_DELAY }); this.hoverWidget = this.instantiationService.createInstance(DebugHoverWidget, this.editor); this.toDispose = [this.defaultHoverLockout, this.altListener, this.displayedStore]; diff --git a/src/vs/workbench/contrib/debug/browser/debugHover.ts b/src/vs/workbench/contrib/debug/browser/debugHover.ts index ddd5e8bdbc685..a5b4546a727db 100644 --- a/src/vs/workbench/contrib/debug/browser/debugHover.ts +++ b/src/vs/workbench/contrib/debug/browser/debugHover.ts @@ -23,6 +23,7 @@ import { ConfigurationChangedEvent, EditorOption } from '../../../../editor/comm import { IDimension } from '../../../../editor/common/core/dimension.js'; import { Position } from '../../../../editor/common/core/position.js'; import { Range } from '../../../../editor/common/core/range.js'; +import { IEditorDecorationsCollection } from '../../../../editor/common/editorCommon.js'; import { ModelDecorationOptions } from '../../../../editor/common/model/textModel.js'; import { ILanguageFeaturesService } from '../../../../editor/common/services/languageFeatures.js'; import * as nls from '../../../../nls.js'; @@ -93,7 +94,7 @@ export class DebugHoverWidget implements IContentWidget { private tree!: AsyncDataTree; private showAtPosition: Position | null; private positionPreference: ContentWidgetPositionPreference[]; - private readonly highlightDecorations = this.editor.createDecorationsCollection(); + private readonly highlightDecorations: IEditorDecorationsCollection; private complexValueContainer!: HTMLElement; private complexValueTitle!: HTMLElement; private valueContainer!: HTMLElement; @@ -118,6 +119,8 @@ export class DebugHoverWidget implements IContentWidget { @IContextKeyService private readonly contextKeyService: IContextKeyService, @IContextMenuService private readonly contextMenuService: IContextMenuService, ) { + this.highlightDecorations = this.editor.createDecorationsCollection(); + this.toDispose = []; this.showAtPosition = null; diff --git a/src/vs/workbench/contrib/debug/browser/debugMemory.ts b/src/vs/workbench/contrib/debug/browser/debugMemory.ts index 8fcd11962b301..277b0567293a2 100644 --- a/src/vs/workbench/contrib/debug/browser/debugMemory.ts +++ b/src/vs/workbench/contrib/debug/browser/debugMemory.ts @@ -235,11 +235,12 @@ class MemoryRegionView extends Disposable implements IMemoryRegion { public readonly onDidInvalidate = this.invalidateEmitter.event; public readonly writable: boolean; - private readonly width = this.range.toOffset - this.range.fromOffset; + private readonly width: number; constructor(private readonly parent: IMemoryRegion, public readonly range: { fromOffset: number; toOffset: number }) { super(); this.writable = parent.writable; + this.width = this.range.toOffset - this.range.fromOffset; this._register(parent); this._register(parent.onDidInvalidate(e => { diff --git a/src/vs/workbench/contrib/debug/common/debugModel.ts b/src/vs/workbench/contrib/debug/common/debugModel.ts index 75794f9dfd45a..47d2b52586b93 100644 --- a/src/vs/workbench/contrib/debug/common/debugModel.ts +++ b/src/vs/workbench/contrib/debug/common/debugModel.ts @@ -744,10 +744,13 @@ export class MemoryRegion extends Disposable implements IMemoryRegion { public readonly onDidInvalidate = this.invalidateEmitter.event; /** @inheritdoc */ - public readonly writable = !!this.session.capabilities.supportsWriteMemoryRequest; + public readonly writable: boolean; constructor(private readonly memoryReference: string, private readonly session: IDebugSession) { super(); + + this.writable = !!this.session.capabilities.supportsWriteMemoryRequest; + this._register(session.onDidInvalidateMemory(e => { if (e.body.memoryReference === memoryReference) { this.invalidate(e.body.offset, e.body.count - e.body.offset); diff --git a/src/vs/workbench/contrib/editSessions/browser/editSessionsStorageService.ts b/src/vs/workbench/contrib/editSessions/browser/editSessionsStorageService.ts index 1bb5eb3373700..a8830d8b5be95 100644 --- a/src/vs/workbench/contrib/editSessions/browser/editSessionsStorageService.ts +++ b/src/vs/workbench/contrib/editSessions/browser/editSessionsStorageService.ts @@ -25,6 +25,7 @@ import { Emitter } from '../../../../base/common/event.js'; import { CancellationError } from '../../../../base/common/errors.js'; import { EditSessionsStoreClient } from '../common/editSessionsStorageClient.js'; import { ISecretStorageService } from '../../../../platform/secrets/common/secrets.js'; +import { ConfigurationSyncStore } from '../../../../base/common/product.js'; type ExistingSession = IQuickPickItem & { session: AuthenticationSession & { providerId: string } }; type AuthenticationProviderOption = IQuickPickItem & { provider: IAuthenticationProvider }; @@ -35,7 +36,7 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes public readonly SIZE_LIMIT = Math.floor(1024 * 1024 * 1.9); // 2 MB - private serverConfiguration = this.productService['editSessions.store']; + private serverConfiguration: Omit | undefined; private machineClient: IUserDataSyncMachinesService | undefined; private authenticationInfo: { sessionId: string; token: string; providerId: string } | undefined; @@ -85,6 +86,8 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes ) { super(); + this.serverConfiguration = this.productService['editSessions.store']; + // If the user signs out of the current session, reset our cached auth state in memory and on disk this._register(this.authenticationService.onDidChangeSessions((e) => this.onDidChangeSessions(e.event))); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts index 41bcd531cfaf8..1cd695aae6e8f 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts @@ -928,7 +928,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension private readonly _onReset = new Emitter(); get onReset() { return this._onReset.event; } - readonly preferPreReleases = this.productService.quality !== 'stable'; + readonly preferPreReleases: boolean; private installing: IExtension[] = []; private tasksInProgress: CancelablePromise[] = []; @@ -972,6 +972,9 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension @IAllowedExtensionsService private readonly allowedExtensionsService: IAllowedExtensionsService, ) { super(); + + this.preferPreReleases = this.productService.quality !== 'stable'; + const preferPreReleasesValue = configurationService.getValue('_extensions.preferPreReleases'); if (!isUndefined(preferPreReleasesValue)) { this.preferPreReleases = !!preferPreReleasesValue; diff --git a/src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts b/src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts index addaf29046f9a..65a50f02bd4f0 100644 --- a/src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts +++ b/src/vs/workbench/contrib/files/browser/editors/textFileSaveErrorHandler.ts @@ -16,7 +16,7 @@ import { IWorkbenchContribution } from '../../../../common/contributions.js'; import { ITextModelService } from '../../../../../editor/common/services/resolverService.js'; import { ResourceMap } from '../../../../../base/common/map.js'; import { DiffEditorInput } from '../../../../common/editor/diffEditorInput.js'; -import { IContextKeyService, RawContextKey } from '../../../../../platform/contextkey/common/contextkey.js'; +import { IContextKey, IContextKeyService, RawContextKey } from '../../../../../platform/contextkey/common/contextkey.js'; import { TextFileContentProvider } from '../../common/files.js'; import { FileEditorInput } from './fileEditorInput.js'; import { SAVE_FILE_AS_LABEL } from '../fileConstants.js'; @@ -45,7 +45,7 @@ export class TextFileSaveErrorHandler extends Disposable implements ISaveErrorHa static readonly ID = 'workbench.contrib.textFileSaveErrorHandler'; private readonly messages = new ResourceMap(); - private readonly conflictResolutionContext = new RawContextKey(CONFLICT_RESOLUTION_CONTEXT, false, true).bindTo(this.contextKeyService); + private readonly conflictResolutionContext: IContextKey; private activeConflictResolutionResource: URI | undefined = undefined; constructor( @@ -59,6 +59,8 @@ export class TextFileSaveErrorHandler extends Disposable implements ISaveErrorHa ) { super(); + this.conflictResolutionContext = new RawContextKey(CONFLICT_RESOLUTION_CONTEXT, false, true).bindTo(this.contextKeyService); + const provider = this._register(instantiationService.createInstance(TextFileContentProvider)); this._register(textModelService.registerTextModelContentProvider(CONFLICT_RESOLUTION_SCHEME, provider)); diff --git a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts index dbc04e88561b1..b973a33e23aca 100644 --- a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts @@ -639,8 +639,8 @@ class EditorGroupRenderer implements IListRenderer { static readonly ID = 'openeditor'; - private readonly closeEditorAction = this.instantiationService.createInstance(CloseEditorAction, CloseEditorAction.ID, CloseEditorAction.LABEL); - private readonly unpinEditorAction = this.instantiationService.createInstance(UnpinEditorAction, UnpinEditorAction.ID, UnpinEditorAction.LABEL); + private readonly closeEditorAction: CloseEditorAction; + private readonly unpinEditorAction: UnpinEditorAction; constructor( private labels: ResourceLabels, @@ -648,7 +648,8 @@ class OpenEditorRenderer implements IListRenderer { const model = this._c?.model.read(reader); @@ -36,6 +36,8 @@ export class InlineCompletionLanguageStatusBarContribution extends Disposable { ) { super(); + this._c = InlineCompletionsController.get(this._editor); + this._register(autorunWithStore((reader, store) => { const state = this._state.read(reader); if (!state) { diff --git a/src/vs/workbench/contrib/markers/browser/markersViewActions.ts b/src/vs/workbench/contrib/markers/browser/markersViewActions.ts index fdd6529ef2337..e9cbd57ffbbaa 100644 --- a/src/vs/workbench/contrib/markers/browser/markersViewActions.ts +++ b/src/vs/workbench/contrib/markers/browser/markersViewActions.ts @@ -9,7 +9,7 @@ import { IContextMenuService } from '../../../../platform/contextview/browser/co import Messages from './messages.js'; import { Disposable } from '../../../../base/common/lifecycle.js'; import { Marker } from './markersModel.js'; -import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; +import { IContextKey, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; import { Event, Emitter } from '../../../../base/common/event.js'; import { Codicon } from '../../../../base/common/codicons.js'; import { ThemeIcon } from '../../../../base/common/themables.js'; @@ -42,6 +42,12 @@ export class MarkersFilters extends Disposable { constructor(options: IMarkersFiltersOptions, private readonly contextKeyService: IContextKeyService) { super(); + this._excludedFiles = MarkersContextKeys.ShowExcludedFilesFilterContextKey.bindTo(this.contextKeyService); + this._activeFile = MarkersContextKeys.ShowActiveFileFilterContextKey.bindTo(this.contextKeyService); + this._showWarnings = MarkersContextKeys.ShowWarningsFilterContextKey.bindTo(this.contextKeyService); + this._showErrors = MarkersContextKeys.ShowErrorsFilterContextKey.bindTo(this.contextKeyService); + this._showInfos = MarkersContextKeys.ShowInfoFilterContextKey.bindTo(this.contextKeyService); + this._showErrors.set(options.showErrors); this._showWarnings.set(options.showWarnings); this._showInfos.set(options.showInfos); @@ -52,7 +58,7 @@ export class MarkersFilters extends Disposable { filterHistory: string[]; - private readonly _excludedFiles = MarkersContextKeys.ShowExcludedFilesFilterContextKey.bindTo(this.contextKeyService); + private readonly _excludedFiles: IContextKey; get excludedFiles(): boolean { return !!this._excludedFiles.get(); } @@ -63,7 +69,7 @@ export class MarkersFilters extends Disposable { } } - private readonly _activeFile = MarkersContextKeys.ShowActiveFileFilterContextKey.bindTo(this.contextKeyService); + private readonly _activeFile: IContextKey; get activeFile(): boolean { return !!this._activeFile.get(); } @@ -74,7 +80,7 @@ export class MarkersFilters extends Disposable { } } - private readonly _showWarnings = MarkersContextKeys.ShowWarningsFilterContextKey.bindTo(this.contextKeyService); + private readonly _showWarnings: IContextKey; get showWarnings(): boolean { return !!this._showWarnings.get(); } @@ -85,7 +91,7 @@ export class MarkersFilters extends Disposable { } } - private readonly _showErrors = MarkersContextKeys.ShowErrorsFilterContextKey.bindTo(this.contextKeyService); + private readonly _showErrors: IContextKey; get showErrors(): boolean { return !!this._showErrors.get(); } @@ -96,7 +102,7 @@ export class MarkersFilters extends Disposable { } } - private readonly _showInfos = MarkersContextKeys.ShowInfoFilterContextKey.bindTo(this.contextKeyService); + private readonly _showInfos: IContextKey; get showInfos(): boolean { return !!this._showInfos.get(); } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts index 28217f06aa72d..ddcdb1cdeff64 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput.ts @@ -67,6 +67,13 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput implements @ICustomEditorLabelService customEditorLabelService: ICustomEditorLabelService, ) { super(result, undefined, editorService, textFileService, labelService, fileService, filesConfigurationService, textResourceConfigurationService, customEditorLabelService); + + this.mergeEditorModeFactory = this._instaService.createInstance( + this.useWorkingCopy + ? TempFileMergeEditorModeFactory + : WorkspaceMergeEditorModeFactory, + this._instaService.createInstance(MergeEditorTelemetry), + ); } override dispose(): void { @@ -93,12 +100,7 @@ export class MergeEditorInput extends AbstractTextResourceEditorInput implements return localize('name', "Merging: {0}", super.getName()); } - private readonly mergeEditorModeFactory = this._instaService.createInstance( - this.useWorkingCopy - ? TempFileMergeEditorModeFactory - : WorkspaceMergeEditorModeFactory, - this._instaService.createInstance(MergeEditorTelemetry), - ); + private readonly mergeEditorModeFactory: TempFileMergeEditorModeFactory | WorkspaceMergeEditorModeFactory; override async resolve(): Promise { if (!this._inputModel) { diff --git a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts index c0c4acc617b7a..bbc52cdd4781c 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/mergeEditorInputModel.ts @@ -7,7 +7,7 @@ import { assertFn } from '../../../../base/common/assert.js'; import { BugIndicatingError } from '../../../../base/common/errors.js'; import { Event } from '../../../../base/common/event.js'; import { DisposableStore, IDisposable } from '../../../../base/common/lifecycle.js'; -import { derived, IObservable, observableFromEvent, observableValue } from '../../../../base/common/observable.js'; +import { derived, IObservable, ISettableObservable, observableFromEvent, observableValue } from '../../../../base/common/observable.js'; import { basename, isEqual } from '../../../../base/common/resources.js'; import Severity from '../../../../base/common/severity.js'; import { URI } from '../../../../base/common/uri.js'; @@ -125,7 +125,7 @@ export class TempFileMergeEditorModeFactory implements IMergeEditorInputModelFac } class TempFileMergeEditorInputModel extends EditorModel implements IMergeEditorInputModel { - private readonly savedAltVersionId = observableValue(this, this.model.resultTextModel.getAlternativeVersionId()); + private readonly savedAltVersionId: ISettableObservable; private readonly altVersionId = observableFromEvent(this, e => this.model.resultTextModel.onDidChangeContent(e), () => @@ -146,6 +146,8 @@ class TempFileMergeEditorInputModel extends EditorModel implements IMergeEditorI @IEditorService private readonly editorService: IEditorService, ) { super(); + + this.savedAltVersionId = observableValue(this, this.model.resultTextModel.getAlternativeVersionId()); } override dispose(): void { @@ -340,10 +342,7 @@ export class WorkspaceMergeEditorModeFactory implements IMergeEditorInputModelFa } class WorkspaceMergeEditorInputModel extends EditorModel implements IMergeEditorInputModel { - public readonly isDirty = observableFromEvent(this, - Event.any(this.resultTextFileModel.onDidChangeDirty, this.resultTextFileModel.onDidSaveError), - () => /** @description isDirty */ this.resultTextFileModel.isDirty() - ); + public readonly isDirty: IObservable; private reported = false; private readonly dateTimeOpened = new Date(); @@ -357,6 +356,11 @@ class WorkspaceMergeEditorInputModel extends EditorModel implements IMergeEditor @IStorageService private readonly _storageService: IStorageService, ) { super(); + + this.isDirty = observableFromEvent(this, + Event.any(this.resultTextFileModel.onDidChangeDirty, this.resultTextFileModel.onDidSaveError), + () => /** @description isDirty */ this.resultTextFileModel.isDirty() + ); } public override dispose(): void { diff --git a/src/vs/workbench/contrib/mergeEditor/browser/model/diffComputer.ts b/src/vs/workbench/contrib/mergeEditor/browser/model/diffComputer.ts index 8bc16815852b9..111e80543de4c 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/model/diffComputer.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/model/diffComputer.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { assertFn, checkAdjacentItems } from '../../../../../base/common/assert.js'; -import { IReader } from '../../../../../base/common/observable.js'; +import { IObservable, IReader } from '../../../../../base/common/observable.js'; import { RangeMapping as DiffRangeMapping } from '../../../../../editor/common/diff/rangeMapping.js'; import { ITextModel } from '../../../../../editor/common/model.js'; import { IEditorWorkerService } from '../../../../../editor/common/services/editorWorker.js'; @@ -23,14 +23,15 @@ export interface IMergeDiffComputerResult { } export class MergeDiffComputer implements IMergeDiffComputer { - private readonly mergeAlgorithm = observableConfigValue<'smart' | 'experimental' | 'legacy' | 'advanced'>( - 'mergeEditor.diffAlgorithm', 'advanced', this.configurationService) - .map(v => v === 'smart' ? 'legacy' : v === 'experimental' ? 'advanced' : v); + private readonly mergeAlgorithm: IObservable<'legacy' | 'advanced'>; constructor( @IEditorWorkerService private readonly editorWorkerService: IEditorWorkerService, @IConfigurationService private readonly configurationService: IConfigurationService, ) { + this.mergeAlgorithm = observableConfigValue<'smart' | 'experimental' | 'legacy' | 'advanced'>( + 'mergeEditor.diffAlgorithm', 'advanced', this.configurationService) + .map(v => v === 'smart' ? 'legacy' : v === 'experimental' ? 'advanced' : v); } async computeDiff(textModel1: ITextModel, textModel2: ITextModel, reader: IReader): Promise { diff --git a/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts b/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts index 26c5f44afd109..54adf7d103d41 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/model/mergeEditorModel.ts @@ -5,11 +5,11 @@ import { CompareResult, equals } from '../../../../../base/common/arrays.js'; import { BugIndicatingError } from '../../../../../base/common/errors.js'; -import { autorunHandleChanges, derived, IObservable, IReader, ISettableObservable, ITransaction, keepObserved, observableValue, transaction, waitForState } from '../../../../../base/common/observable.js'; +import { autorunHandleChanges, derived, IObservable, IObservableWithChange, IReader, ISettableObservable, ITransaction, keepObserved, observableValue, transaction, waitForState } from '../../../../../base/common/observable.js'; import { URI } from '../../../../../base/common/uri.js'; import { Range } from '../../../../../editor/common/core/range.js'; import { ILanguageService } from '../../../../../editor/common/languages/language.js'; -import { ITextModel } from '../../../../../editor/common/model.js'; +import { ITextModel, ITextSnapshot } from '../../../../../editor/common/model.js'; import { localize } from '../../../../../nls.js'; import { IResourceUndoRedoElement, IUndoRedoService, UndoRedoElementType, UndoRedoGroup } from '../../../../../platform/undoRedo/common/undoRedo.js'; import { EditorModel } from '../../../../common/editor/editorModel.js'; @@ -29,16 +29,16 @@ export interface InputData { } export class MergeEditorModel extends EditorModel { - private readonly input1TextModelDiffs = this._register(new TextModelDiffs(this.base, this.input1.textModel, this.diffComputer)); - private readonly input2TextModelDiffs = this._register(new TextModelDiffs(this.base, this.input2.textModel, this.diffComputer)); - private readonly resultTextModelDiffs = this._register(new TextModelDiffs(this.base, this.resultTextModel, this.diffComputer)); + private readonly input1TextModelDiffs: TextModelDiffs; + private readonly input2TextModelDiffs: TextModelDiffs; + private readonly resultTextModelDiffs: TextModelDiffs; public readonly modifiedBaseRanges = derived(this, (reader) => { const input1Diffs = this.input1TextModelDiffs.diffs.read(reader); const input2Diffs = this.input2TextModelDiffs.diffs.read(reader); return ModifiedBaseRange.fromDiffs(input1Diffs, input2Diffs, this.base, this.input1.textModel, this.input2.textModel); }); - private readonly modifiedBaseRangeResultStates = derived(this, reader => { + private readonly modifiedBaseRangeResultStates: IObservable> = derived(this, reader => { const map = new Map( this.modifiedBaseRanges.read(reader).map<[ModifiedBaseRange, ModifiedBaseRangeData]>((s) => [ s, new ModifiedBaseRangeData(s) @@ -47,7 +47,7 @@ export class MergeEditorModel extends EditorModel { return map; }); - private readonly resultSnapshot = this.resultTextModel.createSnapshot(); + private readonly resultSnapshot: ITextSnapshot; constructor( readonly base: ITextModel, @@ -62,6 +62,35 @@ export class MergeEditorModel extends EditorModel { ) { super(); + this.input1TextModelDiffs = this._register(new TextModelDiffs(this.base, this.input1.textModel, this.diffComputer)); + this.input2TextModelDiffs = this._register(new TextModelDiffs(this.base, this.input2.textModel, this.diffComputer)); + this.resultTextModelDiffs = this._register(new TextModelDiffs(this.base, this.resultTextModel, this.diffComputer)); + + this.resultSnapshot = this.resultTextModel.createSnapshot(); + + this.baseInput1Diffs = this.input1TextModelDiffs.diffs; + + this.baseInput2Diffs = this.input2TextModelDiffs.diffs; + this.baseResultDiffs = this.resultTextModelDiffs.diffs; + + this.diffComputingState = derived(this, reader => { + const states = [ + this.input1TextModelDiffs, + this.input2TextModelDiffs, + this.resultTextModelDiffs, + ].map((s) => s.state.read(reader)); + + if (states.some((s) => s === TextModelDiffState.initializing)) { + return MergeEditorModelState.initializing; + } + if (states.some((s) => s === TextModelDiffState.updating)) { + return MergeEditorModelState.updating; + } + return MergeEditorModelState.upToDate; + }); + + this.onInitialized = waitForState(this.diffComputingState, state => state === MergeEditorModelState.upToDate).then(() => { }); + this._register(keepObserved(this.modifiedBaseRangeResultStates)); this._register(keepObserved(this.input1ResultMapping)); this._register(keepObserved(this.input2ResultMapping)); @@ -199,10 +228,10 @@ export class MergeEditorModel extends EditorModel { return this.modifiedBaseRangeResultStates.get().has(baseRange); } - public readonly baseInput1Diffs = this.input1TextModelDiffs.diffs; + public readonly baseInput1Diffs: IObservableWithChange; - public readonly baseInput2Diffs = this.input2TextModelDiffs.diffs; - public readonly baseResultDiffs = this.resultTextModelDiffs.diffs; + public readonly baseInput2Diffs: IObservableWithChange; + public readonly baseResultDiffs: IObservableWithChange; public get isApplyingEditInResult(): boolean { return this.resultTextModelDiffs.isApplyingChange; } public readonly input1ResultMapping = derived(this, reader => { return this.getInputResultMapping( @@ -289,21 +318,7 @@ export class MergeEditorModel extends EditorModel { return this.modifiedBaseRanges.get().filter(r => r.baseRange.intersects(rangeInBase)); } - public readonly diffComputingState = derived(this, reader => { - const states = [ - this.input1TextModelDiffs, - this.input2TextModelDiffs, - this.resultTextModelDiffs, - ].map((s) => s.state.read(reader)); - - if (states.some((s) => s === TextModelDiffState.initializing)) { - return MergeEditorModelState.initializing; - } - if (states.some((s) => s === TextModelDiffState.updating)) { - return MergeEditorModelState.updating; - } - return MergeEditorModelState.upToDate; - }); + public readonly diffComputingState: IObservable; public readonly inputDiffComputingState = derived(this, reader => { const states = [ @@ -322,7 +337,7 @@ export class MergeEditorModel extends EditorModel { public readonly isUpToDate = derived(this, reader => this.diffComputingState.read(reader) === MergeEditorModelState.upToDate); - public readonly onInitialized = waitForState(this.diffComputingState, state => state === MergeEditorModelState.upToDate).then(() => { }); + public readonly onInitialized: Promise; private firstRun = true; private updateBaseRangeAcceptedState(resultDiffs: DetailedLineRangeMapping[], states: Map, tx: ITransaction): void { @@ -755,11 +770,15 @@ function arrayCount(array: Iterable, predicate: (value: T) => boolean): nu } class ModifiedBaseRangeData { - constructor(private readonly baseRange: ModifiedBaseRange) { } + constructor(private readonly baseRange: ModifiedBaseRange) { + this.accepted = observableValue(`BaseRangeState${this.baseRange.baseRange}`, ModifiedBaseRangeState.base); + this.handledInput1 = observableValue(`BaseRangeHandledState${this.baseRange.baseRange}.Input1`, false); + this.handledInput2 = observableValue(`BaseRangeHandledState${this.baseRange.baseRange}.Input2`, false); + } - public accepted: ISettableObservable = observableValue(`BaseRangeState${this.baseRange.baseRange}`, ModifiedBaseRangeState.base); - public handledInput1: ISettableObservable = observableValue(`BaseRangeHandledState${this.baseRange.baseRange}.Input1`, false); - public handledInput2: ISettableObservable = observableValue(`BaseRangeHandledState${this.baseRange.baseRange}.Input2`, false); + public accepted: ISettableObservable; + public handledInput1: ISettableObservable; + public handledInput2: ISettableObservable; public computedFromDiffing = false; public previousNonDiffingState: ModifiedBaseRangeState | undefined = undefined; diff --git a/src/vs/workbench/contrib/mergeEditor/browser/model/modifiedBaseRange.ts b/src/vs/workbench/contrib/mergeEditor/browser/model/modifiedBaseRange.ts index cd62b5944a1ad..4941345e9d97c 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/model/modifiedBaseRange.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/model/modifiedBaseRange.ts @@ -45,9 +45,9 @@ export class ModifiedBaseRange { ); } - public readonly input1CombinedDiff = DetailedLineRangeMapping.join(this.input1Diffs); - public readonly input2CombinedDiff = DetailedLineRangeMapping.join(this.input2Diffs); - public readonly isEqualChange = equals(this.input1Diffs, this.input2Diffs, (a, b) => a.getLineEdit().equals(b.getLineEdit())); + public readonly input1CombinedDiff: DetailedLineRangeMapping | undefined; + public readonly input2CombinedDiff: DetailedLineRangeMapping | undefined; + public readonly isEqualChange: boolean; constructor( public readonly baseRange: LineRange, @@ -67,6 +67,10 @@ export class ModifiedBaseRange { */ public readonly input2Diffs: readonly DetailedLineRangeMapping[] ) { + this.input1CombinedDiff = DetailedLineRangeMapping.join(this.input1Diffs); + this.input2CombinedDiff = DetailedLineRangeMapping.join(this.input2Diffs); + this.isEqualChange = equals(this.input1Diffs, this.input2Diffs, (a, b) => a.getLineEdit().equals(b.getLineEdit())); + if (this.input1Diffs.length === 0 && this.input2Diffs.length === 0) { throw new BugIndicatingError('must have at least one diff'); } diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editorGutter.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editorGutter.ts index 18cb85e229226..3de8ee66c3746 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editorGutter.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editorGutter.ts @@ -5,23 +5,17 @@ import { h, reset } from '../../../../../base/browser/dom.js'; import { Disposable, IDisposable, toDisposable } from '../../../../../base/common/lifecycle.js'; -import { autorun, IReader, observableFromEvent, observableSignal, observableSignalFromEvent, transaction } from '../../../../../base/common/observable.js'; +import { autorun, IObservable, IReader, observableFromEvent, observableSignal, observableSignalFromEvent, transaction } from '../../../../../base/common/observable.js'; import { CodeEditorWidget } from '../../../../../editor/browser/widget/codeEditor/codeEditorWidget.js'; import { LineRange } from '../model/lineRange.js'; export class EditorGutter extends Disposable { - private readonly scrollTop = observableFromEvent(this, - this._editor.onDidScrollChange, - (e) => /** @description editor.onDidScrollChange */ this._editor.getScrollTop() - ); - private readonly isScrollTopZero = this.scrollTop.map((scrollTop) => /** @description isScrollTopZero */ scrollTop === 0); - private readonly modelAttached = observableFromEvent(this, - this._editor.onDidChangeModel, - (e) => /** @description editor.onDidChangeModel */ this._editor.hasModel() - ); - - private readonly editorOnDidChangeViewZones = observableSignalFromEvent('onDidChangeViewZones', this._editor.onDidChangeViewZones); - private readonly editorOnDidContentSizeChange = observableSignalFromEvent('onDidContentSizeChange', this._editor.onDidContentSizeChange); + private readonly scrollTop: IObservable; + private readonly isScrollTopZero: IObservable; + private readonly modelAttached: IObservable; + + private readonly editorOnDidChangeViewZones: IObservable; + private readonly editorOnDidContentSizeChange: IObservable; private readonly domNodeSizeChanged = observableSignal('domNodeSizeChanged'); constructor( @@ -30,6 +24,20 @@ export class EditorGutter extends D private readonly itemProvider: IGutterItemProvider ) { super(); + + this.scrollTop = observableFromEvent(this, + this._editor.onDidScrollChange, + (e) => /** @description editor.onDidScrollChange */ this._editor.getScrollTop() + ); + this.isScrollTopZero = this.scrollTop.map((scrollTop) => /** @description isScrollTopZero */ scrollTop === 0); + this.modelAttached = observableFromEvent(this, + this._editor.onDidChangeModel, + (e) => /** @description editor.onDidChangeModel */ this._editor.hasModel() + ); + + this.editorOnDidChangeViewZones = observableSignalFromEvent('onDidChangeViewZones', this._editor.onDidChangeViewZones); + this.editorOnDidContentSizeChange = observableSignalFromEvent('onDidContentSizeChange', this._editor.onDidContentSizeChange); + this._domNode.className = 'gutter monaco-editor'; const scrollDecoration = this._domNode.appendChild( h('div.scroll-decoration', { role: 'presentation', ariaHidden: 'true', style: { width: '100%' } }) diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts index 5520e2a0d7237..9a436d09e423a 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/codeEditorView.ts @@ -23,9 +23,11 @@ import { DEFAULT_EDITOR_MAX_DIMENSIONS, DEFAULT_EDITOR_MIN_DIMENSIONS } from '.. import { setStyle } from '../../utils.js'; import { observableConfigValue } from '../../../../../../platform/observable/common/platformObservableUtils.js'; import { MergeEditorViewModel } from '../viewModel.js'; +import { Position } from '../../../../../../editor/common/core/position.js'; +import { MergeEditorModel } from '../../model/mergeEditorModel.js'; export abstract class CodeEditorView extends Disposable { - readonly model = this.viewModel.map(m => /** @description model */ m?.model); + readonly model: IObservable; protected readonly htmlElements = h('div.code-view', [ h('div.header@header', [ @@ -62,39 +64,23 @@ export abstract class CodeEditorView extends Disposable { // snap?: boolean | undefined; }; - protected readonly checkboxesVisible = observableConfigValue('mergeEditor.showCheckboxes', false, this.configurationService); - protected readonly showDeletionMarkers = observableConfigValue('mergeEditor.showDeletionMarkers', true, this.configurationService); - protected readonly useSimplifiedDecorations = observableConfigValue('mergeEditor.useSimplifiedDecorations', false, this.configurationService); + protected readonly checkboxesVisible: IObservable; + protected readonly showDeletionMarkers: IObservable; + protected readonly useSimplifiedDecorations: IObservable; - public readonly editor = this.instantiationService.createInstance( - CodeEditorWidget, - this.htmlElements.editor, - {}, - { - contributions: this.getEditorContributions(), - } - ); + public readonly editor: CodeEditorWidget; public updateOptions(newOptions: Readonly): void { this.editor.updateOptions(newOptions); } - public readonly isFocused = observableFromEvent(this, - Event.any(this.editor.onDidBlurEditorWidget, this.editor.onDidFocusEditorWidget), - () => /** @description editor.hasWidgetFocus */ this.editor.hasWidgetFocus() - ); + public readonly isFocused: IObservable; - public readonly cursorPosition = observableFromEvent(this, - this.editor.onDidChangeCursorPosition, - () => /** @description editor.getPosition */ this.editor.getPosition() - ); + public readonly cursorPosition: IObservable; - public readonly selection = observableFromEvent(this, - this.editor.onDidChangeCursorSelection, - () => /** @description editor.getSelections */ this.editor.getSelections() - ); + public readonly selection: IObservable; - public readonly cursorLineNumber = this.cursorPosition.map(p => /** @description cursorPosition.lineNumber */ p?.lineNumber); + public readonly cursorLineNumber: IObservable; constructor( private readonly instantiationService: IInstantiationService, @@ -103,6 +89,37 @@ export abstract class CodeEditorView extends Disposable { ) { super(); + this.model = this.viewModel.map(m => /** @description model */ m?.model); + + this.checkboxesVisible = observableConfigValue('mergeEditor.showCheckboxes', false, this.configurationService); + this.showDeletionMarkers = observableConfigValue('mergeEditor.showDeletionMarkers', true, this.configurationService); + this.useSimplifiedDecorations = observableConfigValue('mergeEditor.useSimplifiedDecorations', false, this.configurationService); + + this.editor = this.instantiationService.createInstance( + CodeEditorWidget, + this.htmlElements.editor, + {}, + { + contributions: this.getEditorContributions(), + } + ); + + this.isFocused = observableFromEvent(this, + Event.any(this.editor.onDidBlurEditorWidget, this.editor.onDidFocusEditorWidget), + () => /** @description editor.hasWidgetFocus */ this.editor.hasWidgetFocus() + ); + + this.cursorPosition = observableFromEvent(this, + this.editor.onDidChangeCursorPosition, + () => /** @description editor.getPosition */ this.editor.getPosition() + ); + + this.selection = observableFromEvent(this, + this.editor.onDidChangeCursorSelection, + () => /** @description editor.getSelections */ this.editor.getSelections() + ); + + this.cursorLineNumber = this.cursorPosition.map(p => /** @description cursorPosition.lineNumber */ p?.lineNumber); } protected getEditorContributions(): IEditorContributionDescription[] { diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts index 4a3b0081cd345..0588852a3e8be 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/editors/inputCodeEditorView.ts @@ -27,9 +27,11 @@ import { handledConflictMinimapOverViewRulerColor, unhandledConflictMinimapOverV import { MergeEditorViewModel } from '../viewModel.js'; import { EditorGutter, IGutterItemInfo, IGutterItemView } from '../editorGutter.js'; import { CodeEditorView, createSelectionsAutorun, TitleMenu } from './codeEditorView.js'; +import { MergeEditorModel } from '../../model/mergeEditorModel.js'; +import { LineRange } from '../../model/lineRange.js'; export class InputCodeEditorView extends CodeEditorView { - public readonly otherInputNumber = this.inputNumber === 1 ? 2 : 1; + public readonly otherInputNumber: 1 | 2; constructor( public readonly inputNumber: 1 | 2, @@ -40,8 +42,124 @@ export class InputCodeEditorView extends CodeEditorView { ) { super(instantiationService, viewModel, configurationService); + this.otherInputNumber = this.inputNumber === 1 ? 2 : 1; + this.htmlElements.root.classList.add(`input`); + this.modifiedBaseRangeGutterItemInfos = derivedOpts({ debugName: `input${this.inputNumber}.modifiedBaseRangeGutterItemInfos` }, reader => { + const viewModel = this.viewModel.read(reader); + if (!viewModel) { return []; } + const model = viewModel.model; + const inputNumber = this.inputNumber; + + const showNonConflictingChanges = viewModel.showNonConflictingChanges.read(reader); + + return model.modifiedBaseRanges.read(reader) + .filter((r) => r.getInputDiffs(this.inputNumber).length > 0 && (showNonConflictingChanges || r.isConflicting || !model.isHandled(r).read(reader))) + .map((baseRange, idx) => new ModifiedBaseRangeGutterItemModel(idx.toString(), baseRange, inputNumber, viewModel)); + }); + + this.decorations = derivedOpts({ debugName: `input${this.inputNumber}.decorations` }, reader => { + const viewModel = this.viewModel.read(reader); + if (!viewModel) { + return []; + } + const model = viewModel.model; + const textModel = (this.inputNumber === 1 ? model.input1 : model.input2).textModel; + + const activeModifiedBaseRange = viewModel.activeModifiedBaseRange.read(reader); + + const result = new Array(); + + const showNonConflictingChanges = viewModel.showNonConflictingChanges.read(reader); + const showDeletionMarkers = this.showDeletionMarkers.read(reader); + const diffWithThis = viewModel.baseCodeEditorView.read(reader) !== undefined && viewModel.baseShowDiffAgainst.read(reader) === this.inputNumber; + const useSimplifiedDecorations = !diffWithThis && this.useSimplifiedDecorations.read(reader); + + for (const modifiedBaseRange of model.modifiedBaseRanges.read(reader)) { + const range = modifiedBaseRange.getInputRange(this.inputNumber); + if (!range) { + continue; + } + + const blockClassNames = ['merge-editor-block']; + let blockPadding: [top: number, right: number, bottom: number, left: number] = [0, 0, 0, 0]; + const isHandled = model.isInputHandled(modifiedBaseRange, this.inputNumber).read(reader); + if (isHandled) { + blockClassNames.push('handled'); + } + if (modifiedBaseRange === activeModifiedBaseRange) { + blockClassNames.push('focused'); + blockPadding = [0, 2, 0, 2]; + } + if (modifiedBaseRange.isConflicting) { + blockClassNames.push('conflicting'); + } + const inputClassName = this.inputNumber === 1 ? 'input i1' : 'input i2'; + blockClassNames.push(inputClassName); + + if (!modifiedBaseRange.isConflicting && !showNonConflictingChanges && isHandled) { + continue; + } + + if (useSimplifiedDecorations && !isHandled) { + blockClassNames.push('use-simplified-decorations'); + } + + result.push({ + range: range.toInclusiveRangeOrEmpty(), + options: { + showIfCollapsed: true, + blockClassName: blockClassNames.join(' '), + blockPadding, + blockIsAfterEnd: range.startLineNumber > textModel.getLineCount(), + description: 'Merge Editor', + minimap: { + position: MinimapPosition.Gutter, + color: { id: isHandled ? handledConflictMinimapOverViewRulerColor : unhandledConflictMinimapOverViewRulerColor }, + }, + overviewRuler: modifiedBaseRange.isConflicting ? { + position: OverviewRulerLane.Center, + color: { id: isHandled ? handledConflictMinimapOverViewRulerColor : unhandledConflictMinimapOverViewRulerColor }, + } : undefined + } + }); + + if (!useSimplifiedDecorations && (modifiedBaseRange.isConflicting || !model.isHandled(modifiedBaseRange).read(reader))) { + const inputDiffs = modifiedBaseRange.getInputDiffs(this.inputNumber); + for (const diff of inputDiffs) { + const range = diff.outputRange.toInclusiveRange(); + if (range) { + result.push({ + range, + options: { + className: `merge-editor-diff ${inputClassName}`, + description: 'Merge Editor', + isWholeLine: true, + } + }); + } + + if (diff.rangeMappings) { + for (const d of diff.rangeMappings) { + if (showDeletionMarkers || !d.outputRange.isEmpty()) { + result.push({ + range: d.outputRange, + options: { + className: d.outputRange.isEmpty() ? `merge-editor-diff-empty-word ${inputClassName}` : `merge-editor-diff-word ${inputClassName}`, + description: 'Merge Editor', + showIfCollapsed: true, + } + }); + } + } + } + } + } + } + return result; + }); + this._register( new EditorGutter(this.editor, this.htmlElements.gutterDiv, { getIntersectingGutterItems: (range, reader) => { @@ -98,124 +216,14 @@ export class InputCodeEditorView extends CodeEditorView { this._register(applyObservableDecorations(this.editor, this.decorations)); } - private readonly modifiedBaseRangeGutterItemInfos = derivedOpts({ debugName: `input${this.inputNumber}.modifiedBaseRangeGutterItemInfos` }, reader => { - const viewModel = this.viewModel.read(reader); - if (!viewModel) { return []; } - const model = viewModel.model; - const inputNumber = this.inputNumber; + private readonly modifiedBaseRangeGutterItemInfos: IObservable; - const showNonConflictingChanges = viewModel.showNonConflictingChanges.read(reader); - - return model.modifiedBaseRanges.read(reader) - .filter((r) => r.getInputDiffs(this.inputNumber).length > 0 && (showNonConflictingChanges || r.isConflicting || !model.isHandled(r).read(reader))) - .map((baseRange, idx) => new ModifiedBaseRangeGutterItemModel(idx.toString(), baseRange, inputNumber, viewModel)); - }); - - private readonly decorations = derivedOpts({ debugName: `input${this.inputNumber}.decorations` }, reader => { - const viewModel = this.viewModel.read(reader); - if (!viewModel) { - return []; - } - const model = viewModel.model; - const textModel = (this.inputNumber === 1 ? model.input1 : model.input2).textModel; - - const activeModifiedBaseRange = viewModel.activeModifiedBaseRange.read(reader); - - const result = new Array(); - - const showNonConflictingChanges = viewModel.showNonConflictingChanges.read(reader); - const showDeletionMarkers = this.showDeletionMarkers.read(reader); - const diffWithThis = viewModel.baseCodeEditorView.read(reader) !== undefined && viewModel.baseShowDiffAgainst.read(reader) === this.inputNumber; - const useSimplifiedDecorations = !diffWithThis && this.useSimplifiedDecorations.read(reader); - - for (const modifiedBaseRange of model.modifiedBaseRanges.read(reader)) { - const range = modifiedBaseRange.getInputRange(this.inputNumber); - if (!range) { - continue; - } - - const blockClassNames = ['merge-editor-block']; - let blockPadding: [top: number, right: number, bottom: number, left: number] = [0, 0, 0, 0]; - const isHandled = model.isInputHandled(modifiedBaseRange, this.inputNumber).read(reader); - if (isHandled) { - blockClassNames.push('handled'); - } - if (modifiedBaseRange === activeModifiedBaseRange) { - blockClassNames.push('focused'); - blockPadding = [0, 2, 0, 2]; - } - if (modifiedBaseRange.isConflicting) { - blockClassNames.push('conflicting'); - } - const inputClassName = this.inputNumber === 1 ? 'input i1' : 'input i2'; - blockClassNames.push(inputClassName); - - if (!modifiedBaseRange.isConflicting && !showNonConflictingChanges && isHandled) { - continue; - } - - if (useSimplifiedDecorations && !isHandled) { - blockClassNames.push('use-simplified-decorations'); - } - - result.push({ - range: range.toInclusiveRangeOrEmpty(), - options: { - showIfCollapsed: true, - blockClassName: blockClassNames.join(' '), - blockPadding, - blockIsAfterEnd: range.startLineNumber > textModel.getLineCount(), - description: 'Merge Editor', - minimap: { - position: MinimapPosition.Gutter, - color: { id: isHandled ? handledConflictMinimapOverViewRulerColor : unhandledConflictMinimapOverViewRulerColor }, - }, - overviewRuler: modifiedBaseRange.isConflicting ? { - position: OverviewRulerLane.Center, - color: { id: isHandled ? handledConflictMinimapOverViewRulerColor : unhandledConflictMinimapOverViewRulerColor }, - } : undefined - } - }); - - if (!useSimplifiedDecorations && (modifiedBaseRange.isConflicting || !model.isHandled(modifiedBaseRange).read(reader))) { - const inputDiffs = modifiedBaseRange.getInputDiffs(this.inputNumber); - for (const diff of inputDiffs) { - const range = diff.outputRange.toInclusiveRange(); - if (range) { - result.push({ - range, - options: { - className: `merge-editor-diff ${inputClassName}`, - description: 'Merge Editor', - isWholeLine: true, - } - }); - } - - if (diff.rangeMappings) { - for (const d of diff.rangeMappings) { - if (showDeletionMarkers || !d.outputRange.isEmpty()) { - result.push({ - range: d.outputRange, - options: { - className: d.outputRange.isEmpty() ? `merge-editor-diff-empty-word ${inputClassName}` : `merge-editor-diff-word ${inputClassName}`, - description: 'Merge Editor', - showIfCollapsed: true, - } - }); - } - } - } - } - } - } - return result; - }); + private readonly decorations: IObservable; } export class ModifiedBaseRangeGutterItemModel implements IGutterItemInfo { - private readonly model = this.viewModel.model; - public readonly range = this.baseRange.getInputRange(this.inputNumber); + private readonly model: MergeEditorModel; + public readonly range: LineRange; constructor( public readonly id: string, @@ -223,9 +231,13 @@ export class ModifiedBaseRangeGutterItemModel implements IGutterItemInfo { private readonly inputNumber: 1 | 2, private readonly viewModel: MergeEditorViewModel ) { + this.model = this.viewModel.model; + this.range = this.baseRange.getInputRange(this.inputNumber); + + this.enabled = this.model.isUpToDate; } - public readonly enabled = this.model.isUpToDate; + public readonly enabled: IObservable; public readonly toggleState: IObservable = derived(this, reader => { const input = this.model diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts index 32b12772bef78..e917b35b3bb98 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/mergeEditor.ts @@ -75,13 +75,13 @@ export class MergeEditor extends AbstractTextEditor { private readonly inputResultView = this._register(this.instantiationService.createInstance(ResultCodeEditorView, this._viewModel)); private readonly _layoutMode = this.instantiationService.createInstance(MergeEditorLayoutStore); private readonly _layoutModeObs = observableValue(this, this._layoutMode.value); - private readonly _ctxIsMergeEditor: IContextKey = ctxIsMergeEditor.bindTo(this.contextKeyService); - private readonly _ctxUsesColumnLayout: IContextKey = ctxMergeEditorLayout.bindTo(this.contextKeyService); - private readonly _ctxShowBase: IContextKey = ctxMergeEditorShowBase.bindTo(this.contextKeyService); - private readonly _ctxShowBaseAtTop = ctxMergeEditorShowBaseAtTop.bindTo(this.contextKeyService); - private readonly _ctxResultUri: IContextKey = ctxMergeResultUri.bindTo(this.contextKeyService); - private readonly _ctxBaseUri: IContextKey = ctxMergeBaseUri.bindTo(this.contextKeyService); - private readonly _ctxShowNonConflictingChanges: IContextKey = ctxMergeEditorShowNonConflictingChanges.bindTo(this.contextKeyService); + private readonly _ctxIsMergeEditor: IContextKey; + private readonly _ctxUsesColumnLayout: IContextKey; + private readonly _ctxShowBase: IContextKey; + private readonly _ctxShowBaseAtTop: IContextKey; + private readonly _ctxResultUri: IContextKey; + private readonly _ctxBaseUri: IContextKey; + private readonly _ctxShowNonConflictingChanges: IContextKey; private readonly _inputModel = observableValue(this, undefined); public get inputModel(): IObservable { return this._inputModel; @@ -100,11 +100,7 @@ export class MergeEditor extends AbstractTextEditor { this.inputResultView.editor, ); - protected readonly codeLensesVisible = observableConfigValue( - 'mergeEditor.showCodeLenses', - true, - this.configurationService, - ); + protected readonly codeLensesVisible: IObservable; private readonly scrollSynchronizer = this._register(new ScrollSynchronizer(this._viewModel, this.input1View, this.input2View, this.baseView, this.inputResultView, this._layoutModeObs)); @@ -124,6 +120,20 @@ export class MergeEditor extends AbstractTextEditor { @IConfigurationService private readonly configurationService: IConfigurationService ) { super(MergeEditor.ID, group, telemetryService, instantiation, storageService, textResourceConfigurationService, themeService, editorService, editorGroupService, fileService); + + this._ctxIsMergeEditor = ctxIsMergeEditor.bindTo(this.contextKeyService); + this._ctxUsesColumnLayout = ctxMergeEditorLayout.bindTo(this.contextKeyService); + this._ctxShowBase = ctxMergeEditorShowBase.bindTo(this.contextKeyService); + this._ctxShowBaseAtTop = ctxMergeEditorShowBaseAtTop.bindTo(this.contextKeyService); + this._ctxResultUri = ctxMergeResultUri.bindTo(this.contextKeyService); + this._ctxBaseUri = ctxMergeBaseUri.bindTo(this.contextKeyService); + this._ctxShowNonConflictingChanges = ctxMergeEditorShowNonConflictingChanges.bindTo(this.contextKeyService); + + this.codeLensesVisible = observableConfigValue( + 'mergeEditor.showCodeLenses', + true, + this.configurationService, + ); } override dispose(): void { diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/viewModel.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/viewModel.ts index 74322dc65a405..5c7074dc06544 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/viewModel.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/viewModel.ts @@ -26,7 +26,7 @@ export class MergeEditorViewModel extends Disposable { { range: ModifiedBaseRange | undefined; counter: number } >(this, { range: undefined, counter: 0 }); - private readonly attachedHistory = this._register(new AttachedHistory(this.model.resultTextModel)); + private readonly attachedHistory: AttachedHistory; constructor( public readonly model: MergeEditorModel, @@ -40,6 +40,14 @@ export class MergeEditorViewModel extends Disposable { ) { super(); + this.attachedHistory = this._register(new AttachedHistory(this.model.resultTextModel)); + + this.shouldUseAppendInsteadOfAccept = observableConfigValue( + 'mergeEditor.shouldUseAppendInsteadOfAccept', + false, + this.configurationService, + ); + this._register(resultCodeEditorView.editor.onDidChangeModelContent(e => { if (this.model.isApplyingEditInResult || e.isRedoing || e.isUndoing) { return; @@ -86,11 +94,7 @@ export class MergeEditorViewModel extends Disposable { })); } - public readonly shouldUseAppendInsteadOfAccept = observableConfigValue( - 'mergeEditor.shouldUseAppendInsteadOfAccept', - false, - this.configurationService, - ); + public readonly shouldUseAppendInsteadOfAccept: IObservable; private counter = 0; private readonly lastFocusedEditor = derivedObservableWithWritableCache< @@ -293,11 +297,13 @@ export class MergeEditorViewModel extends Disposable { class AttachedHistory extends Disposable { private readonly attachedHistory: { element: IAttachedHistoryElement; altId: number }[] = []; - private previousAltId: number = this.model.getAlternativeVersionId(); + private previousAltId: number; constructor(private readonly model: ITextModel) { super(); + this.previousAltId = this.model.getAlternativeVersionId(); + this._register(model.onDidChangeContent((e) => { const currentAltId = model.getAlternativeVersionId(); diff --git a/src/vs/workbench/contrib/mergeEditor/browser/view/viewZones.ts b/src/vs/workbench/contrib/mergeEditor/browser/view/viewZones.ts index edd459163737b..c832fc74dcba3 100644 --- a/src/vs/workbench/contrib/mergeEditor/browser/view/viewZones.ts +++ b/src/vs/workbench/contrib/mergeEditor/browser/view/viewZones.ts @@ -17,15 +17,19 @@ import { getAlignments } from './lineAlignment.js'; import { MergeEditorViewModel } from './viewModel.js'; export class ViewZoneComputer { - private readonly conflictActionsFactoryInput1 = new ConflictActionsFactory(this.input1Editor); - private readonly conflictActionsFactoryInput2 = new ConflictActionsFactory(this.input2Editor); - private readonly conflictActionsFactoryResult = new ConflictActionsFactory(this.resultEditor); + private readonly conflictActionsFactoryInput1: ConflictActionsFactory; + private readonly conflictActionsFactoryInput2: ConflictActionsFactory; + private readonly conflictActionsFactoryResult: ConflictActionsFactory; constructor( private readonly input1Editor: ICodeEditor, private readonly input2Editor: ICodeEditor, private readonly resultEditor: ICodeEditor, - ) { } + ) { + this.conflictActionsFactoryInput1 = new ConflictActionsFactory(this.input1Editor); + this.conflictActionsFactoryInput2 = new ConflictActionsFactory(this.input2Editor); + this.conflictActionsFactoryResult = new ConflictActionsFactory(this.resultEditor); + } public computeViewZones( reader: IReader, diff --git a/src/vs/workbench/contrib/multiDiffEditor/browser/multiDiffEditorInput.ts b/src/vs/workbench/contrib/multiDiffEditor/browser/multiDiffEditorInput.ts index aa09311d40184..cd82da49caba6 100644 --- a/src/vs/workbench/contrib/multiDiffEditor/browser/multiDiffEditorInput.ts +++ b/src/vs/workbench/contrib/multiDiffEditor/browser/multiDiffEditorInput.ts @@ -93,6 +93,12 @@ export class MultiDiffEditorInput extends EditorInput implements ILanguageSuppor ) { super(); + this.textFileServiceOnDidChange = new FastEventDispatcher( + this._textFileService.files.onDidChangeDirty, + item => item.resource.toString(), + uri => uri.toString() + ); + this._register(autorun((reader) => { /** @description Updates name */ const resources = this.resources.read(reader); @@ -233,11 +239,7 @@ export class MultiDiffEditorInput extends EditorInput implements ILanguageSuppor public readonly resources = derived(this, reader => this._resolvedSource.cachedPromiseResult.read(reader)?.data?.resources.read(reader)); - private readonly textFileServiceOnDidChange = new FastEventDispatcher( - this._textFileService.files.onDidChangeDirty, - item => item.resource.toString(), - uri => uri.toString() - ); + private readonly textFileServiceOnDidChange: FastEventDispatcher; private readonly _isDirtyObservables = mapObservableArrayCached(this, this.resources.map(r => r ?? []), res => { const isModifiedDirty = res.modifiedUri ? isUriDirty(this.textFileServiceOnDidChange, this._textFileService, res.modifiedUri) : constObservable(false); diff --git a/src/vs/workbench/contrib/multiDiffEditor/browser/scmMultiDiffSourceResolver.ts b/src/vs/workbench/contrib/multiDiffEditor/browser/scmMultiDiffSourceResolver.ts index ec198f8ad6344..951530deb2477 100644 --- a/src/vs/workbench/contrib/multiDiffEditor/browser/scmMultiDiffSourceResolver.ts +++ b/src/vs/workbench/contrib/multiDiffEditor/browser/scmMultiDiffSourceResolver.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable } from '../../../../base/common/lifecycle.js'; -import { observableFromEvent, ValueWithChangeEventFromObservable, waitForState } from '../../../../base/common/observable.js'; +import { IObservable, observableFromEvent, ValueWithChangeEventFromObservable, waitForState } from '../../../../base/common/observable.js'; import { URI, UriComponents } from '../../../../base/common/uri.js'; import { IMultiDiffEditorOptions } from '../../../../editor/browser/widget/multiDiffEditor/multiDiffEditorWidgetImpl.js'; import { localize2 } from '../../../../nls.js'; @@ -84,21 +84,26 @@ export class ScmMultiDiffSourceResolver implements IMultiDiffSourceResolver { } class ScmResolvedMultiDiffSource implements IResolvedMultiDiffSource { - private readonly _resources = observableFromEvent( - this._group.onDidChangeResources, - () => /** @description resources */ this._group.resources.map(e => new MultiDiffEditorItem(e.multiDiffEditorOriginalUri, e.multiDiffEditorModifiedUri, e.sourceUri)) - ); - readonly resources = new ValueWithChangeEventFromObservable(this._resources); + private readonly _resources: IObservable; + readonly resources: ValueWithChangeEventFromObservable; - public readonly contextKeys: Record = { - scmResourceGroup: this._group.id, - scmProvider: this._repository.provider.contextValue, - }; + public readonly contextKeys: Record; constructor( private readonly _group: ISCMResourceGroup, private readonly _repository: ISCMRepository, - ) { } + ) { + this._resources = observableFromEvent( + this._group.onDidChangeResources, + () => /** @description resources */ this._group.resources.map(e => new MultiDiffEditorItem(e.multiDiffEditorOriginalUri, e.multiDiffEditorModifiedUri, e.sourceUri)) + ); + this.resources = new ValueWithChangeEventFromObservable(this._resources); + + this.contextKeys = { + scmResourceGroup: this._group.id, + scmProvider: this._repository.provider.contextValue, + }; + } } interface UriFields { diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/multicursor/notebookMulticursor.ts b/src/vs/workbench/contrib/notebook/browser/contrib/multicursor/notebookMulticursor.ts index 8d0938fceac9a..709aaf47b74f2 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/multicursor/notebookMulticursor.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/multicursor/notebookMulticursor.ts @@ -35,7 +35,7 @@ import { WordHighlighterContribution } from '../../../../../../editor/contrib/wo import { IAccessibilityService } from '../../../../../../platform/accessibility/common/accessibility.js'; import { MenuId, registerAction2 } from '../../../../../../platform/actions/common/actions.js'; import { IConfigurationService } from '../../../../../../platform/configuration/common/configuration.js'; -import { ContextKeyExpr, IContextKeyService, RawContextKey } from '../../../../../../platform/contextkey/common/contextkey.js'; +import { ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey } from '../../../../../../platform/contextkey/common/contextkey.js'; import { ServicesAccessor } from '../../../../../../platform/instantiation/common/instantiation.js'; import { KeybindingWeight } from '../../../../../../platform/keybinding/common/keybindingsRegistry.js'; import { IPastFutureElements, IUndoRedoElement, IUndoRedoService, UndoRedoElementType } from '../../../../../../platform/undoRedo/common/undoRedo.js'; @@ -111,8 +111,8 @@ export class NotebookMultiCursorController extends Disposable implements INotebo return this.state; } - private _nbIsMultiSelectSession = NOTEBOOK_MULTI_CURSOR_CONTEXT.IsNotebookMultiCursor.bindTo(this.contextKeyService); - private _nbMultiSelectState = NOTEBOOK_MULTI_CURSOR_CONTEXT.NotebookMultiSelectCursorState.bindTo(this.contextKeyService); + private _nbIsMultiSelectSession: IContextKey; + private _nbMultiSelectState: IContextKey; constructor( private readonly notebookEditor: INotebookEditor, @@ -127,6 +127,9 @@ export class NotebookMultiCursorController extends Disposable implements INotebo this.anchorCell = this.notebookEditor.activeCellAndCodeEditor; + this._nbIsMultiSelectSession = NOTEBOOK_MULTI_CURSOR_CONTEXT.IsNotebookMultiCursor.bindTo(this.contextKeyService); + this._nbMultiSelectState = NOTEBOOK_MULTI_CURSOR_CONTEXT.NotebookMultiSelectCursorState.bindTo(this.contextKeyService); + // anchor cell will catch and relay all type, cut, paste events to the cursors controllers // need to create new controllers when the anchor cell changes, then update their listeners // ** cursor controllers need to happen first, because anchor listeners relay to them diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts index 3ff16d064f390..cd153dbe702f0 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffElementViewModel.ts @@ -680,8 +680,8 @@ export class SideBySideDiffElementViewModel extends DiffElementCellViewModelBase return this.mainDocumentTextModel; } - override readonly original!: DiffNestedCellViewModel; - override readonly modified!: DiffNestedCellViewModel; + declare readonly original: DiffNestedCellViewModel; + declare readonly modified: DiffNestedCellViewModel; override readonly type: 'unchanged' | 'modified'; /** diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookMultiDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookMultiDiffEditor.ts index c6d7549eb6e76..f32e736803a99 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookMultiDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookMultiDiffEditor.ts @@ -12,7 +12,7 @@ import { IEditorOpenContext } from '../../../../common/editor.js'; import { IEditorGroup } from '../../../../services/editor/common/editorGroupsService.js'; import { CancellationToken, CancellationTokenSource } from '../../../../../base/common/cancellation.js'; import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; -import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js'; +import { IContextKey, IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js'; import { INotebookEditorWorkerService } from '../../common/services/notebookWorkerService.js'; import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js'; import { IEditorOptions as ICodeEditorOptions } from '../../../../../editor/common/config/editorOptions.js'; @@ -57,9 +57,9 @@ export class NotebookMultiTextDiffEditor extends EditorPane { get notebookOptions() { return this._notebookOptions; } - private readonly ctxAllCollapsed = this._parentContextKeyService.createKey(NOTEBOOK_DIFF_CELLS_COLLAPSED.key, false); - private readonly ctxHasUnchangedCells = this._parentContextKeyService.createKey(NOTEBOOK_DIFF_HAS_UNCHANGED_CELLS.key, false); - private readonly ctxHiddenUnchangedCells = this._parentContextKeyService.createKey(NOTEBOOK_DIFF_UNCHANGED_CELLS_HIDDEN.key, true); + private readonly ctxAllCollapsed: IContextKey; + private readonly ctxHasUnchangedCells: IContextKey; + private readonly ctxHiddenUnchangedCells: IContextKey; constructor( group: IEditorGroup, @@ -73,6 +73,11 @@ export class NotebookMultiTextDiffEditor extends EditorPane { @INotebookService private readonly notebookService: INotebookService, ) { super(NotebookMultiTextDiffEditor.ID, group, telemetryService, themeService, storageService); + + this.ctxAllCollapsed = this._parentContextKeyService.createKey(NOTEBOOK_DIFF_CELLS_COLLAPSED.key, false); + this.ctxHasUnchangedCells = this._parentContextKeyService.createKey(NOTEBOOK_DIFF_HAS_UNCHANGED_CELLS.key, false); + this.ctxHiddenUnchangedCells = this._parentContextKeyService.createKey(NOTEBOOK_DIFF_UNCHANGED_CELLS_HIDDEN.key, true); + this._notebookOptions = instantiationService.createInstance(NotebookOptions, this.window, false, undefined); this._register(this._notebookOptions); } diff --git a/src/vs/workbench/contrib/notebook/browser/services/notebookServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/services/notebookServiceImpl.ts index b1670958f9fa3..a1f6341903955 100644 --- a/src/vs/workbench/contrib/notebook/browser/services/notebookServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/services/notebookServiceImpl.ts @@ -483,7 +483,7 @@ export class NotebookService extends Disposable implements INotebookService { return this._notebookProviderInfoStore; } - private readonly _notebookRenderersInfoStore = this._instantiationService.createInstance(NotebookOutputRendererInfoStore); + private readonly _notebookRenderersInfoStore: NotebookOutputRendererInfoStore; private readonly _onDidChangeOutputRenderers = this._register(new Emitter()); readonly onDidChangeOutputRenderers = this._onDidChangeOutputRenderers.event; @@ -525,6 +525,8 @@ export class NotebookService extends Disposable implements INotebookService { ) { super(); + this._notebookRenderersInfoStore = this._instantiationService.createInstance(NotebookOutputRendererInfoStore); + notebookRendererExtensionPoint.setHandler((renderers) => { this._notebookRenderersInfoStore.clear(); diff --git a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts index fdeaf59ad84e3..0024c29b3eb69 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts @@ -77,7 +77,7 @@ function validateWebviewBoundary(element: HTMLElement) { } export class NotebookCellList extends WorkbenchList implements IDisposable, IStyleController, INotebookCellList { - protected override readonly view!: NotebookCellListView; + protected declare readonly view: NotebookCellListView; private viewZones!: NotebookViewZones; get onWillScroll(): Event { return this.view.onWillScroll; } diff --git a/src/vs/workbench/contrib/output/browser/outputServices.ts b/src/vs/workbench/contrib/output/browser/outputServices.ts index f644a0f2cc124..b34bac340cfe5 100644 --- a/src/vs/workbench/contrib/output/browser/outputServices.ts +++ b/src/vs/workbench/contrib/output/browser/outputServices.ts @@ -108,6 +108,13 @@ class OutputViewFilters extends Disposable implements IOutputViewFilters { ) { super(); + this._trace = SHOW_TRACE_FILTER_CONTEXT.bindTo(this.contextKeyService); + this._debug = SHOW_DEBUG_FILTER_CONTEXT.bindTo(this.contextKeyService); + this._info = SHOW_INFO_FILTER_CONTEXT.bindTo(this.contextKeyService); + this._warning = SHOW_WARNING_FILTER_CONTEXT.bindTo(this.contextKeyService); + this._error = SHOW_ERROR_FILTER_CONTEXT.bindTo(this.contextKeyService); + this._categories = HIDE_CATEGORY_FILTER_CONTEXT.bindTo(this.contextKeyService); + this._trace.set(options.trace); this._debug.set(options.debug); this._info.set(options.info); @@ -131,7 +138,7 @@ class OutputViewFilters extends Disposable implements IOutputViewFilters { } } - private readonly _trace = SHOW_TRACE_FILTER_CONTEXT.bindTo(this.contextKeyService); + private readonly _trace: IContextKey; get trace(): boolean { return !!this._trace.get(); } @@ -142,7 +149,7 @@ class OutputViewFilters extends Disposable implements IOutputViewFilters { } } - private readonly _debug = SHOW_DEBUG_FILTER_CONTEXT.bindTo(this.contextKeyService); + private readonly _debug: IContextKey; get debug(): boolean { return !!this._debug.get(); } @@ -153,7 +160,7 @@ class OutputViewFilters extends Disposable implements IOutputViewFilters { } } - private readonly _info = SHOW_INFO_FILTER_CONTEXT.bindTo(this.contextKeyService); + private readonly _info: IContextKey; get info(): boolean { return !!this._info.get(); } @@ -164,7 +171,7 @@ class OutputViewFilters extends Disposable implements IOutputViewFilters { } } - private readonly _warning = SHOW_WARNING_FILTER_CONTEXT.bindTo(this.contextKeyService); + private readonly _warning: IContextKey; get warning(): boolean { return !!this._warning.get(); } @@ -175,7 +182,7 @@ class OutputViewFilters extends Disposable implements IOutputViewFilters { } } - private readonly _error = SHOW_ERROR_FILTER_CONTEXT.bindTo(this.contextKeyService); + private readonly _error: IContextKey; get error(): boolean { return !!this._error.get(); } @@ -186,7 +193,7 @@ class OutputViewFilters extends Disposable implements IOutputViewFilters { } } - private readonly _categories = HIDE_CATEGORY_FILTER_CONTEXT.bindTo(this.contextKeyService); + private readonly _categories: IContextKey; get categories(): string { return this._categories.get() || ','; } diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts index d896d8650da5f..f9c46671ecf27 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts @@ -26,6 +26,7 @@ import { assertIsDefined } from '../../../../base/common/types.js'; import { isEqual } from '../../../../base/common/resources.js'; import { IUserDataProfileService } from '../../../services/userDataProfile/common/userDataProfile.js'; import { DEFINE_KEYBINDING_EDITOR_CONTRIB_ID, IDefineKeybindingEditorContribution } from '../../../services/preferences/common/preferences.js'; +import { IEditorDecorationsCollection } from '../../../../editor/common/editorCommon.js'; const NLS_KB_LAYOUT_ERROR_MESSAGE = nls.localize('defineKeybinding.kbLayoutErrorMessage', "You won't be able to produce this key combination under your current keyboard layout."); @@ -88,7 +89,7 @@ class DefineKeybindingEditorContribution extends Disposable implements IDefineKe export class KeybindingEditorDecorationsRenderer extends Disposable { private _updateDecorations: RunOnceScheduler; - private readonly _dec = this._editor.createDecorationsCollection(); + private readonly _dec: IEditorDecorationsCollection; constructor( private _editor: ICodeEditor, @@ -97,6 +98,7 @@ export class KeybindingEditorDecorationsRenderer extends Disposable { super(); this._updateDecorations = this._register(new RunOnceScheduler(() => this._updateDecorationsNow(), 500)); + this._dec = this._editor.createDecorationsCollection(); const model = assertIsDefined(this._editor.getModel()); this._register(model.onDidChangeContent(() => this._updateDecorations.schedule())); diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts b/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts index c8f0b595562fa..a15b3650cdfa2 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts @@ -787,7 +787,7 @@ class UnsupportedSettingsRenderer extends Disposable implements languages.CodeAc class WorkspaceConfigurationRenderer extends Disposable { private static readonly supportedKeys = ['folders', 'tasks', 'launch', 'extensions', 'settings', 'remoteAuthority', 'transient']; - private readonly decorations = this.editor.createDecorationsCollection(); + private readonly decorations: editorCommon.IEditorDecorationsCollection; private renderingDelayer: Delayer = new Delayer(200); constructor(private editor: ICodeEditor, private workspaceSettingsEditorModel: SettingsEditorModel, @@ -795,6 +795,9 @@ class WorkspaceConfigurationRenderer extends Disposable { @IMarkerService private readonly markerService: IMarkerService ) { super(); + + this.decorations = this.editor.createDecorationsCollection(); + this._register(this.editor.getModel()!.onDidChangeContent(() => this.renderingDelayer.trigger(() => this.render()))); } diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts b/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts index 84321a355d912..4ce1eec2fd097 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts @@ -37,6 +37,7 @@ import { ILanguageService } from '../../../../editor/common/languages/language.j import { getDefaultHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegateFactory.js'; import type { IManagedHover } from '../../../../base/browser/ui/hover/hover.js'; import { IHoverService } from '../../../../platform/hover/browser/hover.js'; +import { IEditorDecorationsCollection } from '../../../../editor/common/editorCommon.js'; export class FolderSettingsActionViewItem extends BaseActionViewItem { @@ -500,13 +501,16 @@ export class EditPreferenceWidget extends Disposable { private _line: number = -1; private _preferences: T[] = []; - private readonly _editPreferenceDecoration = this.editor.createDecorationsCollection(); + private readonly _editPreferenceDecoration: IEditorDecorationsCollection; private readonly _onClick = this._register(new Emitter()); readonly onClick: Event = this._onClick.event; constructor(private editor: ICodeEditor) { super(); + + this._editPreferenceDecoration = this.editor.createDecorationsCollection(); + this._register(this.editor.onMouseDown((e: IEditorMouseEvent) => { if (e.target.type !== MouseTargetType.GUTTER_GLYPH_MARGIN || e.target.detail.isAfterLines || !this.isVisible()) { return; diff --git a/src/vs/workbench/contrib/quickaccess/browser/commandsQuickAccess.ts b/src/vs/workbench/contrib/quickaccess/browser/commandsQuickAccess.ts index 3ab1684b9acca..04ebd66ac89fd 100644 --- a/src/vs/workbench/contrib/quickaccess/browser/commandsQuickAccess.ts +++ b/src/vs/workbench/contrib/quickaccess/browser/commandsQuickAccess.ts @@ -49,7 +49,7 @@ export class CommandsQuickAccessProvider extends AbstractEditorCommandsQuickAcce // a chance to register so that the complete set of commands shows up as result // We do not want to delay functionality beyond that time though to keep the commands // functional. - private readonly extensionRegistrationRace = raceTimeout(this.extensionService.whenInstalledExtensionsRegistered(), 800); + private readonly extensionRegistrationRace: Promise; private useAiRelatedInfo = false; @@ -87,6 +87,8 @@ export class CommandsQuickAccessProvider extends AbstractEditorCommandsQuickAcce }), }, instantiationService, keybindingService, commandService, telemetryService, dialogService); + this.extensionRegistrationRace = raceTimeout(this.extensionService.whenInstalledExtensionsRegistered(), 800); + this._register(configurationService.onDidChangeConfiguration((e) => this.updateOptions(e))); this.updateOptions(); } diff --git a/src/vs/workbench/contrib/remote/browser/remoteIndicator.ts b/src/vs/workbench/contrib/remote/browser/remoteIndicator.ts index d8f7af344b47f..1ba7a86e9cc37 100644 --- a/src/vs/workbench/contrib/remote/browser/remoteIndicator.ts +++ b/src/vs/workbench/contrib/remote/browser/remoteIndicator.ts @@ -8,11 +8,11 @@ import { IRemoteAgentService, remoteConnectionLatencyMeasurer } from '../../../s import { RunOnceScheduler, retry } from '../../../../base/common/async.js'; import { Emitter, Event } from '../../../../base/common/event.js'; import { Disposable, DisposableStore } from '../../../../base/common/lifecycle.js'; -import { MenuId, IMenuService, MenuItemAction, MenuRegistry, registerAction2, Action2, SubmenuItemAction } from '../../../../platform/actions/common/actions.js'; +import { MenuId, IMenuService, MenuItemAction, MenuRegistry, registerAction2, Action2, SubmenuItemAction, IMenu } from '../../../../platform/actions/common/actions.js'; import { IWorkbenchContribution } from '../../../common/contributions.js'; import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from '../../../services/statusbar/browser/statusbar.js'; import { ILabelService } from '../../../../platform/label/common/label.js'; -import { ContextKeyExpr, IContextKeyService, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js'; +import { ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js'; import { ICommandService } from '../../../../platform/commands/common/commands.js'; import { Schemas } from '../../../../base/common/network.js'; import { IExtensionService } from '../../../services/extensions/common/extensions.js'; @@ -82,18 +82,18 @@ export class RemoteStatusIndicator extends Disposable implements IWorkbenchContr private remoteStatusEntry: IStatusbarEntryAccessor | undefined; - private readonly legacyIndicatorMenu = this._register(this.menuService.createMenu(MenuId.StatusBarWindowIndicatorMenu, this.contextKeyService)); // to be removed once migration completed - private readonly remoteIndicatorMenu = this._register(this.menuService.createMenu(MenuId.StatusBarRemoteIndicatorMenu, this.contextKeyService)); + private readonly legacyIndicatorMenu: IMenu; // to be removed once migration completed + private readonly remoteIndicatorMenu: IMenu; private remoteMenuActionsGroups: ActionGroup[] | undefined; - private readonly remoteAuthority = this.environmentService.remoteAuthority; + private readonly remoteAuthority: string | undefined; private virtualWorkspaceLocation: { scheme: string; authority: string } | undefined = undefined; private connectionState: 'initializing' | 'connected' | 'reconnecting' | 'disconnected' | undefined = undefined; private connectionToken: string | undefined = undefined; - private readonly connectionStateContextKey = new RawContextKey<'' | 'initializing' | 'disconnected' | 'connected'>('remoteConnectionState', '').bindTo(this.contextKeyService); + private readonly connectionStateContextKey: IContextKey<'' | 'initializing' | 'connected' | 'disconnected'>; private networkState: 'online' | 'offline' | 'high-latency' | undefined = undefined; private measureNetworkConnectionLatencyScheduler: RunOnceScheduler | undefined = undefined; @@ -152,6 +152,11 @@ export class RemoteStatusIndicator extends Disposable implements IWorkbenchContr ) { super(); + this.legacyIndicatorMenu = this._register(this.menuService.createMenu(MenuId.StatusBarWindowIndicatorMenu, this.contextKeyService)); + this.remoteIndicatorMenu = this._register(this.menuService.createMenu(MenuId.StatusBarRemoteIndicatorMenu, this.contextKeyService)); + this.remoteAuthority = this.environmentService.remoteAuthority; + this.connectionStateContextKey = new RawContextKey<'' | 'initializing' | 'disconnected' | 'connected'>('remoteConnectionState', '').bindTo(this.contextKeyService); + // Set initial connection state if (this.remoteAuthority) { this.connectionState = 'initializing'; diff --git a/src/vs/workbench/contrib/scm/browser/activity.ts b/src/vs/workbench/contrib/scm/browser/activity.ts index a5d9ca5adde5a..0c43b5e63f95d 100644 --- a/src/vs/workbench/contrib/scm/browser/activity.ts +++ b/src/vs/workbench/contrib/scm/browser/activity.ts @@ -30,11 +30,9 @@ const ActiveRepositoryContextKeys = { }; export class SCMActiveRepositoryController extends Disposable implements IWorkbenchContribution { - private readonly _countBadgeConfig = observableConfigValue<'all' | 'focused' | 'off'>('scm.countBadge', 'all', this.configurationService); + private readonly _countBadgeConfig: IObservable<'all' | 'focused' | 'off'>; - private readonly _repositories = observableFromEvent(this, - Event.any(this.scmService.onDidAddRepository, this.scmService.onDidRemoveRepository), - () => this.scmService.repositories); + private readonly _repositories: IObservable>; private readonly _activeRepositoryHistoryItemRefName = derived(reader => { const repository = this.scmViewService.activeRepository.read(reader); @@ -88,6 +86,11 @@ export class SCMActiveRepositoryController extends Disposable implements IWorkbe ) { super(); + this._countBadgeConfig = observableConfigValue<'all' | 'focused' | 'off'>('scm.countBadge', 'all', this.configurationService); + this._repositories = observableFromEvent(this, + Event.any(this.scmService.onDidAddRepository, this.scmService.onDidRemoveRepository), + () => this.scmService.repositories); + this._activeRepositoryNameContextKey = ActiveRepositoryContextKeys.ActiveRepositoryName.bindTo(this.contextKeyService); this._activeRepositoryBranchNameContextKey = ActiveRepositoryContextKeys.ActiveRepositoryBranchName.bindTo(this.contextKeyService); @@ -177,9 +180,7 @@ export class SCMActiveRepositoryController extends Disposable implements IWorkbe } export class SCMActiveResourceContextKeyController extends Disposable implements IWorkbenchContribution { - private readonly _repositories = observableFromEvent(this, - Event.any(this.scmService.onDidAddRepository, this.scmService.onDidRemoveRepository), - () => this.scmService.repositories); + private readonly _repositories: IObservable>; private readonly _onDidRepositoryChange = new Emitter(); @@ -190,6 +191,10 @@ export class SCMActiveResourceContextKeyController extends Disposable implements ) { super(); + this._repositories = observableFromEvent(this, + Event.any(this.scmService.onDidAddRepository, this.scmService.onDidRemoveRepository), + () => this.scmService.repositories); + const activeResourceHasChangesContextKey = new RawContextKey('scmActiveResourceHasChanges', false, localize('scmActiveResourceHasChanges', "Whether the active resource has changes")); const activeResourceRepositoryContextKey = new RawContextKey('scmActiveResourceRepository', undefined, localize('scmActiveResourceRepository', "The active resource's repository")); diff --git a/src/vs/workbench/contrib/scm/browser/quickDiffDecorator.ts b/src/vs/workbench/contrib/scm/browser/quickDiffDecorator.ts index 01c9eb2173c2f..b57adda655680 100644 --- a/src/vs/workbench/contrib/scm/browser/quickDiffDecorator.ts +++ b/src/vs/workbench/contrib/scm/browser/quickDiffDecorator.ts @@ -22,7 +22,8 @@ import { IWorkbenchContribution } from '../../../common/contributions.js'; import { ResourceMap } from '../../../../base/common/map.js'; import { IUriIdentityService } from '../../../../platform/uriIdentity/common/uriIdentity.js'; import { IContextKey, IContextKeyService, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js'; -import { autorun, autorunWithStore, observableFromEvent } from '../../../../base/common/observable.js'; +import { IObservable, autorun, autorunWithStore, observableFromEvent } from '../../../../base/common/observable.js'; +import { EditorInput } from '../../../common/editor/editorInput.js'; export const quickDiffDecorationCount = new RawContextKey('quickDiffDecorationCount', 0); @@ -188,8 +189,7 @@ export class QuickDiffWorkbenchController extends Disposable implements IWorkben private enabled = false; private readonly quickDiffDecorationCount: IContextKey; - private readonly activeEditor = observableFromEvent(this, - this.editorService.onDidActiveEditorChange, () => this.editorService.activeEditor); + private readonly activeEditor: IObservable; // Resource URI -> Code Editor Id -> Decoration (Disposable) private readonly decorators = new ResourceMap>(); @@ -209,6 +209,9 @@ export class QuickDiffWorkbenchController extends Disposable implements IWorkben this.quickDiffDecorationCount = quickDiffDecorationCount.bindTo(contextKeyService); + this.activeEditor = observableFromEvent(this, + this.editorService.onDidActiveEditorChange, () => this.editorService.activeEditor); + const onDidChangeConfiguration = Event.filter(configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.diffDecorations')); this._register(onDidChangeConfiguration(this.onDidChangeConfiguration, this)); this.onDidChangeConfiguration(); diff --git a/src/vs/workbench/contrib/scm/browser/scmHistoryViewPane.ts b/src/vs/workbench/contrib/scm/browser/scmHistoryViewPane.ts index 43895d3633159..b95db70d81a1c 100644 --- a/src/vs/workbench/contrib/scm/browser/scmHistoryViewPane.ts +++ b/src/vs/workbench/contrib/scm/browser/scmHistoryViewPane.ts @@ -319,7 +319,7 @@ class HistoryItemRenderer implements ITreeRenderer('scm.graph.badges', 'filter', this._configurationService); + private readonly _badgesConfig: IObservable<'all' | 'filter'>; constructor( private readonly hoverDelegate: IHoverDelegate, @@ -329,7 +329,9 @@ class HistoryItemRenderer implements ITreeRenderer('scm.graph.badges', 'filter', this._configurationService); + } renderTemplate(container: HTMLElement): HistoryItemTemplate { // hack @@ -751,18 +753,9 @@ type RepositoryState = { class SCMHistoryViewModel extends Disposable { - private readonly _closedRepository = observableFromEvent( - this, - this._scmService.onDidRemoveRepository, - repository => repository); + private readonly _closedRepository: IObservable; - private readonly _firstRepository = this._scmService.repositoryCount > 0 ? - constObservable(Iterable.first(this._scmService.repositories)) : - observableFromEvent( - this, - Event.once(this._scmService.onDidAddRepository), - repository => repository - ); + private readonly _firstRepository: IObservable; private readonly _selectedRepository = observableValue<'auto' | ISCMRepository>(this, 'auto'); @@ -779,7 +772,7 @@ class SCMHistoryViewModel extends Disposable { * The active | selected repository takes precedence over the first repository when the observable * values are updated in the same transaction (or during the initial read of the observable value). */ - readonly repository = latestChangedValue(this, [this._firstRepository, this._graphRepository]); + readonly repository: IObservable; readonly onDidChangeHistoryItemsFilter = observableSignal(this); readonly isViewModelEmpty = observableValue(this, false); @@ -798,6 +791,21 @@ class SCMHistoryViewModel extends Disposable { ) { super(); + this._closedRepository = observableFromEvent( + this, + this._scmService.onDidRemoveRepository, + repository => repository); + + this._firstRepository = this._scmService.repositoryCount > 0 ? + constObservable(Iterable.first(this._scmService.repositories)) : + observableFromEvent( + this, + Event.once(this._scmService.onDidAddRepository), + repository => repository + ); + + this.repository = latestChangedValue(this, [this._firstRepository, this._graphRepository]); + this._repositoryFilterState = this._loadHistoryItemsFilterState(); this._extensionService.onWillStop(this._saveHistoryItemsFilterState, this, this._store); diff --git a/src/vs/workbench/contrib/scm/browser/scmViewService.ts b/src/vs/workbench/contrib/scm/browser/scmViewService.ts index 52af3ec95aa27..f324da4812c53 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewService.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewService.ts @@ -18,9 +18,10 @@ import { binarySearch } from '../../../../base/common/arrays.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { IContextKey, IContextKeyService, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js'; import { IExtensionService } from '../../../services/extensions/common/extensions.js'; -import { derivedObservableWithCache, derivedOpts, latestChangedValue, observableFromEventOpts } from '../../../../base/common/observable.js'; +import { IObservable, derivedObservableWithCache, derivedOpts, latestChangedValue, observableFromEventOpts } from '../../../../base/common/observable.js'; import { IEditorService } from '../../../services/editor/common/editorService.js'; import { EditorResourceAccessor } from '../../../common/editor.js'; +import { EditorInput } from '../../../common/editor/editorInput.js'; function getProviderStorageKey(provider: ISCMProvider): string { return `${provider.contextValue}:${provider.label}${provider.rootUri ? `:${provider.rootUri.toString()}` : ''}`; @@ -164,12 +165,7 @@ export class SCMViewService implements ISCMViewService { }, this.onDidFocusRepository, () => this.focusedRepository); - private readonly _activeEditor = observableFromEventOpts( - { - owner: this, - equalsFn: () => false - }, this.editorService.onDidActiveEditorChange, - () => this.editorService.activeEditor); + private readonly _activeEditor: IObservable; private readonly _activeEditorRepository = derivedObservableWithCache(this, (reader, lastValue) => { @@ -222,6 +218,13 @@ export class SCMViewService implements ISCMViewService { // noop } + this._activeEditor = observableFromEventOpts( + { + owner: this, + equalsFn: () => false + }, this.editorService.onDidActiveEditorChange, + () => this.editorService.activeEditor); + this._repositoriesSortKey = this.previousState?.sortKey ?? this.getViewSortOrder(); this._sortKeyContextKey = RepositoryContextKeys.RepositorySortKey.bindTo(contextKeyService); this._sortKeyContextKey.set(this._repositoriesSortKey); diff --git a/src/vs/workbench/contrib/scm/browser/workingSet.ts b/src/vs/workbench/contrib/scm/browser/workingSet.ts index 1185f8de20a3b..77ac59481b140 100644 --- a/src/vs/workbench/contrib/scm/browser/workingSet.ts +++ b/src/vs/workbench/contrib/scm/browser/workingSet.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Disposable, DisposableMap, DisposableStore } from '../../../../base/common/lifecycle.js'; -import { autorun, autorunWithStore, derived } from '../../../../base/common/observable.js'; +import { IObservable, autorun, autorunWithStore, derived } from '../../../../base/common/observable.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { observableConfigValue } from '../../../../platform/observable/common/platformObservableUtils.js'; import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js'; @@ -29,7 +29,7 @@ export class SCMWorkingSetController extends Disposable implements IWorkbenchCon static readonly ID = 'workbench.contrib.scmWorkingSets'; private _workingSets!: Map; - private _enabledConfig = observableConfigValue('scm.workingSets.enabled', false, this.configurationService); + private _enabledConfig: IObservable; private readonly _repositoryDisposables = new DisposableMap(); @@ -42,6 +42,8 @@ export class SCMWorkingSetController extends Disposable implements IWorkbenchCon ) { super(); + this._enabledConfig = observableConfigValue('scm.workingSets.enabled', false, this.configurationService); + this._store.add(autorunWithStore((reader, store) => { if (!this._enabledConfig.read(reader)) { this.storageService.remove('scm.workingSets', StorageScope.WORKSPACE); diff --git a/src/vs/workbench/contrib/search/browser/anythingQuickAccess.ts b/src/vs/workbench/contrib/search/browser/anythingQuickAccess.ts index bcb65cdddfd8b..a9e5f2171cbc3 100644 --- a/src/vs/workbench/contrib/search/browser/anythingQuickAccess.ts +++ b/src/vs/workbench/contrib/search/browser/anythingQuickAccess.ts @@ -85,56 +85,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider | undefined = undefined; - - editorViewState = this._register(this.instantiationService.createInstance(PickerEditorState)); - - scorerCache: FuzzyScorerCache = Object.create(null); - fileQueryCache: FileQueryCacheState | undefined = undefined; - - lastOriginalFilter: string | undefined = undefined; - lastFilter: string | undefined = undefined; - lastRange: IRange | undefined = undefined; - - lastGlobalPicks: PicksWithActive | undefined = undefined; - - isQuickNavigating: boolean | undefined = undefined; - - constructor( - private readonly provider: AnythingQuickAccessProvider, - private readonly instantiationService: IInstantiationService - ) { - super(); - } - - set(picker: IQuickPick): void { - - // Picker for this run - this.picker = picker; - Event.once(picker.onDispose)(() => { - if (picker === this.picker) { - this.picker = undefined; // clear the picker when disposed to not keep it in memory for too long - } - }); - - // Caches - const isQuickNavigating = !!picker.quickNavigate; - if (!isQuickNavigating) { - this.fileQueryCache = this.provider.createFileQueryCache(); - this.scorerCache = Object.create(null); - } - - // Other - this.isQuickNavigating = isQuickNavigating; - this.lastOriginalFilter = undefined; - this.lastFilter = undefined; - this.lastRange = undefined; - this.lastGlobalPicks = undefined; - this.editorViewState.reset(); - } - }(this, this.instantiationService)); + private readonly pickState; get defaultFilterValue(): DefaultQuickAccessFilterValue | undefined { if (this.configuration.preserveInput) { @@ -171,6 +122,65 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider | undefined = undefined; + + editorViewState: PickerEditorState; + + scorerCache: FuzzyScorerCache = Object.create(null); + fileQueryCache: FileQueryCacheState | undefined = undefined; + + lastOriginalFilter: string | undefined = undefined; + lastFilter: string | undefined = undefined; + lastRange: IRange | undefined = undefined; + + lastGlobalPicks: PicksWithActive | undefined = undefined; + + isQuickNavigating: boolean | undefined = undefined; + + constructor( + private readonly provider: AnythingQuickAccessProvider, + private readonly instantiationService: IInstantiationService + ) { + super(); + + this.editorViewState = this._register(this.instantiationService.createInstance(PickerEditorState)); + } + + set(picker: IQuickPick): void { + + // Picker for this run + this.picker = picker; + Event.once(picker.onDispose)(() => { + if (picker === this.picker) { + this.picker = undefined; // clear the picker when disposed to not keep it in memory for too long + } + }); + + // Caches + const isQuickNavigating = !!picker.quickNavigate; + if (!isQuickNavigating) { + this.fileQueryCache = this.provider.createFileQueryCache(); + this.scorerCache = Object.create(null); + } + + // Other + this.isQuickNavigating = isQuickNavigating; + this.lastOriginalFilter = undefined; + this.lastFilter = undefined; + this.lastRange = undefined; + this.lastGlobalPicks = undefined; + this.editorViewState.reset(); + } + }(this, this.instantiationService)); + + this.fileQueryBuilder = this.instantiationService.createInstance(QueryBuilder); + + this.workspaceSymbolsQuickAccess = this._register(this.instantiationService.createInstance(SymbolsQuickAccessProvider)); + + this.editorSymbolsQuickAccess = this.instantiationService.createInstance(GotoSymbolQuickAccessProvider); } private get configuration() { @@ -519,7 +529,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider(AnythingQuickAccessProvider.TYPING_SEARCH_DELAY)); - private readonly fileQueryBuilder = this.instantiationService.createInstance(QueryBuilder); + private readonly fileQueryBuilder: QueryBuilder; private createFileQueryCache(): FileQueryCacheState { return new FileQueryCacheState( @@ -825,7 +835,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider> { if ( @@ -850,7 +860,7 @@ export class AnythingQuickAccessProvider extends PickerQuickAccessProvider> | null { const filterSegments = query.original.split(GotoSymbolQuickAccessProvider.PREFIX); diff --git a/src/vs/workbench/contrib/search/common/cacheState.ts b/src/vs/workbench/contrib/search/common/cacheState.ts index 3d7aa51da36ba..5bae3074f3cd4 100644 --- a/src/vs/workbench/contrib/search/common/cacheState.ts +++ b/src/vs/workbench/contrib/search/common/cacheState.ts @@ -38,7 +38,7 @@ export class FileQueryCacheState { return isUpdating || !this.previousCacheState ? isUpdating : this.previousCacheState.isUpdating; } - private readonly query = this.cacheQuery(this._cacheKey); + private readonly query: IFileQuery; private loadingPhase = LoadingPhase.Created; private loadPromise: Promise | undefined; @@ -49,6 +49,8 @@ export class FileQueryCacheState { private disposeFn: (cacheKey: string) => Promise, private previousCacheState: FileQueryCacheState | undefined ) { + this.query = this.cacheQuery(this._cacheKey); + if (this.previousCacheState) { const current = Object.assign({}, this.query, { cacheKey: null }); const previous = Object.assign({}, this.previousCacheState.query, { cacheKey: null }); diff --git a/src/vs/workbench/contrib/speech/browser/speechService.ts b/src/vs/workbench/contrib/speech/browser/speechService.ts index 8529260f59afd..74bb52bf6662e 100644 --- a/src/vs/workbench/contrib/speech/browser/speechService.ts +++ b/src/vs/workbench/contrib/speech/browser/speechService.ts @@ -7,7 +7,7 @@ import { localize } from '../../../../nls.js'; import { CancellationToken, CancellationTokenSource } from '../../../../base/common/cancellation.js'; import { Emitter, Event } from '../../../../base/common/event.js'; import { Disposable, DisposableStore, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js'; -import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; +import { IContextKey, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; import { ILogService } from '../../../../platform/log/common/log.js'; import { IHostService } from '../../../services/host/browser/host.js'; import { DeferredPromise } from '../../../../base/common/async.js'; @@ -58,7 +58,7 @@ export class SpeechService extends Disposable implements ISpeechService { private readonly providers = new Map(); private readonly providerDescriptors = new Map(); - private readonly hasSpeechProviderContext = HasSpeechProvider.bindTo(this.contextKeyService); + private readonly hasSpeechProviderContext: IContextKey; constructor( @ILogService private readonly logService: ILogService, @@ -70,6 +70,10 @@ export class SpeechService extends Disposable implements ISpeechService { ) { super(); + this.hasSpeechProviderContext = HasSpeechProvider.bindTo(this.contextKeyService); + this.speechToTextInProgress = SpeechToTextInProgress.bindTo(this.contextKeyService); + this.textToSpeechInProgress = TextToSpeechInProgress.bindTo(this.contextKeyService); + this.handleAndRegisterSpeechExtensions(); } @@ -136,7 +140,7 @@ export class SpeechService extends Disposable implements ISpeechService { private activeSpeechToTextSessions = 0; get hasActiveSpeechToTextSession() { return this.activeSpeechToTextSessions > 0; } - private readonly speechToTextInProgress = SpeechToTextInProgress.bindTo(this.contextKeyService); + private readonly speechToTextInProgress: IContextKey; async createSpeechToTextSession(token: CancellationToken, context: string = 'speech'): Promise { const provider = await this.getProvider(); @@ -249,7 +253,7 @@ export class SpeechService extends Disposable implements ISpeechService { private activeTextToSpeechSessions = 0; get hasActiveTextToSpeechSession() { return this.activeTextToSpeechSessions > 0; } - private readonly textToSpeechInProgress = TextToSpeechInProgress.bindTo(this.contextKeyService); + private readonly textToSpeechInProgress: IContextKey; async createTextToSpeechSession(token: CancellationToken, context: string = 'speech'): Promise { const provider = await this.getProvider(); diff --git a/src/vs/workbench/contrib/terminalContrib/suggest/browser/pwshCompletionProviderAddon.ts b/src/vs/workbench/contrib/terminalContrib/suggest/browser/pwshCompletionProviderAddon.ts index 9928faaff89ad..b2b2d6a929b56 100644 --- a/src/vs/workbench/contrib/terminalContrib/suggest/browser/pwshCompletionProviderAddon.ts +++ b/src/vs/workbench/contrib/terminalContrib/suggest/browser/pwshCompletionProviderAddon.ts @@ -52,10 +52,10 @@ const enum RequestCompletionsSequence { } export class PwshCompletionProviderAddon extends Disposable implements ITerminalAddon, ITerminalCompletionProvider { + static readonly ID = 'pwsh-shell-integration'; id: string = PwshCompletionProviderAddon.ID; triggerCharacters?: string[] | undefined; isBuiltin?: boolean = true; - static readonly ID = 'pwsh-shell-integration'; static cachedPwshCommands: Set; readonly shellTypes = [GeneralShellType.PowerShell]; private _lastUserDataTimestamp: number = 0; diff --git a/src/vs/workbench/contrib/terminalContrib/typeAhead/browser/terminalTypeAheadAddon.ts b/src/vs/workbench/contrib/terminalContrib/typeAhead/browser/terminalTypeAheadAddon.ts index e286592242dbb..3552d45e26564 100644 --- a/src/vs/workbench/contrib/terminalContrib/typeAhead/browser/terminalTypeAheadAddon.ts +++ b/src/vs/workbench/contrib/terminalContrib/typeAhead/browser/terminalTypeAheadAddon.ts @@ -1290,8 +1290,8 @@ export const enum CharPredictState { export class TypeAheadAddon extends Disposable implements ITerminalAddon { private _typeaheadStyle?: TypeAheadStyle; - private _typeaheadThreshold = this._configurationService.getValue(TERMINAL_CONFIG_SECTION).localEchoLatencyThreshold; - private _excludeProgramRe = compileExcludeRegexp(this._configurationService.getValue(TERMINAL_CONFIG_SECTION).localEchoExcludePrograms); + private _typeaheadThreshold: number; + private _excludeProgramRe: RegExp; protected _lastRow?: { y: number; startingX: number; endingX: number; charState: CharPredictState }; protected _timeline?: PredictionTimeline; private _terminalTitle = ''; @@ -1308,6 +1308,10 @@ export class TypeAheadAddon extends Disposable implements ITerminalAddon { @ITelemetryService private readonly _telemetryService: ITelemetryService, ) { super(); + + this._typeaheadThreshold = this._configurationService.getValue(TERMINAL_CONFIG_SECTION).localEchoLatencyThreshold; + this._excludeProgramRe = compileExcludeRegexp(this._configurationService.getValue(TERMINAL_CONFIG_SECTION).localEchoExcludePrograms); + this._register(toDisposable(() => this._clearPredictionDebounce?.dispose())); } diff --git a/src/vs/workbench/contrib/testing/browser/explorerProjections/index.ts b/src/vs/workbench/contrib/testing/browser/explorerProjections/index.ts index 552bf1a22989a..6d87e182d7ba9 100644 --- a/src/vs/workbench/contrib/testing/browser/explorerProjections/index.ts +++ b/src/vs/workbench/contrib/testing/browser/explorerProjections/index.ts @@ -74,7 +74,7 @@ export abstract class TestItemTreeElement { /** * Depth of the element in the tree. */ - public depth: number = this.parent ? this.parent.depth + 1 : 0; + public depth: number; /** * Whether the node's test result is 'retired' -- from an outdated test run. @@ -104,7 +104,9 @@ export abstract class TestItemTreeElement { * in a 'flat' projection. */ public readonly parent: TestItemTreeElement | null = null, - ) { } + ) { + this.depth = this.parent ? this.parent.depth + 1 : 0; + } public toJSON() { if (this.depth === 0) { diff --git a/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsOutput.ts b/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsOutput.ts index 4f06c5ee9ca56..05aacdf6f6f43 100644 --- a/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsOutput.ts +++ b/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsOutput.ts @@ -41,17 +41,21 @@ import { ITaskRawOutput, ITestResult, ITestRunTaskResults, LiveTestResult, TestR import { ITestMessage, TestMessageType, getMarkId } from '../../common/testTypes.js'; import { ScrollEvent } from '../../../../../base/common/scrollable.js'; import { CALL_STACK_WIDGET_HEADER_HEIGHT } from '../../../debug/browser/callStackWidget.js'; +import { ITextModel } from '../../../../../editor/common/model.js'; class SimpleDiffEditorModel extends EditorModel { - public readonly original = this._original.object.textEditorModel; - public readonly modified = this._modified.object.textEditorModel; + public readonly original: ITextModel; + public readonly modified: ITextModel; constructor( private readonly _original: IReference, private readonly _modified: IReference, ) { super(); + + this.original = this._original.object.textEditorModel; + this.modified = this._modified.object.textEditorModel; } public override dispose() { diff --git a/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsTree.ts b/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsTree.ts index 4915553ce6120..bb54f2fbba1b6 100644 --- a/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsTree.ts +++ b/src/vs/workbench/contrib/testing/browser/testResultsView/testResultsTree.ts @@ -79,9 +79,9 @@ class TestResultElement implements ITreeElement { public readonly changeEmitter = new Emitter(); public readonly onDidChange = this.changeEmitter.event; public readonly type = 'result'; - public readonly context = this.value.id; - public readonly id = this.value.id; - public readonly label = this.value.name; + public readonly context: string; + public readonly id: string; + public readonly label: string; public get icon() { return icons.testingStatesToIcons.get( @@ -91,7 +91,11 @@ class TestResultElement implements ITreeElement { ); } - constructor(public readonly value: ITestResult) { } + constructor(public readonly value: ITestResult) { + this.context = this.value.id; + this.id = this.value.id; + this.label = this.value.name; + } } const openCoverageLabel = localize('openTestCoverage', 'View Test Coverage'); @@ -100,7 +104,7 @@ const closeCoverageLabel = localize('closeTestCoverage', 'Close Test Coverage'); class CoverageElement implements ITreeElement { public readonly type = 'coverage'; public readonly context: undefined; - public readonly id = `coverage-${this.results.id}/${this.task.id}`; + public readonly id: string; public readonly onDidChange: Event; public get label() { @@ -120,6 +124,7 @@ class CoverageElement implements ITreeElement { public readonly task: ITestRunTaskResults, private readonly coverageService: ITestCoverageService, ) { + this.id = `coverage-${this.results.id}/${this.task.id}`; this.onDidChange = Event.fromObservableLight(coverageService.selected); } } @@ -127,11 +132,12 @@ class CoverageElement implements ITreeElement { class OlderResultsElement implements ITreeElement { public readonly type = 'older'; public readonly context: undefined; - public readonly id = `older-${this.n}`; + public readonly id: string; public readonly onDidChange = Event.None; public readonly label: string; constructor(private readonly n: number) { + this.id = `older-${this.n}`; this.label = localize('nOlderResults', '{0} older results', n); } @@ -139,11 +145,8 @@ class OlderResultsElement implements ITreeElement { class TestCaseElement implements ITreeElement { public readonly type = 'test'; - public readonly context: ITestItemContext = { - $mid: MarshalledId.TestItemContext, - tests: [InternalTestItem.serialize(this.test)], - }; - public readonly id = `${this.results.id}/${this.test.item.extId}`; + public readonly context: ITestItemContext; + public readonly id: string; public readonly description?: string; public get onDidChange() { @@ -179,7 +182,13 @@ class TestCaseElement implements ITreeElement { public readonly results: ITestResult, public readonly test: TestResultItem, public readonly taskIndex: number, - ) { } + ) { + this.context = { + $mid: MarshalledId.TestItemContext, + tests: [InternalTestItem.serialize(this.test)], + }; + this.id = `${this.results.id}/${this.test.item.extId}`; + } } class TaskElement implements ITreeElement { diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts index 0894eeca52b57..eeed6c7772c23 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerFilter.ts @@ -37,11 +37,7 @@ export class TestingExplorerFilter extends BaseActionViewItem { private wrapper!: HTMLDivElement; private readonly focusEmitter = this._register(new Emitter()); public readonly onDidFocus = this.focusEmitter.event; - private readonly history: StoredValue<{ values: string[]; lastValue: string } | string[]> = this._register(this.instantiationService.createInstance(StoredValue, { - key: 'testing.filterHistory2', - scope: StorageScope.WORKSPACE, - target: StorageTarget.MACHINE - })); + private readonly history: StoredValue<{ values: string[]; lastValue: string } | string[]>; private readonly filtersAction = new Action('markersFiltersAction', localize('testing.filters.menu', "More Filters..."), 'testing-filter-button ' + ThemeIcon.asClassName(testingFilterIcon)); @@ -53,6 +49,13 @@ export class TestingExplorerFilter extends BaseActionViewItem { @ITestService private readonly testService: ITestService, ) { super(null, action, options); + + this.history = this._register(this.instantiationService.createInstance(StoredValue, { + key: 'testing.filterHistory2', + scope: StorageScope.WORKSPACE, + target: StorageTarget.MACHINE + })); + this.updateFilterActiveState(); this._register(testService.excluded.onTestExclusionsChanged(this.updateFilterActiveState, this)); } diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts index 7c9c38a02399e..cd84065c86dc3 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts @@ -36,7 +36,7 @@ import { MenuEntryActionViewItem, createActionViewItem, getActionBarActions, get import { IMenuService, MenuId, MenuItemAction } from '../../../../platform/actions/common/actions.js'; import { ICommandService } from '../../../../platform/commands/common/commands.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; -import { IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; +import { IContextKey, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; import { IContextMenuService } from '../../../../platform/contextview/browser/contextView.js'; import { IHoverService } from '../../../../platform/hover/browser/hover.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; @@ -703,15 +703,11 @@ class TestingExplorerViewModel extends Disposable { public readonly projection = this._register(new MutableDisposable()); private readonly revealTimeout = new MutableDisposable(); - private readonly _viewMode = TestingContextKeys.viewMode.bindTo(this.contextKeyService); - private readonly _viewSorting = TestingContextKeys.viewSorting.bindTo(this.contextKeyService); + private readonly _viewMode: IContextKey; + private readonly _viewSorting: IContextKey; private readonly welcomeVisibilityEmitter = new Emitter(); private readonly actionRunner = this._register(new TestExplorerActionRunner(() => this.tree.getSelection().filter(isDefined))); - private readonly lastViewState = this._register(new StoredValue({ - key: 'testing.treeState', - scope: StorageScope.WORKSPACE, - target: StorageTarget.MACHINE, - }, this.storageService)); + private readonly lastViewState: StoredValue; private readonly noTestForDocumentWidget: NoTestsForDocumentWidget; /** @@ -781,6 +777,16 @@ class TestingExplorerViewModel extends Disposable { ) { super(); + this._viewMode = TestingContextKeys.viewMode.bindTo(this.contextKeyService); + + this._viewSorting = TestingContextKeys.viewSorting.bindTo(this.contextKeyService); + + this.lastViewState = this._register(new StoredValue({ + key: 'testing.treeState', + scope: StorageScope.WORKSPACE, + target: StorageTarget.MACHINE, + }, this.storageService)); + this.hasPendingReveal = !!filterState.reveal.get(); this.noTestForDocumentWidget = this._register(instantiationService.createInstance(NoTestsForDocumentWidget, listContainer)); this._viewMode.set(this.storageService.get('testing.viewMode', StorageScope.WORKSPACE, TestExplorerViewMode.Tree) as TestExplorerViewMode); diff --git a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts index 08611d53fc3e9..2f80da8f59645 100644 --- a/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts +++ b/src/vs/workbench/contrib/testing/browser/testingOutputPeek.ts @@ -117,11 +117,7 @@ export class TestingPeekOpener extends Disposable implements ITestingPeekOpener private lastUri?: TestUriWithDocument; /** @inheritdoc */ - public readonly historyVisible = this._register(MutableObservableValue.stored(new StoredValue({ - key: 'testHistoryVisibleInPeek', - scope: StorageScope.PROFILE, - target: StorageTarget.USER, - }, this.storageService), false)); + public readonly historyVisible: MutableObservableValue; constructor( @IConfigurationService private readonly configuration: IConfigurationService, @@ -135,6 +131,13 @@ export class TestingPeekOpener extends Disposable implements ITestingPeekOpener @INotificationService private readonly notificationService: INotificationService, ) { super(); + + this.historyVisible = this._register(MutableObservableValue.stored(new StoredValue({ + key: 'testHistoryVisibleInPeek', + scope: StorageScope.PROFILE, + target: StorageTarget.USER, + }, this.storageService), false)); + this._register(testResults.onTestChanged(this.openPeekOnFailure, this)); } diff --git a/src/vs/workbench/contrib/testing/common/testExclusions.ts b/src/vs/workbench/contrib/testing/common/testExclusions.ts index 5ac06c15fc1d0..d81362d756d10 100644 --- a/src/vs/workbench/contrib/testing/common/testExclusions.ts +++ b/src/vs/workbench/contrib/testing/common/testExclusions.ts @@ -12,26 +12,31 @@ import { StoredValue } from './storedValue.js'; import { InternalTestItem } from './testTypes.js'; export class TestExclusions extends Disposable { - private readonly excluded = this._register( - MutableObservableValue.stored(new StoredValue>({ - key: 'excludedTestItems', - scope: StorageScope.WORKSPACE, - target: StorageTarget.MACHINE, - serialization: { - deserialize: v => new Set(JSON.parse(v)), - serialize: v => JSON.stringify([...v]) - }, - }, this.storageService), new Set()) - ); + private readonly excluded: MutableObservableValue>; constructor(@IStorageService private readonly storageService: IStorageService) { super(); + + this.excluded = this._register( + MutableObservableValue.stored(new StoredValue>({ + key: 'excludedTestItems', + scope: StorageScope.WORKSPACE, + target: StorageTarget.MACHINE, + serialization: { + deserialize: v => new Set(JSON.parse(v)), + serialize: v => JSON.stringify([...v]) + }, + }, this.storageService), new Set()) + ); + + this.onTestExclusionsChanged = this.excluded.onDidChange; + } /** * Event that fires when the excluded tests change. */ - public readonly onTestExclusionsChanged: Event = this.excluded.onDidChange; + public readonly onTestExclusionsChanged: Event; /** * Gets whether there's any excluded tests. diff --git a/src/vs/workbench/contrib/testing/common/testExplorerFilterState.ts b/src/vs/workbench/contrib/testing/common/testExplorerFilterState.ts index 1d865c3a37d0a..99edfe4433fe7 100644 --- a/src/vs/workbench/contrib/testing/common/testExplorerFilterState.ts +++ b/src/vs/workbench/contrib/testing/common/testExplorerFilterState.ts @@ -99,11 +99,7 @@ export class TestExplorerFilterState extends Disposable implements ITestExplorer public readonly text = this._register(new MutableObservableValue('')); /** @inheritdoc */ - public readonly fuzzy = this._register(MutableObservableValue.stored(new StoredValue({ - key: 'testHistoryFuzzy', - scope: StorageScope.PROFILE, - target: StorageTarget.USER, - }, this.storageService), false)); + public readonly fuzzy: MutableObservableValue; public readonly reveal: ISettableObservable = observableValue('TestExplorerFilterState.reveal', undefined); @@ -116,6 +112,12 @@ export class TestExplorerFilterState extends Disposable implements ITestExplorer @IStorageService private readonly storageService: IStorageService, ) { super(); + + this.fuzzy = this._register(MutableObservableValue.stored(new StoredValue({ + key: 'testHistoryFuzzy', + scope: StorageScope.PROFILE, + target: StorageTarget.USER, + }, this.storageService), false)); } /** @inheritdoc */ diff --git a/src/vs/workbench/contrib/testing/common/testResultStorage.ts b/src/vs/workbench/contrib/testing/common/testResultStorage.ts index 2253712efb8d3..151479733209e 100644 --- a/src/vs/workbench/contrib/testing/common/testResultStorage.ts +++ b/src/vs/workbench/contrib/testing/common/testResultStorage.ts @@ -49,11 +49,7 @@ const currentRevision = 1; export abstract class BaseTestResultStorage extends Disposable implements ITestResultStorage { declare readonly _serviceBrand: undefined; - protected readonly stored = this._register(new StoredValue>({ - key: 'storedTestResults', - scope: StorageScope.WORKSPACE, - target: StorageTarget.MACHINE - }, this.storageService)); + protected readonly stored: StoredValue>; constructor( @IUriIdentityService private readonly uriIdentityService: IUriIdentityService, @@ -61,6 +57,12 @@ export abstract class BaseTestResultStorage extends Disposable implements ITestR @ILogService private readonly logService: ILogService, ) { super(); + + this.stored = this._register(new StoredValue>({ + key: 'storedTestResults', + scope: StorageScope.WORKSPACE, + target: StorageTarget.MACHINE + }, this.storageService)); } /** diff --git a/src/vs/workbench/contrib/testing/common/testServiceImpl.ts b/src/vs/workbench/contrib/testing/common/testServiceImpl.ts index 00ea40df0f784..16dc7c98f8ef8 100644 --- a/src/vs/workbench/contrib/testing/common/testServiceImpl.ts +++ b/src/vs/workbench/contrib/testing/common/testServiceImpl.ts @@ -72,7 +72,7 @@ export class TestService extends Disposable implements ITestService { /** * @inheritdoc */ - public readonly collection = new MainThreadTestCollection(this.uriIdentityService, this.expandTest.bind(this)); + public readonly collection: MainThreadTestCollection; /** * @inheritdoc @@ -82,11 +82,7 @@ export class TestService extends Disposable implements ITestService { /** * @inheritdoc */ - public readonly showInlineOutput = this._register(MutableObservableValue.stored(new StoredValue({ - key: 'inlineTestOutputVisible', - scope: StorageScope.WORKSPACE, - target: StorageTarget.USER - }, this.storage), true)); + public readonly showInlineOutput: MutableObservableValue; constructor( @IContextKeyService contextKeyService: IContextKeyService, @@ -101,7 +97,13 @@ export class TestService extends Disposable implements ITestService { @IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService, ) { super(); + this.collection = new MainThreadTestCollection(this.uriIdentityService, this.expandTest.bind(this)); this.excluded = instantiationService.createInstance(TestExclusions); + this.showInlineOutput = this._register(MutableObservableValue.stored(new StoredValue({ + key: 'inlineTestOutputVisible', + scope: StorageScope.WORKSPACE, + target: StorageTarget.USER + }, this.storage), true)); this.isRefreshingTests = TestingContextKeys.isRefreshingTests.bindTo(contextKeyService); this.activeEditorHasTests = TestingContextKeys.activeEditorHasTests.bindTo(contextKeyService); diff --git a/src/vs/workbench/contrib/testing/test/common/testStubs.ts b/src/vs/workbench/contrib/testing/test/common/testStubs.ts index d484c5e4f6294..87b45af29e516 100644 --- a/src/vs/workbench/contrib/testing/test/common/testStubs.ts +++ b/src/vs/workbench/contrib/testing/test/common/testStubs.ts @@ -7,7 +7,7 @@ import { URI } from '../../../../../base/common/uri.js'; import { MainThreadTestCollection } from '../../common/mainThreadTestCollection.js'; import { ITestItem, TestsDiff } from '../../common/testTypes.js'; import { TestId } from '../../common/testId.js'; -import { createTestItemChildren, ITestItemApi, ITestItemLike, TestItemCollection, TestItemEventOp } from '../../common/testItemCollection.js'; +import { createTestItemChildren, ITestItemApi, ITestItemChildren, ITestItemLike, TestItemCollection, TestItemEventOp } from '../../common/testItemCollection.js'; export class TestTestItem implements ITestItemLike { private readonly props: ITestItem; @@ -39,9 +39,9 @@ export class TestTestItem implements ITestItemLike { return this._extId.localId; } - public api: ITestItemApi = { controllerId: this._extId.controllerId }; + public api: ITestItemApi; - public children = createTestItemChildren(this.api, i => i.api, TestTestItem); + public children: ITestItemChildren; constructor( private readonly _extId: TestId, @@ -59,6 +59,10 @@ export class TestTestItem implements ITestItemLike { tags: [], uri, }; + + this.api = { controllerId: this._extId.controllerId }; + + this.children = createTestItemChildren(this.api, i => i.api, TestTestItem); } public get(key: K): ITestItem[K] { diff --git a/src/vs/workbench/contrib/welcomeDialog/browser/welcomeWidget.ts b/src/vs/workbench/contrib/welcomeDialog/browser/welcomeWidget.ts index c33e006b35e9f..70dc2ac277c2b 100644 --- a/src/vs/workbench/contrib/welcomeDialog/browser/welcomeWidget.ts +++ b/src/vs/workbench/contrib/welcomeDialog/browser/welcomeWidget.ts @@ -34,7 +34,7 @@ export class WelcomeWidget extends Disposable implements IOverlayWidget { private readonly _rootDomNode: HTMLElement; private readonly element: HTMLElement; private readonly messageContainer: HTMLElement; - private readonly markdownRenderer = this.instantiationService.createInstance(MarkdownRenderer, {}); + private readonly markdownRenderer: MarkdownRenderer; constructor( private readonly _editor: ICodeEditor, @@ -44,6 +44,9 @@ export class WelcomeWidget extends Disposable implements IOverlayWidget { private readonly openerService: IOpenerService ) { super(); + + this.markdownRenderer = this.instantiationService.createInstance(MarkdownRenderer, {}); + this._rootDomNode = document.createElement('div'); this._rootDomNode.className = 'welcome-widget'; diff --git a/src/vs/workbench/services/authentication/browser/authenticationExtensionsService.ts b/src/vs/workbench/services/authentication/browser/authenticationExtensionsService.ts index af74628d58ce1..593ae11da7866 100644 --- a/src/vs/workbench/services/authentication/browser/authenticationExtensionsService.ts +++ b/src/vs/workbench/services/authentication/browser/authenticationExtensionsService.ts @@ -42,13 +42,8 @@ export class AuthenticationExtensionsService extends Disposable implements IAuth private _onDidAccountPreferenceChange: Emitter<{ providerId: string; extensionIds: string[] }> = this._register(new Emitter<{ providerId: string; extensionIds: string[] }>()); readonly onDidChangeAccountPreference = this._onDidAccountPreferenceChange.event; - private _inheritAuthAccountPreferenceParentToChildren: Record = this._productService.inheritAuthAccountPreference || {}; - private _inheritAuthAccountPreferenceChildToParent = Object.entries(this._inheritAuthAccountPreferenceParentToChildren).reduce<{ [extensionId: string]: string }>((acc, [parent, children]) => { - children.forEach((child: string) => { - acc[child] = parent; - }); - return acc; - }, {}); + private _inheritAuthAccountPreferenceParentToChildren: Record; + private _inheritAuthAccountPreferenceChildToParent: { [extensionId: string]: string }; constructor( @IActivityService private readonly activityService: IActivityService, @@ -61,6 +56,16 @@ export class AuthenticationExtensionsService extends Disposable implements IAuth @IAuthenticationAccessService private readonly _authenticationAccessService: IAuthenticationAccessService ) { super(); + + this._inheritAuthAccountPreferenceParentToChildren = this._productService.inheritAuthAccountPreference || {}; + + this._inheritAuthAccountPreferenceChildToParent = Object.entries(this._inheritAuthAccountPreferenceParentToChildren).reduce<{ [extensionId: string]: string }>((acc, [parent, children]) => { + children.forEach((child: string) => { + acc[child] = parent; + }); + return acc; + }, {}); + this.registerListeners(); } diff --git a/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts index 65b49fb7bd124..b81cba17b56de 100644 --- a/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/webExtensionManagementService.ts @@ -250,7 +250,7 @@ class InstallExtensionTask extends AbstractExtensionTask implem readonly identifier: IExtensionIdentifier; readonly source: URI | IGalleryExtension; - private _profileLocation = this.options.profileLocation; + private _profileLocation: URI; get profileLocation() { return this._profileLocation; } private _operation = InstallOperation.Install; @@ -266,6 +266,7 @@ class InstallExtensionTask extends AbstractExtensionTask implem super(); this.identifier = URI.isUri(extension) ? { id: getGalleryExtensionId(manifest.publisher, manifest.name) } : extension.identifier; this.source = extension; + this._profileLocation = this.options.profileLocation; } protected async doRun(token: CancellationToken): Promise { diff --git a/src/vs/workbench/services/files/electron-sandbox/diskFileSystemProvider.ts b/src/vs/workbench/services/files/electron-sandbox/diskFileSystemProvider.ts index c037805a6d351..82279e1c35a94 100644 --- a/src/vs/workbench/services/files/electron-sandbox/diskFileSystemProvider.ts +++ b/src/vs/workbench/services/files/electron-sandbox/diskFileSystemProvider.ts @@ -32,7 +32,7 @@ export class DiskFileSystemProvider extends AbstractDiskFileSystemProvider imple IFileSystemProviderWithFileAtomicReadCapability, IFileSystemProviderWithFileCloneCapability { - private readonly provider = this._register(new DiskFileSystemProviderClient(this.mainProcessService.getChannel(LOCAL_FILE_SYSTEM_CHANNEL_NAME), { pathCaseSensitive: isLinux, trash: true })); + private readonly provider: DiskFileSystemProviderClient; constructor( private readonly mainProcessService: IMainProcessService, @@ -42,6 +42,8 @@ export class DiskFileSystemProvider extends AbstractDiskFileSystemProvider imple ) { super(logService, { watcher: { forceUniversal: true /* send all requests to universal watcher process */ } }); + this.provider = this._register(new DiskFileSystemProviderClient(this.mainProcessService.getChannel(LOCAL_FILE_SYSTEM_CHANNEL_NAME), { pathCaseSensitive: isLinux, trash: true })); + this.registerListeners(); } diff --git a/src/vs/workbench/services/filesConfiguration/common/filesConfigurationService.ts b/src/vs/workbench/services/filesConfiguration/common/filesConfigurationService.ts index e9e60430f2556..f05718626d69c 100644 --- a/src/vs/workbench/services/filesConfiguration/common/filesConfigurationService.ts +++ b/src/vs/workbench/services/filesConfiguration/common/filesConfigurationService.ts @@ -8,7 +8,7 @@ import { createDecorator } from '../../../../platform/instantiation/common/insta import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; import { Event, Emitter } from '../../../../base/common/event.js'; import { Disposable, IDisposable, toDisposable } from '../../../../base/common/lifecycle.js'; -import { RawContextKey, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; +import { RawContextKey, IContextKeyService, IContextKey } from '../../../../platform/contextkey/common/contextkey.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { IFilesConfiguration, AutoSaveConfiguration, HotExitConfiguration, FILES_READONLY_INCLUDE_CONFIG, FILES_READONLY_EXCLUDE_CONFIG, IFileStatWithMetadata, IFileService, IBaseFileStat, hasReadonlyCapability, IFilesConfigurationNode } from '../../../../platform/files/common/files.js'; import { equals } from '../../../../base/common/objects.js'; @@ -149,7 +149,7 @@ export class FilesConfigurationService extends Disposable implements IFilesConfi private readonly autoSaveConfigurationCache = new LRUCache(1000); private readonly autoSaveDisabledOverrides = new ResourceMap(); - private readonly autoSaveAfterShortDelayContext = AutoSaveAfterShortDelayContext.bindTo(this.contextKeyService); + private readonly autoSaveAfterShortDelayContext: IContextKey; private readonly readonlyIncludeMatcher = this._register(new GlobalIdleValue(() => this.createReadonlyMatcher(FILES_READONLY_INCLUDE_CONFIG))); private readonly readonlyExcludeMatcher = this._register(new GlobalIdleValue(() => this.createReadonlyMatcher(FILES_READONLY_EXCLUDE_CONFIG))); @@ -175,6 +175,8 @@ export class FilesConfigurationService extends Disposable implements IFilesConfi this.currentFilesAssociationConfiguration = configuration?.files?.associations; this.currentHotExitConfiguration = configuration?.files?.hotExit || HotExitConfiguration.ON_EXIT; + this.autoSaveAfterShortDelayContext = AutoSaveAfterShortDelayContext.bindTo(this.contextKeyService); + this.onFilesConfigurationChange(configuration, false); this.registerListeners(); diff --git a/src/vs/workbench/services/history/browser/historyService.ts b/src/vs/workbench/services/history/browser/historyService.ts index 62791d7a0bcf2..00324ce0a3452 100644 --- a/src/vs/workbench/services/history/browser/historyService.ts +++ b/src/vs/workbench/services/history/browser/historyService.ts @@ -21,7 +21,7 @@ import { getExcludes, ISearchConfiguration, SEARCH_EXCLUDE_CONFIG } from '../../ import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; import { EditorServiceImpl } from '../../../browser/parts/editor/editor.js'; import { IWorkbenchLayoutService } from '../../layout/browser/layoutService.js'; -import { IContextKeyService, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js'; +import { IContextKey, IContextKeyService, RawContextKey } from '../../../../platform/contextkey/common/contextkey.js'; import { coalesce, remove } from '../../../../base/common/arrays.js'; import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; import { addDisposableListener, EventType, EventHelper, WindowIdleValue } from '../../../../base/browser/dom.js'; @@ -60,7 +60,7 @@ export class HistoryService extends Disposable implements IHistoryService { private readonly activeEditorListeners = this._register(new DisposableStore()); private lastActiveEditor: IEditorIdentifier | undefined = undefined; - private readonly editorHelper = this.instantiationService.createInstance(EditorHelper); + private readonly editorHelper: EditorHelper; constructor( @IEditorService private readonly editorService: EditorServiceImpl, @@ -77,6 +77,21 @@ export class HistoryService extends Disposable implements IHistoryService { ) { super(); + this.editorHelper = this.instantiationService.createInstance(EditorHelper); + + this.canNavigateBackContextKey = (new RawContextKey('canNavigateBack', false, localize('canNavigateBack', "Whether it is possible to navigate back in editor history"))).bindTo(this.contextKeyService); + this.canNavigateForwardContextKey = (new RawContextKey('canNavigateForward', false, localize('canNavigateForward', "Whether it is possible to navigate forward in editor history"))).bindTo(this.contextKeyService); + + this.canNavigateBackInNavigationsContextKey = (new RawContextKey('canNavigateBackInNavigationLocations', false, localize('canNavigateBackInNavigationLocations', "Whether it is possible to navigate back in editor navigation locations history"))).bindTo(this.contextKeyService); + this.canNavigateForwardInNavigationsContextKey = (new RawContextKey('canNavigateForwardInNavigationLocations', false, localize('canNavigateForwardInNavigationLocations', "Whether it is possible to navigate forward in editor navigation locations history"))).bindTo(this.contextKeyService); + this.canNavigateToLastNavigationLocationContextKey = (new RawContextKey('canNavigateToLastNavigationLocation', false, localize('canNavigateToLastNavigationLocation', "Whether it is possible to navigate to the last editor navigation location"))).bindTo(this.contextKeyService); + + this.canNavigateBackInEditsContextKey = (new RawContextKey('canNavigateBackInEditLocations', false, localize('canNavigateBackInEditLocations', "Whether it is possible to navigate back in editor edit locations history"))).bindTo(this.contextKeyService); + this.canNavigateForwardInEditsContextKey = (new RawContextKey('canNavigateForwardInEditLocations', false, localize('canNavigateForwardInEditLocations', "Whether it is possible to navigate forward in editor edit locations history"))).bindTo(this.contextKeyService); + this.canNavigateToLastEditLocationContextKey = (new RawContextKey('canNavigateToLastEditLocation', false, localize('canNavigateToLastEditLocation', "Whether it is possible to navigate to the last editor edit location"))).bindTo(this.contextKeyService); + + this.canReopenClosedEditorContextKey = (new RawContextKey('canReopenClosedEditor', false, localize('canReopenClosedEditor', "Whether it is possible to reopen the last closed editor"))).bindTo(this.contextKeyService); + this.registerListeners(); // if the service is created late enough that an editor is already opened @@ -302,18 +317,18 @@ export class HistoryService extends Disposable implements IHistoryService { //#region History Context Keys - private readonly canNavigateBackContextKey = (new RawContextKey('canNavigateBack', false, localize('canNavigateBack', "Whether it is possible to navigate back in editor history"))).bindTo(this.contextKeyService); - private readonly canNavigateForwardContextKey = (new RawContextKey('canNavigateForward', false, localize('canNavigateForward', "Whether it is possible to navigate forward in editor history"))).bindTo(this.contextKeyService); + private readonly canNavigateBackContextKey: IContextKey; + private readonly canNavigateForwardContextKey: IContextKey; - private readonly canNavigateBackInNavigationsContextKey = (new RawContextKey('canNavigateBackInNavigationLocations', false, localize('canNavigateBackInNavigationLocations', "Whether it is possible to navigate back in editor navigation locations history"))).bindTo(this.contextKeyService); - private readonly canNavigateForwardInNavigationsContextKey = (new RawContextKey('canNavigateForwardInNavigationLocations', false, localize('canNavigateForwardInNavigationLocations', "Whether it is possible to navigate forward in editor navigation locations history"))).bindTo(this.contextKeyService); - private readonly canNavigateToLastNavigationLocationContextKey = (new RawContextKey('canNavigateToLastNavigationLocation', false, localize('canNavigateToLastNavigationLocation', "Whether it is possible to navigate to the last editor navigation location"))).bindTo(this.contextKeyService); + private readonly canNavigateBackInNavigationsContextKey: IContextKey; + private readonly canNavigateForwardInNavigationsContextKey: IContextKey; + private readonly canNavigateToLastNavigationLocationContextKey: IContextKey; - private readonly canNavigateBackInEditsContextKey = (new RawContextKey('canNavigateBackInEditLocations', false, localize('canNavigateBackInEditLocations', "Whether it is possible to navigate back in editor edit locations history"))).bindTo(this.contextKeyService); - private readonly canNavigateForwardInEditsContextKey = (new RawContextKey('canNavigateForwardInEditLocations', false, localize('canNavigateForwardInEditLocations', "Whether it is possible to navigate forward in editor edit locations history"))).bindTo(this.contextKeyService); - private readonly canNavigateToLastEditLocationContextKey = (new RawContextKey('canNavigateToLastEditLocation', false, localize('canNavigateToLastEditLocation', "Whether it is possible to navigate to the last editor edit location"))).bindTo(this.contextKeyService); + private readonly canNavigateBackInEditsContextKey: IContextKey; + private readonly canNavigateForwardInEditsContextKey: IContextKey; + private readonly canNavigateToLastEditLocationContextKey: IContextKey; - private readonly canReopenClosedEditorContextKey = (new RawContextKey('canReopenClosedEditor', false, localize('canReopenClosedEditor', "Whether it is possible to reopen the last closed editor"))).bindTo(this.contextKeyService); + private readonly canReopenClosedEditorContextKey: IContextKey; updateContextKeys(): void { this.contextKeyService.bufferChangeEvents(() => { @@ -1257,27 +1272,35 @@ interface IEditorNavigationStacks extends IDisposable { class EditorNavigationStacks extends Disposable implements IEditorNavigationStacks { - private readonly selectionsStack = this._register(this.instantiationService.createInstance(EditorNavigationStack, GoFilter.NONE, this.scope)); - private readonly editsStack = this._register(this.instantiationService.createInstance(EditorNavigationStack, GoFilter.EDITS, this.scope)); - private readonly navigationsStack = this._register(this.instantiationService.createInstance(EditorNavigationStack, GoFilter.NAVIGATION, this.scope)); + private readonly selectionsStack: EditorNavigationStack; + private readonly editsStack: EditorNavigationStack; + private readonly navigationsStack: EditorNavigationStack; - private readonly stacks: EditorNavigationStack[] = [ - this.selectionsStack, - this.editsStack, - this.navigationsStack - ]; + private readonly stacks: EditorNavigationStack[]; - readonly onDidChange = Event.any( - this.selectionsStack.onDidChange, - this.editsStack.onDidChange, - this.navigationsStack.onDidChange - ); + readonly onDidChange: Event; constructor( private readonly scope: GoScope, @IInstantiationService private readonly instantiationService: IInstantiationService ) { super(); + + this.selectionsStack = this._register(this.instantiationService.createInstance(EditorNavigationStack, GoFilter.NONE, this.scope)); + this.editsStack = this._register(this.instantiationService.createInstance(EditorNavigationStack, GoFilter.EDITS, this.scope)); + this.navigationsStack = this._register(this.instantiationService.createInstance(EditorNavigationStack, GoFilter.NAVIGATION, this.scope)); + + this.stacks = [ + this.selectionsStack, + this.editsStack, + this.navigationsStack + ]; + + this.onDidChange = Event.any( + this.selectionsStack.onDidChange, + this.editsStack.onDidChange, + this.navigationsStack.onDidChange + ); } canGoForward(filter?: GoFilter): boolean { @@ -1414,7 +1437,7 @@ export class EditorNavigationStack extends Disposable { private readonly mapEditorToDisposable = new Map(); private readonly mapGroupToDisposable = new Map(); - private readonly editorHelper = this.instantiationService.createInstance(EditorHelper); + private readonly editorHelper: EditorHelper; private stack: IEditorNavigationStackEntry[] = []; @@ -1445,6 +1468,8 @@ export class EditorNavigationStack extends Disposable { ) { super(); + this.editorHelper = this.instantiationService.createInstance(EditorHelper); + this.registerListeners(); } diff --git a/src/vs/workbench/services/host/electron-sandbox/nativeHostService.ts b/src/vs/workbench/services/host/electron-sandbox/nativeHostService.ts index be5cdaa8bb6f5..dbcac1868bc41 100644 --- a/src/vs/workbench/services/host/electron-sandbox/nativeHostService.ts +++ b/src/vs/workbench/services/host/electron-sandbox/nativeHostService.ts @@ -39,17 +39,21 @@ class WorkbenchHostService extends Disposable implements IHostService { @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService ) { super(); + + this.onDidChangeFocus = Event.latch( + Event.any( + Event.map(Event.filter(this.nativeHostService.onDidFocusMainOrAuxiliaryWindow, id => hasWindow(id), this._store), () => this.hasFocus, this._store), + Event.map(Event.filter(this.nativeHostService.onDidBlurMainOrAuxiliaryWindow, id => hasWindow(id), this._store), () => this.hasFocus, this._store), + Event.map(this.onDidChangeActiveWindow, () => this.hasFocus, this._store) + ), undefined, this._store + ); + + this.onDidChangeFullScreen = Event.filter(this.nativeHostService.onDidChangeWindowFullScreen, e => hasWindow(e.windowId), this._store); } //#region Focus - readonly onDidChangeFocus = Event.latch( - Event.any( - Event.map(Event.filter(this.nativeHostService.onDidFocusMainOrAuxiliaryWindow, id => hasWindow(id), this._store), () => this.hasFocus, this._store), - Event.map(Event.filter(this.nativeHostService.onDidBlurMainOrAuxiliaryWindow, id => hasWindow(id), this._store), () => this.hasFocus, this._store), - Event.map(this.onDidChangeActiveWindow, () => this.hasFocus, this._store) - ), undefined, this._store - ); + readonly onDidChangeFocus: Event; get hasFocus(): boolean { return getActiveDocument().hasFocus(); @@ -94,7 +98,7 @@ class WorkbenchHostService extends Disposable implements IHostService { return Event.latch(emitter.event, undefined, this._store); } - readonly onDidChangeFullScreen = Event.filter(this.nativeHostService.onDidChangeWindowFullScreen, e => hasWindow(e.windowId), this._store); + readonly onDidChangeFullScreen: Event<{ windowId: number; fullscreen: boolean }>; openWindow(options?: IOpenEmptyWindowOptions): Promise; openWindow(toOpen: IWindowOpenable[], options?: IOpenWindowOptions): Promise; diff --git a/src/vs/workbench/services/integrity/electron-sandbox/integrityService.ts b/src/vs/workbench/services/integrity/electron-sandbox/integrityService.ts index 8050895e5f63d..96da0a54f327e 100644 --- a/src/vs/workbench/services/integrity/electron-sandbox/integrityService.ts +++ b/src/vs/workbench/services/integrity/electron-sandbox/integrityService.ts @@ -59,7 +59,7 @@ export class IntegrityService implements IIntegrityService { declare readonly _serviceBrand: undefined; - private readonly _storage = new IntegrityStorage(this.storageService); + private readonly _storage: IntegrityStorage; private readonly _isPurePromise = this._isPure(); isPure(): Promise { @@ -75,6 +75,8 @@ export class IntegrityService implements IIntegrityService { @IChecksumService private readonly checksumService: IChecksumService, @ILogService private readonly logService: ILogService ) { + this._storage = new IntegrityStorage(this.storageService); + this._compute(); } diff --git a/src/vs/workbench/services/notification/common/notificationService.ts b/src/vs/workbench/services/notification/common/notificationService.ts index f557bc098c133..a61a1c3b6f0cc 100644 --- a/src/vs/workbench/services/notification/common/notificationService.ts +++ b/src/vs/workbench/services/notification/common/notificationService.ts @@ -29,6 +29,8 @@ export class NotificationService extends Disposable implements INotificationServ ) { super(); + this.globalFilterEnabled = this.storageService.getBoolean(NotificationService.GLOBAL_FILTER_SETTINGS_KEY, StorageScope.APPLICATION, false); + this.updateFilters(); this.registerListeners(); } @@ -81,7 +83,7 @@ export class NotificationService extends Disposable implements INotificationServ private readonly _onDidChangeFilter = this._register(new Emitter()); readonly onDidChangeFilter = this._onDidChangeFilter.event; - private globalFilterEnabled = this.storageService.getBoolean(NotificationService.GLOBAL_FILTER_SETTINGS_KEY, StorageScope.APPLICATION, false); + private globalFilterEnabled: boolean; private readonly mapSourceToFilter: Map = (() => { const map = new Map(); diff --git a/src/vs/workbench/services/storage/browser/storageService.ts b/src/vs/workbench/services/storage/browser/storageService.ts index 68573404c1e03..ca10b6f7d95dc 100644 --- a/src/vs/workbench/services/storage/browser/storageService.ts +++ b/src/vs/workbench/services/storage/browser/storageService.ts @@ -29,7 +29,7 @@ export class BrowserStorageService extends AbstractStorageService { private profileStorage: IStorage | undefined; private profileStorageDatabase: IIndexedDBStorageDatabase | undefined; - private profileStorageProfile = this.userDataProfileService.currentProfile; + private profileStorageProfile: IUserDataProfile; private readonly profileStorageDisposables = this._register(new DisposableStore()); private workspaceStorage: IStorage | undefined; @@ -50,6 +50,8 @@ export class BrowserStorageService extends AbstractStorageService { ) { super({ flushInterval: BrowserStorageService.BROWSER_DEFAULT_FLUSH_INTERVAL }); + this.profileStorageProfile = this.userDataProfileService.currentProfile; + this.registerListeners(); } diff --git a/src/vs/workbench/services/textMate/browser/backgroundTokenization/textMateWorkerTokenizerController.ts b/src/vs/workbench/services/textMate/browser/backgroundTokenization/textMateWorkerTokenizerController.ts index fa0f874e7e837..242df45636f5b 100644 --- a/src/vs/workbench/services/textMate/browser/backgroundTokenization/textMateWorkerTokenizerController.ts +++ b/src/vs/workbench/services/textMate/browser/backgroundTokenization/textMateWorkerTokenizerController.ts @@ -33,7 +33,7 @@ export class TextMateWorkerTokenizerController extends Disposable { */ private readonly _states = new TokenizationStateStore(); - private readonly _loggingEnabled = observableConfigValue('editor.experimental.asyncTokenizationLogging', false, this._configurationService); + private readonly _loggingEnabled: IObservable; private _applyStateStackDiffFn?: typeof applyStateStackDiff; private _initialState?: StateStack; @@ -48,6 +48,7 @@ export class TextMateWorkerTokenizerController extends Disposable { ) { super(); + this._loggingEnabled = observableConfigValue('editor.experimental.asyncTokenizationLogging', false, this._configurationService); this._register(keepObserved(this._loggingEnabled)); this._register(this._model.onDidChangeContent((e) => { diff --git a/src/vs/workbench/services/textMate/browser/textMateTokenizationFeatureImpl.ts b/src/vs/workbench/services/textMate/browser/textMateTokenizationFeatureImpl.ts index 2620e9a420063..9795248911d11 100644 --- a/src/vs/workbench/services/textMate/browser/textMateTokenizationFeatureImpl.ts +++ b/src/vs/workbench/services/textMate/browser/textMateTokenizationFeatureImpl.ts @@ -55,11 +55,7 @@ export class TextMateTokenizationFeature extends Disposable implements ITextMate private readonly _tokenizersRegistrations = new DisposableStore(); private _currentTheme: IRawTheme | null = null; private _currentTokenColorMap: string[] | null = null; - private readonly _threadedBackgroundTokenizerFactory = this._instantiationService.createInstance( - ThreadedBackgroundTokenizerFactory, - (timeMs, languageId, sourceExtensionId, lineLength, isRandomSample) => this._reportTokenizationTime(timeMs, languageId, sourceExtensionId, lineLength, true, isRandomSample), - () => this.getAsyncTokenizationEnabled(), - ); + private readonly _threadedBackgroundTokenizerFactory: ThreadedBackgroundTokenizerFactory; constructor( @ILanguageService private readonly _languageService: ILanguageService, @@ -78,6 +74,12 @@ export class TextMateTokenizationFeature extends Disposable implements ITextMate this._styleElement = domStylesheets.createStyleSheet(); this._styleElement.className = 'vscode-tokens-styles'; + this._threadedBackgroundTokenizerFactory = this._instantiationService.createInstance( + ThreadedBackgroundTokenizerFactory, + (timeMs, languageId, sourceExtensionId, lineLength, isRandomSample) => this._reportTokenizationTime(timeMs, languageId, sourceExtensionId, lineLength, true, isRandomSample), + () => this.getAsyncTokenizationEnabled(), + ); + grammarsExtPoint.setHandler((extensions) => this._handleGrammarsExtPoint(extensions)); this._updateTheme(this._themeService.getColorTheme(), true); diff --git a/src/vs/workbench/services/textfile/browser/textFileService.ts b/src/vs/workbench/services/textfile/browser/textFileService.ts index 352a5e7dd8ca4..84388990e132b 100644 --- a/src/vs/workbench/services/textfile/browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -51,9 +51,9 @@ export abstract class AbstractTextFileService extends Disposable implements ITex private static readonly TEXTFILE_SAVE_CREATE_SOURCE = SaveSourceRegistry.registerSource('textFileCreate.source', localize('textFileCreate.source', "File Created")); private static readonly TEXTFILE_SAVE_REPLACE_SOURCE = SaveSourceRegistry.registerSource('textFileOverwrite.source', localize('textFileOverwrite.source', "File Replaced")); - readonly files: ITextFileEditorModelManager = this._register(this.instantiationService.createInstance(TextFileEditorModelManager)); + readonly files: ITextFileEditorModelManager; - readonly untitled: IUntitledTextEditorModelManager = this.untitledTextEditorService; + readonly untitled: IUntitledTextEditorModelManager; constructor( @IFileService protected readonly fileService: IFileService, @@ -77,6 +77,10 @@ export abstract class AbstractTextFileService extends Disposable implements ITex ) { super(); + this.files = this._register(this.instantiationService.createInstance(TextFileEditorModelManager)); + + this.untitled = this.untitledTextEditorService; + this.provideDecorations(); } diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index 31b4827edfb0f..58e3bc7308f08 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -86,8 +86,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil readonly capabilities = WorkingCopyCapabilities.None; - readonly name = basename(this.labelService.getUriLabel(this.resource)); - private resourceHasExtension: boolean = !!extUri.extname(this.resource); + readonly name: string; + private resourceHasExtension: boolean; private contentEncoding: string | undefined; // encoding as reported from disk @@ -130,6 +130,10 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil ) { super(modelService, languageService, languageDetectionService, accessibilityService); + this.name = basename(this.labelService.getUriLabel(this.resource)); + + this.resourceHasExtension = !!extUri.extname(this.resource); + // Make known to working copy service this._register(this.workingCopyService.registerWorkingCopy(this)); diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts index 0da81d1e2f6bb..81a2ae95035ab 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts @@ -99,6 +99,8 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE ) { super(); + this.saveParticipants = this._register(this.instantiationService.createInstance(TextFileSaveParticipant)); + this.registerListeners(); } @@ -558,7 +560,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE //#region Save participants - private readonly saveParticipants = this._register(this.instantiationService.createInstance(TextFileSaveParticipant)); + private readonly saveParticipants: TextFileSaveParticipant; addSaveParticipant(participant: ITextFileSaveParticipant): IDisposable { return this.saveParticipants.addSaveParticipant(participant); diff --git a/src/vs/workbench/services/untitled/common/untitledTextEditorModel.ts b/src/vs/workbench/services/untitled/common/untitledTextEditorModel.ts index 5a4c357d56690..31ff76a179efc 100644 --- a/src/vs/workbench/services/untitled/common/untitledTextEditorModel.ts +++ b/src/vs/workbench/services/untitled/common/untitledTextEditorModel.ts @@ -144,6 +144,8 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt ) { super(modelService, languageService, languageDetectionService, accessibilityService); + this.dirty = this.hasAssociatedFilePath || !!this.initialValue; + // Make known to working copy service this._register(this.workingCopyService.registerWorkingCopy(this)); @@ -237,7 +239,7 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IUnt //#region Dirty - private dirty = this.hasAssociatedFilePath || !!this.initialValue; + private dirty: boolean; isDirty(): boolean { return this.dirty; diff --git a/src/vs/workbench/services/userDataProfile/browser/snippetsResource.ts b/src/vs/workbench/services/userDataProfile/browser/snippetsResource.ts index 7b29090f272b4..547a169086899 100644 --- a/src/vs/workbench/services/userDataProfile/browser/snippetsResource.ts +++ b/src/vs/workbench/services/userDataProfile/browser/snippetsResource.ts @@ -99,7 +99,7 @@ export class SnippetsResource implements IProfileResource { export class SnippetsResourceTreeItem implements IProfileResourceTreeItem { readonly type = ProfileResourceType.Snippets; - readonly handle = this.profile.snippetsHome.toString(); + readonly handle: string; readonly label = { label: localize('snippets', "Snippets") }; readonly collapsibleState = TreeItemCollapsibleState.Collapsed; checkbox: ITreeItemCheckboxState | undefined; @@ -110,7 +110,9 @@ export class SnippetsResourceTreeItem implements IProfileResourceTreeItem { private readonly profile: IUserDataProfile, @IInstantiationService private readonly instantiationService: IInstantiationService, @IUriIdentityService private readonly uriIdentityService: IUriIdentityService, - ) { } + ) { + this.handle = this.profile.snippetsHome.toString(); + } async getChildren(): Promise { const snippetsResources = await this.instantiationService.createInstance(SnippetsResource).getSnippetsResources(this.profile); diff --git a/src/vs/workbench/services/workingCopy/common/untitledFileWorkingCopy.ts b/src/vs/workbench/services/workingCopy/common/untitledFileWorkingCopy.ts index 08df8feee6ca5..58da7105b0bbd 100644 --- a/src/vs/workbench/services/workingCopy/common/untitledFileWorkingCopy.ts +++ b/src/vs/workbench/services/workingCopy/common/untitledFileWorkingCopy.ts @@ -92,7 +92,7 @@ export interface IUntitledFileWorkingCopyInitialContents { export class UntitledFileWorkingCopy extends Disposable implements IUntitledFileWorkingCopy { - readonly capabilities = this.isScratchpad ? WorkingCopyCapabilities.Untitled | WorkingCopyCapabilities.Scratchpad : WorkingCopyCapabilities.Untitled; + readonly capabilities: number; private _model: M | undefined = undefined; get model(): M | undefined { return this._model; } @@ -131,13 +131,16 @@ export class UntitledFileWorkingCopy ex ) { super(); + this.capabilities = this.isScratchpad ? WorkingCopyCapabilities.Untitled | WorkingCopyCapabilities.Scratchpad : WorkingCopyCapabilities.Untitled; + this.modified = this.hasAssociatedFilePath || Boolean(this.initialContents && this.initialContents.markModified !== false); + // Make known to working copy service this._register(workingCopyService.registerWorkingCopy(this)); } //#region Dirty/Modified - private modified = this.hasAssociatedFilePath || Boolean(this.initialContents && this.initialContents.markModified !== false); + private modified: boolean; isDirty(): boolean { return this.modified && !this.isScratchpad; // Scratchpad working copies are never dirty diff --git a/src/vs/workbench/services/workingCopy/common/workingCopyFileService.ts b/src/vs/workbench/services/workingCopy/common/workingCopyFileService.ts index 4e2d5626d1185..c3ee664fcabd2 100644 --- a/src/vs/workbench/services/workingCopy/common/workingCopyFileService.ts +++ b/src/vs/workbench/services/workingCopy/common/workingCopyFileService.ts @@ -314,6 +314,10 @@ export class WorkingCopyFileService extends Disposable implements IWorkingCopyFi ) { super(); + this.fileOperationParticipants = this._register(this.instantiationService.createInstance(WorkingCopyFileOperationParticipant)); + + this.saveParticipants = this._register(this.instantiationService.createInstance(StoredFileWorkingCopySaveParticipant)); + // register a default working copy provider that uses the working copy service this._register(this.registerWorkingCopyProvider(resource => { return this.workingCopyService.workingCopies.filter(workingCopy => { @@ -491,7 +495,7 @@ export class WorkingCopyFileService extends Disposable implements IWorkingCopyFi //#region File operation participants - private readonly fileOperationParticipants = this._register(this.instantiationService.createInstance(WorkingCopyFileOperationParticipant)); + private readonly fileOperationParticipants: WorkingCopyFileOperationParticipant; addFileOperationParticipant(participant: IWorkingCopyFileOperationParticipant): IDisposable { return this.fileOperationParticipants.addFileOperationParticipant(participant); @@ -505,7 +509,7 @@ export class WorkingCopyFileService extends Disposable implements IWorkingCopyFi //#region Save participants (stored file working copies only) - private readonly saveParticipants = this._register(this.instantiationService.createInstance(StoredFileWorkingCopySaveParticipant)); + private readonly saveParticipants: StoredFileWorkingCopySaveParticipant; get hasSaveParticipants(): boolean { return this.saveParticipants.length > 0; } diff --git a/src/vs/workbench/test/browser/parts/editor/editorGroupModel.test.ts b/src/vs/workbench/test/browser/parts/editor/editorGroupModel.test.ts index 30c8430e65577..9b7777b514736 100644 --- a/src/vs/workbench/test/browser/parts/editor/editorGroupModel.test.ts +++ b/src/vs/workbench/test/browser/parts/editor/editorGroupModel.test.ts @@ -236,10 +236,12 @@ suite('EditorGroupModel', () => { class TestFileEditorInput extends EditorInput implements IFileEditorInput { - readonly preferredResource = this.resource; + readonly preferredResource: URI; constructor(public id: string, public resource: URI) { super(); + + this.preferredResource = this.resource; } override get typeId() { return 'testFileEditorInputForGroups'; } override get editorId() { return this.id; } diff --git a/src/vs/workbench/test/browser/parts/editor/filteredEditorGroupModel.test.ts b/src/vs/workbench/test/browser/parts/editor/filteredEditorGroupModel.test.ts index c4fef60fd157d..77655bb6ae789 100644 --- a/src/vs/workbench/test/browser/parts/editor/filteredEditorGroupModel.test.ts +++ b/src/vs/workbench/test/browser/parts/editor/filteredEditorGroupModel.test.ts @@ -104,10 +104,12 @@ suite('FilteredEditorGroupModel', () => { class TestFileEditorInput extends EditorInput implements IFileEditorInput { - readonly preferredResource = this.resource; + readonly preferredResource: URI; constructor(public id: string, public resource: URI) { super(); + + this.preferredResource = this.resource; } override get typeId() { return 'testFileEditorInputForGroups'; } override get editorId() { return this.id; } diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index 6161e10f542fc..b69ea60a74cbd 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -1467,17 +1467,22 @@ export class TestTextResourceConfigurationService implements ITextResourceConfig export class RemoteFileSystemProvider implements IFileSystemProvider { - constructor(private readonly wrappedFsp: IFileSystemProvider, private readonly remoteAuthority: string) { } + constructor(private readonly wrappedFsp: IFileSystemProvider, private readonly remoteAuthority: string) { + this.capabilities = this.wrappedFsp.capabilities; + this.onDidChangeCapabilities = this.wrappedFsp.onDidChangeCapabilities; - readonly capabilities: FileSystemProviderCapabilities = this.wrappedFsp.capabilities; - readonly onDidChangeCapabilities: Event = this.wrappedFsp.onDidChangeCapabilities; + this.onDidChangeFile = Event.map(this.wrappedFsp.onDidChangeFile, changes => changes.map(c => { + return { + type: c.type, + resource: c.resource.with({ scheme: Schemas.vscodeRemote, authority: this.remoteAuthority }), + }; + })); + } - readonly onDidChangeFile: Event = Event.map(this.wrappedFsp.onDidChangeFile, changes => changes.map(c => { - return { - type: c.type, - resource: c.resource.with({ scheme: Schemas.vscodeRemote, authority: this.remoteAuthority }), - }; - })); + readonly capabilities: FileSystemProviderCapabilities; + readonly onDidChangeCapabilities: Event; + + readonly onDidChangeFile: Event; watch(resource: URI, opts: IWatchOptions): IDisposable { return this.wrappedFsp.watch(this.toFileResource(resource), opts); } stat(resource: URI): Promise { return this.wrappedFsp.stat(this.toFileResource(resource)); } @@ -1728,7 +1733,7 @@ export function registerTestSideBySideEditor(): IDisposable { export class TestFileEditorInput extends EditorInput implements IFileEditorInput { - readonly preferredResource = this.resource; + readonly preferredResource: URI; gotDisposed = false; gotSaved = false; @@ -1745,6 +1750,8 @@ export class TestFileEditorInput extends EditorInput implements IFileEditorInput private _typeId: string ) { super(); + + this.preferredResource = this.resource; } override get typeId() { return this._typeId; } diff --git a/src/vs/workbench/test/common/workbenchTestServices.ts b/src/vs/workbench/test/common/workbenchTestServices.ts index ef7fce72b1e03..16a4842ac6192 100644 --- a/src/vs/workbench/test/common/workbenchTestServices.ts +++ b/src/vs/workbench/test/common/workbenchTestServices.ts @@ -181,13 +181,14 @@ export class TestWorkingCopy extends Disposable implements IWorkingCopy { readonly capabilities = WorkingCopyCapabilities.None; - readonly name = basename(this.resource); + readonly name: string; private dirty = false; constructor(readonly resource: URI, isDirty = false, readonly typeId = 'testWorkingCopyType') { super(); + this.name = basename(this.resource); this.dirty = isDirty; }