@effect-tui/react 0.1.1 → 0.1.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.
- package/dist/jsx-runtime.d.ts +13 -0
- package/dist/jsx-runtime.d.ts.map +1 -1
- package/dist/jsx-runtime.js.map +1 -1
- package/dist/src/codeblock.d.ts.map +1 -1
- package/dist/src/codeblock.js.map +1 -1
- package/dist/src/components/Divider.d.ts +18 -0
- package/dist/src/components/Divider.d.ts.map +1 -0
- package/dist/src/components/Divider.js +17 -0
- package/dist/src/components/Divider.js.map +1 -0
- package/dist/src/components/Markdown.d.ts +66 -0
- package/dist/src/components/Markdown.d.ts.map +1 -0
- package/dist/src/components/Markdown.js +226 -0
- package/dist/src/components/Markdown.js.map +1 -0
- package/dist/src/components/MultilineTextInput.d.ts +65 -0
- package/dist/src/components/MultilineTextInput.d.ts.map +1 -0
- package/dist/src/components/MultilineTextInput.js +607 -0
- package/dist/src/components/MultilineTextInput.js.map +1 -0
- package/dist/src/components/Overlay.d.ts +46 -0
- package/dist/src/components/Overlay.d.ts.map +1 -0
- package/dist/src/components/Overlay.js +11 -0
- package/dist/src/components/Overlay.js.map +1 -0
- package/dist/src/components/Static.d.ts +44 -0
- package/dist/src/components/Static.d.ts.map +1 -0
- package/dist/src/components/Static.js +53 -0
- package/dist/src/components/Static.js.map +1 -0
- package/dist/src/components/TextInput.d.ts +53 -0
- package/dist/src/components/TextInput.d.ts.map +1 -0
- package/dist/src/components/TextInput.js +210 -0
- package/dist/src/components/TextInput.js.map +1 -0
- package/dist/src/components/index.d.ts +7 -0
- package/dist/src/components/index.d.ts.map +1 -0
- package/dist/src/components/index.js +7 -0
- package/dist/src/components/index.js.map +1 -0
- package/dist/src/components/text-editing.d.ts +62 -0
- package/dist/src/components/text-editing.d.ts.map +1 -0
- package/dist/src/components/text-editing.js +385 -0
- package/dist/src/components/text-editing.js.map +1 -0
- package/dist/src/console/ConsoleCapture.d.ts +36 -0
- package/dist/src/console/ConsoleCapture.d.ts.map +1 -0
- package/dist/src/console/ConsoleCapture.js +210 -0
- package/dist/src/console/ConsoleCapture.js.map +1 -0
- package/dist/src/console/ConsolePopover.d.ts +18 -0
- package/dist/src/console/ConsolePopover.d.ts.map +1 -0
- package/dist/src/console/ConsolePopover.js +324 -0
- package/dist/src/console/ConsolePopover.js.map +1 -0
- package/dist/src/console/clipboard.d.ts +10 -0
- package/dist/src/console/clipboard.d.ts.map +1 -0
- package/dist/src/console/clipboard.js +74 -0
- package/dist/src/console/clipboard.js.map +1 -0
- package/dist/src/console/index.d.ts +5 -0
- package/dist/src/console/index.d.ts.map +1 -0
- package/dist/src/console/index.js +33 -0
- package/dist/src/console/index.js.map +1 -0
- package/dist/src/console/useConsole.d.ts +44 -0
- package/dist/src/console/useConsole.d.ts.map +1 -0
- package/dist/src/console/useConsole.js +91 -0
- package/dist/src/console/useConsole.js.map +1 -0
- package/dist/src/debug/DebugOverlay.d.ts +49 -0
- package/dist/src/debug/DebugOverlay.d.ts.map +1 -0
- package/dist/src/debug/DebugOverlay.js +438 -0
- package/dist/src/debug/DebugOverlay.js.map +1 -0
- package/dist/src/debug/DiagnosticsPanel.d.ts.map +1 -1
- package/dist/src/debug/DiagnosticsPanel.js.map +1 -1
- package/dist/src/dev/Toast.d.ts +19 -0
- package/dist/src/dev/Toast.d.ts.map +1 -0
- package/dist/src/dev/Toast.js +72 -0
- package/dist/src/dev/Toast.js.map +1 -0
- package/dist/src/dev/index.d.ts +2 -0
- package/dist/src/dev/index.d.ts.map +1 -0
- package/dist/src/dev/index.js +3 -0
- package/dist/src/dev/index.js.map +1 -0
- package/dist/src/dev.d.ts +114 -0
- package/dist/src/dev.d.ts.map +1 -0
- package/dist/src/dev.js +373 -0
- package/dist/src/dev.js.map +1 -0
- package/dist/src/highlight.d.ts +3 -3
- package/dist/src/highlight.d.ts.map +1 -1
- package/dist/src/highlight.js.map +1 -1
- package/dist/src/hmr-plugin.d.ts +2 -0
- package/dist/src/hmr-plugin.d.ts.map +1 -0
- package/dist/src/hmr-plugin.js +53 -0
- package/dist/src/hmr-plugin.js.map +1 -0
- package/dist/src/hooks/index.d.ts +4 -0
- package/dist/src/hooks/index.d.ts.map +1 -1
- package/dist/src/hooks/index.js +2 -0
- package/dist/src/hooks/index.js.map +1 -1
- package/dist/src/hooks/use-keyboard.d.ts +11 -0
- package/dist/src/hooks/use-keyboard.d.ts.map +1 -1
- package/dist/src/hooks/use-keyboard.js +22 -4
- package/dist/src/hooks/use-keyboard.js.map +1 -1
- package/dist/src/hooks/use-mouse.d.ts +24 -0
- package/dist/src/hooks/use-mouse.d.ts.map +1 -0
- package/dist/src/hooks/use-mouse.js +41 -0
- package/dist/src/hooks/use-mouse.js.map +1 -0
- package/dist/src/hooks/use-paste.d.ts +11 -0
- package/dist/src/hooks/use-paste.d.ts.map +1 -1
- package/dist/src/hooks/use-paste.js +17 -3
- package/dist/src/hooks/use-paste.js.map +1 -1
- package/dist/src/hooks/use-scroll.d.ts +79 -0
- package/dist/src/hooks/use-scroll.d.ts.map +1 -0
- package/dist/src/hooks/use-scroll.js +239 -0
- package/dist/src/hooks/use-scroll.js.map +1 -0
- package/dist/src/hooks/useFrameStats.js.map +1 -1
- package/dist/src/hosts/base.d.ts +62 -1
- package/dist/src/hosts/base.d.ts.map +1 -1
- package/dist/src/hosts/base.js +118 -5
- package/dist/src/hosts/base.js.map +1 -1
- package/dist/src/hosts/box.d.ts +7 -7
- package/dist/src/hosts/box.d.ts.map +1 -1
- package/dist/src/hosts/box.js +31 -26
- package/dist/src/hosts/box.js.map +1 -1
- package/dist/src/hosts/canvas.d.ts +8 -8
- package/dist/src/hosts/canvas.d.ts.map +1 -1
- package/dist/src/hosts/canvas.js +13 -22
- package/dist/src/hosts/canvas.js.map +1 -1
- package/dist/src/hosts/codeblock.d.ts +7 -7
- package/dist/src/hosts/codeblock.d.ts.map +1 -1
- package/dist/src/hosts/codeblock.js +11 -20
- package/dist/src/hosts/codeblock.js.map +1 -1
- package/dist/src/hosts/flex-container.d.ts +45 -0
- package/dist/src/hosts/flex-container.d.ts.map +1 -0
- package/dist/src/hosts/flex-container.js +90 -0
- package/dist/src/hosts/flex-container.js.map +1 -0
- package/dist/src/hosts/hstack.d.ts +6 -11
- package/dist/src/hosts/hstack.d.ts.map +1 -1
- package/dist/src/hosts/hstack.js +6 -41
- package/dist/src/hosts/hstack.js.map +1 -1
- package/dist/src/hosts/index.d.ts +4 -0
- package/dist/src/hosts/index.d.ts.map +1 -1
- package/dist/src/hosts/index.js +10 -0
- package/dist/src/hosts/index.js.map +1 -1
- package/dist/src/hosts/overlay-item.d.ts +32 -0
- package/dist/src/hosts/overlay-item.d.ts.map +1 -0
- package/dist/src/hosts/overlay-item.js +54 -0
- package/dist/src/hosts/overlay-item.js.map +1 -0
- package/dist/src/hosts/overlay.d.ts +30 -0
- package/dist/src/hosts/overlay.d.ts.map +1 -0
- package/dist/src/hosts/overlay.js +105 -0
- package/dist/src/hosts/overlay.js.map +1 -0
- package/dist/src/hosts/scroll.d.ts +56 -0
- package/dist/src/hosts/scroll.d.ts.map +1 -0
- package/dist/src/hosts/scroll.js +204 -0
- package/dist/src/hosts/scroll.js.map +1 -0
- package/dist/src/hosts/single-child.d.ts +16 -0
- package/dist/src/hosts/single-child.d.ts.map +1 -0
- package/dist/src/hosts/single-child.js +45 -0
- package/dist/src/hosts/single-child.js.map +1 -0
- package/dist/src/hosts/spacer.d.ts.map +1 -1
- package/dist/src/hosts/spacer.js +7 -3
- package/dist/src/hosts/spacer.js.map +1 -1
- package/dist/src/hosts/text.d.ts +9 -6
- package/dist/src/hosts/text.d.ts.map +1 -1
- package/dist/src/hosts/text.js +49 -22
- package/dist/src/hosts/text.js.map +1 -1
- package/dist/src/hosts/vstack.d.ts +6 -11
- package/dist/src/hosts/vstack.d.ts.map +1 -1
- package/dist/src/hosts/vstack.js +6 -41
- package/dist/src/hosts/vstack.js.map +1 -1
- package/dist/src/hosts/zstack.d.ts.map +1 -1
- package/dist/src/hosts/zstack.js +16 -5
- package/dist/src/hosts/zstack.js.map +1 -1
- package/dist/src/index.d.ts +9 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +10 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/inline/index.d.ts.map +1 -1
- package/dist/src/inline/index.js.map +1 -1
- package/dist/src/motion/color-motion-value.d.ts.map +1 -1
- package/dist/src/motion/color-motion-value.js.map +1 -1
- package/dist/src/motion/color.d.ts +1 -29
- package/dist/src/motion/color.d.ts.map +1 -1
- package/dist/src/motion/color.js +2 -170
- package/dist/src/motion/color.js.map +1 -1
- package/dist/src/motion/color.test.js.map +1 -1
- package/dist/src/motion/event-emitter.d.ts.map +1 -1
- package/dist/src/motion/event-emitter.js.map +1 -1
- package/dist/src/motion/frame.js.map +1 -1
- package/dist/src/motion/hooks.d.ts.map +1 -1
- package/dist/src/motion/hooks.js +8 -3
- package/dist/src/motion/hooks.js.map +1 -1
- package/dist/src/motion/index.d.ts.map +1 -1
- package/dist/src/motion/index.js.map +1 -1
- package/dist/src/motion/motion-value.d.ts.map +1 -1
- package/dist/src/motion/motion-value.js.map +1 -1
- package/dist/src/motion/motion-value.test.js.map +1 -1
- package/dist/src/motion/spring-math.d.ts +6 -1
- package/dist/src/motion/spring-math.d.ts.map +1 -1
- package/dist/src/motion/spring-math.js +6 -1
- package/dist/src/motion/spring-math.js.map +1 -1
- package/dist/src/motion/types.d.ts.map +1 -1
- package/dist/src/motion/types.js.map +1 -1
- package/dist/src/profiler.js.map +1 -1
- package/dist/src/reconciler/host-config.d.ts +5 -5
- package/dist/src/reconciler/host-config.d.ts.map +1 -1
- package/dist/src/reconciler/host-config.js +43 -51
- package/dist/src/reconciler/host-config.js.map +1 -1
- package/dist/src/reconciler/noop-methods.d.ts +29 -0
- package/dist/src/reconciler/noop-methods.d.ts.map +1 -0
- package/dist/src/reconciler/noop-methods.js +43 -0
- package/dist/src/reconciler/noop-methods.js.map +1 -0
- package/dist/src/reconciler/types.d.ts +68 -14
- package/dist/src/reconciler/types.d.ts.map +1 -1
- package/dist/src/remote/Procedures.d.ts +22 -0
- package/dist/src/remote/Procedures.d.ts.map +1 -0
- package/dist/src/remote/Procedures.js +42 -0
- package/dist/src/remote/Procedures.js.map +1 -0
- package/dist/src/remote/Router.d.ts +20 -0
- package/dist/src/remote/Router.d.ts.map +1 -0
- package/dist/src/remote/Router.js +26 -0
- package/dist/src/remote/Router.js.map +1 -0
- package/dist/src/remote/Server.d.ts +6 -0
- package/dist/src/remote/Server.d.ts.map +1 -0
- package/dist/src/remote/Server.js +53 -0
- package/dist/src/remote/Server.js.map +1 -0
- package/dist/src/remote/index.d.ts +18 -0
- package/dist/src/remote/index.d.ts.map +1 -0
- package/dist/src/remote/index.js +74 -0
- package/dist/src/remote/index.js.map +1 -0
- package/dist/src/renderer/core/FrameBuilder.d.ts +18 -0
- package/dist/src/renderer/core/FrameBuilder.d.ts.map +1 -0
- package/dist/src/renderer/core/FrameBuilder.js +38 -0
- package/dist/src/renderer/core/FrameBuilder.js.map +1 -0
- package/dist/src/renderer/core/RendererState.d.ts +41 -0
- package/dist/src/renderer/core/RendererState.d.ts.map +1 -0
- package/dist/src/renderer/core/RendererState.js +70 -0
- package/dist/src/renderer/core/RendererState.js.map +1 -0
- package/dist/src/renderer/core/index.d.ts +3 -0
- package/dist/src/renderer/core/index.d.ts.map +1 -0
- package/dist/src/renderer/core/index.js +3 -0
- package/dist/src/renderer/core/index.js.map +1 -0
- package/dist/src/renderer/input/InputProcessor.d.ts +25 -0
- package/dist/src/renderer/input/InputProcessor.d.ts.map +1 -0
- package/dist/src/renderer/input/InputProcessor.js +81 -0
- package/dist/src/renderer/input/InputProcessor.js.map +1 -0
- package/dist/src/renderer/input/index.d.ts +2 -0
- package/dist/src/renderer/input/index.d.ts.map +1 -0
- package/dist/src/renderer/input/index.js +2 -0
- package/dist/src/renderer/input/index.js.map +1 -0
- package/dist/src/renderer/lifecycle/EventBus.d.ts +41 -0
- package/dist/src/renderer/lifecycle/EventBus.d.ts.map +1 -0
- package/dist/src/renderer/lifecycle/EventBus.js +78 -0
- package/dist/src/renderer/lifecycle/EventBus.js.map +1 -0
- package/dist/src/renderer/lifecycle/ResizeManager.d.ts +34 -0
- package/dist/src/renderer/lifecycle/ResizeManager.d.ts.map +1 -0
- package/dist/src/renderer/lifecycle/ResizeManager.js +47 -0
- package/dist/src/renderer/lifecycle/ResizeManager.js.map +1 -0
- package/dist/src/renderer/lifecycle/TerminalSetup.d.ts +36 -0
- package/dist/src/renderer/lifecycle/TerminalSetup.d.ts.map +1 -0
- package/dist/src/renderer/lifecycle/TerminalSetup.js +82 -0
- package/dist/src/renderer/lifecycle/TerminalSetup.js.map +1 -0
- package/dist/src/renderer/lifecycle/index.d.ts +4 -0
- package/dist/src/renderer/lifecycle/index.d.ts.map +1 -0
- package/dist/src/renderer/lifecycle/index.js +4 -0
- package/dist/src/renderer/lifecycle/index.js.map +1 -0
- package/dist/src/renderer/modes/FullscreenRenderer.d.ts +12 -0
- package/dist/src/renderer/modes/FullscreenRenderer.d.ts.map +1 -0
- package/dist/src/renderer/modes/FullscreenRenderer.js +52 -0
- package/dist/src/renderer/modes/FullscreenRenderer.js.map +1 -0
- package/dist/src/renderer/modes/InlineRenderer.d.ts +22 -0
- package/dist/src/renderer/modes/InlineRenderer.d.ts.map +1 -0
- package/dist/src/renderer/modes/InlineRenderer.js +154 -0
- package/dist/src/renderer/modes/InlineRenderer.js.map +1 -0
- package/dist/src/renderer/modes/RendererMode.d.ts +42 -0
- package/dist/src/renderer/modes/RendererMode.d.ts.map +1 -0
- package/dist/src/renderer/modes/RendererMode.js +2 -0
- package/dist/src/renderer/modes/RendererMode.js.map +1 -0
- package/dist/src/renderer/modes/StaticContentRenderer.d.ts +25 -0
- package/dist/src/renderer/modes/StaticContentRenderer.d.ts.map +1 -0
- package/dist/src/renderer/modes/StaticContentRenderer.js +47 -0
- package/dist/src/renderer/modes/StaticContentRenderer.js.map +1 -0
- package/dist/src/renderer/modes/index.d.ts +5 -0
- package/dist/src/renderer/modes/index.d.ts.map +1 -0
- package/dist/src/renderer/modes/index.js +4 -0
- package/dist/src/renderer/modes/index.js.map +1 -0
- package/dist/src/renderer-context.d.ts +9 -0
- package/dist/src/renderer-context.d.ts.map +1 -0
- package/dist/src/renderer-context.js +22 -0
- package/dist/src/renderer-context.js.map +1 -0
- package/dist/src/renderer-types.d.ts +103 -0
- package/dist/src/renderer-types.d.ts.map +1 -0
- package/dist/src/renderer-types.js +2 -0
- package/dist/src/renderer-types.js.map +1 -0
- package/dist/src/renderer.d.ts +4 -86
- package/dist/src/renderer.d.ts.map +1 -1
- package/dist/src/renderer.js +213 -384
- package/dist/src/renderer.js.map +1 -1
- package/dist/src/test/index.d.ts.map +1 -1
- package/dist/src/test/index.js.map +1 -1
- package/dist/src/test/mock-streams.d.ts.map +1 -1
- package/dist/src/test/mock-streams.js.map +1 -1
- package/dist/src/test/render-tui.d.ts.map +1 -1
- package/dist/src/test/render-tui.js +2 -5
- package/dist/src/test/render-tui.js.map +1 -1
- package/dist/src/trace/SpanTree.d.ts.map +1 -1
- package/dist/src/trace/SpanTree.js +21 -11
- package/dist/src/trace/SpanTree.js.map +1 -1
- package/dist/src/trace/format-value.d.ts +15 -0
- package/dist/src/trace/format-value.d.ts.map +1 -0
- package/dist/src/trace/format-value.js +77 -0
- package/dist/src/trace/format-value.js.map +1 -0
- package/dist/src/trace/index.d.ts.map +1 -1
- package/dist/src/trace/index.js.map +1 -1
- package/dist/src/trace/location.js +1 -1
- package/dist/src/trace/location.js.map +1 -1
- package/dist/src/trace/span-processor.d.ts.map +1 -1
- package/dist/src/trace/span-processor.js.map +1 -1
- package/dist/src/trace/span-state.d.ts +19 -2
- package/dist/src/trace/span-state.d.ts.map +1 -1
- package/dist/src/trace/span-state.js +62 -31
- package/dist/src/trace/span-state.js.map +1 -1
- package/dist/src/trace/tui-logger.js.map +1 -1
- package/dist/src/utils/border.d.ts +1 -1
- package/dist/src/utils/border.d.ts.map +1 -1
- package/dist/src/utils/border.js +6 -0
- package/dist/src/utils/border.js.map +1 -1
- package/dist/src/utils/flex-layout.d.ts +2 -1
- package/dist/src/utils/flex-layout.d.ts.map +1 -1
- package/dist/src/utils/flex-layout.js +22 -33
- package/dist/src/utils/flex-layout.js.map +1 -1
- package/dist/src/utils/index.d.ts +1 -1
- package/dist/src/utils/index.d.ts.map +1 -1
- package/dist/src/utils/index.js +1 -1
- package/dist/src/utils/index.js.map +1 -1
- package/dist/src/utils/padding.d.ts.map +1 -1
- package/dist/src/utils/padding.js.map +1 -1
- package/dist/src/utils/styles.d.ts +20 -1
- package/dist/src/utils/styles.d.ts.map +1 -1
- package/dist/src/utils/styles.js +36 -1
- package/dist/src/utils/styles.js.map +1 -1
- package/dist/src/visualize/index.d.ts +8 -19
- package/dist/src/visualize/index.d.ts.map +1 -1
- package/dist/src/visualize/index.js +11 -25
- package/dist/src/visualize/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/jsx-dev-runtime.ts +5 -0
- package/jsx-runtime.ts +54 -0
- package/package.json +124 -92
- package/src/codeblock.tsx +34 -34
- package/src/components/Divider.tsx +23 -0
- package/src/components/Markdown.tsx +380 -0
- package/src/components/MultilineTextInput.tsx +749 -0
- package/src/components/Overlay.tsx +56 -0
- package/src/components/Static.tsx +68 -0
- package/src/components/TextInput.tsx +285 -0
- package/src/components/index.ts +6 -0
- package/src/components/text-editing.ts +464 -0
- package/src/console/ConsoleCapture.ts +272 -0
- package/src/console/ConsolePopover.tsx +487 -0
- package/src/console/clipboard.ts +81 -0
- package/src/console/index.ts +42 -0
- package/src/console/useConsole.ts +129 -0
- package/src/debug/DebugOverlay.ts +557 -0
- package/src/debug/DiagnosticsPanel.tsx +27 -27
- package/src/dev/Toast.tsx +117 -0
- package/src/dev/index.ts +2 -0
- package/src/dev.tsx +489 -0
- package/src/highlight.ts +46 -46
- package/src/hmr-plugin.ts +61 -0
- package/src/hooks/index.ts +4 -0
- package/src/hooks/use-keyboard.ts +44 -24
- package/src/hooks/use-mouse.ts +51 -0
- package/src/hooks/use-paste.ts +21 -6
- package/src/hooks/use-scroll.ts +386 -0
- package/src/hooks/useFrameStats.ts +17 -17
- package/src/hosts/base.ts +180 -59
- package/src/hosts/box.ts +117 -96
- package/src/hosts/canvas.ts +137 -141
- package/src/hosts/codeblock.ts +117 -133
- package/src/hosts/flex-container.ts +124 -0
- package/src/hosts/hstack.ts +11 -59
- package/src/hosts/index.ts +24 -14
- package/src/hosts/overlay-item.ts +72 -0
- package/src/hosts/overlay.ts +125 -0
- package/src/hosts/scroll.ts +255 -0
- package/src/hosts/single-child.ts +52 -0
- package/src/hosts/spacer.ts +30 -26
- package/src/hosts/text.ts +198 -164
- package/src/hosts/vstack.ts +11 -59
- package/src/hosts/zstack.ts +79 -67
- package/src/index.ts +44 -19
- package/src/inline/index.tsx +123 -123
- package/src/motion/color-motion-value.ts +67 -67
- package/src/motion/color.test.ts +107 -107
- package/src/motion/color.ts +9 -190
- package/src/motion/event-emitter.ts +20 -20
- package/src/motion/frame.ts +35 -35
- package/src/motion/hooks.ts +144 -139
- package/src/motion/index.ts +10 -10
- package/src/motion/motion-value.test.ts +207 -207
- package/src/motion/motion-value.ts +112 -112
- package/src/motion/spring-math.ts +88 -83
- package/src/motion/types.ts +25 -25
- package/src/profiler.ts +50 -50
- package/src/reconciler/host-config.ts +152 -174
- package/src/reconciler/noop-methods.ts +55 -0
- package/src/reconciler/types.ts +112 -46
- package/src/remote/Procedures.ts +52 -0
- package/src/remote/Router.ts +58 -0
- package/src/remote/Server.ts +76 -0
- package/src/remote/index.ts +90 -0
- package/src/renderer/core/FrameBuilder.ts +49 -0
- package/src/renderer/core/RendererState.ts +80 -0
- package/src/renderer/core/index.ts +2 -0
- package/src/renderer/input/InputProcessor.ts +94 -0
- package/src/renderer/input/index.ts +1 -0
- package/src/renderer/lifecycle/EventBus.ts +90 -0
- package/src/renderer/lifecycle/ResizeManager.ts +65 -0
- package/src/renderer/lifecycle/TerminalSetup.ts +105 -0
- package/src/renderer/lifecycle/index.ts +3 -0
- package/src/renderer/modes/FullscreenRenderer.ts +53 -0
- package/src/renderer/modes/InlineRenderer.ts +178 -0
- package/src/renderer/modes/RendererMode.ts +46 -0
- package/src/renderer/modes/StaticContentRenderer.ts +56 -0
- package/src/renderer/modes/index.ts +4 -0
- package/src/renderer-context.ts +27 -0
- package/src/renderer-types.ts +109 -0
- package/src/renderer.ts +391 -642
- package/src/test/index.ts +5 -5
- package/src/test/mock-streams.ts +115 -115
- package/src/test/render-tui.ts +84 -87
- package/src/utils/border.ts +79 -73
- package/src/utils/flex-layout.ts +80 -93
- package/src/utils/index.ts +1 -1
- package/src/utils/padding.ts +27 -27
- package/src/utils/styles.ts +50 -7
- package/src/visualize/index.tsx +225 -240
- package/dist/src/output.d.ts +0 -47
- package/dist/src/output.d.ts.map +0 -1
- package/dist/src/output.js +0 -125
- package/dist/src/output.js.map +0 -1
- package/dist/src/terminal.d.ts +0 -37
- package/dist/src/terminal.d.ts.map +0 -1
- package/dist/src/terminal.js +0 -65
- package/dist/src/terminal.js.map +0 -1
- package/src/output.ts +0 -156
- package/src/terminal.ts +0 -67
- package/src/trace/SpanTree.tsx +0 -195
- package/src/trace/index.tsx +0 -205
- package/src/trace/location.ts +0 -90
- package/src/trace/span-processor.ts +0 -65
- package/src/trace/span-state.ts +0 -286
- package/src/trace/tui-logger.ts +0 -72
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// RPC handlers for remote session control
|
|
2
|
+
import type { Rpc } from "@effect/rpc"
|
|
3
|
+
import { Effect, Layer, Context } from "effect"
|
|
4
|
+
import type { KeyMsg } from "@effect-tui/core"
|
|
5
|
+
import { TuiRpcs } from "./Procedures.js"
|
|
6
|
+
|
|
7
|
+
// Service interface for the TUI session
|
|
8
|
+
export interface TuiSessionImpl {
|
|
9
|
+
readonly getScreenshot: () => string
|
|
10
|
+
readonly dispatchKey: (key: KeyMsg) => void
|
|
11
|
+
readonly dispatchPaste: (text: string) => void
|
|
12
|
+
readonly dispatchResize: (width: number, height: number) => void
|
|
13
|
+
readonly getInfo: () => { pid: number; width: number; height: number }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class TuiSession extends Context.Tag("TuiSession")<
|
|
17
|
+
TuiSession,
|
|
18
|
+
TuiSessionImpl
|
|
19
|
+
>() {}
|
|
20
|
+
|
|
21
|
+
// Create the RPC handlers layer
|
|
22
|
+
export const HandlersLive: Layer.Layer<
|
|
23
|
+
| Rpc.Handler<"Screenshot">
|
|
24
|
+
| Rpc.Handler<"SendKey">
|
|
25
|
+
| Rpc.Handler<"Paste">
|
|
26
|
+
| Rpc.Handler<"Resize">
|
|
27
|
+
| Rpc.Handler<"Info">,
|
|
28
|
+
never,
|
|
29
|
+
TuiSession
|
|
30
|
+
> = TuiRpcs.toLayer(
|
|
31
|
+
Effect.gen(function* () {
|
|
32
|
+
const session = yield* TuiSession
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
Screenshot: () => Effect.sync(() => session.getScreenshot()),
|
|
36
|
+
|
|
37
|
+
SendKey: ({ name, text, ctrl, shift, meta }) =>
|
|
38
|
+
Effect.sync(() => {
|
|
39
|
+
const key: KeyMsg = {
|
|
40
|
+
type: "key",
|
|
41
|
+
name: name as KeyMsg["name"],
|
|
42
|
+
text,
|
|
43
|
+
ctrl: ctrl ?? false,
|
|
44
|
+
shift: shift ?? false,
|
|
45
|
+
meta: meta ?? false,
|
|
46
|
+
}
|
|
47
|
+
session.dispatchKey(key)
|
|
48
|
+
}),
|
|
49
|
+
|
|
50
|
+
Paste: ({ text }) => Effect.sync(() => session.dispatchPaste(text)),
|
|
51
|
+
|
|
52
|
+
Resize: ({ width, height }) =>
|
|
53
|
+
Effect.sync(() => session.dispatchResize(width, height)),
|
|
54
|
+
|
|
55
|
+
Info: () => Effect.sync(() => session.getInfo()),
|
|
56
|
+
}
|
|
57
|
+
}),
|
|
58
|
+
)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Remote server that exposes TUI session via Unix socket
|
|
2
|
+
import { Effect, Layer } from "effect"
|
|
3
|
+
import { RpcSerialization, RpcServer } from "@effect/rpc"
|
|
4
|
+
import { BunSocketServer } from "@effect/platform-bun"
|
|
5
|
+
import * as fs from "node:fs"
|
|
6
|
+
import * as path from "node:path"
|
|
7
|
+
import { TuiRpcs } from "./Procedures.js"
|
|
8
|
+
import { HandlersLive, TuiSession, type TuiSessionImpl } from "./Router.js"
|
|
9
|
+
|
|
10
|
+
// Default socket directory
|
|
11
|
+
const SOCKET_DIR = "/tmp/effect-tui-sessions"
|
|
12
|
+
|
|
13
|
+
// Ensure socket directory exists
|
|
14
|
+
const ensureSocketDir = Effect.sync(() => {
|
|
15
|
+
if (!fs.existsSync(SOCKET_DIR)) {
|
|
16
|
+
fs.mkdirSync(SOCKET_DIR, { recursive: true })
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
// Get socket path for current process
|
|
21
|
+
export const getSocketPath = (pid?: number) =>
|
|
22
|
+
path.join(SOCKET_DIR, `${pid ?? process.pid}.sock`)
|
|
23
|
+
|
|
24
|
+
// Clean up socket file
|
|
25
|
+
const cleanupSocket = (socketPath: string) =>
|
|
26
|
+
Effect.sync(() => {
|
|
27
|
+
try {
|
|
28
|
+
if (fs.existsSync(socketPath)) {
|
|
29
|
+
fs.unlinkSync(socketPath)
|
|
30
|
+
}
|
|
31
|
+
} catch {
|
|
32
|
+
// Ignore cleanup errors
|
|
33
|
+
}
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
// Create the server layer
|
|
37
|
+
export const makeServerLayer = (
|
|
38
|
+
sessionImpl: TuiSessionImpl,
|
|
39
|
+
socketPath?: string,
|
|
40
|
+
) => {
|
|
41
|
+
const actualPath = socketPath ?? getSocketPath()
|
|
42
|
+
|
|
43
|
+
// Setup layer - creates directory, cleans stale socket
|
|
44
|
+
const SetupLive = Layer.scopedDiscard(
|
|
45
|
+
Effect.gen(function* () {
|
|
46
|
+
yield* ensureSocketDir
|
|
47
|
+
yield* cleanupSocket(actualPath)
|
|
48
|
+
yield* Effect.addFinalizer(() => cleanupSocket(actualPath))
|
|
49
|
+
// Use console.log so it gets captured by the debug console panel
|
|
50
|
+
console.log(`[remote] Listening on ${actualPath}`)
|
|
51
|
+
}),
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
// RPC handlers layer (needs TuiSession)
|
|
55
|
+
const HandlersLayer = HandlersLive.pipe(
|
|
56
|
+
Layer.provide(Layer.succeed(TuiSession, sessionImpl)),
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
// Full RPC server stack:
|
|
60
|
+
// 1. RpcServer.layer creates the RPC server, needs handlers
|
|
61
|
+
// 2. Handlers provide the implementation
|
|
62
|
+
// 3. Protocol layer provides socket protocol
|
|
63
|
+
// 4. Socket server provides the actual socket
|
|
64
|
+
const RpcLive = RpcServer.layer(TuiRpcs).pipe(
|
|
65
|
+
Layer.provide(HandlersLayer),
|
|
66
|
+
Layer.provideMerge(RpcServer.layerProtocolSocketServer),
|
|
67
|
+
Layer.provide(RpcSerialization.layerNdjson),
|
|
68
|
+
Layer.provide(
|
|
69
|
+
BunSocketServer.layer({
|
|
70
|
+
path: actualPath,
|
|
71
|
+
}),
|
|
72
|
+
),
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
return Layer.merge(SetupLive, RpcLive)
|
|
76
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// Remote session control for effect-tui
|
|
2
|
+
//
|
|
3
|
+
// Allows external tools (like Claude Code) to connect to a running TUI session
|
|
4
|
+
// to send keypresses and get screenshots.
|
|
5
|
+
//
|
|
6
|
+
// Usage:
|
|
7
|
+
// 1. Run app with EFFECT_TUI_REMOTE=1 to enable remote control
|
|
8
|
+
// 2. Connect using etui CLI or raw socket at /tmp/effect-tui-sessions/<pid>.sock
|
|
9
|
+
|
|
10
|
+
export { TuiRpcs } from "./Procedures.js"
|
|
11
|
+
export { TuiSession, HandlersLive } from "./Router.js"
|
|
12
|
+
export { makeServerLayer, getSocketPath } from "./Server.js"
|
|
13
|
+
|
|
14
|
+
import { Effect, Exit, Layer, Scope } from "effect"
|
|
15
|
+
import * as fs from "node:fs"
|
|
16
|
+
import type { TuiRenderer } from "../renderer-types.js"
|
|
17
|
+
import type { TuiSessionImpl } from "./Router.js"
|
|
18
|
+
import { makeServerLayer, getSocketPath } from "./Server.js"
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Enable remote control for a TUI renderer.
|
|
22
|
+
* Starts an RPC server on a Unix socket at /tmp/effect-tui-sessions/<pid>.sock
|
|
23
|
+
*
|
|
24
|
+
* @param renderer - The TUI renderer to control
|
|
25
|
+
* @param socketPath - Optional custom socket path
|
|
26
|
+
* @returns A cleanup function to stop the server
|
|
27
|
+
*/
|
|
28
|
+
export function enableRemote(
|
|
29
|
+
renderer: TuiRenderer,
|
|
30
|
+
socketPath?: string,
|
|
31
|
+
): () => void {
|
|
32
|
+
const actualPath = socketPath ?? getSocketPath()
|
|
33
|
+
|
|
34
|
+
// Create session implementation from renderer
|
|
35
|
+
const session: TuiSessionImpl = {
|
|
36
|
+
getScreenshot: () => renderer.getScreenshot(),
|
|
37
|
+
dispatchKey: (key) => renderer.dispatchKey?.(key),
|
|
38
|
+
dispatchPaste: (text) => renderer.dispatchPaste?.(text),
|
|
39
|
+
dispatchResize: (width, height) => renderer.dispatchResize?.(width, height),
|
|
40
|
+
getInfo: () => ({
|
|
41
|
+
pid: process.pid,
|
|
42
|
+
width: renderer.width,
|
|
43
|
+
height: renderer.height,
|
|
44
|
+
}),
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Build and run the server layer
|
|
48
|
+
const serverLayer = makeServerLayer(session, actualPath)
|
|
49
|
+
|
|
50
|
+
// Use Effect runtime to manage the server lifecycle
|
|
51
|
+
let scope: Scope.CloseableScope | null = null
|
|
52
|
+
|
|
53
|
+
Effect.runPromise(
|
|
54
|
+
Effect.gen(function* () {
|
|
55
|
+
scope = yield* Scope.make()
|
|
56
|
+
yield* Layer.buildWithScope(serverLayer, scope)
|
|
57
|
+
}),
|
|
58
|
+
).catch((err) => {
|
|
59
|
+
console.error("[effect-tui] Remote server error:", err)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
// Ensure socket cleanup on process exit (Effect finalizers may not run on abrupt exit)
|
|
63
|
+
const cleanupSocket = () => {
|
|
64
|
+
try {
|
|
65
|
+
if (fs.existsSync(actualPath)) {
|
|
66
|
+
fs.unlinkSync(actualPath)
|
|
67
|
+
}
|
|
68
|
+
} catch {
|
|
69
|
+
// Ignore cleanup errors
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// "exit" event fires synchronously on any exit (normal, SIGINT, SIGTERM, etc.)
|
|
74
|
+
process.on("exit", cleanupSocket)
|
|
75
|
+
|
|
76
|
+
return () => {
|
|
77
|
+
process.off("exit", cleanupSocket)
|
|
78
|
+
cleanupSocket()
|
|
79
|
+
if (scope) {
|
|
80
|
+
Effect.runPromise(Scope.close(scope, Exit.void))
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Check if remote control should be enabled (via EFFECT_TUI_REMOTE=1 env var)
|
|
87
|
+
*/
|
|
88
|
+
export function shouldEnableRemote(): boolean {
|
|
89
|
+
return process.env.EFFECT_TUI_REMOTE === "1"
|
|
90
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { performance } from "node:perf_hooks"
|
|
2
|
+
import type { CellBuffer, Palette } from "@effect-tui/core"
|
|
3
|
+
import type { HostInstance } from "../../reconciler/types.js"
|
|
4
|
+
import * as Prof from "../../profiler.js"
|
|
5
|
+
|
|
6
|
+
export interface FrameTimings {
|
|
7
|
+
clear: number
|
|
8
|
+
layout: number
|
|
9
|
+
render: number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Handles the measure → layout → render pipeline for a single frame.
|
|
14
|
+
*/
|
|
15
|
+
export class FrameBuilder {
|
|
16
|
+
/**
|
|
17
|
+
* Execute the frame pipeline: clear buffer, measure, layout, and render.
|
|
18
|
+
* Returns timing information for each phase.
|
|
19
|
+
*/
|
|
20
|
+
build(root: HostInstance, buffer: CellBuffer, palette: Palette, width: number, height: number): FrameTimings {
|
|
21
|
+
// Clear buffer
|
|
22
|
+
let t = Prof.startPhase()
|
|
23
|
+
const clearStart = performance.now()
|
|
24
|
+
buffer.clear(0)
|
|
25
|
+
const clearMs = performance.now() - clearStart
|
|
26
|
+
Prof.endPhase("clear", t)
|
|
27
|
+
|
|
28
|
+
// Layout (measure + position)
|
|
29
|
+
t = Prof.startPhase()
|
|
30
|
+
const layoutStart = performance.now()
|
|
31
|
+
root.measure(width, height)
|
|
32
|
+
root.layout({ x: 0, y: 0, w: width, h: height })
|
|
33
|
+
const layoutMs = performance.now() - layoutStart
|
|
34
|
+
Prof.endPhase("layout", t)
|
|
35
|
+
|
|
36
|
+
// Render
|
|
37
|
+
t = Prof.startPhase()
|
|
38
|
+
const renderStart = performance.now()
|
|
39
|
+
root.render(buffer, palette)
|
|
40
|
+
const renderMs = performance.now() - renderStart
|
|
41
|
+
Prof.endPhase("render", t)
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
clear: clearMs,
|
|
45
|
+
layout: layoutMs,
|
|
46
|
+
render: renderMs,
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { CellBuffer, Palette } from "@effect-tui/core"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Mutable state for the renderer.
|
|
5
|
+
* Centralized to make state management explicit and easier to track.
|
|
6
|
+
*/
|
|
7
|
+
export class RendererState {
|
|
8
|
+
// Dimensions
|
|
9
|
+
width: number
|
|
10
|
+
height: number
|
|
11
|
+
lastWidth: number
|
|
12
|
+
|
|
13
|
+
// Rendering flags
|
|
14
|
+
dirty = true
|
|
15
|
+
running = true
|
|
16
|
+
|
|
17
|
+
// Buffers (double-buffered for diffing)
|
|
18
|
+
prevBuffer: CellBuffer | null = null
|
|
19
|
+
nextBuffer: CellBuffer | null = null
|
|
20
|
+
readonly palette = new Palette()
|
|
21
|
+
|
|
22
|
+
// Loop handle
|
|
23
|
+
loop: ReturnType<typeof setInterval> | null = null
|
|
24
|
+
|
|
25
|
+
// Event handler references for cleanup
|
|
26
|
+
inputHandler: ((data: Buffer) => void) | null = null
|
|
27
|
+
resizeHandler: (() => void) | null = null
|
|
28
|
+
|
|
29
|
+
constructor(width: number, height: number) {
|
|
30
|
+
this.width = width
|
|
31
|
+
this.height = height
|
|
32
|
+
this.lastWidth = width
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Ensure buffers exist and are correctly sized.
|
|
37
|
+
* Call this at the start of each frame.
|
|
38
|
+
*/
|
|
39
|
+
ensureBuffers(width: number, height: number): void {
|
|
40
|
+
if (!this.prevBuffer || !this.nextBuffer || this.prevBuffer.w !== width || this.prevBuffer.h !== height) {
|
|
41
|
+
this.prevBuffer = new CellBuffer(width, height)
|
|
42
|
+
this.nextBuffer = new CellBuffer(width, height)
|
|
43
|
+
this.prevBuffer.clear(0)
|
|
44
|
+
this.nextBuffer.clear(0)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Swap prev and next buffers after rendering.
|
|
50
|
+
*/
|
|
51
|
+
swapBuffers(): void {
|
|
52
|
+
const tmp = this.prevBuffer
|
|
53
|
+
this.prevBuffer = this.nextBuffer
|
|
54
|
+
this.nextBuffer = tmp
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Invalidate buffers (e.g., on resize).
|
|
59
|
+
*/
|
|
60
|
+
invalidateBuffers(): void {
|
|
61
|
+
this.prevBuffer = null
|
|
62
|
+
this.nextBuffer = null
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Mark as needing render.
|
|
67
|
+
*/
|
|
68
|
+
markDirty(): void {
|
|
69
|
+
this.dirty = true
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Update dimensions.
|
|
74
|
+
*/
|
|
75
|
+
updateDimensions(width: number, height: number): void {
|
|
76
|
+
this.width = width
|
|
77
|
+
this.height = height
|
|
78
|
+
this.lastWidth = width
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { decodeInput, ANSI, type KeyMsg, type MouseMsg } from "@effect-tui/core"
|
|
2
|
+
|
|
3
|
+
export interface InputProcessorConfig {
|
|
4
|
+
exitOnCtrlC: boolean
|
|
5
|
+
dispatchKey: (key: KeyMsg) => boolean // Returns true if event was handled (preventDefault called)
|
|
6
|
+
dispatchMouse: (mouse: MouseMsg) => void
|
|
7
|
+
dispatchPaste: (text: string) => void
|
|
8
|
+
flushSync: <T>(fn: () => T) => T
|
|
9
|
+
onInputProcessed: () => void
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Processes raw terminal input, handling keyboard, mouse, and bracketed paste.
|
|
14
|
+
*/
|
|
15
|
+
export class InputProcessor {
|
|
16
|
+
private pasteActive = false
|
|
17
|
+
private pasteBuffer = ""
|
|
18
|
+
|
|
19
|
+
constructor(private config: InputProcessorConfig) {}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Process incoming data from stdin.
|
|
23
|
+
* Handles bracketed paste detection, key/mouse event decoding, and dispatch.
|
|
24
|
+
*/
|
|
25
|
+
process(data: Buffer): void {
|
|
26
|
+
let chunk = data.toString("utf8")
|
|
27
|
+
|
|
28
|
+
while (chunk.length > 0) {
|
|
29
|
+
if (this.pasteActive) {
|
|
30
|
+
const endIdx = chunk.indexOf(ANSI.paste.endMarker)
|
|
31
|
+
if (endIdx >= 0) {
|
|
32
|
+
this.pasteBuffer += chunk.slice(0, endIdx)
|
|
33
|
+
this.config.dispatchPaste(this.pasteBuffer)
|
|
34
|
+
this.pasteBuffer = ""
|
|
35
|
+
this.pasteActive = false
|
|
36
|
+
chunk = chunk.slice(endIdx + ANSI.paste.endMarker.length)
|
|
37
|
+
continue
|
|
38
|
+
} else {
|
|
39
|
+
this.pasteBuffer += chunk
|
|
40
|
+
chunk = ""
|
|
41
|
+
break
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const startIdx = chunk.indexOf(ANSI.paste.startMarker)
|
|
46
|
+
if (startIdx >= 0) {
|
|
47
|
+
// Emit any input before the paste start
|
|
48
|
+
this.emitInput(chunk.slice(0, startIdx))
|
|
49
|
+
this.pasteActive = true
|
|
50
|
+
this.pasteBuffer = ""
|
|
51
|
+
chunk = chunk.slice(startIdx + ANSI.paste.startMarker.length)
|
|
52
|
+
continue
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// No paste markers; treat as normal input
|
|
56
|
+
this.emitInput(chunk)
|
|
57
|
+
chunk = ""
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Notify that input processing is complete
|
|
61
|
+
this.config.onInputProcessed()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private emitInput(str: string): void {
|
|
65
|
+
if (!str) return
|
|
66
|
+
const events = decodeInput(Buffer.from(str, "utf8"))
|
|
67
|
+
|
|
68
|
+
for (const event of events) {
|
|
69
|
+
if (event.type === "mouse") {
|
|
70
|
+
this.config.flushSync(() => {
|
|
71
|
+
this.config.dispatchMouse(event)
|
|
72
|
+
})
|
|
73
|
+
} else {
|
|
74
|
+
const wrapped: KeyMsg = {
|
|
75
|
+
...event,
|
|
76
|
+
defaultPrevented: false,
|
|
77
|
+
preventDefault() {
|
|
78
|
+
wrapped.defaultPrevented = true
|
|
79
|
+
},
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this.config.flushSync(() => {
|
|
83
|
+
this.config.dispatchKey(wrapped)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
// Default Ctrl+C handling - exit unless user called preventDefault()
|
|
87
|
+
// Only match Ctrl+C (not Ctrl+Shift+C which should be available for copy)
|
|
88
|
+
if (this.config.exitOnCtrlC && !wrapped.defaultPrevented && event.ctrl && !event.shift && event.text === "c") {
|
|
89
|
+
process.exit(0)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { InputProcessor, type InputProcessorConfig } from "./InputProcessor.js"
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { KeyMsg, MouseMsg } from "@effect-tui/core"
|
|
2
|
+
import type { FrameStats } from "../../renderer-types.js"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Centralized event subscription management for the renderer.
|
|
6
|
+
* Provides type-safe subscription methods with automatic cleanup.
|
|
7
|
+
*/
|
|
8
|
+
export class EventBus {
|
|
9
|
+
private keyHandlers = new Set<(key: KeyMsg) => void>()
|
|
10
|
+
private mouseHandlers = new Set<(mouse: MouseMsg) => void>()
|
|
11
|
+
private pasteHandlers = new Set<(text: string) => void>()
|
|
12
|
+
private resizeHandlers = new Set<(width: number, height: number) => void>()
|
|
13
|
+
private frameHandlers = new Set<(stats: FrameStats) => void>()
|
|
14
|
+
|
|
15
|
+
onKey(handler: (key: KeyMsg) => void): () => void {
|
|
16
|
+
this.keyHandlers.add(handler)
|
|
17
|
+
return () => this.keyHandlers.delete(handler)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
onMouse(handler: (mouse: MouseMsg) => void): () => void {
|
|
21
|
+
this.mouseHandlers.add(handler)
|
|
22
|
+
return () => this.mouseHandlers.delete(handler)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
onPaste(handler: (text: string) => void): () => void {
|
|
26
|
+
this.pasteHandlers.add(handler)
|
|
27
|
+
return () => this.pasteHandlers.delete(handler)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
onResize(handler: (width: number, height: number) => void): () => void {
|
|
31
|
+
this.resizeHandlers.add(handler)
|
|
32
|
+
return () => this.resizeHandlers.delete(handler)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
onFrameStats(handler: (stats: FrameStats) => void): () => void {
|
|
36
|
+
this.frameHandlers.add(handler)
|
|
37
|
+
return () => this.frameHandlers.delete(handler)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Dispatch a key event to all handlers.
|
|
42
|
+
* Stops early if preventDefault is called.
|
|
43
|
+
*/
|
|
44
|
+
dispatchKey(key: KeyMsg): void {
|
|
45
|
+
for (const handler of this.keyHandlers) {
|
|
46
|
+
if (key.defaultPrevented) break
|
|
47
|
+
handler(key)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Dispatch a mouse event to all handlers.
|
|
53
|
+
*/
|
|
54
|
+
dispatchMouse(mouse: MouseMsg): void {
|
|
55
|
+
for (const handler of this.mouseHandlers) {
|
|
56
|
+
handler(mouse)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Dispatch a paste event to all handlers.
|
|
62
|
+
*/
|
|
63
|
+
dispatchPaste(text: string): void {
|
|
64
|
+
for (const handler of this.pasteHandlers) {
|
|
65
|
+
handler(text)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Dispatch a resize event to all handlers.
|
|
71
|
+
*/
|
|
72
|
+
dispatchResize(width: number, height: number): void {
|
|
73
|
+
for (const handler of this.resizeHandlers) {
|
|
74
|
+
handler(width, height)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Dispatch frame stats to all handlers.
|
|
80
|
+
*/
|
|
81
|
+
dispatchFrame(stats: FrameStats): void {
|
|
82
|
+
for (const handler of this.frameHandlers) {
|
|
83
|
+
handler(stats)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
get hasFrameHandlers(): boolean {
|
|
88
|
+
return this.frameHandlers.size > 0
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { TuiWriteStream } from "../../renderer-types.js"
|
|
2
|
+
|
|
3
|
+
export interface ResizeState {
|
|
4
|
+
width: number
|
|
5
|
+
height: number
|
|
6
|
+
lastWidth: number
|
|
7
|
+
previousHeight: number // For inline mode
|
|
8
|
+
inlineClearHeight: number
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ResizeResult {
|
|
12
|
+
newWidth: number
|
|
13
|
+
newHeight: number
|
|
14
|
+
needsFullClear: boolean // Fullscreen mode
|
|
15
|
+
inlineClearHeight: number // Inline mode
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Handles terminal resize events and calculates necessary clear/redraw actions.
|
|
20
|
+
*/
|
|
21
|
+
export class ResizeManager {
|
|
22
|
+
constructor(
|
|
23
|
+
private stdout: TuiWriteStream,
|
|
24
|
+
private mode: "fullscreen" | "inline",
|
|
25
|
+
) {}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Process a resize event and determine what actions are needed.
|
|
29
|
+
*/
|
|
30
|
+
handleResize(currentState: ResizeState): ResizeResult {
|
|
31
|
+
const newWidth = this.stdout.columns || 80
|
|
32
|
+
const newHeight = this.stdout.rows || 24
|
|
33
|
+
|
|
34
|
+
let needsFullClear = false
|
|
35
|
+
let inlineClearHeight = currentState.inlineClearHeight
|
|
36
|
+
|
|
37
|
+
if (this.mode === "fullscreen") {
|
|
38
|
+
// Fullscreen: defer clear to renderFrame so it's written atomically with content
|
|
39
|
+
needsFullClear = true
|
|
40
|
+
} else if (newWidth !== currentState.lastWidth || newHeight !== currentState.height) {
|
|
41
|
+
// Inline: on dimension change, request clear on next render
|
|
42
|
+
const clearHeight = Math.max(currentState.previousHeight, currentState.height, newHeight)
|
|
43
|
+
if (clearHeight > inlineClearHeight) {
|
|
44
|
+
inlineClearHeight = clearHeight
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
newWidth,
|
|
50
|
+
newHeight,
|
|
51
|
+
needsFullClear,
|
|
52
|
+
inlineClearHeight,
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get current terminal dimensions.
|
|
58
|
+
*/
|
|
59
|
+
getDimensions(): { width: number; height: number } {
|
|
60
|
+
return {
|
|
61
|
+
width: this.stdout.columns || 80,
|
|
62
|
+
height: this.stdout.rows || 24,
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|