Файли
openidea/src/features/database/index.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

152 рядки
5.2 KiB
TypeScript

/**
* Database tools (IDEA's Database tool window, scoped): data sources for
* SQLite / PostgreSQL / MySQL-MariaDB, a schema tree, query consoles with
* results grids, and a table data editor. Connections, introspection and
* statements run in Rust (`ide-db`).
*/
import { lazyComponent } from "@/ui";
import { activeEditor, registerEditorContribution } from "@/editor/api";
import { registerActions } from "@/platform/actions";
import { useProject } from "@/platform/project";
import {
registerEditorKind,
registerOverlay,
registerServiceView,
registerToolWindow,
setFileDecorations,
toolWindowService,
} from "@/workbench/contributions";
import { SQL_LANGUAGE, consoleExtension, executeInView } from "./console";
import { DatabaseDialogs } from "./Dialogs";
import { TABLE_KIND, tableTitle } from "./tableInput";
import { nodeTarget, type DbNode } from "./nodes";
import { registerDatabaseTreeActions } from "./treeActions";
import {
DB_TOOL_WINDOW,
RESULTS_VIEW,
consoleSource,
consoleTints,
loadSources,
openConsole,
openSourceDialog,
useDatabase,
watchIdleConnections,
} from "./store";
export function activate(): () => void {
const disposers = [
registerToolWindow({
id: DB_TOOL_WINDOW,
title: "Database",
icon: "toolwindow-database",
anchor: "right",
order: 20,
component: lazyComponent(() => import("./DatabaseView").then((m) => m.DatabaseView)),
headerActions: lazyComponent(() => import("./DatabaseView").then((m) => m.DatabaseHeaderActions)),
}),
registerServiceView({
id: RESULTS_VIEW,
title: "Database",
icon: "database",
order: 20,
onUse: true,
component: lazyComponent(() => import("./ResultsView").then((m) => m.ResultsView)),
}),
registerEditorKind({ kind: TABLE_KIND, component: lazyComponent(() => import("./TableEditor").then((m) => m.TableEditor)), title: tableTitle, icon: () => "database" }),
registerOverlay({ id: "database.dialogs", component: DatabaseDialogs }),
registerEditorContribution({ id: "database.console", order: 57, extensions: consoleExtension }),
// A reopened project starts with a fresh backend: forget the old one's state.
useProject.subscribe((s, prev) => {
if (s.project?.root === prev.project?.root) return;
useDatabase.setState({
sources: [],
loaded: false,
connected: new Set(),
databases: {},
schemas: {},
tables: {},
details: {},
completion: {},
results: [],
output: [],
activeResult: null,
selectedSource: null,
selectedNode: null,
treeExpanded: new Set(),
treeReveal: null,
manualCommit: new Set(),
pendingTx: new Set(),
running: {},
dialog: null,
newMenuOpen: false,
});
}),
// Consoles of coloured data sources get a tinted tab.
useDatabase.subscribe((s, prev) => {
if (s.consoles !== prev.consoles || s.sources !== prev.sources) setFileDecorations("database", consoleTints(s));
}),
() => setFileDecorations("database", new Map()),
watchIdleConnections(),
registerDatabaseTreeActions(),
registerActions([
{
id: "db.showToolWindow",
title: "Database",
category: "Tools",
icon: "toolwindow-database",
keywords: ["data sources", "sql", "tables"],
when: "projectOpen",
run: () => toolWindowService().show(DB_TOOL_WINDOW, true),
},
{
id: "db.newDataSource",
title: "New Data Source…",
category: "Tools",
icon: "plus",
keywords: ["database", "connection", "postgres", "mysql", "sqlite"],
when: "projectOpen",
run: async () => {
if (!useDatabase.getState().loaded) await loadSources();
openSourceDialog(null);
},
},
{
id: "db.openConsole",
title: "Query Console",
category: "Tools",
icon: "file-sql",
keywords: ["database", "sql console"],
when: "projectOpen",
run: async ({ arg }) => {
const s = useDatabase.getState();
if (!s.loaded) await loadSources();
const { sources, selectedSource } = useDatabase.getState();
// A tree node (New ▸ Query Console) opens its data source's console.
const node = arg && typeof arg === "object" && "kind" in arg ? nodeTarget(arg as DbNode) : null;
const id = node ?? selectedSource ?? (sources.length === 1 ? sources[0]!.id : null);
if (id) await openConsole(id);
else toolWindowService().show(DB_TOOL_WINDOW, true);
},
},
{
id: "db.execute",
title: "Execute SQL Statement",
category: "Tools",
icon: "run",
when: `editorTextFocus && editorLangId == ${SQL_LANGUAGE}`,
run: async () => {
const e = activeEditor();
if (!e || e.ctx.language !== SQL_LANGUAGE) return;
if (!useDatabase.getState().loaded) await loadSources();
if (!consoleSource(e.ctx.path) && !useDatabase.getState().sources.length) {
openSourceDialog(null);
return;
}
await executeInView(e.view, e.ctx.path);
},
},
]),
];
return () => disposers.reverse().forEach((d) => d());
}