@zaly/tui 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/dist/actions-CnVzKVID.d.mts +41 -0
  2. package/dist/actions-CnVzKVID.d.mts.map +1 -0
  3. package/dist/actions-DEIKF2ts.mjs +48 -0
  4. package/dist/actions-DEIKF2ts.mjs.map +1 -0
  5. package/dist/{box-DyaByEiG.mjs → box-DepqUtuo.mjs} +2 -2
  6. package/dist/{box-DyaByEiG.mjs.map → box-DepqUtuo.mjs.map} +1 -1
  7. package/dist/{builder-D49ECBEf.mjs → builder-T9oGIWFa.mjs} +2 -2
  8. package/dist/{builder-D49ECBEf.mjs.map → builder-T9oGIWFa.mjs.map} +1 -1
  9. package/dist/{callbacks-CNjGNxVw.mjs → callbacks-DcMBGQEO.mjs} +2 -2
  10. package/dist/{callbacks-CNjGNxVw.mjs.map → callbacks-DcMBGQEO.mjs.map} +1 -1
  11. package/dist/{client-D6C_uczF.mjs → client-BBdtbLp4.mjs} +5 -10
  12. package/dist/client-BBdtbLp4.mjs.map +1 -0
  13. package/dist/client-cIckDgAj.mjs +2 -0
  14. package/dist/clipboard-l_TWxxTf.mjs +404 -0
  15. package/dist/clipboard-l_TWxxTf.mjs.map +1 -0
  16. package/dist/clipboard.mjs +1 -403
  17. package/dist/ctx-Ctmvof1N.mjs +43 -0
  18. package/dist/ctx-Ctmvof1N.mjs.map +1 -0
  19. package/dist/ctx-DhJIKuOX.mjs +2 -0
  20. package/dist/divider-cclEAdPx.mjs +9 -0
  21. package/dist/divider-cclEAdPx.mjs.map +1 -0
  22. package/dist/files-Aw3iWpXD.d.mts +29 -0
  23. package/dist/files-Aw3iWpXD.d.mts.map +1 -0
  24. package/dist/files-BvThQpOf.mjs +42 -0
  25. package/dist/files-BvThQpOf.mjs.map +1 -0
  26. package/dist/github-Cy2hfWJ7.mjs +137 -0
  27. package/dist/github-Cy2hfWJ7.mjs.map +1 -0
  28. package/dist/github-DS00VoOj.d.mts +64 -0
  29. package/dist/github-DS00VoOj.d.mts.map +1 -0
  30. package/dist/image-BTxDPPiT.d.mts +37 -0
  31. package/dist/image-BTxDPPiT.d.mts.map +1 -0
  32. package/dist/index.mjs +6 -202
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/input-CRBuTrsL.mjs +497 -0
  35. package/dist/input-CRBuTrsL.mjs.map +1 -0
  36. package/dist/{inspect-D1d9t-ni.mjs → inspect-BaKG6cU_.mjs} +2 -2
  37. package/dist/{inspect-D1d9t-ni.mjs.map → inspect-BaKG6cU_.mjs.map} +1 -1
  38. package/dist/log-DYHEYX_z.mjs +130 -0
  39. package/dist/log-DYHEYX_z.mjs.map +1 -0
  40. package/dist/logger-Ch0LwSG_.mjs +71 -0
  41. package/dist/logger-Ch0LwSG_.mjs.map +1 -0
  42. package/dist/markdown-CYHHoYu0.mjs +124 -0
  43. package/dist/markdown-CYHHoYu0.mjs.map +1 -0
  44. package/dist/markdown.mjs +1 -1
  45. package/dist/overlay-9xNgsuuy.mjs +18 -0
  46. package/dist/overlay-9xNgsuuy.mjs.map +1 -0
  47. package/dist/{picker-ndVVt6qF.mjs → picker-cH-rc7-X.mjs} +5 -5
  48. package/dist/{picker-ndVVt6qF.mjs.map → picker-cH-rc7-X.mjs.map} +1 -1
  49. package/dist/queries-B_lOwEiE.mjs +200 -0
  50. package/dist/queries-B_lOwEiE.mjs.map +1 -0
  51. package/dist/{registry-U654j61Y.mjs → registry-CdeLjUo2.mjs} +2 -4
  52. package/dist/registry-CdeLjUo2.mjs.map +1 -0
  53. package/dist/render-CPUD4yaW.mjs +33 -0
  54. package/dist/render-CPUD4yaW.mjs.map +1 -0
  55. package/dist/{renderer-CxL4xbkl.mjs → renderer-DJ1pWXSL.mjs} +8 -7
  56. package/dist/{renderer-CxL4xbkl.mjs.map → renderer-DJ1pWXSL.mjs.map} +1 -1
  57. package/dist/renderer-Dgj_qEOA.mjs +2 -0
  58. package/dist/{renderer-CdLCkJB-.mjs → renderer-qSMVeNSV.mjs} +3 -5
  59. package/dist/{renderer-CdLCkJB-.mjs.map → renderer-qSMVeNSV.mjs.map} +1 -1
  60. package/dist/select-m7NE6Rwa.mjs +195 -0
  61. package/dist/select-m7NE6Rwa.mjs.map +1 -0
  62. package/dist/services/logger.mjs +1 -70
  63. package/dist/services/notifier.mjs +2 -2
  64. package/dist/services/picker.d.mts +1 -1
  65. package/dist/services/picker.mjs +6 -6
  66. package/dist/services/prompt.d.mts +1 -1
  67. package/dist/services/prompt.mjs +5 -5
  68. package/dist/shiki/server.d.mts +1 -0
  69. package/dist/shiki/server.mjs +129 -0
  70. package/dist/shiki/server.mjs.map +1 -0
  71. package/dist/{shiki-BrjVUkeh.mjs → shiki-B5NwIiot.mjs} +5 -10
  72. package/dist/shiki-B5NwIiot.mjs.map +1 -0
  73. package/dist/shiki-BK-v9CtF.mjs +12 -0
  74. package/dist/shiki-BK-v9CtF.mjs.map +1 -0
  75. package/dist/show-DR2x1YFc.mjs +85 -0
  76. package/dist/show-DR2x1YFc.mjs.map +1 -0
  77. package/dist/style.mjs +2 -2
  78. package/dist/text-9lwQeqYr.d.mts +33 -0
  79. package/dist/text-9lwQeqYr.d.mts.map +1 -0
  80. package/dist/text-DILrol9j.mjs +32 -0
  81. package/dist/text-DILrol9j.mjs.map +1 -0
  82. package/dist/text-q26V6_Sc.mjs +111 -0
  83. package/dist/text-q26V6_Sc.mjs.map +1 -0
  84. package/dist/text.d.mts +2 -33
  85. package/dist/text.mjs +1 -110
  86. package/dist/themes.mjs +1 -1
  87. package/dist/tree-Bo1afYhe.mjs +73 -0
  88. package/dist/tree-Bo1afYhe.mjs.map +1 -0
  89. package/dist/widget-BkMwhY2p.mjs +40 -0
  90. package/dist/widget-BkMwhY2p.mjs.map +1 -0
  91. package/dist/widget-M7jD8Rgg.d.mts +49 -0
  92. package/dist/widget-M7jD8Rgg.d.mts.map +1 -0
  93. package/dist/widgets/autocomplete.mjs +2 -2
  94. package/dist/widgets/box.mjs +1 -1
  95. package/dist/widgets/code.mjs +7 -7
  96. package/dist/widgets/completions/actions.d.mts +2 -41
  97. package/dist/widgets/completions/actions.mjs +1 -47
  98. package/dist/widgets/completions/files.d.mts +2 -29
  99. package/dist/widgets/completions/files.mjs +1 -41
  100. package/dist/widgets/completions/github.d.mts +2 -64
  101. package/dist/widgets/completions/github.mjs +1 -136
  102. package/dist/widgets/completions/index.d.mts +3 -3
  103. package/dist/widgets/completions/index.mjs +3 -3
  104. package/dist/widgets/diff.d.mts +1 -1
  105. package/dist/widgets/diff.mjs +3 -3
  106. package/dist/widgets/divider.mjs +1 -8
  107. package/dist/widgets/image.d.mts +2 -37
  108. package/dist/widgets/image.mjs +1 -1
  109. package/dist/widgets/input.mjs +1 -496
  110. package/dist/widgets/log.mjs +1 -129
  111. package/dist/widgets/markdown.d.mts +2 -2
  112. package/dist/widgets/markdown.mjs +1 -123
  113. package/dist/widgets/overlay.mjs +1 -17
  114. package/dist/widgets/picker.mjs +1 -1
  115. package/dist/widgets/select.mjs +1 -194
  116. package/dist/widgets/show.mjs +1 -84
  117. package/dist/widgets/text.mjs +1 -31
  118. package/dist/widgets/tree.mjs +1 -72
  119. package/dist/widgets/widget.d.mts +2 -49
  120. package/dist/widgets/widget.mjs +1 -39
  121. package/dist/worker-BvRm4OsW.mjs +2 -0
  122. package/dist/worker-T6SdPzUH.mjs +52 -0
  123. package/dist/worker-T6SdPzUH.mjs.map +1 -0
  124. package/package.json +5 -1
  125. package/dist/client-D6C_uczF.mjs.map +0 -1
  126. package/dist/clipboard.mjs.map +0 -1
  127. package/dist/registry-U654j61Y.mjs.map +0 -1
  128. package/dist/render-DxVLqqB9.mjs +0 -74
  129. package/dist/render-DxVLqqB9.mjs.map +0 -1
  130. package/dist/rolldown-runtime-D7D4PA-g.mjs +0 -13
  131. package/dist/services/logger.mjs.map +0 -1
  132. package/dist/shiki-BrjVUkeh.mjs.map +0 -1
  133. package/dist/text.d.mts.map +0 -1
  134. package/dist/text.mjs.map +0 -1
  135. package/dist/widgets/completions/actions.d.mts.map +0 -1
  136. package/dist/widgets/completions/actions.mjs.map +0 -1
  137. package/dist/widgets/completions/files.d.mts.map +0 -1
  138. package/dist/widgets/completions/files.mjs.map +0 -1
  139. package/dist/widgets/completions/github.d.mts.map +0 -1
  140. package/dist/widgets/completions/github.mjs.map +0 -1
  141. package/dist/widgets/divider.mjs.map +0 -1
  142. package/dist/widgets/image.d.mts.map +0 -1
  143. package/dist/widgets/input.mjs.map +0 -1
  144. package/dist/widgets/log.mjs.map +0 -1
  145. package/dist/widgets/markdown.mjs.map +0 -1
  146. package/dist/widgets/overlay.mjs.map +0 -1
  147. package/dist/widgets/select.mjs.map +0 -1
  148. package/dist/widgets/show.mjs.map +0 -1
  149. package/dist/widgets/text.mjs.map +0 -1
  150. package/dist/widgets/tree.mjs.map +0 -1
  151. package/dist/widgets/widget.d.mts.map +0 -1
  152. package/dist/widgets/widget.mjs.map +0 -1
  153. package/dist/worker-DjHuQSbY.mjs +0 -27
  154. package/dist/worker-DjHuQSbY.mjs.map +0 -1
