nastech-tui 0.0.1
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.
- package/.prettierrc +11 -0
- package/README.md +346 -0
- package/eslint.config.mjs +111 -0
- package/package.json +51 -0
- package/packages/nastech-ink/ambient.d.ts +83 -0
- package/packages/nastech-ink/index.d.ts +40 -0
- package/packages/nastech-ink/index.js +1 -0
- package/packages/nastech-ink/nastech-ink/ambient.d.ts +83 -0
- package/packages/nastech-ink/nastech-ink/index.d.ts +40 -0
- package/packages/nastech-ink/nastech-ink/index.js +1 -0
- package/packages/nastech-ink/nastech-ink/package.json +54 -0
- package/packages/nastech-ink/nastech-ink/src/bootstrap/state.ts +9 -0
- package/packages/nastech-ink/nastech-ink/src/entry-exports.ts +32 -0
- package/packages/nastech-ink/nastech-ink/src/hooks/use-stderr.ts +15 -0
- package/packages/nastech-ink/nastech-ink/src/hooks/use-stdout.ts +15 -0
- package/packages/nastech-ink/nastech-ink/src/ink/Ansi.tsx +435 -0
- package/packages/nastech-ink/nastech-ink/src/ink/app-mouse.test.ts +123 -0
- package/packages/nastech-ink/nastech-ink/src/ink/bidi.ts +145 -0
- package/packages/nastech-ink/nastech-ink/src/ink/cache-eviction.ts +45 -0
- package/packages/nastech-ink/nastech-ink/src/ink/clearTerminal.ts +68 -0
- package/packages/nastech-ink/nastech-ink/src/ink/colorize.test.ts +60 -0
- package/packages/nastech-ink/nastech-ink/src/ink/colorize.ts +277 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/AlternateScreen.tsx +133 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/App.tsx +830 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/AppContext.ts +20 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/Box.tsx +294 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/Button.tsx +236 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/ClockContext.tsx +133 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/CursorAdvanceContext.ts +35 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/CursorDeclarationContext.ts +28 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/ErrorOverview.tsx +130 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/Link.tsx +38 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/Newline.tsx +43 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/NoSelect.tsx +73 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/RawAnsi.tsx +61 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/ScrollBox.tsx +290 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/Spacer.tsx +23 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/StdinContext.ts +25 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/TerminalFocusContext.tsx +63 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/TerminalSizeContext.tsx +7 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/Text.test.ts +38 -0
- package/packages/nastech-ink/nastech-ink/src/ink/components/Text.tsx +336 -0
- package/packages/nastech-ink/nastech-ink/src/ink/constants.ts +6 -0
- package/packages/nastech-ink/nastech-ink/src/ink/cursor.ts +5 -0
- package/packages/nastech-ink/nastech-ink/src/ink/devtools.ts +2 -0
- package/packages/nastech-ink/nastech-ink/src/ink/dom.ts +495 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/click-event.ts +38 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/cmd-shortcuts.test.ts +65 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/dispatcher.ts +242 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/emitter.ts +40 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/event-handlers.ts +84 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/event.ts +11 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/focus-event.ts +18 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/input-event.ts +176 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/keyboard-event.ts +57 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/mouse-event.ts +18 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/paste-event.ts +10 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/resize-event.ts +12 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/terminal-event.ts +107 -0
- package/packages/nastech-ink/nastech-ink/src/ink/events/terminal-focus-event.ts +19 -0
- package/packages/nastech-ink/nastech-ink/src/ink/focus.ts +219 -0
- package/packages/nastech-ink/nastech-ink/src/ink/frame.ts +124 -0
- package/packages/nastech-ink/nastech-ink/src/ink/get-max-width.ts +27 -0
- package/packages/nastech-ink/nastech-ink/src/ink/global.d.ts +1 -0
- package/packages/nastech-ink/nastech-ink/src/ink/hit-test.test.ts +38 -0
- package/packages/nastech-ink/nastech-ink/src/ink/hit-test.ts +224 -0
- package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-animation-frame.ts +62 -0
- package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-app.ts +9 -0
- package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-cursor-advance.ts +33 -0
- package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-declared-cursor.ts +75 -0
- package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-external-process.ts +27 -0
- package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-input.ts +95 -0
- package/packages/nastech-ink/nastech-ink/src/ink/hooks/use-interval.ts +71 -0
- package/packages/nastech-ink/package.json +57 -0
- package/packages/nastech-ink/src/bootstrap/state.ts +9 -0
- package/packages/nastech-ink/src/entry-exports.ts +32 -0
- package/packages/nastech-ink/src/hooks/use-stderr.ts +15 -0
- package/packages/nastech-ink/src/hooks/use-stdout.ts +15 -0
- package/packages/nastech-ink/src/ink/Ansi.tsx +435 -0
- package/packages/nastech-ink/src/ink/app-mouse.test.ts +123 -0
- package/packages/nastech-ink/src/ink/app-rawmode-mouse.test.ts +91 -0
- package/packages/nastech-ink/src/ink/bidi.ts +145 -0
- package/packages/nastech-ink/src/ink/cache-eviction.ts +45 -0
- package/packages/nastech-ink/src/ink/clearTerminal.ts +68 -0
- package/packages/nastech-ink/src/ink/colorize.test.ts +60 -0
- package/packages/nastech-ink/src/ink/colorize.ts +277 -0
- package/packages/nastech-ink/src/ink/components/AlternateScreen.tsx +133 -0
- package/packages/nastech-ink/src/ink/components/App.tsx +855 -0
- package/packages/nastech-ink/src/ink/components/AppContext.ts +20 -0
- package/packages/nastech-ink/src/ink/components/Box.tsx +294 -0
- package/packages/nastech-ink/src/ink/components/Button.tsx +236 -0
- package/packages/nastech-ink/src/ink/components/ClockContext.tsx +133 -0
- package/packages/nastech-ink/src/ink/components/CursorAdvanceContext.ts +35 -0
- package/packages/nastech-ink/src/ink/components/CursorDeclarationContext.ts +28 -0
- package/packages/nastech-ink/src/ink/components/ErrorOverview.tsx +130 -0
- package/packages/nastech-ink/src/ink/components/Link.tsx +38 -0
- package/packages/nastech-ink/src/ink/components/Newline.tsx +43 -0
- package/packages/nastech-ink/src/ink/components/NoSelect.tsx +73 -0
- package/packages/nastech-ink/src/ink/components/RawAnsi.tsx +61 -0
- package/packages/nastech-ink/src/ink/components/ScrollBox.tsx +290 -0
- package/packages/nastech-ink/src/ink/components/Spacer.tsx +23 -0
- package/packages/nastech-ink/src/ink/components/StdinContext.ts +25 -0
- package/packages/nastech-ink/src/ink/components/TerminalFocusContext.tsx +63 -0
- package/packages/nastech-ink/src/ink/components/TerminalSizeContext.tsx +7 -0
- package/packages/nastech-ink/src/ink/components/Text.test.ts +38 -0
- package/packages/nastech-ink/src/ink/components/Text.tsx +336 -0
- package/packages/nastech-ink/src/ink/constants.ts +6 -0
- package/packages/nastech-ink/src/ink/cursor.ts +5 -0
- package/packages/nastech-ink/src/ink/devtools.ts +2 -0
- package/packages/nastech-ink/src/ink/dom.ts +495 -0
- package/packages/nastech-ink/src/ink/events/click-event.ts +38 -0
- package/packages/nastech-ink/src/ink/events/cmd-shortcuts.test.ts +65 -0
- package/packages/nastech-ink/src/ink/events/dispatcher.ts +242 -0
- package/packages/nastech-ink/src/ink/events/emitter.ts +40 -0
- package/packages/nastech-ink/src/ink/events/event-handlers.ts +84 -0
- package/packages/nastech-ink/src/ink/events/event.ts +11 -0
- package/packages/nastech-ink/src/ink/events/focus-event.ts +18 -0
- package/packages/nastech-ink/src/ink/events/input-event.ts +176 -0
- package/packages/nastech-ink/src/ink/events/keyboard-event.ts +57 -0
- package/packages/nastech-ink/src/ink/events/mouse-event.ts +18 -0
- package/packages/nastech-ink/src/ink/events/paste-event.ts +10 -0
- package/packages/nastech-ink/src/ink/events/resize-event.ts +12 -0
- package/packages/nastech-ink/src/ink/events/terminal-event.ts +107 -0
- package/packages/nastech-ink/src/ink/events/terminal-focus-event.ts +19 -0
- package/packages/nastech-ink/src/ink/focus.ts +219 -0
- package/packages/nastech-ink/src/ink/frame.ts +124 -0
- package/packages/nastech-ink/src/ink/get-max-width.ts +27 -0
- package/packages/nastech-ink/src/ink/global.d.ts +1 -0
- package/packages/nastech-ink/src/ink/hit-test.test.ts +38 -0
- package/packages/nastech-ink/src/ink/hit-test.ts +224 -0
- package/packages/nastech-ink/src/ink/hooks/use-animation-frame.ts +62 -0
- package/packages/nastech-ink/src/ink/hooks/use-app.ts +9 -0
- package/packages/nastech-ink/src/ink/hooks/use-cursor-advance.ts +33 -0
- package/packages/nastech-ink/src/ink/hooks/use-declared-cursor.ts +75 -0
- package/packages/nastech-ink/src/ink/hooks/use-external-process.ts +27 -0
- package/packages/nastech-ink/src/ink/hooks/use-input.ts +95 -0
- package/packages/nastech-ink/src/ink/hooks/use-interval.ts +71 -0
- package/packages/nastech-ink/src/ink/hooks/use-search-highlight.ts +56 -0
- package/packages/nastech-ink/src/ink/hooks/use-selection.ts +101 -0
- package/packages/nastech-ink/src/ink/hooks/use-stdin.ts +9 -0
- package/packages/nastech-ink/src/ink/hooks/use-tab-status.ts +71 -0
- package/packages/nastech-ink/src/ink/hooks/use-terminal-focus.ts +18 -0
- package/packages/nastech-ink/src/ink/hooks/use-terminal-title.ts +34 -0
- package/packages/nastech-ink/src/ink/hooks/use-terminal-viewport.ts +100 -0
- package/packages/nastech-ink/src/ink/hyperlinkHover.ts +52 -0
- package/packages/nastech-ink/src/ink/ink-cursor-advance.test.ts +234 -0
- package/packages/nastech-ink/src/ink/ink-resize.test.ts +50 -0
- package/packages/nastech-ink/src/ink/ink.tsx +2705 -0
- package/packages/nastech-ink/src/ink/instances.ts +10 -0
- package/packages/nastech-ink/src/ink/layout/engine.ts +6 -0
- package/packages/nastech-ink/src/ink/layout/geometry.ts +98 -0
- package/packages/nastech-ink/src/ink/layout/node.ts +145 -0
- package/packages/nastech-ink/src/ink/layout/yoga.ts +313 -0
- package/packages/nastech-ink/src/ink/line-width-cache.ts +38 -0
- package/packages/nastech-ink/src/ink/log-update.test.ts +223 -0
- package/packages/nastech-ink/src/ink/log-update.ts +752 -0
- package/packages/nastech-ink/src/ink/lru.ts +14 -0
- package/packages/nastech-ink/src/ink/measure-element.ts +23 -0
- package/packages/nastech-ink/src/ink/measure-text.ts +50 -0
- package/packages/nastech-ink/src/ink/node-cache.ts +53 -0
- package/packages/nastech-ink/src/ink/optimizer.ts +99 -0
- package/packages/nastech-ink/src/ink/output.ts +845 -0
- package/packages/nastech-ink/src/ink/parse-keypress.test.ts +133 -0
- package/packages/nastech-ink/src/ink/parse-keypress.ts +848 -0
- package/packages/nastech-ink/src/ink/reconciler.ts +382 -0
- package/packages/nastech-ink/src/ink/render-border.ts +206 -0
- package/packages/nastech-ink/src/ink/render-node-to-output.ts +1582 -0
- package/packages/nastech-ink/src/ink/render-to-screen.ts +236 -0
- package/packages/nastech-ink/src/ink/renderer.ts +169 -0
- package/packages/nastech-ink/src/ink/root.ts +204 -0
- package/packages/nastech-ink/src/ink/screen.ts +1590 -0
- package/packages/nastech-ink/src/ink/searchHighlight.ts +91 -0
- package/packages/nastech-ink/src/ink/selection.test.ts +82 -0
- package/packages/nastech-ink/src/ink/selection.ts +1143 -0
- package/packages/nastech-ink/src/ink/squash-text-nodes.ts +74 -0
- package/packages/nastech-ink/src/ink/stringWidth.ts +341 -0
- package/packages/nastech-ink/src/ink/styles.ts +750 -0
- package/packages/nastech-ink/src/ink/supports-hyperlinks.ts +51 -0
- package/packages/nastech-ink/src/ink/tabstops.ts +44 -0
- package/packages/nastech-ink/src/ink/terminal-focus-state.ts +52 -0
- package/packages/nastech-ink/src/ink/terminal-querier.ts +222 -0
- package/packages/nastech-ink/src/ink/terminal.test.ts +15 -0
- package/packages/nastech-ink/src/ink/terminal.ts +299 -0
- package/packages/nastech-ink/src/ink/termio/ansi.ts +75 -0
- package/packages/nastech-ink/src/ink/termio/csi.ts +334 -0
- package/packages/nastech-ink/src/ink/termio/dec.ts +99 -0
- package/packages/nastech-ink/src/ink/termio/esc.ts +69 -0
- package/packages/nastech-ink/src/ink/termio/osc.test.ts +191 -0
- package/packages/nastech-ink/src/ink/termio/osc.ts +724 -0
- package/packages/nastech-ink/src/ink/termio/parser.ts +467 -0
- package/packages/nastech-ink/src/ink/termio/sgr.ts +362 -0
- package/packages/nastech-ink/src/ink/termio/tokenize.test.ts +185 -0
- package/packages/nastech-ink/src/ink/termio/tokenize.ts +350 -0
- package/packages/nastech-ink/src/ink/termio/types.ts +230 -0
- package/packages/nastech-ink/src/ink/termio.ts +42 -0
- package/packages/nastech-ink/src/ink/useTerminalNotification.ts +110 -0
- package/packages/nastech-ink/src/ink/warn.ts +15 -0
- package/packages/nastech-ink/src/ink/widest-line.ts +22 -0
- package/packages/nastech-ink/src/ink/wrap-text.test.ts +17 -0
- package/packages/nastech-ink/src/ink/wrap-text.ts +144 -0
- package/packages/nastech-ink/src/ink/wrapAnsi.ts +13 -0
- package/packages/nastech-ink/src/native-ts/yoga-layout/enums.ts +112 -0
- package/packages/nastech-ink/src/native-ts/yoga-layout/index.ts +2326 -0
- package/packages/nastech-ink/src/utils/debug.ts +6 -0
- package/packages/nastech-ink/src/utils/earlyInput.ts +131 -0
- package/packages/nastech-ink/src/utils/env.ts +66 -0
- package/packages/nastech-ink/src/utils/envUtils.ts +13 -0
- package/packages/nastech-ink/src/utils/execFileNoThrow.test.ts +146 -0
- package/packages/nastech-ink/src/utils/execFileNoThrow.ts +115 -0
- package/packages/nastech-ink/src/utils/fullscreen.ts +3 -0
- package/packages/nastech-ink/src/utils/intl.ts +87 -0
- package/packages/nastech-ink/src/utils/log.ts +7 -0
- package/packages/nastech-ink/src/utils/semver.ts +57 -0
- package/packages/nastech-ink/src/utils/sliceAnsi.ts +106 -0
- package/packages/nastech-ink/text-input.d.ts +2 -0
- package/packages/nastech-ink/text-input.js +1 -0
- package/scripts/build.mjs +61 -0
- package/scripts/profile-tui.mjs +121 -0
- package/src/__tests__/activeSessionSwitcher.test.ts +157 -0
- package/src/__tests__/appChromeStatusRule.test.tsx +84 -0
- package/src/__tests__/appChromeStatusRuleDevCredits.test.tsx +73 -0
- package/src/__tests__/approvalAction.test.ts +50 -0
- package/src/__tests__/asCommandDispatch.test.ts +27 -0
- package/src/__tests__/blockLayout.test.ts +122 -0
- package/src/__tests__/clipboard.test.ts +369 -0
- package/src/__tests__/constants.test.ts +53 -0
- package/src/__tests__/createGatewayEventHandler.test.ts +1091 -0
- package/src/__tests__/createSlashHandler.test.ts +822 -0
- package/src/__tests__/creditsCommand.test.ts +144 -0
- package/src/__tests__/cursorDriftRegression.test.ts +114 -0
- package/src/__tests__/details.test.ts +115 -0
- package/src/__tests__/emoji.test.ts +64 -0
- package/src/__tests__/externalLink.test.ts +144 -0
- package/src/__tests__/forceTruecolor.test.ts +191 -0
- package/src/__tests__/gatewayClient.test.ts +394 -0
- package/src/__tests__/gatewayRecovery.test.ts +47 -0
- package/src/__tests__/markdown.test.ts +331 -0
- package/src/__tests__/mathUnicode.test.ts +293 -0
- package/src/__tests__/memoryMonitor.test.ts +102 -0
- package/src/__tests__/messageLine.test.ts +19 -0
- package/src/__tests__/messages.test.ts +92 -0
- package/src/__tests__/orchestratorPromptSession.test.ts +64 -0
- package/src/__tests__/osc52.test.ts +67 -0
- package/src/__tests__/parentLog.test.ts +75 -0
- package/src/__tests__/paths.test.ts +70 -0
- package/src/__tests__/platform.test.ts +556 -0
- package/src/__tests__/precisionWheel.test.ts +44 -0
- package/src/__tests__/prompt.test.ts +31 -0
- package/src/__tests__/providers.test.ts +65 -0
- package/src/__tests__/reasoning.test.ts +76 -0
- package/src/__tests__/rpc.test.ts +27 -0
- package/src/__tests__/scroll.test.ts +99 -0
- package/src/__tests__/slashParity.test.ts +123 -0
- package/src/__tests__/spawnHistoryStore.test.ts +46 -0
- package/src/__tests__/stateIsolation.test.ts +46 -0
- package/src/__tests__/statusBarTicker.test.ts +18 -0
- package/src/__tests__/statusRule.test.ts +32 -0
- package/src/__tests__/streamingMarkdown.test.ts +121 -0
- package/src/__tests__/subagentTree.test.ts +407 -0
- package/src/__tests__/syntax.test.ts +45 -0
- package/src/__tests__/terminalModes.test.ts +39 -0
- package/src/__tests__/terminalParity.test.ts +77 -0
- package/src/__tests__/terminalSetup.test.ts +386 -0
- package/src/__tests__/termux.test.ts +35 -0
- package/src/__tests__/termuxComposerLayout.test.ts +40 -0
- package/src/__tests__/text.test.ts +233 -0
- package/src/__tests__/textInputBurstInput.test.ts +40 -0
- package/src/__tests__/textInputCursorSourceOfTruth.test.ts +50 -0
- package/src/__tests__/textInputFastEcho.test.ts +200 -0
- package/src/__tests__/textInputLineNav.test.ts +55 -0
- package/src/__tests__/textInputPassThrough.test.ts +59 -0
- package/src/__tests__/textInputRightClick.test.ts +48 -0
- package/src/__tests__/textInputWrap.test.ts +151 -0
- package/src/__tests__/theme.test.ts +311 -0
- package/src/__tests__/turnControllerNotice.test.ts +43 -0
- package/src/__tests__/turnStore.test.ts +66 -0
- package/src/__tests__/useCompletion.test.ts +35 -0
- package/src/__tests__/useComposerState.test.ts +59 -0
- package/src/__tests__/useConfigSync.test.ts +460 -0
- package/src/__tests__/useInputHandlers.test.ts +77 -0
- package/src/__tests__/useQueue.test.ts +28 -0
- package/src/__tests__/useSessionLifecycle.test.ts +60 -0
- package/src/__tests__/useVirtualHistoryHeights.test.ts +39 -0
- package/src/__tests__/viewport.test.ts +58 -0
- package/src/__tests__/viewportStore.test.ts +85 -0
- package/src/__tests__/virtualHeights.test.ts +96 -0
- package/src/__tests__/virtualHistoryClamp.test.ts +19 -0
- package/src/__tests__/virtualHistoryOffsetCache.test.ts +282 -0
- package/src/__tests__/wheelAccel.test.ts +138 -0
- package/src/app/createGatewayEventHandler.ts +833 -0
- package/src/app/createSlashHandler.ts +130 -0
- package/src/app/delegationStore.ts +77 -0
- package/src/app/gatewayContext.tsx +19 -0
- package/src/app/gatewayRecovery.ts +35 -0
- package/src/app/inputSelectionStore.ts +15 -0
- package/src/app/interfaces.ts +394 -0
- package/src/app/overlayStore.ts +53 -0
- package/src/app/scroll.ts +71 -0
- package/src/app/setupHandoff.ts +54 -0
- package/src/app/slash/commands/core.ts +648 -0
- package/src/app/slash/commands/credits.ts +57 -0
- package/src/app/slash/commands/debug.ts +48 -0
- package/src/app/slash/commands/ops.ts +717 -0
- package/src/app/slash/commands/session.ts +554 -0
- package/src/app/slash/commands/setup.ts +20 -0
- package/src/app/slash/registry.ts +20 -0
- package/src/app/slash/types.ts +21 -0
- package/src/app/spawnHistoryStore.ts +159 -0
- package/src/app/turnController.ts +866 -0
- package/src/app/turnStore.ts +85 -0
- package/src/app/uiStore.ts +44 -0
- package/src/app/useComposerState.ts +367 -0
- package/src/app/useConfigSync.ts +288 -0
- package/src/app/useInputHandlers.ts +576 -0
- package/src/app/useLongRunToolCharms.ts +69 -0
- package/src/app/useMainApp.ts +1039 -0
- package/src/app/useSessionLifecycle.ts +366 -0
- package/src/app/useSubmission.ts +429 -0
- package/src/app.tsx +25 -0
- package/src/banner.ts +93 -0
- package/src/components/activeSessionSwitcher.tsx +635 -0
- package/src/components/agentsOverlay.tsx +1073 -0
- package/src/components/appChrome.tsx +554 -0
- package/src/components/appLayout.tsx +444 -0
- package/src/components/appOverlays.tsx +254 -0
- package/src/components/branding.tsx +466 -0
- package/src/components/fpsOverlay.tsx +30 -0
- package/src/components/helpHint.tsx +73 -0
- package/src/components/markdown.tsx +1119 -0
- package/src/components/maskedPrompt.tsx +34 -0
- package/src/components/messageLine.tsx +237 -0
- package/src/components/modelPicker.tsx +527 -0
- package/src/components/overlayControls.tsx +50 -0
- package/src/components/pluginsHub.tsx +238 -0
- package/src/components/prompts.tsx +276 -0
- package/src/components/queuedMessages.tsx +64 -0
- package/src/components/sessionPicker.tsx +227 -0
- package/src/components/skillsHub.tsx +308 -0
- package/src/components/streamingAssistant.tsx +110 -0
- package/src/components/streamingMarkdown.tsx +174 -0
- package/src/components/textInput.tsx +1340 -0
- package/src/components/themed.tsx +30 -0
- package/src/components/thinking.tsx +1224 -0
- package/src/components/todoPanel.tsx +93 -0
- package/src/config/env.ts +64 -0
- package/src/config/limits.ts +13 -0
- package/src/config/timing.ts +6 -0
- package/src/content/charms.ts +1 -0
- package/src/content/faces.ts +17 -0
- package/src/content/fortunes.ts +30 -0
- package/src/content/hotkeys.ts +37 -0
- package/src/content/placeholders.ts +13 -0
- package/src/content/setup.ts +17 -0
- package/src/content/verbs.ts +38 -0
- package/src/domain/blockLayout.ts +146 -0
- package/src/domain/details.ts +76 -0
- package/src/domain/messages.ts +91 -0
- package/src/domain/paths.ts +16 -0
- package/src/domain/providers.ts +11 -0
- package/src/domain/roles.ts +9 -0
- package/src/domain/slash.ts +10 -0
- package/src/domain/usage.ts +3 -0
- package/src/domain/viewport.ts +51 -0
- package/src/entry.tsx +104 -0
- package/src/gatewayClient.ts +730 -0
- package/src/gatewayTypes.ts +568 -0
- package/src/hooks/useCompletion.ts +112 -0
- package/src/hooks/useGitBranch.ts +72 -0
- package/src/hooks/useInputHistory.ts +11 -0
- package/src/hooks/useQueue.ts +76 -0
- package/src/hooks/useVirtualHistory.ts +554 -0
- package/src/lib/circularBuffer.ts +48 -0
- package/src/lib/clipboard.ts +182 -0
- package/src/lib/editor.test.ts +74 -0
- package/src/lib/editor.ts +47 -0
- package/src/lib/emoji.ts +55 -0
- package/src/lib/externalCli.ts +16 -0
- package/src/lib/externalLink.ts +435 -0
- package/src/lib/forceTruecolor.ts +60 -0
- package/src/lib/fpsStore.ts +51 -0
- package/src/lib/fuzzy.test.ts +109 -0
- package/src/lib/fuzzy.ts +177 -0
- package/src/lib/gracefulExit.ts +47 -0
- package/src/lib/history.ts +82 -0
- package/src/lib/inputMetrics.ts +203 -0
- package/src/lib/liveProgress.test.ts +116 -0
- package/src/lib/liveProgress.ts +79 -0
- package/src/lib/mathUnicode.ts +770 -0
- package/src/lib/memory.test.ts +155 -0
- package/src/lib/memory.ts +188 -0
- package/src/lib/memoryMonitor.ts +109 -0
- package/src/lib/messages.test.ts +29 -0
- package/src/lib/messages.ts +8 -0
- package/src/lib/openExternalUrl.test.ts +217 -0
- package/src/lib/openExternalUrl.ts +158 -0
- package/src/lib/osc52.ts +73 -0
- package/src/lib/parentLog.ts +57 -0
- package/src/lib/perfPane.tsx +107 -0
- package/src/lib/platform.ts +409 -0
- package/src/lib/precisionWheel.ts +48 -0
- package/src/lib/prompt.ts +35 -0
- package/src/lib/reasoning.ts +55 -0
- package/src/lib/rpc.ts +41 -0
- package/src/lib/subagentTree.ts +355 -0
- package/src/lib/syntax.ts +117 -0
- package/src/lib/terminalModes.ts +51 -0
- package/src/lib/terminalParity.ts +78 -0
- package/src/lib/terminalSetup.ts +444 -0
- package/src/lib/termux.ts +29 -0
- package/src/lib/text.test.ts +18 -0
- package/src/lib/text.ts +339 -0
- package/src/lib/todo.test.ts +21 -0
- package/src/lib/todo.ts +9 -0
- package/src/lib/viewportStore.ts +124 -0
- package/src/lib/virtualHeights.ts +145 -0
- package/src/lib/wheelAccel.ts +190 -0
- package/src/protocol/interpolation.ts +3 -0
- package/src/protocol/paste.ts +1 -0
- package/src/theme.ts +589 -0
- package/src/types/nastech-ink.d.ts +176 -0
- package/src/types.ts +212 -0
- package/tsconfig.build.json +9 -0
- package/tsconfig.json +19 -0
- package/vitest.config.ts +7 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { Event } from './event.js'
|
|
2
|
+
|
|
3
|
+
type EventPhase = 'none' | 'capturing' | 'at_target' | 'bubbling'
|
|
4
|
+
|
|
5
|
+
type TerminalEventInit = {
|
|
6
|
+
bubbles?: boolean
|
|
7
|
+
cancelable?: boolean
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Base class for all terminal events with DOM-style propagation.
|
|
12
|
+
*
|
|
13
|
+
* Extends Event so existing event types (ClickEvent, InputEvent,
|
|
14
|
+
* TerminalFocusEvent) share a common ancestor and can migrate later.
|
|
15
|
+
*
|
|
16
|
+
* Mirrors the browser's Event API: target, currentTarget, eventPhase,
|
|
17
|
+
* stopPropagation(), preventDefault(), timeStamp.
|
|
18
|
+
*/
|
|
19
|
+
export class TerminalEvent extends Event {
|
|
20
|
+
readonly type: string
|
|
21
|
+
readonly timeStamp: number
|
|
22
|
+
readonly bubbles: boolean
|
|
23
|
+
readonly cancelable: boolean
|
|
24
|
+
|
|
25
|
+
private _target: EventTarget | null = null
|
|
26
|
+
private _currentTarget: EventTarget | null = null
|
|
27
|
+
private _eventPhase: EventPhase = 'none'
|
|
28
|
+
private _propagationStopped = false
|
|
29
|
+
private _defaultPrevented = false
|
|
30
|
+
|
|
31
|
+
constructor(type: string, init?: TerminalEventInit) {
|
|
32
|
+
super()
|
|
33
|
+
this.type = type
|
|
34
|
+
this.timeStamp = performance.now()
|
|
35
|
+
this.bubbles = init?.bubbles ?? true
|
|
36
|
+
this.cancelable = init?.cancelable ?? true
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get target(): EventTarget | null {
|
|
40
|
+
return this._target
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get currentTarget(): EventTarget | null {
|
|
44
|
+
return this._currentTarget
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
get eventPhase(): EventPhase {
|
|
48
|
+
return this._eventPhase
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get defaultPrevented(): boolean {
|
|
52
|
+
return this._defaultPrevented
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
stopPropagation(): void {
|
|
56
|
+
this._propagationStopped = true
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
override stopImmediatePropagation(): void {
|
|
60
|
+
super.stopImmediatePropagation()
|
|
61
|
+
this._propagationStopped = true
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
preventDefault(): void {
|
|
65
|
+
if (this.cancelable) {
|
|
66
|
+
this._defaultPrevented = true
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// -- Internal setters used by the Dispatcher
|
|
71
|
+
|
|
72
|
+
/** @internal */
|
|
73
|
+
_setTarget(target: EventTarget): void {
|
|
74
|
+
this._target = target
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** @internal */
|
|
78
|
+
_setCurrentTarget(target: EventTarget | null): void {
|
|
79
|
+
this._currentTarget = target
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** @internal */
|
|
83
|
+
_setEventPhase(phase: EventPhase): void {
|
|
84
|
+
this._eventPhase = phase
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** @internal */
|
|
88
|
+
_isPropagationStopped(): boolean {
|
|
89
|
+
return this._propagationStopped
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** @internal */
|
|
93
|
+
_isImmediatePropagationStopped(): boolean {
|
|
94
|
+
return this.didStopImmediatePropagation()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Hook for subclasses to do per-node setup before each handler fires.
|
|
99
|
+
* Default is a no-op.
|
|
100
|
+
*/
|
|
101
|
+
_prepareForTarget(_target: EventTarget): void {}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export type EventTarget = {
|
|
105
|
+
parentNode: EventTarget | undefined
|
|
106
|
+
_eventHandlers?: Record<string, unknown>
|
|
107
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Event } from './event.js'
|
|
2
|
+
|
|
3
|
+
export type TerminalFocusEventType = 'terminalfocus' | 'terminalblur'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Event fired when the terminal window gains or loses focus.
|
|
7
|
+
*
|
|
8
|
+
* Uses DECSET 1004 focus reporting - the terminal sends:
|
|
9
|
+
* - CSI I (\x1b[I) when the terminal gains focus
|
|
10
|
+
* - CSI O (\x1b[O) when the terminal loses focus
|
|
11
|
+
*/
|
|
12
|
+
export class TerminalFocusEvent extends Event {
|
|
13
|
+
readonly type: TerminalFocusEventType
|
|
14
|
+
|
|
15
|
+
constructor(type: TerminalFocusEventType) {
|
|
16
|
+
super()
|
|
17
|
+
this.type = type
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import type { DOMElement } from './dom.js'
|
|
2
|
+
import { FocusEvent } from './events/focus-event.js'
|
|
3
|
+
|
|
4
|
+
const MAX_FOCUS_STACK = 32
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* DOM-like focus manager for the Ink terminal UI.
|
|
8
|
+
*
|
|
9
|
+
* Pure state — tracks activeElement and a focus stack. Has no reference
|
|
10
|
+
* to the tree; callers pass the root when tree walks are needed.
|
|
11
|
+
*
|
|
12
|
+
* Stored on the root DOMElement so any node can reach it by walking
|
|
13
|
+
* parentNode (like browser's `node.ownerDocument`).
|
|
14
|
+
*/
|
|
15
|
+
export class FocusManager {
|
|
16
|
+
activeElement: DOMElement | null = null
|
|
17
|
+
private dispatchFocusEvent: (target: DOMElement, event: FocusEvent) => boolean
|
|
18
|
+
private enabled = true
|
|
19
|
+
private focusStack: DOMElement[] = []
|
|
20
|
+
|
|
21
|
+
constructor(dispatchFocusEvent: (target: DOMElement, event: FocusEvent) => boolean) {
|
|
22
|
+
this.dispatchFocusEvent = dispatchFocusEvent
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
focus(node: DOMElement): void {
|
|
26
|
+
if (node === this.activeElement) {
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!this.enabled) {
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const previous = this.activeElement
|
|
35
|
+
|
|
36
|
+
if (previous) {
|
|
37
|
+
// Deduplicate before pushing to prevent unbounded growth from Tab cycling
|
|
38
|
+
const idx = this.focusStack.indexOf(previous)
|
|
39
|
+
|
|
40
|
+
if (idx !== -1) {
|
|
41
|
+
this.focusStack.splice(idx, 1)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
this.focusStack.push(previous)
|
|
45
|
+
|
|
46
|
+
if (this.focusStack.length > MAX_FOCUS_STACK) {
|
|
47
|
+
this.focusStack.shift()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
this.dispatchFocusEvent(previous, new FocusEvent('blur', node))
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
this.activeElement = node
|
|
54
|
+
this.dispatchFocusEvent(node, new FocusEvent('focus', previous))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
blur(): void {
|
|
58
|
+
if (!this.activeElement) {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const previous = this.activeElement
|
|
63
|
+
this.activeElement = null
|
|
64
|
+
this.dispatchFocusEvent(previous, new FocusEvent('blur', null))
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Called by the reconciler when a node is removed from the tree.
|
|
69
|
+
* Handles both the exact node and any focused descendant within
|
|
70
|
+
* the removed subtree. Dispatches blur and restores focus from stack.
|
|
71
|
+
*/
|
|
72
|
+
handleNodeRemoved(node: DOMElement, root: DOMElement): void {
|
|
73
|
+
// Remove the node and any descendants from the stack
|
|
74
|
+
this.focusStack = this.focusStack.filter(n => n !== node && isInTree(n, root))
|
|
75
|
+
|
|
76
|
+
// Check if activeElement is the removed node OR a descendant
|
|
77
|
+
if (!this.activeElement) {
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (this.activeElement !== node && isInTree(this.activeElement, root)) {
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const removed = this.activeElement
|
|
86
|
+
this.activeElement = null
|
|
87
|
+
this.dispatchFocusEvent(removed, new FocusEvent('blur', null))
|
|
88
|
+
|
|
89
|
+
// Restore focus to the most recent still-mounted element
|
|
90
|
+
while (this.focusStack.length > 0) {
|
|
91
|
+
const candidate = this.focusStack.pop()!
|
|
92
|
+
|
|
93
|
+
if (isInTree(candidate, root)) {
|
|
94
|
+
this.activeElement = candidate
|
|
95
|
+
this.dispatchFocusEvent(candidate, new FocusEvent('focus', removed))
|
|
96
|
+
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
handleAutoFocus(node: DOMElement): void {
|
|
103
|
+
this.focus(node)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
handleClickFocus(node: DOMElement): void {
|
|
107
|
+
const tabIndex = node.attributes['tabIndex']
|
|
108
|
+
|
|
109
|
+
if (typeof tabIndex !== 'number') {
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
this.focus(node)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
enable(): void {
|
|
117
|
+
this.enabled = true
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
disable(): void {
|
|
121
|
+
this.enabled = false
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
focusNext(root: DOMElement): void {
|
|
125
|
+
this.moveFocus(1, root)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
focusPrevious(root: DOMElement): void {
|
|
129
|
+
this.moveFocus(-1, root)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private moveFocus(direction: 1 | -1, root: DOMElement): void {
|
|
133
|
+
if (!this.enabled) {
|
|
134
|
+
return
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const tabbable = collectTabbable(root)
|
|
138
|
+
|
|
139
|
+
if (tabbable.length === 0) {
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const currentIndex = this.activeElement ? tabbable.indexOf(this.activeElement) : -1
|
|
144
|
+
|
|
145
|
+
const nextIndex =
|
|
146
|
+
currentIndex === -1
|
|
147
|
+
? direction === 1
|
|
148
|
+
? 0
|
|
149
|
+
: tabbable.length - 1
|
|
150
|
+
: (currentIndex + direction + tabbable.length) % tabbable.length
|
|
151
|
+
|
|
152
|
+
const next = tabbable[nextIndex]
|
|
153
|
+
|
|
154
|
+
if (next) {
|
|
155
|
+
this.focus(next)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function collectTabbable(root: DOMElement): DOMElement[] {
|
|
161
|
+
const result: DOMElement[] = []
|
|
162
|
+
walkTree(root, result)
|
|
163
|
+
|
|
164
|
+
return result
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function walkTree(node: DOMElement, result: DOMElement[]): void {
|
|
168
|
+
const tabIndex = node.attributes['tabIndex']
|
|
169
|
+
|
|
170
|
+
if (typeof tabIndex === 'number' && tabIndex >= 0) {
|
|
171
|
+
result.push(node)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
for (const child of node.childNodes) {
|
|
175
|
+
if (child.nodeName !== '#text') {
|
|
176
|
+
walkTree(child, result)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function isInTree(node: DOMElement, root: DOMElement): boolean {
|
|
182
|
+
let current: DOMElement | undefined = node
|
|
183
|
+
|
|
184
|
+
while (current) {
|
|
185
|
+
if (current === root) {
|
|
186
|
+
return true
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
current = current.parentNode
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return false
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Walk up to root and return it. The root is the node that holds
|
|
197
|
+
* the FocusManager — like browser's `node.getRootNode()`.
|
|
198
|
+
*/
|
|
199
|
+
export function getRootNode(node: DOMElement): DOMElement {
|
|
200
|
+
let current: DOMElement | undefined = node
|
|
201
|
+
|
|
202
|
+
while (current) {
|
|
203
|
+
if (current.focusManager) {
|
|
204
|
+
return current
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
current = current.parentNode
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
throw new Error('Node is not in a tree with a FocusManager')
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Walk up to root and return its FocusManager.
|
|
215
|
+
* Like browser's `node.ownerDocument` — focus belongs to the root.
|
|
216
|
+
*/
|
|
217
|
+
export function getFocusManager(node: DOMElement): FocusManager {
|
|
218
|
+
return getRootNode(node).focusManager!
|
|
219
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { Cursor } from './cursor.js'
|
|
2
|
+
import type { Size } from './layout/geometry.js'
|
|
3
|
+
import type { ScrollHint } from './render-node-to-output.js'
|
|
4
|
+
import { type CharPool, createScreen, type HyperlinkPool, type Screen, type StylePool } from './screen.js'
|
|
5
|
+
|
|
6
|
+
export type Frame = {
|
|
7
|
+
readonly screen: Screen
|
|
8
|
+
readonly viewport: Size
|
|
9
|
+
readonly cursor: Cursor
|
|
10
|
+
/** DECSTBM scroll optimization hint (alt-screen only, null otherwise). */
|
|
11
|
+
readonly scrollHint?: ScrollHint | null
|
|
12
|
+
/** A ScrollBox has remaining pendingScrollDelta — schedule another frame. */
|
|
13
|
+
readonly scrollDrainPending?: boolean
|
|
14
|
+
/** Absolute overlay moved/resized — schedule corrective frame without prevScreen. */
|
|
15
|
+
readonly absoluteOverlayMoved?: boolean
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function emptyFrame(
|
|
19
|
+
rows: number,
|
|
20
|
+
columns: number,
|
|
21
|
+
stylePool: StylePool,
|
|
22
|
+
charPool: CharPool,
|
|
23
|
+
hyperlinkPool: HyperlinkPool
|
|
24
|
+
): Frame {
|
|
25
|
+
return {
|
|
26
|
+
screen: createScreen(0, 0, stylePool, charPool, hyperlinkPool),
|
|
27
|
+
viewport: { width: columns, height: rows },
|
|
28
|
+
cursor: { x: 0, y: 0, visible: true }
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type FlickerReason = 'resize' | 'offscreen' | 'clear'
|
|
33
|
+
|
|
34
|
+
export type FrameEvent = {
|
|
35
|
+
durationMs: number
|
|
36
|
+
/** Phase breakdown in ms + patch count. Populated when the ink instance
|
|
37
|
+
* has frame-timing instrumentation enabled (via onFrame wiring). */
|
|
38
|
+
phases?: {
|
|
39
|
+
/** createRenderer output: DOM → yoga layout → screen buffer */
|
|
40
|
+
renderer: number
|
|
41
|
+
/** LogUpdate.render(): screen diff → Patch[] (the hot path this PR optimizes) */
|
|
42
|
+
diff: number
|
|
43
|
+
/** optimize(): patch merge/dedupe */
|
|
44
|
+
optimize: number
|
|
45
|
+
/** writeDiffToTerminal(): serialize patches → ANSI → stdout */
|
|
46
|
+
write: number
|
|
47
|
+
/** Pre-optimize patch count (proxy for how much changed this frame) */
|
|
48
|
+
patches: number
|
|
49
|
+
/** Post-optimize patch count. */
|
|
50
|
+
optimizedPatches: number
|
|
51
|
+
/** Bytes written to stdout this frame. */
|
|
52
|
+
writeBytes: number
|
|
53
|
+
/** Whether stdout.write returned false. */
|
|
54
|
+
backpressure: boolean
|
|
55
|
+
/** Previous stdout.write callback latency; 0 if drained before next frame. */
|
|
56
|
+
prevFrameDrainMs: number
|
|
57
|
+
/** yoga calculateLayout() time (runs in resetAfterCommit, before onRender) */
|
|
58
|
+
yoga: number
|
|
59
|
+
/** React reconcile time: scrollMutated → resetAfterCommit. 0 if no commit. */
|
|
60
|
+
commit: number
|
|
61
|
+
/** layoutNode() calls this frame (recursive, includes cache-hit returns) */
|
|
62
|
+
yogaVisited: number
|
|
63
|
+
/** measureFunc (text wrap/width) calls — the expensive part */
|
|
64
|
+
yogaMeasured: number
|
|
65
|
+
/** early returns via _hasL single-slot cache */
|
|
66
|
+
yogaCacheHits: number
|
|
67
|
+
/** total yoga Node instances alive (create - free). Growth = leak. */
|
|
68
|
+
yogaLive: number
|
|
69
|
+
}
|
|
70
|
+
flickers: Array<{
|
|
71
|
+
desiredHeight: number
|
|
72
|
+
availableHeight: number
|
|
73
|
+
reason: FlickerReason
|
|
74
|
+
}>
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export type Patch =
|
|
78
|
+
| { type: 'stdout'; content: string }
|
|
79
|
+
| { type: 'clear'; count: number }
|
|
80
|
+
| {
|
|
81
|
+
type: 'clearTerminal'
|
|
82
|
+
reason: FlickerReason
|
|
83
|
+
// Populated by log-update when a scrollback diff triggers the reset.
|
|
84
|
+
debug?: { triggerY: number; prevLine: string; nextLine: string }
|
|
85
|
+
}
|
|
86
|
+
| { type: 'cursorHide' }
|
|
87
|
+
| { type: 'cursorShow' }
|
|
88
|
+
| { type: 'cursorMove'; x: number; y: number }
|
|
89
|
+
| { type: 'cursorTo'; col: number }
|
|
90
|
+
| { type: 'carriageReturn' }
|
|
91
|
+
| { type: 'hyperlink'; uri: string }
|
|
92
|
+
// Pre-serialized style transition string from StylePool.transition() —
|
|
93
|
+
// cached by (fromId, toId), zero allocations after warmup.
|
|
94
|
+
| { type: 'styleStr'; str: string }
|
|
95
|
+
|
|
96
|
+
export type Diff = Patch[]
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Determines whether the screen should be cleared based on the current and previous frame.
|
|
100
|
+
* Returns the reason for clearing, or undefined if no clear is needed.
|
|
101
|
+
*
|
|
102
|
+
* Screen clearing is triggered when:
|
|
103
|
+
* 1. Terminal has been resized (viewport dimensions changed) → 'resize'
|
|
104
|
+
* 2. Current frame screen height exceeds available terminal rows → 'offscreen'
|
|
105
|
+
* 3. Previous frame screen height exceeded available terminal rows → 'offscreen'
|
|
106
|
+
*/
|
|
107
|
+
export function shouldClearScreen(prevFrame: Frame, frame: Frame): FlickerReason | undefined {
|
|
108
|
+
const didResize =
|
|
109
|
+
frame.viewport.height !== prevFrame.viewport.height || frame.viewport.width !== prevFrame.viewport.width
|
|
110
|
+
|
|
111
|
+
if (didResize) {
|
|
112
|
+
return 'resize'
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const currentFrameOverflows = frame.screen.height >= frame.viewport.height
|
|
116
|
+
|
|
117
|
+
const previousFrameOverflowed = prevFrame.screen.height >= prevFrame.viewport.height
|
|
118
|
+
|
|
119
|
+
if (currentFrameOverflows || previousFrameOverflowed) {
|
|
120
|
+
return 'offscreen'
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return undefined
|
|
124
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { LayoutEdge, type LayoutNode } from './layout/node.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Returns the yoga node's content width (computed width minus padding and
|
|
5
|
+
* border).
|
|
6
|
+
*
|
|
7
|
+
* Warning: can return a value WIDER than the parent container. In a
|
|
8
|
+
* column-direction flex parent, width is the cross axis — align-items:
|
|
9
|
+
* stretch never shrinks children below their intrinsic size, so the text
|
|
10
|
+
* node overflows (standard CSS behavior). Yoga measures leaf nodes in two
|
|
11
|
+
* passes: the AtMost pass determines width, the Exactly pass determines
|
|
12
|
+
* height. getComputedWidth() reflects the wider AtMost result while
|
|
13
|
+
* getComputedHeight() reflects the narrower Exactly result. Callers that
|
|
14
|
+
* use this for wrapping should clamp to actual available screen space so
|
|
15
|
+
* the rendered line count stays consistent with the layout height.
|
|
16
|
+
*/
|
|
17
|
+
const getMaxWidth = (yogaNode: LayoutNode): number => {
|
|
18
|
+
return (
|
|
19
|
+
yogaNode.getComputedWidth() -
|
|
20
|
+
yogaNode.getComputedPadding(LayoutEdge.Left) -
|
|
21
|
+
yogaNode.getComputedPadding(LayoutEdge.Right) -
|
|
22
|
+
yogaNode.getComputedBorder(LayoutEdge.Left) -
|
|
23
|
+
yogaNode.getComputedBorder(LayoutEdge.Right)
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default getMaxWidth
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { appendChildNode, createNode } from './dom.js'
|
|
4
|
+
import { dispatchClick, hitTest } from './hit-test.js'
|
|
5
|
+
import { nodeCache } from './node-cache.js'
|
|
6
|
+
|
|
7
|
+
const rect = (node: ReturnType<typeof createNode>, x: number, y: number, width: number, height: number) => {
|
|
8
|
+
nodeCache.set(node, { x, y, width, height })
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
describe('hit-test', () => {
|
|
12
|
+
it('hits absolutely positioned children that paint outside their parent rect', () => {
|
|
13
|
+
const root = createNode('ink-root')
|
|
14
|
+
const parent = createNode('ink-box')
|
|
15
|
+
const wrapper = createNode('ink-box')
|
|
16
|
+
const overlay = createNode('ink-box')
|
|
17
|
+
const row = createNode('ink-box')
|
|
18
|
+
const seen: string[] = []
|
|
19
|
+
|
|
20
|
+
appendChildNode(root, parent)
|
|
21
|
+
appendChildNode(parent, wrapper)
|
|
22
|
+
appendChildNode(wrapper, overlay)
|
|
23
|
+
appendChildNode(overlay, row)
|
|
24
|
+
|
|
25
|
+
overlay.style.position = 'absolute'
|
|
26
|
+
row._eventHandlers = { onClick: () => seen.push('row') }
|
|
27
|
+
|
|
28
|
+
rect(root, 0, 0, 120, 40)
|
|
29
|
+
rect(parent, 0, 30, 120, 1)
|
|
30
|
+
rect(wrapper, 0, 30, 120, 1)
|
|
31
|
+
rect(overlay, 0, 20, 96, 6)
|
|
32
|
+
rect(row, 1, 22, 80, 1)
|
|
33
|
+
|
|
34
|
+
expect(hitTest(root, 2, 22)).toBe(row)
|
|
35
|
+
expect(dispatchClick(root, 2, 22)).toBe(true)
|
|
36
|
+
expect(seen).toEqual(['row'])
|
|
37
|
+
})
|
|
38
|
+
})
|