дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 11:15:40 +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
113 рядки
3.9 KiB
TypeScript
113 рядки
3.9 KiB
TypeScript
import { beforeEach, describe, expect, it } from "vitest";
|
|
import { editorKeyName } from "./editorKeys";
|
|
import {
|
|
_reloadMacros,
|
|
deleteMacro,
|
|
describeStep,
|
|
playSteps,
|
|
recordStep,
|
|
renameMacro,
|
|
saveMacro,
|
|
startRecording,
|
|
stopRecording,
|
|
storableArg,
|
|
STORAGE_KEY,
|
|
useMacros,
|
|
} from "./model";
|
|
|
|
beforeEach(() => {
|
|
localStorage.clear();
|
|
_reloadMacros();
|
|
});
|
|
|
|
describe("macros", () => {
|
|
it("records actions, merged typing and keys only while recording", () => {
|
|
recordStep({ kind: "text", text: "ignored" });
|
|
startRecording();
|
|
recordStep({ kind: "text", text: "he" });
|
|
recordStep({ kind: "text", text: "llo" });
|
|
recordStep({ kind: "key", key: "Enter" });
|
|
recordStep({ kind: "action", id: "editor.duplicateLine" });
|
|
const steps = stopRecording();
|
|
expect(steps).toEqual([
|
|
{ kind: "text", text: "hello" },
|
|
{ kind: "key", key: "Enter" },
|
|
{ kind: "action", id: "editor.duplicateLine" },
|
|
]);
|
|
expect(useMacros.getState().last).toEqual(steps);
|
|
// An empty recording keeps the last macro.
|
|
startRecording();
|
|
stopRecording();
|
|
expect(useMacros.getState().last).toEqual(steps);
|
|
});
|
|
|
|
it("persists saved macros; renames and deletes them", () => {
|
|
saveMacro("Dup", [{ kind: "action", id: "editor.duplicateLine" }]);
|
|
saveMacro("Two", []);
|
|
expect(renameMacro("Dup", "Two")).toBe(false);
|
|
expect(renameMacro("Dup", "Duplicate")).toBe(true);
|
|
_reloadMacros();
|
|
expect(useMacros.getState().saved.map((m) => m.name)).toEqual(["Duplicate", "Two"]);
|
|
deleteMacro("Two");
|
|
_reloadMacros();
|
|
expect(useMacros.getState().saved.map((m) => m.name)).toEqual(["Duplicate"]);
|
|
});
|
|
|
|
it("drops malformed stored steps", () => {
|
|
localStorage.setItem(
|
|
STORAGE_KEY,
|
|
JSON.stringify({ last: [{ kind: "text", text: "a" }, { kind: "action" }, { kind: "action", id: "x", arg: {} }], saved: [{ name: "" }] }),
|
|
);
|
|
_reloadMacros();
|
|
expect(useMacros.getState().last).toEqual([{ kind: "text", text: "a" }]);
|
|
expect(useMacros.getState().saved).toEqual([]);
|
|
});
|
|
|
|
it("plays steps in order and stops at the first that cannot run; nothing is recorded meanwhile", async () => {
|
|
const log: string[] = [];
|
|
startRecording();
|
|
const ok = await playSteps(
|
|
[
|
|
{ kind: "action", id: "a", arg: 1 },
|
|
{ kind: "text", text: "t" },
|
|
{ kind: "key", key: "Tab" },
|
|
{ kind: "action", id: "b" },
|
|
],
|
|
{
|
|
action: async (id, arg) => {
|
|
recordStep({ kind: "action", id });
|
|
log.push(`${id}${arg ?? ""}`);
|
|
return id !== "b";
|
|
},
|
|
text: (t) => (log.push(t), true),
|
|
key: (k) => (log.push(k), true),
|
|
},
|
|
);
|
|
expect(ok).toBe(false);
|
|
expect(log).toEqual(["a1", "t", "Tab", "b"]);
|
|
expect(useMacros.getState().recording).toEqual([]);
|
|
expect(useMacros.getState().playing).toBe(false);
|
|
});
|
|
|
|
it("stores plain action arguments only and describes steps", () => {
|
|
expect(storableArg("x")).toBe("x");
|
|
expect(storableArg(2)).toBe(2);
|
|
expect(storableArg(undefined)).toBeUndefined();
|
|
expect(storableArg({ path: "/a" })).toBeNull();
|
|
expect(storableArg(Number.NaN)).toBeNull();
|
|
const title = (id: string) => (id === "a" ? "Action A" : id);
|
|
expect(describeStep({ kind: "action", id: "a", arg: "x" }, title)).toBe("Action A (x)");
|
|
expect(describeStep({ kind: "text", text: "a\nb" }, title)).toBe('Type "a↵b"');
|
|
expect(describeStep({ kind: "key", key: "Enter" }, title)).toBe("Press Enter");
|
|
});
|
|
|
|
it("names the editor keys a macro records", () => {
|
|
const k = (key: string, mods: Partial<Record<"altKey" | "ctrlKey" | "metaKey" | "shiftKey", boolean>> = {}) =>
|
|
editorKeyName({ key, altKey: false, ctrlKey: false, metaKey: false, shiftKey: false, ...mods });
|
|
expect(k("Enter")).toBe("Enter");
|
|
expect(k("ArrowLeft", { shiftKey: true, altKey: true })).toBe("Alt+Shift+ArrowLeft");
|
|
expect(k("a")).toBeNull();
|
|
expect(k("s", { metaKey: true })).toBeNull();
|
|
});
|
|
});
|