Skip to content

Commit d75bd2f

Browse files
authored
Create Debouncer; use it for HatAllocator (#1646)
- Required by #1651 ## Checklist - [ ] I have added [tests](https://www.cursorless.org/docs/contributing/test-case-recorder/) - [ ] I have updated the [docs](https://github.com/cursorless-dev/cursorless/tree/main/docs) and [cheatsheet](https://github.com/cursorless-dev/cursorless/tree/main/cursorless-talon/src/cheatsheet) - [ ] I have not broken the cheatsheet
1 parent 1cc4cd5 commit d75bd2f

File tree

2 files changed

+51
-32
lines changed

2 files changed

+51
-32
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { ide } from "../singletons/ide.singleton";
2+
3+
/**
4+
* Debounces a callback. Uses the `decorationDebounceDelayMs` configuration
5+
* value to determine the debounce delay.
6+
*/
7+
export class Debouncer {
8+
private timeoutHandle: NodeJS.Timeout | null = null;
9+
10+
constructor(
11+
/** The callback to debounce */
12+
private callback: () => void,
13+
) {
14+
this.run = this.run.bind(this);
15+
}
16+
17+
run() {
18+
if (this.timeoutHandle != null) {
19+
clearTimeout(this.timeoutHandle);
20+
}
21+
22+
const decorationDebounceDelayMs = ide().configuration.getOwnConfiguration(
23+
"decorationDebounceDelayMs",
24+
);
25+
26+
this.timeoutHandle = setTimeout(() => {
27+
this.callback();
28+
this.timeoutHandle = null;
29+
}, decorationDebounceDelayMs);
30+
}
31+
32+
dispose() {
33+
if (this.timeoutHandle != null) {
34+
clearTimeout(this.timeoutHandle);
35+
}
36+
}
37+
}

packages/cursorless-engine/src/core/HatAllocator.ts

Lines changed: 14 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,44 +2,45 @@ import type { Disposable, Hats, TokenHat } from "@cursorless/common";
22
import { ide } from "../singletons/ide.singleton";
33
import tokenGraphemeSplitter from "../singletons/tokenGraphemeSplitter.singleton";
44
import { allocateHats } from "../util/allocateHats";
5+
import { Debouncer } from "./Debouncer";
56
import { IndividualHatMap } from "./IndividualHatMap";
67

78
interface Context {
89
getActiveMap(): Promise<IndividualHatMap>;
910
}
1011

1112
export class HatAllocator {
12-
private timeoutHandle: NodeJS.Timeout | null = null;
1313
private disposables: Disposable[] = [];
14+
private debouncer = new Debouncer(() => this.allocateHats());
1415

1516
constructor(private hats: Hats, private context: Context) {
1617
ide().disposeOnExit(this);
1718

18-
this.allocateHatsDebounced = this.allocateHatsDebounced.bind(this);
19-
2019
this.disposables.push(
21-
this.hats.onDidChangeEnabledHatStyles(this.allocateHatsDebounced),
22-
this.hats.onDidChangeIsEnabled(this.allocateHatsDebounced),
20+
this.hats.onDidChangeEnabledHatStyles(this.debouncer.run),
21+
this.hats.onDidChangeIsEnabled(this.debouncer.run),
2322

2423
// An event that fires when a text document opens
25-
ide().onDidOpenTextDocument(this.allocateHatsDebounced),
24+
ide().onDidOpenTextDocument(this.debouncer.run),
2625
// An event that fires when a text document closes
27-
ide().onDidCloseTextDocument(this.allocateHatsDebounced),
26+
ide().onDidCloseTextDocument(this.debouncer.run),
2827
// An Event which fires when the active editor has changed. Note that the event also fires when the active editor changes to undefined.
29-
ide().onDidChangeActiveTextEditor(this.allocateHatsDebounced),
28+
ide().onDidChangeActiveTextEditor(this.debouncer.run),
3029
// An Event which fires when the array of visible editors has changed.
31-
ide().onDidChangeVisibleTextEditors(this.allocateHatsDebounced),
30+
ide().onDidChangeVisibleTextEditors(this.debouncer.run),
3231
// An event that is emitted when a text document is changed. This usually happens when the contents changes but also when other things like the dirty-state changes.
33-
ide().onDidChangeTextDocument(this.allocateHatsDebounced),
32+
ide().onDidChangeTextDocument(this.debouncer.run),
3433
// An Event which fires when the selection in an editor has changed.
35-
ide().onDidChangeTextEditorSelection(this.allocateHatsDebounced),
34+
ide().onDidChangeTextEditorSelection(this.debouncer.run),
3635
// An Event which fires when the visible ranges of an editor has changed.
37-
ide().onDidChangeTextEditorVisibleRanges(this.allocateHatsDebounced),
36+
ide().onDidChangeTextEditorVisibleRanges(this.debouncer.run),
3837
// Re-draw hats on grapheme splitting algorithm change in case they
3938
// changed their token hat splitting setting.
4039
tokenGraphemeSplitter().registerAlgorithmChangeListener(
41-
this.allocateHatsDebounced,
40+
this.debouncer.run,
4241
),
42+
43+
this.debouncer,
4344
);
4445
}
4546

@@ -75,26 +76,7 @@ export class HatAllocator {
7576
);
7677
}
7778

78-
allocateHatsDebounced() {
79-
if (this.timeoutHandle != null) {
80-
clearTimeout(this.timeoutHandle);
81-
}
82-
83-
const decorationDebounceDelayMs = ide().configuration.getOwnConfiguration(
84-
"decorationDebounceDelayMs",
85-
);
86-
87-
this.timeoutHandle = setTimeout(() => {
88-
this.allocateHats();
89-
this.timeoutHandle = null;
90-
}, decorationDebounceDelayMs);
91-
}
92-
9379
dispose() {
9480
this.disposables.forEach(({ dispose }) => dispose());
95-
96-
if (this.timeoutHandle != null) {
97-
clearTimeout(this.timeoutHandle);
98-
}
9981
}
10082
}

0 commit comments

Comments
 (0)