@@ -0,0 +1,137 @@
1
+ import { stringWidth } from "@zaly/shared/ansi";
2
+ import { spawn } from "node:child_process";
3
+ //#region src/widgets/completions/github.ts
4
+ /**
5
+ * Completion source for GitHub issues and pull requests from the repo
6
+ * at `cwd`. Shells out to the `gh` CLI on first use, caches the result,
7
+ * and fuzzy-filters locally on subsequent calls so typing stays snappy.
8
+ *
9
+ * Accepts insert `#123 ` into the input — ready for a markdown-style
10
+ * reference in a chat message or commit subject.
11
+ *
12
+ * ```ts
13
+ * autocomplete({
14
+ * input: "chat-input",
15
+ * sources: {
16
+ * gh: githubSource(),
17
+ * },
18
+ * })
19
+ * ```
20
+ *
21
+ * Silently returns no items when `gh` isn't installed, the user isn't
22
+ * authenticated, or the directory isn't a GitHub repo — so it's safe
23
+ * to wire up unconditionally.
24
+ */
25
+ function githubSource(opts = {}) {
26
+ const cwd = opts.cwd ?? process.cwd();
27
+ const trigger = opts.trigger ?? /(?<=^|\s)#/;
28
+ const prefix = opts.prefix ?? "#";
29
+ const state = opts.state ?? "open";
30
+ const limit = opts.limit ?? 50;
31
+ const fetcher = opts.fetcher ?? defaultFetcher(limit);
32
+ let cache;
33
+ return {
34
+ accept: (item) => `${prefix}${item.number} `,
35
+ async complete(_query, match) {
36
+ cache ??= fetcher(cwd, state).catch(() => []);
37
+ const items = await cache;
38
+ const out = [];
39
+ for (const item of items) {
40
+ const score = match(`#${item.number} ${item.title}`);
41
+ if (!score) continue;
42
+ out.push({
43
+ ...item,
44
+ score
45
+ });
46
+ }
47
+ return out;
48
+ },
49
+ render: defaultRender,
50
+ triggers: [trigger]
51
+ };
52
+ }
53
+ const defaultRender = (item, ctx) => {
54
+ const { style } = ctx;
55
+ const num = `#${item.number}`;
56
+ const stateSlot = stateStyleSlot(item.state);
57
+ const typeLabel = item.type === "pr" ? "pr" : "issue";
58
+ const author = item.author?.login ? `@${item.author.login}` : "";
59
+ const lead = `${style.add("optionName")(num)} ${style.add(stateSlot)(`${item.state}·${typeLabel}`)} ${item.title}`;
60
+ if (author === "") return lead;
61
+ const gap = 2;
62
+ const leadW = stringWidth(lead);
63
+ const hintW = stringWidth(author);
64
+ const padded = ctx.width - leadW - hintW - gap;
65
+ if (padded < 1) return lead;
66
+ return lead + " ".repeat(padded + gap) + style.add("optionDesc")(author);
67
+ };
68
+ function stateStyleSlot(state) {
69
+ if (state === "open") return "success";
70
+ if (state === "merged") return "accent";
71
+ return "muted";
72
+ }
73
+ /** Default fetcher — shells out to `gh issue list` + `gh pr list` in
74
+ * parallel. Either failing is swallowed so a repo with only issues
75
+ * (or only PRs) still works. */
76
+ function defaultFetcher(limit) {
77
+ const fields = "number,title,state,author,url";
78
+ return async (cwd, state) => {
79
+ const [issues, prs] = await Promise.all([runGh(cwd, [
80
+ "issue",
81
+ "list",
82
+ "--state",
83
+ state,
84
+ "--json",
85
+ fields,
86
+ "--limit",
87
+ String(limit)
88
+ ]), runGh(cwd, [
89
+ "pr",
90
+ "list",
91
+ "--state",
92
+ state,
93
+ "--json",
94
+ fields,
95
+ "--limit",
96
+ String(limit)
97
+ ])]);
98
+ return [...parse(issues).map((x) => Object.assign(x, { type: "issue" })), ...parse(prs).map((x) => Object.assign(x, { type: "pr" }))].map((item) => Object.assign(item, { text: `#${item.number} ${item.title}` }));
99
+ };
100
+ }
101
+ function parse(out) {
102
+ try {
103
+ return JSON.parse(out);
104
+ } catch {
105
+ return [];
106
+ }
107
+ }
108
+ function runGh(cwd, args) {
109
+ return new Promise((resolve) => {
110
+ try {
111
+ const child = spawn("gh", args, {
112
+ cwd,
113
+ stdio: [
114
+ "ignore",
115
+ "pipe",
116
+ "ignore"
117
+ ]
118
+ });
119
+ let stdout = "";
120
+ child.stdout.on("data", (chunk) => {
121
+ stdout += chunk.toString("utf8");
122
+ });
123
+ child.on("close", (code) => {
124
+ resolve(code === 0 ? stdout : "");
125
+ });
126
+ child.on("error", () => {
127
+ resolve("");
128
+ });
129
+ } catch {
130
+ resolve("");
131
+ }
132
+ });
133
+ }
134
+ //#endregion
135
+ export { githubSource as t };
136
+
137
+ //# sourceMappingURL=github-Cy2hfWJ7.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-Cy2hfWJ7.mjs","names":[],"sources":["../src/widgets/completions/github.ts"],"sourcesContent":["import type { ScoredItem } from \"../../search/matcher.ts\"\nimport type { CompletionSource } from \"../autocomplete.ts\"\nimport type { PickerItem } from \"../picker.ts\"\nimport type { OptionRender } from \"../select.ts\"\n\nimport { stringWidth } from \"@zaly/shared/ansi\"\nimport { spawn } from \"node:child_process\"\n\n/** A GitHub issue or pull request returned by `githubSource`. Shape\n * mirrors the `gh` CLI's `--json number,title,state,author,url`\n * output, with `type` added to distinguish issues from PRs. */\nexport type GithubItem = PickerItem & {\n number: number\n title: string\n /** `\"open\"` / `\"closed\"` for issues; `\"open\"` / `\"closed\"` / `\"merged\"`\n * for PRs. Kept as a string so we don't trip if gh evolves. */\n state: string\n type: \"issue\" | \"pr\"\n url: string\n author?: { login?: string }\n}\n\nexport type GithubState = \"open\" | \"closed\" | \"all\"\n\nexport type GithubFetcher = (cwd: string, state: GithubState) => Promise<GithubItem[]>\n\nexport interface GithubSourceOptions {\n /** Working directory used to locate the repo. `gh` resolves the repo\n * from the git remote of this dir. Default: `process.cwd()`. */\n cwd?: string\n /** Trigger regex. Default: `/(?<=^|\\s)#/` — `#` preceded by start-of-\n * string or whitespace (same lookbehind trick as `filesSource`). */\n trigger?: RegExp\n /** Prepended to the accepted value so the trigger character stays in\n * the input. Default: `\"#\"`. */\n prefix?: string\n /** Which issues / PRs to include. Default: `\"open\"`. */\n state?: GithubState\n /** Per-kind cap passed to `gh`. Default: `50`. */\n limit?: number\n /** Override the fetch implementation. Mainly useful for tests — the\n * default shells out to `gh`. The fetcher is called at most once per\n * `githubSource` instance; results are cached thereafter. */\n fetcher?: GithubFetcher\n}\n\n/**\n * Completion source for GitHub issues and pull requests from the repo\n * at `cwd`. Shells out to the `gh` CLI on first use, caches the result,\n * and fuzzy-filters locally on subsequent calls so typing stays snappy.\n *\n * Accepts insert `#123 ` into the input — ready for a markdown-style\n * reference in a chat message or commit subject.\n *\n * ```ts\n * autocomplete({\n * input: \"chat-input\",\n * sources: {\n * gh: githubSource(),\n * },\n * })\n * ```\n *\n * Silently returns no items when `gh` isn't installed, the user isn't\n * authenticated, or the directory isn't a GitHub repo — so it's safe\n * to wire up unconditionally.\n */\nexport function githubSource(opts: GithubSourceOptions = {}): CompletionSource<GithubItem> {\n const cwd = opts.cwd ?? process.cwd()\n const trigger = opts.trigger ?? /(?<=^|\\s)#/\n const prefix = opts.prefix ?? \"#\"\n const state: GithubState = opts.state ?? \"open\"\n const limit = opts.limit ?? 50\n const fetcher = opts.fetcher ?? defaultFetcher(limit)\n\n // Lazy, single-fetch cache. The Promise is reused by concurrent\n // callers so rapid keystrokes while the first fetch is in flight\n // don't spawn duplicate `gh` processes.\n let cache: Promise<GithubItem[]> | undefined\n\n return {\n accept: (item) => `${prefix}${item.number} `,\n async complete(_query: string, match): Promise<ScoredItem<GithubItem>[]> {\n cache ??= fetcher(cwd, state).catch(() => [])\n const items = await cache\n const out: ScoredItem<GithubItem>[] = []\n for (const item of items) {\n // Match on \"#<num> <title>\" so users can type either digits or\n // words and both hit. Keeps ranking implicit — source order\n // (freshest first from gh) wins when scores tie.\n const target = `#${item.number} ${item.title}`\n const score = match(target)\n if (!score) continue\n out.push({ ...item, score })\n }\n return out\n },\n render: defaultRender,\n triggers: [trigger],\n }\n}\n\nconst defaultRender: OptionRender<GithubItem> = (item, ctx) => {\n const { style } = ctx\n const num = `#${item.number}`\n const stateSlot = stateStyleSlot(item.state)\n const typeLabel = item.type === \"pr\" ? \"pr\" : \"issue\"\n const author = item.author?.login ? `@${item.author.login}` : \"\"\n\n // Layout: [#num] [state/type] title ............. @author\n // All chrome is left-aligned; author is the right-column hint.\n const lead = `${style.add(\"optionName\")(num)} ${style.add(stateSlot)(`${item.state}·${typeLabel}`)} ${item.title}`\n\n if (author === \"\") return lead\n const gap = 2\n const leadW = stringWidth(lead)\n const hintW = stringWidth(author)\n const padded = ctx.width - leadW - hintW - gap\n if (padded < 1) return lead\n return lead + \" \".repeat(padded + gap) + style.add(\"optionDesc\")(author)\n}\n\nfunction stateStyleSlot(state: string): string {\n if (state === \"open\") return \"success\"\n if (state === \"merged\") return \"accent\"\n // \"closed\" and anything unknown → dim.\n return \"muted\"\n}\n\n/** Default fetcher — shells out to `gh issue list` + `gh pr list` in\n * parallel. Either failing is swallowed so a repo with only issues\n * (or only PRs) still works. */\nfunction defaultFetcher(limit: number): GithubFetcher {\n const fields = \"number,title,state,author,url\"\n return async (cwd, state) => {\n const [issues, prs] = await Promise.all([\n runGh(cwd, [\"issue\", \"list\", \"--state\", state, \"--json\", fields, \"--limit\", String(limit)]),\n runGh(cwd, [\"pr\", \"list\", \"--state\", state, \"--json\", fields, \"--limit\", String(limit)]),\n ])\n return [\n ...parse(issues).map((x) => Object.assign(x, { type: \"issue\" as const })),\n ...parse(prs).map((x) => Object.assign(x, { type: \"pr\" as const })),\n ].map((item) => Object.assign(item, { text: `#${item.number} ${item.title}` }))\n }\n}\n\nfunction parse(out: string): Omit<GithubItem, \"type\">[] {\n try {\n return JSON.parse(out) as Omit<GithubItem, \"type\">[]\n } catch {\n return []\n }\n}\n\nfunction runGh(cwd: string, args: string[]): Promise<string> {\n return new Promise((resolve) => {\n try {\n const child = spawn(\"gh\", args, { cwd, stdio: [\"ignore\", \"pipe\", \"ignore\"] })\n let stdout = \"\"\n child.stdout.on(\"data\", (chunk: Buffer) => {\n stdout += chunk.toString(\"utf8\")\n })\n child.on(\"close\", (code) => {\n resolve(code === 0 ? stdout : \"\")\n })\n child.on(\"error\", () => {\n resolve(\"\")\n })\n } catch {\n resolve(\"\")\n }\n })\n}\n"],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ import { n as PickerItem } from "./picker-D8OLb6kZ.mjs";
2
+ import { o as CompletionSource } from "./autocomplete-Dfw-yQDa.mjs";
3
+ //#region src/widgets/completions/github.d.ts
4
+ /** A GitHub issue or pull request returned by `githubSource`. Shape
5
+ * mirrors the `gh` CLI's `--json number,title,state,author,url`
6
+ * output, with `type` added to distinguish issues from PRs. */
7
+ type GithubItem = PickerItem & {
8
+ number: number;
9
+ title: string;
10
+ /** `"open"` / `"closed"` for issues; `"open"` / `"closed"` / `"merged"`
11
+ * for PRs. Kept as a string so we don't trip if gh evolves. */
12
+ state: string;
13
+ type: "issue" | "pr";
14
+ url: string;
15
+ author?: {
16
+ login?: string;
17
+ };
18
+ };
19
+ type GithubState = "open" | "closed" | "all";
20
+ type GithubFetcher = (cwd: string, state: GithubState) => Promise<GithubItem[]>;
21
+ interface GithubSourceOptions {
22
+ /** Working directory used to locate the repo. `gh` resolves the repo
23
+ * from the git remote of this dir. Default: `process.cwd()`. */
24
+ cwd?: string;
25
+ /** Trigger regex. Default: `/(?<=^|\s)#/` — `#` preceded by start-of-
26
+ * string or whitespace (same lookbehind trick as `filesSource`). */
27
+ trigger?: RegExp;
28
+ /** Prepended to the accepted value so the trigger character stays in
29
+ * the input. Default: `"#"`. */
30
+ prefix?: string;
31
+ /** Which issues / PRs to include. Default: `"open"`. */
32
+ state?: GithubState;
33
+ /** Per-kind cap passed to `gh`. Default: `50`. */
34
+ limit?: number;
35
+ /** Override the fetch implementation. Mainly useful for tests — the
36
+ * default shells out to `gh`. The fetcher is called at most once per
37
+ * `githubSource` instance; results are cached thereafter. */
38
+ fetcher?: GithubFetcher;
39
+ }
40
+ /**
41
+ * Completion source for GitHub issues and pull requests from the repo
42
+ * at `cwd`. Shells out to the `gh` CLI on first use, caches the result,
43
+ * and fuzzy-filters locally on subsequent calls so typing stays snappy.
44
+ *
45
+ * Accepts insert `#123 ` into the input — ready for a markdown-style
46
+ * reference in a chat message or commit subject.
47
+ *
48
+ * ```ts
49
+ * autocomplete({
50
+ * input: "chat-input",
51
+ * sources: {
52
+ * gh: githubSource(),
53
+ * },
54
+ * })
55
+ * ```
56
+ *
57
+ * Silently returns no items when `gh` isn't installed, the user isn't
58
+ * authenticated, or the directory isn't a GitHub repo — so it's safe
59
+ * to wire up unconditionally.
60
+ */
61
+ declare function githubSource(opts?: GithubSourceOptions): CompletionSource<GithubItem>;
62
+ //#endregion
63
+ export { githubSource as a, GithubState as i, GithubItem as n, GithubSourceOptions as r, GithubFetcher as t };
64
+ //# sourceMappingURL=github-DS00VoOj.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-DS00VoOj.d.mts","names":[],"sources":["../src/widgets/completions/github.ts"],"mappings":";;;;;;KAWY,aAAa;EACvB;EACA;;;EAGA;EACA;EACA;EACA;IAAW;;;KAGD;KAEA,iBAAiB,aAAa,OAAO,gBAAgB,QAAQ;UAExD;;;EAGf;;;EAGA,UAAU;;;EAGV;;EAEA,QAAQ;;EAER;;;;EAIA,UAAU;;;;;;;;;;;;;;;;;;;;;;;iBAwBI,aAAa,OAAM,sBAA2B,iBAAiB"}
@@ -0,0 +1,37 @@
1
+ import { J as Layout, P as RenderCtx, p as Node } from "./queries-DH3bj74K.mjs";
2
+ //#region src/widgets/image.d.ts
3
+ interface ImageState {
4
+ /**
5
+ * Path to an image file. PNG passes through with zero decoding; other
6
+ * formats (JPEG/WebP/GIF/AVIF/SVG) are read via image-meta for
7
+ * dimensions and — for KGP terminals — converted once to a cached
8
+ * temp PNG via sharp. iTerm2 accepts all formats natively.
9
+ */
10
+ src: string;
11
+ /** Display width in terminal cells. Defaults to `ctx.width`. */
12
+ width?: number;
13
+ /**
14
+ * Display height in terminal cells. When omitted, computed from the
15
+ * source aspect ratio + `cellAspect`.
16
+ */
17
+ height?: number;
18
+ /** Fallback text shown on terminals without an image protocol. */
19
+ alt?: string;
20
+ /**
21
+ * Character cell aspect ratio (cellHeight / cellWidth). Most terminals
22
+ * land around 2.0. Tweak if aspect-preserved images look stretched.
23
+ */
24
+ cellAspect?: number;
25
+ }
26
+ declare class Image extends Node<ImageState> {
27
+ #private;
28
+ constructor(state: ImageState);
29
+ get fallback(): string[];
30
+ layout(): Layout;
31
+ protected _render(ctx: RenderCtx): Promise<string[]>;
32
+ }
33
+ declare function image(src: string, style?: Omit<ImageState, "src">): Image;
34
+ declare function image(state: ImageState): Image;
35
+ //#endregion
36
+ export { ImageState as n, image as r, Image as t };
37
+ //# sourceMappingURL=image-BTxDPPiT.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-BTxDPPiT.d.mts","names":[],"sources":["../src/widgets/image.ts"],"mappings":";;UAWiB;;;;;;;EAOf;;EAEA;;;;;EAKA;;EAEA;;;;;EAKA;;cAGW,cAAc,KAAK;;EAI9B,YAAY,OAAO;MAOf;EAIK,UAAU;YAIH,QAAQ,KAAK,YAAY;;iBAuC3B,MAAM,aAAa,QAAQ,KAAK,qBAAqB;iBACrD,MAAM,OAAO,aAAa"}
package/dist/index.mjs CHANGED
@@ -1,7 +1,8 @@
1
1
  import { C as useActiveOwner, E as withOwner, S as unwrap, T as withActiveNode, _ as peek, a as createIterable, b as toAccessor, c as createRef, d as createSuspenseBoundary, f as effect, g as onCleanup, h as memo, i as createContext, l as createRoot, m as isAccessor, n as SuspenseContext, o as createNode, p as inRenderContextOf, r as createAsync, s as createProgressive, t as Owner, u as createStore, v as provideContext, w as useContext, x as untrack, y as signal } from "./reactive-f7NpAi69.mjs";
