@xincli/opentui-core 0.4.6
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/README.md +63 -0
- package/dev/keypress-debug-renderer.ts +148 -0
- package/dev/keypress-debug.ts +43 -0
- package/dev/print-env-vars.ts +32 -0
- package/dev/test-tmux-graphics-334.sh +68 -0
- package/dev/test-tmux-theme-queries.sh +151 -0
- package/dev/thai-debug-test.ts +68 -0
- package/dev/theme-mode.ts +290 -0
- package/docs/development.md +144 -0
- package/package.json +102 -0
- package/prebuilt/aarch64-android/libopentui.so +0 -0
- package/scripts/build-android.ts +226 -0
- package/scripts/build-native-termux.sh +525 -0
- package/scripts/build.ts +530 -0
- package/scripts/dist-test.ts +312 -0
- package/scripts/package-prebuilt.ts +110 -0
- package/scripts/publish.ts +60 -0
- package/scripts/test-node-hook.mjs +16 -0
- package/scripts/test-node.ts +241 -0
- package/scripts/vendor-deps.sh +73 -0
- package/src/NativeSpanFeed.ts +375 -0
- package/src/Renderable.ts +1878 -0
- package/src/__snapshots__/buffer.test.ts.snap +28 -0
- package/src/animation/Timeline.test.ts +2709 -0
- package/src/animation/Timeline.ts +598 -0
- package/src/ansi.ts +22 -0
- package/src/audio.ts +479 -0
- package/src/benchmark/attenuation-benchmark.ts +81 -0
- package/src/benchmark/audio-playback-benchmark.ts +344 -0
- package/src/benchmark/box-draw-benchmark.ts +1042 -0
- package/src/benchmark/colormatrix-benchmark.ts +123 -0
- package/src/benchmark/gain-benchmark.ts +80 -0
- package/src/benchmark/latest-all-bench-run.json +707 -0
- package/src/benchmark/latest-async-bench-run.json +336 -0
- package/src/benchmark/latest-default-bench-run.json +657 -0
- package/src/benchmark/latest-large-bench-run.json +707 -0
- package/src/benchmark/latest-quick-bench-run.json +207 -0
- package/src/benchmark/layout-benchmark.ts +2547 -0
- package/src/benchmark/markdown-benchmark.ts +1796 -0
- package/src/benchmark/native-span-feed-async-benchmark.ts +355 -0
- package/src/benchmark/native-span-feed-benchmark.md +56 -0
- package/src/benchmark/native-span-feed-benchmark.ts +596 -0
- package/src/benchmark/native-span-feed-compare.ts +280 -0
- package/src/benchmark/render-traversal-benchmark.ts +928 -0
- package/src/benchmark/text-buffer-render-benchmark.ts +874 -0
- package/src/benchmark/text-table-benchmark.ts +948 -0
- package/src/buffer.test.ts +292 -0
- package/src/buffer.ts +564 -0
- package/src/console.test.ts +629 -0
- package/src/console.ts +1253 -0
- package/src/edit-buffer.test.ts +1852 -0
- package/src/edit-buffer.ts +417 -0
- package/src/editor-view.test.ts +1056 -0
- package/src/editor-view.ts +290 -0
- package/src/index.ts +25 -0
- package/src/lib/KeyHandler.integration.test.ts +292 -0
- package/src/lib/KeyHandler.stopPropagation.test.ts +289 -0
- package/src/lib/KeyHandler.test.ts +662 -0
- package/src/lib/KeyHandler.ts +222 -0
- package/src/lib/RGBA.test.ts +60 -0
- package/src/lib/RGBA.ts +343 -0
- package/src/lib/ascii.font.ts +330 -0
- package/src/lib/border.test.ts +83 -0
- package/src/lib/border.ts +170 -0
- package/src/lib/bunfs.test.ts +27 -0
- package/src/lib/bunfs.ts +18 -0
- package/src/lib/clipboard.test.ts +63 -0
- package/src/lib/clipboard.ts +41 -0
- package/src/lib/clock.ts +35 -0
- package/src/lib/data-paths.test.ts +133 -0
- package/src/lib/data-paths.ts +109 -0
- package/src/lib/debounce.ts +106 -0
- package/src/lib/detect-links.test.ts +98 -0
- package/src/lib/detect-links.ts +56 -0
- package/src/lib/env.test.ts +228 -0
- package/src/lib/env.ts +209 -0
- package/src/lib/extmarks-history.ts +51 -0
- package/src/lib/extmarks-multiwidth.test.ts +324 -0
- package/src/lib/extmarks.test.ts +3547 -0
- package/src/lib/extmarks.ts +861 -0
- package/src/lib/fonts/block.json +405 -0
- package/src/lib/fonts/grid.json +265 -0
- package/src/lib/fonts/huge.json +741 -0
- package/src/lib/fonts/pallet.json +314 -0
- package/src/lib/fonts/shade.json +591 -0
- package/src/lib/fonts/slick.json +321 -0
- package/src/lib/fonts/tiny.json +69 -0
- package/src/lib/hast-styled-text.ts +59 -0
- package/src/lib/index.ts +22 -0
- package/src/lib/keybinding.internal.test.ts +342 -0
- package/src/lib/keybinding.internal.ts +182 -0
- package/src/lib/objects-in-viewport.test.ts +789 -0
- package/src/lib/objects-in-viewport.ts +153 -0
- package/src/lib/output.capture.ts +58 -0
- package/src/lib/parse.keypress-kitty.protocol.test.ts +347 -0
- package/src/lib/parse.keypress-kitty.test.ts +712 -0
- package/src/lib/parse.keypress-kitty.ts +470 -0
- package/src/lib/parse.keypress.test.ts +2020 -0
- package/src/lib/parse.keypress.ts +480 -0
- package/src/lib/parse.mouse.test.ts +552 -0
- package/src/lib/parse.mouse.ts +232 -0
- package/src/lib/paste.ts +18 -0
- package/src/lib/queue.ts +65 -0
- package/src/lib/render-geometry.ts +36 -0
- package/src/lib/renderable.validations.test.ts +87 -0
- package/src/lib/renderable.validations.ts +83 -0
- package/src/lib/scroll-acceleration.ts +98 -0
- package/src/lib/selection.ts +261 -0
- package/src/lib/singleton.ts +34 -0
- package/src/lib/stdin-parser.test.ts +2439 -0
- package/src/lib/stdin-parser.ts +2007 -0
- package/src/lib/styled-text.ts +178 -0
- package/src/lib/terminal-capability-detection.test.ts +226 -0
- package/src/lib/terminal-capability-detection.ts +98 -0
- package/src/lib/terminal-palette.test.ts +954 -0
- package/src/lib/terminal-palette.ts +441 -0
- package/src/lib/tree-sitter/assets/README.md +119 -0
- package/src/lib/tree-sitter/assets/javascript/highlights.scm +205 -0
- package/src/lib/tree-sitter/assets/javascript/tree-sitter-javascript.wasm +0 -0
- package/src/lib/tree-sitter/assets/markdown/highlights.scm +150 -0
- package/src/lib/tree-sitter/assets/markdown/injections.scm +27 -0
- package/src/lib/tree-sitter/assets/markdown/tree-sitter-markdown.wasm +0 -0
- package/src/lib/tree-sitter/assets/markdown_inline/highlights.scm +115 -0
- package/src/lib/tree-sitter/assets/markdown_inline/tree-sitter-markdown_inline.wasm +0 -0
- package/src/lib/tree-sitter/assets/typescript/highlights.scm +604 -0
- package/src/lib/tree-sitter/assets/typescript/tree-sitter-typescript.wasm +0 -0
- package/src/lib/tree-sitter/assets/update.ts +360 -0
- package/src/lib/tree-sitter/assets/zig/highlights.scm +284 -0
- package/src/lib/tree-sitter/assets/zig/tree-sitter-zig.wasm +0 -0
- package/src/lib/tree-sitter/assets.d.ts +9 -0
- package/src/lib/tree-sitter/cache.test.ts +291 -0
- package/src/lib/tree-sitter/client.test.ts +1434 -0
- package/src/lib/tree-sitter/client.ts +847 -0
- package/src/lib/tree-sitter/default-parsers.ts +133 -0
- package/src/lib/tree-sitter/download-utils.ts +148 -0
- package/src/lib/tree-sitter/index.ts +75 -0
- package/src/lib/tree-sitter/parser.worker.ts +1098 -0
- package/src/lib/tree-sitter/parsers-config.ts +81 -0
- package/src/lib/tree-sitter/resolve-ft.test.ts +55 -0
- package/src/lib/tree-sitter/resolve-ft.ts +189 -0
- package/src/lib/tree-sitter/types.ts +132 -0
- package/src/lib/tree-sitter/update-assets.ts +10 -0
- package/src/lib/tree-sitter-styled-text.test.ts +1253 -0
- package/src/lib/tree-sitter-styled-text.ts +314 -0
- package/src/lib/validate-dir-name.ts +55 -0
- package/src/lib/yoga.options.test.ts +628 -0
- package/src/lib/yoga.options.ts +346 -0
- package/src/native-event-worker-repro.test.ts +48 -0
- package/src/native-event-worker-repro.worker.ts +9 -0
- package/src/native-handle.test.ts +221 -0
- package/src/platform/ffi.test.ts +516 -0
- package/src/platform/ffi.ts +653 -0
- package/src/platform/runtime.test.ts +52 -0
- package/src/platform/runtime.ts +121 -0
- package/src/platform/test.ts +45 -0
- package/src/platform/worker-handler-cleanup.fixture.ts +12 -0
- package/src/platform/worker-onmessage-startup.fixture.ts +10 -0
- package/src/platform/worker-startup.fixture.ts +9 -0
- package/src/platform/worker.node-test.ts +153 -0
- package/src/platform/worker.ts +425 -0
- package/src/plugins/core-slot.ts +579 -0
- package/src/plugins/registry.ts +402 -0
- package/src/plugins/types.ts +46 -0
- package/src/post/effects.ts +948 -0
- package/src/post/filters.ts +512 -0
- package/src/post/matrices.ts +288 -0
- package/src/renderables/ASCIIFont.ts +219 -0
- package/src/renderables/Box.test.ts +474 -0
- package/src/renderables/Box.ts +353 -0
- package/src/renderables/Code.test.ts +2388 -0
- package/src/renderables/Code.ts +555 -0
- package/src/renderables/Diff.regression.test.ts +381 -0
- package/src/renderables/Diff.test.ts +3212 -0
- package/src/renderables/Diff.ts +1278 -0
- package/src/renderables/EditBufferRenderable.test.ts +288 -0
- package/src/renderables/EditBufferRenderable.ts +1152 -0
- package/src/renderables/FrameBuffer.ts +47 -0
- package/src/renderables/Input.test.ts +1310 -0
- package/src/renderables/Input.ts +273 -0
- package/src/renderables/LineNumberRenderable.ts +725 -0
- package/src/renderables/Markdown.ts +2144 -0
- package/src/renderables/ScrollBar.ts +423 -0
- package/src/renderables/ScrollBox.ts +903 -0
- package/src/renderables/Select.test.ts +1134 -0
- package/src/renderables/Select.ts +535 -0
- package/src/renderables/Slider.test.ts +456 -0
- package/src/renderables/Slider.ts +342 -0
- package/src/renderables/TabSelect.test.ts +238 -0
- package/src/renderables/TabSelect.ts +447 -0
- package/src/renderables/Text.selection-buffer.test.ts +118 -0
- package/src/renderables/Text.test.ts +2662 -0
- package/src/renderables/Text.ts +147 -0
- package/src/renderables/TextBufferRenderable.ts +504 -0
- package/src/renderables/TextNode.test.ts +1137 -0
- package/src/renderables/TextNode.ts +379 -0
- package/src/renderables/TextTable.test.ts +1411 -0
- package/src/renderables/TextTable.ts +1434 -0
- package/src/renderables/Textarea.ts +425 -0
- package/src/renderables/TimeToFirstDraw.ts +89 -0
- package/src/renderables/__snapshots__/Code.test.ts.snap +13 -0
- package/src/renderables/__snapshots__/Diff.test.ts.snap +785 -0
- package/src/renderables/__snapshots__/Text.test.ts.snap +421 -0
- package/src/renderables/__snapshots__/TextTable.test.ts.snap +215 -0
- package/src/renderables/__tests__/Code.test.ts +55 -0
- package/src/renderables/__tests__/LineNumberRenderable.scrollbox-simple.test.ts +144 -0
- package/src/renderables/__tests__/LineNumberRenderable.scrollbox.test.ts +827 -0
- package/src/renderables/__tests__/LineNumberRenderable.test.ts +1906 -0
- package/src/renderables/__tests__/LineNumberRenderable.wrapping.test.ts +85 -0
- package/src/renderables/__tests__/Markdown.code-colors.test.ts +288 -0
- package/src/renderables/__tests__/Markdown.test.ts +4175 -0
- package/src/renderables/__tests__/MultiRenderable.selection.test.ts +87 -0
- package/src/renderables/__tests__/Textarea.buffer.test.ts +683 -0
- package/src/renderables/__tests__/Textarea.destroyed-events.test.ts +675 -0
- package/src/renderables/__tests__/Textarea.editing.test.ts +2120 -0
- package/src/renderables/__tests__/Textarea.error-handling.test.ts +35 -0
- package/src/renderables/__tests__/Textarea.events.test.ts +738 -0
- package/src/renderables/__tests__/Textarea.highlights.test.ts +590 -0
- package/src/renderables/__tests__/Textarea.keybinding.test.ts +3275 -0
- package/src/renderables/__tests__/Textarea.paste.test.ts +357 -0
- package/src/renderables/__tests__/Textarea.rendering.test.ts +1927 -0
- package/src/renderables/__tests__/Textarea.scroll.test.ts +733 -0
- package/src/renderables/__tests__/Textarea.selection.test.ts +1589 -0
- package/src/renderables/__tests__/Textarea.stress.test.ts +670 -0
- package/src/renderables/__tests__/Textarea.undo-redo.test.ts +383 -0
- package/src/renderables/__tests__/Textarea.visual-lines.test.ts +310 -0
- package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.code.test.ts.snap +221 -0
- package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox-simple.test.ts.snap +89 -0
- package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.scrollbox.test.ts.snap +457 -0
- package/src/renderables/__tests__/__snapshots__/LineNumberRenderable.test.ts.snap +158 -0
- package/src/renderables/__tests__/__snapshots__/Textarea.rendering.test.ts.snap +387 -0
- package/src/renderables/__tests__/markdown-parser.test.ts +241 -0
- package/src/renderables/__tests__/renderable-test-utils.ts +60 -0
- package/src/renderables/composition/README.md +8 -0
- package/src/renderables/composition/VRenderable.ts +32 -0
- package/src/renderables/composition/constructs.ts +127 -0
- package/src/renderables/composition/vnode.ts +277 -0
- package/src/renderables/index.ts +23 -0
- package/src/renderables/markdown-parser.ts +79 -0
- package/src/renderer-theme-mode.ts +199 -0
- package/src/renderer.ts +4975 -0
- package/src/runtime-plugin-support-configure.ts +63 -0
- package/src/runtime-plugin-support.ts +13 -0
- package/src/runtime-plugin.ts +626 -0
- package/src/specs/terminal-startup.md +64 -0
- package/src/syntax-style.test.ts +841 -0
- package/src/syntax-style.ts +274 -0
- package/src/testing/README.md +219 -0
- package/src/testing/bun-test-node.ts +880 -0
- package/src/testing/capture-spans.test.ts +216 -0
- package/src/testing/integration.test.ts +276 -0
- package/src/testing/manual-clock.ts +117 -0
- package/src/testing/mock-keys.test.ts +1378 -0
- package/src/testing/mock-keys.ts +457 -0
- package/src/testing/mock-mouse.test.ts +218 -0
- package/src/testing/mock-mouse.ts +247 -0
- package/src/testing/mock-tree-sitter-client.ts +81 -0
- package/src/testing/spy.ts +13 -0
- package/src/testing/terminal-capabilities.ts +47 -0
- package/src/testing/test-recorder.test.ts +410 -0
- package/src/testing/test-recorder.ts +133 -0
- package/src/testing/test-renderer.ts +375 -0
- package/src/testing/test-renderer.wait.test.ts +278 -0
- package/src/testing/test-streams.ts +31 -0
- package/src/testing.ts +9 -0
- package/src/tests/__snapshots__/absolute-positioning.snapshot.test.ts.snap +481 -0
- package/src/tests/__snapshots__/renderable.snapshot.test.ts.snap +19 -0
- package/src/tests/__snapshots__/scrollbox.test.ts.snap +29 -0
- package/src/tests/absolute-positioning.snapshot.test.ts +638 -0
- package/src/tests/allocator-stats.test.ts +53 -0
- package/src/tests/audio.test.ts +303 -0
- package/src/tests/destroy-during-render.test.ts +200 -0
- package/src/tests/destroy-on-exit.fixture.ts +36 -0
- package/src/tests/destroy-on-exit.test.ts +62 -0
- package/src/tests/ffi-borrowed-pointer-callsites.test.ts +153 -0
- package/src/tests/hover-cursor.test.ts +98 -0
- package/src/tests/native-backed-measurement-lifecycle.test.ts +133 -0
- package/src/tests/native-backed-measurement-parity.test.ts +322 -0
- package/src/tests/native-span-feed-async.test.ts +173 -0
- package/src/tests/native-span-feed-close.test.ts +120 -0
- package/src/tests/native-span-feed-coverage.test.ts +227 -0
- package/src/tests/native-span-feed-edge-cases.test.ts +384 -0
- package/src/tests/native-span-feed-use-after-free.test.ts +45 -0
- package/src/tests/opacity.test.ts +123 -0
- package/src/tests/renderable.snapshot.test.ts +524 -0
- package/src/tests/renderable.test.ts +1851 -0
- package/src/tests/renderer.clock.test.ts +270 -0
- package/src/tests/renderer.console-startup.test.ts +2151 -0
- package/src/tests/renderer.control.test.ts +458 -0
- package/src/tests/renderer.core-slot-binding.test.ts +962 -0
- package/src/tests/renderer.cursor.test.ts +26 -0
- package/src/tests/renderer.custom-stdout.test.ts +1112 -0
- package/src/tests/renderer.destroy-during-render.test.ts +147 -0
- package/src/tests/renderer.focus-restore.test.ts +257 -0
- package/src/tests/renderer.focus.test.ts +329 -0
- package/src/tests/renderer.idle.test.ts +219 -0
- package/src/tests/renderer.input.test.ts +2615 -0
- package/src/tests/renderer.kitty-flags.test.ts +195 -0
- package/src/tests/renderer.lifecycle.test.ts +34 -0
- package/src/tests/renderer.mouse.test.ts +1315 -0
- package/src/tests/renderer.notifications.test.ts +27 -0
- package/src/tests/renderer.palette.test.ts +1199 -0
- package/src/tests/renderer.remote.test.ts +247 -0
- package/src/tests/renderer.render-stats.test.ts +146 -0
- package/src/tests/renderer.scrollback-surface.test.ts +474 -0
- package/src/tests/renderer.selection.test.ts +138 -0
- package/src/tests/renderer.slot-registry.test.ts +684 -0
- package/src/tests/renderer.tracker.test.ts +202 -0
- package/src/tests/renderer.useMouse.test.ts +83 -0
- package/src/tests/runtime-plugin-node-modules-cycle.fixture.ts +76 -0
- package/src/tests/runtime-plugin-node-modules-import-like-string.fixture.ts +48 -0
- package/src/tests/runtime-plugin-node-modules-mjs.fixture.ts +43 -0
- package/src/tests/runtime-plugin-node-modules-no-bare-rewrite.fixture.ts +67 -0
- package/src/tests/runtime-plugin-node-modules-package-type-cache.fixture.ts +72 -0
- package/src/tests/runtime-plugin-node-modules-runtime-specifier.fixture.ts +44 -0
- package/src/tests/runtime-plugin-node-modules-scoped-package-bare-rewrite.fixture.ts +85 -0
- package/src/tests/runtime-plugin-path-alias.fixture.ts +43 -0
- package/src/tests/runtime-plugin-resolve-roots.fixture.ts +65 -0
- package/src/tests/runtime-plugin-support-configure.fixture.ts +31 -0
- package/src/tests/runtime-plugin-support-late-addition.fixture.ts +17 -0
- package/src/tests/runtime-plugin-support.fixture.ts +11 -0
- package/src/tests/runtime-plugin-support.test.ts +54 -0
- package/src/tests/runtime-plugin-windows-file-url.fixture.ts +30 -0
- package/src/tests/runtime-plugin.fixture.ts +40 -0
- package/src/tests/runtime-plugin.test.ts +369 -0
- package/src/tests/scrollbox-culling-bug.test.ts +114 -0
- package/src/tests/scrollbox-hitgrid-resize.test.ts +136 -0
- package/src/tests/scrollbox-hitgrid.test.ts +909 -0
- package/src/tests/scrollbox.test.ts +1895 -0
- package/src/tests/wrap-resize-perf.test.ts +276 -0
- package/src/tests/yoga-api-coverage.test.ts +409 -0
- package/src/tests/yoga-callback-stress.test.ts +122 -0
- package/src/tests/yoga-ffi.test.ts +117 -0
- package/src/tests/yoga-setters.test.ts +921 -0
- package/src/tests/yoga-upstream/YGAlignBaselineTest.test.ts +124 -0
- package/src/tests/yoga-upstream/YGComputedBorderTest.test.ts +27 -0
- package/src/tests/yoga-upstream/YGComputedMarginTest.test.ts +27 -0
- package/src/tests/yoga-upstream/YGComputedPaddingTest.test.ts +27 -0
- package/src/tests/yoga-upstream/YGDirtiedTest.test.ts +157 -0
- package/src/tests/yoga-upstream/YGErrataTest.test.ts +40 -0
- package/src/tests/yoga-upstream/YGFlexBasisAuto.test.ts +23 -0
- package/src/tests/yoga-upstream/YGHasNewLayout.test.ts +81 -0
- package/src/tests/yoga-upstream/YGMeasureCacheTest.test.ts +31 -0
- package/src/tests/yoga-upstream/YGMeasureTest.test.ts +70 -0
- package/src/tests/yoga-upstream/generated/YGAbsolutePositionTest.test.ts +1864 -0
- package/src/tests/yoga-upstream/generated/YGAlignContentTest.test.ts +5829 -0
- package/src/tests/yoga-upstream/generated/YGAlignItemsTest.test.ts +2444 -0
- package/src/tests/yoga-upstream/generated/YGAlignSelfTest.test.ts +293 -0
- package/src/tests/yoga-upstream/generated/YGAndroidNewsFeed.test.ts +315 -0
- package/src/tests/yoga-upstream/generated/YGAspectRatioTest.test.ts +231 -0
- package/src/tests/yoga-upstream/generated/YGAutoTest.test.ts +347 -0
- package/src/tests/yoga-upstream/generated/YGBorderTest.test.ts +256 -0
- package/src/tests/yoga-upstream/generated/YGBoxSizingTest.test.ts +2747 -0
- package/src/tests/yoga-upstream/generated/YGDimensionTest.test.ts +129 -0
- package/src/tests/yoga-upstream/generated/YGDisplayContentsTest.test.ts +109 -0
- package/src/tests/yoga-upstream/generated/YGDisplayTest.test.ts +1097 -0
- package/src/tests/yoga-upstream/generated/YGFlexDirectionTest.test.ts +4562 -0
- package/src/tests/yoga-upstream/generated/YGFlexTest.test.ts +677 -0
- package/src/tests/yoga-upstream/generated/YGFlexWrapTest.test.ts +2071 -0
- package/src/tests/yoga-upstream/generated/YGGapTest.test.ts +3303 -0
- package/src/tests/yoga-upstream/generated/YGIntrinsicSizeTest.test.ts +582 -0
- package/src/tests/yoga-upstream/generated/YGJustifyContentTest.test.ts +2150 -0
- package/src/tests/yoga-upstream/generated/YGMarginTest.test.ts +1963 -0
- package/src/tests/yoga-upstream/generated/YGMinMaxDimensionTest.test.ts +1446 -0
- package/src/tests/yoga-upstream/generated/YGPaddingTest.test.ts +354 -0
- package/src/tests/yoga-upstream/generated/YGPercentageTest.test.ts +1760 -0
- package/src/tests/yoga-upstream/generated/YGRoundingTest.test.ts +1161 -0
- package/src/tests/yoga-upstream/generated/YGSizeOverflowTest.test.ts +207 -0
- package/src/tests/yoga-upstream/generated/YGStaticPositionTest.test.ts +6338 -0
- package/src/tests/yoga-upstream/tools/MeasureCounter.ts +54 -0
- package/src/tests/yoga-upstream/tools/utils.ts +81 -0
- package/src/text-buffer-view.test.ts +722 -0
- package/src/text-buffer-view.ts +193 -0
- package/src/text-buffer.test.ts +512 -0
- package/src/text-buffer.ts +250 -0
- package/src/types.ts +199 -0
- package/src/utils.ts +88 -0
- package/src/yoga.ts +1146 -0
- package/src/zig/ansi.zig +502 -0
- package/src/zig/audio.zig +1206 -0
- package/src/zig/bench/README.md +50 -0
- package/src/zig/bench/buffer-color-blending_bench.zig +350 -0
- package/src/zig/bench/buffer-draw-box_bench.zig +786 -0
- package/src/zig/bench/buffer-draw-text-buffer_bench.zig +894 -0
- package/src/zig/bench/edit-buffer_bench.zig +476 -0
- package/src/zig/bench/editor-view_bench.zig +169 -0
- package/src/zig/bench/native-span-feed_bench.zig +107 -0
- package/src/zig/bench/rope-markers_bench.zig +713 -0
- package/src/zig/bench/rope_bench.zig +514 -0
- package/src/zig/bench/styled-text_bench.zig +476 -0
- package/src/zig/bench/text-buffer-coords_bench.zig +362 -0
- package/src/zig/bench/text-buffer-view_bench.zig +459 -0
- package/src/zig/bench/text-chunk-graphemes_bench.zig +272 -0
- package/src/zig/bench/utf8_bench.zig +799 -0
- package/src/zig/bench-utils.zig +431 -0
- package/src/zig/bench.zig +223 -0
- package/src/zig/buffer-methods.zig +215 -0
- package/src/zig/buffer.zig +2515 -0
- package/src/zig/build.zig +700 -0
- package/src/zig/build.zig.zon +19 -0
- package/src/zig/edit-buffer.zig +900 -0
- package/src/zig/editor-view.zig +812 -0
- package/src/zig/event-bus.zig +28 -0
- package/src/zig/event-emitter.zig +65 -0
- package/src/zig/file-logger.zig +92 -0
- package/src/zig/grapheme.zig +838 -0
- package/src/zig/handles.zig +267 -0
- package/src/zig/lib.zig +2813 -0
- package/src/zig/link.zig +349 -0
- package/src/zig/logger.zig +43 -0
- package/src/zig/mem-registry.zig +126 -0
- package/src/zig/miniaudio_shim.c +21 -0
- package/src/zig/native-renderable.zig +112 -0
- package/src/zig/native-span-feed-bench-lib.zig +7 -0
- package/src/zig/native-span-feed.zig +747 -0
- package/src/zig/renderer-output.zig +677 -0
- package/src/zig/renderer.zig +2106 -0
- package/src/zig/rope.zig +1220 -0
- package/src/zig/split-scrollback.zig +88 -0
- package/src/zig/syntax-style.zig +174 -0
- package/src/zig/terminal.zig +1652 -0
- package/src/zig/test.zig +82 -0
- package/src/zig/tests/README.md +18 -0
- package/src/zig/tests/ansi_test.zig +18 -0
- package/src/zig/tests/audio_test.zig +439 -0
- package/src/zig/tests/buffer-methods_test.zig +1111 -0
- package/src/zig/tests/buffer_test.zig +2926 -0
- package/src/zig/tests/edit-buffer-history_test.zig +299 -0
- package/src/zig/tests/edit-buffer_test.zig +1688 -0
- package/src/zig/tests/editor-view_test.zig +3454 -0
- package/src/zig/tests/event-emitter_test.zig +249 -0
- package/src/zig/tests/grapheme_test.zig +1329 -0
- package/src/zig/tests/handles_test.zig +123 -0
- package/src/zig/tests/link_test.zig +220 -0
- package/src/zig/tests/mem-registry_test.zig +473 -0
- package/src/zig/tests/memory_leak_regression_test.zig +234 -0
- package/src/zig/tests/native-renderable_test.zig +16 -0
- package/src/zig/tests/native-span-feed_test.zig +1266 -0
- package/src/zig/tests/renderer_test.zig +2604 -0
- package/src/zig/tests/rope-nested_test.zig +712 -0
- package/src/zig/tests/rope_fuzz_test.zig +238 -0
- package/src/zig/tests/rope_test.zig +2362 -0
- package/src/zig/tests/segment-merge.test.zig +148 -0
- package/src/zig/tests/split-scrollback_test.zig +70 -0
- package/src/zig/tests/syntax-style_test.zig +558 -0
- package/src/zig/tests/terminal_test.zig +1489 -0
- package/src/zig/tests/test-renderer.zig +126 -0
- package/src/zig/tests/text-buffer-drawing_test.zig +3291 -0
- package/src/zig/tests/text-buffer-highlights_test.zig +706 -0
- package/src/zig/tests/text-buffer-iterators_test.zig +776 -0
- package/src/zig/tests/text-buffer-segment_test.zig +320 -0
- package/src/zig/tests/text-buffer-selection_test.zig +1056 -0
- package/src/zig/tests/text-buffer-selection_viewport_test.zig +358 -0
- package/src/zig/tests/text-buffer-view_test.zig +3672 -0
- package/src/zig/tests/text-buffer_test.zig +2191 -0
- package/src/zig/tests/unicode-width-map.zon +3909 -0
- package/src/zig/tests/utf8_no_zwj_test.zig +260 -0
- package/src/zig/tests/utf8_test.zig +4060 -0
- package/src/zig/tests/utf8_wcwidth_cursor_test.zig +267 -0
- package/src/zig/tests/utf8_wcwidth_test.zig +357 -0
- package/src/zig/tests/word-wrap-editing_test.zig +498 -0
- package/src/zig/tests/wrap-cache-perf_test.zig +113 -0
- package/src/zig/tests/yoga_test.zig +65 -0
- package/src/zig/text-buffer-iterators.zig +496 -0
- package/src/zig/text-buffer-segment.zig +403 -0
- package/src/zig/text-buffer-view.zig +1428 -0
- package/src/zig/text-buffer.zig +1272 -0
- package/src/zig/utf8.zig +1954 -0
- package/src/zig/utils.zig +12 -0
- package/src/zig/uucode-stub.zig +76 -0
- package/src/zig/vendor/miniaudio/miniaudio.h +93468 -0
- package/src/zig/yoga.zig +658 -0
- package/src/zig-structs.ts +381 -0
- package/src/zig.ts +5260 -0
- package/tsconfig.build.json +17 -0
- package/tsconfig.json +27 -0
- package/tsconfig.node-test.json +138 -0
package/src/zig/test.zig
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Import all test modules
|
|
2
|
+
const text_buffer_tests = @import("tests/text-buffer_test.zig");
|
|
3
|
+
const text_buffer_highlights_tests = @import("tests/text-buffer-highlights_test.zig");
|
|
4
|
+
const text_buffer_view_tests = @import("tests/text-buffer-view_test.zig");
|
|
5
|
+
const text_buffer_selection_tests = @import("tests/text-buffer-selection_test.zig");
|
|
6
|
+
const text_buffer_drawing_tests = @import("tests/text-buffer-drawing_test.zig");
|
|
7
|
+
const text_buffer_segment_tests = @import("tests/text-buffer-segment_test.zig");
|
|
8
|
+
const text_buffer_iterators_tests = @import("tests/text-buffer-iterators_test.zig");
|
|
9
|
+
const edit_buffer_tests = @import("tests/edit-buffer_test.zig");
|
|
10
|
+
const edit_buffer_history_tests = @import("tests/edit-buffer-history_test.zig");
|
|
11
|
+
const editor_view_tests = @import("tests/editor-view_test.zig");
|
|
12
|
+
const grapheme_tests = @import("tests/grapheme_test.zig");
|
|
13
|
+
const link_tests = @import("tests/link_test.zig");
|
|
14
|
+
const syntax_style_tests = @import("tests/syntax-style_test.zig");
|
|
15
|
+
const rope_tests = @import("tests/rope_test.zig");
|
|
16
|
+
const rope_nested_tests = @import("tests/rope-nested_test.zig");
|
|
17
|
+
const rope_fuzz_tests = @import("tests/rope_fuzz_test.zig");
|
|
18
|
+
const utf8_tests = @import("tests/utf8_test.zig");
|
|
19
|
+
const utf8_wcwidth_tests = @import("tests/utf8_wcwidth_test.zig");
|
|
20
|
+
const utf8_wcwidth_cursor_tests = @import("tests/utf8_wcwidth_cursor_test.zig");
|
|
21
|
+
const utf8_no_zwj_tests = @import("tests/utf8_no_zwj_test.zig");
|
|
22
|
+
const event_emitter_tests = @import("tests/event-emitter_test.zig");
|
|
23
|
+
const buffer_tests = @import("tests/buffer_test.zig");
|
|
24
|
+
const segment_merge_tests = @import("tests/segment-merge.test.zig");
|
|
25
|
+
const word_wrap_editing_tests = @import("tests/word-wrap-editing_test.zig");
|
|
26
|
+
const renderer_tests = @import("tests/renderer_test.zig");
|
|
27
|
+
const terminal_tests = @import("tests/terminal_test.zig");
|
|
28
|
+
const mem_registry_tests = @import("tests/mem-registry_test.zig");
|
|
29
|
+
const memory_leak_regression_tests = @import("tests/memory_leak_regression_test.zig");
|
|
30
|
+
const wrap_cache_perf_tests = @import("tests/wrap-cache-perf_test.zig");
|
|
31
|
+
const native_span_feed_tests = @import("tests/native-span-feed_test.zig");
|
|
32
|
+
const native_renderable_tests = @import("tests/native-renderable_test.zig");
|
|
33
|
+
const buffer_methods_tests = @import("tests/buffer-methods_test.zig");
|
|
34
|
+
const split_scrollback_tests = @import("tests/split-scrollback_test.zig");
|
|
35
|
+
const audio_tests = @import("tests/audio_test.zig");
|
|
36
|
+
const handles_tests = @import("tests/handles_test.zig");
|
|
37
|
+
const yoga_tests = @import("tests/yoga_test.zig");
|
|
38
|
+
const ansi_tests = @import("tests/ansi_test.zig");
|
|
39
|
+
// const example_tests = @import("example_test.zig");
|
|
40
|
+
|
|
41
|
+
// Re-export test declarations from individual test files
|
|
42
|
+
// This allows `zig test index.zig` to run all tests
|
|
43
|
+
comptime {
|
|
44
|
+
_ = text_buffer_tests;
|
|
45
|
+
_ = text_buffer_highlights_tests;
|
|
46
|
+
_ = text_buffer_view_tests;
|
|
47
|
+
_ = text_buffer_selection_tests;
|
|
48
|
+
_ = text_buffer_drawing_tests;
|
|
49
|
+
_ = text_buffer_segment_tests;
|
|
50
|
+
_ = text_buffer_iterators_tests;
|
|
51
|
+
_ = edit_buffer_tests;
|
|
52
|
+
_ = edit_buffer_history_tests;
|
|
53
|
+
_ = editor_view_tests;
|
|
54
|
+
_ = grapheme_tests;
|
|
55
|
+
_ = link_tests;
|
|
56
|
+
_ = syntax_style_tests;
|
|
57
|
+
_ = rope_tests;
|
|
58
|
+
_ = rope_nested_tests;
|
|
59
|
+
_ = rope_fuzz_tests;
|
|
60
|
+
_ = utf8_tests;
|
|
61
|
+
_ = utf8_wcwidth_tests;
|
|
62
|
+
_ = utf8_wcwidth_cursor_tests;
|
|
63
|
+
_ = utf8_no_zwj_tests;
|
|
64
|
+
_ = event_emitter_tests;
|
|
65
|
+
_ = buffer_tests;
|
|
66
|
+
_ = segment_merge_tests;
|
|
67
|
+
_ = word_wrap_editing_tests;
|
|
68
|
+
_ = renderer_tests;
|
|
69
|
+
_ = terminal_tests;
|
|
70
|
+
_ = mem_registry_tests;
|
|
71
|
+
_ = memory_leak_regression_tests;
|
|
72
|
+
_ = wrap_cache_perf_tests;
|
|
73
|
+
_ = native_span_feed_tests;
|
|
74
|
+
_ = native_renderable_tests;
|
|
75
|
+
_ = buffer_methods_tests;
|
|
76
|
+
_ = split_scrollback_tests;
|
|
77
|
+
_ = audio_tests;
|
|
78
|
+
_ = handles_tests;
|
|
79
|
+
_ = yoga_tests;
|
|
80
|
+
_ = ansi_tests;
|
|
81
|
+
// _ = example_tests;
|
|
82
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Test Suite
|
|
2
|
+
|
|
3
|
+
This directory contains the test suite for the OpenTUI Zig components.
|
|
4
|
+
|
|
5
|
+
### Run all tests:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
zig build test --summary all
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Adding New Test Files
|
|
12
|
+
|
|
13
|
+
1. Create a new `*_test.zig` file in this directory
|
|
14
|
+
2. Import it in `../index.zig`:
|
|
15
|
+
```zig
|
|
16
|
+
const new_tests = @import("new_test.zig");
|
|
17
|
+
```
|
|
18
|
+
3. Update the build system if needed to include any new dependencies
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const std = @import("std");
|
|
2
|
+
|
|
3
|
+
const ansi = @import("../ansi.zig");
|
|
4
|
+
|
|
5
|
+
test "fallbackAnsi256Color returns base, cube, and grayscale colors" {
|
|
6
|
+
try std.testing.expectEqual(@as(u32, 0xff0000), ansi.rgbaToRgb24(ansi.fallbackAnsi256Color(9)));
|
|
7
|
+
try std.testing.expectEqual(@as(u32, 0x0000ff), ansi.rgbaToRgb24(ansi.fallbackAnsi256Color(21)));
|
|
8
|
+
try std.testing.expectEqual(@as(u32, 0x080808), ansi.rgbaToRgb24(ansi.fallbackAnsi256Color(232)));
|
|
9
|
+
try std.testing.expectEqual(@as(u32, 0xeeeeee), ansi.rgbaToRgb24(ansi.fallbackAnsi256Color(255)));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
test "packed RGBA stores metadata" {
|
|
13
|
+
const color = ansi.indexedColor(9, 255, 0, 0);
|
|
14
|
+
|
|
15
|
+
try std.testing.expectEqual(@as(u8, 255), ansi.red(color));
|
|
16
|
+
try std.testing.expectEqual(@as(u8, 9), ansi.slot(color));
|
|
17
|
+
try std.testing.expectEqual(ansi.ColorIntent.indexed, ansi.intent(color));
|
|
18
|
+
}
|
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
const std = @import("std");
|
|
2
|
+
const testing = std.testing;
|
|
3
|
+
const audio = @import("../audio.zig");
|
|
4
|
+
|
|
5
|
+
const TEST_SAMPLE_RATE: u32 = 48_000;
|
|
6
|
+
|
|
7
|
+
fn expectStatusOk(status: i32) !void {
|
|
8
|
+
try testing.expectEqual(audio.Status.ok, status);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
fn createEngine(options_ptr: ?*const audio.CreateOptions) !*audio.Engine {
|
|
12
|
+
return audio.create(testing.allocator, options_ptr) orelse error.TestUnexpectedResult;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
fn buildPcm16Wav(allocator: std.mem.Allocator, channels: u16, sample_rate: u32, samples: []const i16) ![]u8 {
|
|
16
|
+
if (channels == 0 or samples.len == 0) return error.InvalidInput;
|
|
17
|
+
if (samples.len % @as(usize, channels) != 0) return error.InvalidInput;
|
|
18
|
+
|
|
19
|
+
const bytes_per_sample: usize = @sizeOf(i16);
|
|
20
|
+
const data_size = try std.math.mul(usize, samples.len, bytes_per_sample);
|
|
21
|
+
const total_size = 44 + data_size;
|
|
22
|
+
|
|
23
|
+
const out = try allocator.alloc(u8, total_size);
|
|
24
|
+
var stream = std.io.fixedBufferStream(out);
|
|
25
|
+
const writer = stream.writer();
|
|
26
|
+
|
|
27
|
+
const channels_u32: u32 = channels;
|
|
28
|
+
const byte_rate: u32 = sample_rate * channels_u32 * 2;
|
|
29
|
+
const block_align: u16 = channels * 2;
|
|
30
|
+
|
|
31
|
+
try writer.writeAll("RIFF");
|
|
32
|
+
try writer.writeInt(u32, @intCast(total_size - 8), .little);
|
|
33
|
+
try writer.writeAll("WAVE");
|
|
34
|
+
try writer.writeAll("fmt ");
|
|
35
|
+
try writer.writeInt(u32, 16, .little);
|
|
36
|
+
try writer.writeInt(u16, 1, .little);
|
|
37
|
+
try writer.writeInt(u16, channels, .little);
|
|
38
|
+
try writer.writeInt(u32, sample_rate, .little);
|
|
39
|
+
try writer.writeInt(u32, byte_rate, .little);
|
|
40
|
+
try writer.writeInt(u16, block_align, .little);
|
|
41
|
+
try writer.writeInt(u16, 16, .little);
|
|
42
|
+
try writer.writeAll("data");
|
|
43
|
+
try writer.writeInt(u32, @intCast(data_size), .little);
|
|
44
|
+
|
|
45
|
+
for (samples) |sample| {
|
|
46
|
+
try writer.writeInt(i16, sample, .little);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return out;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fn loadSoundFromSamples(engine: *audio.Engine, channels: u16, samples: []const i16) !u32 {
|
|
53
|
+
const wav = try buildPcm16Wav(testing.allocator, channels, TEST_SAMPLE_RATE, samples);
|
|
54
|
+
defer testing.allocator.free(wav);
|
|
55
|
+
|
|
56
|
+
var sound_id: u32 = 0;
|
|
57
|
+
try expectStatusOk(audio.load(engine, wav.ptr, wav.len, &sound_id));
|
|
58
|
+
try testing.expect(sound_id > 0);
|
|
59
|
+
return sound_id;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
fn createGroup(engine: *audio.Engine, name: []const u8) !u32 {
|
|
63
|
+
var group_id: u32 = 0;
|
|
64
|
+
try expectStatusOk(audio.createGroup(engine, name.ptr, name.len, &group_id));
|
|
65
|
+
return group_id;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
fn playLoop(engine: *audio.Engine, sound_id: u32, group_id: u32, pan: f32) !u32 {
|
|
69
|
+
var voice_id: u32 = 0;
|
|
70
|
+
const options = audio.VoiceOptions{
|
|
71
|
+
.volume = 0.8,
|
|
72
|
+
.pan = pan,
|
|
73
|
+
.loop = true,
|
|
74
|
+
.group_id = group_id,
|
|
75
|
+
};
|
|
76
|
+
try expectStatusOk(audio.play(engine, sound_id, &options, &voice_id));
|
|
77
|
+
try testing.expect(voice_id > 0);
|
|
78
|
+
return voice_id;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
fn hasSignal(samples: []const f32) bool {
|
|
82
|
+
for (samples) |sample| {
|
|
83
|
+
if (@abs(sample) > 0.0005) return true;
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
test "audio - create initializes engine with defaults" {
|
|
89
|
+
const engine = try createEngine(null);
|
|
90
|
+
defer audio.destroy(engine);
|
|
91
|
+
|
|
92
|
+
try testing.expectEqual(audio.default_sample_rate, engine.sample_rate);
|
|
93
|
+
try testing.expectEqual(@as(u8, 2), engine.output_channels);
|
|
94
|
+
try testing.expect(!engine.started);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
test "audio - create applies custom sample rate and playback channels" {
|
|
98
|
+
var options = audio.CreateOptions{
|
|
99
|
+
.sample_rate = 44_100,
|
|
100
|
+
.playback_channels = 4,
|
|
101
|
+
};
|
|
102
|
+
const engine = try createEngine(&options);
|
|
103
|
+
defer audio.destroy(engine);
|
|
104
|
+
|
|
105
|
+
try testing.expectEqual(@as(u32, 44_100), engine.sample_rate);
|
|
106
|
+
try testing.expectEqual(@as(u8, 4), engine.output_channels);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
test "audio - destroy works after create" {
|
|
110
|
+
const engine = try createEngine(null);
|
|
111
|
+
audio.destroy(engine);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
test "audio - start requires playback device" {
|
|
115
|
+
const engine = try createEngine(null);
|
|
116
|
+
defer audio.destroy(engine);
|
|
117
|
+
|
|
118
|
+
var options = audio.StartOptions{
|
|
119
|
+
.period_size_in_frames = 128,
|
|
120
|
+
.periods = 2,
|
|
121
|
+
.performance_profile = 1,
|
|
122
|
+
.share_mode = 0,
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const status = audio.start(engine, &options);
|
|
126
|
+
if (status == audio.Status.ok) {
|
|
127
|
+
try testing.expect(engine.started);
|
|
128
|
+
try testing.expect(engine.has_device);
|
|
129
|
+
} else {
|
|
130
|
+
try testing.expectEqual(audio.Status.err_device, status);
|
|
131
|
+
try testing.expect(!engine.started);
|
|
132
|
+
try testing.expect(!engine.has_device);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
try expectStatusOk(audio.stop(engine));
|
|
137
|
+
try testing.expect(!engine.started);
|
|
138
|
+
try testing.expect(!engine.has_device);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
test "audio - startMixer enables mixing without playback device" {
|
|
142
|
+
const engine = try createEngine(null);
|
|
143
|
+
defer audio.destroy(engine);
|
|
144
|
+
|
|
145
|
+
try expectStatusOk(audio.startMixer(engine));
|
|
146
|
+
try testing.expect(engine.started);
|
|
147
|
+
try testing.expect(!engine.has_device);
|
|
148
|
+
|
|
149
|
+
try expectStatusOk(audio.stop(engine));
|
|
150
|
+
try testing.expect(!engine.started);
|
|
151
|
+
try testing.expect(!engine.has_device);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
test "audio - load valid wav returns sound id" {
|
|
155
|
+
const engine = try createEngine(null);
|
|
156
|
+
defer audio.destroy(engine);
|
|
157
|
+
|
|
158
|
+
const mono_samples = [_]i16{ 0, 8000, -8000, 12_000, -12_000, 0 };
|
|
159
|
+
const sound_id = try loadSoundFromSamples(engine, 1, &mono_samples);
|
|
160
|
+
try testing.expectEqual(@as(u32, 1), sound_id);
|
|
161
|
+
|
|
162
|
+
var stats: audio.Stats = undefined;
|
|
163
|
+
try expectStatusOk(audio.getStats(engine, &stats));
|
|
164
|
+
try testing.expectEqual(@as(u32, 1), stats.sounds_loaded);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
test "audio - unload frees loaded sound and invalidates handle" {
|
|
168
|
+
const engine = try createEngine(null);
|
|
169
|
+
defer audio.destroy(engine);
|
|
170
|
+
|
|
171
|
+
const mono_samples = [_]i16{ 0, 8000, -8000, 12_000, -12_000, 0 };
|
|
172
|
+
const sound_id = try loadSoundFromSamples(engine, 1, &mono_samples);
|
|
173
|
+
|
|
174
|
+
try expectStatusOk(audio.unload(engine, sound_id));
|
|
175
|
+
|
|
176
|
+
var stats: audio.Stats = undefined;
|
|
177
|
+
try expectStatusOk(audio.getStats(engine, &stats));
|
|
178
|
+
try testing.expectEqual(@as(u32, 0), stats.sounds_loaded);
|
|
179
|
+
|
|
180
|
+
var voice_id: u32 = 0;
|
|
181
|
+
const options = audio.VoiceOptions{ .volume = 1, .pan = 0, .loop = false, .group_id = 0 };
|
|
182
|
+
try testing.expectEqual(audio.Status.err_not_found, audio.play(engine, sound_id, &options, &voice_id));
|
|
183
|
+
try testing.expectEqual(audio.Status.err_not_found, audio.unload(engine, sound_id));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
test "audio - unload stops active voices for sound" {
|
|
187
|
+
const engine = try createEngine(null);
|
|
188
|
+
defer audio.destroy(engine);
|
|
189
|
+
|
|
190
|
+
const mono_samples = [_]i16{ 2000, -2000, 4000, -4000, 2000, -2000 };
|
|
191
|
+
const sound_id = try loadSoundFromSamples(engine, 1, &mono_samples);
|
|
192
|
+
try expectStatusOk(audio.startMixer(engine));
|
|
193
|
+
|
|
194
|
+
const voice_id = try playLoop(engine, sound_id, 0, 0);
|
|
195
|
+
try testing.expect(engine.voices[voice_id - 1].active);
|
|
196
|
+
|
|
197
|
+
try expectStatusOk(audio.unload(engine, sound_id));
|
|
198
|
+
try testing.expect(!engine.voices[voice_id - 1].active);
|
|
199
|
+
|
|
200
|
+
var stats: audio.Stats = undefined;
|
|
201
|
+
try expectStatusOk(audio.getStats(engine, &stats));
|
|
202
|
+
try testing.expectEqual(@as(u32, 0), stats.sounds_loaded);
|
|
203
|
+
try testing.expectEqual(@as(u32, 0), stats.voices_active);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
test "audio - unloaded sound id is not reused by later loads" {
|
|
207
|
+
const engine = try createEngine(null);
|
|
208
|
+
defer audio.destroy(engine);
|
|
209
|
+
|
|
210
|
+
const first_samples = [_]i16{ 0, 8000, -8000, 0 };
|
|
211
|
+
const first_sound_id = try loadSoundFromSamples(engine, 1, &first_samples);
|
|
212
|
+
try expectStatusOk(audio.unload(engine, first_sound_id));
|
|
213
|
+
|
|
214
|
+
const second_samples = [_]i16{ 1000, -1000, 5000, -5000 };
|
|
215
|
+
const second_sound_id = try loadSoundFromSamples(engine, 1, &second_samples);
|
|
216
|
+
try testing.expect(second_sound_id != first_sound_id);
|
|
217
|
+
|
|
218
|
+
try expectStatusOk(audio.startMixer(engine));
|
|
219
|
+
|
|
220
|
+
var voice_id: u32 = 0;
|
|
221
|
+
const options = audio.VoiceOptions{ .volume = 1, .pan = 0, .loop = false, .group_id = 0 };
|
|
222
|
+
try testing.expectEqual(audio.Status.err_not_found, audio.play(engine, first_sound_id, &options, &voice_id));
|
|
223
|
+
try expectStatusOk(audio.play(engine, second_sound_id, &options, &voice_id));
|
|
224
|
+
try testing.expect(voice_id > 0);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
test "audio - createGroup creates and deduplicates group" {
|
|
228
|
+
const engine = try createEngine(null);
|
|
229
|
+
defer audio.destroy(engine);
|
|
230
|
+
|
|
231
|
+
const first = try createGroup(engine, "effects");
|
|
232
|
+
const second = try createGroup(engine, "effects");
|
|
233
|
+
try testing.expectEqual(first, second);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
test "audio - play valid sound returns voice id" {
|
|
237
|
+
const engine = try createEngine(null);
|
|
238
|
+
defer audio.destroy(engine);
|
|
239
|
+
|
|
240
|
+
const mono_samples = [_]i16{ 3000, -3000, 6000, -6000, 3000, -3000 };
|
|
241
|
+
const sound_id = try loadSoundFromSamples(engine, 1, &mono_samples);
|
|
242
|
+
try expectStatusOk(audio.startMixer(engine));
|
|
243
|
+
|
|
244
|
+
var voice_id: u32 = 0;
|
|
245
|
+
const options = audio.VoiceOptions{ .volume = 1, .pan = 0, .loop = true, .group_id = 0 };
|
|
246
|
+
try expectStatusOk(audio.play(engine, sound_id, &options, &voice_id));
|
|
247
|
+
try testing.expect(voice_id > 0);
|
|
248
|
+
try testing.expect(engine.voices[voice_id - 1].active);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
test "audio - stopVoice stops active voice" {
|
|
252
|
+
const engine = try createEngine(null);
|
|
253
|
+
defer audio.destroy(engine);
|
|
254
|
+
|
|
255
|
+
const mono_samples = [_]i16{ 2000, -2000, 4000, -4000, 2000, -2000 };
|
|
256
|
+
const sound_id = try loadSoundFromSamples(engine, 1, &mono_samples);
|
|
257
|
+
try expectStatusOk(audio.startMixer(engine));
|
|
258
|
+
|
|
259
|
+
const voice_id = try playLoop(engine, sound_id, 0, 0);
|
|
260
|
+
try expectStatusOk(audio.stopVoice(engine, voice_id));
|
|
261
|
+
try testing.expect(!engine.voices[voice_id - 1].active);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
test "audio - setVoiceGroup moves voice between groups" {
|
|
265
|
+
const engine = try createEngine(null);
|
|
266
|
+
defer audio.destroy(engine);
|
|
267
|
+
|
|
268
|
+
const mono_samples = [_]i16{ 1500, -1500, 5000, -5000, 1500, -1500 };
|
|
269
|
+
const sound_id = try loadSoundFromSamples(engine, 1, &mono_samples);
|
|
270
|
+
const group_a = try createGroup(engine, "group-a");
|
|
271
|
+
const group_b = try createGroup(engine, "group-b");
|
|
272
|
+
try expectStatusOk(audio.startMixer(engine));
|
|
273
|
+
|
|
274
|
+
const voice_id = try playLoop(engine, sound_id, group_a, 0);
|
|
275
|
+
try expectStatusOk(audio.setVoiceGroup(engine, voice_id, group_b));
|
|
276
|
+
try testing.expectEqual(group_b, engine.voices[voice_id - 1].group_id);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
test "audio - setGroupVolume applies clamped volume" {
|
|
280
|
+
const engine = try createEngine(null);
|
|
281
|
+
defer audio.destroy(engine);
|
|
282
|
+
|
|
283
|
+
const group_id = try createGroup(engine, "mix-group");
|
|
284
|
+
try expectStatusOk(audio.setGroupVolume(engine, group_id, 2.5));
|
|
285
|
+
try testing.expectApproxEqAbs(@as(f32, 2.5), engine.groups.items[group_id].volume, 0.0001);
|
|
286
|
+
|
|
287
|
+
try expectStatusOk(audio.setGroupVolume(engine, group_id, 8));
|
|
288
|
+
try testing.expectApproxEqAbs(@as(f32, 4), engine.groups.items[group_id].volume, 0.0001);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
test "audio - setMasterVolume applies clamped volume" {
|
|
292
|
+
const engine = try createEngine(null);
|
|
293
|
+
defer audio.destroy(engine);
|
|
294
|
+
|
|
295
|
+
try expectStatusOk(audio.setMasterVolume(engine, 1.7));
|
|
296
|
+
try testing.expectApproxEqAbs(@as(f32, 1.7), engine.master_volume, 0.0001);
|
|
297
|
+
|
|
298
|
+
try expectStatusOk(audio.setMasterVolume(engine, -3));
|
|
299
|
+
try testing.expectApproxEqAbs(@as(f32, 0), engine.master_volume, 0.0001);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
test "audio - mixToBuffer returns mixed samples" {
|
|
303
|
+
const engine = try createEngine(null);
|
|
304
|
+
defer audio.destroy(engine);
|
|
305
|
+
|
|
306
|
+
const mono_samples = [_]i16{ 4000, -2000, 7000, -7000, 5000, -3000 };
|
|
307
|
+
const sound_id = try loadSoundFromSamples(engine, 1, &mono_samples);
|
|
308
|
+
try expectStatusOk(audio.startMixer(engine));
|
|
309
|
+
_ = try playLoop(engine, sound_id, 0, 0.2);
|
|
310
|
+
|
|
311
|
+
var out: [128]f32 = [_]f32{0} ** 128;
|
|
312
|
+
try expectStatusOk(audio.mixToBuffer(engine, out[0..].ptr, 64, 2));
|
|
313
|
+
try testing.expect(hasSignal(&out));
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
test "audio - mixToBuffer mono downmix averages stereo" {
|
|
317
|
+
const stereo_engine = try createEngine(null);
|
|
318
|
+
defer audio.destroy(stereo_engine);
|
|
319
|
+
const mono_engine = try createEngine(null);
|
|
320
|
+
defer audio.destroy(mono_engine);
|
|
321
|
+
|
|
322
|
+
const mono_samples = [_]i16{ 5000, -2000, 8000, -8000, 5000, -2000 };
|
|
323
|
+
const stereo_sound_id = try loadSoundFromSamples(stereo_engine, 1, &mono_samples);
|
|
324
|
+
const mono_sound_id = try loadSoundFromSamples(mono_engine, 1, &mono_samples);
|
|
325
|
+
try expectStatusOk(audio.startMixer(stereo_engine));
|
|
326
|
+
try expectStatusOk(audio.startMixer(mono_engine));
|
|
327
|
+
|
|
328
|
+
_ = try playLoop(stereo_engine, stereo_sound_id, 0, 0.7);
|
|
329
|
+
_ = try playLoop(mono_engine, mono_sound_id, 0, 0.7);
|
|
330
|
+
|
|
331
|
+
var stereo_warmup: [64]f32 = [_]f32{0} ** 64;
|
|
332
|
+
var mono_warmup: [32]f32 = [_]f32{0} ** 32;
|
|
333
|
+
try expectStatusOk(audio.mixToBuffer(stereo_engine, stereo_warmup[0..].ptr, 32, 2));
|
|
334
|
+
try expectStatusOk(audio.mixToBuffer(mono_engine, mono_warmup[0..].ptr, 32, 1));
|
|
335
|
+
|
|
336
|
+
var stereo: [128]f32 = [_]f32{0} ** 128;
|
|
337
|
+
var mono: [64]f32 = [_]f32{0} ** 64;
|
|
338
|
+
try expectStatusOk(audio.mixToBuffer(stereo_engine, stereo[0..].ptr, 64, 2));
|
|
339
|
+
try expectStatusOk(audio.mixToBuffer(mono_engine, mono[0..].ptr, 64, 1));
|
|
340
|
+
|
|
341
|
+
for (0..64) |i| {
|
|
342
|
+
const expected = std.math.clamp((stereo[i * 2] + stereo[i * 2 + 1]) * 0.5, -1, 1);
|
|
343
|
+
try testing.expectApproxEqAbs(expected, mono[i], 0.0001);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
test "audio - mixToBuffer multichannel keeps extra channels zero" {
|
|
348
|
+
const engine = try createEngine(null);
|
|
349
|
+
defer audio.destroy(engine);
|
|
350
|
+
|
|
351
|
+
const mono_samples = [_]i16{ 2500, -1500, 7000, -7000, 2500, -1500 };
|
|
352
|
+
const sound_id = try loadSoundFromSamples(engine, 1, &mono_samples);
|
|
353
|
+
try expectStatusOk(audio.startMixer(engine));
|
|
354
|
+
_ = try playLoop(engine, sound_id, 0, 0);
|
|
355
|
+
|
|
356
|
+
var quad: [256]f32 = [_]f32{0} ** 256;
|
|
357
|
+
try expectStatusOk(audio.mixToBuffer(engine, quad[0..].ptr, 64, 4));
|
|
358
|
+
|
|
359
|
+
for (0..64) |frame| {
|
|
360
|
+
const base = frame * 4;
|
|
361
|
+
try testing.expectEqual(@as(f32, 0), quad[base + 2]);
|
|
362
|
+
try testing.expectEqual(@as(f32, 0), quad[base + 3]);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
test "audio - enableTap and readTap return captured frames" {
|
|
367
|
+
const engine = try createEngine(null);
|
|
368
|
+
defer audio.destroy(engine);
|
|
369
|
+
|
|
370
|
+
const mono_samples = [_]i16{ 1000, -1000, 4000, -4000, 1000, -1000 };
|
|
371
|
+
const sound_id = try loadSoundFromSamples(engine, 1, &mono_samples);
|
|
372
|
+
try expectStatusOk(audio.startMixer(engine));
|
|
373
|
+
_ = try playLoop(engine, sound_id, 0, 0.35);
|
|
374
|
+
|
|
375
|
+
try expectStatusOk(audio.enableTap(engine, true, 256));
|
|
376
|
+
|
|
377
|
+
var mixed: [256]f32 = [_]f32{0} ** 256;
|
|
378
|
+
try expectStatusOk(audio.mixToBuffer(engine, mixed[0..].ptr, 128, 2));
|
|
379
|
+
|
|
380
|
+
var tapped: [128]f32 = [_]f32{0} ** 128;
|
|
381
|
+
var frames_read: u32 = 0;
|
|
382
|
+
try expectStatusOk(audio.readTap(engine, tapped[0..].ptr, 64, 2, &frames_read));
|
|
383
|
+
try testing.expect(frames_read > 0);
|
|
384
|
+
try testing.expect(hasSignal(tapped[0 .. @as(usize, frames_read) * 2]));
|
|
385
|
+
|
|
386
|
+
try expectStatusOk(audio.enableTap(engine, false, 0));
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
test "audio - refresh and playback device selection APIs" {
|
|
390
|
+
const engine = try createEngine(null);
|
|
391
|
+
defer audio.destroy(engine);
|
|
392
|
+
|
|
393
|
+
const refresh_status = audio.refreshPlaybackDevices(engine);
|
|
394
|
+
if (refresh_status != audio.Status.ok) return error.SkipZigTest;
|
|
395
|
+
|
|
396
|
+
const count = audio.getPlaybackDeviceCount(engine);
|
|
397
|
+
try testing.expectEqual(@as(u32, @intCast(engine.playback_devices.items.len)), count);
|
|
398
|
+
if (count == 0) return error.SkipZigTest;
|
|
399
|
+
|
|
400
|
+
var name_buf: [256]u8 = [_]u8{0} ** 256;
|
|
401
|
+
const copied = audio.getPlaybackDeviceName(engine, 0, name_buf[0..].ptr, name_buf.len);
|
|
402
|
+
try testing.expect(copied <= name_buf.len);
|
|
403
|
+
|
|
404
|
+
_ = audio.isPlaybackDeviceDefault(engine, 0);
|
|
405
|
+
|
|
406
|
+
try expectStatusOk(audio.selectPlaybackDevice(engine, 0));
|
|
407
|
+
try testing.expectEqual(@as(?u32, 0), engine.selected_playback_index);
|
|
408
|
+
|
|
409
|
+
audio.clearPlaybackDeviceSelection(engine);
|
|
410
|
+
try testing.expectEqual(@as(?u32, null), engine.selected_playback_index);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
test "audio - getStats returns current counters" {
|
|
414
|
+
const engine = try createEngine(null);
|
|
415
|
+
defer audio.destroy(engine);
|
|
416
|
+
|
|
417
|
+
const mono_samples = [_]i16{ 3000, -3000, 9000, -9000, 3000, -3000 };
|
|
418
|
+
const sound_id = try loadSoundFromSamples(engine, 1, &mono_samples);
|
|
419
|
+
|
|
420
|
+
var before: audio.Stats = undefined;
|
|
421
|
+
try expectStatusOk(audio.getStats(engine, &before));
|
|
422
|
+
|
|
423
|
+
try expectStatusOk(audio.startMixer(engine));
|
|
424
|
+
const voice_id = try playLoop(engine, sound_id, 0, 0);
|
|
425
|
+
|
|
426
|
+
var out: [128]f32 = [_]f32{0} ** 128;
|
|
427
|
+
try expectStatusOk(audio.mixToBuffer(engine, out[0..].ptr, 64, 2));
|
|
428
|
+
|
|
429
|
+
var after: audio.Stats = undefined;
|
|
430
|
+
try expectStatusOk(audio.getStats(engine, &after));
|
|
431
|
+
|
|
432
|
+
try testing.expectEqual(@as(u32, 1), after.sounds_loaded);
|
|
433
|
+
try testing.expect(after.voices_active >= 1);
|
|
434
|
+
try testing.expect(after.frames_mixed > before.frames_mixed);
|
|
435
|
+
try testing.expect(after.last_peak > 0);
|
|
436
|
+
try testing.expect(after.last_rms > 0);
|
|
437
|
+
|
|
438
|
+
try expectStatusOk(audio.stopVoice(engine, voice_id));
|
|
439
|
+
}
|