-
Notifications
You must be signed in to change notification settings - Fork 29.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cache outline headers & ref count outline provider #210213
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,20 +4,21 @@ | |
*--------------------------------------------------------------------------------------------*/ | ||
|
||
import { Emitter, Event } from 'vs/base/common/event'; | ||
import { DisposableStore, MutableDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; | ||
import { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; | ||
import { isEqual } from 'vs/base/common/resources'; | ||
import { URI } from 'vs/base/common/uri'; | ||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; | ||
import { IMarkerService } from 'vs/platform/markers/common/markers'; | ||
import { IThemeService } from 'vs/platform/theme/common/themeService'; | ||
import { IActiveNotebookEditor, ICellViewModel, INotebookEditor, INotebookViewCellsUpdateEvent } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; | ||
import { CellKind, NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon'; | ||
import { INotebookExecutionStateService, NotebookExecutionType, type ICellExecutionStateChangedEvent, type IExecutionStateChangedEvent } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService'; | ||
import { IActiveNotebookEditor, ICellViewModel, INotebookEditor, type INotebookViewCellsUpdateEvent } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; | ||
import { CellKind, NotebookCellsChangeType, NotebookSetting } from 'vs/workbench/contrib/notebook/common/notebookCommon'; | ||
import { INotebookExecutionStateService, NotebookExecutionType } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService'; | ||
import { OutlineChangeEvent, OutlineConfigKeys, OutlineTarget } from 'vs/workbench/services/outline/browser/outline'; | ||
import { OutlineEntry } from './OutlineEntry'; | ||
import { IOutlineModelService } from 'vs/editor/contrib/documentSymbols/browser/outlineModel'; | ||
import { CancellationToken } from 'vs/base/common/cancellation'; | ||
import { NotebookOutlineConstants, NotebookOutlineEntryFactory } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookOutlineEntryFactory'; | ||
import { Delayer } from 'vs/base/common/async'; | ||
|
||
export class NotebookCellOutlineProvider { | ||
private readonly _disposables = new DisposableStore(); | ||
|
@@ -41,7 +42,6 @@ export class NotebookCellOutlineProvider { | |
} | ||
|
||
private readonly _outlineEntryFactory: NotebookOutlineEntryFactory; | ||
|
||
constructor( | ||
private readonly _editor: INotebookEditor, | ||
private readonly _target: OutlineTarget, | ||
|
@@ -53,29 +53,34 @@ export class NotebookCellOutlineProvider { | |
) { | ||
this._outlineEntryFactory = new NotebookOutlineEntryFactory(notebookExecutionStateService); | ||
|
||
const selectionListener = new MutableDisposable(); | ||
this._disposables.add(selectionListener); | ||
|
||
selectionListener.value = combinedDisposable( | ||
Event.debounce<void, void>( | ||
_editor.onDidChangeSelection, | ||
(last, _current) => last, | ||
200 | ||
)(this._recomputeActive, this), | ||
Event.debounce<INotebookViewCellsUpdateEvent, INotebookViewCellsUpdateEvent>( | ||
_editor.onDidChangeViewCells, | ||
(last, _current) => last ?? _current, | ||
200 | ||
)(this._recomputeState, this) | ||
this._disposables.add(Event.debounce<void, void>( | ||
_editor.onDidChangeSelection, | ||
(last, _current) => last, | ||
200 | ||
)(() => { | ||
this._recomputeActive(); | ||
}, this)) | ||
this._disposables.add(Event.debounce<INotebookViewCellsUpdateEvent, INotebookViewCellsUpdateEvent>( | ||
_editor.onDidChangeViewCells, | ||
(last, _current) => last ?? _current, | ||
200 | ||
)(() => { | ||
this._recomputeActive(); | ||
}, this) | ||
); | ||
|
||
// .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. | ||
const delayer = this._disposables.add(new Delayer<void>(300)); | ||
const delayedRecompute = () => delayer.trigger(() => this._recomputeState()); | ||
|
||
this._disposables.add(_configurationService.onDidChangeConfiguration(e => { | ||
if (e.affectsConfiguration(NotebookSetting.outlineShowMarkdownHeadersOnly) || | ||
e.affectsConfiguration(NotebookSetting.outlineShowCodeCells) || | ||
e.affectsConfiguration(NotebookSetting.outlineShowCodeCellSymbols) || | ||
e.affectsConfiguration(NotebookSetting.breadcrumbsShowCodeCells) | ||
) { | ||
this._recomputeState(); | ||
delayedRecompute(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Debouncing in outline provider resulted in significant improvements When ever we make changes in editor (typing), we trigger outline changes synchronously Thus every key stroke results in a 50ms delay in renderer. |
||
} | ||
})); | ||
|
||
|
@@ -84,17 +89,28 @@ export class NotebookCellOutlineProvider { | |
})); | ||
|
||
this._disposables.add( | ||
Event.debounce<ICellExecutionStateChangedEvent | IExecutionStateChangedEvent>( | ||
notebookExecutionStateService.onDidChangeExecution, | ||
(last, _current) => last ?? _current, | ||
200)(e => { | ||
if (e.type === NotebookExecutionType.cell && !!this._editor.textModel && e.affectsNotebook(this._editor.textModel?.uri)) { | ||
this._recomputeState(); | ||
} | ||
}) | ||
notebookExecutionStateService.onDidChangeExecution(e => { | ||
if (e.type === NotebookExecutionType.cell && !!this._editor.textModel && e.affectsNotebook(this._editor.textModel?.uri)) { | ||
delayedRecompute(); | ||
} | ||
}) | ||
); | ||
|
||
this._recomputeState(); | ||
const disposable = this._disposables.add(new DisposableStore()); | ||
const monitorModelChanges = () => { | ||
disposable.clear(); | ||
if (!this._editor.textModel) { | ||
return; | ||
} | ||
disposable.add(this._editor.textModel.onDidChangeContent(contentChanges => { | ||
if (contentChanges.rawEvents.some(c => c.kind === NotebookCellsChangeType.ChangeCellContent)) { | ||
delayedRecompute(); | ||
} | ||
})); | ||
} | ||
this._disposables.add(this._editor.onDidChangeModel(monitorModelChanges)); | ||
monitorModelChanges(); | ||
this._recomputeState() | ||
} | ||
|
||
dispose(): void { | ||
|
@@ -104,10 +120,6 @@ export class NotebookCellOutlineProvider { | |
this._disposables.dispose(); | ||
} | ||
|
||
init(): void { | ||
this._recomputeState(); | ||
} | ||
|
||
async setFullSymbols(cancelToken: CancellationToken) { | ||
const notebookEditorWidget = this._editor; | ||
|
||
|
@@ -126,8 +138,9 @@ export class NotebookCellOutlineProvider { | |
|
||
this._recomputeState(); | ||
} | ||
|
||
private handle = 0; | ||
private _recomputeState(): void { | ||
this.handle = this.handle + 1; | ||
this._entriesDisposables.clear(); | ||
this._activeEntry = undefined; | ||
this._uri = undefined; | ||
|
@@ -159,11 +172,6 @@ export class NotebookCellOutlineProvider { | |
const entries: OutlineEntry[] = []; | ||
for (const cell of notebookCells) { | ||
entries.push(...this._outlineEntryFactory.getOutlineEntries(cell, this._target, entries.length)); | ||
// send an event whenever any of the cells change | ||
this._entriesDisposables.add(cell.model.onDidChangeContent(() => { | ||
this._recomputeState(); | ||
this._onDidChange.fire({}); | ||
})); | ||
} | ||
|
||
// build a tree from the list of entries | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This caching results in saving 50% of the time used to calculate outlines.
Down from 50ms to 26
I.e. this PR brings down the total time in keystokes from 150ms to 0 (when debounced) and when user stops typing, then we spend 20ms.
We should see some significant perf gains here.