Improves observable logging experience (#215782)

This commit is contained in:
Henning Dieterichs 2024-06-16 20:22:39 +02:00 committed by GitHub
parent 937c8c0c94
commit 8dcd7945af
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 122 additions and 91 deletions

View File

@ -76,7 +76,7 @@ export function autorunWithStoreHandleChanges<TChangeSummary>(
{
owner: options.owner,
debugName: options.debugName,
debugReferenceFn: options.debugReferenceFn,
debugReferenceFn: options.debugReferenceFn ?? fn,
createEmptyChangeSummary: options.createEmptyChangeSummary,
handleChange: options.handleChange,
},

View File

@ -6,7 +6,7 @@
import { strictEquals, EqualityComparer } from 'vs/base/common/equals';
import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import { keepObserved, recomputeInitiallyAndOnChange } from 'vs/base/common/observable';
import { DebugNameData, Owner, getFunctionName } from 'vs/base/common/observableInternal/debugName';
import { DebugNameData, DebugOwner, getFunctionName } from 'vs/base/common/observableInternal/debugName';
import type { derivedOpts } from 'vs/base/common/observableInternal/derived';
import { getLogger } from 'vs/base/common/observableInternal/logging';
@ -201,9 +201,9 @@ export abstract class ConvenientObservable<T, TChange> implements IObservable<T,
/** @sealed */
public map<TNew>(fn: (value: T, reader: IReader) => TNew): IObservable<TNew>;
public map<TNew>(owner: Owner, fn: (value: T, reader: IReader) => TNew): IObservable<TNew>;
public map<TNew>(fnOrOwner: Owner | ((value: T, reader: IReader) => TNew), fnOrUndefined?: (value: T, reader: IReader) => TNew): IObservable<TNew> {
const owner = fnOrUndefined === undefined ? undefined : fnOrOwner as Owner;
public map<TNew>(owner: DebugOwner, fn: (value: T, reader: IReader) => TNew): IObservable<TNew>;
public map<TNew>(fnOrOwner: DebugOwner | ((value: T, reader: IReader) => TNew), fnOrUndefined?: (value: T, reader: IReader) => TNew): IObservable<TNew> {
const owner = fnOrUndefined === undefined ? undefined : fnOrOwner as DebugOwner;
const fn = fnOrUndefined === undefined ? fnOrOwner as (value: T, reader: IReader) => TNew : fnOrUndefined;
return _derived(

View File

@ -8,7 +8,7 @@ export interface IDebugNameData {
* The owner object of an observable.
* Used for debugging only, such as computing a name for the observable by iterating over the fields of the owner.
*/
readonly owner?: Owner | undefined;
readonly owner?: DebugOwner | undefined;
/**
* A string or function that returns a string that represents the name of the observable.
@ -25,7 +25,7 @@ export interface IDebugNameData {
export class DebugNameData {
constructor(
public readonly owner: Owner | undefined,
public readonly owner: DebugOwner | undefined,
public readonly debugNameSource: DebugNameSource | undefined,
public readonly referenceFn: Function | undefined,
) { }
@ -36,10 +36,10 @@ export class DebugNameData {
}
/**
* The owner object of an observable.
* The owning object of an observable.
* Is only used for debugging purposes, such as computing a name for the observable by iterating over the fields of the owner.
*/
export type Owner = object | undefined;
export type DebugOwner = object | undefined;
export type DebugNameSource = string | (() => string | undefined);
const countPerName = new Map<string, number>();

View File

@ -7,7 +7,7 @@ import { assertFn } from 'vs/base/common/assert';
import { EqualityComparer, strictEquals } from 'vs/base/common/equals';
import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import { BaseObservable, IChangeContext, IObservable, IObserver, IReader, ISettableObservable, ITransaction, _setDerivedOpts, } from 'vs/base/common/observableInternal/base';
import { DebugNameData, IDebugNameData, Owner } from 'vs/base/common/observableInternal/debugName';
import { DebugNameData, IDebugNameData, DebugOwner } from 'vs/base/common/observableInternal/debugName';
import { getLogger } from 'vs/base/common/observableInternal/logging';
/**
@ -17,8 +17,8 @@ import { getLogger } from 'vs/base/common/observableInternal/logging';
* {@link computeFn} should start with a JS Doc using `@description` to name the derived.
*/
export function derived<T>(computeFn: (reader: IReader) => T): IObservable<T>;
export function derived<T>(owner: Owner, computeFn: (reader: IReader) => T): IObservable<T>;
export function derived<T>(computeFnOrOwner: ((reader: IReader) => T) | Owner, computeFn?: ((reader: IReader) => T) | undefined): IObservable<T> {
export function derived<T>(owner: DebugOwner, computeFn: (reader: IReader) => T): IObservable<T>;
export function derived<T>(computeFnOrOwner: ((reader: IReader) => T) | DebugOwner, computeFn?: ((reader: IReader) => T) | undefined): IObservable<T> {
if (computeFn !== undefined) {
return new Derived(
new DebugNameData(computeFnOrOwner, undefined, computeFn),
@ -39,7 +39,7 @@ export function derived<T>(computeFnOrOwner: ((reader: IReader) => T) | Owner, c
);
}
export function derivedWithSetter<T>(owner: Owner | undefined, computeFn: (reader: IReader) => T, setter: (value: T, transaction: ITransaction | undefined) => void): ISettableObservable<T> {
export function derivedWithSetter<T>(owner: DebugOwner | undefined, computeFn: (reader: IReader) => T, setter: (value: T, transaction: ITransaction | undefined) => void): ISettableObservable<T> {
return new DerivedWithSetter(
new DebugNameData(owner, undefined, computeFn),
computeFn,
@ -105,7 +105,7 @@ export function derivedWithStore<T>(computeFn: (reader: IReader, store: Disposab
export function derivedWithStore<T>(owner: object, computeFn: (reader: IReader, store: DisposableStore) => T): IObservable<T>;
export function derivedWithStore<T>(computeFnOrOwner: ((reader: IReader, store: DisposableStore) => T) | object, computeFnOrUndefined?: ((reader: IReader, store: DisposableStore) => T)): IObservable<T> {
let computeFn: (reader: IReader, store: DisposableStore) => T;
let owner: Owner;
let owner: DebugOwner;
if (computeFnOrUndefined === undefined) {
computeFn = computeFnOrOwner as any;
owner = undefined;
@ -128,10 +128,10 @@ export function derivedWithStore<T>(computeFnOrOwner: ((reader: IReader, store:
}
export function derivedDisposable<T extends IDisposable | undefined>(computeFn: (reader: IReader) => T): IObservable<T>;
export function derivedDisposable<T extends IDisposable | undefined>(owner: Owner, computeFn: (reader: IReader) => T): IObservable<T>;
export function derivedDisposable<T extends IDisposable | undefined>(computeFnOrOwner: ((reader: IReader) => T) | Owner, computeFnOrUndefined?: ((reader: IReader) => T)): IObservable<T> {
export function derivedDisposable<T extends IDisposable | undefined>(owner: DebugOwner, computeFn: (reader: IReader) => T): IObservable<T>;
export function derivedDisposable<T extends IDisposable | undefined>(computeFnOrOwner: ((reader: IReader) => T) | DebugOwner, computeFnOrUndefined?: ((reader: IReader) => T)): IObservable<T> {
let computeFn: (reader: IReader) => T;
let owner: Owner;
let owner: DebugOwner;
if (computeFnOrUndefined === undefined) {
computeFn = computeFnOrOwner as any;
owner = undefined;

View File

@ -6,7 +6,7 @@ import { autorun } from 'vs/base/common/observableInternal/autorun';
import { IObservable, IReader, observableValue, transaction } from './base';
import { Derived, derived } from 'vs/base/common/observableInternal/derived';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { DebugNameData, Owner } from 'vs/base/common/observableInternal/debugName';
import { DebugNameData, DebugOwner } from 'vs/base/common/observableInternal/debugName';
import { strictEquals } from 'vs/base/common/equals';
import { CancellationError } from 'vs/base/common/errors';
@ -179,7 +179,7 @@ export function derivedWithCancellationToken<T>(computeFn: (reader: IReader, can
export function derivedWithCancellationToken<T>(owner: object, computeFn: (reader: IReader, cancellationToken: CancellationToken) => T): IObservable<T>;
export function derivedWithCancellationToken<T>(computeFnOrOwner: ((reader: IReader, cancellationToken: CancellationToken) => T) | object, computeFnOrUndefined?: ((reader: IReader, cancellationToken: CancellationToken) => T)): IObservable<T> {
let computeFn: (reader: IReader, store: CancellationToken) => T;
let owner: Owner;
let owner: DebugOwner;
if (computeFnOrUndefined === undefined) {
computeFn = computeFnOrOwner as any;
owner = undefined;

View File

@ -5,9 +5,9 @@
import { Event } from 'vs/base/common/event';
import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { autorun } from 'vs/base/common/observableInternal/autorun';
import { autorun, autorunOpts } from 'vs/base/common/observableInternal/autorun';
import { BaseObservable, ConvenientObservable, IObservable, IObserver, IReader, ITransaction, _setKeepObserved, _setRecomputeInitiallyAndOnChange, observableValue, subtransaction, transaction } from 'vs/base/common/observableInternal/base';
import { DebugNameData, Owner, getFunctionName } from 'vs/base/common/observableInternal/debugName';
import { DebugNameData, IDebugNameData, DebugOwner, getDebugName, } from 'vs/base/common/observableInternal/debugName';
import { derived, derivedOpts } from 'vs/base/common/observableInternal/derived';
import { getLogger } from 'vs/base/common/observableInternal/logging';
import { IValueWithChangeEvent } from '../event';
@ -54,21 +54,49 @@ export function observableFromPromise<T>(promise: Promise<T>): IObservable<{ val
return observable;
}
export function observableFromEvent<T, TArgs = unknown>(
owner: DebugOwner,
event: Event<TArgs>,
getValue: (args: TArgs | undefined) => T,
): IObservable<T>;
export function observableFromEvent<T, TArgs = unknown>(
event: Event<TArgs>,
getValue: (args: TArgs | undefined) => T,
): IObservable<T> {
return new FromEventObservable(event, getValue, () => FromEventObservable.globalTransaction, strictEquals);
): IObservable<T>;
export function observableFromEvent(...args:
[owner: DebugOwner, event: Event<any>, getValue: (args: any | undefined) => any]
| [event: Event<any>, getValue: (args: any | undefined) => any]
): IObservable<any> {
let owner;
let event;
let getValue;
if (args.length === 3) {
[owner, event, getValue] = args;
} else {
[event, getValue] = args;
}
return new FromEventObservable(
new DebugNameData(owner, undefined, getValue),
event,
getValue,
() => FromEventObservable.globalTransaction,
strictEquals
);
}
export function observableFromEventOpts<T, TArgs = unknown>(
options: {
options: IDebugNameData & {
equalsFn?: EqualityComparer<T>;
},
event: Event<TArgs>,
getValue: (args: TArgs | undefined) => T,
): IObservable<T> {
return new FromEventObservable(event, getValue, () => FromEventObservable.globalTransaction, options.equalsFn ?? strictEquals);
return new FromEventObservable(
new DebugNameData(options.owner, options.debugName, options.debugReferenceFn ?? getValue),
event,
getValue, () => FromEventObservable.globalTransaction, options.equalsFn ?? strictEquals
);
}
export class FromEventObservable<TArgs, T> extends BaseObservable<T> {
@ -79,6 +107,7 @@ export class FromEventObservable<TArgs, T> extends BaseObservable<T> {
private subscription: IDisposable | undefined;
constructor(
private readonly _debugNameData: DebugNameData,
private readonly event: Event<TArgs>,
public readonly _getValue: (args: TArgs | undefined) => T,
private readonly _getTransaction: () => ITransaction | undefined,
@ -88,7 +117,7 @@ export class FromEventObservable<TArgs, T> extends BaseObservable<T> {
}
private getDebugName(): string | undefined {
return getFunctionName(this._getValue);
return this._debugNameData.getDebugName(this);
}
public get debugName(): string {
@ -424,9 +453,9 @@ export class KeepAliveObserver implements IObserver {
}
}
export function derivedObservableWithCache<T>(owner: Owner, computeFn: (reader: IReader, lastValue: T | undefined) => T): IObservable<T> {
export function derivedObservableWithCache<T>(owner: DebugOwner, computeFn: (reader: IReader, lastValue: T | undefined) => T): IObservable<T> {
let lastValue: T | undefined = undefined;
const observable = derived(owner, reader => {
const observable = derivedOpts({ owner, debugReferenceFn: computeFn }, reader => {
lastValue = computeFn(reader, lastValue);
return lastValue;
});
@ -457,7 +486,7 @@ export function derivedObservableWithWritableCache<T>(owner: object, computeFn:
/**
* When the items array changes, referential equal items are not mapped again.
*/
export function mapObservableArrayCached<TIn, TOut, TKey = TIn>(owner: Owner, items: IObservable<readonly TIn[]>, map: (input: TIn, store: DisposableStore) => TOut, keySelector?: (input: TIn) => TKey): IObservable<readonly TOut[]> {
export function mapObservableArrayCached<TIn, TOut, TKey = TIn>(owner: DebugOwner, items: IObservable<readonly TIn[]>, map: (input: TIn, store: DisposableStore) => TOut, keySelector?: (input: TIn) => TKey): IObservable<readonly TOut[]> {
let m = new ArrayMap(map, keySelector);
const self = derivedOpts({
debugReferenceFn: map,
@ -533,11 +562,11 @@ export class ValueWithChangeEventFromObservable<T> implements IValueWithChangeEv
}
}
export function observableFromValueWithChangeEvent<T>(_owner: Owner, value: IValueWithChangeEvent<T>): IObservable<T> {
export function observableFromValueWithChangeEvent<T>(owner: DebugOwner, value: IValueWithChangeEvent<T>): IObservable<T> {
if (value instanceof ValueWithChangeEventFromObservable) {
return value.observable;
}
return observableFromEvent(value.onDidChange, () => value.value);
return observableFromEvent(owner, value.onDidChange, () => value.value);
}
/**
@ -546,7 +575,7 @@ export function observableFromValueWithChangeEvent<T>(_owner: Owner, value: IVal
* When observed and any of the observables change, it has the value of the last changed observable.
* If multiple observables change in the same transaction, the last observable wins.
*/
export function latestChangedValue<T extends IObservable<any>[]>(...observables: T): IObservable<ReturnType<T[number]['get']>> {
export function latestChangedValue<T extends IObservable<any>[]>(owner: DebugOwner, observables: T): IObservable<ReturnType<T[number]['get']>> {
if (observables.length === 0) {
throw new BugIndicatingError();
}
@ -554,10 +583,10 @@ export function latestChangedValue<T extends IObservable<any>[]>(...observables:
let hasLastChangedValue = false;
let lastChangedValue: any = undefined;
return observableFromEvent<any, void>(cb => {
const result = observableFromEvent<any, void>(owner, cb => {
const store = new DisposableStore();
for (const o of observables) {
store.add(autorun(reader => {
store.add(autorunOpts({ debugName: () => getDebugName(result, new DebugNameData(owner, undefined, undefined)) + '.updateLastChangedValue' }, reader => {
hasLastChangedValue = true;
lastChangedValue = o.read(reader);
cb();
@ -577,4 +606,5 @@ export function latestChangedValue<T extends IObservable<any>[]>(...observables:
return observables[observables.length - 1].get();
}
});
return result;
}

View File

@ -140,7 +140,7 @@ export class ObservableCodeEditor extends Disposable {
private readonly _model = observableValue(this, this.editor.getModel());
public readonly model: IObservable<ITextModel | null> = this._model;
public readonly isReadonly = observableFromEvent(this.editor.onDidChangeConfiguration, () => this.editor.getOption(EditorOption.readOnly));
public readonly isReadonly = observableFromEvent(this, this.editor.onDidChangeConfiguration, () => this.editor.getOption(EditorOption.readOnly));
private readonly _versionId = observableValueOpts<number | null, IModelContentChangedEvent | undefined>({ owner: this, lazy: true }, this.editor.getModel()?.getVersionId() ?? null);
public readonly versionId: IObservable<number | null, IModelContentChangedEvent | undefined> = this._versionId;
@ -157,7 +157,7 @@ export class ObservableCodeEditor extends Disposable {
reader => this.selections.read(reader)?.map(s => s.getStartPosition()) ?? null
);
public readonly isFocused = observableFromEvent(e => {
public readonly isFocused = observableFromEvent(this, e => {
const d1 = this.editor.onDidFocusEditorWidget(e);
const d2 = this.editor.onDidBlurEditorWidget(e);
return {
@ -175,7 +175,7 @@ export class ObservableCodeEditor extends Disposable {
public readonly onDidType = observableSignal<string>(this);
public getOption<T extends EditorOption>(id: T): IObservable<FindComputedEditorOptionValueById<T>> {
return observableFromEvent(cb => this.editor.onDidChangeConfiguration(e => {
return observableFromEvent(this, cb => this.editor.onDidChangeConfiguration(e => {
if (e.hasChanged(id)) { cb(undefined); }
}), () => this.editor.getOption(id));
}

View File

@ -27,15 +27,15 @@ export class DiffEditorEditors extends Disposable {
private readonly _onDidContentSizeChange = this._register(new Emitter<IContentSizeChangedEvent>());
public get onDidContentSizeChange() { return this._onDidContentSizeChange.event; }
public readonly modifiedScrollTop = observableFromEvent(this.modified.onDidScrollChange, () => /** @description modified.getScrollTop */ this.modified.getScrollTop());
public readonly modifiedScrollHeight = observableFromEvent(this.modified.onDidScrollChange, () => /** @description modified.getScrollHeight */ this.modified.getScrollHeight());
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 modifiedModel = observableCodeEditor(this.modified).model;
public readonly modifiedSelections = observableFromEvent(this.modified.onDidChangeCursorSelection, () => this.modified.getSelections() ?? []);
public readonly modifiedSelections = observableFromEvent(this, this.modified.onDidChangeCursorSelection, () => this.modified.getSelections() ?? []);
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.original.onDidChangeCursorPosition, () => this.original.getPosition() ?? new Position(1, 1));
public readonly originalCursor = observableFromEvent(this, this.original.onDidChangeCursorPosition, () => this.original.getPosition() ?? new Position(1, 1));
public readonly isOriginalFocused = observableCodeEditor(this.original).isFocused;
public readonly isModifiedFocused = observableCodeEditor(this.modified).isFocused;

View File

@ -81,7 +81,7 @@ export class DiffEditorViewZones extends Disposable {
}));
const originalModelTokenizationCompleted = this._diffModel.map(m =>
m ? observableFromEvent(m.model.original.onDidChangeTokens, () => m.model.original.tokenization.backgroundTokenizationState === BackgroundTokenizationState.Completed) : undefined
m ? observableFromEvent(this, m.model.original.onDidChangeTokens, () => m.model.original.tokenization.backgroundTokenizationState === BackgroundTokenizationState.Completed) : undefined
).map((m, reader) => m?.read(reader));
const alignments = derived<ILineRangeAlignment[] | null>((reader) => {

View File

@ -16,7 +16,7 @@ export class DiffEditorOptions {
private readonly _diffEditorWidth = observableValue<number>(this, 0);
private readonly _screenReaderMode = observableFromEvent(this._accessibilityService.onDidChangeScreenReaderOptimized, () => this._accessibilityService.isScreenReaderOptimized());
private readonly _screenReaderMode = observableFromEvent(this, this._accessibilityService.onDidChangeScreenReaderOptimized, () => this._accessibilityService.isScreenReaderOptimized());
constructor(
options: Readonly<IDiffEditorOptions>,

View File

@ -37,7 +37,7 @@ 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._menu.onDidChange, () => this._menu.getActions());
private readonly _actions = observableFromEvent(this, this._menu.onDidChange, () => this._menu.getActions());
private readonly _hasActions = this._actions.map(a => a.length > 0);
private readonly _showSash = derived(this, reader => this._options.renderSideBySide.read(reader) && this._hasActions.read(reader));

View File

@ -26,8 +26,8 @@ export class MovedBlocksLinesFeature extends Disposable {
public static readonly movedCodeBlockPadding = 4;
private readonly _element: SVGElement;
private readonly _originalScrollTop = observableFromEvent(this._editors.original.onDidScrollChange, () => this._editors.original.getScrollTop());
private readonly _modifiedScrollTop = observableFromEvent(this._editors.modified.onDidScrollChange, () => this._editors.modified.getScrollTop());
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);
public readonly width = observableValue(this, 0);

View File

@ -11,12 +11,12 @@ import { LineRange } from 'vs/editor/common/core/lineRange';
import { OffsetRange } from 'vs/editor/common/core/offsetRange';
export class EditorGutter<T extends IGutterItemInfo = IGutterItemInfo> extends Disposable {
private readonly scrollTop = observableFromEvent(
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(
private readonly modelAttached = observableFromEvent(this,
this._editor.onDidChangeModel,
(e) => /** @description editor.onDidChangeModel */ this._editor.hasModel()
);

View File

@ -73,8 +73,8 @@ export class MultiDiffEditorWidgetImpl extends Disposable {
return template;
}));
public readonly scrollTop = observableFromEvent(this._scrollableElement.onScroll, () => /** @description scrollTop */ this._scrollableElement.getScrollPosition().scrollTop);
public readonly scrollLeft = observableFromEvent(this._scrollableElement.onScroll, () => /** @description scrollLeft */ this._scrollableElement.getScrollPosition().scrollLeft);
public readonly scrollTop = observableFromEvent(this, this._scrollableElement.onScroll, () => /** @description scrollTop */ this._scrollableElement.getScrollPosition().scrollTop);
public readonly scrollLeft = observableFromEvent(this, this._scrollableElement.onScroll, () => /** @description scrollLeft */ this._scrollableElement.getScrollPosition().scrollLeft);
private readonly _viewItemsInfo = derivedWithStore<{ items: readonly VirtualizedViewItem[]; getItem: (viewModel: DocumentDiffItemViewModel) => VirtualizedViewItem }>(this,
(reader, store) => {

View File

@ -34,7 +34,7 @@ export interface IGhostTextWidgetModel {
export class GhostTextWidget extends Disposable {
private readonly isDisposed = observableValue(this, false);
private readonly currentTextModel = observableFromEvent(this.editor.onDidChangeModel, () => /** @description editor.model */ this.editor.getModel());
private readonly currentTextModel = observableFromEvent(this, this.editor.onDidChangeModel, () => /** @description editor.model */ this.editor.getModel());
constructor(
private readonly editor: ICodeEditor,

View File

@ -59,14 +59,14 @@ export class InlineCompletionsController extends Disposable {
})
));
private readonly _suggestWidgetSelectedItem = observableFromEvent(cb => this._suggestWidgetAdaptor.onDidSelectedItemChange(() => {
private readonly _suggestWidgetSelectedItem = observableFromEvent(this, cb => this._suggestWidgetAdaptor.onDidSelectedItemChange(() => {
this._editorObs.forceUpdate(_tx => cb(undefined));
}), () => this._suggestWidgetAdaptor.selectedItem);
private readonly _enabledInConfig = observableFromEvent(this.editor.onDidChangeConfiguration, () => this.editor.getOption(EditorOption.inlineSuggest).enabled);
private readonly _isScreenReaderEnabled = observableFromEvent(this._accessibilityService.onDidChangeScreenReaderOptimized, () => this._accessibilityService.isScreenReaderOptimized());
private readonly _editorDictationInProgress = observableFromEvent(
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
);
@ -114,7 +114,7 @@ export class InlineCompletionsController extends Disposable {
private readonly _playAccessibilitySignal = observableSignal(this);
private readonly _fontFamily = observableFromEvent(this.editor.onDidChangeConfiguration, () => this.editor.getOption(EditorOption.inlineSuggest).fontFamily);
private readonly _fontFamily = observableFromEvent(this, this.editor.onDidChangeConfiguration, () => this.editor.getOption(EditorOption.inlineSuggest).fontFamily);
constructor(
public readonly editor: ICodeEditor,

View File

@ -36,7 +36,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
export class InlineCompletionsHintsWidget extends Disposable {
private readonly alwaysShowToolbar = observableFromEvent(this.editor.onDidChangeConfiguration, () => this.editor.getOption(EditorOption.inlineSuggest).showToolbar === 'always');
private readonly alwaysShowToolbar = observableFromEvent(this, this.editor.onDidChangeConfiguration, () => this.editor.getOption(EditorOption.inlineSuggest).showToolbar === 'always');
private sessionPosition: Position | undefined = undefined;

View File

@ -28,7 +28,7 @@ export interface IGhostTextWidgetModel {
export class GhostTextWidget extends Disposable {
private readonly isDisposed = observableValue(this, false);
private readonly currentTextModel = observableFromEvent(this.editor.onDidChangeModel, () => /** @description editor.model */ this.editor.getModel());
private readonly currentTextModel = observableFromEvent(this, this.editor.onDidChangeModel, () => /** @description editor.model */ this.editor.getModel());
constructor(
private readonly editor: ICodeEditor,

View File

@ -52,9 +52,9 @@ export class InlineEditController extends Disposable {
private _jumpBackPosition: Position | undefined;
private _isAccepting: ISettableObservable<boolean> = observableValue(this, false);
private readonly _enabled = observableFromEvent(this.editor.onDidChangeConfiguration, () => this.editor.getOption(EditorOption.inlineEdit).enabled);
private readonly _fontFamily = observableFromEvent(this.editor.onDidChangeConfiguration, () => this.editor.getOption(EditorOption.inlineEdit).fontFamily);
private readonly _backgroundColoring = observableFromEvent(this.editor.onDidChangeConfiguration, () => this.editor.getOption(EditorOption.inlineEdit).backgroundColoring);
private readonly _enabled = observableFromEvent(this, this.editor.onDidChangeConfiguration, () => this.editor.getOption(EditorOption.inlineEdit).enabled);
private readonly _fontFamily = observableFromEvent(this, this.editor.onDidChangeConfiguration, () => this.editor.getOption(EditorOption.inlineEdit).fontFamily);
private readonly _backgroundColoring = observableFromEvent(this, this.editor.onDidChangeConfiguration, () => this.editor.getOption(EditorOption.inlineEdit).backgroundColoring);
constructor(
@ -84,7 +84,7 @@ export class InlineEditController extends Disposable {
}));
//Check if the cursor is at the ghost text
const cursorPosition = observableFromEvent(editor.onDidChangeCursorPosition, () => editor.getPosition());
const cursorPosition = observableFromEvent(this, editor.onDidChangeCursorPosition, () => editor.getPosition());
this._register(autorun(reader => {
/** @description InlineEditController.cursorPositionChanged model */
if (!this._enabled.read(reader)) {

View File

@ -27,7 +27,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
export class InlineEditHintsWidget extends Disposable {
private readonly alwaysShowToolbar = observableFromEvent(this.editor.onDidChangeConfiguration, () => this.editor.getOption(EditorOption.inlineEdit).showToolbar === 'always');
private readonly alwaysShowToolbar = observableFromEvent(this, this.editor.onDidChangeConfiguration, () => this.editor.getOption(EditorOption.inlineEdit).showToolbar === 'always');
private sessionPosition: Position | undefined = undefined;

View File

@ -67,7 +67,7 @@ export interface IAccessbilitySignalOptions {
export class AccessibilitySignalService extends Disposable implements IAccessibilitySignalService {
readonly _serviceBrand: undefined;
private readonly sounds: Map<string, HTMLAudioElement> = new Map();
private readonly screenReaderAttached = observableFromEvent(
private readonly screenReaderAttached = observableFromEvent(this,
this.accessibilityService.onDidChangeScreenReaderOptimized,
() => /** @description accessibilityService.onDidChangeScreenReaderOptimized */ this.accessibilityService.isScreenReaderOptimized()
);

View File

@ -4,13 +4,14 @@
*--------------------------------------------------------------------------------------------*/
import { IDisposable } from 'vs/base/common/lifecycle';
import { autorunOpts, IObservable, IReader, observableFromEvent } from 'vs/base/common/observable';
import { autorunOpts, IObservable, IReader } from 'vs/base/common/observable';
import { observableFromEventOpts } from 'vs/base/common/observableInternal/utils';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ContextKeyValue, RawContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { ContextKeyValue, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
/** Creates an observable update when a configuration key updates. */
export function observableConfigValue<T>(key: string, defaultValue: T, configurationService: IConfigurationService): IObservable<T> {
return observableFromEvent(
return observableFromEventOpts({ debugName: () => `Configuration Key "${key}"`, },
(handleChange) => configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(key)) {
handleChange(e);

View File

@ -19,7 +19,7 @@ export class AccessibilitySignalLineDebuggerContribution
) {
super();
const isEnabled = observableFromEvent(
const isEnabled = observableFromEvent(this,
accessibilitySignalService.onSoundEnabledChanged(AccessibilitySignal.onDebugBreak),
() => accessibilitySignalService.isSoundEnabled(AccessibilitySignal.onDebugBreak)
);

View File

@ -35,7 +35,7 @@ export class EditorTextPropertySignalsContribution extends Disposable implements
.some(signal => observableFromValueWithChangeEvent(this, this._accessibilitySignalService.getEnabledState(signal, false)).read(reader))
);
private readonly _activeEditorObservable = observableFromEvent(
private readonly _activeEditorObservable = observableFromEvent(this,
this._editorService.onDidActiveEditorChange,
(_) => {
const activeTextEditorControl = this._editorService.activeTextEditorControl;

View File

@ -33,7 +33,7 @@ class DiffEditorHelperContribution extends Disposable implements IDiffEditorCont
const isEmbeddedDiffEditor = this._diffEditor instanceof EmbeddedDiffEditorWidget;
if (!isEmbeddedDiffEditor) {
const computationResult = observableFromEvent(e => this._diffEditor.onDidUpdateDiff(e), () => /** @description diffEditor.diffComputationResult */ this._diffEditor.getDiffComputationResult());
const computationResult = observableFromEvent(this, e => this._diffEditor.onDidUpdateDiff(e), () => /** @description diffEditor.diffComputationResult */ this._diffEditor.getDiffComputationResult());
const onlyWhiteSpaceChange = computationResult.map(r => r && !r.identical && r.changes2.length === 0);
this._register(autorunWithStore((reader, store) => {

View File

@ -126,7 +126,7 @@ export class TempFileMergeEditorModeFactory implements IMergeEditorInputModelFac
class TempFileMergeEditorInputModel extends EditorModel implements IMergeEditorInputModel {
private readonly savedAltVersionId = observableValue(this, this.model.resultTextModel.getAlternativeVersionId());
private readonly altVersionId = observableFromEvent(
private readonly altVersionId = observableFromEvent(this,
e => this.model.resultTextModel.onDidChangeContent(e),
() =>
/** @description getAlternativeVersionId */ this.model.resultTextModel.getAlternativeVersionId()
@ -340,7 +340,7 @@ export class WorkspaceMergeEditorModeFactory implements IMergeEditorInputModelFa
}
class WorkspaceMergeEditorInputModel extends EditorModel implements IMergeEditorInputModel {
public readonly isDirty = observableFromEvent(
public readonly isDirty = observableFromEvent(this,
Event.any(this.resultTextFileModel.onDidChangeDirty, this.resultTextFileModel.onDidSaveError),
() => /** @description isDirty */ this.resultTextFileModel.isDirty()
);

View File

@ -10,12 +10,12 @@ import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditor/codeEditor
import { LineRange } from 'vs/workbench/contrib/mergeEditor/browser/model/lineRange';
export class EditorGutter<T extends IGutterItemInfo = IGutterItemInfo> extends Disposable {
private readonly scrollTop = observableFromEvent(
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(
private readonly modelAttached = observableFromEvent(this,
this._editor.onDidChangeModel,
(e) => /** @description editor.onDidChangeModel */ this._editor.hasModel()
);

View File

@ -79,17 +79,17 @@ export abstract class CodeEditorView extends Disposable {
this.editor.updateOptions(newOptions);
}
public readonly isFocused = observableFromEvent(
public readonly isFocused = observableFromEvent(this,
Event.any(this.editor.onDidBlurEditorWidget, this.editor.onDidFocusEditorWidget),
() => /** @description editor.hasWidgetFocus */ this.editor.hasWidgetFocus()
);
public readonly cursorPosition = observableFromEvent(
public readonly cursorPosition = observableFromEvent(this,
this.editor.onDidChangeCursorPosition,
() => /** @description editor.getPosition */ this.editor.getPosition()
);
public readonly selection = observableFromEvent(
public readonly selection = observableFromEvent(this,
this.editor.onDidChangeCursorSelection,
() => /** @description editor.getSelections */ this.editor.getSelections()
);

View File

@ -61,11 +61,11 @@ export class ScmMultiDiffSourceResolver implements IMultiDiffSourceResolver {
async resolveDiffSource(uri: URI): Promise<IResolvedMultiDiffSource> {
const { repositoryUri, groupId } = ScmMultiDiffSourceResolver.parseUri(uri)!;
const repository = await waitForState(observableFromEvent(
const repository = await waitForState(observableFromEvent(this,
this._scmService.onDidAddRepository,
() => [...this._scmService.repositories].find(r => r.provider.rootUri?.toString() === repositoryUri.toString()))
);
const group = await waitForState(observableFromEvent(
const group = await waitForState(observableFromEvent(this,
repository.provider.onDidChangeResourceGroups,
() => repository.provider.groups.find(g => g.id === groupId)
));

View File

@ -46,7 +46,7 @@ export class NotebookAccessibilityProvider extends Disposable implements IListAc
getAriaLabel(element: CellViewModel) {
const event = Event.filter(this.onDidAriaLabelChange, e => e === element);
return observableFromEvent(event, () => {
return observableFromEvent(this, event, () => {
const viewModel = this.viewModel();
if (!viewModel) {
return '';

View File

@ -33,17 +33,17 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
export class SCMActiveRepositoryController extends Disposable implements IWorkbenchContribution {
private readonly _countBadgeConfig = observableConfigValue<'all' | 'focused' | 'off'>('scm.countBadge', 'all', this.configurationService);
private readonly _repositories = observableFromEvent(
private readonly _repositories = observableFromEvent(this,
Event.any(this.scmService.onDidAddRepository, this.scmService.onDidRemoveRepository),
() => this.scmService.repositories);
private readonly _focusedRepository = observableFromEventOpts<ISCMRepository | undefined>(
{ equalsFn: () => false },
{ owner: this, equalsFn: () => false },
this.scmViewService.onDidFocusRepository,
() => this.scmViewService.focusedRepository);
private readonly _activeEditor = observableFromEventOpts(
{ equalsFn: () => false },
{ owner: this, equalsFn: () => false },
this.editorService.onDidActiveEditorChange,
() => this.editorService.activeEditor);
@ -71,9 +71,9 @@ export class SCMActiveRepositoryController extends Disposable implements IWorkbe
* The focused repository takes precedence over the active editor repository when the observable
* values are updated in the same transaction (or during the initial read of the observable value).
*/
private readonly _activeRepository = latestChangedValue(this._activeEditorRepository, this._focusedRepository);
private readonly _activeRepository = latestChangedValue(this, [this._activeEditorRepository, this._focusedRepository]);
private readonly _countBadgeRepositories = derived(reader => {
private readonly _countBadgeRepositories = derived(this, reader => {
switch (this._countBadgeConfig.read(reader)) {
case 'all': {
const repositories = this._repositories.read(reader);
@ -90,7 +90,7 @@ export class SCMActiveRepositoryController extends Disposable implements IWorkbe
}
});
private readonly _countBadge = derived(reader => {
private readonly _countBadge = derived(this, reader => {
let total = 0;
for (const repository of this._countBadgeRepositories.read(reader)) {
@ -171,7 +171,7 @@ export class SCMActiveRepositoryController extends Disposable implements IWorkbe
}
private _getRepositoryResourceCount(repository: ISCMRepository): IObservable<number> {
return observableFromEvent(repository.provider.onDidChangeResources, () => getRepositoryResourceCount(repository.provider));
return observableFromEvent(this, repository.provider.onDidChangeResources, () => /** @description repositoryResourceCount */ getRepositoryResourceCount(repository.provider));
}
private _updateActivityCountBadge(count: number, store: DisposableStore): void {

View File

@ -81,8 +81,8 @@ export class CodeCoverageDecorations extends Disposable implements IEditorContri
this.summaryWidget = new Lazy(() => this._register(instantiationService.createInstance(CoverageToolbarWidget, this.editor)));
const modelObs = observableFromEvent(editor.onDidChangeModel, () => editor.getModel());
const configObs = observableFromEvent(editor.onDidChangeConfiguration, i => i);
const modelObs = observableFromEvent(this, editor.onDidChangeModel, () => editor.getModel());
const configObs = observableFromEvent(this, editor.onDidChangeConfiguration, i => i);
const fileCoverage = derived(reader => {
const report = coverage.selected.read(reader);

View File

@ -821,12 +821,12 @@ class TestingExplorerViewModel extends Disposable {
this.tree.rerender();
}));
const allOpenEditorInputs = observableFromEvent(
const allOpenEditorInputs = observableFromEvent(this,
editorService.onDidEditorsChange,
() => new Set(editorGroupsService.groups.flatMap(g => g.editors).map(e => e.resource).filter(isDefined)),
);
const activeResource = observableFromEvent(editorService.onDidActiveEditorChange, () => {
const activeResource = observableFromEvent(this, editorService.onDidActiveEditorChange, () => {
if (editorService.activeEditor instanceof DiffEditorInput) {
return editorService.activeEditor.primary.resource;
} else {