Файли
openidea/src/workbench/mainToolbar.ts
T
l0ng-ai 1e00ea5ee2 feat: Third pass aligning core experience with IntelliJ IDEA
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
2026-10-25 21:24:00 +08:00

101 рядки
4.4 KiB
TypeScript

/**
* Customize Main Toolbar: which widgets (project, VCS, run…) and actions the
* title bar shows on each side, in which order. Stored in
* `appearance.mainToolbar` (global settings); unset = the default toolbar.
*/
import type { MainToolbarSettings } from "@/bindings";
import { getAction } from "@/platform/actions";
import { call, commands, isTauri } from "@/platform/ipc";
import { useProject } from "@/platform/project";
import type { TitleItemContribution } from "./contributions";
export const PROJECT_WIDGET = "project";
/** Shown as "Version Control ▾" while the project has no repository. */
export const VCS_WIDGET = "vcs.branch";
export const ACTION_PREFIX = "action:";
export const SEARCH_ENTRY = `${ACTION_PREFIX}navigate.searchEverywhere`;
export interface ToolbarLayout {
left: string[];
right: string[];
hidden: string[];
}
export const isActionEntry = (id: string) => id.startsWith(ACTION_PREFIX);
export const entryAction = (id: string) => id.slice(ACTION_PREFIX.length);
const byPriority = (a: TitleItemContribution, b: TitleItemContribution) => a.priority - b.priority || a.id.localeCompare(b.id);
/** Widgets in their default place (built-ins included), by side. */
function defaultWidgets(items: Iterable<TitleItemContribution>): { left: string[]; right: string[] } {
const all = [...items];
const left = all.filter((i) => i.align === "left").sort(byPriority).map((i) => i.id);
const right = all.filter((i) => i.align === "right").sort(byPriority).map((i) => i.id);
return { left: [PROJECT_WIDGET, ...(left.includes(VCS_WIDGET) ? [] : [VCS_WIDGET]), ...left], right };
}
export function defaultToolbar(items: Iterable<TitleItemContribution>): ToolbarLayout {
const { left, right } = defaultWidgets(items);
return { left, right: [...right, SEARCH_ENTRY], hidden: [] };
}
/**
* The entries to show per side: the saved order, plus widgets registered since
* (not listed, not removed) at their default side's end.
*/
export function resolveToolbar(
saved: MainToolbarSettings | null | undefined,
items: Iterable<TitleItemContribution>,
): { left: string[]; right: string[] } {
const list = [...items];
if (!saved) {
const d = defaultToolbar(list);
return { left: d.left, right: d.right };
}
const left = [...(saved.left ?? [])];
const right = [...(saved.right ?? [])];
const known = new Set([...left, ...right, ...(saved.hidden ?? [])]);
const d = defaultWidgets(list);
for (const id of d.left) if (!known.has(id)) left.push(id);
for (const id of d.right) if (!known.has(id)) right.push(id);
return { left, right };
}
/** The full editable layout (Customize Main Toolbar dialog). */
export function editableToolbar(saved: MainToolbarSettings | null | undefined, items: Iterable<TitleItemContribution>): ToolbarLayout {
const list = [...items];
const { left, right } = resolveToolbar(saved, list);
return { left, right, hidden: saved ? [...(saved.hidden ?? [])] : [] };
}
export function widgetTitle(id: string, items: ReadonlyMap<string, TitleItemContribution>): string {
if (id === PROJECT_WIDGET) return "Project Widget";
if (id === VCS_WIDGET && !items.has(id)) return "VCS Widget";
if (isActionEntry(id)) return getAction(entryAction(id))?.title ?? entryAction(id);
return items.get(id)?.title ?? id;
}
/** Shows or removes a widget, keeping the rest of the layout. */
export function toggleWidget(layout: ToolbarLayout, id: string, defaultSide: "left" | "right"): ToolbarLayout {
const shown = layout.left.includes(id) || layout.right.includes(id);
if (shown)
return {
left: layout.left.filter((x) => x !== id),
right: layout.right.filter((x) => x !== id),
hidden: [...layout.hidden.filter((x) => x !== id), ...(isActionEntry(id) ? [] : [id])],
};
const side = defaultSide === "left" ? { left: [...layout.left, id], right: layout.right } : { left: layout.left, right: [...layout.right, id] };
return { ...side, hidden: layout.hidden.filter((x) => x !== id) };
}
export function useMainToolbarSettings(): MainToolbarSettings | null | undefined {
return useProject((s) => s.settings?.appearance?.mainToolbar);
}
/** Saves `layout`; `null` restores the default toolbar. */
export async function saveToolbar(layout: ToolbarLayout | null): Promise<void> {
if (!isTauri()) return;
const settings = await call(commands.settingsSet("global", "appearance.mainToolbar", JSON.stringify(layout)));
useProject.setState({ settings });
}