@silvery/term 0.3.0

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 (92) hide show
  1. package/package.json +54 -0
  2. package/src/adapters/canvas-adapter.ts +356 -0
  3. package/src/adapters/dom-adapter.ts +452 -0
  4. package/src/adapters/flexily-zero-adapter.ts +368 -0
  5. package/src/adapters/terminal-adapter.ts +305 -0
  6. package/src/adapters/yoga-adapter.ts +370 -0
  7. package/src/ansi/ansi.ts +251 -0
  8. package/src/ansi/constants.ts +76 -0
  9. package/src/ansi/detection.ts +441 -0
  10. package/src/ansi/hyperlink.ts +38 -0
  11. package/src/ansi/index.ts +201 -0
  12. package/src/ansi/patch-console.ts +159 -0
  13. package/src/ansi/sgr-codes.ts +34 -0
  14. package/src/ansi/storybook.ts +209 -0
  15. package/src/ansi/term.ts +724 -0
  16. package/src/ansi/types.ts +202 -0
  17. package/src/ansi/underline.ts +156 -0
  18. package/src/ansi/utils.ts +65 -0
  19. package/src/ansi-sanitize.ts +509 -0
  20. package/src/app.ts +571 -0
  21. package/src/bound-term.ts +94 -0
  22. package/src/bracketed-paste.ts +75 -0
  23. package/src/browser-renderer.ts +174 -0
  24. package/src/buffer.ts +1984 -0
  25. package/src/clipboard.ts +74 -0
  26. package/src/cursor-query.ts +85 -0
  27. package/src/device-attrs.ts +228 -0
  28. package/src/devtools.ts +123 -0
  29. package/src/dom/index.ts +194 -0
  30. package/src/errors.ts +39 -0
  31. package/src/focus-reporting.ts +48 -0
  32. package/src/hit-registry-core.ts +228 -0
  33. package/src/hit-registry.ts +176 -0
  34. package/src/index.ts +458 -0
  35. package/src/input.ts +119 -0
  36. package/src/inspector.ts +155 -0
  37. package/src/kitty-detect.ts +95 -0
  38. package/src/kitty-manager.ts +160 -0
  39. package/src/layout-engine.ts +296 -0
  40. package/src/layout.ts +26 -0
  41. package/src/measurer.ts +74 -0
  42. package/src/mode-query.ts +106 -0
  43. package/src/mouse-events.ts +419 -0
  44. package/src/mouse.ts +83 -0
  45. package/src/non-tty.ts +223 -0
  46. package/src/osc-markers.ts +32 -0
  47. package/src/osc-palette.ts +169 -0
  48. package/src/output.ts +406 -0
  49. package/src/pane-manager.ts +248 -0
  50. package/src/pipeline/CLAUDE.md +587 -0
  51. package/src/pipeline/content-phase-adapter.ts +976 -0
  52. package/src/pipeline/content-phase.ts +1765 -0
  53. package/src/pipeline/helpers.ts +42 -0
  54. package/src/pipeline/index.ts +416 -0
  55. package/src/pipeline/layout-phase.ts +686 -0
  56. package/src/pipeline/measure-phase.ts +198 -0
  57. package/src/pipeline/measure-stats.ts +21 -0
  58. package/src/pipeline/output-phase.ts +2593 -0
  59. package/src/pipeline/render-box.ts +343 -0
  60. package/src/pipeline/render-helpers.ts +243 -0
  61. package/src/pipeline/render-text.ts +1255 -0
  62. package/src/pipeline/types.ts +161 -0
  63. package/src/pipeline.ts +29 -0
  64. package/src/pixel-size.ts +119 -0
  65. package/src/render-adapter.ts +179 -0
  66. package/src/renderer.ts +1330 -0
  67. package/src/runtime/create-app.tsx +1845 -0
  68. package/src/runtime/create-buffer.ts +18 -0
  69. package/src/runtime/create-runtime.ts +325 -0
  70. package/src/runtime/diff.ts +56 -0
  71. package/src/runtime/event-handlers.ts +254 -0
  72. package/src/runtime/index.ts +119 -0
  73. package/src/runtime/keys.ts +8 -0
  74. package/src/runtime/layout.ts +164 -0
  75. package/src/runtime/run.tsx +318 -0
  76. package/src/runtime/term-provider.ts +399 -0
  77. package/src/runtime/terminal-lifecycle.ts +246 -0
  78. package/src/runtime/tick.ts +219 -0
  79. package/src/runtime/types.ts +210 -0
  80. package/src/scheduler.ts +723 -0
  81. package/src/screenshot.ts +57 -0
  82. package/src/scroll-region.ts +69 -0
  83. package/src/scroll-utils.ts +97 -0
  84. package/src/term-def.ts +267 -0
  85. package/src/terminal-caps.ts +5 -0
  86. package/src/terminal-colors.ts +216 -0
  87. package/src/termtest.ts +224 -0
  88. package/src/text-sizing.ts +109 -0
  89. package/src/toolbelt/index.ts +72 -0
  90. package/src/unicode.ts +1763 -0
  91. package/src/xterm/index.ts +491 -0
  92. package/src/xterm/xterm-provider.ts +204 -0
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Bracketed Paste Mode
3
+ *
4
+ * Enables bracketed paste so the terminal wraps pasted text with markers.
5
+ * This lets the app distinguish pasted text from typed input and receive
6
+ * it as a single event rather than individual keystrokes.
7
+ *
8
+ * Protocol: DEC private mode 2004
9
+ * - Enable: CSI ? 2004 h
10
+ * - Disable: CSI ? 2004 l
11
+ * - Paste start marker: CSI 200 ~
12
+ * - Paste end marker: CSI 201 ~
13
+ *
14
+ * Supported by: Ghostty, Kitty, WezTerm, iTerm2, Alacritty, xterm, tmux, foot
15
+ */
16
+
17
+ // ============================================================================
18
+ // Constants
19
+ // ============================================================================
20
+
21
+ /** Escape sequence that marks the beginning of pasted text */
22
+ export const PASTE_START = "\x1b[200~"
23
+
24
+ /** Escape sequence that marks the end of pasted text */
25
+ export const PASTE_END = "\x1b[201~"
26
+
27
+ // ============================================================================
28
+ // Protocol Control
29
+ // ============================================================================
30
+
31
+ /**
32
+ * Enable bracketed paste mode.
33
+ * Writes CSI ? 2004 h to the output stream.
34
+ */
35
+ export function enableBracketedPaste(stdout: NodeJS.WriteStream): void {
36
+ stdout.write("\x1b[?2004h")
37
+ }
38
+
39
+ /**
40
+ * Disable bracketed paste mode.
41
+ * Writes CSI ? 2004 l to the output stream.
42
+ */
43
+ export function disableBracketedPaste(stdout: NodeJS.WriteStream): void {
44
+ stdout.write("\x1b[?2004l")
45
+ }
46
+
47
+ // ============================================================================
48
+ // Parsing
49
+ // ============================================================================
50
+
51
+ /** Result of parsing a bracketed paste sequence */
52
+ export interface BracketedPasteResult {
53
+ type: "paste"
54
+ content: string
55
+ }
56
+
57
+ /**
58
+ * Detect and extract bracketed paste content from raw terminal input.
59
+ *
60
+ * Returns the paste content if the input contains a complete bracketed paste
61
+ * sequence (PASTE_START ... PASTE_END), or null if no paste markers are found.
62
+ */
63
+ export function parseBracketedPaste(input: string): BracketedPasteResult | null {
64
+ const startIdx = input.indexOf(PASTE_START)
65
+ if (startIdx === -1) return null
66
+
67
+ const contentStart = startIdx + PASTE_START.length
68
+ const endIdx = input.indexOf(PASTE_END, contentStart)
69
+ if (endIdx === -1) return null
70
+
71
+ return {
72
+ type: "paste",
73
+ content: input.slice(contentStart, endIdx),
74
+ }
75
+ }
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Shared Browser Renderer
3
+ *
4
+ * Common lifecycle logic for browser-based renderers (Canvas, DOM).
5
+ * Both canvas/index.ts and dom/index.ts were ~70-80% identical — this module
6
+ * extracts the shared reconciler setup, scheduling, and render loop.
7
+ */
8
+
9
+ import type { ReactElement } from "react"
10
+ import { createFlexilyZeroEngine } from "./adapters/flexily-zero-adapter"
11
+ import { setLayoutEngine } from "./layout-engine"
12
+ import { executeRenderAdapter } from "./pipeline"
13
+ import { createContainer, createFiberRoot, getContainerRoot, reconciler } from "@silvery/react/reconciler"
14
+ import type { RenderAdapter, RenderBuffer } from "./render-adapter"
15
+ import { setRenderAdapter } from "./render-adapter"
16
+
17
+ // ============================================================================
18
+ // Types
19
+ // ============================================================================
20
+
21
+ /** Config for creating a browser adapter */
22
+ export interface BrowserAdapterFactory<TConfig> {
23
+ createAdapter(config: TConfig): RenderAdapter
24
+ }
25
+
26
+ /** Callback invoked after each render with the new buffer */
27
+ export type OnRender<TBuffer extends RenderBuffer> = (buffer: TBuffer) => void
28
+
29
+ /** Base instance returned by createBrowserRenderer */
30
+ export interface BrowserInstance {
31
+ /** Re-render with a new element */
32
+ rerender: (element: ReactElement) => void
33
+ /** Unmount and clean up */
34
+ unmount: () => void
35
+ /** Dispose (alias for unmount) — enables `using` */
36
+ [Symbol.dispose](): void
37
+ /** Get the current buffer */
38
+ getBuffer: () => RenderBuffer | null
39
+ /** Force a re-render */
40
+ refresh: () => void
41
+ }
42
+
43
+ // ============================================================================
44
+ // Initialization
45
+ // ============================================================================
46
+
47
+ let initialized = false
48
+
49
+ /**
50
+ * Initialize the browser rendering system with a specific adapter.
51
+ * Called automatically by render functions, but can be called manually.
52
+ * Idempotent — only the first call takes effect.
53
+ */
54
+ export function initBrowserRenderer<TConfig>(factory: BrowserAdapterFactory<TConfig>, config: TConfig): void {
55
+ if (initialized) return
56
+
57
+ setLayoutEngine(createFlexilyZeroEngine())
58
+ setRenderAdapter(factory.createAdapter(config))
59
+
60
+ initialized = true
61
+ }
62
+
63
+ // ============================================================================
64
+ // Render Loop
65
+ // ============================================================================
66
+
67
+ /**
68
+ * Create a browser renderer instance with reconciler lifecycle and scheduling.
69
+ *
70
+ * @param element - React element to render
71
+ * @param width - Render width
72
+ * @param height - Render height
73
+ * @param onRender - Called after each render with the new buffer
74
+ * @param onUnmount - Optional cleanup callback after reconciler unmount
75
+ */
76
+ export function createBrowserRenderer<TBuffer extends RenderBuffer>(
77
+ element: ReactElement,
78
+ width: number,
79
+ height: number,
80
+ onRender: OnRender<TBuffer>,
81
+ onUnmount?: () => void,
82
+ ): BrowserInstance {
83
+ const container = createContainer(() => {
84
+ scheduleRender()
85
+ })
86
+
87
+ const root = getContainerRoot(container)
88
+ const fiberRoot = createFiberRoot(container)
89
+
90
+ let currentBuffer: RenderBuffer | null = null
91
+ let currentElement: ReactElement = element
92
+ let renderScheduled = false
93
+
94
+ function scheduleRender(): void {
95
+ if (renderScheduled) return
96
+ renderScheduled = true
97
+
98
+ if (typeof requestAnimationFrame !== "undefined") {
99
+ requestAnimationFrame(() => {
100
+ renderScheduled = false
101
+ doRender()
102
+ })
103
+ } else {
104
+ setTimeout(() => {
105
+ renderScheduled = false
106
+ doRender()
107
+ }, 0)
108
+ }
109
+ }
110
+
111
+ function doRender(): void {
112
+ reconciler.updateContainerSync(currentElement, fiberRoot, null, null)
113
+ reconciler.flushSyncWork()
114
+
115
+ const prevBuffer = currentBuffer
116
+ const result = executeRenderAdapter(root, width, height, prevBuffer)
117
+ currentBuffer = result.buffer
118
+
119
+ onRender(currentBuffer as TBuffer)
120
+ }
121
+
122
+ // Initial render
123
+ doRender()
124
+
125
+ const unmount = (): void => {
126
+ reconciler.updateContainer(null, fiberRoot, null, () => {})
127
+ onUnmount?.()
128
+ }
129
+
130
+ return {
131
+ rerender(newElement: ReactElement): void {
132
+ currentElement = newElement
133
+ scheduleRender()
134
+ },
135
+
136
+ unmount,
137
+ [Symbol.dispose]: unmount,
138
+
139
+ getBuffer(): RenderBuffer | null {
140
+ return currentBuffer
141
+ },
142
+
143
+ refresh(): void {
144
+ scheduleRender()
145
+ },
146
+ }
147
+ }
148
+
149
+ // ============================================================================
150
+ // One-Shot Render
151
+ // ============================================================================
152
+
153
+ /**
154
+ * Render a React element once and return the buffer.
155
+ * No ongoing updates — useful for static rendering or server-side generation.
156
+ */
157
+ export function renderOnce<TBuffer extends RenderBuffer>(
158
+ element: ReactElement,
159
+ width: number,
160
+ height: number,
161
+ ): TBuffer {
162
+ const container = createContainer(() => {})
163
+ const root = getContainerRoot(container)
164
+ const fiberRoot = createFiberRoot(container)
165
+
166
+ reconciler.updateContainerSync(element, fiberRoot, null, null)
167
+ reconciler.flushSyncWork()
168
+
169
+ const { buffer } = executeRenderAdapter(root, width, height, null)
170
+
171
+ reconciler.updateContainer(null, fiberRoot, null, () => {})
172
+
173
+ return buffer as TBuffer
174
+ }