@effect-tui/react 0.1.3 → 0.1.5
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 +55 -0
- package/dist/src/components/TextInput.d.ts.map +1 -0
- package/dist/src/components/TextInput.js +277 -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 +30 -23
- package/dist/src/hosts/box.js.map +1 -1
- package/dist/src/hosts/canvas.d.ts +16 -8
- package/dist/src/hosts/canvas.d.ts.map +1 -1
- package/dist/src/hosts/canvas.js +27 -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 +25 -0
- package/dist/src/renderer/modes/InlineRenderer.d.ts.map +1 -0
- package/dist/src/renderer/modes/InlineRenderer.js +161 -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 +214 -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 +356 -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 -94
- package/src/hosts/canvas.ts +170 -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 +186 -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 +392 -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,129 @@
|
|
|
1
|
+
// useConsole hook - manages console visibility and toggle keybinding
|
|
2
|
+
// Uses ` (backtick) for toggle, ~ (tilde) for screenshot
|
|
3
|
+
// Auto-show on error
|
|
4
|
+
|
|
5
|
+
import { useState, useEffect, useCallback, useMemo } from "react"
|
|
6
|
+
import { getConsoleCapture, type LogEntry } from "./ConsoleCapture.js"
|
|
7
|
+
import { useKeyboard } from "../hooks/use-keyboard.js"
|
|
8
|
+
|
|
9
|
+
// ─────────────────────────────────────────────────────────────
|
|
10
|
+
// Types
|
|
11
|
+
// ─────────────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
export interface UseConsoleOptions {
|
|
14
|
+
/** Auto-show console on console.error (default: true) */
|
|
15
|
+
autoShowOnError?: boolean
|
|
16
|
+
/** Start with console visible (default: false) */
|
|
17
|
+
initiallyVisible?: boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface UseConsoleReturn {
|
|
21
|
+
/** Whether the console is currently visible */
|
|
22
|
+
visible: boolean
|
|
23
|
+
/** Set visibility directly */
|
|
24
|
+
setVisible: (visible: boolean) => void
|
|
25
|
+
/** Toggle visibility */
|
|
26
|
+
toggle: () => void
|
|
27
|
+
/** Current log entries */
|
|
28
|
+
entries: LogEntry[]
|
|
29
|
+
/** Clear all log entries */
|
|
30
|
+
clear: () => void
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ─────────────────────────────────────────────────────────────
|
|
34
|
+
// Hook
|
|
35
|
+
// ─────────────────────────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Hook for managing the debug console.
|
|
39
|
+
*
|
|
40
|
+
* Features:
|
|
41
|
+
* - ` (backtick) to toggle visibility
|
|
42
|
+
* - ~ (tilde) to take screenshot
|
|
43
|
+
* - Auto-show on console.error (configurable)
|
|
44
|
+
* - Access to log entries and clear function
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```tsx
|
|
48
|
+
* function App() {
|
|
49
|
+
* const { visible } = useConsole({ autoShowOnError: true })
|
|
50
|
+
*
|
|
51
|
+
* return (
|
|
52
|
+
* <zstack>
|
|
53
|
+
* <MainContent />
|
|
54
|
+
* {visible && <ConsolePopover position="bottom" />}
|
|
55
|
+
* </zstack>
|
|
56
|
+
* )
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export function useConsole(options: UseConsoleOptions = {}): UseConsoleReturn {
|
|
61
|
+
const { autoShowOnError = true, initiallyVisible = false } = options
|
|
62
|
+
|
|
63
|
+
const capture = useMemo(() => getConsoleCapture(), [])
|
|
64
|
+
|
|
65
|
+
const [visible, setVisible] = useState(initiallyVisible)
|
|
66
|
+
const [entries, setEntries] = useState<LogEntry[]>(() => capture.getEntries())
|
|
67
|
+
|
|
68
|
+
// Activate capture on mount
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
if (!capture.isActive) {
|
|
71
|
+
capture.activate()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return () => {
|
|
75
|
+
// Don't deactivate on unmount - other components may still use it
|
|
76
|
+
// The singleton handles cleanup on process exit
|
|
77
|
+
}
|
|
78
|
+
}, [capture])
|
|
79
|
+
|
|
80
|
+
// Subscribe to entries and errors
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
const handleEntry = (_entry: LogEntry) => {
|
|
83
|
+
setEntries(capture.getEntries())
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const handleError = (_entry: LogEntry) => {
|
|
87
|
+
if (autoShowOnError) {
|
|
88
|
+
setVisible(true)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
capture.on("entry", handleEntry)
|
|
93
|
+
capture.on("error", handleError)
|
|
94
|
+
|
|
95
|
+
return () => {
|
|
96
|
+
capture.off("entry", handleEntry)
|
|
97
|
+
capture.off("error", handleError)
|
|
98
|
+
}
|
|
99
|
+
}, [capture, autoShowOnError])
|
|
100
|
+
|
|
101
|
+
// Toggle function
|
|
102
|
+
const toggle = useCallback(() => {
|
|
103
|
+
setVisible((v) => !v)
|
|
104
|
+
}, [])
|
|
105
|
+
|
|
106
|
+
// Clear function
|
|
107
|
+
const clear = useCallback(() => {
|
|
108
|
+
capture.clear()
|
|
109
|
+
setEntries([])
|
|
110
|
+
}, [capture])
|
|
111
|
+
|
|
112
|
+
// Keyboard handler for ` toggle
|
|
113
|
+
// No useCallback needed - useKeyboard uses refs internally
|
|
114
|
+
useKeyboard((key) => {
|
|
115
|
+
// ` (backtick) - toggle console
|
|
116
|
+
if (key.name === "char" && key.text === "`") {
|
|
117
|
+
toggle()
|
|
118
|
+
key.preventDefault?.()
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
visible,
|
|
124
|
+
setVisible,
|
|
125
|
+
toggle,
|
|
126
|
+
entries,
|
|
127
|
+
clear,
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
// Integrated debug overlay for all TUI apps
|
|
2
|
+
// Provides console log viewer with Ctrl+Shift+D toggle and Ctrl+Shift+S screenshot
|
|
3
|
+
|
|
4
|
+
import type { CellBuffer, Palette, KeyMsg, MouseMsg } from "@effect-tui/core"
|
|
5
|
+
import { getConsoleCapture, type LogLevel } from "../console/ConsoleCapture.js"
|
|
6
|
+
import { copyToClipboardSync, copyToClipboard } from "../console/clipboard.js"
|
|
7
|
+
|
|
8
|
+
// ─────────────────────────────────────────────────────────────
|
|
9
|
+
// Types
|
|
10
|
+
// ─────────────────────────────────────────────────────────────
|
|
11
|
+
|
|
12
|
+
export interface DebugOverlayOptions {
|
|
13
|
+
/** Initial height as percentage of terminal (default: 30) */
|
|
14
|
+
heightPercent?: number
|
|
15
|
+
/** Minimum height percent (default: 10) */
|
|
16
|
+
minHeightPercent?: number
|
|
17
|
+
/** Maximum height percent (default: 80) */
|
|
18
|
+
maxHeightPercent?: number
|
|
19
|
+
/** Show file locations in log entries (default: true) */
|
|
20
|
+
showLocations?: boolean
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface SelectionPoint {
|
|
24
|
+
line: number
|
|
25
|
+
col: number
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// ─────────────────────────────────────────────────────────────
|
|
29
|
+
// Color constants (8-bit palette indices for performance)
|
|
30
|
+
// ─────────────────────────────────────────────────────────────
|
|
31
|
+
|
|
32
|
+
const TITLE_BG = 236 // gray(4)
|
|
33
|
+
const TITLE_FG = 15 // white
|
|
34
|
+
const CONTENT_BG = 234 // gray(2)
|
|
35
|
+
const SELECTION_BG_R = 60
|
|
36
|
+
const SELECTION_BG_G = 90
|
|
37
|
+
const SELECTION_BG_B = 140
|
|
38
|
+
|
|
39
|
+
const LOG_COLORS: Record<LogLevel, number> = {
|
|
40
|
+
LOG: 15, // white
|
|
41
|
+
INFO: 14, // cyan
|
|
42
|
+
WARN: 11, // yellow
|
|
43
|
+
ERROR: 9, // red
|
|
44
|
+
DEBUG: 250, // gray(12)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ─────────────────────────────────────────────────────────────
|
|
48
|
+
// Helpers
|
|
49
|
+
// ─────────────────────────────────────────────────────────────
|
|
50
|
+
|
|
51
|
+
function formatTimestamp(date: Date): string {
|
|
52
|
+
const h = date.getHours().toString().padStart(2, "0")
|
|
53
|
+
const m = date.getMinutes().toString().padStart(2, "0")
|
|
54
|
+
const s = date.getSeconds().toString().padStart(2, "0")
|
|
55
|
+
return `${h}:${m}:${s}`
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function formatLocation(loc?: { file: string; line: number }): string {
|
|
59
|
+
if (!loc) return ""
|
|
60
|
+
const parts = loc.file.split("/")
|
|
61
|
+
const filename = parts[parts.length - 1]
|
|
62
|
+
return `${filename}:${loc.line}`
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function wrapLine(text: string, maxWidth: number): string[] {
|
|
66
|
+
if (text.length <= maxWidth) return [text]
|
|
67
|
+
|
|
68
|
+
const lines: string[] = []
|
|
69
|
+
let remaining = text
|
|
70
|
+
|
|
71
|
+
while (remaining.length > 0) {
|
|
72
|
+
if (remaining.length <= maxWidth) {
|
|
73
|
+
lines.push(remaining)
|
|
74
|
+
break
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let breakAt = maxWidth
|
|
78
|
+
const lastSpace = remaining.lastIndexOf(" ", maxWidth)
|
|
79
|
+
if (lastSpace > maxWidth * 0.5) {
|
|
80
|
+
breakAt = lastSpace
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
lines.push(remaining.slice(0, breakAt))
|
|
84
|
+
remaining = remaining.slice(breakAt).trimStart()
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return lines
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function normalizeSelection(anchor: SelectionPoint, head: SelectionPoint): [SelectionPoint, SelectionPoint] {
|
|
91
|
+
if (anchor.line < head.line || (anchor.line === head.line && anchor.col <= head.col)) {
|
|
92
|
+
return [anchor, head]
|
|
93
|
+
}
|
|
94
|
+
return [head, anchor]
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ─────────────────────────────────────────────────────────────
|
|
98
|
+
// Debug Overlay Class
|
|
99
|
+
// ─────────────────────────────────────────────────────────────
|
|
100
|
+
|
|
101
|
+
interface DisplayLine {
|
|
102
|
+
text: string
|
|
103
|
+
level: LogLevel
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export class DebugOverlay {
|
|
107
|
+
private _visible = false
|
|
108
|
+
private sizePercent: number
|
|
109
|
+
private minSizePercent: number
|
|
110
|
+
private maxSizePercent: number
|
|
111
|
+
private showLocations: boolean
|
|
112
|
+
|
|
113
|
+
// Scroll state
|
|
114
|
+
private scrollOffset = 0
|
|
115
|
+
private wasAtEnd = true
|
|
116
|
+
|
|
117
|
+
// Selection state
|
|
118
|
+
private selectionAnchor: SelectionPoint | null = null
|
|
119
|
+
private selectionHead: SelectionPoint | null = null
|
|
120
|
+
private isSelecting = false
|
|
121
|
+
|
|
122
|
+
// Feedback message
|
|
123
|
+
private feedback: string | null = null
|
|
124
|
+
private feedbackTimeout: ReturnType<typeof setTimeout> | null = null
|
|
125
|
+
|
|
126
|
+
// Cached display lines
|
|
127
|
+
private displayLines: DisplayLine[] = []
|
|
128
|
+
private lastEntriesLength = 0
|
|
129
|
+
private lastWidth = 0
|
|
130
|
+
|
|
131
|
+
// Screenshot callback
|
|
132
|
+
private getScreenshot: (() => string) | null = null
|
|
133
|
+
|
|
134
|
+
constructor(options: DebugOverlayOptions = {}) {
|
|
135
|
+
this.sizePercent = options.heightPercent ?? 30
|
|
136
|
+
this.minSizePercent = options.minHeightPercent ?? 10
|
|
137
|
+
this.maxSizePercent = options.maxHeightPercent ?? 80
|
|
138
|
+
this.showLocations = options.showLocations ?? true
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
get visible(): boolean {
|
|
142
|
+
return this._visible
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
show(): void {
|
|
146
|
+
this._visible = true
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
hide(): void {
|
|
150
|
+
this._visible = false
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
toggle(): void {
|
|
154
|
+
this._visible = !this._visible
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
setScreenshotFn(fn: () => string): void {
|
|
158
|
+
this.getScreenshot = fn
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ─────────────────────────────────────────────────────────────
|
|
162
|
+
// Key handling - returns true if event was consumed
|
|
163
|
+
// ─────────────────────────────────────────────────────────────
|
|
164
|
+
|
|
165
|
+
handleKey(key: KeyMsg, width: number, height: number): boolean {
|
|
166
|
+
// Ctrl+Shift+D - toggle overlay (handled even when hidden)
|
|
167
|
+
if (key.ctrl && key.shift && key.name === "char" && key.text === "d") {
|
|
168
|
+
this.toggle()
|
|
169
|
+
return true
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Ctrl+Shift+S - screenshot (handled even when hidden)
|
|
173
|
+
if (key.ctrl && key.shift && key.name === "char" && key.text === "s") {
|
|
174
|
+
this.takeScreenshot()
|
|
175
|
+
return true
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Rest only applies when visible
|
|
179
|
+
if (!this._visible) return false
|
|
180
|
+
|
|
181
|
+
// Ctrl+Y or Ctrl+C - copy selection
|
|
182
|
+
if (key.ctrl && !key.shift && key.name === "char" && (key.text === "y" || key.text === "c")) {
|
|
183
|
+
this.copySelection()
|
|
184
|
+
return true
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Ctrl+S - save logs
|
|
188
|
+
if (key.ctrl && !key.shift && key.name === "char" && key.text === "s") {
|
|
189
|
+
this.saveLogs()
|
|
190
|
+
return true
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Size controls
|
|
194
|
+
if (key.name === "char" && (key.text === "+" || key.text === "=")) {
|
|
195
|
+
this.sizePercent = Math.min(this.maxSizePercent, this.sizePercent + 5)
|
|
196
|
+
return true
|
|
197
|
+
}
|
|
198
|
+
if (key.name === "char" && key.text === "-") {
|
|
199
|
+
this.sizePercent = Math.max(this.minSizePercent, this.sizePercent - 5)
|
|
200
|
+
return true
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const viewportHeight = this.getViewportHeight(height)
|
|
204
|
+
const maxScroll = Math.max(0, this.displayLines.length - viewportHeight)
|
|
205
|
+
|
|
206
|
+
// Shift+up/down - jump to top/bottom
|
|
207
|
+
if (key.shift && key.name === "up") {
|
|
208
|
+
this.scrollOffset = 0
|
|
209
|
+
this.wasAtEnd = false
|
|
210
|
+
return true
|
|
211
|
+
}
|
|
212
|
+
if (key.shift && key.name === "down") {
|
|
213
|
+
this.scrollOffset = maxScroll
|
|
214
|
+
this.wasAtEnd = true
|
|
215
|
+
return true
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Regular up/down - scroll
|
|
219
|
+
if (key.name === "up") {
|
|
220
|
+
this.scrollOffset = Math.max(0, this.scrollOffset - 1)
|
|
221
|
+
this.wasAtEnd = this.scrollOffset >= maxScroll
|
|
222
|
+
return true
|
|
223
|
+
}
|
|
224
|
+
if (key.name === "down") {
|
|
225
|
+
this.scrollOffset = Math.min(maxScroll, this.scrollOffset + 1)
|
|
226
|
+
this.wasAtEnd = this.scrollOffset >= maxScroll
|
|
227
|
+
return true
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Home/End
|
|
231
|
+
if (key.name === "home") {
|
|
232
|
+
this.scrollOffset = 0
|
|
233
|
+
this.wasAtEnd = false
|
|
234
|
+
return true
|
|
235
|
+
}
|
|
236
|
+
if (key.name === "end") {
|
|
237
|
+
this.scrollOffset = maxScroll
|
|
238
|
+
this.wasAtEnd = true
|
|
239
|
+
return true
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return false
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ─────────────────────────────────────────────────────────────
|
|
246
|
+
// Mouse handling - returns true if event was consumed
|
|
247
|
+
// ─────────────────────────────────────────────────────────────
|
|
248
|
+
|
|
249
|
+
handleMouse(mouse: MouseMsg, width: number, height: number): boolean {
|
|
250
|
+
if (!this._visible) return false
|
|
251
|
+
|
|
252
|
+
const popoverHeight = this.getPopoverHeight(height)
|
|
253
|
+
const contentStartY = height - popoverHeight + 1
|
|
254
|
+
|
|
255
|
+
// Check if mouse is in overlay area
|
|
256
|
+
if (mouse.y < height - popoverHeight || mouse.y >= height) return false
|
|
257
|
+
|
|
258
|
+
// Mouse wheel scroll
|
|
259
|
+
if (mouse.button === "scroll-up" || mouse.button === "scroll-down") {
|
|
260
|
+
const viewportHeight = this.getViewportHeight(height)
|
|
261
|
+
const maxScroll = Math.max(0, this.displayLines.length - viewportHeight)
|
|
262
|
+
const delta = mouse.button === "scroll-up" ? -3 : 3
|
|
263
|
+
this.scrollOffset = Math.max(0, Math.min(maxScroll, this.scrollOffset + delta))
|
|
264
|
+
this.wasAtEnd = this.scrollOffset >= maxScroll
|
|
265
|
+
return true
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Text selection
|
|
269
|
+
if (mouse.button === "left") {
|
|
270
|
+
const relativeY = mouse.y - contentStartY
|
|
271
|
+
const lineIndex = Math.floor(relativeY + this.scrollOffset)
|
|
272
|
+
const col = Math.max(0, mouse.x)
|
|
273
|
+
|
|
274
|
+
if (lineIndex < 0 || lineIndex >= this.displayLines.length) return true
|
|
275
|
+
|
|
276
|
+
if (mouse.action === "press") {
|
|
277
|
+
this.selectionAnchor = { line: lineIndex, col }
|
|
278
|
+
this.selectionHead = { line: lineIndex, col }
|
|
279
|
+
this.isSelecting = true
|
|
280
|
+
} else if (mouse.action === "drag" && this.isSelecting) {
|
|
281
|
+
this.selectionHead = { line: lineIndex, col }
|
|
282
|
+
|
|
283
|
+
// Auto-scroll at edges
|
|
284
|
+
const viewportHeight = this.getViewportHeight(height)
|
|
285
|
+
if (relativeY <= 1) {
|
|
286
|
+
this.scrollOffset = Math.max(0, this.scrollOffset - 1)
|
|
287
|
+
} else if (relativeY >= viewportHeight - 2) {
|
|
288
|
+
const maxScroll = Math.max(0, this.displayLines.length - viewportHeight)
|
|
289
|
+
this.scrollOffset = Math.min(maxScroll, this.scrollOffset + 1)
|
|
290
|
+
}
|
|
291
|
+
} else if (mouse.action === "release") {
|
|
292
|
+
this.isSelecting = false
|
|
293
|
+
}
|
|
294
|
+
return true
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return true // Consume all mouse events in overlay area
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// ─────────────────────────────────────────────────────────────
|
|
301
|
+
// Rendering
|
|
302
|
+
// ─────────────────────────────────────────────────────────────
|
|
303
|
+
|
|
304
|
+
render(buffer: CellBuffer, palette: Palette, width: number, height: number): void {
|
|
305
|
+
if (!this._visible) return
|
|
306
|
+
|
|
307
|
+
const popoverHeight = this.getPopoverHeight(height)
|
|
308
|
+
const viewportHeight = this.getViewportHeight(height)
|
|
309
|
+
const startY = height - popoverHeight
|
|
310
|
+
|
|
311
|
+
// Update display lines if needed
|
|
312
|
+
this.updateDisplayLines(width)
|
|
313
|
+
|
|
314
|
+
// Auto-scroll to end if sticky
|
|
315
|
+
if (this.wasAtEnd) {
|
|
316
|
+
this.scrollOffset = Math.max(0, this.displayLines.length - viewportHeight)
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Title bar styles
|
|
320
|
+
const titleStyle = palette.id({ fg: TITLE_FG, bg: TITLE_BG })
|
|
321
|
+
const hintStyle = palette.id({ fg: this.feedback ? 10 : 250, bg: TITLE_BG })
|
|
322
|
+
|
|
323
|
+
// Draw title bar
|
|
324
|
+
const titleText = this.feedback ?? "Console"
|
|
325
|
+
const hints = `[^Y copy] [^S save] [^⇧S screenshot] [+/- ${this.sizePercent}%]`
|
|
326
|
+
|
|
327
|
+
buffer.fillRect(0, startY, width, 1, 32, titleStyle)
|
|
328
|
+
buffer.drawText(1, startY, ` ${titleText}`, titleStyle)
|
|
329
|
+
buffer.drawText(width - hints.length - 1, startY, hints, hintStyle)
|
|
330
|
+
|
|
331
|
+
// Content area
|
|
332
|
+
const contentStyle = palette.id({ bg: CONTENT_BG })
|
|
333
|
+
buffer.fillRect(0, startY + 1, width, viewportHeight, 32, contentStyle)
|
|
334
|
+
|
|
335
|
+
// Draw log lines
|
|
336
|
+
const contentStartY = startY + 1
|
|
337
|
+
for (let i = 0; i < viewportHeight; i++) {
|
|
338
|
+
const lineIdx = this.scrollOffset + i
|
|
339
|
+
if (lineIdx >= this.displayLines.length) break
|
|
340
|
+
|
|
341
|
+
const line = this.displayLines[lineIdx]
|
|
342
|
+
const y = contentStartY + i
|
|
343
|
+
const paddedText = line.text.padEnd(width - 1, " ")
|
|
344
|
+
|
|
345
|
+
// Check for selection
|
|
346
|
+
const sel = this.getLineSelection(lineIdx, paddedText.length)
|
|
347
|
+
|
|
348
|
+
if (sel) {
|
|
349
|
+
// Render with selection highlight
|
|
350
|
+
const before = paddedText.slice(0, sel.startCol)
|
|
351
|
+
const selected = paddedText.slice(sel.startCol, sel.endCol)
|
|
352
|
+
const after = paddedText.slice(sel.endCol)
|
|
353
|
+
|
|
354
|
+
const normalStyle = palette.id({ fg: LOG_COLORS[line.level], bg: CONTENT_BG })
|
|
355
|
+
const selStyle = palette.id({ fg: 15, bg: { r: SELECTION_BG_R, g: SELECTION_BG_G, b: SELECTION_BG_B } })
|
|
356
|
+
|
|
357
|
+
let x = 0
|
|
358
|
+
if (before.length > 0) {
|
|
359
|
+
buffer.drawText(x, y, before, normalStyle)
|
|
360
|
+
x += before.length
|
|
361
|
+
}
|
|
362
|
+
buffer.drawText(x, y, selected, selStyle)
|
|
363
|
+
x += selected.length
|
|
364
|
+
if (after.length > 0) {
|
|
365
|
+
buffer.drawText(x, y, after, normalStyle)
|
|
366
|
+
}
|
|
367
|
+
} else {
|
|
368
|
+
const style = palette.id({ fg: LOG_COLORS[line.level], bg: CONTENT_BG })
|
|
369
|
+
buffer.drawText(0, y, paddedText, style)
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Draw scrollbar if needed
|
|
374
|
+
if (this.displayLines.length > viewportHeight) {
|
|
375
|
+
this.drawScrollbar(buffer, palette, width, contentStartY, viewportHeight)
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// ─────────────────────────────────────────────────────────────
|
|
380
|
+
// Private helpers
|
|
381
|
+
// ─────────────────────────────────────────────────────────────
|
|
382
|
+
|
|
383
|
+
private getPopoverHeight(termHeight: number): number {
|
|
384
|
+
return Math.max(5, Math.floor(termHeight * (this.sizePercent / 100)))
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
private getViewportHeight(termHeight: number): number {
|
|
388
|
+
return this.getPopoverHeight(termHeight) - 1 // -1 for title bar
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
private updateDisplayLines(width: number): void {
|
|
392
|
+
const capture = getConsoleCapture()
|
|
393
|
+
const entries = capture.getEntries()
|
|
394
|
+
|
|
395
|
+
// Only rebuild if entries changed or width changed
|
|
396
|
+
if (entries.length === this.lastEntriesLength && width === this.lastWidth) {
|
|
397
|
+
return
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
this.lastEntriesLength = entries.length
|
|
401
|
+
this.lastWidth = width
|
|
402
|
+
this.displayLines = []
|
|
403
|
+
|
|
404
|
+
const availableWidth = width - 1 // Leave room for scrollbar
|
|
405
|
+
|
|
406
|
+
for (const entry of entries) {
|
|
407
|
+
const timestamp = formatTimestamp(entry.timestamp)
|
|
408
|
+
const location = this.showLocations ? formatLocation(entry.location) : ""
|
|
409
|
+
|
|
410
|
+
const prefix = `[${timestamp}] [${entry.level}] `
|
|
411
|
+
const suffix = location ? ` (${location})` : ""
|
|
412
|
+
|
|
413
|
+
const messageLines = entry.message.split("\n")
|
|
414
|
+
|
|
415
|
+
for (let j = 0; j < messageLines.length; j++) {
|
|
416
|
+
const msgLine = messageLines[j]
|
|
417
|
+
const isFirstLine = j === 0
|
|
418
|
+
const isLastLine = j === messageLines.length - 1
|
|
419
|
+
|
|
420
|
+
const linePrefix = isFirstLine ? prefix : " "
|
|
421
|
+
const lineSuffix = isLastLine ? suffix : ""
|
|
422
|
+
|
|
423
|
+
const fullLine = linePrefix + msgLine + lineSuffix
|
|
424
|
+
const wrappedLines = wrapLine(fullLine, availableWidth)
|
|
425
|
+
|
|
426
|
+
for (const wrappedLine of wrappedLines) {
|
|
427
|
+
this.displayLines.push({
|
|
428
|
+
text: wrappedLine,
|
|
429
|
+
level: entry.level,
|
|
430
|
+
})
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
private getLineSelection(
|
|
437
|
+
lineIndex: number,
|
|
438
|
+
lineLength: number,
|
|
439
|
+
): { startCol: number; endCol: number } | null {
|
|
440
|
+
if (!this.selectionAnchor || !this.selectionHead) return null
|
|
441
|
+
|
|
442
|
+
const [start, end] = normalizeSelection(this.selectionAnchor, this.selectionHead)
|
|
443
|
+
|
|
444
|
+
if (lineIndex < start.line || lineIndex > end.line) return null
|
|
445
|
+
|
|
446
|
+
const startCol = lineIndex === start.line ? Math.min(start.col, lineLength) : 0
|
|
447
|
+
const endCol = lineIndex === end.line ? Math.min(end.col, lineLength) : lineLength
|
|
448
|
+
|
|
449
|
+
if (startCol >= endCol && lineIndex === start.line && lineIndex === end.line) return null
|
|
450
|
+
|
|
451
|
+
return { startCol, endCol }
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
private drawScrollbar(
|
|
455
|
+
buffer: CellBuffer,
|
|
456
|
+
palette: Palette,
|
|
457
|
+
width: number,
|
|
458
|
+
contentStartY: number,
|
|
459
|
+
viewportHeight: number,
|
|
460
|
+
): void {
|
|
461
|
+
const maxScroll = this.displayLines.length - viewportHeight
|
|
462
|
+
const scrollRatio = maxScroll > 0 ? this.scrollOffset / maxScroll : 0
|
|
463
|
+
const thumbRatio = viewportHeight / this.displayLines.length
|
|
464
|
+
const thumbHeight = Math.max(1, Math.floor(viewportHeight * thumbRatio))
|
|
465
|
+
const thumbY = Math.floor((viewportHeight - thumbHeight) * scrollRatio)
|
|
466
|
+
|
|
467
|
+
const trackStyle = palette.id({ fg: 8 })
|
|
468
|
+
const thumbStyle = palette.id({ fg: 7 })
|
|
469
|
+
|
|
470
|
+
for (let i = 0; i < viewportHeight; i++) {
|
|
471
|
+
const isThumb = i >= thumbY && i < thumbY + thumbHeight
|
|
472
|
+
const char = isThumb ? "┃" : "│"
|
|
473
|
+
const style = isThumb ? thumbStyle : trackStyle
|
|
474
|
+
buffer.drawText(width - 1, contentStartY + i, char, style)
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
private getSelectedText(): string {
|
|
479
|
+
if (!this.selectionAnchor || !this.selectionHead) return ""
|
|
480
|
+
|
|
481
|
+
const [start, end] = normalizeSelection(this.selectionAnchor, this.selectionHead)
|
|
482
|
+
const lines: string[] = []
|
|
483
|
+
|
|
484
|
+
for (let i = start.line; i <= end.line && i < this.displayLines.length; i++) {
|
|
485
|
+
const lineText = this.displayLines[i]?.text ?? ""
|
|
486
|
+
const startCol = i === start.line ? Math.min(start.col, lineText.length) : 0
|
|
487
|
+
const endCol = i === end.line ? Math.min(end.col, lineText.length) : lineText.length
|
|
488
|
+
lines.push(lineText.slice(startCol, endCol))
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return lines.join("\n")
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
private copySelection(): void {
|
|
495
|
+
const text = this.getSelectedText()
|
|
496
|
+
if (!text) return
|
|
497
|
+
|
|
498
|
+
const copied = copyToClipboardSync(text)
|
|
499
|
+
if (!copied) {
|
|
500
|
+
copyToClipboard(text)
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
this.showFeedback("Copied!")
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
private async saveLogs(): Promise<void> {
|
|
507
|
+
const allText = this.displayLines.map((l) => l.text).join("\n")
|
|
508
|
+
const tmpPath = `/tmp/console-logs-${Date.now()}.txt`
|
|
509
|
+
|
|
510
|
+
try {
|
|
511
|
+
await Bun.write(tmpPath, allText)
|
|
512
|
+
const copied = copyToClipboardSync(tmpPath)
|
|
513
|
+
if (!copied) {
|
|
514
|
+
await copyToClipboard(tmpPath)
|
|
515
|
+
}
|
|
516
|
+
this.showFeedback(`Saved: ${tmpPath}`)
|
|
517
|
+
} catch {
|
|
518
|
+
this.showFeedback("Save failed")
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
private async takeScreenshot(): Promise<void> {
|
|
523
|
+
if (!this.getScreenshot) {
|
|
524
|
+
this.showFeedback("Screenshot not available")
|
|
525
|
+
return
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
const screenshot = this.getScreenshot()
|
|
529
|
+
const tmpPath = `/tmp/tui-screenshot-${Date.now()}.txt`
|
|
530
|
+
|
|
531
|
+
try {
|
|
532
|
+
await Bun.write(tmpPath, screenshot)
|
|
533
|
+
const copied = copyToClipboardSync(tmpPath)
|
|
534
|
+
if (!copied) {
|
|
535
|
+
await copyToClipboard(tmpPath)
|
|
536
|
+
}
|
|
537
|
+
this.showFeedback(`Screenshot: ${tmpPath}`)
|
|
538
|
+
// Also show the console so user sees the feedback
|
|
539
|
+
if (!this._visible) {
|
|
540
|
+
this._visible = true
|
|
541
|
+
}
|
|
542
|
+
} catch {
|
|
543
|
+
this.showFeedback("Screenshot failed")
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
private showFeedback(message: string, durationMs = 2000): void {
|
|
548
|
+
if (this.feedbackTimeout) {
|
|
549
|
+
clearTimeout(this.feedbackTimeout)
|
|
550
|
+
}
|
|
551
|
+
this.feedback = message
|
|
552
|
+
this.feedbackTimeout = setTimeout(() => {
|
|
553
|
+
this.feedback = null
|
|
554
|
+
this.feedbackTimeout = null
|
|
555
|
+
}, durationMs)
|
|
556
|
+
}
|
|
557
|
+
}
|