@alchemy.run/sigil 0.0.0-alpha.1 → 0.0.0-alpha.10

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 (212) hide show
  1. package/README.md +499 -313
  2. package/THIRD_PARTY_NOTICES.md +70 -23
  3. package/dist/Text-DV9CuzAT.d.ts +452 -0
  4. package/dist/ansi.d.ts +217 -0
  5. package/dist/ansi.js +87 -0
  6. package/dist/capabilities.d.ts +5 -0
  7. package/dist/capabilities.js +3 -0
  8. package/dist/cell-_ZVhbfl0.js +44 -0
  9. package/dist/color-CkbalRqK.js +2 -0
  10. package/dist/color-policy-BAC9-TZX.js +592 -0
  11. package/dist/color-policy-CCxuHIdD.d.ts +22 -0
  12. package/dist/color-profile-CyeHnG1T.d.ts +97 -0
  13. package/dist/color-profile-DHhQHY55.js +36 -0
  14. package/dist/color.d.ts +21 -0
  15. package/dist/color.js +3 -0
  16. package/dist/cursor-position-D2LAkRG0.d.ts +7 -0
  17. package/dist/detect-B3dL4Q11.js +374 -0
  18. package/dist/detect-Db6GbKOm.d.ts +195 -0
  19. package/dist/{devtools-QpCMm9JH.mjs → devtools-DbthxoD1.js} +23 -24
  20. package/dist/env-YVw64yZS.js +9 -0
  21. package/dist/escapes-CB_6CWOE.d.ts +72 -0
  22. package/dist/geometry-BxXOzJgo.d.ts +11 -0
  23. package/dist/index-D48vQhhe.d.ts +21 -0
  24. package/dist/index-DDVME65c.d.ts +919 -0
  25. package/dist/index.d.ts +1310 -0
  26. package/dist/index.js +3209 -0
  27. package/dist/osc-BFKKSqpg.js +71 -0
  28. package/dist/osc-Cn0fw77g.d.ts +23 -0
  29. package/dist/paint-Cx-zC_sX.d.ts +81 -0
  30. package/dist/query-BNc2B8GD.d.ts +152 -0
  31. package/dist/router.d.ts +392 -0
  32. package/dist/router.js +709 -0
  33. package/dist/sample-Cqw1bjUL.js +445 -0
  34. package/dist/screen-CgC2WlVM.d.ts +49 -0
  35. package/dist/screen-CiPytswf.js +342 -0
  36. package/dist/screen.d.ts +5 -0
  37. package/dist/screen.js +5 -0
  38. package/dist/semantic-text-style-DIMzC7xt.js +91 -0
  39. package/dist/serialize-BTkAZgw1.js +79 -0
  40. package/dist/session-DDQ5V300.js +723 -0
  41. package/dist/sgr-BhwaWAJB.js +246 -0
  42. package/dist/store-C1P5fOUi.d.ts +72 -0
  43. package/dist/string-width-CijQwpIk.js +69 -0
  44. package/dist/strip-BvU4toXG.js +6 -0
  45. package/dist/terminal.d.ts +121 -0
  46. package/dist/terminal.js +2 -0
  47. package/dist/tokenize-AjqbvtiT.js +1242 -0
  48. package/dist/tokenize-Dx1y_l5H.d.ts +57 -0
  49. package/dist/truncate-D31fhU6i.js +562 -0
  50. package/dist/use-focus-CcCIdCWA.js +1337 -0
  51. package/dist/yoga-5jKhYCJC.js +3465 -0
  52. package/dist/yoga.d.ts +2 -0
  53. package/dist/yoga.js +2 -0
  54. package/package.json +70 -24
  55. package/src/ansi/chalk.ts +138 -0
  56. package/src/ansi/cursor.ts +46 -0
  57. package/src/ansi/east-asian-width.ts +259 -0
  58. package/src/ansi/escapes.ts +120 -0
  59. package/src/ansi/graphemes.ts +8 -0
  60. package/src/ansi/hyperlink.ts +44 -0
  61. package/src/ansi/index.ts +27 -0
  62. package/src/ansi/osc.ts +77 -0
  63. package/src/ansi/sgr.ts +234 -0
  64. package/src/ansi/slice.ts +43 -0
  65. package/src/ansi/string-width.ts +121 -0
  66. package/src/ansi/strip.ts +13 -0
  67. package/src/ansi/tokenize.ts +380 -0
  68. package/src/ansi/truncate.ts +196 -0
  69. package/src/ansi/wrap.ts +765 -0
  70. package/src/ansi-tokenizer.ts +510 -0
  71. package/src/capabilities/color-policy.ts +34 -0
  72. package/src/capabilities/detect.ts +608 -0
  73. package/src/capabilities/index.ts +37 -0
  74. package/src/capabilities/query.ts +679 -0
  75. package/src/capabilities/store.ts +394 -0
  76. package/src/code-excerpt.ts +39 -0
  77. package/src/color/index.ts +3 -0
  78. package/src/color/paint.ts +169 -0
  79. package/src/color/palette.ts +48 -0
  80. package/src/color/sample.ts +323 -0
  81. package/src/color.ts +1 -0
  82. package/src/components/AccessibilityContext.ts +5 -0
  83. package/src/components/AnimationContext.ts +24 -0
  84. package/src/components/AnsiText.tsx +42 -0
  85. package/src/components/App.tsx +878 -0
  86. package/src/components/AppContext.ts +111 -0
  87. package/src/components/BackgroundContext.ts +7 -0
  88. package/src/components/Box.tsx +100 -0
  89. package/src/components/CursorContext.ts +19 -0
  90. package/src/components/ErrorBoundary.tsx +39 -0
  91. package/src/components/ErrorOverview.tsx +135 -0
  92. package/src/components/FocusContext.ts +30 -0
  93. package/src/components/Hyperlink.tsx +56 -0
  94. package/src/components/Newline.tsx +16 -0
  95. package/src/components/Spacer.tsx +11 -0
  96. package/src/components/Static.tsx +60 -0
  97. package/src/components/StderrContext.ts +24 -0
  98. package/src/components/StdinContext.ts +48 -0
  99. package/src/components/StdoutContext.ts +26 -0
  100. package/src/components/TerminalOscContext.ts +25 -0
  101. package/src/components/Text.tsx +122 -0
  102. package/src/components/Transform.tsx +38 -0
  103. package/src/components/VirtualList.tsx +128 -0
  104. package/src/cursor-position.ts +103 -0
  105. package/src/devtools.ts +103 -0
  106. package/src/dom.ts +301 -0
  107. package/src/env.ts +12 -0
  108. package/src/get-max-width.ts +11 -0
  109. package/src/global.d.ts +38 -0
  110. package/src/glyphs.ts +99 -0
  111. package/src/hooks/use-animation.ts +142 -0
  112. package/src/hooks/use-app.ts +8 -0
  113. package/src/hooks/use-box-metrics.ts +134 -0
  114. package/src/hooks/use-capabilities.ts +73 -0
  115. package/src/hooks/use-cursor.ts +33 -0
  116. package/src/hooks/use-focus-manager.ts +62 -0
  117. package/src/hooks/use-focus.ts +82 -0
  118. package/src/hooks/use-input.ts +267 -0
  119. package/src/hooks/use-is-screen-reader-enabled.ts +12 -0
  120. package/src/hooks/use-paste.ts +78 -0
  121. package/src/hooks/use-stderr.ts +8 -0
  122. package/src/hooks/use-stdin.ts +10 -0
  123. package/src/hooks/use-stdout.ts +8 -0
  124. package/src/hooks/use-terminal-osc.ts +59 -0
  125. package/src/hooks/use-virtual-scroll.ts +84 -0
  126. package/src/hooks/use-window-size.ts +37 -0
  127. package/src/index.ts +96 -0
  128. package/src/ink.tsx +1452 -0
  129. package/src/input-parser.ts +303 -0
  130. package/src/instances.ts +9 -0
  131. package/src/kitty-keyboard.ts +185 -0
  132. package/src/measure-element.ts +62 -0
  133. package/src/measure-text.ts +31 -0
  134. package/src/paint-tree.ts +220 -0
  135. package/src/parse-keypress.ts +515 -0
  136. package/src/parse-stack-line.ts +138 -0
  137. package/src/patch-console.ts +106 -0
  138. package/src/quick-lru.ts +85 -0
  139. package/src/reconciler.ts +425 -0
  140. package/src/render-background.ts +59 -0
  141. package/src/render-border.ts +167 -0
  142. package/src/render-frame.ts +83 -0
  143. package/src/render-to-string.ts +146 -0
  144. package/src/render.ts +284 -0
  145. package/src/router/components.tsx +343 -0
  146. package/src/router/context.ts +41 -0
  147. package/src/router/history.ts +194 -0
  148. package/src/router/hooks.tsx +391 -0
  149. package/src/router/index.ts +34 -0
  150. package/src/router/matcher.ts +571 -0
  151. package/src/sanitize-ansi.ts +33 -0
  152. package/src/screen/ansi.ts +184 -0
  153. package/src/screen/canvas.ts +160 -0
  154. package/src/screen/cell.ts +138 -0
  155. package/src/screen/color-profile.ts +47 -0
  156. package/src/screen/geometry.ts +9 -0
  157. package/src/screen/index.ts +6 -0
  158. package/src/screen/screen.ts +305 -0
  159. package/src/screen/serialize.ts +129 -0
  160. package/src/screen.ts +1 -0
  161. package/src/semantic-text-style.ts +118 -0
  162. package/src/signal-exit.ts +106 -0
  163. package/src/squash-text-nodes.ts +37 -0
  164. package/src/stream.ts +28 -0
  165. package/src/structured-text.ts +325 -0
  166. package/src/styles.ts +753 -0
  167. package/src/terminal/index.ts +2 -0
  168. package/src/terminal/inline-presenter.ts +120 -0
  169. package/src/terminal/input.ts +92 -0
  170. package/src/terminal/render-scheduler.ts +37 -0
  171. package/src/terminal/screen-presenter.ts +242 -0
  172. package/src/terminal/session.ts +408 -0
  173. package/src/terminal-size.ts +58 -0
  174. package/src/terminal.ts +1 -0
  175. package/src/testing/browser.ts +588 -0
  176. package/src/testing/emulators.ts +205 -0
  177. package/src/testing/explorer-app/index.html +12 -0
  178. package/src/testing/explorer-app/main.ts +381 -0
  179. package/src/testing/explorer-app/style.css +194 -0
  180. package/src/testing/explorer-app/tsconfig.json +15 -0
  181. package/src/testing/explorer-app/vite-env.d.ts +1 -0
  182. package/src/testing/index.ts +26 -0
  183. package/src/testing/keys.ts +56 -0
  184. package/src/testing/live.ts +85 -0
  185. package/src/testing/matchers.ts +70 -0
  186. package/src/testing/public.ts +94 -0
  187. package/src/testing/terminal.ts +361 -0
  188. package/src/testing/vitest.ts +157 -0
  189. package/src/throttle.ts +73 -0
  190. package/src/transform-adapter.ts +14 -0
  191. package/src/types.ts +10 -0
  192. package/src/virtual-scroll.ts +133 -0
  193. package/src/wrap-text.ts +54 -0
  194. package/src/yoga/config.ts +57 -0
  195. package/src/yoga/core/absoluteLayout.ts +626 -0
  196. package/src/yoga/core/baseline.ts +66 -0
  197. package/src/yoga/core/cache.ts +136 -0
  198. package/src/yoga/core/calculateLayout.ts +2926 -0
  199. package/src/yoga/core/config.ts +104 -0
  200. package/src/yoga/core/flexLine.ts +177 -0
  201. package/src/yoga/core/helpers.ts +293 -0
  202. package/src/yoga/core/layoutResults.ts +167 -0
  203. package/src/yoga/core/node.ts +611 -0
  204. package/src/yoga/core/numeric.ts +44 -0
  205. package/src/yoga/core/pixelGrid.ts +151 -0
  206. package/src/yoga/core/style.ts +887 -0
  207. package/src/yoga/core/types.ts +224 -0
  208. package/src/yoga/generated/YGEnums.ts +263 -0
  209. package/src/yoga/index.ts +19 -0
  210. package/src/yoga/node.ts +1140 -0
  211. package/dist/index.d.mts +0 -2379
  212. package/dist/index.mjs +0 -10072
