@marimo-team/islands 0.23.14-dev37 → 0.23.14-dev39
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/{code-visibility-DcykAbWl.js → code-visibility-CqDnWUEQ.js} +1 -1
- package/dist/main.js +2469 -1057
- package/dist/{reveal-component-CotAAD_d.js → reveal-component-BtwLhHQU.js} +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/editor/cell/cell-context-menu.tsx +2 -2
- package/src/components/editor/code/__tests__/readonly-python-code.test.tsx +79 -0
- package/src/components/editor/code/readonly-python-code.tsx +35 -30
- package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +1 -1
- package/src/core/codemirror/go-to-definition/__tests__/utils.test.ts +75 -3
- package/src/core/codemirror/go-to-definition/extension.ts +3 -3
- package/src/core/codemirror/go-to-definition/underline.ts +5 -14
- package/src/core/codemirror/go-to-definition/utils.ts +49 -1
package/package.json
CHANGED
|
@@ -23,7 +23,7 @@ import { toast } from "@/components/ui/use-toast";
|
|
|
23
23
|
import { useCellData, useCellRuntime } from "@/core/cells/cells";
|
|
24
24
|
import { CellOutputId } from "@/core/cells/ids";
|
|
25
25
|
import { isOutputEmpty } from "@/core/cells/outputs";
|
|
26
|
-
import {
|
|
26
|
+
import { goToDefinitionWithLspFallback } from "@/core/codemirror/go-to-definition/utils";
|
|
27
27
|
import { sendToPanelManager } from "@/core/vscode/vscode-bindings";
|
|
28
28
|
import { copyImageToClipboard, copyToClipboard } from "@/utils/copy";
|
|
29
29
|
import { getImageExtension } from "@/utils/filenames";
|
|
@@ -170,7 +170,7 @@ export const CellActionsContextMenu = ({
|
|
|
170
170
|
// Only suppress focus restoration when we actually navigated;
|
|
171
171
|
// otherwise let Radix return focus to the trigger cell.
|
|
172
172
|
suppressCloseAutoFocus.current =
|
|
173
|
-
|
|
173
|
+
goToDefinitionWithLspFallback(editorView);
|
|
174
174
|
}
|
|
175
175
|
},
|
|
176
176
|
},
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
4
|
+
import { beforeAll, describe, expect, it } from "vitest";
|
|
5
|
+
import { SetupMocks } from "@/__mocks__/common";
|
|
6
|
+
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
7
|
+
import { ReadonlyCode } from "../readonly-python-code";
|
|
8
|
+
|
|
9
|
+
beforeAll(() => {
|
|
10
|
+
SetupMocks.resizeObserver();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The only button is the show/hide toggle: copy is disabled and the
|
|
15
|
+
* insert-cell button is off by default.
|
|
16
|
+
*/
|
|
17
|
+
function renderReadonly(props: { initiallyHideCode?: boolean }) {
|
|
18
|
+
return render(
|
|
19
|
+
<TooltipProvider>
|
|
20
|
+
<ReadonlyCode code="x = 1" showCopyCode={false} {...props} />
|
|
21
|
+
</TooltipProvider>,
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function isCollapsed(root: ParentNode) {
|
|
26
|
+
return root.querySelector(".cm")?.classList.contains("opacity-20") ?? false;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe("ReadonlyCode", () => {
|
|
30
|
+
it("starts collapsed when initiallyHideCode is true", () => {
|
|
31
|
+
const { container } = renderReadonly({ initiallyHideCode: true });
|
|
32
|
+
expect(isCollapsed(container)).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("starts expanded when initiallyHideCode is false", () => {
|
|
36
|
+
const { container } = renderReadonly({ initiallyHideCode: false });
|
|
37
|
+
expect(isCollapsed(container)).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("starts expanded when initiallyHideCode is unset", () => {
|
|
41
|
+
const { container } = renderReadonly({});
|
|
42
|
+
expect(isCollapsed(container)).toBe(false);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("toggles visibility locally on click", () => {
|
|
46
|
+
const { container } = renderReadonly({ initiallyHideCode: true });
|
|
47
|
+
const toggle = screen.getByRole("button");
|
|
48
|
+
|
|
49
|
+
fireEvent.click(toggle);
|
|
50
|
+
expect(isCollapsed(container)).toBe(false);
|
|
51
|
+
|
|
52
|
+
fireEvent.click(toggle);
|
|
53
|
+
expect(isCollapsed(container)).toBe(true);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("keeps each instance's visibility independent", () => {
|
|
57
|
+
const { container } = render(
|
|
58
|
+
<TooltipProvider>
|
|
59
|
+
<ReadonlyCode
|
|
60
|
+
code="a = 1"
|
|
61
|
+
showCopyCode={false}
|
|
62
|
+
initiallyHideCode={true}
|
|
63
|
+
/>
|
|
64
|
+
<ReadonlyCode
|
|
65
|
+
code="b = 2"
|
|
66
|
+
showCopyCode={false}
|
|
67
|
+
initiallyHideCode={true}
|
|
68
|
+
/>
|
|
69
|
+
</TooltipProvider>,
|
|
70
|
+
);
|
|
71
|
+
const [firstToggle] = screen.getAllByRole("button");
|
|
72
|
+
const [first, second] = container.querySelectorAll(".cm");
|
|
73
|
+
|
|
74
|
+
fireEvent.click(firstToggle);
|
|
75
|
+
|
|
76
|
+
expect(first.classList.contains("opacity-20")).toBe(false);
|
|
77
|
+
expect(second.classList.contains("opacity-20")).toBe(true);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -2,18 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
import { markdown } from "@codemirror/lang-markdown";
|
|
4
4
|
import { sql } from "@codemirror/lang-sql";
|
|
5
|
+
import {
|
|
6
|
+
defaultHighlightStyle,
|
|
7
|
+
syntaxHighlighting,
|
|
8
|
+
} from "@codemirror/language";
|
|
5
9
|
import CodeMirror, {
|
|
6
10
|
EditorView,
|
|
7
11
|
type ReactCodeMirrorProps,
|
|
8
12
|
} from "@uiw/react-codemirror";
|
|
9
13
|
import { CopyIcon, EyeIcon, EyeOffIcon, PlusIcon } from "lucide-react";
|
|
10
|
-
import { memo, useState } from "react";
|
|
14
|
+
import { memo, useMemo, useState } from "react";
|
|
11
15
|
import { useAddCodeToNewCell } from "@/components/editor/cell/useAddCell";
|
|
12
16
|
import { Button } from "@/components/ui/button";
|
|
13
17
|
import { Tooltip } from "@/components/ui/tooltip";
|
|
14
18
|
import { toast } from "@/components/ui/use-toast";
|
|
15
19
|
import type { LanguageAdapterType } from "@/core/codemirror/language/types";
|
|
16
20
|
import { customPythonLanguageSupport } from "@/core/codemirror/language/languages/python";
|
|
21
|
+
import { darkTheme } from "@/core/codemirror/theme/dark";
|
|
22
|
+
import { lightTheme } from "@/core/codemirror/theme/light";
|
|
17
23
|
import { useTheme } from "@/theme/useTheme";
|
|
18
24
|
import { cn } from "@/utils/cn";
|
|
19
25
|
import { copyToClipboard } from "@/utils/copy";
|
|
@@ -72,33 +78,39 @@ export const ReadonlyCode = memo(
|
|
|
72
78
|
} = props;
|
|
73
79
|
const [hideCode, setHideCode] = useState(initiallyHideCode);
|
|
74
80
|
|
|
81
|
+
const extensions = useMemo(
|
|
82
|
+
() => [
|
|
83
|
+
theme === "dark" ? darkTheme : lightTheme,
|
|
84
|
+
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
|
|
85
|
+
...readonlyCodeExtensions(language),
|
|
86
|
+
],
|
|
87
|
+
[theme, language],
|
|
88
|
+
);
|
|
89
|
+
|
|
75
90
|
return (
|
|
76
91
|
<div
|
|
77
92
|
className={cn(
|
|
78
|
-
"relative hover-actions-parent w-full overflow-hidden",
|
|
93
|
+
"relative hover-actions-parent w-full overflow-hidden pb-1",
|
|
79
94
|
className,
|
|
80
95
|
)}
|
|
81
96
|
>
|
|
82
|
-
{showHideCode && hideCode && (
|
|
83
|
-
<HideCodeButton
|
|
84
|
-
tooltip="Show code"
|
|
85
|
-
onClick={() => setHideCode(false)}
|
|
86
|
-
/>
|
|
87
|
-
)}
|
|
88
97
|
<div className="absolute top-0 right-0 my-1 mx-2 z-10 hover-action flex gap-2">
|
|
89
98
|
{showCopyCode && <CopyButton text={code} />}
|
|
90
99
|
{insertNewCell && <InsertNewCell code={code} />}
|
|
91
|
-
{showHideCode &&
|
|
92
|
-
<
|
|
100
|
+
{showHideCode && (
|
|
101
|
+
<ToggleCodeButton
|
|
102
|
+
hidden={hideCode ?? false}
|
|
103
|
+
onClick={() => setHideCode(!hideCode)}
|
|
104
|
+
/>
|
|
93
105
|
)}
|
|
94
106
|
</div>
|
|
95
107
|
<CodeMirror
|
|
96
108
|
{...rest}
|
|
97
109
|
className={cn("cm", hideCode && "opacity-20 h-8 overflow-hidden")}
|
|
98
|
-
theme=
|
|
110
|
+
theme="none"
|
|
99
111
|
height="100%"
|
|
100
|
-
editable={
|
|
101
|
-
extensions={
|
|
112
|
+
editable={false}
|
|
113
|
+
extensions={extensions}
|
|
102
114
|
value={code}
|
|
103
115
|
readOnly={true}
|
|
104
116
|
/>
|
|
@@ -123,35 +135,28 @@ const CopyButton = (props: { text: string }) => {
|
|
|
123
135
|
);
|
|
124
136
|
};
|
|
125
137
|
|
|
126
|
-
const
|
|
138
|
+
const ToggleCodeButton = (props: { hidden: boolean; onClick: () => void }) => {
|
|
127
139
|
return (
|
|
128
|
-
<Tooltip
|
|
140
|
+
<Tooltip
|
|
141
|
+
content={props.hidden ? "Show code" : "Hide code"}
|
|
142
|
+
usePortal={false}
|
|
143
|
+
>
|
|
129
144
|
<Button
|
|
130
145
|
onClick={props.onClick}
|
|
131
146
|
size="xs"
|
|
132
147
|
className="py-0"
|
|
133
148
|
variant="secondary"
|
|
134
149
|
>
|
|
135
|
-
|
|
150
|
+
{props.hidden ? (
|
|
151
|
+
<EyeIcon size={14} strokeWidth={1.5} />
|
|
152
|
+
) : (
|
|
153
|
+
<EyeOffIcon size={14} strokeWidth={1.5} />
|
|
154
|
+
)}
|
|
136
155
|
</Button>
|
|
137
156
|
</Tooltip>
|
|
138
157
|
);
|
|
139
158
|
};
|
|
140
159
|
|
|
141
|
-
export const HideCodeButton = (props: {
|
|
142
|
-
tooltip?: string;
|
|
143
|
-
className?: string;
|
|
144
|
-
onClick: () => void;
|
|
145
|
-
}) => {
|
|
146
|
-
return (
|
|
147
|
-
<div className={props.className} onClick={props.onClick}>
|
|
148
|
-
<Tooltip usePortal={false} content={props.tooltip}>
|
|
149
|
-
<EyeIcon className="hover-action w-5 h-5 text-muted-foreground cursor-pointer absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 opacity-80 hover:opacity-100 z-20" />
|
|
150
|
-
</Tooltip>
|
|
151
|
-
</div>
|
|
152
|
-
);
|
|
153
|
-
};
|
|
154
|
-
|
|
155
160
|
const InsertNewCell = (props: { code: string }) => {
|
|
156
161
|
const addCodeToNewCell = useAddCodeToNewCell();
|
|
157
162
|
|
|
@@ -2,13 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
import { python } from "@codemirror/lang-python";
|
|
4
4
|
import { EditorState } from "@codemirror/state";
|
|
5
|
-
import { EditorView } from "@codemirror/view";
|
|
6
|
-
import { afterEach, describe, expect, test } from "vitest";
|
|
5
|
+
import { EditorView, keymap } from "@codemirror/view";
|
|
6
|
+
import { afterEach, describe, expect, test, vi } from "vitest";
|
|
7
7
|
import { cellId, variableName } from "@/__tests__/branded";
|
|
8
8
|
import { initialNotebookState, notebookAtom } from "@/core/cells/cells";
|
|
9
9
|
import { store } from "@/core/state/jotai";
|
|
10
10
|
import { variablesAtom } from "@/core/variables/state";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
goToDefinitionAtCursorPosition,
|
|
13
|
+
goToDefinitionWithLspFallback,
|
|
14
|
+
requestLspGoToDefinition,
|
|
15
|
+
} from "../utils";
|
|
12
16
|
|
|
13
17
|
async function tick(): Promise<void> {
|
|
14
18
|
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
@@ -181,3 +185,71 @@ print(mymodule)`;
|
|
|
181
185
|
);
|
|
182
186
|
});
|
|
183
187
|
});
|
|
188
|
+
|
|
189
|
+
describe("goToDefinitionWithLspFallback", () => {
|
|
190
|
+
test("falls through to LSP when marimo cannot resolve the symbol", () => {
|
|
191
|
+
const lspGoToDefinition = vi.fn(() => true);
|
|
192
|
+
const view = new EditorView({
|
|
193
|
+
state: EditorState.create({
|
|
194
|
+
doc: "parser.add_argument('--foo')",
|
|
195
|
+
selection: { anchor: "parser.add_argument".indexOf("add_argument") },
|
|
196
|
+
extensions: [
|
|
197
|
+
python(),
|
|
198
|
+
keymap.of([{ key: "F12", run: lspGoToDefinition }]),
|
|
199
|
+
],
|
|
200
|
+
}),
|
|
201
|
+
parent: document.body,
|
|
202
|
+
});
|
|
203
|
+
views.push(view);
|
|
204
|
+
|
|
205
|
+
const result = goToDefinitionWithLspFallback(view);
|
|
206
|
+
|
|
207
|
+
expect(result).toBe(true);
|
|
208
|
+
expect(lspGoToDefinition).toHaveBeenCalledOnce();
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test("does not invoke LSP when marimo resolves the symbol", async () => {
|
|
212
|
+
const lspGoToDefinition = vi.fn(() => true);
|
|
213
|
+
const code = "a = 10\nprint(a)";
|
|
214
|
+
const view = new EditorView({
|
|
215
|
+
state: EditorState.create({
|
|
216
|
+
doc: code,
|
|
217
|
+
selection: { anchor: code.indexOf("a", 3) },
|
|
218
|
+
extensions: [
|
|
219
|
+
python(),
|
|
220
|
+
keymap.of([{ key: "F12", run: lspGoToDefinition }]),
|
|
221
|
+
],
|
|
222
|
+
}),
|
|
223
|
+
parent: document.body,
|
|
224
|
+
});
|
|
225
|
+
views.push(view);
|
|
226
|
+
|
|
227
|
+
const result = goToDefinitionWithLspFallback(view);
|
|
228
|
+
|
|
229
|
+
expect(result).toBe(true);
|
|
230
|
+
expect(lspGoToDefinition).not.toHaveBeenCalled();
|
|
231
|
+
await tick();
|
|
232
|
+
expect(view.state.selection.main.head).toBe(0);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
test("falls through with a modified shortcut like Ctrl-F12", () => {
|
|
236
|
+
const lspGoToDefinition = vi.fn(() => true);
|
|
237
|
+
const view = new EditorView({
|
|
238
|
+
state: EditorState.create({
|
|
239
|
+
doc: "parser.add_argument('--foo')",
|
|
240
|
+
selection: { anchor: "parser.add_argument".indexOf("add_argument") },
|
|
241
|
+
extensions: [
|
|
242
|
+
python(),
|
|
243
|
+
keymap.of([{ key: "Ctrl-F12", run: lspGoToDefinition }]),
|
|
244
|
+
],
|
|
245
|
+
}),
|
|
246
|
+
parent: document.body,
|
|
247
|
+
});
|
|
248
|
+
views.push(view);
|
|
249
|
+
|
|
250
|
+
const result = requestLspGoToDefinition(view, "Ctrl-F12");
|
|
251
|
+
|
|
252
|
+
expect(result).toBe(true);
|
|
253
|
+
expect(lspGoToDefinition).toHaveBeenCalledOnce();
|
|
254
|
+
});
|
|
255
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
import { EditorView } from "@codemirror/view";
|
|
3
3
|
import { createUnderlinePlugin, underlineField } from "./underline";
|
|
4
|
-
import {
|
|
4
|
+
import { goToDefinitionWithLspFallback } from "./utils";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Create a go-to-definition extension.
|
|
@@ -9,8 +9,8 @@ import { goToDefinition } from "./utils";
|
|
|
9
9
|
export function goToDefinitionBundle() {
|
|
10
10
|
return [
|
|
11
11
|
underlineField,
|
|
12
|
-
createUnderlinePlugin((view
|
|
13
|
-
|
|
12
|
+
createUnderlinePlugin((view) => {
|
|
13
|
+
goToDefinitionWithLspFallback(view);
|
|
14
14
|
}),
|
|
15
15
|
EditorView.baseTheme({
|
|
16
16
|
".underline": {
|
|
@@ -55,12 +55,9 @@ class MetaUnderlineVariablePlugin {
|
|
|
55
55
|
private view: EditorView;
|
|
56
56
|
private commandClickMode: boolean;
|
|
57
57
|
private hoveredRange: { from: number; to: number; position: number } | null;
|
|
58
|
-
private onClick: (view: EditorView
|
|
58
|
+
private onClick: (view: EditorView) => void;
|
|
59
59
|
|
|
60
|
-
constructor(
|
|
61
|
-
view: EditorView,
|
|
62
|
-
onClick: (view: EditorView, variableName: string) => void,
|
|
63
|
-
) {
|
|
60
|
+
constructor(view: EditorView, onClick: (view: EditorView) => void) {
|
|
64
61
|
this.view = view;
|
|
65
62
|
this.commandClickMode = false;
|
|
66
63
|
this.hoveredRange = null;
|
|
@@ -191,20 +188,16 @@ class MetaUnderlineVariablePlugin {
|
|
|
191
188
|
// If we have a hovered range, go to it
|
|
192
189
|
private click = (event: MouseEvent) => {
|
|
193
190
|
if (this.hoveredRange) {
|
|
194
|
-
const variableName = this.view.state.doc.sliceString(
|
|
195
|
-
this.hoveredRange.from,
|
|
196
|
-
this.hoveredRange.to,
|
|
197
|
-
);
|
|
198
191
|
event.preventDefault();
|
|
199
192
|
event.stopPropagation();
|
|
200
|
-
|
|
201
|
-
// Move the cursor to the clicked position
|
|
193
|
+
// Move the cursor before resolving so LSP uses the clicked position.
|
|
202
194
|
this.view.dispatch({
|
|
203
195
|
selection: {
|
|
204
196
|
head: this.hoveredRange.position,
|
|
205
197
|
anchor: this.hoveredRange.position,
|
|
206
198
|
},
|
|
207
199
|
});
|
|
200
|
+
this.onClick(this.view);
|
|
208
201
|
}
|
|
209
202
|
};
|
|
210
203
|
|
|
@@ -217,7 +210,5 @@ class MetaUnderlineVariablePlugin {
|
|
|
217
210
|
}
|
|
218
211
|
}
|
|
219
212
|
|
|
220
|
-
export const createUnderlinePlugin = (
|
|
221
|
-
onClick: (view: EditorView, variableName: string) => void,
|
|
222
|
-
) =>
|
|
213
|
+
export const createUnderlinePlugin = (onClick: (view: EditorView) => void) =>
|
|
223
214
|
ViewPlugin.define((view) => new MetaUnderlineVariablePlugin(view, onClick));
|
|
@@ -2,8 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
import { closeCompletion } from "@codemirror/autocomplete";
|
|
4
4
|
import type { EditorState } from "@codemirror/state";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
closeHoverTooltips,
|
|
7
|
+
type EditorView,
|
|
8
|
+
type KeyBinding,
|
|
9
|
+
keymap,
|
|
10
|
+
} from "@codemirror/view";
|
|
6
11
|
import type { CellId } from "@/core/cells/ids";
|
|
12
|
+
import { hotkeysAtom, platformAtom } from "../../config/config";
|
|
7
13
|
import { notebookAtom } from "../../cells/cells";
|
|
8
14
|
import { store } from "../../state/jotai";
|
|
9
15
|
import { variablesAtom } from "../../variables/state";
|
|
@@ -11,6 +17,20 @@ import type { VariableName, Variables } from "../../variables/types";
|
|
|
11
17
|
import { getPositionAtWordBounds } from "../completion/hints";
|
|
12
18
|
import { goToLine, goToVariableDefinition } from "./commands";
|
|
13
19
|
|
|
20
|
+
function keymapBindingMatchesHotkey(
|
|
21
|
+
binding: KeyBinding,
|
|
22
|
+
hotkey: string,
|
|
23
|
+
): boolean {
|
|
24
|
+
const platform = store.get(platformAtom);
|
|
25
|
+
const bindingKey =
|
|
26
|
+
platform === "mac"
|
|
27
|
+
? (binding.mac ?? binding.key)
|
|
28
|
+
: platform === "windows"
|
|
29
|
+
? (binding.win ?? binding.key)
|
|
30
|
+
: (binding.linux ?? binding.key);
|
|
31
|
+
return bindingKey === hotkey;
|
|
32
|
+
}
|
|
33
|
+
|
|
14
34
|
/**
|
|
15
35
|
* Get the word under the cursor.
|
|
16
36
|
*/
|
|
@@ -68,6 +88,34 @@ export function goToDefinitionAtCursorPosition(view: EditorView): boolean {
|
|
|
68
88
|
return goToDefinition(view, word, position);
|
|
69
89
|
}
|
|
70
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Invoke the editor's go-to-definition keymap handlers for the configured
|
|
93
|
+
* hotkey. Matches CodeMirror key strings directly (including customized
|
|
94
|
+
* shortcuts like `Ctrl-F12`) instead of synthesizing keyboard events.
|
|
95
|
+
*/
|
|
96
|
+
export function requestLspGoToDefinition(
|
|
97
|
+
view: EditorView,
|
|
98
|
+
hotkey = store.get(hotkeysAtom).getHotkey("cell.goToDefinition").key,
|
|
99
|
+
): boolean {
|
|
100
|
+
for (const binding of view.state.facet(keymap).flat()) {
|
|
101
|
+
if (keymapBindingMatchesHotkey(binding, hotkey) && binding.run?.(view)) {
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Go to the definition under the cursor, falling back to the language server
|
|
110
|
+
* when marimo cannot resolve the symbol (e.g. external library code).
|
|
111
|
+
*/
|
|
112
|
+
export function goToDefinitionWithLspFallback(view: EditorView): boolean {
|
|
113
|
+
if (goToDefinitionAtCursorPosition(view)) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
return requestLspGoToDefinition(view);
|
|
117
|
+
}
|
|
118
|
+
|
|
71
119
|
/**
|
|
72
120
|
* Go to the definition of the variable under the cursor.
|
|
73
121
|
* @param view The editor view at which the command was invoked.
|