@zaly/tui 0.0.4

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 (228) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +59 -0
  3. package/assets/schemas/theme.schema.json +899 -0
  4. package/assets/themes/LICENSE-tokyonight.txt +201 -0
  5. package/assets/themes/NOTICES.md +69 -0
  6. package/assets/themes/ayu-dark.json +119 -0
  7. package/assets/themes/catppuccin-frappe.json +124 -0
  8. package/assets/themes/catppuccin-latte.json +124 -0
  9. package/assets/themes/catppuccin-macchiato.json +124 -0
  10. package/assets/themes/catppuccin-mocha.json +124 -0
  11. package/assets/themes/dracula-soft.json +119 -0
  12. package/assets/themes/dracula.json +119 -0
  13. package/assets/themes/everforest-dark.json +118 -0
  14. package/assets/themes/everforest-light.json +118 -0
  15. package/assets/themes/github-dark.json +123 -0
  16. package/assets/themes/github-light.json +123 -0
  17. package/assets/themes/gruvbox-dark-medium.json +112 -0
  18. package/assets/themes/kanagawa-dragon.json +115 -0
  19. package/assets/themes/kanagawa-wave.json +115 -0
  20. package/assets/themes/material-theme-palenight.json +114 -0
  21. package/assets/themes/min-dark.json +55 -0
  22. package/assets/themes/min-light.json +59 -0
  23. package/assets/themes/monokai.json +116 -0
  24. package/assets/themes/night-owl.json +116 -0
  25. package/assets/themes/nord.json +101 -0
  26. package/assets/themes/one-dark-pro.json +110 -0
  27. package/assets/themes/one-light.json +108 -0
  28. package/assets/themes/poimandres.json +123 -0
  29. package/assets/themes/rose-pine.json +98 -0
  30. package/assets/themes/solarized-dark.json +116 -0
  31. package/assets/themes/solarized-light.json +116 -0
  32. package/assets/themes/synthwave-84.json +100 -0
  33. package/assets/themes/tokyonight-day.json +157 -0
  34. package/assets/themes/tokyonight-moon.json +157 -0
  35. package/assets/themes/tokyonight-night.json +157 -0
  36. package/assets/themes/tokyonight-storm.json +157 -0
  37. package/assets/themes/vesper.json +103 -0
  38. package/assets/themes/vitesse-dark.json +126 -0
  39. package/assets/themes/vitesse-light.json +126 -0
  40. package/dist/ansi-Clq0ozyA.mjs +206 -0
  41. package/dist/ansi-Clq0ozyA.mjs.map +1 -0
  42. package/dist/ansi.d.mts +48 -0
  43. package/dist/ansi.d.mts.map +1 -0
  44. package/dist/ansi.mjs +2 -0
  45. package/dist/autocomplete-Dfw-yQDa.d.mts +100 -0
  46. package/dist/autocomplete-Dfw-yQDa.d.mts.map +1 -0
  47. package/dist/box-DyaByEiG.mjs +386 -0
  48. package/dist/box-DyaByEiG.mjs.map +1 -0
  49. package/dist/builder-D49ECBEf.mjs +385 -0
  50. package/dist/builder-D49ECBEf.mjs.map +1 -0
  51. package/dist/callbacks-CNjGNxVw.mjs +279 -0
  52. package/dist/callbacks-CNjGNxVw.mjs.map +1 -0
  53. package/dist/client-D6C_uczF.mjs +142 -0
  54. package/dist/client-D6C_uczF.mjs.map +1 -0
  55. package/dist/clipboard.d.mts +104 -0
  56. package/dist/clipboard.d.mts.map +1 -0
  57. package/dist/clipboard.mjs +404 -0
  58. package/dist/clipboard.mjs.map +1 -0
  59. package/dist/flex-Bguo-fUe.mjs +202 -0
  60. package/dist/flex-Bguo-fUe.mjs.map +1 -0
  61. package/dist/image-Cm5T-uw-.mjs +108 -0
  62. package/dist/image-Cm5T-uw-.mjs.map +1 -0
  63. package/dist/image.d.mts +123 -0
  64. package/dist/image.d.mts.map +1 -0
  65. package/dist/image.mjs +2 -0
  66. package/dist/index.d.mts +64 -0
  67. package/dist/index.d.mts.map +1 -0
  68. package/dist/index.mjs +222 -0
  69. package/dist/index.mjs.map +1 -0
  70. package/dist/input-B5Vy-iaa.d.mts +141 -0
  71. package/dist/input-B5Vy-iaa.d.mts.map +1 -0
  72. package/dist/inspect-D1d9t-ni.mjs +101 -0
  73. package/dist/inspect-D1d9t-ni.mjs.map +1 -0
  74. package/dist/inspect-D6FW_QUo.d.mts +67 -0
  75. package/dist/inspect-D6FW_QUo.d.mts.map +1 -0
  76. package/dist/kitty-JbCJC0iQ.mjs +673 -0
  77. package/dist/kitty-JbCJC0iQ.mjs.map +1 -0
  78. package/dist/markdown.d.mts +24 -0
  79. package/dist/markdown.d.mts.map +1 -0
  80. package/dist/markdown.mjs +2 -0
  81. package/dist/md.bun.d.mts +14 -0
  82. package/dist/md.bun.d.mts.map +1 -0
  83. package/dist/md.bun.mjs +28 -0
  84. package/dist/md.bun.mjs.map +1 -0
  85. package/dist/md.node.d.mts +14 -0
  86. package/dist/md.node.d.mts.map +1 -0
  87. package/dist/md.node.mjs +126 -0
  88. package/dist/md.node.mjs.map +1 -0
  89. package/dist/node-BZ7f6HzU.mjs +316 -0
  90. package/dist/node-BZ7f6HzU.mjs.map +1 -0
  91. package/dist/picker-D8OLb6kZ.d.mts +36 -0
  92. package/dist/picker-D8OLb6kZ.d.mts.map +1 -0
  93. package/dist/picker-ndVVt6qF.mjs +621 -0
  94. package/dist/picker-ndVVt6qF.mjs.map +1 -0
  95. package/dist/queries-DH3bj74K.d.mts +1963 -0
  96. package/dist/queries-DH3bj74K.d.mts.map +1 -0
  97. package/dist/reactive-f7NpAi69.mjs +623 -0
  98. package/dist/reactive-f7NpAi69.mjs.map +1 -0
  99. package/dist/registry-U654j61Y.mjs +356 -0
  100. package/dist/registry-U654j61Y.mjs.map +1 -0
  101. package/dist/render-DxVLqqB9.mjs +74 -0
  102. package/dist/render-DxVLqqB9.mjs.map +1 -0
  103. package/dist/renderer-CdLCkJB-.mjs +42 -0
  104. package/dist/renderer-CdLCkJB-.mjs.map +1 -0
  105. package/dist/renderer-CxL4xbkl.mjs +2644 -0
  106. package/dist/renderer-CxL4xbkl.mjs.map +1 -0
  107. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  108. package/dist/search-FvGnswRl.d.mts +49 -0
  109. package/dist/search-FvGnswRl.d.mts.map +1 -0
  110. package/dist/select-CbmAZdpt.d.mts +116 -0
  111. package/dist/select-CbmAZdpt.d.mts.map +1 -0
  112. package/dist/services/logger.d.mts +2 -0
  113. package/dist/services/logger.mjs +71 -0
  114. package/dist/services/logger.mjs.map +1 -0
  115. package/dist/services/notifier.d.mts +17 -0
  116. package/dist/services/notifier.d.mts.map +1 -0
  117. package/dist/services/notifier.mjs +71 -0
  118. package/dist/services/notifier.mjs.map +1 -0
  119. package/dist/services/picker.d.mts +36 -0
  120. package/dist/services/picker.d.mts.map +1 -0
  121. package/dist/services/picker.mjs +137 -0
  122. package/dist/services/picker.mjs.map +1 -0
  123. package/dist/services/prompt.d.mts +30 -0
  124. package/dist/services/prompt.d.mts.map +1 -0
  125. package/dist/services/prompt.mjs +83 -0
  126. package/dist/services/prompt.mjs.map +1 -0
  127. package/dist/shiki-BrjVUkeh.mjs +423 -0
  128. package/dist/shiki-BrjVUkeh.mjs.map +1 -0
  129. package/dist/size-D8JogYLy.mjs +34 -0
  130. package/dist/size-D8JogYLy.mjs.map +1 -0
  131. package/dist/style.d.mts +10 -0
  132. package/dist/style.d.mts.map +1 -0
  133. package/dist/style.mjs +4 -0
  134. package/dist/text.d.mts +33 -0
  135. package/dist/text.d.mts.map +1 -0
  136. package/dist/text.mjs +111 -0
  137. package/dist/text.mjs.map +1 -0
  138. package/dist/theme.config-CU3B50HN.mjs +832 -0
  139. package/dist/theme.config-CU3B50HN.mjs.map +1 -0
  140. package/dist/themes.d.mts +113 -0
  141. package/dist/themes.d.mts.map +1 -0
  142. package/dist/themes.mjs +2 -0
  143. package/dist/tree-C28QOVIK.d.mts +23 -0
  144. package/dist/tree-C28QOVIK.d.mts.map +1 -0
  145. package/dist/types-B9Eh7k2v.d.mts +212 -0
  146. package/dist/types-B9Eh7k2v.d.mts.map +1 -0
  147. package/dist/types-D3jk1rtk.d.mts +140 -0
  148. package/dist/types-D3jk1rtk.d.mts.map +1 -0
  149. package/dist/utils-3M4D_AXZ.mjs +40 -0
  150. package/dist/utils-3M4D_AXZ.mjs.map +1 -0
  151. package/dist/widgets/autocomplete.d.mts +2 -0
  152. package/dist/widgets/autocomplete.mjs +165 -0
  153. package/dist/widgets/autocomplete.mjs.map +1 -0
  154. package/dist/widgets/box.d.mts +2 -0
  155. package/dist/widgets/box.mjs +2 -0
  156. package/dist/widgets/code.d.mts +48 -0
  157. package/dist/widgets/code.d.mts.map +1 -0
  158. package/dist/widgets/code.mjs +59 -0
  159. package/dist/widgets/code.mjs.map +1 -0
  160. package/dist/widgets/completions/actions.d.mts +41 -0
  161. package/dist/widgets/completions/actions.d.mts.map +1 -0
  162. package/dist/widgets/completions/actions.mjs +48 -0
  163. package/dist/widgets/completions/actions.mjs.map +1 -0
  164. package/dist/widgets/completions/files.d.mts +29 -0
  165. package/dist/widgets/completions/files.d.mts.map +1 -0
  166. package/dist/widgets/completions/files.mjs +42 -0
  167. package/dist/widgets/completions/files.mjs.map +1 -0
  168. package/dist/widgets/completions/github.d.mts +64 -0
  169. package/dist/widgets/completions/github.d.mts.map +1 -0
  170. package/dist/widgets/completions/github.mjs +137 -0
  171. package/dist/widgets/completions/github.mjs.map +1 -0
  172. package/dist/widgets/completions/index.d.mts +4 -0
  173. package/dist/widgets/completions/index.mjs +4 -0
  174. package/dist/widgets/diff.d.mts +57 -0
  175. package/dist/widgets/diff.d.mts.map +1 -0
  176. package/dist/widgets/diff.mjs +199 -0
  177. package/dist/widgets/diff.mjs.map +1 -0
  178. package/dist/widgets/divider.d.mts +11 -0
  179. package/dist/widgets/divider.d.mts.map +1 -0
  180. package/dist/widgets/divider.mjs +9 -0
  181. package/dist/widgets/divider.mjs.map +1 -0
  182. package/dist/widgets/image.d.mts +37 -0
  183. package/dist/widgets/image.d.mts.map +1 -0
  184. package/dist/widgets/image.mjs +77 -0
  185. package/dist/widgets/image.mjs.map +1 -0
  186. package/dist/widgets/input.d.mts +2 -0
  187. package/dist/widgets/input.mjs +497 -0
  188. package/dist/widgets/input.mjs.map +1 -0
  189. package/dist/widgets/log.d.mts +2 -0
  190. package/dist/widgets/log.mjs +130 -0
  191. package/dist/widgets/log.mjs.map +1 -0
  192. package/dist/widgets/markdown.d.mts +45 -0
  193. package/dist/widgets/markdown.d.mts.map +1 -0
  194. package/dist/widgets/markdown.mjs +124 -0
  195. package/dist/widgets/markdown.mjs.map +1 -0
  196. package/dist/widgets/overlay.d.mts +2 -0
  197. package/dist/widgets/overlay.mjs +18 -0
  198. package/dist/widgets/overlay.mjs.map +1 -0
  199. package/dist/widgets/picker.d.mts +2 -0
  200. package/dist/widgets/picker.mjs +2 -0
  201. package/dist/widgets/progress.d.mts +48 -0
  202. package/dist/widgets/progress.d.mts.map +1 -0
  203. package/dist/widgets/progress.mjs +48 -0
  204. package/dist/widgets/progress.mjs.map +1 -0
  205. package/dist/widgets/select.d.mts +2 -0
  206. package/dist/widgets/select.mjs +195 -0
  207. package/dist/widgets/select.mjs.map +1 -0
  208. package/dist/widgets/show.d.mts +55 -0
  209. package/dist/widgets/show.d.mts.map +1 -0
  210. package/dist/widgets/show.mjs +85 -0
  211. package/dist/widgets/show.mjs.map +1 -0
  212. package/dist/widgets/spinner.d.mts +65 -0
  213. package/dist/widgets/spinner.d.mts.map +1 -0
  214. package/dist/widgets/spinner.mjs +147 -0
  215. package/dist/widgets/spinner.mjs.map +1 -0
  216. package/dist/widgets/text.d.mts +2 -0
  217. package/dist/widgets/text.mjs +32 -0
  218. package/dist/widgets/text.mjs.map +1 -0
  219. package/dist/widgets/tree.d.mts +2 -0
  220. package/dist/widgets/tree.mjs +73 -0
  221. package/dist/widgets/tree.mjs.map +1 -0
  222. package/dist/widgets/widget.d.mts +49 -0
  223. package/dist/widgets/widget.d.mts.map +1 -0
  224. package/dist/widgets/widget.mjs +40 -0
  225. package/dist/widgets/widget.mjs.map +1 -0
  226. package/dist/worker-DjHuQSbY.mjs +27 -0
  227. package/dist/worker-DjHuQSbY.mjs.map +1 -0
  228. package/package.json +117 -0