package/dist/yoga.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ import { C as Unit, S as PositionType, T as constants, _ as Justify, a as Config, b as NodeType, c as Dimension, d as Edge, f as Errata, g as Gutter, h as GridTrackType, i as Node, l as Direction, m as FlexDirection, n as DirtiedFunction, o as Align, p as ExperimentalFeature, r as MeasureFunction, s as BoxSizing, t as Yoga, u as Display, v as LogLevel, w as Wrap, x as Overflow, y as MeasureMode } from "./index-DDVME65c.js";
2
+ export { Align, BoxSizing, type Config, Dimension, Direction, type DirtiedFunction, Display, Edge, Errata, ExperimentalFeature, FlexDirection, GridTrackType, Gutter, Justify, LogLevel, type MeasureFunction, MeasureMode, type Node, NodeType, Overflow, PositionType, Unit, Wrap, Yoga, constants };
package/dist/yoga.js ADDED
@@ -0,0 +1,2 @@
1
+ import { _ as Overflow, a as Direction, b as Wrap, c as Errata, d as GridTrackType, f as Gutter, g as NodeType, h as MeasureMode, i as Dimension, l as ExperimentalFeature, m as LogLevel, n as Align, o as Display, p as Justify, r as BoxSizing, s as Edge, t as Yoga, u as FlexDirection, v as PositionType, x as constants, y as Unit } from "./yoga-5jKhYCJC.js";
2
+ export { Align, BoxSizing, Dimension, Direction, Display, Edge, Errata, ExperimentalFeature, FlexDirection, GridTrackType, Gutter, Justify, LogLevel, MeasureMode, NodeType, Overflow, PositionType, Unit, Wrap, Yoga, constants };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alchemy.run/sigil",
3
- "version": "0.0.0-alpha.1",
3
+ "version": "0.0.0-alpha.10",
4
4
  "description": "React for CLIs. A self-contained fork of Ink with an integrated TypeScript Yoga layout engine.",
