дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 19:25:54 +02:00
Project & files - Project view modes (Project Files / Open Files / All Changed Files / Scratches); External Libraries for Python, JDK (src.zip), Node, Cargo, Go, Maven/Gradle jars; read-only jar/zip browsing - ⌘N New popup with type search and more file kinds; New Project, Rename Project, Reload All from Disk, Export/Import Settings, Power Save Mode - File type associations, extra content roots and exclude patterns (indexed and watched without reopening the project) Editor & navigation - Find bar: search scope (comments/strings), Preserve Case, Exclude, multiline, history; Find in Files: Module scope, custom pattern scopes, multiline - Search Everywhere filters, Assign Shortcut, settings results; named bookmark lists, file/folder bookmarks; Structure filters and Show Inherited; Recent Locations timestamps and breadcrumbs; Code Vision author - Completion options, editor tab placement/layout, inline completion (LSP 3.18) - Spell checking (Typo inspection, ide-spell) and Inspections settings with custom profiles; Code Style schemes, formatter markers, Do not format Run, VCS, services, database - Typed run configurations (Shell, Program, npm, Gradle, Maven, Docker, Compound), Modify options, Before launch, env dialog, Current File, Emulate terminal (PTY) - Git log graph/view options, Go to Hash/Branch/Tag, date filter keeps the graph; Pull/Merge/Rebase dialogs, Manage Remotes, Worktrees - Generic Services host (Docker connections/registries, run sessions); TODO scope/changes tabs with changelists; Coverage report import - Data sources: wire-compatible vendors, URL import, SSL certs, Options, Schemas and Advanced tabs, color and comment Workbench - Run Anything, Customize Main Toolbar, named tool window layouts, menu completeness, Code Cleanup, macros, "Don't Show Again", editor banners - Chinese translations for the new UI Claude-Session: https://claude.ai/code/session_01SaPPsVPuk6ZTNsoUCNCbMv
191 рядки
7.9 KiB
TypeScript
191 рядки
7.9 KiB
TypeScript
import { useRef, useState } from "react";
|
|
import clsx from "clsx";
|
|
import { BarButton, Icon, IconButton, Menu, type MenuItem } from "@/ui";
|
|
import { executeAction } from "@/platform/actions";
|
|
import { useContextKeys } from "@/platform/context";
|
|
import { useTx } from "@/platform/i18n";
|
|
import { shortcutLabel } from "@/platform/keymap";
|
|
import { runExecutors, useRunExecutors } from "@/workbench/contributions";
|
|
import { configIcon } from "./configs";
|
|
import { CURRENT_FILE, rerunSession, sessionsOf, startRun, stopSession, useRun } from "./store";
|
|
import styles from "./Run.module.css";
|
|
|
|
/** Title bar: configuration chooser, Run / Debug, and Rerun / Stop while running. */
|
|
export function RunWidget() {
|
|
const tx = useTx();
|
|
const configs = useRun((s) => s.configs);
|
|
const selectedId = useRun((s) => s.selectedId);
|
|
const sessions = useRun((s) => s.sessions);
|
|
const chooserOpen = useRun((s) => s.chooserOpen);
|
|
const selected = configs.find((c) => c.id === selectedId);
|
|
const currentFile = selectedId === CURRENT_FILE;
|
|
const running = sessions.filter((s) => s.status === "running" || s.status === "starting");
|
|
// A compound is running while any of its configurations is; Stop stops them all.
|
|
const compoundRunning = selected?.kind === "compound" ? sessionsOf(selected, running) : [];
|
|
const runningSelected = compoundRunning[0] ?? running.find((s) => s.config.id === selectedId) ?? null;
|
|
const target = runningSelected ?? running[running.length - 1] ?? null;
|
|
// Debug sessions belong to the debugger feature; like IDEA the widget offers their Rerun / Stop.
|
|
const debugging = useContextKeys((c) => !!c.debugSessionActive);
|
|
const canRerunDebug = useContextKeys((c) => !!c.debugCanRerun);
|
|
const debugPaused = useContextKeys((c) => !!c.debugSessionPaused);
|
|
const active = !!runningSelected || debugging;
|
|
const moreRef = useRef<HTMLButtonElement>(null);
|
|
const [moreOpen, setMoreOpen] = useState(false);
|
|
const executors = useRunExecutors((s) => s.executors);
|
|
// IDEA: the selected configuration's other executors (Run with Coverage, Profile) come first.
|
|
const executorItems: MenuItem[] = selected
|
|
? runExecutors(executors)
|
|
.filter((e) => e.supports(selected))
|
|
.map((e) => ({ kind: "action", action: e.action, label: e.label(selected.name), icon: e.icon }))
|
|
: [];
|
|
const moreItems: MenuItem[] = [
|
|
...executorItems,
|
|
...(executorItems.length ? [{ kind: "separator" } as const] : []),
|
|
{ kind: "action", action: "run.runContext" },
|
|
{ kind: "action", action: "run.debugContext" },
|
|
{ kind: "separator" },
|
|
{ kind: "action", action: "run.editConfigs" },
|
|
{ kind: "action", action: "run.reloadConfigs" },
|
|
];
|
|
|
|
return (
|
|
<div className={styles.widget}>
|
|
<BarButton
|
|
variant="title"
|
|
className={styles.widgetChooser}
|
|
tooltip={tx("Run/Debug Configurations")}
|
|
shortcut={shortcutLabel("run.chooseConfig")}
|
|
aria-haspopup="listbox"
|
|
aria-expanded={chooserOpen}
|
|
data-run-chooser=""
|
|
onClick={() => void executeAction("run.chooseConfig", "select")}
|
|
>
|
|
{selected && (
|
|
// IDEA: the configuration's type icon, with a status dot on its top-right corner while active.
|
|
<span className={styles.widgetConfigIcon}>
|
|
<Icon name={configIcon(selected)} size={16} />
|
|
{active && (
|
|
<span className={styles.widgetStatusDot} aria-label={debugging ? "Debugging" : "Running"} role="img" />
|
|
)}
|
|
</span>
|
|
)}
|
|
<span className={styles.widgetName}>
|
|
{selected?.name ?? tx(currentFile ? "Current File" : "Select Configuration")}
|
|
</span>
|
|
<Icon name="chevron-down" size={14} className={styles.widgetChevron} />
|
|
</BarButton>
|
|
<span className={styles.widgetButtons}>
|
|
{target ? (
|
|
<>
|
|
<IconButton
|
|
icon="rerun-filled"
|
|
size="large"
|
|
iconSize={16}
|
|
className={clsx(styles.widgetButton, styles.widgetFilled, styles.widgetFilledRun)}
|
|
title={`Rerun '${compoundRunning.length && selected ? selected.name : target.config.name}'`}
|
|
shortcut={shortcutLabel("run.run")}
|
|
onClick={() => (compoundRunning.length && selected ? void startRun(selected) : rerunSession(target.id))}
|
|
/>
|
|
<IconButton
|
|
icon="stop-filled"
|
|
size="large"
|
|
iconSize={16}
|
|
className={clsx(styles.widgetButton, styles.widgetFilled, styles.widgetFilledStop)}
|
|
title={
|
|
compoundRunning.length && selected
|
|
? `Stop '${selected.name}'`
|
|
: running.length > 1
|
|
? `Stop (${running.length} running)`
|
|
: `Stop '${target.config.name}'`
|
|
}
|
|
shortcut={shortcutLabel("run.stop")}
|
|
onClick={() =>
|
|
compoundRunning.length
|
|
? compoundRunning.forEach((s) => void stopSession(s.id))
|
|
: running.length > 1
|
|
? void executeAction("run.stop")
|
|
: void stopSession(target.id)
|
|
}
|
|
/>
|
|
</>
|
|
) : debugging ? (
|
|
// IDEA while debugging: Resume (when paused), Rerun Debug and Stop as filled buttons.
|
|
<>
|
|
{debugPaused && (
|
|
<IconButton
|
|
icon="resume"
|
|
size="large"
|
|
iconSize={18}
|
|
className={styles.widgetButton}
|
|
title="Resume Program"
|
|
shortcut={shortcutLabel("debug.resume")}
|
|
onClick={() => void executeAction("debug.resume")}
|
|
/>
|
|
)}
|
|
<IconButton
|
|
icon="restart-debug-filled"
|
|
size="large"
|
|
iconSize={16}
|
|
className={clsx(styles.widgetButton, styles.widgetFilled, styles.widgetFilledRun)}
|
|
title="Rerun Debug Session"
|
|
shortcut={shortcutLabel("debug.rerun")}
|
|
disabled={!canRerunDebug}
|
|
onClick={() => void executeAction("debug.rerun")}
|
|
/>
|
|
<IconButton
|
|
icon="stop-filled"
|
|
size="large"
|
|
iconSize={16}
|
|
className={clsx(styles.widgetButton, styles.widgetFilled, styles.widgetFilledStop)}
|
|
title="Stop Debug Session"
|
|
shortcut={shortcutLabel("debug.stop")}
|
|
onClick={() => void executeAction("debug.stop")}
|
|
/>
|
|
</>
|
|
) : (
|
|
<>
|
|
<IconButton
|
|
icon="run"
|
|
size="large"
|
|
iconSize={18}
|
|
className={clsx(styles.widgetButton, styles.widgetRun)}
|
|
title={selected ? `Run '${selected.name}'` : currentFile ? "Run Current File" : "Run"}
|
|
shortcut={shortcutLabel("run.run")}
|
|
disabled={!selected && !currentFile}
|
|
onClick={() => void executeAction("run.run")}
|
|
/>
|
|
<IconButton
|
|
icon="debug"
|
|
size="large"
|
|
iconSize={18}
|
|
className={styles.widgetButton}
|
|
title={selected ? `Debug '${selected.name}'` : currentFile ? "Debug Current File" : "Debug"}
|
|
shortcut={shortcutLabel("run.debug")}
|
|
disabled={!selected && !currentFile}
|
|
onClick={() => void executeAction("run.debug")}
|
|
/>
|
|
</>
|
|
)}
|
|
<IconButton
|
|
ref={moreRef}
|
|
icon="more"
|
|
size="large"
|
|
iconSize={18}
|
|
className={styles.widgetButton}
|
|
title="More Actions"
|
|
aria-haspopup="menu"
|
|
aria-expanded={moreOpen}
|
|
onClick={() => setMoreOpen((v) => !v)}
|
|
/>
|
|
<Menu
|
|
open={moreOpen}
|
|
anchor={moreRef}
|
|
items={moreItems}
|
|
placement="bottom-end"
|
|
onClose={() => setMoreOpen(false)}
|
|
/>
|
|
</span>
|
|
</div>
|
|
);
|
|
}
|