mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-13 04:34:21 -10:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0daf8ac15d |
No files matched your search
@@ -221,6 +221,8 @@ pub struct DebuggerSettings {
|
||||
/// Data Views: list variables by name instead of the adapter's order.
|
||||
pub sort_values: bool,
|
||||
pub value_tooltip: bool,
|
||||
/// While suspended, selecting an expression shows its value.
|
||||
pub value_tooltip_on_selection: bool,
|
||||
pub value_tooltip_delay: u32,
|
||||
/// Stepping: do not step into library code (debugpy `justMyCode`, js-debug `skipFiles`).
|
||||
pub skip_library_code: bool,
|
||||
@@ -238,6 +240,7 @@ impl Default for DebuggerSettings {
|
||||
inline_values: true,
|
||||
sort_values: false,
|
||||
value_tooltip: true,
|
||||
value_tooltip_on_selection: true,
|
||||
value_tooltip_delay: 700,
|
||||
skip_library_code: true,
|
||||
python: PythonDebuggerSettings::default(),
|
||||
|
||||
@@ -2239,6 +2239,8 @@ export type DebuggerSettings = {
|
||||
/** Data Views: list variables by name instead of the adapter's order. */
|
||||
sortValues?: boolean,
|
||||
valueTooltip?: boolean,
|
||||
/** While suspended, selecting an expression shows its value. */
|
||||
valueTooltipOnSelection?: boolean,
|
||||
valueTooltipDelay?: number,
|
||||
/** Stepping: do not step into library code (debugpy `justMyCode`, js-debug `skipFiles`). */
|
||||
skipLibraryCode?: boolean,
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { EditorSelection, EditorState } from "@codemirror/state";
|
||||
import { selectionExpression } from "../editor/valueTooltip";
|
||||
import { classifyValue, identifiersIn, inlineValue, sortVariables } from "../values";
|
||||
import { inlineValuesFor } from "../editor/execution";
|
||||
import { frameLabel, groupFrames, isLibraryFrame } from "../frames";
|
||||
@@ -109,3 +111,22 @@ describe("sortVariables", () => {
|
||||
expect(names(sortVariables(items))).toEqual(["[0]", "[1]", "[10]", "[2]"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("selectionExpression", () => {
|
||||
const at = (doc: string, from: number, to: number) =>
|
||||
selectionExpression(EditorState.create({ doc, selection: EditorSelection.single(from, to) }));
|
||||
it("takes a one-line selection", () => {
|
||||
expect(at("total += item.price", 9, 19)).toEqual({ from: 9, text: "item.price" });
|
||||
});
|
||||
it("ignores empty, blank, multi-line and multiple selections", () => {
|
||||
expect(at("a + b", 2, 2)).toBeNull();
|
||||
expect(at("a b", 1, 4)).toBeNull();
|
||||
expect(at("a\nb", 0, 3)).toBeNull();
|
||||
const multi = EditorState.create({
|
||||
doc: "a + b",
|
||||
selection: EditorSelection.create([EditorSelection.range(0, 1), EditorSelection.range(4, 5)]),
|
||||
extensions: EditorState.allowMultipleSelections.of(true),
|
||||
});
|
||||
expect(selectionExpression(multi)).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -3,9 +3,10 @@
|
||||
* while suspended, hovering an expression (or the selection under the mouse)
|
||||
* evaluates it in the selected frame.
|
||||
*/
|
||||
import type { Extension } from "@codemirror/state";
|
||||
import type { EditorState, Extension } from "@codemirror/state";
|
||||
import type { DebugSessionId, Variable } from "@/bindings";
|
||||
import { hoverTooltip, type EditorView } from "@codemirror/view";
|
||||
import { hoverTooltip, ViewPlugin, type EditorView, type ViewUpdate } from "@codemirror/view";
|
||||
import { showHint } from "@/editor/lsp/hint";
|
||||
import { workflowSettings } from "@/platform/workflowSettings";
|
||||
import { navigationModifierHeld } from "@/platform/navigationModifier";
|
||||
import { activeSession, evaluate } from "../state";
|
||||
@@ -109,3 +110,59 @@ export function valueTooltip(): Extension {
|
||||
{ hoverTime: BASE_HOVER },
|
||||
);
|
||||
}
|
||||
|
||||
const SELECTION_DELAY = 400;
|
||||
const MAX_SELECTION = 200;
|
||||
|
||||
/** The selected text when it can be evaluated: one non-blank line, not too long. */
|
||||
export function selectionExpression(state: EditorState): { from: number; text: string } | null {
|
||||
const sel = state.selection;
|
||||
if (sel.ranges.length !== 1 || sel.main.empty) return null;
|
||||
const text = state.sliceDoc(sel.main.from, sel.main.to).trim();
|
||||
if (!text || text.length > MAX_SELECTION || text.includes("\n")) return null;
|
||||
return { from: sel.main.from, text };
|
||||
}
|
||||
|
||||
/**
|
||||
* Settings › Debugger › Data Views › "Show value tooltip on code selection": while
|
||||
* suspended, selecting an expression shows its value once the selection settles.
|
||||
*/
|
||||
export function selectionValueTooltip(): Extension {
|
||||
return ViewPlugin.fromClass(
|
||||
class {
|
||||
private timer: ReturnType<typeof setTimeout> | undefined;
|
||||
private seq = 0;
|
||||
constructor(readonly view: EditorView) {}
|
||||
|
||||
update(u: ViewUpdate) {
|
||||
if (!u.selectionSet) return;
|
||||
clearTimeout(this.timer);
|
||||
this.seq++;
|
||||
if (!u.transactions.some((tr) => tr.isUserEvent("select"))) return;
|
||||
const seq = this.seq;
|
||||
this.timer = setTimeout(() => void this.show(seq), SELECTION_DELAY);
|
||||
}
|
||||
|
||||
private async show(seq: number) {
|
||||
if (!workflowSettings().debugger.valueTooltipOnSelection) return;
|
||||
const session = activeSession();
|
||||
if (!session || session.status !== "paused") return;
|
||||
const expr = selectionExpression(this.view.state);
|
||||
if (!expr) return;
|
||||
let value;
|
||||
try {
|
||||
value = await evaluate(expr.text, "hover", session);
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
// The selection moved on while evaluating.
|
||||
if (seq !== this.seq) return;
|
||||
showHint(this.view, () => valueHint(expr.text, value, session.id), { pos: expr.from, timeout: 60_000 });
|
||||
}
|
||||
|
||||
destroy() {
|
||||
clearTimeout(this.timer);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
import { lazyComponent } from "@/ui";
|
||||
import { onIdeEvent } from "@/platform/ipc";
|
||||
import { useProject } from "@/platform/project";
|
||||
import { valueTooltip } from "./editor/valueTooltip";
|
||||
import { selectionValueTooltip, valueTooltip } from "./editor/valueTooltip";
|
||||
import { registerEditorContribution } from "@/editor/api";
|
||||
import {
|
||||
registerMenuGroup,
|
||||
@@ -65,6 +65,7 @@ export function activate(): () => void {
|
||||
executionPoint(ctx),
|
||||
runToCursorInlay(ctx),
|
||||
valueTooltip(),
|
||||
selectionValueTooltip(),
|
||||
smartStepTargets(ctx),
|
||||
],
|
||||
}),
|
||||
|
||||
@@ -180,6 +180,7 @@ export const EXECUTION_PAGES: PageSpec[] = [
|
||||
label: "Show value tooltip on mouse hover",
|
||||
hint: "Hovering a variable while suspended evaluates it in the selected frame.",
|
||||
},
|
||||
{ kind: "toggle", key: "debugger.valueTooltipOnSelection", label: "Show value tooltip on code selection" },
|
||||
{ kind: "custom", label: "Value tooltip delay (ms)", component: TooltipDelayRow },
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1903,6 +1903,7 @@
|
||||
"Show the selected coverage suite in editors and the project view": "在编辑器和项目视图中显示所选覆盖率套件",
|
||||
"Show tool window bars": "显示工具窗口栏",
|
||||
"Show tool window names": "显示工具窗口名称",
|
||||
"Show value tooltip on code selection": "选中代码时显示值提示",
|
||||
"Show value tooltip on mouse hover": "鼠标悬停时显示值工具提示",
|
||||
"Show values inline": "内联显示值",
|
||||
"Show virtual space at file bottom": "在文件底部显示虚拟空间",
|
||||
|
||||
@@ -85,6 +85,7 @@ export interface DebuggerSettingsValid {
|
||||
inlineValues: boolean;
|
||||
sortValues: boolean;
|
||||
valueTooltip: boolean;
|
||||
valueTooltipOnSelection: boolean;
|
||||
valueTooltipDelay: number;
|
||||
skipLibraryCode: boolean;
|
||||
python: { attachSubprocess: boolean; gevent: boolean };
|
||||
@@ -245,6 +246,7 @@ export const DEFAULT_WORKFLOW: WorkflowSettings = {
|
||||
inlineValues: true,
|
||||
sortValues: false,
|
||||
valueTooltip: true,
|
||||
valueTooltipOnSelection: true,
|
||||
valueTooltipDelay: 700,
|
||||
skipLibraryCode: true,
|
||||
python: { attachSubprocess: true, gevent: false },
|
||||
@@ -380,6 +382,7 @@ export function validateDebugger(raw: unknown): DebuggerSettingsValid {
|
||||
inlineValues: bool(v.inlineValues, d.inlineValues),
|
||||
sortValues: bool(v.sortValues, d.sortValues),
|
||||
valueTooltip: bool(v.valueTooltip, d.valueTooltip),
|
||||
valueTooltipOnSelection: bool(v.valueTooltipOnSelection, d.valueTooltipOnSelection),
|
||||
valueTooltipDelay: num(v.valueTooltipDelay, d.valueTooltipDelay, WORKFLOW_LIMITS.tooltipDelay, true),
|
||||
skipLibraryCode: bool(v.skipLibraryCode, d.skipLibraryCode),
|
||||
python: {
|
||||
|
||||
Reference in new issue
Block a user