@marimo-team/islands 0.23.16-dev9 → 0.23.17-dev0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chat-ui-JeekqoMH.js → chat-ui-DsZJj75A.js} +3104 -3107
- package/dist/{code-visibility-DveLKNtj.js → common-CotPLtrU.js} +1068 -1036
- package/dist/{formats-CO8cn5_K.js → formats-Dwq1THhr.js} +1 -1
- package/dist/{html-to-image-Bif4utQZ.js → html-to-image-CZ1kLKkq.js} +7336 -6342
- package/dist/main.js +211 -147
- package/dist/{node-sql-parser-DLl_zNw0.js → node-sql-parser-v1Vi-Fft.js} +16867 -16665
- package/dist/{process-output-TAzy-GUk.js → process-output-bVfbcx5_.js} +30 -26
- package/dist/{reveal-component-DxV4Ppa2.js → reveal-component-IoHipy82.js} +634 -626
- package/dist/style.css +1 -1
- package/dist/toDate-CqhBWjvO.js +713 -0
- package/dist/{vega-component-DphdxaJ_.js → vega-component-C7nO5zcf.js} +2 -2
- package/package.json +3 -4
- package/src/__mocks__/requests.ts +56 -4
- package/src/components/data-table/__tests__/__snapshots__/chart-spec-model.test.ts.snap +174 -21
- package/src/components/data-table/__tests__/chart-spec-model.test.ts +102 -1
- package/src/components/data-table/__tests__/columns.test.tsx +9 -1
- package/src/components/data-table/column-summary/chart-spec-model.tsx +163 -103
- package/src/components/data-table/column-summary/legacy-chart-spec.ts +15 -7
- package/src/components/data-table/column-summary/utils.ts +26 -7
- package/src/components/data-table/columns.tsx +11 -1
- package/src/components/data-table/types.ts +1 -1
- package/src/components/editor/__tests__/viewer-banner.test.tsx +14 -0
- package/src/components/editor/actions/__tests__/pair-with-agent-commands.test.ts +99 -18
- package/src/components/editor/actions/__tests__/pdf-export.test.ts +32 -13
- package/src/components/editor/actions/pair-with-agent-commands.ts +21 -10
- package/src/components/editor/actions/pair-with-agent-modal.tsx +2 -2
- package/src/components/editor/actions/pdf-export.ts +11 -14
- package/src/components/editor/actions/useNotebookActions.tsx +28 -19
- package/src/components/editor/cell/code/__tests__/cell-editor-activity-lifecycle.test.ts +250 -0
- package/src/components/editor/cell/code/cell-editor.tsx +13 -7
- package/src/components/editor/chrome/__tests__/state.test.ts +7 -1
- package/src/components/editor/chrome/panels/__tests__/logs-panel.test.tsx +25 -0
- package/src/components/editor/chrome/panels/__tests__/panel-accordion-state.test.ts +42 -0
- package/src/components/editor/chrome/panels/file-explorer-panel.tsx +6 -17
- package/src/components/editor/chrome/panels/logs-panel.tsx +12 -2
- package/src/components/editor/chrome/panels/panel-accordion-state.ts +51 -0
- package/src/components/editor/chrome/panels/session-panel.tsx +5 -16
- package/src/components/editor/chrome/panels/write-secret-modal.tsx +40 -12
- package/src/components/editor/chrome/state.ts +10 -0
- package/src/components/editor/connections/__tests__/json-credentials.test.ts +114 -0
- package/src/components/editor/connections/__tests__/paths.test.ts +39 -0
- package/src/components/editor/connections/__tests__/quick-add-data-sources.test.tsx +113 -0
- package/src/components/editor/connections/add-connection-dialog.tsx +2 -0
- package/src/components/editor/connections/components.tsx +6 -2
- package/src/components/editor/connections/database/__tests__/__snapshots__/as-code.test.ts.snap +27 -5
- package/src/components/editor/connections/database/__tests__/as-code.test.ts +33 -0
- package/src/components/editor/connections/database/as-code.ts +37 -13
- package/src/components/editor/connections/database/schemas.ts +6 -5
- package/src/components/editor/connections/form-renderers.tsx +99 -1
- package/src/components/editor/connections/json-credentials.ts +57 -0
- package/src/components/editor/connections/paths.ts +21 -0
- package/src/components/editor/connections/quick-add-data-sources.tsx +106 -0
- package/src/components/editor/connections/secret-combobox.tsx +41 -20
- package/src/components/editor/connections/storage/__tests__/__snapshots__/as-code.test.ts.snap +88 -2
- package/src/components/editor/connections/storage/__tests__/as-code.test.ts +128 -8
- package/src/components/editor/connections/storage/as-code.ts +79 -36
- package/src/components/editor/connections/storage/schemas.ts +85 -44
- package/src/components/editor/file-tree/__tests__/renderers.test.ts +31 -0
- package/src/components/editor/file-tree/file-viewer.tsx +11 -7
- package/src/components/editor/file-tree/renderers.tsx +21 -0
- package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +2 -2
- package/src/components/editor/viewer-banner.tsx +6 -1
- package/src/components/forms/form.tsx +59 -24
- package/src/components/forms/options.ts +2 -1
- package/src/components/slides/__tests__/cell-output-block.test.tsx +40 -0
- package/src/components/slides/__tests__/slide-cell-view.test.tsx +33 -0
- package/src/components/slides/reveal-component.tsx +22 -17
- package/src/components/slides/slide-cell-view.tsx +1 -1
- package/src/components/slides/slides.css +4 -2
- package/src/components/static-html/share-modal.tsx +1 -1
- package/src/core/ai/context/providers/file.ts +8 -29
- package/src/core/cells/__tests__/cells.test.ts +12 -2
- package/src/core/cells/__tests__/logs.test.ts +5 -5
- package/src/core/cells/cells.ts +17 -4
- package/src/core/cells/document-changes.ts +1 -0
- package/src/core/cells/logs.ts +14 -4
- package/src/core/codemirror/cm.ts +3 -0
- package/src/core/codemirror/code-lens/__tests__/actions.test.ts +68 -0
- package/src/core/codemirror/code-lens/__tests__/analyzer.test.ts +224 -0
- package/src/core/codemirror/code-lens/__tests__/entities.test.ts +175 -0
- package/src/core/codemirror/code-lens/__tests__/extension.test.ts +325 -0
- package/src/core/codemirror/code-lens/__tests__/perf.test.ts +121 -0
- package/src/core/codemirror/code-lens/__tests__/popover.test.ts +93 -0
- package/src/core/codemirror/code-lens/actions.ts +33 -0
- package/src/core/codemirror/code-lens/analyzer.ts +284 -0
- package/src/core/codemirror/code-lens/entities.ts +123 -0
- package/src/core/codemirror/code-lens/extension.ts +298 -0
- package/src/core/codemirror/code-lens/icons.ts +36 -0
- package/src/core/codemirror/code-lens/popover.tsx +240 -0
- package/src/core/codemirror/copilot/__tests__/language-server.test.ts +396 -100
- package/src/core/codemirror/copilot/__tests__/transport.test.ts +128 -540
- package/src/core/codemirror/copilot/language-server.ts +182 -70
- package/src/core/codemirror/copilot/transport.ts +15 -207
- package/src/core/codemirror/copilot/types.ts +9 -2
- package/src/core/codemirror/find-replace/__tests__/navigate.test.ts +42 -30
- package/src/core/codemirror/find-replace/navigate.ts +2 -0
- package/src/core/codemirror/go-to-definition/__tests__/commands.test.ts +24 -3
- package/src/core/codemirror/go-to-definition/commands.ts +93 -90
- package/src/core/codemirror/language/__tests__/sql.test.ts +627 -61
- package/src/core/codemirror/language/languages/python.ts +23 -11
- package/src/core/codemirror/language/languages/sql/completion-store.ts +5 -1
- package/src/core/codemirror/language/languages/sql/renderers.tsx +3 -3
- package/src/core/codemirror/language/languages/sql/sql.ts +251 -16
- package/src/core/codemirror/lsp/__tests__/federated-lsp.test.ts +161 -0
- package/src/core/codemirror/lsp/__tests__/log-messages.test.ts +53 -0
- package/src/core/codemirror/lsp/__tests__/normalize-markdown-math.test.ts +25 -0
- package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +598 -156
- package/src/core/codemirror/lsp/__tests__/transports.test.ts +112 -0
- package/src/core/codemirror/lsp/federated-lsp.ts +76 -23
- package/src/core/codemirror/lsp/log-messages.ts +37 -0
- package/src/core/codemirror/lsp/normalize-markdown-math.ts +8 -4
- package/src/core/codemirror/lsp/notebook-lsp.ts +220 -56
- package/src/core/codemirror/lsp/transports.ts +8 -1
- package/src/core/codemirror/lsp/types.ts +68 -8
- package/src/core/codemirror/lsp/utils.ts +14 -0
- package/src/core/codemirror/python-node-names.ts +90 -0
- package/src/core/codemirror/reactive-references/analyzer.ts +52 -57
- package/src/core/codemirror/utils.ts +28 -0
- package/src/core/config/feature-flag.tsx +3 -1
- package/src/core/datasets/data-source-discovery.ts +5 -0
- package/src/core/datasets/request-registry.ts +11 -0
- package/src/core/edit-app.tsx +1 -2
- package/src/core/export/__tests__/hooks.test.ts +2 -4
- package/src/core/export/hooks.ts +4 -3
- package/src/core/islands/__tests__/bridge.test.ts +107 -0
- package/src/core/islands/bootstrap.ts +1 -0
- package/src/core/islands/bridge.ts +18 -0
- package/src/core/kernel/messages.ts +2 -0
- package/src/core/lsp/__tests__/transport.test.ts +509 -337
- package/src/core/lsp/transport.ts +304 -132
- package/src/core/mode.ts +10 -0
- package/src/core/network/__tests__/api.test.ts +42 -0
- package/src/core/network/__tests__/connection.test.ts +45 -0
- package/src/core/network/__tests__/requests-lazy.test.ts +47 -1
- package/src/core/network/__tests__/requests-network.test.ts +48 -0
- package/src/core/network/api.ts +27 -0
- package/src/core/network/connection.ts +15 -0
- package/src/core/network/requests-lazy.ts +3 -0
- package/src/core/network/requests-network.ts +31 -8
- package/src/core/network/requests-static.ts +3 -0
- package/src/core/network/requests-toasting.tsx +3 -0
- package/src/core/network/types.ts +27 -6
- package/src/core/rtc/state.ts +9 -0
- package/src/core/static/download-html.ts +5 -14
- package/src/core/wasm/__tests__/bridge.test.ts +99 -5
- package/src/core/wasm/bridge.ts +42 -9
- package/src/core/wasm/worker/types.ts +10 -3
- package/src/core/wasm/worker/worker.ts +7 -8
- package/src/core/websocket/useMarimoKernelConnection.tsx +4 -0
- package/src/css/app/codemirror.css +16 -2
- package/src/hooks/__tests__/useDataSourceDiscovery.test.ts +80 -0
- package/src/hooks/useDataSourceDiscovery.ts +18 -0
- package/src/plugins/impl/DataTablePlugin.tsx +4 -1
- package/src/plugins/impl/__tests__/DataTablePlugin.test.tsx +158 -0
- package/src/plugins/impl/anywidget/__tests__/model.test.ts +55 -0
- package/src/plugins/impl/anywidget/model.ts +20 -5
- package/src/plugins/impl/data-frames/forms/__tests__/__snapshots__/form.test.tsx.snap +33 -21
- package/src/plugins/impl/data-frames/forms/renderers.tsx +11 -8
- package/src/stories/log-viewer.stories.tsx +12 -6
- package/src/utils/__tests__/blob.test.ts +27 -1
- package/src/utils/__tests__/download.test.tsx +44 -4
- package/src/utils/blob.ts +24 -1
- package/src/utils/download.ts +14 -15
- package/dist/toDate-CmR_xR3P.js +0 -692
|
@@ -20,6 +20,26 @@ vi.mock("@/core/cells/cells", () => ({
|
|
|
20
20
|
getAllEditorViews: () => mockGetAllEditorViews(),
|
|
21
21
|
}));
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* A view stub that only carries what navigate needs
|
|
25
|
+
*/
|
|
26
|
+
function createMockView(state: EditorState): EditorView {
|
|
27
|
+
const cell = document.createElement("div");
|
|
28
|
+
cell.className = "marimo-cell";
|
|
29
|
+
// jsdom doesn't implement scrollIntoView.
|
|
30
|
+
cell.scrollIntoView = vi.fn();
|
|
31
|
+
const dom = document.createElement("div");
|
|
32
|
+
cell.append(dom);
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
state,
|
|
36
|
+
dom,
|
|
37
|
+
// Don't actually apply changes; it's complex to mock properly and the
|
|
38
|
+
// assertions only care that dispatch was called.
|
|
39
|
+
dispatch: vi.fn(),
|
|
40
|
+
} as unknown as EditorView;
|
|
41
|
+
}
|
|
42
|
+
|
|
23
43
|
describe("navigate", () => {
|
|
24
44
|
let view1: EditorView;
|
|
25
45
|
let view2: EditorView;
|
|
@@ -36,20 +56,8 @@ describe("navigate", () => {
|
|
|
36
56
|
});
|
|
37
57
|
|
|
38
58
|
// Create mock views that track dispatch calls
|
|
39
|
-
view1 =
|
|
40
|
-
|
|
41
|
-
dispatch: vi.fn(() => {
|
|
42
|
-
// Mock dispatch - in real tests we just need to verify it was called
|
|
43
|
-
// Don't actually apply changes as it's complex to mock properly
|
|
44
|
-
}),
|
|
45
|
-
} as unknown as EditorView;
|
|
46
|
-
|
|
47
|
-
view2 = {
|
|
48
|
-
state: state2,
|
|
49
|
-
dispatch: vi.fn(() => {
|
|
50
|
-
// Mock dispatch - in real tests we just need to verify it was called
|
|
51
|
-
}),
|
|
52
|
-
} as unknown as EditorView;
|
|
59
|
+
view1 = createMockView(state1);
|
|
60
|
+
view2 = createMockView(state2);
|
|
53
61
|
|
|
54
62
|
mockViews = [view1, view2];
|
|
55
63
|
mockGetAllEditorViews.mockReturnValue(mockViews);
|
|
@@ -234,6 +242,22 @@ describe("navigate", () => {
|
|
|
234
242
|
|
|
235
243
|
expect(result).toBe(false);
|
|
236
244
|
});
|
|
245
|
+
|
|
246
|
+
it("should scroll the cell owning the match into view", async () => {
|
|
247
|
+
const cell = view1.dom.closest(".marimo-cell");
|
|
248
|
+
invariant(cell, "mock view should be inside a cell");
|
|
249
|
+
|
|
250
|
+
expect(findNext()).toBeTruthy();
|
|
251
|
+
|
|
252
|
+
// The scroll is deferred a frame.
|
|
253
|
+
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
254
|
+
|
|
255
|
+
expect(cell.scrollIntoView).toHaveBeenCalledWith({
|
|
256
|
+
behavior: "instant",
|
|
257
|
+
block: "nearest",
|
|
258
|
+
inline: "nearest",
|
|
259
|
+
});
|
|
260
|
+
});
|
|
237
261
|
});
|
|
238
262
|
|
|
239
263
|
describe("findPrev", () => {
|
|
@@ -319,10 +343,7 @@ describe("navigate", () => {
|
|
|
319
343
|
extensions: [EditorState.readOnly.of(true)],
|
|
320
344
|
});
|
|
321
345
|
|
|
322
|
-
const readOnlyView =
|
|
323
|
-
state: readOnlyState,
|
|
324
|
-
dispatch: vi.fn(),
|
|
325
|
-
} as unknown as EditorView;
|
|
346
|
+
const readOnlyView = createMockView(readOnlyState);
|
|
326
347
|
|
|
327
348
|
// Replace view1 with read-only view temporarily
|
|
328
349
|
mockGetAllEditorViews.mockReturnValueOnce([readOnlyView, view2]);
|
|
@@ -568,10 +589,7 @@ describe("navigate", () => {
|
|
|
568
589
|
doc: Text.of(["hello world hello there hello"]),
|
|
569
590
|
});
|
|
570
591
|
|
|
571
|
-
const testView =
|
|
572
|
-
state: testDoc,
|
|
573
|
-
dispatch: vi.fn(),
|
|
574
|
-
} as unknown as EditorView;
|
|
592
|
+
const testView = createMockView(testDoc);
|
|
575
593
|
|
|
576
594
|
mockGetAllEditorViews.mockReturnValue([testView]);
|
|
577
595
|
|
|
@@ -613,10 +631,7 @@ describe("navigate", () => {
|
|
|
613
631
|
doc: Text.of([""]),
|
|
614
632
|
});
|
|
615
633
|
|
|
616
|
-
const emptyView =
|
|
617
|
-
state: emptyState,
|
|
618
|
-
dispatch: vi.fn(),
|
|
619
|
-
} as unknown as EditorView;
|
|
634
|
+
const emptyView = createMockView(emptyState);
|
|
620
635
|
|
|
621
636
|
mockGetAllEditorViews.mockReturnValue([emptyView]);
|
|
622
637
|
|
|
@@ -629,10 +644,7 @@ describe("navigate", () => {
|
|
|
629
644
|
doc: Text.of(["orphan content"]),
|
|
630
645
|
});
|
|
631
646
|
|
|
632
|
-
const orphanView =
|
|
633
|
-
state: orphanState,
|
|
634
|
-
dispatch: vi.fn(),
|
|
635
|
-
} as unknown as EditorView;
|
|
647
|
+
const orphanView = createMockView(orphanState);
|
|
636
648
|
|
|
637
649
|
store.set(findReplaceAtom, {
|
|
638
650
|
type: "setCurrentView",
|
|
@@ -6,6 +6,7 @@ import { EditorView } from "@codemirror/view";
|
|
|
6
6
|
import { getAllEditorViews } from "@/core/cells/cells";
|
|
7
7
|
import { replaceEditorContent } from "@/core/codemirror/replace-editor-content";
|
|
8
8
|
import { store } from "@/core/state/jotai";
|
|
9
|
+
import { scrollOwnerCell } from "../utils";
|
|
9
10
|
import { asQueryCreator, type QueryType } from "./query";
|
|
10
11
|
import { findReplaceAtom } from "./state";
|
|
11
12
|
|
|
@@ -85,6 +86,7 @@ const findInDirection = (direction: "next" | "prev") =>
|
|
|
85
86
|
effects: [EditorView.scrollIntoView(selection.main, { y: "center" })],
|
|
86
87
|
userEvent: "select.search",
|
|
87
88
|
});
|
|
89
|
+
scrollOwnerCell(view);
|
|
88
90
|
store.set(findReplaceAtom, {
|
|
89
91
|
type: "setCurrentView",
|
|
90
92
|
view,
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
import { python } from "@codemirror/lang-python";
|
|
4
4
|
import { EditorState } from "@codemirror/state";
|
|
5
5
|
import { EditorView } from "@codemirror/view";
|
|
6
|
-
import { afterEach, describe, expect, test } from "vitest";
|
|
6
|
+
import { afterEach, describe, expect, test, vi } from "vitest";
|
|
7
7
|
import { goToVariableDefinition } from "../commands";
|
|
8
8
|
|
|
9
9
|
async function tick(): Promise<void> {
|
|
10
10
|
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
function createEditor(content: string) {
|
|
13
|
+
function createEditor(content: string, parent: HTMLElement = document.body) {
|
|
14
14
|
const state = EditorState.create({
|
|
15
15
|
doc: content,
|
|
16
16
|
extensions: [python()],
|
|
@@ -18,7 +18,7 @@ function createEditor(content: string) {
|
|
|
18
18
|
|
|
19
19
|
const view = new EditorView({
|
|
20
20
|
state,
|
|
21
|
-
parent
|
|
21
|
+
parent,
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
return view;
|
|
@@ -383,6 +383,27 @@ print('myVar')`);
|
|
|
383
383
|
"
|
|
384
384
|
`);
|
|
385
385
|
});
|
|
386
|
+
|
|
387
|
+
test("scrolls the cell owning the definition into view", async () => {
|
|
388
|
+
const cell = document.createElement("div");
|
|
389
|
+
cell.className = "marimo-cell";
|
|
390
|
+
// jsdom doesn't implement scrollIntoView.
|
|
391
|
+
cell.scrollIntoView = vi.fn();
|
|
392
|
+
document.body.append(cell);
|
|
393
|
+
|
|
394
|
+
view = createEditor("myVar = 10\nprint(myVar)", cell);
|
|
395
|
+
expect(goToVariableDefinition(view, "myVar")).toBe(true);
|
|
396
|
+
// The jump and the scroll are both deferred to the next frame.
|
|
397
|
+
await tick();
|
|
398
|
+
|
|
399
|
+
expect(cell.scrollIntoView).toHaveBeenCalledWith({
|
|
400
|
+
behavior: "instant",
|
|
401
|
+
block: "nearest",
|
|
402
|
+
inline: "nearest",
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
cell.remove();
|
|
406
|
+
});
|
|
386
407
|
});
|
|
387
408
|
|
|
388
409
|
/**
|
|
@@ -4,19 +4,13 @@ import { syntaxTree } from "@codemirror/language";
|
|
|
4
4
|
import type { EditorState } from "@codemirror/state";
|
|
5
5
|
import { EditorView } from "@codemirror/view";
|
|
6
6
|
import type { SyntaxNode, Tree, TreeCursor } from "@lezer/common";
|
|
7
|
+
import { PyKeyword, PyNode, SCOPE_CREATING_NODES } from "../python-node-names";
|
|
8
|
+
import { scrollOwnerCell } from "../utils";
|
|
7
9
|
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
"LambdaExpression",
|
|
11
|
-
"ArrayComprehensionExpression",
|
|
12
|
-
"SetComprehensionExpression",
|
|
13
|
-
"DictionaryComprehensionExpression",
|
|
14
|
-
"ComprehensionExpression",
|
|
15
|
-
"ClassDefinition",
|
|
10
|
+
const POSITION_SENSITIVE_SCOPES: ReadonlySet<string> = new Set([
|
|
11
|
+
PyNode.ClassDefinition,
|
|
16
12
|
]);
|
|
17
13
|
|
|
18
|
-
const POSITION_SENSITIVE_SCOPES = new Set(["ClassDefinition"]);
|
|
19
|
-
|
|
20
14
|
interface ScopeContext {
|
|
21
15
|
id: number;
|
|
22
16
|
type: string;
|
|
@@ -45,6 +39,8 @@ function goToPosition(view: EditorView, from: number): void {
|
|
|
45
39
|
}),
|
|
46
40
|
});
|
|
47
41
|
});
|
|
42
|
+
|
|
43
|
+
scrollOwnerCell(view);
|
|
48
44
|
}
|
|
49
45
|
|
|
50
46
|
function findFirstMatchingVariable(
|
|
@@ -62,14 +58,14 @@ function findFirstMatchingVariable(
|
|
|
62
58
|
}
|
|
63
59
|
|
|
64
60
|
if (
|
|
65
|
-
node.name ===
|
|
61
|
+
node.name === PyNode.VariableName &&
|
|
66
62
|
state.doc.sliceString(node.from, node.to) === variableName
|
|
67
63
|
) {
|
|
68
64
|
from = node.from;
|
|
69
65
|
return false;
|
|
70
66
|
}
|
|
71
67
|
|
|
72
|
-
if (node.name ===
|
|
68
|
+
if (node.name === PyNode.Comment || node.name === PyNode.String) {
|
|
73
69
|
return false;
|
|
74
70
|
}
|
|
75
71
|
|
|
@@ -89,10 +85,12 @@ function getScopeChain(tree: Tree, usagePosition: number): ScopeContext[] {
|
|
|
89
85
|
// Skip ClassDefinition if we've already seen a function/lambda.
|
|
90
86
|
const inFunctionLikeScope = scopeChain.some(
|
|
91
87
|
(scope) =>
|
|
92
|
-
scope.type ===
|
|
93
|
-
scope.type ===
|
|
88
|
+
scope.type === PyNode.FunctionDefinition ||
|
|
89
|
+
scope.type === PyNode.LambdaExpression,
|
|
94
90
|
);
|
|
95
|
-
if (
|
|
91
|
+
if (
|
|
92
|
+
!(inFunctionLikeScope && currentNode.name === PyNode.ClassDefinition)
|
|
93
|
+
) {
|
|
96
94
|
scopeChain.push({
|
|
97
95
|
id: currentNode.from,
|
|
98
96
|
type: currentNode.name,
|
|
@@ -127,30 +125,27 @@ function traverseChildren(
|
|
|
127
125
|
|
|
128
126
|
function collectMatchingTargets(
|
|
129
127
|
cursor: TreeCursor,
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
128
|
+
options: {
|
|
129
|
+
state: EditorState;
|
|
130
|
+
variableName: string;
|
|
131
|
+
scopeId: number;
|
|
132
|
+
declarations: VariableDeclaration[];
|
|
133
|
+
},
|
|
134
134
|
) {
|
|
135
|
+
const { state, variableName, scopeId, declarations } = options;
|
|
135
136
|
switch (cursor.name) {
|
|
136
|
-
case
|
|
137
|
+
case PyNode.VariableName:
|
|
137
138
|
if (state.doc.sliceString(cursor.from, cursor.to) === variableName) {
|
|
138
139
|
addDeclaration(declarations, scopeId, cursor.from);
|
|
139
140
|
}
|
|
140
141
|
break;
|
|
141
142
|
|
|
142
|
-
case
|
|
143
|
-
case
|
|
143
|
+
case PyNode.TupleExpression:
|
|
144
|
+
case PyNode.ArrayExpression: {
|
|
144
145
|
const childCursor = cursor.node.cursor();
|
|
145
146
|
childCursor.firstChild();
|
|
146
147
|
do {
|
|
147
|
-
collectMatchingTargets(
|
|
148
|
-
childCursor,
|
|
149
|
-
state,
|
|
150
|
-
variableName,
|
|
151
|
-
scopeId,
|
|
152
|
-
declarations,
|
|
153
|
-
);
|
|
148
|
+
collectMatchingTargets(childCursor, options);
|
|
154
149
|
} while (childCursor.nextSibling());
|
|
155
150
|
break;
|
|
156
151
|
}
|
|
@@ -161,15 +156,18 @@ function collectMatchingTargets(
|
|
|
161
156
|
|
|
162
157
|
function collectFunctionParameters(
|
|
163
158
|
node: SyntaxNode | Tree,
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
159
|
+
options: {
|
|
160
|
+
state: EditorState;
|
|
161
|
+
variableName: string;
|
|
162
|
+
scopeId: number;
|
|
163
|
+
declarations: VariableDeclaration[];
|
|
164
|
+
},
|
|
168
165
|
) {
|
|
166
|
+
const { state, variableName, scopeId, declarations } = options;
|
|
169
167
|
const cursor = node.cursor();
|
|
170
168
|
cursor.firstChild();
|
|
171
169
|
do {
|
|
172
|
-
if (cursor.name !==
|
|
170
|
+
if (cursor.name !== PyNode.ParamList) {
|
|
173
171
|
continue;
|
|
174
172
|
}
|
|
175
173
|
|
|
@@ -177,7 +175,7 @@ function collectFunctionParameters(
|
|
|
177
175
|
paramCursor.firstChild();
|
|
178
176
|
do {
|
|
179
177
|
if (
|
|
180
|
-
paramCursor.name ===
|
|
178
|
+
paramCursor.name === PyNode.VariableName &&
|
|
181
179
|
state.doc.sliceString(paramCursor.from, paramCursor.to) === variableName
|
|
182
180
|
) {
|
|
183
181
|
addDeclaration(declarations, scopeId, paramCursor.from);
|
|
@@ -188,38 +186,37 @@ function collectFunctionParameters(
|
|
|
188
186
|
|
|
189
187
|
function collectForTargets(
|
|
190
188
|
node: SyntaxNode | Tree,
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
189
|
+
options: {
|
|
190
|
+
state: EditorState;
|
|
191
|
+
variableName: string;
|
|
192
|
+
scopeId: number;
|
|
193
|
+
declarations: VariableDeclaration[];
|
|
194
|
+
},
|
|
195
195
|
) {
|
|
196
196
|
const cursor = node.cursor();
|
|
197
197
|
cursor.firstChild();
|
|
198
198
|
let foundFor = false;
|
|
199
199
|
do {
|
|
200
|
-
if (cursor.name ===
|
|
200
|
+
if (cursor.name === PyKeyword.For) {
|
|
201
201
|
foundFor = true;
|
|
202
|
-
} else if (foundFor && cursor.name ===
|
|
202
|
+
} else if (foundFor && cursor.name === PyKeyword.In) {
|
|
203
203
|
break;
|
|
204
204
|
} else if (foundFor) {
|
|
205
|
-
collectMatchingTargets(
|
|
206
|
-
cursor,
|
|
207
|
-
state,
|
|
208
|
-
variableName,
|
|
209
|
-
scopeId,
|
|
210
|
-
declarations,
|
|
211
|
-
);
|
|
205
|
+
collectMatchingTargets(cursor, options);
|
|
212
206
|
}
|
|
213
207
|
} while (cursor.nextSibling());
|
|
214
208
|
}
|
|
215
209
|
|
|
216
210
|
function collectMatchingDeclarations(
|
|
217
211
|
node: SyntaxNode | Tree,
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
212
|
+
options: {
|
|
213
|
+
state: EditorState;
|
|
214
|
+
variableName: string;
|
|
215
|
+
scopeStack: number[];
|
|
216
|
+
declarations: VariableDeclaration[];
|
|
217
|
+
},
|
|
222
218
|
) {
|
|
219
|
+
const { state, variableName, scopeStack, declarations } = options;
|
|
223
220
|
const cursor = node.cursor();
|
|
224
221
|
const nodeName = cursor.name;
|
|
225
222
|
const nodeStart = cursor.from;
|
|
@@ -231,13 +228,13 @@ function collectMatchingDeclarations(
|
|
|
231
228
|
const currentScope = currentScopeStack[currentScopeStack.length - 1] ?? -1;
|
|
232
229
|
|
|
233
230
|
switch (nodeName) {
|
|
234
|
-
case
|
|
235
|
-
case
|
|
231
|
+
case PyNode.FunctionDefinition:
|
|
232
|
+
case PyNode.ClassDefinition: {
|
|
236
233
|
const subCursor = node.cursor();
|
|
237
234
|
subCursor.firstChild();
|
|
238
235
|
do {
|
|
239
236
|
if (
|
|
240
|
-
subCursor.name ===
|
|
237
|
+
subCursor.name === PyNode.VariableName &&
|
|
241
238
|
state.doc.sliceString(subCursor.from, subCursor.to) === variableName
|
|
242
239
|
) {
|
|
243
240
|
const parentScope = scopeStack[scopeStack.length - 1] ?? -1;
|
|
@@ -246,41 +243,44 @@ function collectMatchingDeclarations(
|
|
|
246
243
|
}
|
|
247
244
|
} while (subCursor.nextSibling());
|
|
248
245
|
|
|
249
|
-
if (nodeName ===
|
|
250
|
-
collectFunctionParameters(
|
|
251
|
-
node,
|
|
246
|
+
if (nodeName === PyNode.FunctionDefinition) {
|
|
247
|
+
collectFunctionParameters(node, {
|
|
252
248
|
state,
|
|
253
249
|
variableName,
|
|
254
|
-
nodeStart,
|
|
250
|
+
scopeId: nodeStart,
|
|
255
251
|
declarations,
|
|
256
|
-
);
|
|
252
|
+
});
|
|
257
253
|
}
|
|
258
254
|
break;
|
|
259
255
|
}
|
|
260
|
-
case
|
|
261
|
-
collectFunctionParameters(
|
|
262
|
-
node,
|
|
256
|
+
case PyNode.LambdaExpression:
|
|
257
|
+
collectFunctionParameters(node, {
|
|
263
258
|
state,
|
|
264
259
|
variableName,
|
|
265
|
-
nodeStart,
|
|
260
|
+
scopeId: nodeStart,
|
|
266
261
|
declarations,
|
|
267
|
-
);
|
|
262
|
+
});
|
|
268
263
|
break;
|
|
269
264
|
|
|
270
|
-
case
|
|
271
|
-
case
|
|
272
|
-
case
|
|
273
|
-
case
|
|
274
|
-
case
|
|
275
|
-
collectForTargets(node,
|
|
265
|
+
case PyNode.ArrayComprehensionExpression:
|
|
266
|
+
case PyNode.DictionaryComprehensionExpression:
|
|
267
|
+
case PyNode.SetComprehensionExpression:
|
|
268
|
+
case PyNode.ComprehensionExpression:
|
|
269
|
+
case PyNode.ForStatement:
|
|
270
|
+
collectForTargets(node, {
|
|
271
|
+
state,
|
|
272
|
+
variableName,
|
|
273
|
+
scopeId: currentScope,
|
|
274
|
+
declarations,
|
|
275
|
+
});
|
|
276
276
|
break;
|
|
277
277
|
|
|
278
|
-
case
|
|
278
|
+
case PyNode.AssignStatement: {
|
|
279
279
|
const assignOpPositions: number[] = [];
|
|
280
280
|
const subCursor = node.cursor();
|
|
281
281
|
subCursor.firstChild();
|
|
282
282
|
do {
|
|
283
|
-
if (subCursor.name ===
|
|
283
|
+
if (subCursor.name === PyNode.AssignOp) {
|
|
284
284
|
assignOpPositions.push(subCursor.from);
|
|
285
285
|
}
|
|
286
286
|
} while (subCursor.nextSibling());
|
|
@@ -295,18 +295,17 @@ function collectMatchingDeclarations(
|
|
|
295
295
|
targetCursor.firstChild();
|
|
296
296
|
do {
|
|
297
297
|
if (targetCursor.from < lastAssignOpPosition) {
|
|
298
|
-
collectMatchingTargets(
|
|
299
|
-
targetCursor,
|
|
298
|
+
collectMatchingTargets(targetCursor, {
|
|
300
299
|
state,
|
|
301
300
|
variableName,
|
|
302
|
-
currentScope,
|
|
301
|
+
scopeId: currentScope,
|
|
303
302
|
declarations,
|
|
304
|
-
);
|
|
303
|
+
});
|
|
305
304
|
}
|
|
306
305
|
} while (targetCursor.nextSibling());
|
|
307
306
|
break;
|
|
308
307
|
}
|
|
309
|
-
case
|
|
308
|
+
case PyNode.ImportStatement: {
|
|
310
309
|
// The grammar emits one ImportStatement for both `import x [as y]` and
|
|
311
310
|
// `from m import x [as y], ...`. Direct children include the keywords
|
|
312
311
|
// (`from`/`import`/`as`), commas, dots, and every VariableName from the
|
|
@@ -327,19 +326,19 @@ function collectMatchingDeclarations(
|
|
|
327
326
|
pending = null;
|
|
328
327
|
};
|
|
329
328
|
do {
|
|
330
|
-
if (subCursor.name ===
|
|
329
|
+
if (subCursor.name === PyKeyword.Import) {
|
|
331
330
|
pastImport = true;
|
|
332
331
|
continue;
|
|
333
332
|
}
|
|
334
333
|
if (!pastImport) {
|
|
335
334
|
continue;
|
|
336
335
|
}
|
|
337
|
-
if (subCursor.name ===
|
|
336
|
+
if (subCursor.name === PyKeyword.As) {
|
|
338
337
|
// Next VariableName is the alias and replaces `pending`.
|
|
339
338
|
pending = null;
|
|
340
339
|
continue;
|
|
341
340
|
}
|
|
342
|
-
if (subCursor.name ===
|
|
341
|
+
if (subCursor.name === PyNode.VariableName) {
|
|
343
342
|
// Flush any previous pending name (no `as` followed it).
|
|
344
343
|
commit();
|
|
345
344
|
pending = {
|
|
@@ -355,17 +354,17 @@ function collectMatchingDeclarations(
|
|
|
355
354
|
commit();
|
|
356
355
|
break;
|
|
357
356
|
}
|
|
358
|
-
case
|
|
359
|
-
case
|
|
357
|
+
case PyNode.TryStatement:
|
|
358
|
+
case PyNode.WithStatement: {
|
|
360
359
|
const subCursor = node.cursor();
|
|
361
360
|
subCursor.firstChild();
|
|
362
361
|
let foundAs = false;
|
|
363
362
|
do {
|
|
364
|
-
if (subCursor.name ===
|
|
363
|
+
if (subCursor.name === PyKeyword.As) {
|
|
365
364
|
foundAs = true;
|
|
366
365
|
} else if (
|
|
367
366
|
foundAs &&
|
|
368
|
-
subCursor.name ===
|
|
367
|
+
subCursor.name === PyNode.VariableName &&
|
|
369
368
|
state.doc.sliceString(subCursor.from, subCursor.to) === variableName
|
|
370
369
|
) {
|
|
371
370
|
addDeclaration(declarations, currentScope, subCursor.from);
|
|
@@ -379,13 +378,12 @@ function collectMatchingDeclarations(
|
|
|
379
378
|
}
|
|
380
379
|
|
|
381
380
|
traverseChildren(cursor, (childNode) => {
|
|
382
|
-
collectMatchingDeclarations(
|
|
383
|
-
childNode,
|
|
381
|
+
collectMatchingDeclarations(childNode, {
|
|
384
382
|
state,
|
|
385
383
|
variableName,
|
|
386
|
-
currentScopeStack,
|
|
384
|
+
scopeStack: currentScopeStack,
|
|
387
385
|
declarations,
|
|
388
|
-
);
|
|
386
|
+
});
|
|
389
387
|
});
|
|
390
388
|
}
|
|
391
389
|
|
|
@@ -397,7 +395,12 @@ function findScopedDefinitionPosition(
|
|
|
397
395
|
const tree = syntaxTree(state);
|
|
398
396
|
const declarations: VariableDeclaration[] = [];
|
|
399
397
|
|
|
400
|
-
collectMatchingDeclarations(tree,
|
|
398
|
+
collectMatchingDeclarations(tree, {
|
|
399
|
+
state,
|
|
400
|
+
variableName,
|
|
401
|
+
scopeStack: [],
|
|
402
|
+
declarations,
|
|
403
|
+
});
|
|
401
404
|
|
|
402
405
|
const clampedUsagePosition = Math.max(
|
|
403
406
|
0,
|