Skip to content

Commit 0f5bd0d

Browse files
committed
Scope info provider
1 parent cb22980 commit 0f5bd0d

32 files changed

+1113
-112
lines changed

packages/common/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export { getKey, splitKey } from "./util/splitKey";
1111
export { hrtimeBigintToSeconds } from "./util/timeUtils";
1212
export * from "./util/walkSync";
1313
export * from "./util/walkAsync";
14+
export * from "./util/disposableFrom";
1415
export * from "./util/camelCaseToAllDown";
1516
export { Notifier } from "./util/Notifier";
1617
export type { Listener } from "./util/Notifier";
@@ -43,6 +44,7 @@ export * from "./types/TextEditorOptions";
4344
export * from "./types/TextLine";
4445
export * from "./types/Token";
4546
export * from "./types/HatTokenMap";
47+
export * from "./types/ScopeProvider";
4648
export * from "./types/SpokenForm";
4749
export * from "./util/textFormatters";
4850
export * from "./types/snippet.types";

packages/cursorless-engine/src/api/ScopeProvider.ts renamed to packages/common/src/types/ScopeProvider.ts

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ import {
33
GeneralizedRange,
44
Range,
55
ScopeType,
6+
SpokenForm,
67
TextEditor,
7-
} from "@cursorless/common";
8+
} from "..";
89

910
export interface ScopeProvider {
1011
/**
@@ -17,6 +18,7 @@ export interface ScopeProvider {
1718
editor: TextEditor,
1819
config: ScopeRangeConfig,
1920
) => ScopeRanges[];
21+
2022
/**
2123
* Get the iteration scope ranges for the given editor.
2224
* @param editor The editor
@@ -75,6 +77,41 @@ export interface ScopeProvider {
7577
editor: TextEditor,
7678
scopeType: ScopeType,
7779
) => ScopeSupport;
80+
81+
/**
82+
* Registers a callback to be run when the scope support changes for the active
83+
* editor. The callback will be run immediately once with the current support
84+
* levels for the active editor.
85+
*
86+
* Note that this watcher could be expensive, because it runs all the scope
87+
* handlers for the active editor every time the content of the active editor
88+
* changes. If you only need info about the available scopes, including their
89+
* spoken forms, you should use {@link onDidChangeScopeInfo} instead.
90+
* @param callback The callback to run when the scope support changes
91+
* @returns A {@link Disposable} which will stop the callback from running
92+
*/
93+
onDidChangeScopeSupport: (callback: ScopeSupportEventCallback) => Disposable;
94+
95+
/**
96+
* Registers a callback to be run when the scope info changes. The callback
97+
* will be run immediately once with the current scope info.
98+
*
99+
* Includes information about the available scopes, including their custom
100+
* spoken forms, if available. Note that even custom regex scopes will be
101+
* available, as reported to the engine by Talon.
102+
* @param callback The callback to run when the scope support changes
103+
* @returns A {@link Disposable} which will stop the callback from running
104+
*/
105+
onDidChangeScopeInfo(callback: ScopeTypeInfoEventCallback): Disposable;
106+
107+
/**
108+
* Get info about {@link scopeType}, including its custom spoken form, if
109+
* available.
110+
* @param editor The editor to check
111+
* @param scopeType The scope type to check
112+
* @returns Info about {@link scopeType}
113+
*/
114+
getScopeInfo: (scopeType: ScopeType) => ScopeTypeInfo;
78115
}
79116