@@ -0,0 +1,621 @@
1
+ import { S as unwrap, f as effect, h as memo, s as createProgressive, x as untrack } from "./reactive-f7NpAi69.mjs";
2
+ import { widget } from "./widgets/widget.mjs";
3
+ import { Input } from "./widgets/input.mjs";
4
+ import { select } from "./widgets/select.mjs";
5
+ import { tree } from "./widgets/tree.mjs";
6
+ import { sliceAnsi, stripAnsi } from "@zaly/shared/ansi";
7
+ import { TopK } from "@zaly/shared/minheap";
8
+ //#region src/search/score.ts
9
+ const SCORE_MATCH = 16;
10
+ const SCORE_GAP_START = -3;
11
+ const SCORE_GAP_EXTENSION = -1;
12
+ const BONUS_BOUNDARY = SCORE_MATCH / 2;
13
+ const BONUS_NONWORD = SCORE_MATCH / 2;
14
+ const BONUS_CAMEL_123 = BONUS_BOUNDARY - 1;
15
+ const BONUS_CONSECUTIVE = 4;
16
+ const BONUS_FIRST_CHAR_MULTIPLIER = 2;
17
+ const BONUS_NO_PATH_SEP = BONUS_BOUNDARY - 2;
18
+ const CHAR_WHITE = 0;
19
+ const CHAR_NONWORD = 1;
20
+ const CHAR_DELIMITER = 2;
21
+ const CHAR_LOWER = 3;
22
+ const CHAR_UPPER = 4;
23
+ const CHAR_LETTER = 5;
24
+ const CHAR_NUMBER = 6;
25
+ const PATH_SEPS = /* @__PURE__ */ new Set(["/", "\\"]);
26
+ const CHAR_CLASS = Array.from({ length: 256 }, (_, b) => {
27
+ const ch = String.fromCharCode(b);
28
+ if (/\s/.test(ch)) return CHAR_WHITE;
29
+ if (String.raw`/\,:;|`.includes(ch)) return CHAR_DELIMITER;
30
+ if (b >= 48 && b <= 57) return CHAR_NUMBER;
31
+ if (b >= 65 && b <= 90) return CHAR_UPPER;
32
+ if (b >= 97 && b <= 122) return CHAR_LOWER;
33
+ return CHAR_NONWORD;
34
+ });
35
+ function charClass(str, pos) {
36
+ const code = str.charCodeAt(pos);
37
+ return code <= 255 ? CHAR_CLASS[code] ?? CHAR_NONWORD : CHAR_LETTER;
38
+ }
39
+ var Score = class {
40
+ #opts;
41
+ #bonusMatrix = [];
42
+ #bonusBoundaryWhite;
43
+ #bonusBoundaryDelimiter;
44
+ #consecutive = 0;
45
+ #firstBonus = 0;
46
+ #prev;
47
+ #prevClass = CHAR_WHITE;
48
+ #score = 0;
49
+ #str = "";
50
+ isFile = false;
51
+ constructor(opts = {}) {
52
+ this.#opts = opts;
53
+ this.#bonusBoundaryWhite = opts.historyBonus ? BONUS_BOUNDARY : 10;
54
+ this.#bonusBoundaryDelimiter = opts.historyBonus ? BONUS_BOUNDARY : 9;
55
+ for (let prev = 0; prev <= 6; prev++) {
56
+ this.#bonusMatrix[prev] = [];
57
+ for (let curr = 0; curr <= 6; curr++) this.#bonusMatrix[prev][curr] = this.#computeBonus(prev, curr);
58
+ }
59
+ }
60
+ get score() {
61
+ return this.#score;
62
+ }
63
+ isLeftBoundary(str, pos) {
64
+ return pos === 0 || charClass(str, pos - 1) < CHAR_LOWER;
65
+ }
66
+ isRightBoundary(str, pos) {
67
+ return pos === str.length - 1 || charClass(str, pos + 1) < CHAR_LOWER;
68
+ }
69
+ init(str, first) {
70
+ this.#str = str;
71
+ this.#score = 0;
72
+ this.#consecutive = 0;
73
+ this.#prevClass = first > 0 ? charClass(str, first - 1) : CHAR_WHITE;
74
+ this.#prev = void 0;
75
+ this.#firstBonus = 0;
76
+ if (this.isFile && this.#opts.filenameBonus && !hasPathSepAfter(str, first)) this.#score += BONUS_NO_PATH_SEP;
77
+ this.update(first);
78
+ }
79
+ update(pos) {
80
+ const cls = charClass(this.#str, pos);
81
+ const gap = this.#prev === void 0 ? 0 : pos - this.#prev - 1;
82
+ let bonus = 0;
83
+ if (gap > 0) {
84
+ this.#prevClass = charClass(this.#str, pos - 1);
85
+ bonus = this.#bonusMatrix[this.#prevClass]?.[cls] ?? 0;
86
+ this.#score += SCORE_GAP_START + (gap - 1) * SCORE_GAP_EXTENSION;
87
+ this.#consecutive = 0;
88
+ this.#firstBonus = 0;
89
+ } else {
90
+ bonus = this.#bonusMatrix[this.#prevClass]?.[cls] ?? 0;
91
+ if (this.#consecutive === 0) this.#firstBonus = bonus;
92
+ else {
93
+ if (bonus >= BONUS_BOUNDARY && bonus > this.#firstBonus) this.#firstBonus = bonus;
94
+ bonus = Math.max(bonus, this.#firstBonus, BONUS_CONSECUTIVE);
95
+ }
96
+ this.#consecutive++;
97
+ }
98
+ if (this.#prev === void 0) bonus *= BONUS_FIRST_CHAR_MULTIPLIER;
99
+ this.#score += SCORE_MATCH + bonus;
100
+ this.#prevClass = cls;
101
+ this.#prev = pos;
102
+ }
103
+ get(str, from, to) {
104
+ this.init(str, from);
105
+ for (let i = from + 1; i <= to; i++) this.update(i);
106
+ return this.#score;
107
+ }
108
+ #computeBonus(prev, curr) {
109
+ if (curr > CHAR_NONWORD) {
110
+ if (prev === CHAR_WHITE) return this.#bonusBoundaryWhite;
111
+ if (prev === CHAR_DELIMITER) return this.#bonusBoundaryDelimiter;
112
+ if (prev === CHAR_NONWORD) return BONUS_BOUNDARY;
113
+ }
114
+ if (prev === CHAR_LOWER && curr === CHAR_UPPER || prev !== CHAR_NUMBER && curr === CHAR_NUMBER) return BONUS_CAMEL_123;
115
+ if (curr === CHAR_NONWORD || curr === CHAR_DELIMITER) return BONUS_NONWORD;
116
+ if (curr === CHAR_WHITE) return 10;
117
+ return 0;
118
+ }
119
+ };
120
+ function hasPathSepAfter(str, first) {
121
+ for (let i = first + 1; i < str.length; i++) if (PATH_SEPS.has(str[i])) return true;
122
+ return false;
123
+ }
124
+ //#endregion
125
+ //#region src/search/matcher.ts
126
+ var Matcher = class {
127
+ opts;
128
+ score;
129
+ mods = [];
130
+ one;
131
+ pattern = "";
132
+ tick = 0;
133
+ constructor(opts = {}) {
134
+ this.opts = {
135
+ fuzzy: true,
136
+ ignorecase: true,
137
+ smartcase: true,
138
+ ...opts
139
+ };
140
+ this.score = new Score(opts);
141
+ }
142
+ empty() {
143
+ return this.mods.length === 0;
144
+ }
145
+ init(pattern) {
146
+ pattern = pattern.trim();
147
+ if (pattern === this.pattern) return false;
148
+ this.pattern = pattern;
149
+ this.tick++;
150
+ this.mods = [];
151
+ this.one = void 0;
152
+ if (pattern === "") return true;
153
+ if (this.opts.regex) this.mods = [[this.#prepare(pattern)]];
154
+ else {
155
+ let isOr = false;
156
+ for (const part of pattern.split(/ +/)) {
157
+ if (part === "|") {
158
+ isOr = true;
159
+ continue;
160
+ }
161
+ const mod = this.#prepare(part);
162
+ if (mod.pattern === "") continue;
163
+ if (isOr && this.mods.length > 0) this.mods.at(-1)?.push(mod);
164
+ else this.mods.push([mod]);
165
+ isOr = false;
166
+ }
167
+ }
168
+ this.mods = this.mods.map((ors) => ors.toSorted((a, b) => a.entropy - b.entropy));
169
+ this.mods = this.mods.toSorted((a, b) => (b[0]?.entropy ?? 0) - (a[0]?.entropy ?? 0));
170
+ if (this.mods.length === 1 && this.mods[0]?.length === 1) this.one = this.mods[0][0];
171
+ return true;
172
+ }
173
+ match(input) {
174
+ if (this.empty()) return 1e3;
175
+ const item = typeof input === "string" ? { text: input } : input;
176
+ if (this.one) return this.#match(item, this.one)?.score ?? 0;
177
+ let score = 0;
178
+ for (const any of this.mods) {
179
+ let match;
180
+ for (const mod of any) {
181
+ match = this.#match(item, mod);
182
+ if (match) break;
183
+ }
184
+ if (!match) return 0;
185
+ score += match.score;
186
+ }
187
+ return score;
188
+ }
189
+ update(item) {
190
+ const score = this.match(item);
191
+ const it = item;
192
+ it.score = score;
193
+ return it;
194
+ }
195
+ positions(input) {
196
+ if (this.empty()) return [];
197
+ const item = typeof input === "string" ? { text: input } : input;
198
+ const ret = [];
199
+ const all = this.mods.flat();
200
+ for (const mod of all) {
201
+ const match = this.#match(item, mod);
202
+ if (!match) continue;
203
+ if (mod.fuzzy) ret.push(...this.#fuzzyPositions(match.search, mod.chars, match.from));
204
+ else for (let i = match.from; i <= match.to; i++) ret.push(i);
205
+ }
206
+ return [...new Set(ret)].toSorted((a, b) => a - b);
207
+ }
208
+ fields() {
209
+ const ret = /* @__PURE__ */ new Set();
210
+ for (const mod of this.mods.flat()) ret.add(mod.field ?? "text");
211
+ return [...ret];
212
+ }
213
+ #prepare(pattern) {
214
+ const mod = {
215
+ chars: [],
216
+ entropy: 0,
217
+ pattern
218
+ };
219
+ if (this.opts.regex) {
220
+ mod.regex = true;
221
+ const isLower = mod.pattern.toLowerCase() === mod.pattern;
222
+ mod.ignorecase = this.opts.smartcase ? isLower : this.opts.ignorecase;
223
+ try {
224
+ mod.re = new RegExp(mod.pattern, mod.ignorecase ? "i" : void 0);
225
+ } catch {
226
+ mod.re = void 0;
227
+ }
228
+ } else {
229
+ const file = parseFilePattern(pattern);
230
+ if (file) {
231
+ mod.field = "file";
232
+ mod.pattern = `${file}$`;
233
+ }
234
+ const field = mod.pattern.match(/^([\w_][\w_]+):(.*)$/);
235
+ if (field) {
236
+ mod.field = field[1];
237
+ mod.pattern = field[2];
238
+ }
239
+ mod.ignorecase = this.opts.ignorecase;
240
+ const isLower = mod.pattern.toLowerCase() === mod.pattern;
241
+ if (this.opts.smartcase) mod.ignorecase = isLower;
242
+ mod.fuzzy = this.opts.fuzzy;
243
+ if (!mod.fuzzy) mod.entropy += 10;
244
+ if (mod.pattern.startsWith("!")) {
245
+ mod.fuzzy = false;
246
+ mod.inverse = true;
247
+ mod.pattern = mod.pattern.slice(1);
248
+ mod.entropy -= 1;
249
+ }
250
+ if (mod.pattern.startsWith("'")) {
251
+ mod.fuzzy = false;
252
+ mod.pattern = mod.pattern.slice(1);
253
+ mod.entropy += 10;
254
+ if (mod.pattern.endsWith("'")) {
255
+ mod.word = true;
256
+ mod.pattern = mod.pattern.slice(0, -1);
257
+ mod.entropy += 10;
258
+ }
259
+ } else if (mod.pattern.startsWith("^")) {
260
+ mod.fuzzy = false;
261
+ mod.exactPrefix = true;
262
+ mod.pattern = mod.pattern.slice(1);
263
+ mod.entropy += 20;
264
+ }
265
+ if (mod.pattern.endsWith("$")) {
266
+ mod.fuzzy = false;
267
+ mod.exactSuffix = true;
268
+ mod.pattern = mod.pattern.slice(0, -1);
269
+ mod.entropy += 20;
270
+ }
271
+ const rareChars = (mod.pattern.match(/[^\w\s]/g) ?? []).length;
272
+ mod.entropy += Math.min(mod.pattern.length, 20) + rareChars * 2;
273
+ if (!mod.ignorecase && !isLower) mod.entropy *= 2;
274
+ if (mod.ignorecase) mod.pattern = mod.pattern.toLowerCase();
275
+ }
276
+ mod.chars = [...mod.pattern];
277
+ return mod;
278
+ }
279
+ #match(item, mod) {
280
+ this.score.isFile = itemField(item, "file") !== void 0;
281
+ let str = item.text;
282
+ if (mod.field) {
283
+ const value = itemField(item, mod.field);
284
+ if (value === void 0) return mod.inverse ? {
285
+ from: 0,
286
+ score: 1e3,
287
+ search: str,
288
+ str,
289
+ to: 0
290
+ } : void 0;
291
+ str = value;
292
+ }
293
+ const original = str;
294
+ if (mod.ignorecase) str = str.toLowerCase();
295
+ if (mod.regex) return this.#regex(original, mod);
296
+ if (mod.fuzzy) return this.#fuzzy(str, original, mod.chars);
297
+ let from = -1;
298
+ let to = -1;
299
+ if (mod.exactPrefix) {
300
+ if (str.startsWith(mod.pattern)) {
301
+ from = 0;
302
+ to = mod.pattern.length - 1;
303
+ }
304
+ } else if (mod.exactSuffix) {
305
+ if (str.endsWith(mod.pattern)) {
306
+ from = str.length - mod.pattern.length;
307
+ to = str.length - 1;
308
+ }
309
+ } else {
310
+ from = str.indexOf(mod.pattern);
311
+ to = from + mod.pattern.length - 1;
312
+ while (mod.word && from >= 0) {
313
+ if (this.score.isLeftBoundary(str, from) && this.score.isRightBoundary(str, to)) break;
314
+ from = str.indexOf(mod.pattern, to + 1);
315
+ to = from + mod.pattern.length - 1;
316
+ }
317
+ }
318
+ if (mod.inverse) return from === -1 ? {
319
+ from: 0,
320
+ score: 1e3,
321
+ search: str,
322
+ str: original,
323
+ to: 0
324
+ } : void 0;
325
+ if (from >= 0) return {
326
+ from,
327
+ score: this.score.get(original, from, to),
328
+ search: str,
329
+ str: original,
330
+ to
331
+ };
332
+ }
333
+ #regex(str, mod) {
334
+ const match = mod.re?.exec(str);
335
+ if (!match?.[0]) return void 0;
336
+ const from = match.index;
337
+ const to = from + match[0].length - 1;
338
+ return {
339
+ from,
340
+ score: this.score.get(str, from, to),
341
+ search: str,
342
+ str,
343
+ to
344
+ };
345
+ }
346
+ #fuzzyFind(str, original, pattern, init = 0) {
347
+ const from = str.indexOf(pattern[0] ?? "", init);
348
+ if (from === -1) return void 0;
349
+ this.score.init(original, from);
350
+ let last = from;
351
+ for (let i = 1; i < pattern.length; i++) {
352
+ last = str.indexOf(pattern[i], last + 1);
353
+ if (last === -1) return void 0;
354
+ this.score.update(last);
355
+ }
356
+ return {
357
+ from,
358
+ score: this.score.score,
359
+ to: last
360
+ };
361
+ }
362
+ #fuzzy(str, original, pattern) {
363
+ let best = this.#fuzzyFind(str, original, pattern);
364
+ if (!best) return void 0;
365
+ for (let next = this.#fuzzyFind(str, original, pattern, best.from + 1); next; next = this.#fuzzyFind(str, original, pattern, next.from + 1)) if (next.score > best.score) best = next;
366
+ return {
367
+ from: best.from,
368
+ score: best.score,
369
+ search: str,
370
+ str: original,
371
+ to: best.to
372
+ };
373
+ }
374
+ #fuzzyPositions(str, pattern, from) {
375
+ const ret = [from];
376
+ let last = from;
377
+ for (let i = 1; i < pattern.length; i++) {
378
+ last = str.indexOf(pattern[i], last + 1);
379
+ if (last === -1) break;
380
+ ret.push(last);
381
+ }
382
+ return ret;
383
+ }
384
+ };
385
+ function itemField(item, field) {
386
+ const value = item[field];
387
+ if (value === void 0 || value === null) return void 0;
388
+ if (typeof value === "string") return value;
389
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
390
+ if (Array.isArray(value)) return value.join(" ");
391
+ }
392
+ function parseFilePattern(pattern) {
393
+ return pattern.match(/^(.*[/\\].*):\d*:?:?\d*$/)?.[1] ?? pattern.match(/^(.+\.[a-z_]+):\d*:?:?\d*$/)?.[1];
394
+ }
395
+ //#endregion
396
+ //#region src/search/sort.ts
397
+ function parse(field) {
398
+ const len = field.startsWith("#");
399
+ return {
400
+ desc: field.endsWith(":desc"),
401
+ len,
402
+ name: field.replace(/^#/, "").replace(/:desc$/, "")
403
+ };
404
+ }
405
+ function sorter(fields = [
406
+ "score:desc",
407
+ "#text",
408
+ "idx"
409
+ ]) {
410
+ const parsed = fields.map(parse);
411
+ return (a, b) => {
412
+ for (const field of parsed) {
413
+ let av = a[field.name];
414
+ let bv = b[field.name];
415
+ if (av === void 0 || bv === void 0) continue;
416
+ if (field.len) {
417
+ av = typeof av === "string" || Array.isArray(av) ? av.length : 0;
418
+ bv = typeof bv === "string" || Array.isArray(bv) ? bv.length : 0;
419
+ }
420
+ if (av === bv) continue;
421
+ if (typeof av === "boolean" && typeof bv === "boolean") {
422
+ av = av ? 0 : 1;
423
+ bv = bv ? 0 : 1;
424
+ }
425
+ return compare(av, bv) * (field.desc ? -1 : 1);
426
+ }
427
+ return 0;
428
+ };
429
+ }
430
+ function compare(a, b) {
431
+ if (typeof a === "number" && typeof b === "number") return a - b;
432
+ if (typeof a === "string" && typeof b === "string") return a.localeCompare(b);
433
+ return String(a).localeCompare(String(b));
434
+ }
435
+ //#endregion
436
+ //#region src/search/search.ts
437
+ const BONUS_FRECENCY = 8;
438
+ const SEARCH_LIMIT = 1e3;
439
+ const aborted = Symbol("search.aborted");
440
+ var Searcher = class {
441
+ #opts;
442
+ #sorter;
443
+ #matcher;
444
+ #ac;
445
+ constructor(opts) {
446
+ this.#opts = opts;
447
+ const sortOpts = opts.sort === true ? void 0 : opts.sort;
448
+ this.#sorter = sortOpts === false ? void 0 : sorter(sortOpts);
449
+ this.#matcher = new Matcher(opts);
450
+ }
451
+ /** Create a match function bound to the current pattern. If the
452
+ * matcher has been updated since the search started, match will
453
+ * return `0` to indicate no match, to prevent stale results */
454
+ createMatch(opts) {
455
+ const m = this.#matcher;
456
+ return (s) => opts.signal.aborted ? 0 : m.match(s);
457
+ }
458
+ async search(items, query = "", opts = {}) {
459
+ try {
460
+ return await this.#search(items, query, opts);
461
+ } catch (error) {
462
+ if (error === aborted) return [];
463
+ throw error;
464
+ }
465
+ }
466
+ get limit() {
467
+ return this.#opts.limit ?? (this.#sorter ? SEARCH_LIMIT : Infinity);
468
+ }
469
+ async #search(items, query = "", opts = {}) {
470
+ this.#ac?.abort(aborted);
471
+ const ac = this.#ac = new AbortController();
472
+ const m = this.#matcher;
473
+ m.init(query);
474
+ const f = this.#opts.frecency?.();
475
+ const s = this.#sorter;
476
+ const limit = this.limit;
477
+ const ret = [];
478
+ let match = (item) => this.#matcher.update(item);
479
+ const topk = s && (this.#opts.sortEmpty || !m.empty()) ? new TopK(limit, (a, b) => -s(a, b)) : void 0;
480
+ if (typeof items === "function") {
481
+ match = (item) => item;
482
+ items = await items(query, this.createMatch({ signal: ac.signal }));
483
+ ac.signal.throwIfAborted();
484
+ }
485
+ if (items.length === 0) return [];
486
+ const results = () => topk?.sorted() ?? ret;
487
+ const todo = [
488
+ [],
489
+ [],
490
+ []
491
+ ];
492
+ let idx = 0;
493
+ if (!topk) todo[0] = items;
494
+ else for (const item of items) {
495
+ item.idx = idx++;
496
+ const it = item;
497
+ if (it.topk) todo[0].push(item);
498
+ else if (it.score) todo[1].push(item);
499
+ else todo[2].push(item);
500
+ }
501
+ const doFilter = !m.empty() && (this.#opts.filter ?? true);
502
+ let lastYield = performance.now();
503
+ let dirty = false;
504
+ let count = 0;
505
+ loop: for (const todos of todo) for (const item of todos) {
506
+ ac.signal.throwIfAborted();
507
+ if (count++ % 256 === 0) {
508
+ const now = performance.now();
509
+ if (now - lastYield >= (this.#opts.throttle ?? 16)) {
510
+ lastYield = now;
511
+ await new Promise((r) => setImmediate(r));
512
+ if (opts.progress && dirty) {
513
+ dirty = false;
514
+ await opts.progress(results());
515
+ }
516
+ }
517
+ }
518
+ const si = match(item);
519
+ if (si.file && si.score && f) {
520
+ const frecency = f(si.file);
521
+ si.score += (1 - 1 / (1 + frecency)) * BONUS_FRECENCY;
522
+ }
523
+ if (doFilter && si.score === 0) continue;
524
+ if (topk) {
525
+ si.topk = false;
526
+ const ta = topk.add(si);
527
+ if (ta.added) {
528
+ si.topk = true;
529
+ dirty = true;
530
+ if (ta.evicted) ta.evicted.topk = false;
531
+ }
532
+ } else {
533
+ ret.push(si);
534
+ dirty = true;
535
+ if (ret.length >= limit) break loop;
536
+ }
537
+ }
538
+ return results();
539
+ }
540
+ positions(s) {
541
+ return this.#matcher.positions(s);
542
+ }
543
+ };
544
+ //#endregion
545
+ //#region src/widgets/picker.ts
546
+ function isTree(props) {
547
+ return "tree" in props;
548
+ }
549
+ const picker = widget((props) => {
550
+ const pattern = memo(() => {
551
+ if (props.pattern !== void 0) return unwrap(props.pattern);
552
+ return (props.input instanceof Input ? props.input : props.input?.())?.state.value ?? "";
553
+ });
554
+ let node;
555
+ let items;
556
+ if (isTree(props)) {
557
+ props = {
558
+ filter: false,
559
+ fuzzy: false,
560
+ sort: false,
561
+ ...props
562
+ };
563
+ const t = tree(props);
564
+ node = t;
565
+ items = t.items;
566
+ } else {
567
+ node = select({
568
+ ...props,
569
+ items: []
570
+ });
571
+ items = props.items;
572
+ }
573
+ const searcher = new Searcher(props);
574
+ node.extendRenderer((prev) => (item, ctx) => {
575
+ let row = prev(item, ctx);
576
+ if (!item.score) return row;
577
+ const stripped = stripAnsi(row);
578
+ const positions = searcher.positions(stripped).toSorted((a, b) => b - a);
579
+ while (positions.length > 0) {
580
+ const from = positions.pop();
581
+ let to = from;
582
+ while (positions.length && positions.at(-1) === to + 1) to = positions.pop();
583
+ row = sliceAnsi(row, 0, from) + ctx.style.accent(stripped.slice(from, to + 1)) + sliceAnsi(row, to + 1);
584
+ }
585
+ return row;
586
+ });
587
+ const results = createProgressive(async ({ set }) => await searcher.search(unwrap(items), pattern(), { progress: (r) => set(r) }), { initialValue: [] });
588
+ node.state.items = results;
589
+ if (props.input) node.bind(props.input);
590
+ const matches = () => unwrap(node.state.items).map((item, i) => [item, i]).filter(([item]) => item.score).map(([, i]) => i);
591
+ effect(() => {
592
+ const m = matches();
593
+ node.state.more = m.length >= searcher.limit;
594
+ if (m.length === 0 || pattern() === "") return;
595
+ untrack(() => {
596
+ if (props.filter === false) {
597
+ const active = node.active;
598
+ node.active = m.find((i) => i >= active) ?? m[0];
599
+ } else node.active = 0;
600
+ });
601
+ });
602
+ return node.withActions({
603
+ ...props.actions,
604
+ "picker.next": () => {
605
+ const active = node.active;
606
+ const m = matches();
607
+ if (m.length === 0) return node.action("select.next");
608
+ node.active = node.state.reverse ? m.toReversed().find((i) => i < active) ?? m.at(-1) : m.find((i) => i > active) ?? m[0];
609
+ },
610
+ "picker.prev": () => {
611
+ const active = node.active;
612
+ const m = matches();
613
+ if (m.length === 0) return node.action("select.prev");
614
+ node.active = node.state.reverse ? m.find((i) => i > active) ?? m[0] : m.toReversed().find((i) => i < active) ?? m.at(-1);
615
+ }
616
+ });
617
+ });
618
+ //#endregion
619
+ export { picker as t };
620
+
621
+ //# sourceMappingURL=picker-ndVVt6qF.mjs.map