Skip to content

Commit 9b4bb24

Browse files
Notebook cell scope provider (#2693)
Fixes #1053 Related #1052 I'm sure how we're gonna support the python comment style cells ```py # %% print("hello") ``` We have tests for them: https://github.com/cursorless-dev/cursorless/blob/56ad4c5cef3f8c8267a098a375cf9139cbbfb0ff/data/fixtures/recorded/selectionTypes/pourCell.yml But they are not a cell scope you can actually target. Tree sitter just sees these as a comment and a function call. We could 1. Remove them. I'm probably leaning towards this. 2. Try to use regular expression to actually support them properly. That means we're back to language specific implementations in typescript. 3. Do what we did before and just yield the current position as a notebook target. Feels very hacky and not something I would like to do. ## 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 --------- Co-authored-by: Phil Cohen <[email protected]>
1 parent 09eb32b commit 9b4bb24

File tree

26 files changed

+299
-272
lines changed

26 files changed

+299
-272
lines changed

data/fixtures/recorded/selectionTypes/drinkCell.yml

Lines changed: 0 additions & 30 deletions
This file was deleted.

data/fixtures/recorded/selectionTypes/drinkCellEach.yml

Lines changed: 0 additions & 41 deletions
This file was deleted.

data/fixtures/recorded/selectionTypes/pourCell.yml

Lines changed: 0 additions & 29 deletions
This file was deleted.

data/fixtures/recorded/selectionTypes/pourCellEach.yml

Lines changed: 0 additions & 41 deletions
This file was deleted.

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/common/src/types/TextEditor.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,8 @@ export interface EditableTextEditor extends TextEditor {
110110

111111
/**
112112
* Edit a new new notebook cell above.
113-
* @return A promise that resolves to a function that must be applied to any
114-
* selections that should be updated as result of this operation. This is a
115-
* horrible hack to work around the fact that in vscode the promise resolves
116-
* before the edits have actually been performed.
117113
*/
118-
editNewNotebookCellAbove(): Promise<(selection: Selection) => Selection>;
114+
editNewNotebookCellAbove(): Promise<void>;
119115

120116
/**
121117
* Edit a new new notebook cell below.

packages/cursorless-engine/src/actions/EditNew/runNotebookCellTargets.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import type { Selection } from "@cursorless/common";
21
import { ide } from "../../singletons/ide.singleton";
32
import type { Destination } from "../../typings/target.types";
43
import { createThatMark, ensureSingleTarget } from "../../util/targetUtils";
@@ -23,18 +22,13 @@ export async function runEditNewNotebookCellTargets(
2322

2423
await actions.setSelection.run([destination.target]);
2524

26-
let modifyThatMark = (selection: Selection) => selection;
2725
if (isAbove) {
28-
modifyThatMark = await editor.editNewNotebookCellAbove();
26+
await editor.editNewNotebookCellAbove();
2927
} else {
3028
await editor.editNewNotebookCellBelow();
3129
}
3230

3331
const thatMark = createThatMark([destination.target.thatTarget]);
3432

35-
// Apply horrible hack to work around the fact that in vscode the promise
36-
// resolves before the edits have actually been performed.
37-
thatMark[0].selection = modifyThatMark(thatMark[0].selection);
38-
3933
return { thatSelections: thatMark };
4034
}

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

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

4039
export class ModifierStageFactoryImpl implements ModifierStageFactory {
4140
constructor(
@@ -135,8 +134,6 @@ export class ModifierStageFactoryImpl implements ModifierStageFactory {
135134
modifier: ContainingScopeModifier | EveryScopeModifier,
136135
): ModifierStage {
137136
switch (modifier.scopeType.type) {
138-
case "notebookCell":
139-
return new NotebookCellStage(modifier);
140137
default:
141138
// Default to containing syntax scope using tree sitter
142139
return new LegacyContainingSyntaxScopeStage(

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,

0 commit comments

Comments
 (0)