mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-06 16:08:05 +00: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
99 lines
3.5 KiB
TypeScript
99 lines
3.5 KiB
TypeScript
/**
|
|
* IDEA's "Specify Scope" choices for the analyses (Inspect Code, Locate
|
|
* Duplicates, Search Structurally), resolved to a backend `SearchScope`.
|
|
*/
|
|
import { activeEditor } from "@/editor/api";
|
|
import { call, commands, isTauri, type SearchScope } from "@/platform/ipc";
|
|
import { useProject } from "@/platform/project";
|
|
import { findCustomScope } from "@/platform/search";
|
|
|
|
export type ScopeKind = "project" | "directory" | "file" | "changed" | "custom";
|
|
|
|
export interface ScopeChoice {
|
|
kind: ScopeKind;
|
|
/** Absolute directory for `directory`. */
|
|
directory: string;
|
|
/** Name of the custom scope for `custom` (`@/platform/search`). */
|
|
custom?: string;
|
|
}
|
|
|
|
export const SCOPE_LABELS: Record<ScopeKind, string> = {
|
|
project: "Whole project",
|
|
directory: "Module or directory",
|
|
file: "Current file",
|
|
changed: "Uncommitted files",
|
|
custom: "Custom scope",
|
|
};
|
|
|
|
/** The file of the active editor, if it is a real file. */
|
|
export function currentFile(): string | null {
|
|
const ctx = activeEditor()?.ctx;
|
|
return ctx && !ctx.virtual ? ctx.path : null;
|
|
}
|
|
|
|
export function dirname(path: string): string {
|
|
const i = path.lastIndexOf("/");
|
|
return i > 0 ? path.slice(0, i) : "/";
|
|
}
|
|
|
|
/** Initial scope: the current file's directory is offered for `directory`. */
|
|
export function defaultScope(kind: ScopeKind = "project"): ScopeChoice {
|
|
const file = currentFile();
|
|
const root = useProject.getState().project?.root ?? "";
|
|
return { kind, directory: file ? dirname(file) : root };
|
|
}
|
|
|
|
/** Paths of files with uncommitted changes (from Git status). */
|
|
export async function changedFiles(): Promise<string[]> {
|
|
if (!isTauri()) return [];
|
|
const status = await call(commands.vcsStatus());
|
|
return status.filter((s) => s.unstaged !== "deleted" && s.staged !== "deleted").map((s) => s.path);
|
|
}
|
|
|
|
/** A backend scope, or a message why there is none. */
|
|
export async function resolveScope(choice: ScopeChoice): Promise<SearchScope | string> {
|
|
switch (choice.kind) {
|
|
case "project":
|
|
return { kind: "project" };
|
|
case "directory":
|
|
return choice.directory.trim() ? { kind: "directory", path: choice.directory.trim() } : "Choose a directory";
|
|
case "file": {
|
|
const file = currentFile();
|
|
return file ? { kind: "files", paths: [file] } : "No file is open";
|
|
}
|
|
case "changed": {
|
|
let paths: string[];
|
|
try {
|
|
paths = await changedFiles();
|
|
} catch (e) {
|
|
return e instanceof Error ? e.message : String(e);
|
|
}
|
|
return paths.length ? { kind: "files", paths } : "There are no uncommitted files";
|
|
}
|
|
case "custom": {
|
|
const scope = choice.custom ? findCustomScope(choice.custom) : null;
|
|
return scope ? { kind: "pattern", pattern: scope.pattern } : "Choose a scope";
|
|
}
|
|
}
|
|
}
|
|
|
|
/** "Project", "Directory src/app", "Current file a.rs", "3 uncommitted files". */
|
|
export function describeScope(choice: ScopeChoice, scope: SearchScope): string {
|
|
const root = useProject.getState().project?.root ?? "";
|
|
const rel = (p: string) => (root && p.startsWith(`${root}/`) ? p.slice(root.length + 1) : p);
|
|
switch (choice.kind) {
|
|
case "project":
|
|
return "Project";
|
|
case "directory":
|
|
return `Directory ${rel(choice.directory)}`;
|
|
case "file":
|
|
return scope.kind === "files" ? `File ${rel(scope.paths[0] ?? "")}` : "Current file";
|
|
case "changed":
|
|
return scope.kind === "files"
|
|
? `${scope.paths.length} uncommitted file${scope.paths.length === 1 ? "" : "s"}`
|
|
: "Uncommitted files";
|
|
case "custom":
|
|
return `Scope '${choice.custom ?? ""}'`;
|
|
}
|
|
}
|