5
5
  "keywords": [
6
6
  "cli",
@@ -27,13 +27,55 @@
27
27
  "url": "alchemy-run/sigil"
28
28
  },
29
29
  "files": [
30
+ "src",
30
31
  "dist",
31
32
  "THIRD_PARTY_NOTICES.md"
32
33
  ],
33
34
  "type": "module",
35
+ "imports": {
36
+ "#/*": "./src/*"
37
+ },
34
38
  "exports": {
35
- "types": "./dist/index.d.mts",
36
- "default": "./dist/index.mjs"
39
+ ".": {
40
+ "import": "./dist/index.js",
41
+ "types": "./dist/index.d.ts",
42
+ "default": "./dist/index.js"
43
+ },
44
+ "./ansi": {
45
+ "import": "./dist/ansi.js",
46
+ "types": "./dist/ansi.d.ts",
47
+ "default": "./dist/ansi.js"
48
+ },
49
+ "./yoga": {
50
+ "import": "./dist/yoga.js",
51
+ "types": "./dist/yoga.d.ts",
52
+ "default": "./dist/yoga.js"
53
+ },
54
+ "./router": {
55
+ "import": "./dist/router.js",
56
+ "types": "./dist/router.d.ts",
57
+ "default": "./dist/router.js"
58
+ },
59
+ "./capabilities": {
60
+ "import": "./dist/capabilities.js",
61
+ "types": "./dist/capabilities.d.ts",
62
+ "default": "./dist/capabilities.js"
63
+ },
64
+ "./color": {
65
+ "import": "./dist/color.js",
66
+ "types": "./dist/color.d.ts",
67
+ "default": "./dist/color.js"
68
+ },
69
+ "./screen": {
70
+ "import": "./dist/screen.js",
71
+ "types": "./dist/screen.d.ts",
72
+ "default": "./dist/screen.js"
73
+ },
74
+ "./terminal": {
75
+ "import": "./dist/terminal.js",
76
+ "types": "./dist/terminal.d.ts",
77
+ "default": "./dist/terminal.js"
78
+ }
37
79
  },
