Skip to content

Commit f3b1ddb

Browse files
authored
Merge pull request microsoft#163836 from microsoft/tyriar/161622_editorStatus
Defer editorStatus model content and cursor position updates
2 parents 9739b76 + 9457f9a commit f3b1ddb

File tree

2 files changed

+41
-6
lines changed

2 files changed

+41
-6
lines changed

src/vs/base/common/event.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,39 @@ export namespace Event {
5353
}
5454
}
5555

56+
/**
57+
* Given an event, returns another event which debounces calls and defers the listeners to a later task via a shared
58+
* `setTimeout`. The event is converted into a signal (`Event<void>`) to avoid additional object creation as a
59+
* result of merging events and to try prevent race conditions that could arise when using related deferred and
60+
* non-deferred events.
61+
*
62+
* This is useful for deferring non-critical work (eg. general UI updates) to ensure it does not block critical work
63+
* (eg. latency of keypress to text rendered).
64+
*
65+
* *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
66+
* event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
67+
* returned event causes this utility to leak a listener on the original event.
68+
*/
69+
export function defer(event: Event<unknown>, disposable?: DisposableStore): Event<void> {
70+
return debounce<unknown, void>(event, () => void 0, 0, undefined, undefined, disposable);
71+
}
72+
73+
/**
74+
* Debounces an event, firing after some delay (default=0) with an array of all event original objects.
75+
*
76+
* *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned
77+
* event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the
78+
* returned event causes this utility to leak a listener on the original event.
79+
*/
80+
export function accumulate<T>(event: Event<T>, delay: number = 0, disposable?: DisposableStore): Event<T[]> {
81+
return Event.debounce<T, T[]>(event, (last, e) => {
82+
if (!last) {
83+
return [e];
84+
}
85+
last.push(e);
86+
return last;
87+
}, delay, undefined, undefined, disposable);
88+
}
5689

5790
/**
5891
* Given an event, returns another event which only fires once.

src/vs/workbench/browser/parts/editor/editorStatus.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -671,7 +671,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
671671
}));
672672

673673
// Hook Listener for Selection changes
674-
this.activeEditorListeners.add(activeCodeEditor.onDidChangeCursorPosition(() => {
674+
this.activeEditorListeners.add(Event.defer(activeCodeEditor.onDidChangeCursorPosition)(() => {
675675
this.onSelectionChange(activeCodeEditor);
676676
this.currentProblemStatus.update(activeCodeEditor);
677677
}));
@@ -682,16 +682,18 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
682682
}));
683683

684684
// Hook Listener for content changes
685-
this.activeEditorListeners.add(activeCodeEditor.onDidChangeModelContent(e => {
685+
this.activeEditorListeners.add(Event.accumulate(activeCodeEditor.onDidChangeModelContent)(e => {
686686
this.onEOLChange(activeCodeEditor);
687687
this.currentProblemStatus.update(activeCodeEditor);
688688

689689
const selections = activeCodeEditor.getSelections();
690690
if (selections) {
691-
for (const change of e.changes) {
692-
if (selections.some(selection => Range.areIntersecting(selection, change.range))) {
693-
this.onSelectionChange(activeCodeEditor);
694-
break;
691+
for (const inner of e) {
692+
for (const change of inner.changes) {
693+
if (selections.some(selection => Range.areIntersecting(selection, change.range))) {
694+
this.onSelectionChange(activeCodeEditor);
695+
break;
696+
}
695697
}
696698
}
697699
}

0 commit comments

Comments
 (0)