Skip to content

Commit c59b75f

Browse files
Implemented
1 parent 8cd7c21 commit c59b75f

File tree

16 files changed

+282
-61
lines changed

16 files changed

+282
-61
lines changed

packages/common/src/ide/PassthroughIDEBase.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { GeneralizedRange } from "../types/GeneralizedRange";
2+
import type { NotebookEditor } from "../types/NotebookEditor";
23
import type { TextDocument } from "../types/TextDocument";
34
import type { EditableTextEditor, TextEditor } from "../types/TextEditor";
45
import type { Capabilities } from "./types/Capabilities";
@@ -17,9 +18,9 @@ import type {
1718
RunMode,
1819
WorkspaceFolder,
1920
} from "./types/ide.types";
21+
import type { KeyValueStore } from "./types/KeyValueStore";
2022
import type { Messages } from "./types/Messages";
2123
import type { QuickPickOptions } from "./types/QuickPickOptions";
22-
import type { KeyValueStore } from "./types/KeyValueStore";
2324

2425
export default class PassthroughIDEBase implements IDE {
2526
configuration: Configuration;
@@ -123,6 +124,10 @@ export default class PassthroughIDEBase implements IDE {
123124
return this.original.visibleTextEditors;
124125
}
125126

127+
public get visibleNotebookEditors(): NotebookEditor[] {
128+
return this.original.visibleNotebookEditors;
129+
}
130+
126131
public get cursorlessVersion(): string {
127132
return this.original.cursorlessVersion;
128133
}

packages/common/src/ide/fake/FakeIDE.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { pull } from "lodash-es";
2-
import type { EditableTextEditor, TextEditor } from "../..";
2+
import type { EditableTextEditor, NotebookEditor, TextEditor } from "../..";
33
import type { GeneralizedRange } from "../../types/GeneralizedRange";
44
import type { TextDocument } from "../../types/TextDocument";
55
import type { TextDocumentChangeEvent } from "../types/Events";
@@ -82,6 +82,10 @@ export class FakeIDE implements IDE {
8282
throw Error("Not implemented");
8383
}
8484

85+
get visibleNotebookEditors(): NotebookEditor[] {
86+
throw Error("Not implemented");
87+
}
88+
8589
public getEditableTextEditor(_editor: TextEditor): EditableTextEditor {
8690
throw Error("Not implemented");
8791
}

packages/common/src/ide/types/ide.types.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
import type { URI } from "vscode-uri";
12
import type {
23
EditableTextEditor,
34
InputBoxOptions,
5+
NotebookEditor,
46
TextDocument,
57
TextEditor,
68
} from "../..";
7-
import type { URI } from "vscode-uri";
89
import type { GeneralizedRange } from "../../types/GeneralizedRange";
910
import type { Capabilities } from "./Capabilities";
1011
import type { Clipboard } from "./Clipboard";
@@ -16,9 +17,9 @@ import type {
1617
TextEditorVisibleRangesChangeEvent,
1718
} from "./events.types";
1819
import type { FlashDescriptor } from "./FlashDescriptor";
20+
import type { KeyValueStore } from "./KeyValueStore";
1921
import type { Messages } from "./Messages";
2022
import type { QuickPickOptions } from "./QuickPickOptions";
21-
import type { KeyValueStore } from "./KeyValueStore";
2223

2324
export type RunMode = "production" | "development" | "test";
2425
export type HighlightId = string;
@@ -79,6 +80,11 @@ export interface IDE {
7980
*/
8081
readonly visibleTextEditors: TextEditor[];
8182

83+
/**
84+
* The currently visible notebook editors or an empty array.
85+
*/
86+
readonly visibleNotebookEditors: NotebookEditor[];
87+
8288
/**
8389
* The capabilities of the IDE
8490
*/

packages/common/src/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,19 @@ export * from "./ide/types/Clipboard";
1414
export * from "./ide/types/CommandHistoryStorage";
1515
export * from "./ide/types/CommandId";
1616
export * from "./ide/types/Configuration";
17-
export * from "./ide/types/events.types";
1817
export * from "./ide/types/Events";
18+
export * from "./ide/types/events.types";
1919
export * from "./ide/types/FileSystem.types";
2020
export * from "./ide/types/FlashDescriptor";
2121
export * from "./ide/types/Hats";
2222
export * from "./ide/types/HatStability";
2323
export * from "./ide/types/hatStyles.types";
2424
export * from "./ide/types/ide.types";
25+
export * from "./ide/types/KeyValueStore";
2526
export * from "./ide/types/Messages";
2627
export * from "./ide/types/Paths";
2728
export * from "./ide/types/QuickPickOptions";
2829
export * from "./ide/types/RawTreeSitterQueryProvider";
29-
export * from "./ide/types/KeyValueStore";
3030
export * from "./ide/types/TutorialContentProvider";
3131
export * from "./ide/util/messages";
3232
export * from "./scopeSupportFacets/languageScopeSupport";
@@ -66,6 +66,8 @@ export * from "./types/Edit";
6666
export * from "./types/GeneralizedRange";
6767
export * from "./types/HatTokenMap";
6868
export * from "./types/InputBoxOptions";
69+
export * from "./types/NotebookCell";
70+
export * from "./types/NotebookEditor";
6971
export * from "./types/Position";
7072
export * from "./types/Range";
7173
export * from "./types/RangeExpansionBehavior";
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import type { TextDocument } from "./TextDocument";
2+
3+
export interface NotebookCell {
4+
/**
5+
* The index of this cell in its containing notebook. The
6+
* index is updated when a cell is moved within its notebook. The index is `-1`
7+
* when the cell has been removed from its notebook.
8+
*/
9+
readonly index: number;
10+
11+
/**
12+
* The kind of this cell.
13+
*/
14+
readonly kind: NotebookCellKind;
15+
16+
/**
17+
* The {@link TextDocument} of this cell.
18+
*/
19+
readonly document: TextDocument;
20+
}
21+
22+
export enum NotebookCellKind {
23+
/**
24+
* A markup-cell is formatted source that is used for display.
25+
*/
26+
Markup = 1,
27+
28+
/**
29+
* A code-cell.
30+
*/
31+
Code = 2,
32+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { URI } from "vscode-uri";
2+
import type { NotebookCell } from "./NotebookCell";
3+
4+
export interface NotebookEditor {
5+
/**
6+
* The associated uri for this document.
7+
*
8+
* *Note* that most documents use the `file`-scheme, which means they are files on disk. However, **not** all documents are
9+
* saved on disk and therefore the `scheme` must be checked before trying to access the underlying file or siblings on disk.
10+
*/
11+
readonly uri: URI;
12+
13+
/**
14+
* The number of cells in the notebook.
15+
*/
16+
readonly cellCount: number;
17+
18+
/**
19+
* The cells of this notebook.
20+
*/
21+
readonly cells: NotebookCell[];
22+
}

packages/cursorless-engine/src/processTargets/ModifierStageFactoryImpl.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import type {
3636
SimpleEveryScopeModifier,
3737
} from "./modifiers/scopeTypeStages/LegacyContainingSyntaxScopeStage";
3838
import { LegacyContainingSyntaxScopeStage } from "./modifiers/scopeTypeStages/LegacyContainingSyntaxScopeStage";
39-
import { NotebookCellStage } from "./modifiers/scopeTypeStages/NotebookCellStage";
4039

4140
export class ModifierStageFactoryImpl implements ModifierStageFactory {
4241
constructor(
@@ -129,8 +128,6 @@ export class ModifierStageFactoryImpl implements ModifierStageFactory {
129128
modifier: ContainingScopeModifier | EveryScopeModifier,
130129
): ModifierStage {
131130
switch (modifier.scopeType.type) {
132-
case "notebookCell":
133-
return new NotebookCellStage(modifier);
134131
case "collectionItem":
135132
return new ItemStage(this.languageDefinitions, this, modifier);
136133
default:

packages/cursorless-engine/src/processTargets/createContinuousRangeTarget.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ export function createContinuousRangeTarget(
3333
includeStart: boolean,
3434
includeEnd: boolean,
3535
): Target {
36+
if (startTarget.editor !== endTarget.editor) {
37+
throw Error("Continuous targets must be in the same editor");
38+
}
39+
3640
if (includeStart && includeEnd && isSameType(startTarget, endTarget)) {
3741
const richTarget = startTarget.maybeCreateRichRangeTarget(
3842
isReversed,
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import {
2+
Range,
3+
type Direction,
4+
type NotebookCell,
5+
type Position,
6+
type ScopeType,
7+
type TextEditor,
8+
} from "@cursorless/common";
9+
import type { LanguageDefinitions } from "../../../languages/LanguageDefinitions";
10+
import { ide } from "../../../singletons/ide.singleton";
11+
import { NotebookCellTarget } from "../../targets";
12+
import type { TargetScope } from "./scope.types";
13+
import type {
14+
ScopeHandler,
15+
ScopeIteratorRequirements,
16+
} from "./scopeHandler.types";
17+
18+
export class NotebookCellScopeHandler implements ScopeHandler {
19+
public readonly scopeType = { type: "notebookCell" } as const;
20+
public readonly iterationScopeType = { type: "document" } as const;
21+
public readonly includeAdjacentInEvery = false;
22+
23+
constructor(
24+
private languageDefinitions: LanguageDefinitions,
25+
_scopeType: ScopeType,
26+
private languageId: string,
27+
) {}
28+
29+
*generateScopes(
30+
editor: TextEditor,
31+
position: Position,
32+
direction: Direction,
33+
hints: ScopeIteratorRequirements,
34+
): Iterable<TargetScope> {
35+
const scopeHandler = this.languageDefinitions
36+
.get(this.languageId)
37+
?.getScopeHandler(this.scopeType);
38+
39+
if (scopeHandler != null) {
40+
yield* scopeHandler.generateScopeCandidates(
41+
editor,
42+
position,
43+
direction,
44+
hints,
45+
);
46+
}
47+
48+
const nb = getNotebook(editor);
49+
50+
if (nb == null) {
51+
return;
52+
}
53+
54+
const { notebook, cell } = nb;
55+
56+
if (hints.containment === "required") {
57+
yield createTargetScope(cell);
58+
return;
59+
}
60+
61+
const cells = (() => {
62+
if (
63+
hints.containment === "disallowed" ||
64+
hints.containment === "disallowedIfStrict"
65+
) {
66+
return direction === "forward"
67+
? notebook.cells.slice(cell.index + 1)
68+
: notebook.cells.slice(0, cell.index).reverse();
69+
}
70+
// Every scope
71+
if (hints.distalPosition != null) {
72+
const searchRange = new Range(position, hints.distalPosition);
73+
if (searchRange.isRangeEqual(editor.document.range)) {
74+
return notebook.cells;
75+
}
76+
}
77+
return direction === "forward"
78+
? notebook.cells.slice(cell.index)
79+
: notebook.cells.slice(0, cell.index + 1).reverse();
80+
})();
81+
82+
for (const cell of cells) {
83+
yield createTargetScope(cell);
84+
}
85+
}
86+
}
87+
88+
function createTargetScope(cell: NotebookCell): TargetScope {
89+
const editor = getEditor(cell);
90+
const contentRange = editor.document.range;
91+
return {
92+
editor,
93+
domain: contentRange,
94+
getTargets: (isReversed: boolean) => [
95+
new NotebookCellTarget({
96+
editor,
97+
isReversed,
98+
contentRange,
99+
}),
100+
],
101+
};
102+
}
103+
104+
function getNotebook(editor: TextEditor) {
105+
const uri = editor.document.uri.toString();
106+
for (const notebook of ide().visibleNotebookEditors) {
107+
for (const cell of notebook.cells) {
108+
if (cell.document.uri.toString() === uri) {
109+
return { notebook, cell };
110+
}
111+
}
112+
}
113+
return undefined;
114+
}
115+
116+
function getEditor(cell: NotebookCell) {
117+
for (const editor of ide().visibleTextEditors) {
118+
if (editor.document.uri.toString() === cell.document.uri.toString()) {
119+
return editor;
120+
}
121+
}
122+
throw new Error("Editor not found notebook cell");
123+
}

packages/cursorless-engine/src/processTargets/modifiers/scopeHandlers/ScopeHandlerFactoryImpl.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { CharacterScopeHandler } from "./CharacterScopeHandler";
88
import { DocumentScopeHandler } from "./DocumentScopeHandler";
99
import { IdentifierScopeHandler } from "./IdentifierScopeHandler";
1010
import { LineScopeHandler } from "./LineScopeHandler";
11+
import { NotebookCellScopeHandler } from "./NotebookCellScopeHandler";
1112
import { OneOfScopeHandler } from "./OneOfScopeHandler";
1213
import { ParagraphScopeHandler } from "./ParagraphScopeHandler";
1314
import {
@@ -103,6 +104,12 @@ export class ScopeHandlerFactoryImpl implements ScopeHandlerFactory {
103104
scopeType,
104105
languageId,
105106
);
107+
case "notebookCell":
108+
return new NotebookCellScopeHandler(
109+
this.languageDefinitions,
110+
scopeType,
111+
languageId,
112+
);
106113
case "custom":
107114
return scopeType.scopeHandler;
108115
case "instance":

0 commit comments

Comments
 (0)