38
80
  "publishConfig": {
39
81
  "access": "public"
@@ -43,27 +85,33 @@
43
85
  "scheduler": "^0.27.0"
44
86
  },
45
87
  "devDependencies": {
88
+ "@slopus/ghostty-wasm": "^1.3.6",
46
89
  "@types/node": "^25.5.2",
47
- "@types/react": "^19.2.14",
90
+ "@types/react": "^19.2.18",
48
91
  "@types/react-reconciler": "^0.33.0",
49
92
  "@types/scheduler": "^0.26.0",
50
- "@types/ws": "^8.18.1",
51
- "boxen": "^8.0.1",
52
- "node-pty": "^1.2.0-beta.12",
53
- "react": "^19.2.4",
93
+ "@vitest/ui": "^4.1.11",
94
+ "@xterm/addon-clipboard": "^0.2.0",
95
+ "@xterm/addon-fit": "^0.11.0",
96
+ "@xterm/addon-image": "^0.9.0",
97
+ "@xterm/addon-unicode11": "^0.9.0",
98
+ "@xterm/addon-web-links": "^0.12.0",
99
+ "@xterm/addon-webgl": "^0.19.0",
100
+ "@xterm/headless": "^6.0.0",
101
+ "@xterm/xterm": "^6.0.0",
102
+ "react": "^19.2.8",
54
103
  "react-devtools-core": "^7.0.1",
55
- "react-router": "^7.14.0",
56
104
  "tsx": "^4.21.0",
57
105
  "typescript": "^7.0.2",
106
+ "vite": "npm:@voidzero-dev/vite-plus-core@^0.2.9",
58
107
  "vite-plus": "^0.2.9",
59
- "vitest": "4.1.10",
60
- "ws": "^8.20.0"
108
+ "vitest": "4.1.11",
109
+ "zigpty": "^0.2.1"
61
110
  },
62
111
  "peerDependencies": {
63
112
  "@types/react": ">=19.2.0",
64
113
  "react": ">=19.2.0",
65
- "react-devtools-core": ">=6.1.2",
66
- "ws": ">=8.20.0"
114
+ "react-devtools-core": ">=6.1.2"
67
115
  },
68
116
  "peerDependenciesMeta": {
69
117
  "@types/react": {
@@ -71,9 +119,6 @@
71
119
  },
72
120
  "react-devtools-core": {
73
121
  "optional": true
74
- },
75
- "ws": {
76
- "optional": true
77
122
  }
78
123
  },
79
124
  "engines": {
@@ -83,16 +128,17 @@
83
128
  "dev": "vp pack -w",
84
129
  "build": "vp pack",
85
130
  "test": "vp test",
131
+ "e2e": "vp test test/e2e.test.ts",
132
+ "explorer": "node --import=tsx scripts/explorer.ts",
86
133
  "lint": "vp lint",
87
134
  "format": "vp fmt .",
88
135
  "check": "vp check",
89
- "typecheck": "tsc --noEmit",
90
- "example": "NODE_NO_WARNINGS=1 node --import=tsx",
91
- "benchmark": "NODE_NO_WARNINGS=1 node --import=tsx",
92
- "inspect": "vp dlx react-devtools",
93
- "build:reference": "NODE_NO_WARNINGS=1 node --import=tsx scripts/build-reference.ts",
94
- "fuzz": "NODE_NO_WARNINGS=1 node --import=tsx test/yoga/fuzz/typescript.ts",
95
- "fuzz:differential": "vp run build:reference && NODE_NO_WARNINGS=1 node --import=tsx test/yoga/fuzz/differential.ts",
96
- "fuzz:loop": "vp run build:reference && NODE_NO_WARNINGS=1 node --import=tsx test/yoga/fuzz/loop.ts"
136
+ "typecheck": "tsc --noEmit && tsc --noEmit -p test/contracts/tsconfig.json",
137
+ "inspect": "vpx react-devtools",
138
+ "build:reference": "tsx scripts/build-reference.ts",
139
+ "bench:terminal": "tsx benchmark/terminal-core.tsx --check",
140
+ "fuzz": "tsx test/yoga/fuzz/typescript.ts",
141
+ "fuzz:differential": "vpr build:reference && tsx test/yoga/fuzz/differential.ts",
142
+ "fuzz:loop": "vpr build:reference && tsx test/yoga/fuzz/loop.ts"
97
143
  }
98
144
  }