80117
interface ScopeRangeConfigBase {
@@ -108,6 +145,24 @@ export type IterationScopeChangeEventCallback = (
108145
scopeRanges: IterationScopeRanges[],
109146
) => void;
110147

148+
export interface ScopeSupportInfo extends ScopeTypeInfo {
149+
support: ScopeSupport;
150+
iterationScopeSupport: ScopeSupport;
151+
}
152+
153+
export type ScopeSupportEventCallback = (
154+
scopeSupportInfos: ScopeSupportInfo[],
155+
) => void;
156+
157+
export interface ScopeTypeInfo {
158+
scopeType: ScopeType;
159+
spokenForm: SpokenForm;
160+
humanReadableName: string;
161+
isLanguageSpecific: boolean;
162+
}
163+
164+
export type ScopeTypeInfoEventCallback = (scopeInfos: ScopeTypeInfo[]) => void;
165+
111166
/**
112167
* Contains the ranges that define a given scope, eg its {@link domain} and the
113168
* ranges for its {@link targets}.

packages/common/src/types/command/PartialTargetDescriptor.types.ts

Lines changed: 93 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -75,89 +75,108 @@ export type PartialMark =
7575
| RangeMark
7676
| ExplicitMark;
7777

78+
export const simpleSurroundingPairNames = [
79+
"angleBrackets",
80+
"backtickQuotes",
81+
"curlyBrackets",
82+
"doubleQuotes",
83+
"escapedDoubleQuotes",
84+
"escapedParentheses",
85+
"escapedSquareBrackets",
86+
"escapedSingleQuotes",
87+
"parentheses",
88+
"singleQuotes",
89+
"squareBrackets",
90+
] as const;
91+
export const complexSurroundingPairNames = [
92+
"string",
93+
"any",
94+
"collectionBoundary",
95+
] as const;
96+
export const surroundingPairNames = [
97+
...simpleSurroundingPairNames,
98+
...complexSurroundingPairNames,
99+
];
78100
export type SimpleSurroundingPairName =
79-
| "angleBrackets"
80-
| "backtickQuotes"
81-
| "curlyBrackets"
82-
| "doubleQuotes"
83-
| "escapedDoubleQuotes"
84-
| "escapedParentheses"
85-
| "escapedSquareBrackets"
86-
| "escapedSingleQuotes"
87-
| "parentheses"
88-
| "singleQuotes"
89-
| "squareBrackets";
101+
(typeof simpleSurroundingPairNames)[number];
90102
export type ComplexSurroundingPairName =
91-
| "string"
92-
| "any"
93-
| "collectionBoundary";
103+
(typeof complexSurroundingPairNames)[number];
94104
export type SurroundingPairName =
95105
| SimpleSurroundingPairName
96106
| ComplexSurroundingPairName;
97107

98-
export type SimpleScopeTypeType =
99-
| "argumentOrParameter"
100-
| "anonymousFunction"
101-
| "attribute"
102-
| "branch"
103-
| "class"
104-
| "className"
105-
| "collectionItem"
106-
| "collectionKey"
107-
| "comment"
108-
| "private.fieldAccess"
109-
| "functionCall"
110-
| "functionCallee"
111-
| "functionName"
112-
| "ifStatement"
113-
| "instance"
114-
| "list"
115-
| "map"
116-
| "name"
117-
| "namedFunction"
118-
| "regularExpression"
119-
| "statement"
120-
| "string"
121-
| "type"
122-
| "value"
123-
| "condition"
124-
| "section"
125-
| "sectionLevelOne"
126-
| "sectionLevelTwo"
127-
| "sectionLevelThree"
128-
| "sectionLevelFour"
129-
| "sectionLevelFive"
130-
| "sectionLevelSix"
131-
| "selector"
132-
| "switchStatementSubject"
133-
| "unit"
134-
| "xmlBothTags"
135-
| "xmlElement"
136-
| "xmlEndTag"
137-
| "xmlStartTag"
138-
| "notebookCell"
108+
export const simpleScopeTypeTypes = [
109+
"argumentOrParameter",
110+
"anonymousFunction",
111+
"attribute",
112+
"branch",
113+
"class",
114+
"className",
115+
"collectionItem",
116+
"collectionKey",
117+
"comment",
118+
"private.fieldAccess",
119+
"functionCall",
120+
"functionCallee",
121+
"functionName",
122+
"ifStatement",
123+
"instance",
124+
"list",
125+
"map",
126+
"name",
127+
"namedFunction",
128+
"regularExpression",
129+
"statement",
130+
"string",
131+
"type",
132+
"value",
133+
"condition",
134+
"section",
135+
"sectionLevelOne",
136+
"sectionLevelTwo",
137+
"sectionLevelThree",
138+
"sectionLevelFour",
139+
"sectionLevelFive",
140+
"sectionLevelSix",
141+
"selector",
142+
"switchStatementSubject",
143+
"unit",
144+
"xmlBothTags",
145+
"xmlElement",
146+
"xmlEndTag",
147+
"xmlStartTag",
139148
// Latex scope types
140-
| "part"
141-
| "chapter"
142-
| "subSection"
143-
| "subSubSection"
144-
| "namedParagraph"
145-
| "subParagraph"
146-
| "environment"
149+
"part",
150+
"chapter",
151+
"subSection",
152+
"subSubSection",
153+
"namedParagraph",
154+
"subParagraph",
155+
"environment",
147156
// Text based scopes
148-
| "character"
149-
| "word"
150-
| "token"
151-
| "identifier"
152-
| "line"
153-
| "sentence"
154-
| "paragraph"
155-
| "document"
156-
| "nonWhitespaceSequence"
157-
| "boundedNonWhitespaceSequence"
158-
| "url"
157+
"character",
158+
"word",
159+
"token",
160+
"identifier",
161+
"line",
162+
"sentence",
163+
"paragraph",
164+
"document",
165+
"nonWhitespaceSequence",
166+
"boundedNonWhitespaceSequence",
167+
"url",
168+
"notebookCell",
159169
// Talon
160-
| "command";
170+
"command",
171+
] as const;
172+
173+
export function isSimpleScopeType(
174+
scopeType: ScopeType,
175+
): scopeType is SimpleScopeType {
176+
return (simpleScopeTypeTypes as readonly string[]).includes(scopeType.type);
177+
}
178+
179+
export type SimpleScopeTypeType = (typeof simpleScopeTypeTypes)[number];
161180

162181
export interface SimpleScopeType {
163182
type: SimpleScopeTypeType;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { Disposable } from "../ide/types/ide.types";
2+
3+
/**
4+
* Construct a disposable that disposes multiple disposables at once. This is
5+
* useful for managing the lifetime of multiple disposables that are created
6+
* together. It ensures that if one of the disposables throws an error during
7+
* disposal, the rest of the disposables will still be disposed.
8+
*/
9+
export function disposableFrom(...disposables: Disposable[]): Disposable {
10+
return {
11+
dispose(): void {
12+
disposables.forEach(({ dispose }) => {
13+
try {
14+
dispose();
15+
} catch (e) {
16+
// just log, but don't throw; some of the VSCode disposables misbehave,
17+
// and we don't want that to prevent us from disposing the rest of the
18+
// disposables
19+
console.error(e);
20+
}
21+
});
22+
},
23+
};
24+
}

packages/cursorless-engine/src/api/CursorlessEngineApi.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Command, HatTokenMap, IDE } from "@cursorless/common";
22
import { Snippets } from "../core/Snippets";
33
import { StoredTargetMap } from "../core/StoredTargets";
44
import { TestCaseRecorder } from "../testCaseRecorder/TestCaseRecorder";
5-
import { ScopeProvider } from "./ScopeProvider";
5+
import { ScopeProvider } from "@cursorless/common";
66

77
export interface CursorlessEngine {
88
commandApi: CommandApi;

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export class Debouncer {
1010
constructor(
1111
/** The callback to debounce */
1212
private callback: () => void,
13+
private debounceDelayMs?: number,
1314
) {
1415
this.run = this.run.bind(this);
1516
}
@@ -19,9 +20,9 @@ export class Debouncer {
1920
clearTimeout(this.timeoutHandle);
2021
}
2122

22-
const decorationDebounceDelayMs = ide().configuration.getOwnConfiguration(
23-
"decorationDebounceDelayMs",
24-
);
23+
const decorationDebounceDelayMs =
24+
this.debounceDelayMs ??
25+
ide().configuration.getOwnConfiguration("decorationDebounceDelayMs");
2526

2627
this.timeoutHandle = setTimeout(() => {
2728
this.callback();

0 commit comments

Comments
 (0)