2
- import { n as inspectFormat, r as isMarkdown, t as inspect } from "./inspect-D1d9t-ni.mjs";
3
- import { n as createRender, t as RenderContext } from "./render-DxVLqqB9.mjs";
4
- import { t as codeToAnsi } from "./shiki-BrjVUkeh.mjs";
2
+ import { n as inspectFormat, r as isMarkdown, t as inspect } from "./inspect-BaKG6cU_.mjs";
3
+ import { n as createRender, t as RenderContext } from "./render-CPUD4yaW.mjs";
4
+ import { t as codeToAnsi } from "./shiki-BK-v9CtF.mjs";
5
+ import { a as isKeyPattern, i as canonical, n as parseAttrs, o as keyMatches, r as KeyPatternError, t as TerminalQueries } from "./queries-B_lOwEiE.mjs";
5
6
  //#region src/input/index.ts
6
7
  function defineAction(action) {
7
8
  return action;
@@ -9,214 +10,17 @@ function defineAction(action) {
9
10
  //#endregion
10
11
  //#region src/core/index.ts
11
12
  async function createCtx(opts = {}) {
12
- const { createCtx: create } = await import("./render-DxVLqqB9.mjs").then((n) => n.i);
13
+ const { createCtx: create } = await import("./ctx-DhJIKuOX.mjs");
13
14
  return create(opts);
14
15
  }
15
16
  //#endregion
16
17
  //#region src/renderer/index.ts
17
18
  /** Factory shorthand for `new Renderer(opts)`. */
18
19
  async function createRenderer(opts = {}) {
19
- const { Renderer } = await import("./renderer-CxL4xbkl.mjs");
20
+ const { Renderer } = await import("./renderer-DJ1pWXSL.mjs");
20
21
  return new Renderer(opts);
21
22
  }
22
23
  //#endregion
23
- //#region src/input/keys.ts
24
- const MOD_NAMES = /* @__PURE__ */ new Set([
25
- "ctrl",
26
- "alt",
27
- "shift",
28
- "meta"
29
- ]);
30
- const SPECIAL_KEY_NAMES = /* @__PURE__ */ new Set([
31
- "enter",
32
- "tab",
33
- "backspace",
34
- "delete",
35
- "space",
36
- "esc",
37
- "up",
38
- "down",
39
- "left",
40
- "right",
41
- "home",
42
- "end",
43
- "pageup",
44
- "pagedown",
45
- "insert",
46
- "f1",
47
- "f2",
48
- "f3",
49
- "f4",
50
- "f5",
51
- "f6",
52
- "f7",
53
- "f8",
54
- "f9",
55
- "f10",
56
- "f11",
57
- "f12"
58
- ]);
59
- var KeyPatternError = class extends Error {
60
- constructor(pattern, reason) {
61
- super(`invalid key pattern ${JSON.stringify(pattern)}: ${reason}`);
62
- this.name = "KeyPatternError";
63
- }
64
- };
65
- function parsePattern(pattern) {
66
- const mods = {
67
- alt: false,
68
- ctrl: false,
69
- meta: false,
70
- shift: false
71
- };
72
- let name = pattern;
73
- while (name.length > 0) {
74
- const dash = name.indexOf("-");
75
- if (dash <= 0) break;
76
- const mod = name.slice(0, dash);
77
- if (!MOD_NAMES.has(mod)) throw new KeyPatternError(pattern, `unknown modifier: ${mod}`);
78
- if (mods[mod]) throw new KeyPatternError(pattern, `duplicate modifier: ${mod}`);
79
- mods[mod] = true;
80
- name = name.slice(dash + 1);
81
- }
82
- const ret = normalizeKey({
83
- ...mods,
84
- name
85
- });
86
- name = ret.name;
87
- if (name === "") throw new KeyPatternError(pattern, "missing key name");
88
- if (name.includes("-") && name !== "-") throw new KeyPatternError(pattern, "too many keys");
89
- if (!isPrintableKeyName(name)) throw new KeyPatternError(pattern, `unknown key name: ${name}`);
90
- if (mods.shift && !canUseShiftModifier(name)) throw new KeyPatternError(pattern, `shift-${name} will not trigger; bind the shifted character instead`);
91
- return ret;
92
- }
93
- function normalizeKey(p) {
94
- if (/^[A-Z]$/.test(p.name)) return {
95
- ...p,
96
- name: p.name.toLowerCase(),
97
- shift: true
98
- };
99
- if (p.name === " ") return {
100
- ...p,
101
- name: "space"
102
- };
103
- return p;
104
- }
105
- function isPrintableKeyName(s) {
106
- return SPECIAL_KEY_NAMES.has(s) || [...s].length === 1 && !/[\p{C}]/u.test(s);
107
- }
108
- function canUseShiftModifier(name) {
109
- return /^[a-zA-Z]$/.test(name) || SPECIAL_KEY_NAMES.has(name);
110
- }
111
- function isKeyPattern(s) {
112
- try {
113
- canonical(s);
114
- return true;
115
- } catch {
116
- return false;
117
- }
118
- }
119
- /**
120
- * Canonical string form of a pattern or event — modifiers in a fixed
121
- * alphabetical order, then the key name, joined by `-`. Used by the
122
- * router to build a pattern index whose keys match regardless of how
123
- * the user spelled the modifier order (`"ctrl-shift-a"` and
124
- * `"shift-ctrl-a"` both canonicalize to `"ctrl-shift-a"`).
125
- */
126
- function canonical(patternOrEvent) {
127
- const p = typeof patternOrEvent === "string" ? parsePattern(patternOrEvent) : normalizeKey(patternOrEvent);
128
- const parts = [];
129
- if (p.alt) parts.push("alt");
130
- if (p.ctrl) parts.push("ctrl");
131
- if (p.meta) parts.push("meta");
132
- if (p.shift) parts.push("shift");
133
- parts.push(p.name);
134
- return parts.join("-");
135
- }
136
- /**
137
- * Test whether an event matches a pattern (or any of a list of patterns).
138
- * Unspecified modifiers in the pattern must be *absent* on the event —
139
- * matching is strict, not inclusive, so `"a"` only matches a bare `a`
140
- * (no ctrl/alt/etc.).
141
- */
142
- function keyMatches(ev, pattern) {
143
- if (Array.isArray(pattern)) {
144
- for (const p of pattern) if (keyMatches(ev, p)) return true;
145
- return false;
146
- }
147
- const p = parsePattern(pattern);
148
- const e = normalizeKey(ev);
149
- return e.name === p.name && e.ctrl === p.ctrl && e.alt === p.alt && e.shift === p.shift && e.meta === p.meta;
150
- }
151
- //#endregion
152
- //#region src/input/queries.ts
153
- var TerminalQueries = class {
154
- #router;
155
- #terminal;
156
- constructor(router, terminal) {
157
- this.#router = router;
158
- this.#terminal = terminal;
159
- }
160
- query(query) {
161
- const timeout = query.timeout ?? 200;
162
- const ac = new AbortController();
163
- return new Promise((resolve) => {
164
- const finish = (value) => {
165
- if (ac.signal.aborted) return;
166
- ac.abort();
167
- clearTimeout(timer);
168
- resolve(value);
169
- };
170
- const timer = setTimeout(() => finish(), timeout);
171
- timer.unref();
172
- this.#router.on("term-response", ({ event }) => {
173
- const value = query.match(event);
174
- if (value !== void 0) finish(value);
175
- }, { signal: ac.signal });
176
- this.#terminal.write(query.wrap?.(query.request) ?? query.request);
177
- });
178
- }
179
- primaryDeviceAttributes(opts = {}) {
180
- return this.query({
181
- match: (ev) => ev.kind === "csi" && ev.final === "c" && ev.params.startsWith("?") ? {
182
- ...ev,
183
- attrs: parseAttrs(ev.params)
184
- } : void 0,
185
- request: "\x1B[c",
186
- ...opts
187
- });
188
- }
189
- secondaryDeviceAttributes(opts = {}) {
190
- return this.query({
191
- match: (ev) => ev.kind === "csi" && ev.final === "c" && ev.params.startsWith(">") ? {
192
- ...ev,
193
- attrs: parseAttrs(ev.params)
194
- } : void 0,
195
- request: "\x1B[>c",
196
- ...opts
197
- });
198
- }
199
- xtVersion(opts = {}) {
200
- return this.query({
201
- match: (ev) => {
202
- if (ev.kind !== "dcs" || !ev.payload.startsWith(">|")) return;
203
- const payload = ev.payload.slice(2);
204
- const m = payload.match(/^([^\s]+)\(([^\s]+)\)$/) ?? payload.match(/^([^\s]+)\s+([^\s]+)$/);
205
- return {
206
- ...ev,
207
- name: m?.[1] ?? payload,
208
- version: m?.[2]
209
- };
210
- },
211
- request: "\x1B[>q",
212
- ...opts
213
- });
214
- }
215
- };
216
- function parseAttrs(params) {
217
- return params.slice(1).split(";").map((n) => Number.parseInt(n, 10)).filter(Number.isFinite);
218
- }
219
- //#endregion
220
24
  export { KeyPatternError, Owner, RenderContext, SuspenseContext, TerminalQueries, canonical, codeToAnsi, createAsync, createContext, createCtx, createIterable, createNode, createProgressive, createRef, createRender, createRenderer, createRoot, createStore, createSuspenseBoundary, defineAction, effect, inRenderContextOf, inspect, inspectFormat, isAccessor, isKeyPattern, isMarkdown, keyMatches, memo, onCleanup, parseAttrs, peek, provideContext, signal, toAccessor, untrack, unwrap, useActiveOwner, useContext, withActiveNode, withOwner };