@@ -0,0 +1,138 @@
1
+ import { isatty } from "node:tty";
2
+
3
+ // Terminal string styling with a chalk-compatible API for the styles Ink uses.
4
+ // Ported from `chalk` (MIT, Sindre Sorhus) without the chaining builder —
5
+ // Ink only ever applies one style per call.
6
+ import { ESC } from "#/ansi/escapes.ts";
7
+ import {
8
+ background,
9
+ backgroundColorNames,
10
+ foreground,
11
+ foregroundColorNames,
12
+ hexToRgb,
13
+ modifierNames,
14
+ rgbToAnsi,
15
+ rgbToAnsi256,
16
+ styles,
17
+ type BackgroundColorName,
18
+ type ForegroundColorName,
19
+ type ModifierName,
20
+ } from "#/ansi/sgr.ts";
21
+ import {
22
+ createSupportsColor,
23
+ type ColorInfo,
24
+ type ColorSupportLevel,
25
+ } from "#/capabilities/detect.ts";
26
+
27
+ export type { BackgroundColorName, ForegroundColorName, ModifierName };
28
+
29
+ export type StyleFunction = (text: string) => string;
30
+
31
+ const stdoutColor = createSupportsColor({ isTTY: isatty(1) });
32
+
33
+ // `level` → color model for hex/rgb downsampling
34
+ const levelMapping = ["ansi", "ansi", "ansi256", "ansi16m"] as const;
35
+ type ColorModel = (typeof levelMapping)[number];
36
+
37
+ const state = {
38
+ level: stdoutColor ? stdoutColor.level : 0,
39
+ };
40
+
41
+ // Replace every occurrence of `substring` with `substring + replacer`,
42
+ // re-opening a style after a nested close code would have ended it.
43
+ const applyStyle = (open: string, close: string, text: string): string => {
44
+ if (state.level <= 0 || !text) {
45
+ return text;
46
+ }
47
+
48
+ let string = text;
49
+
50
+ if (string.includes(ESC)) {
51
+ // Re-open the style wherever the text already contains its close code,
52
+ // otherwise only the part before that code would stay styled.
53
+ string = string.replaceAll(close, close + open);
54
+ }
55
+
56
+ if (string.includes("\n")) {
57
+ // Close the style before every line break and reopen it after, to prevent
58
+ // background bleed across lines (https://github.com/chalk/chalk/pull/92).
59
+ string = string.replaceAll(/\r?\n/g, `${close}$&${open}`);
60
+ }
61
+
62
+ return open + string + close;
63
+ };
64
+
65
+ const styleFunction = (open: string, close: string): StyleFunction => {
66
+ return (text) => applyStyle(open, close, text);
67
+ };
68
+
69
+ const foregroundOpen = (model: ColorModel, args: number[] | [string]): string => {
70
+ return colorOpen(model, args, foreground, rgbToAnsi256, rgbToAnsi);
71
+ };
72
+
73
+ const backgroundOpen = (model: ColorModel, args: number[] | [string]): string => {
74
+ return colorOpen(model, args, background, rgbToAnsi256, rgbToAnsi);
75
+ };
76
+
77
+ const colorOpen = (
78
+ model: ColorModel,
79
+ args: number[] | [string],
80
+ space: typeof foreground,
81
+ toAnsi256: typeof rgbToAnsi256,
82
+ toAnsi: typeof rgbToAnsi,
83
+ ): string => {
84
+ const rgb = (typeof args[0] === "string" ? hexToRgb(args[0]) : args) as [number, number, number];
85
+
86
+ if (model === "ansi16m") {
87
+ return space.ansi16m(...rgb);
88
+ }
89
+
90
+ if (model === "ansi256") {
91
+ return space.ansi256(toAnsi256(...rgb));
92
+ }
93
+
94
+ return space.ansi(toAnsi(...rgb));
95
+ };
96
+
97
+ type NamedStyles = Record<ModifierName | ForegroundColorName | BackgroundColorName, StyleFunction>;
98
+
99
+ export type Chalk = NamedStyles & {
100
+ level: ColorSupportLevel;
101
+ hex: (color: string) => StyleFunction;
102
+ bgHex: (color: string) => StyleFunction;
103
+ rgb: (red: number, green: number, blue: number) => StyleFunction;
104
+ bgRgb: (red: number, green: number, blue: number) => StyleFunction;
105
+ ansi256: (code: number) => StyleFunction;
106
+ bgAnsi256: (code: number) => StyleFunction;
107
+ };
108
+
109
+ const named = {} as NamedStyles;
110
+
111
+ for (const name of [...modifierNames, ...foregroundColorNames, ...backgroundColorNames]) {
112
+ named[name] = styleFunction(styles[name].open, styles[name].close);
113
+ }
114
+
115
+ export const chalk: Chalk = {
116
+ ...named,
117
+
118
+ get level(): ColorSupportLevel {
119
+ return state.level;
120
+ },
121
+ set level(level: ColorSupportLevel) {
122
+ state.level = level;
123
+ },
124
+
125
+ hex: (color) =>
126
+ styleFunction(foregroundOpen(levelMapping[state.level], [color]), foreground.close),
127
+ bgHex: (color) =>
128
+ styleFunction(backgroundOpen(levelMapping[state.level], [color]), background.close),
129
+ rgb: (red, green, blue) =>
130
+ styleFunction(foregroundOpen(levelMapping[state.level], [red, green, blue]), foreground.close),
131
+ bgRgb: (red, green, blue) =>
132
+ styleFunction(backgroundOpen(levelMapping[state.level], [red, green, blue]), background.close),
133
+ // Like chalk, 256-color styles always emit 8-bit codes (level only gates level 0).
134
+ ansi256: (code) => styleFunction(foreground.ansi256(code), foreground.close),
135
+ bgAnsi256: (code) => styleFunction(background.ansi256(code), background.close),
136
+ };
137
+
138
+ export const supportsColor: ColorInfo = stdoutColor;
@@ -0,0 +1,46 @@
1
+ import { cursorHide, cursorShow } from "#/ansi/escapes.ts";
2
+ // Derived from `cli-cursor` + `restore-cursor` (MIT, Sindre Sorhus),
3
+ // collapsed into one module. Restores the cursor on process exit once
4
+ // `hide()` has been called, like `restore-cursor` did.
5
+ import { signalExit } from "#/signal-exit.ts";
6
+
7
+ type CursorStream = {
8
+ isTTY?: boolean;
9
+ write: (data: string) => unknown;
10
+ };
11
+
12
+ let restoreRegistered = false;
13
+
14
+ const registerRestore = (): void => {
15
+ if (restoreRegistered) {
16
+ return;
17
+ }
18
+
19
+ restoreRegistered = true;
20
+
21
+ signalExit(
22
+ () => {
23
+ process.stderr.write(cursorShow);
24
+ },
25
+ { alwaysLast: true },
26
+ );
27
+ };
28
+
29
+ export const cliCursor = {
30
+ show(writableStream: CursorStream = process.stderr): void {
31
+ if (!writableStream.isTTY) {
32
+ return;
33
+ }
34
+
35
+ writableStream.write(cursorShow);
36
+ },
37
+
38
+ hide(writableStream: CursorStream = process.stderr): void {
39
+ if (!writableStream.isTTY) {
40
+ return;
41
+ }
42
+
43
+ registerRestore();
44
+ writableStream.write(cursorHide);
45
+ },
46
+ };
@@ -0,0 +1,259 @@
1
+ // East Asian Width lookup, plus string-width's full-width test.
2
+ // Ported from `get-east-asian-width` and `is-fullwidth-code-point`
3
+ // (MIT, Sindre Sorhus). The range tables are generated from Unicode data.
4
+
5
+ export type EastAsianWidthType =
6
+ | "ambiguous"
7
+ | "fullwidth"
8
+ | "halfwidth"
9
+ | "narrow"
10
+ | "neutral"
11
+ | "wide";
12
+
13
+ // Binary search on a sorted flat array of inclusive [start, end] pairs.
14
+ const isInRange = (ranges: readonly number[], codePoint: number): boolean => {
15
+ let low = 0;
16
+ let high = Math.floor(ranges.length / 2) - 1;
17
+ while (low <= high) {
18
+ const mid = Math.floor((low + high) / 2);
19
+ const i = mid * 2;
20
+ if (codePoint < ranges[i]!) {
21
+ high = mid - 1;
22
+ } else if (codePoint > ranges[i + 1]!) {
23
+ low = mid + 1;
24
+ } else {
25
+ return true;
26
+ }
27
+ }
28
+
29
+ return false;
30
+ };
31
+
32
+ export const ambiguousMinimalCodePoint = 161;
33
+ export const ambiguousMaximumCodePoint = 1114109;
34
+ export const ambiguousRanges: readonly number[] = [
35
+ 161, 161, 164, 164, 167, 168, 170, 170, 173, 174, 176, 180, 182, 186, 188, 191, 198, 198, 208,
36
+ 208, 215, 216, 222, 225, 230, 230, 232, 234, 236, 237, 240, 240, 242, 243, 247, 250, 252, 252,
37
+ 254, 254, 257, 257, 273, 273, 275, 275, 283, 283, 294, 295, 299, 299, 305, 307, 312, 312, 319,
38
+ 322, 324, 324, 328, 331, 333, 333, 338, 339, 358, 359, 363, 363, 462, 462, 464, 464, 466, 466,
39
+ 468, 468, 470, 470, 472, 472, 474, 474, 476, 476, 593, 593, 609, 609, 708, 708, 711, 711, 713,
40
+ 715, 717, 717, 720, 720, 728, 731, 733, 733, 735, 735, 768, 879, 913, 929, 931, 937, 945, 961,
41
+ 963, 969, 1025, 1025, 1040, 1103, 1105, 1105, 8208, 8208, 8211, 8214, 8216, 8217, 8220, 8221,
42
+ 8224, 8226, 8228, 8231, 8240, 8240, 8242, 8243, 8245, 8245, 8251, 8251, 8254, 8254, 8308, 8308,
43
+ 8319, 8319, 8321, 8324, 8364, 8364, 8451, 8451, 8453, 8453, 8457, 8457, 8467, 8467, 8470, 8470,
44
+ 8481, 8482, 8486, 8486, 8491, 8491, 8531, 8532, 8539, 8542, 8544, 8555, 8560, 8569, 8585, 8585,
45
+ 8592, 8601, 8632, 8633, 8658, 8658, 8660, 8660, 8679, 8679, 8704, 8704, 8706, 8707, 8711, 8712,
46
+ 8715, 8715, 8719, 8719, 8721, 8721, 8725, 8725, 8730, 8730, 8733, 8736, 8739, 8739, 8741, 8741,
47
+ 8743, 8748, 8750, 8750, 8756, 8759, 8764, 8765, 8776, 8776, 8780, 8780, 8786, 8786, 8800, 8801,
48
+ 8804, 8807, 8810, 8811, 8814, 8815, 8834, 8835, 8838, 8839, 8853, 8853, 8857, 8857, 8869, 8869,
49
+ 8895, 8895, 8978, 8978, 9312, 9449, 9451, 9547, 9552, 9587, 9600, 9615, 9618, 9621, 9632, 9633,
50
+ 9635, 9641, 9650, 9651, 9654, 9655, 9660, 9661, 9664, 9665, 9670, 9672, 9675, 9675, 9678, 9681,
51
+ 9698, 9701, 9711, 9711, 9733, 9734, 9737, 9737, 9742, 9743, 9756, 9756, 9758, 9758, 9792, 9792,
52
+ 9794, 9794, 9824, 9825, 9827, 9829, 9831, 9834, 9836, 9837, 9839, 9839, 9886, 9887, 9919, 9919,
53
+ 9926, 9933, 9935, 9939, 9941, 9953, 9955, 9955, 9960, 9961, 9963, 9969, 9972, 9972, 9974, 9977,
54
+ 9979, 9980, 9982, 9983, 10045, 10045, 10102, 10111, 11094, 11097, 12872, 12879, 57344, 63743,
55
+ 65024, 65039, 65533, 65533, 127232, 127242, 127248, 127277, 127280, 127337, 127344, 127373,
56
+ 127375, 127376, 127387, 127404, 917760, 917999, 983040, 1048573, 1048576, 1114109,
57
+ ];
58
+
59
+ export const fullwidthMinimalCodePoint = 12288;
60
+ export const fullwidthMaximumCodePoint = 65510;
61
+ export const fullwidthRanges: readonly number[] = [12288, 12288, 65281, 65376, 65504, 65510];
62
+
63
+ export const halfwidthMinimalCodePoint = 8361;
64
+ export const halfwidthMaximumCodePoint = 65518;
65
+ export const halfwidthRanges: readonly number[] = [
66
+ 8361, 8361, 65377, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, 65512, 65518,
67
+ ];
68
+
69
+ export const narrowMinimalCodePoint = 32;
70
+ export const narrowMaximumCodePoint = 10630;
71
+ export const narrowRanges: readonly number[] = [
72
+ 32, 126, 162, 163, 165, 166, 172, 172, 175, 175, 10214, 10221, 10629, 10630,
73
+ ];
74
+
75
+ export const wideMinimalCodePoint = 4352;
76
+ export const wideMaximumCodePoint = 262141;
77
+ export const wideRanges: readonly number[] = [
78
+ 4352, 4447, 8986, 8987, 9001, 9002, 9193, 9196, 9200, 9200, 9203, 9203, 9725, 9726, 9748, 9749,
79
+ 9776, 9783, 9800, 9811, 9855, 9855, 9866, 9871, 9875, 9875, 9889, 9889, 9898, 9899, 9917, 9918,
80
+ 9924, 9925, 9934, 9934, 9940, 9940, 9962, 9962, 9970, 9971, 9973, 9973, 9978, 9978, 9981, 9981,
81
+ 9989, 9989, 9994, 9995, 10024, 10024, 10060, 10060, 10062, 10062, 10067, 10069, 10071, 10071,
82
+ 10133, 10135, 10160, 10160, 10175, 10175, 11035, 11036, 11088, 11088, 11093, 11093, 11904, 11929,
83
+ 11931, 12019, 12032, 12245, 12272, 12287, 12289, 12350, 12353, 12438, 12441, 12543, 12549, 12591,
84
+ 12593, 12686, 12688, 12773, 12783, 12830, 12832, 12871, 12880, 42124, 42128, 42182, 43360, 43388,
85
+ 44032, 55203, 63744, 64255, 65040, 65049, 65072, 65106, 65108, 65126, 65128, 65131, 94176, 94180,
86
+ 94192, 94198, 94208, 101589, 101631, 101662, 101760, 101874, 110576, 110579, 110581, 110587,
87
+ 110589, 110590, 110592, 110882, 110898, 110898, 110928, 110930, 110933, 110933, 110948, 110951,
88
+ 110960, 111355, 119552, 119638, 119648, 119670, 126980, 126980, 127183, 127183, 127374, 127374,
89
+ 127377, 127386, 127488, 127490, 127504, 127547, 127552, 127560, 127568, 127569, 127584, 127589,
90
+ 127744, 127776, 127789, 127797, 127799, 127868, 127870, 127891, 127904, 127946, 127951, 127955,
91
+ 127968, 127984, 127988, 127988, 127992, 128062, 128064, 128064, 128066, 128252, 128255, 128317,
92
+ 128331, 128334, 128336, 128359, 128378, 128378, 128405, 128406, 128420, 128420, 128507, 128591,
93
+ 128640, 128709, 128716, 128716, 128720, 128722, 128725, 128728, 128732, 128735, 128747, 128748,
94
+ 128756, 128764, 128992, 129003, 129008, 129008, 129292, 129338, 129340, 129349, 129351, 129535,
95
+ 129648, 129660, 129664, 129674, 129678, 129734, 129736, 129736, 129741, 129756, 129759, 129770,
96
+ 129775, 129784, 131072, 196605, 196608, 262141,
97
+ ];
98
+
99
+ const commonCjkCodePoint = 0x4e_00;
100
+ const [wideFastPathStart, wideFastPathEnd] = /* #__PURE__ */ findWideFastPathRange(wideRanges);
101
+
102
+ // Use a hot-path range so common `isWide` calls can skip binary search.
103
+ // The range containing U+4E00 covers common CJK ideographs;
104
+ // fallback to the largest range for resilience to Unicode table changes.
105
+ function findWideFastPathRange(ranges: readonly number[]): [number, number] {
106
+ let fastPathStart = ranges[0]!;
107
+ let fastPathEnd = ranges[1]!;
108
+
109
+ for (let index = 0; index < ranges.length; index += 2) {
110
+ const start = ranges[index]!;
111
+ const end = ranges[index + 1]!;
112
+
113
+ if (commonCjkCodePoint >= start && commonCjkCodePoint <= end) {
114
+ return [start, end];
115
+ }
116
+
117
+ if (end - start > fastPathEnd - fastPathStart) {
118
+ fastPathStart = start;
119
+ fastPathEnd = end;
120
+ }
121
+ }
122
+
123
+ return [fastPathStart, fastPathEnd];
124
+ }
125
+
126
+ export const isAmbiguous = (codePoint: number): boolean => {
127
+ if (codePoint < ambiguousMinimalCodePoint || codePoint > ambiguousMaximumCodePoint) {
128
+ return false;
129
+ }
130
+
131
+ return isInRange(ambiguousRanges, codePoint);
132
+ };
133
+
134
+ export const isFullWidth = (codePoint: number): boolean => {
135
+ if (codePoint < fullwidthMinimalCodePoint || codePoint > fullwidthMaximumCodePoint) {
136
+ return false;
137
+ }
138
+
139
+ return isInRange(fullwidthRanges, codePoint);
140
+ };
141
+
142
+ const isHalfWidth = (codePoint: number): boolean => {
143
+ if (codePoint < halfwidthMinimalCodePoint || codePoint > halfwidthMaximumCodePoint) {
144
+ return false;
145
+ }
146
+
147
+ return isInRange(halfwidthRanges, codePoint);
148
+ };
149
+
150
+ const isNarrow = (codePoint: number): boolean => {
151
+ if (codePoint < narrowMinimalCodePoint || codePoint > narrowMaximumCodePoint) {
152
+ return false;
153
+ }
154
+
155
+ return isInRange(narrowRanges, codePoint);
156
+ };
157
+
158
+ export const isWide = (codePoint: number): boolean => {
159
+ if (codePoint >= wideFastPathStart && codePoint <= wideFastPathEnd) {
160
+ return true;
161
+ }
162
+
163
+ if (codePoint < wideMinimalCodePoint || codePoint > wideMaximumCodePoint) {
164
+ return false;
165
+ }
166
+
167
+ return isInRange(wideRanges, codePoint);
168
+ };
169
+
170
+ export function getCategory(codePoint: number): EastAsianWidthType {
171
+ if (isAmbiguous(codePoint)) {
172
+ return "ambiguous";
173
+ }
174
+
175
+ if (isFullWidth(codePoint)) {
176
+ return "fullwidth";
177
+ }
178
+
179
+ if (isHalfWidth(codePoint)) {
180
+ return "halfwidth";
181
+ }
182
+
183
+ if (isNarrow(codePoint)) {
184
+ return "narrow";
185
+ }
186
+
187
+ if (isWide(codePoint)) {
188
+ return "wide";
189
+ }
190
+
191
+ return "neutral";
192
+ }
193
+
194
+ export function eastAsianWidthType(codePoint: number): EastAsianWidthType {
195
+ return getCategory(codePoint);
196
+ }
197
+
198
+ export function eastAsianWidth(
199
+ codePoint: number,
200
+ { ambiguousAsWide = false }: { ambiguousAsWide?: boolean } = {},
201
+ ): 1 | 2 {
202
+ if (isFullWidth(codePoint) || isWide(codePoint) || (ambiguousAsWide && isAmbiguous(codePoint))) {
203
+ return 2;
204
+ }
205
+
206
+ return 1;
207
+ }
208
+
209
+ /**
210
+ Grapheme-cluster width test shared by the tokenizer (slice/clip path): the
211
+ base code point's East Asian Width, plus emoji presentation rules.
212
+ */
213
+ export function isFullwidthGrapheme(grapheme: string, baseCodePoint: number): boolean {
214
+ if (isFullwidthCodePoint(baseCodePoint)) return true;
215
+ // Variation Selector 16 forces emoji presentation (2 columns wide)
216
+ if (grapheme.includes("\uFE0F")) return true;
217
+ // Regional indicator pairs form flag emoji (2 columns wide)
218
+ if (baseCodePoint >= 0x1f1e6 && baseCodePoint <= 0x1f1ff) return true;
219
+ return false;
220
+ }
221
+
222
+ /**
223
+ Wide code points not covered by string-width's CJKT script regex or emoji
224
+ regex — the fallback bucket of its block parser. A disjoint decomposition of
225
+ the `wide` table above, kept alongside it so the width data lives in one
226
+ module.
227
+ */
228
+ export const isWideNotCJKTNotEmoji = (x: number): boolean => {
229
+ return (
230
+ x === 0x231b ||
231
+ x === 0x2329 ||
232
+ (x >= 0x2ff0 && x <= 0x2fff) ||
233
+ (x >= 0x3001 && x <= 0x303e) ||
234
+ (x >= 0x3099 && x <= 0x30ff) ||
235
+ (x >= 0x3105 && x <= 0x312f) ||
236
+ (x >= 0x3131 && x <= 0x318e) ||
237
+ (x >= 0x3190 && x <= 0x31e3) ||
238
+ (x >= 0x31ef && x <= 0x321e) ||
239
+ (x >= 0x3220 && x <= 0x3247) ||
240
+ (x >= 0x3250 && x <= 0x4dbf) ||
241
+ (x >= 0xfe10 && x <= 0xfe19) ||
242
+ (x >= 0xfe30 && x <= 0xfe52) ||
243
+ (x >= 0xfe54 && x <= 0xfe66) ||
244
+ (x >= 0xfe68 && x <= 0xfe6b) ||
245
+ (x >= 0x1f200 && x <= 0x1f202) ||
246
+ (x >= 0x1f210 && x <= 0x1f23b) ||
247
+ (x >= 0x1f240 && x <= 0x1f248) ||
248
+ (x >= 0x20000 && x <= 0x2fffd) ||
249
+ (x >= 0x30000 && x <= 0x3fffd)
250
+ );
251
+ };
252
+
253
+ export function isFullwidthCodePoint(codePoint: number): boolean {
254
+ if (!Number.isInteger(codePoint)) {
255
+ return false;
256
+ }
257
+
258
+ return isFullWidth(codePoint) || isWide(codePoint);
259
+ }