Handle model changes when updating nb outline (#211205)

* Handle model changes when updating nb outline

* More fixes
This commit is contained in:
Don Jayamanne 2024-04-24 15:49:59 +10:00 committed by GitHub
parent 6d23b7f11a
commit a4784887a7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -10,7 +10,7 @@ import { URI } from 'vs/base/common/uri';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IMarkerService } from 'vs/platform/markers/common/markers'; import { IMarkerService } from 'vs/platform/markers/common/markers';
import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IActiveNotebookEditor, ICellViewModel, INotebookEditor, type INotebookViewCellsUpdateEvent } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { IActiveNotebookEditor, ICellViewModel, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellKind, NotebookCellsChangeType, NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { CellKind, NotebookCellsChangeType, NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookExecutionStateService, NotebookExecutionType } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService'; import { INotebookExecutionStateService, NotebookExecutionType } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
import { OutlineChangeEvent, OutlineConfigKeys, OutlineTarget } from 'vs/workbench/services/outline/browser/outline'; import { OutlineChangeEvent, OutlineConfigKeys, OutlineTarget } from 'vs/workbench/services/outline/browser/outline';
@ -29,6 +29,10 @@ export class NotebookCellOutlineProvider {
private _uri: URI | undefined; private _uri: URI | undefined;
private _entries: OutlineEntry[] = []; private _entries: OutlineEntry[] = [];
get entries(): OutlineEntry[] { get entries(): OutlineEntry[] {
if (this.delayedOutlineRecompute.isTriggered()) {
this.delayedOutlineRecompute.cancel();
this._recomputeState();
}
return this._entries; return this._entries;
} }
@ -38,11 +42,15 @@ export class NotebookCellOutlineProvider {
readonly outlineKind = 'notebookCells'; readonly outlineKind = 'notebookCells';
get activeElement(): OutlineEntry | undefined { get activeElement(): OutlineEntry | undefined {
if (this.delayedOutlineRecompute.isTriggered()) {
this.delayedOutlineRecompute.cancel();
this._recomputeState();
}
return this._activeEntry; return this._activeEntry;
} }
private readonly _outlineEntryFactory: NotebookOutlineEntryFactory; private readonly _outlineEntryFactory: NotebookOutlineEntryFactory;
private readonly delayRecomputeActive: () => void; private readonly delayedOutlineRecompute: Delayer<void>;;
constructor( constructor(
private readonly _editor: INotebookEditor, private readonly _editor: INotebookEditor,
private readonly _target: OutlineTarget, private readonly _target: OutlineTarget,
@ -53,29 +61,19 @@ export class NotebookCellOutlineProvider {
@IConfigurationService private readonly _configurationService: IConfigurationService, @IConfigurationService private readonly _configurationService: IConfigurationService,
) { ) {
this._outlineEntryFactory = new NotebookOutlineEntryFactory(notebookExecutionStateService); this._outlineEntryFactory = new NotebookOutlineEntryFactory(notebookExecutionStateService);
const delayerRecomputeActive = this._disposables.add(new Delayer(10));
this.delayRecomputeActive = () => delayerRecomputeActive.trigger(() => this._recomputeActive());
this._disposables.add(Event.debounce<void, void>( const delayerRecomputeActive = this._disposables.add(new Delayer(200));
_editor.onDidChangeSelection, this._disposables.add(_editor.onDidChangeSelection(() => {
(last, _current) => last, delayerRecomputeActive.trigger(() => this._recomputeActive());
200
)(() => {
this.delayRecomputeActive();
}, this)) }, this))
this._disposables.add(Event.debounce<INotebookViewCellsUpdateEvent, INotebookViewCellsUpdateEvent>(
_editor.onDidChangeViewCells,
(last, _current) => last ?? _current,
200
)(() => {
this.delayRecomputeActive();
}, this)
);
// .3s of a delay is sufficient, 100-200s is too quick and will unnecessarily block the ui thread. // .3s of a delay is sufficient, 100-200s is too quick and will unnecessarily block the ui thread.
// Given we're only updating the outline when the user types, we can afford to wait a bit. // Given we're only updating the outline when the user types, we can afford to wait a bit.
const delayer = this._disposables.add(new Delayer<void>(300)); this.delayedOutlineRecompute = this._disposables.add(new Delayer<void>(300));
const delayedRecompute = () => delayer.trigger(() => this._recomputeState()); const delayedRecompute = () => {
delayerRecomputeActive.cancel(); // Active is always recomputed after a recomputing the outline state.
this.delayedOutlineRecompute.trigger(() => this._recomputeState());
};
this._disposables.add(_configurationService.onDidChangeConfiguration(e => { this._disposables.add(_configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(NotebookSetting.outlineShowMarkdownHeadersOnly) || if (e.affectsConfiguration(NotebookSetting.outlineShowMarkdownHeadersOnly) ||
@ -106,7 +104,10 @@ export class NotebookCellOutlineProvider {
return; return;
} }
disposable.add(this._editor.textModel.onDidChangeContent(contentChanges => { disposable.add(this._editor.textModel.onDidChangeContent(contentChanges => {
if (contentChanges.rawEvents.some(c => c.kind === NotebookCellsChangeType.ChangeCellContent)) { if (contentChanges.rawEvents.some(c => c.kind === NotebookCellsChangeType.ChangeCellContent ||
c.kind === NotebookCellsChangeType.ChangeCellInternalMetadata ||
c.kind === NotebookCellsChangeType.Move ||
c.kind === NotebookCellsChangeType.ModelChange)) {
delayedRecompute(); delayedRecompute();
} }
})); }));
@ -259,7 +260,7 @@ export class NotebookCellOutlineProvider {
} }
})); }));
this.delayRecomputeActive(); this._recomputeActive();
} }
private _recomputeActive(): { changeEventTriggered: boolean } { private _recomputeActive(): { changeEventTriggered: boolean } {