135 lines · 6.4 KB · TypeScript
RawDownload
import { describe, expect, it } from "vite-plus/test";import {  captureConfigBinding,  editCaptureConfig,  niriConfigConflict,  niriConfigIncludes,} from "./captureConfigEdit.ts";import { readKdlNodes } from "./captureConfigKdl.ts"; const app = "com.t3tools.T3Code";const binding = captureConfigBinding("niri", app, "Ctrl+Shift+2"); describe("Niri capture config edits", () => {  it("inserts into the existing top-level binds, preserving unrelated text", () => {    const before =      '// My desktop\ninput { keyboard { xkb { layout "us"; }; }; }\nbinds {\n    Mod+Q { spawn "kitty"; } // keep me\n}\n';    const result = editCaptureConfig(before, "niri", app, "install");    expect(result.after).toBe(before.replace("\n}\n", `\n    ${binding}\n}\n`));    expect(readKdlNodes(result.after).filter((node) => node.name === "binds")).toHaveLength(1);  });  it("ignores commented, nested, and string-valued binds and braces", () => {    const before = `// binds { fake\n/* binds { /* nested */ } */\n/- binds { Ctrl+Shift+2 { quit; } }\nrecent-windows { binds { Alt+Tab { next-window; } }; }\nspawn-at-startup "echo" r#"binds { }"#\n"binds" {\n    Mod+Q { spawn "a } \\" b"; }\n}\n`;    // A quoted brace in a valid shell argument must not close the binds section.    const valid = before.replace('"a } \\" b"', '"a } b"');    const result = editCaptureConfig(valid, "niri", app, "install");    expect(result.after).toContain(`    ${binding}\n}\n`);    expect(result.after.startsWith(valid.slice(0, valid.indexOf('"binds" {')))).toBe(true);  });  it.each(["binds {}", "binds { Mod+Q { quit; }; }", "input { }\n", ""])(    "handles compact or absent binds: %s",    (before) => {      const result = editCaptureConfig(before, "niri", app, "install");      const block = readKdlNodes(result.after).find((node) => node.name === "binds")!;      expect(block.children.some((node) => node.name === "Ctrl+Shift+2")).toBe(true);    },  );  it("preserves CRLF and the UTF-8 BOM", () => {    const before = "\uFEFFbinds {\r\n}\r\n";    expect(editCaptureConfig(before, "niri", app, "install").after).toBe(      `\uFEFFbinds {\r\n    ${binding}\r\n}\r\n`,    );  });  it("preserves Unicode spacing around nodes and line continuations", () => {    const spaces =      "\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000";    const before = `binds${spaces}\\${spaces}\n{\n}\n`;    expect(editCaptureConfig(before, "niri", app, "install").after).toBe(      before.replace("}\n", `    ${binding}\n}\n`),    );  });  it("does not duplicate an existing binding, including a custom chord", () => {    const before = `binds {\n    ${binding.replace("Ctrl+Shift+2", "Alt+Ctrl+Y")}\n}\n`;    const result = editCaptureConfig(before, "niri", app, "install");    expect(result.after).toBe(before);    expect(result.shortcut).toBe("Ctrl+Alt+Y");  });  it("replaces and removes only this app's capture binding", () => {    const other = captureConfigBinding("niri", "com.t3tools.Other", "Ctrl+Alt+4");    const before = `binds {\n    ${binding}\n    ${other}\n}\n`;    const result = editCaptureConfig(before, "niri", app, "install", "Ctrl+Alt+Y");    expect(result.after).toContain(other);    expect(result.after).not.toContain("Ctrl+Shift+2");    expect(result.after).toContain("Ctrl+Alt+Y");    const removed = editCaptureConfig(result.after, "niri", app, "remove");    expect(removed.after).toBe(`binds {\n    ${other}\n}\n`);  });  it("refuses occupied keys regardless of modifier order, without removing them", () => {    const before = "binds { Shift+Control+2 { quit; } }";    expect(niriConfigConflict(before, app, "Ctrl+Shift+2")).toBe(true);    expect(() => editCaptureConfig(before, "niri", app, "install")).toThrow("already used");  });  it("does not count a slash-dash-disabled key as occupied", () => {    expect(niriConfigConflict("binds { /- Ctrl+Shift+2 { quit; }; }", app, "Ctrl+Shift+2")).toBe(      false,    );  });  it.each(["binds {", "binds {}\nbinds {}", "/* unfinished", 'spawn "unfinished'])(    "fails safely for malformed structure: %s",    (source) => {      expect(() => editCaptureConfig(source, "niri", app, "install")).toThrow();    },  );  it("reads only real top-level include directives", () => {    expect(      niriConfigIncludes(        '// include "no"\n/- include "no"\ninclude "keys.kdl"\ninclude optional=true "extra.kdl"',      ),    ).toEqual([      { path: "keys.kdl", optional: false },      { path: "extra.kdl", optional: true },    ]);  });}); describe("Hyprland capture config edits", () => {  it.each(["hyprland", "hyprland-lua"] as const)(    "is idempotent and reversible for %s",    (format) => {      const before =        format === "hyprland"          ? "# Keep my preferences\n$mainMod = SUPER\n"          : "-- Keep my preferences\nhl.config({ general = { border_size = 2 } })\n";      const added = editCaptureConfig(before, format, app, "install");      expect(added.after.startsWith(before)).toBe(true);      expect(editCaptureConfig(added.after, format, app, "install").after).toBe(added.after);      const changed = editCaptureConfig(added.after, format, app, "install", "Ctrl+Alt+Y");      expect(changed.after).not.toContain(captureConfigBinding(format, app, "Ctrl+Shift+2"));      expect(changed.after).toContain(captureConfigBinding(format, app, "Ctrl+Alt+Y"));      expect(editCaptureConfig(changed.after, format, app, "remove").after.trim()).toBe(        before.trim(),      );    },  );  it("does not steal an existing legacy shortcut", () => {    expect(() =>      editCaptureConfig("bind = SHIFT CTRL, 2, exec, kitty\n", "hyprland", app, "install"),    ).toThrow("already used");  });  it("leaves commented bindings alone", () => {    const before = "# bind = CTRL SHIFT, 2, global, com.t3tools.T3Code:capture-window\n";    expect(editCaptureConfig(before, "hyprland", app, "remove").after).toBe(before);  });  it.each([    "return {}",    '--[[\nhl.bind("CTRL + SHIFT + 2", hl.dsp.global("com.t3tools.T3Code:capture-window"))\n]]',  ])("does not guess how to edit complex Lua", (source) => {    expect(() => editCaptureConfig(source, "hyprland-lua", app, "install")).toThrow("manual edit");  });  it.each(['Ctrl+"\nexec', "Ctrl+;", "2", "Mod+2"])(    "rejects unsafe or ambiguous keys: %s",    (keys) => {      expect(() => editCaptureConfig("", "hyprland", app, "install", keys)).toThrow();    },  );});