221
25
 
222
26
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["#router","#terminal"],"sources":["../src/input/index.ts","../src/core/index.ts","../src/renderer/index.ts","../src/input/keys.ts","../src/input/queries.ts"],"sourcesContent":["import type { ArgsOpts } from \"@zaly/shared/args\"\nimport type { Action, ActionDef } from \"./actions.ts\"\n\nexport function defineAction<T extends ArgsOpts = ArgsOpts>(action: ActionDef<T>): ActionDef<T>\nexport function defineAction<T extends ArgsOpts = ArgsOpts>(action: Action<T>): Action<T>\nexport function defineAction<T extends ArgsOpts = ArgsOpts>(\n action: ActionDef<T> | Action<T>\n): ActionDef<T> | Action<T> {\n return action\n}\n","import type { Theme } from \"../themes/types.ts\"\nimport type { RenderCtx } from \"./ctx.ts\"\n\nexport type { RenderCtx, MountCtx } from \"./ctx.ts\"\n\nexport type * from \"./node.ts\"\nexport type * from \"./state.ts\"\n\nexport * from \"./reactive.ts\"\nexport * from \"./render.ts\"\n\nexport async function createCtx(\n opts: Partial<RenderCtx> & { theme?: Theme } = {}\n): Promise<RenderCtx> {\n const { createCtx: create } = await import(\"./ctx.ts\")\n return create(opts)\n}\n","import type { Renderer, RendererOptions } from \"./renderer.ts\"\n\nexport type * from \"./renderer.ts\"\nexport type { OverlaySurface } from \"./overlay.ts\"\nexport type { Stream } from \"./stream.ts\"\nexport type { Terminal } from \"./terminal.ts\"\nexport type { UI } from \"./ui.ts\"\n\n/** Factory shorthand for `new Renderer(opts)`. */\nexport async function createRenderer(opts: RendererOptions = {}): Promise<Renderer> {\n const { Renderer } = await import(\"./renderer.ts\")\n return new Renderer(opts)\n}\n","/**\n * Keyboard event shape + pattern-based matcher.\n *\n * `KeyEvent.name` is a canonical name:\n * - Single characters for printable keys: `\"a\"`, `\"A\"`, `\" \"`, `\"!\"`. The\n * `name` reflects the raw character the decoder produced — so `Shift+A`\n * arrives as `{ name: \"A\", shift: true }` (terminals already fold\n * shift into the uppercase byte for letters).\n * - Named constants for non-printing keys: `\"enter\"`, `\"tab\"`, `\"esc\"`,\n * `\"backspace\"`, `\"delete\"`, `\"space\"`, arrows `\"up\"/\"down\"/\"left\"/\n * \"right\"`, navigation `\"home\"/\"end\"/\"pageup\"/\"pagedown\"/\"insert\"`,\n * function keys `\"f1\"` .. `\"f12\"`.\n *\n * Patterns for `keyMatches` are dash-separated modifier prefixes plus the\n * name: `\"a\"`, `\"ctrl-c\"`, `\"shift-tab\"`, `\"ctrl-shift-x\"`. Unknown\n * prefixes are treated as literal characters in the name, so\n * `\"something-foo\"` is interpreted as the name `\"something-foo\"` rather\n * than a missing-modifier error.\n *\n * Modifier prefixes (order-independent):\n * - `ctrl-`\n * - `alt-`\n * - `shift-`\n * - `meta-` (a.k.a. super / cmd)\n */\n\nexport interface KeyEvent {\n /** Canonical key name — raw character or one of the named constants above. */\n name: string\n /**\n * The literal text the keystroke would insert, when that makes sense.\n * For printable chars this is the char itself; for Enter, Tab, etc. it's\n * undefined. Widgets use this to decide whether to insert content vs.\n * treat the key as a command.\n */\n text?: string\n ctrl: boolean\n alt: boolean\n shift: boolean\n meta: boolean\n}\n\n/** Canonical modifier names used in `KeyPattern`. */\nexport type KeyModifier = \"ctrl\" | \"alt\" | \"shift\" | \"meta\"\n\n/**\n * Named keys the decoder emits for non-printable keystrokes. Bindings\n * reference these directly (`\"enter\"`, `\"f5\"`, `\"pageup\"`, …).\n */\nexport type SpecialKeyName = (typeof specialKeys)[number]\n\ndeclare const KeyPatternBrand: unique symbol\n\n/** A validated, canonical key binding string. */\nexport type KeyPattern = string & { readonly [KeyPatternBrand]: true }\n\nconst MOD_NAMES = new Set<string>([\"ctrl\", \"alt\", \"shift\", \"meta\"])\nconst specialKeys = [\n \"enter\",\n \"tab\",\n \"backspace\",\n \"delete\",\n \"space\",\n \"esc\",\n \"up\",\n \"down\",\n \"left\",\n \"right\",\n \"home\",\n \"end\",\n \"pageup\",\n \"pagedown\",\n \"insert\",\n \"f1\",\n \"f2\",\n \"f3\",\n \"f4\",\n \"f5\",\n \"f6\",\n \"f7\",\n \"f8\",\n \"f9\",\n \"f10\",\n \"f11\",\n \"f12\",\n] as const\nconst SPECIAL_KEY_NAMES = new Set<string>(specialKeys)\n\ninterface ParsedPattern {\n name: string\n ctrl: boolean\n alt: boolean\n shift: boolean\n meta: boolean\n}\n\nexport class KeyPatternError extends Error {\n constructor(pattern: string, reason: string) {\n super(`invalid key pattern ${JSON.stringify(pattern)}: ${reason}`)\n this.name = \"KeyPatternError\"\n }\n}\n\nfunction parsePattern(pattern: string): ParsedPattern {\n const mods = { alt: false, ctrl: false, meta: false, shift: false }\n let name = pattern\n while (name.length > 0) {\n const dash = name.indexOf(\"-\")\n if (dash <= 0) break\n const mod = name.slice(0, dash)\n if (!MOD_NAMES.has(mod)) throw new KeyPatternError(pattern, `unknown modifier: ${mod}`)\n if (mods[mod as KeyModifier]) throw new KeyPatternError(pattern, `duplicate modifier: ${mod}`)\n mods[mod as KeyModifier] = true\n name = name.slice(dash + 1)\n }\n\n const ret = normalizeKey({ ...mods, name })\n name = ret.name\n if (name === \"\") throw new KeyPatternError(pattern, \"missing key name\")\n if (name.includes(\"-\") && name !== \"-\") throw new KeyPatternError(pattern, \"too many keys\")\n if (!isPrintableKeyName(name)) throw new KeyPatternError(pattern, `unknown key name: ${name}`)\n if (mods.shift && !canUseShiftModifier(name)) {\n throw new KeyPatternError(\n pattern,\n `shift-${name} will not trigger; bind the shifted character instead`\n )\n }\n return ret\n}\n\nfunction normalizeKey(p: ParsedPattern): ParsedPattern {\n if (/^[A-Z]$/.test(p.name)) return { ...p, name: p.name.toLowerCase(), shift: true }\n if (p.name === \" \") return { ...p, name: \"space\" }\n return p\n}\n\nfunction isPrintableKeyName(s: string): boolean {\n // oxlint-disable-next-line typescript/no-misused-spread\n return SPECIAL_KEY_NAMES.has(s) || ([...s].length === 1 && !/[\\p{C}]/u.test(s))\n}\n\nfunction canUseShiftModifier(name: string): boolean {\n return /^[a-zA-Z]$/.test(name) || SPECIAL_KEY_NAMES.has(name)\n}\n\nexport function isKeyPattern(s: string): s is KeyPattern {\n try {\n canonical(s)\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Canonical string form of a pattern or event — modifiers in a fixed\n * alphabetical order, then the key name, joined by `-`. Used by the\n * router to build a pattern index whose keys match regardless of how\n * the user spelled the modifier order (`\"ctrl-shift-a\"` and\n * `\"shift-ctrl-a\"` both canonicalize to `\"ctrl-shift-a\"`).\n */\nexport function canonical(patternOrEvent: string | KeyEvent): KeyPattern {\n const p =\n typeof patternOrEvent === \"string\" ? parsePattern(patternOrEvent) : normalizeKey(patternOrEvent)\n const parts: string[] = []\n if (p.alt) parts.push(\"alt\")\n if (p.ctrl) parts.push(\"ctrl\")\n if (p.meta) parts.push(\"meta\")\n if (p.shift) parts.push(\"shift\")\n parts.push(p.name)\n return parts.join(\"-\") as KeyPattern\n}\n\n/**\n * Test whether an event matches a pattern (or any of a list of patterns).\n * Unspecified modifiers in the pattern must be *absent* on the event —\n * matching is strict, not inclusive, so `\"a\"` only matches a bare `a`\n * (no ctrl/alt/etc.).\n */\nexport function keyMatches(ev: KeyEvent, pattern: string | readonly string[]): boolean {\n if (Array.isArray(pattern)) {\n for (const p of pattern) if (keyMatches(ev, p)) return true\n return false\n }\n const p = parsePattern(pattern as string)\n const e = normalizeKey(ev)\n return (\n e.name === p.name &&\n e.ctrl === p.ctrl &&\n e.alt === p.alt &&\n e.shift === p.shift &&\n e.meta === p.meta\n )\n}\n","import type { TerminalResponseEvent } from \"./decoder.ts\"\nimport type { InputRouter } from \"./router.ts\"\n\nexport type TerminalQuery<T = TerminalResponseEvent> = TerminalQueryOpts & {\n request: string\n match: (event: TerminalResponseEvent) => T | undefined\n}\n\nexport type TerminalQueryOpts = {\n timeout?: number\n wrap?: (seq: string) => string\n}\n\ntype TerminalQueryWriter = {\n write: (seq: string) => void\n}\n\nexport class TerminalQueries {\n readonly #router: InputRouter\n readonly #terminal: TerminalQueryWriter\n\n constructor(router: InputRouter, terminal: TerminalQueryWriter) {\n this.#router = router\n this.#terminal = terminal\n }\n\n query<T>(query: TerminalQuery<T>): Promise<T | undefined> {\n const timeout = query.timeout ?? 200\n const ac = new AbortController()\n return new Promise((resolve) => {\n const finish = (value?: T) => {\n if (ac.signal.aborted) return\n ac.abort()\n clearTimeout(timer)\n resolve(value)\n }\n const timer = setTimeout(() => finish(), timeout)\n timer.unref()\n this.#router.on(\n \"term-response\",\n ({ event }) => {\n const value = query.match(event)\n if (value !== undefined) finish(value)\n },\n { signal: ac.signal }\n )\n this.#terminal.write(query.wrap?.(query.request) ?? query.request)\n })\n }\n\n primaryDeviceAttributes(opts: TerminalQueryOpts = {}) {\n return this.query<TerminalResponseEvent & { attrs: number[] }>({\n match: (ev) =>\n ev.kind === \"csi\" && ev.final === \"c\" && ev.params.startsWith(\"?\")\n ? { ...ev, attrs: parseAttrs(ev.params) }\n : undefined,\n request: \"\\x1b[c\",\n ...opts,\n })\n }\n\n secondaryDeviceAttributes(opts: TerminalQueryOpts = {}) {\n return this.query<TerminalResponseEvent & { attrs: number[] }>({\n match: (ev) =>\n ev.kind === \"csi\" && ev.final === \"c\" && ev.params.startsWith(\">\")\n ? { ...ev, attrs: parseAttrs(ev.params) }\n : undefined,\n request: \"\\x1b[>c\",\n ...opts,\n })\n }\n\n xtVersion(opts: TerminalQueryOpts = {}) {\n return this.query<TerminalResponseEvent & { name: string; version?: string }>({\n match: (ev) => {\n if (ev.kind !== \"dcs\" || !ev.payload.startsWith(\">|\")) return\n const payload = ev.payload.slice(2)\n const m = payload.match(/^([^\\s]+)\\(([^\\s]+)\\)$/) ?? payload.match(/^([^\\s]+)\\s+([^\\s]+)$/)\n return { ...ev, name: m?.[1] ?? payload, version: m?.[2] }\n },\n request: \"\\x1b[>q\",\n ...opts,\n })\n }\n}\n\nexport function parseAttrs(params: string): number[] {\n return params\n .slice(1)\n .split(\";\")\n .map((n) => Number.parseInt(n, 10))\n .filter(Number.isFinite)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/input/index.ts","../src/core/index.ts","../src/renderer/index.ts"],"sourcesContent":["import type { ArgsOpts } from \"@zaly/shared/args\"\nimport type { Action, ActionDef } from \"./actions.ts\"\n\nexport function defineAction<T extends ArgsOpts = ArgsOpts>(action: ActionDef<T>): ActionDef<T>\nexport function defineAction<T extends ArgsOpts = ArgsOpts>(action: Action<T>): Action<T>\nexport function defineAction<T extends ArgsOpts = ArgsOpts>(\n action: ActionDef<T> | Action<T>\n): ActionDef<T> | Action<T> {\n return action\n}\n","import type { Theme } from \"../themes/types.ts\"\nimport type { RenderCtx } from \"./ctx.ts\"\n\nexport type { RenderCtx, MountCtx } from \"./ctx.ts\"\n\nexport type * from \"./node.ts\"\nexport type * from \"./state.ts\"\n\nexport * from \"./reactive.ts\"\nexport * from \"./render.ts\"\n\nexport async function createCtx(\n opts: Partial<RenderCtx> & { theme?: Theme } = {}\n): Promise<RenderCtx> {\n const { createCtx: create } = await import(\"./ctx.ts\")\n return create(opts)\n}\n","import type { Renderer, RendererOptions } from \"./renderer.ts\"\n\nexport type * from \"./renderer.ts\"\nexport type { OverlaySurface } from \"./overlay.ts\"\nexport type { Stream } from \"./stream.ts\"\nexport type { Terminal } from \"./terminal.ts\"\nexport type { UI } from \"./ui.ts\"\n\n/** Factory shorthand for `new Renderer(opts)`. */\nexport async function createRenderer(opts: RendererOptions = {}): Promise<Renderer> {\n const { Renderer } = await import(\"./renderer.ts\")\n return new Renderer(opts)\n}\n"],"mappings":";;;;;;AAKA,SAAgB,aACd,QAC0B;CAC1B,OAAO;AACT;;;ACEA,eAAsB,UACpB,OAA+C,CAAC,GAC5B;CACpB,MAAM,EAAE,WAAW,WAAW,MAAM,OAAO;CAC3C,OAAO,OAAO,IAAI;AACpB;;;;ACPA,eAAsB,eAAe,OAAwB,CAAC,GAAsB;CAClF,MAAM,EAAE,aAAa,MAAM,OAAO;CAClC,OAAO,IAAI,SAAS,IAAI;AAC1B"}