buninu 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.bashrc +11 -0
- package/ARCHITECTURE.md +452 -0
- package/LICENSE +21 -0
- package/README.md +121 -0
- package/apps/bun/make-bunBin.sh +84 -0
- package/apps/jsgotty/LICENSE +23 -0
- package/apps/jsgotty/LICENSES/Apache-2.0-zmodem.js.txt +201 -0
- package/apps/jsgotty/NOTICE +21 -0
- package/apps/jsgotty/README.en.md +290 -0
- package/apps/jsgotty/README.md +292 -0
- package/apps/jsgotty/client.mjs +700 -0
- package/apps/jsgotty/env.sh +2 -0
- package/apps/jsgotty/gotty.js +3325 -0
- package/apps/jsgotty/node_modules/.package-lock.json +35 -0
- package/apps/jsgotty/node_modules/node-addon-api/LICENSE.md +9 -0
- package/apps/jsgotty/node_modules/node-addon-api/README.md +319 -0
- package/apps/jsgotty/node_modules/node-addon-api/common.gypi +20 -0
- package/apps/jsgotty/node_modules/node-addon-api/except.gypi +25 -0
- package/apps/jsgotty/node_modules/node-addon-api/index.js +12 -0
- package/apps/jsgotty/node_modules/node-addon-api/napi-inl.deprecated.h +186 -0
- package/apps/jsgotty/node_modules/node-addon-api/napi-inl.h +6607 -0
- package/apps/jsgotty/node_modules/node-addon-api/napi.h +3201 -0
- package/apps/jsgotty/node_modules/node-addon-api/node_addon_api.gyp +32 -0
- package/apps/jsgotty/node_modules/node-addon-api/node_api.gyp +9 -0
- package/apps/jsgotty/node_modules/node-addon-api/noexcept.gypi +26 -0
- package/apps/jsgotty/node_modules/node-addon-api/nothing.c +0 -0
- package/apps/jsgotty/node_modules/node-addon-api/package-support.json +21 -0
- package/apps/jsgotty/node_modules/node-addon-api/package.json +480 -0
- package/apps/jsgotty/node_modules/node-addon-api/tools/README.md +73 -0
- package/apps/jsgotty/node_modules/node-addon-api/tools/check-napi.js +99 -0
- package/apps/jsgotty/node_modules/node-addon-api/tools/clang-format.js +71 -0
- package/apps/jsgotty/node_modules/node-addon-api/tools/conversion.js +301 -0
- package/apps/jsgotty/node_modules/node-addon-api/tools/eslint-format.js +79 -0
- package/apps/jsgotty/node_modules/ws/LICENSE +20 -0
- package/apps/jsgotty/node_modules/ws/README.md +548 -0
- package/apps/jsgotty/node_modules/ws/browser.js +8 -0
- package/apps/jsgotty/node_modules/ws/index.js +22 -0
- package/apps/jsgotty/node_modules/ws/lib/buffer-util.js +131 -0
- package/apps/jsgotty/node_modules/ws/lib/constants.js +19 -0
- package/apps/jsgotty/node_modules/ws/lib/event-target.js +292 -0
- package/apps/jsgotty/node_modules/ws/lib/extension.js +203 -0
- package/apps/jsgotty/node_modules/ws/lib/limiter.js +55 -0
- package/apps/jsgotty/node_modules/ws/lib/permessage-deflate.js +528 -0
- package/apps/jsgotty/node_modules/ws/lib/receiver.js +760 -0
- package/apps/jsgotty/node_modules/ws/lib/sender.js +607 -0
- package/apps/jsgotty/node_modules/ws/lib/stream.js +161 -0
- package/apps/jsgotty/node_modules/ws/lib/subprotocol.js +62 -0
- package/apps/jsgotty/node_modules/ws/lib/validation.js +152 -0
- package/apps/jsgotty/node_modules/ws/lib/websocket-server.js +562 -0
- package/apps/jsgotty/node_modules/ws/lib/websocket.js +1407 -0
- package/apps/jsgotty/node_modules/ws/package.json +70 -0
- package/apps/jsgotty/node_modules/ws/wrapper.mjs +21 -0
- package/apps/jsgotty/package-lock.json +46 -0
- package/apps/jsgotty/package.json +13 -0
- package/apps/jsgotty/patches/windowsPtyAgent.js +326 -0
- package/apps/jsgotty/patches/windowsTerminal.js +204 -0
- package/apps/jsgotty/rz.js +199 -0
- package/apps/jsgotty/single-exe/README.md +80 -0
- package/apps/jsgotty/single-exe/assetsHelper.js +90 -0
- package/apps/jsgotty/single-exe/assetsLoader.mjs +85 -0
- package/apps/jsgotty/single-exe/compiled.js +138 -0
- package/apps/jsgotty/single-exe/entry.mjs +9 -0
- package/apps/jsgotty/single-exe/packAssets.sh +7 -0
- package/apps/jsgotty/static/css/index.css +13 -0
- package/apps/jsgotty/static/css/kitty.css +61 -0
- package/apps/jsgotty/static/css/xterm.css +218 -0
- package/apps/jsgotty/static/css/xterm_customize.css +32 -0
- package/apps/jsgotty/static/favicon.ico +0 -0
- package/apps/jsgotty/static/help.md +125 -0
- package/apps/jsgotty/static/icon.svg +66 -0
- package/apps/jsgotty/static/icon_192.png +0 -0
- package/apps/jsgotty/static/index.html +164 -0
- package/apps/jsgotty/static/js/gotty.js +31537 -0
- package/apps/jsgotty/static/js/gotty.js.LICENSE.txt +7 -0
- package/apps/jsgotty/static/js/gotty.js.map +1 -0
- package/apps/jsgotty/static/js/gotty.licenses.txt +650 -0
- package/apps/jsgotty/static/js/kitty.js +1045 -0
- package/apps/jsgotty/static/js/windows_bridge.js +194 -0
- package/apps/jsgotty/static/js/xterm-addon-unicode11.js +2 -0
- package/apps/jsgotty/static/js/zmodem.js +1 -0
- package/apps/jsgotty/static/manifest.json +15 -0
- package/apps/jsgotty/sz.js +273 -0
- package/apps/jsgotty/tests/kitty-order.test.js +58 -0
- package/apps/jsgotty/viu.mjs +393 -0
- package/apps/jsgotty/wgotty +62 -0
- package/apps/jsgotty/windows-bridge-node.js +60 -0
- package/apps/jsgotty/zmodem-node.js +260 -0
- package/apps/jsmdcui/CHANGELOG.md +1048 -0
- package/apps/jsmdcui/LICENSE +22 -0
- package/apps/jsmdcui/README.md +1269 -0
- package/apps/jsmdcui/cdp-maze.js +141 -0
- package/apps/jsmdcui/clean.sh +9 -0
- package/apps/jsmdcui/demos/basic.jpg +0 -0
- package/apps/jsmdcui/demos/chinese.md +32 -0
- package/apps/jsmdcui/demos/event.md +170 -0
- package/apps/jsmdcui/demos/good.jpg +0 -0
- package/apps/jsmdcui/demos/image-processor.md +366 -0
- package/apps/jsmdcui/demos/image-processor.zh-TW.md +366 -0
- package/apps/jsmdcui/demos/img-change.md +73 -0
- package/apps/jsmdcui/demos/imgtool-zh.md +298 -0
- package/apps/jsmdcui/demos/imgtool.md +298 -0
- package/apps/jsmdcui/demos/maze.md +149 -0
- package/apps/jsmdcui/demos/reactive.md +40 -0
- package/apps/jsmdcui/demos/reader.md +513 -0
- package/apps/jsmdcui/demos/select.md +63 -0
- package/apps/jsmdcui/demos/todo-zh.md +190 -0
- package/apps/jsmdcui/demos/todo.md +191 -0
- package/apps/jsmdcui/edit +9 -0
- package/apps/jsmdcui/jsmdcui.sh +5 -0
- package/apps/jsmdcui/llm-maze.txt +94 -0
- package/apps/jsmdcui/package.json +19 -0
- package/apps/jsmdcui/project_structure.txt +35 -0
- package/apps/jsmdcui/runmd.mjs +1140 -0
- package/apps/jsmdcui/runtime/colorschemes/atom-dark.micro +33 -0
- package/apps/jsmdcui/runtime/colorschemes/bubblegum.micro +31 -0
- package/apps/jsmdcui/runtime/colorschemes/cmc-16.micro +47 -0
- package/apps/jsmdcui/runtime/colorschemes/cmc-tc.micro +43 -0
- package/apps/jsmdcui/runtime/colorschemes/darcula.micro +34 -0
- package/apps/jsmdcui/runtime/colorschemes/default.micro +1 -0
- package/apps/jsmdcui/runtime/colorschemes/dracula-tc.micro +49 -0
- package/apps/jsmdcui/runtime/colorschemes/dukedark-tc.micro +38 -0
- package/apps/jsmdcui/runtime/colorschemes/dukelight-tc.micro +38 -0
- package/apps/jsmdcui/runtime/colorschemes/dukeubuntu-tc.micro +38 -0
- package/apps/jsmdcui/runtime/colorschemes/geany.micro +29 -0
- package/apps/jsmdcui/runtime/colorschemes/gotham.micro +29 -0
- package/apps/jsmdcui/runtime/colorschemes/gruvbox-tc.micro +29 -0
- package/apps/jsmdcui/runtime/colorschemes/gruvbox.micro +26 -0
- package/apps/jsmdcui/runtime/colorschemes/material-tc.micro +36 -0
- package/apps/jsmdcui/runtime/colorschemes/monokai-dark.micro +28 -0
- package/apps/jsmdcui/runtime/colorschemes/monokai.micro +34 -0
- package/apps/jsmdcui/runtime/colorschemes/one-dark.micro +39 -0
- package/apps/jsmdcui/runtime/colorschemes/railscast.micro +37 -0
- package/apps/jsmdcui/runtime/colorschemes/simple.micro +33 -0
- package/apps/jsmdcui/runtime/colorschemes/solarized-tc.micro +31 -0
- package/apps/jsmdcui/runtime/colorschemes/solarized.micro +30 -0
- package/apps/jsmdcui/runtime/colorschemes/sunny-day.micro +29 -0
- package/apps/jsmdcui/runtime/colorschemes/twilight.micro +40 -0
- package/apps/jsmdcui/runtime/colorschemes/zenburn.micro +30 -0
- package/apps/jsmdcui/runtime/help/actions.md +161 -0
- package/apps/jsmdcui/runtime/help/cdp.md +124 -0
- package/apps/jsmdcui/runtime/help/colors.md +421 -0
- package/apps/jsmdcui/runtime/help/commands.md +161 -0
- package/apps/jsmdcui/runtime/help/copypaste.md +149 -0
- package/apps/jsmdcui/runtime/help/defaultkeys.md +148 -0
- package/apps/jsmdcui/runtime/help/help.md +1269 -0
- package/apps/jsmdcui/runtime/help/keybindings.md +355 -0
- package/apps/jsmdcui/runtime/help/linter.md +90 -0
- package/apps/jsmdcui/runtime/help/options.md +709 -0
- package/apps/jsmdcui/runtime/help/plugins.md +544 -0
- package/apps/jsmdcui/runtime/help/tutorial.md +112 -0
- package/apps/jsmdcui/runtime/jsplugins/cdp/cdp-server.js +1185 -0
- package/apps/jsmdcui/runtime/jsplugins/cdp/cdp.js +201 -0
- package/apps/jsmdcui/runtime/jsplugins/chapter/chapter.js +111 -0
- package/apps/jsmdcui/runtime/jsplugins/diff/diff.js +46 -0
- package/apps/jsmdcui/runtime/jsplugins/example/example.js +117 -0
- package/apps/jsmdcui/runtime/jsplugins/linter/linter.js +281 -0
- package/apps/jsmdcui/runtime/plugins/autoclose/autoclose.lua +75 -0
- package/apps/jsmdcui/runtime/plugins/ftoptions/ftoptions.lua +17 -0
- package/apps/jsmdcui/runtime/plugins/literate/README.md +5 -0
- package/apps/jsmdcui/runtime/plugins/literate/literate.lua +55 -0
- package/apps/jsmdcui/runtime/plugins/status/help/status.md +21 -0
- package/apps/jsmdcui/runtime/plugins/status/status.lua +62 -0
- package/apps/jsmdcui/runtime/syntax/LICENSE +22 -0
- package/apps/jsmdcui/runtime/syntax/PowerShell.yaml +128 -0
- package/apps/jsmdcui/runtime/syntax/README.md +63 -0
- package/apps/jsmdcui/runtime/syntax/ada.yaml +43 -0
- package/apps/jsmdcui/runtime/syntax/apacheconf.yaml +59 -0
- package/apps/jsmdcui/runtime/syntax/arduino.yaml +101 -0
- package/apps/jsmdcui/runtime/syntax/asciidoc.yaml +51 -0
- package/apps/jsmdcui/runtime/syntax/asm.yaml +123 -0
- package/apps/jsmdcui/runtime/syntax/ats.yaml +99 -0
- package/apps/jsmdcui/runtime/syntax/awk.yaml +44 -0
- package/apps/jsmdcui/runtime/syntax/b.yaml +87 -0
- package/apps/jsmdcui/runtime/syntax/bat.yaml +57 -0
- package/apps/jsmdcui/runtime/syntax/c.yaml +60 -0
- package/apps/jsmdcui/runtime/syntax/caddyfile.yaml +23 -0
- package/apps/jsmdcui/runtime/syntax/cake.yaml +7 -0
- package/apps/jsmdcui/runtime/syntax/clojure.yaml +38 -0
- package/apps/jsmdcui/runtime/syntax/cmake.yaml +42 -0
- package/apps/jsmdcui/runtime/syntax/coffeescript.yaml +56 -0
- package/apps/jsmdcui/runtime/syntax/colortest.yaml +19 -0
- package/apps/jsmdcui/runtime/syntax/conky.yaml +17 -0
- package/apps/jsmdcui/runtime/syntax/cpp.yaml +91 -0
- package/apps/jsmdcui/runtime/syntax/crontab.yaml +36 -0
- package/apps/jsmdcui/runtime/syntax/crystal.yaml +72 -0
- package/apps/jsmdcui/runtime/syntax/csharp.yaml +52 -0
- package/apps/jsmdcui/runtime/syntax/css.yaml +44 -0
- package/apps/jsmdcui/runtime/syntax/csx.yaml +8 -0
- package/apps/jsmdcui/runtime/syntax/cuda.yaml +68 -0
- package/apps/jsmdcui/runtime/syntax/cython.yaml +52 -0
- package/apps/jsmdcui/runtime/syntax/d.yaml +121 -0
- package/apps/jsmdcui/runtime/syntax/dart.yaml +46 -0
- package/apps/jsmdcui/runtime/syntax/default.yaml +10 -0
- package/apps/jsmdcui/runtime/syntax/dockerfile.yaml +36 -0
- package/apps/jsmdcui/runtime/syntax/dot.yaml +29 -0
- package/apps/jsmdcui/runtime/syntax/elixir.yaml +30 -0
- package/apps/jsmdcui/runtime/syntax/elm.yaml +38 -0
- package/apps/jsmdcui/runtime/syntax/erb.yaml +42 -0
- package/apps/jsmdcui/runtime/syntax/erlang.yaml +45 -0
- package/apps/jsmdcui/runtime/syntax/fish.yaml +48 -0
- package/apps/jsmdcui/runtime/syntax/forth.yaml +34 -0
- package/apps/jsmdcui/runtime/syntax/fortran.yaml +64 -0
- package/apps/jsmdcui/runtime/syntax/freebsd-kernel.yaml +14 -0
- package/apps/jsmdcui/runtime/syntax/fsharp.yaml +48 -0
- package/apps/jsmdcui/runtime/syntax/gdscript.yaml +61 -0
- package/apps/jsmdcui/runtime/syntax/gemini.yaml +19 -0
- package/apps/jsmdcui/runtime/syntax/gentoo-ebuild.yaml +48 -0
- package/apps/jsmdcui/runtime/syntax/gentoo-etc-portage.yaml +23 -0
- package/apps/jsmdcui/runtime/syntax/git-commit.yaml +35 -0
- package/apps/jsmdcui/runtime/syntax/git-config.yaml +14 -0
- package/apps/jsmdcui/runtime/syntax/git-rebase-todo.yaml +19 -0
- package/apps/jsmdcui/runtime/syntax/gleam.yaml +69 -0
- package/apps/jsmdcui/runtime/syntax/glsl.yaml +26 -0
- package/apps/jsmdcui/runtime/syntax/gnuplot.yaml +15 -0
- package/apps/jsmdcui/runtime/syntax/go.yaml +62 -0
- package/apps/jsmdcui/runtime/syntax/godoc.yaml +17 -0
- package/apps/jsmdcui/runtime/syntax/golo.yaml +73 -0
- package/apps/jsmdcui/runtime/syntax/gomod.yaml +31 -0
- package/apps/jsmdcui/runtime/syntax/graphql.yaml +47 -0
- package/apps/jsmdcui/runtime/syntax/groff.yaml +30 -0
- package/apps/jsmdcui/runtime/syntax/groovy.yaml +111 -0
- package/apps/jsmdcui/runtime/syntax/haml.yaml +16 -0
- package/apps/jsmdcui/runtime/syntax/hare.yaml +52 -0
- package/apps/jsmdcui/runtime/syntax/haskell.yaml +52 -0
- package/apps/jsmdcui/runtime/syntax/hc.yaml +52 -0
- package/apps/jsmdcui/runtime/syntax/html.yaml +70 -0
- package/apps/jsmdcui/runtime/syntax/html4.yaml +25 -0
- package/apps/jsmdcui/runtime/syntax/html5.yaml +25 -0
- package/apps/jsmdcui/runtime/syntax/ini.yaml +23 -0
- package/apps/jsmdcui/runtime/syntax/inputrc.yaml +14 -0
- package/apps/jsmdcui/runtime/syntax/java.yaml +37 -0
- package/apps/jsmdcui/runtime/syntax/javascript.yaml +124 -0
- package/apps/jsmdcui/runtime/syntax/jinja2.yaml +19 -0
- package/apps/jsmdcui/runtime/syntax/json.yaml +39 -0
- package/apps/jsmdcui/runtime/syntax/jsonnet.yaml +92 -0
- package/apps/jsmdcui/runtime/syntax/julia.yaml +57 -0
- package/apps/jsmdcui/runtime/syntax/justfile.yaml +40 -0
- package/apps/jsmdcui/runtime/syntax/keymap.yaml +27 -0
- package/apps/jsmdcui/runtime/syntax/kickstart.yaml +16 -0
- package/apps/jsmdcui/runtime/syntax/kotlin.yaml +66 -0
- package/apps/jsmdcui/runtime/syntax/kvlang.yaml +67 -0
- package/apps/jsmdcui/runtime/syntax/ledger.yaml +14 -0
- package/apps/jsmdcui/runtime/syntax/lfe.yaml +17 -0
- package/apps/jsmdcui/runtime/syntax/lilypond.yaml +26 -0
- package/apps/jsmdcui/runtime/syntax/lisp.yaml +17 -0
- package/apps/jsmdcui/runtime/syntax/log.yaml +92 -0
- package/apps/jsmdcui/runtime/syntax/lua.yaml +111 -0
- package/apps/jsmdcui/runtime/syntax/mail.yaml +25 -0
- package/apps/jsmdcui/runtime/syntax/makefile.yaml +38 -0
- package/apps/jsmdcui/runtime/syntax/man.yaml +12 -0
- package/apps/jsmdcui/runtime/syntax/markdown.yaml +64 -0
- package/apps/jsmdcui/runtime/syntax/mc.yaml +23 -0
- package/apps/jsmdcui/runtime/syntax/meson.yaml +51 -0
- package/apps/jsmdcui/runtime/syntax/micro.yaml +34 -0
- package/apps/jsmdcui/runtime/syntax/mpdconf.yaml +13 -0
- package/apps/jsmdcui/runtime/syntax/msbuild.yaml +6 -0
- package/apps/jsmdcui/runtime/syntax/nanorc.yaml +16 -0
- package/apps/jsmdcui/runtime/syntax/nftables.yaml +30 -0
- package/apps/jsmdcui/runtime/syntax/nginx.yaml +22 -0
- package/apps/jsmdcui/runtime/syntax/nim.yaml +27 -0
- package/apps/jsmdcui/runtime/syntax/nix.yaml +32 -0
- package/apps/jsmdcui/runtime/syntax/nu.yaml +114 -0
- package/apps/jsmdcui/runtime/syntax/objc.yaml +60 -0
- package/apps/jsmdcui/runtime/syntax/ocaml.yaml +43 -0
- package/apps/jsmdcui/runtime/syntax/octave.yaml +83 -0
- package/apps/jsmdcui/runtime/syntax/odin.yaml +64 -0
- package/apps/jsmdcui/runtime/syntax/pascal.yaml +45 -0
- package/apps/jsmdcui/runtime/syntax/patch.yaml +14 -0
- package/apps/jsmdcui/runtime/syntax/peg.yaml +16 -0
- package/apps/jsmdcui/runtime/syntax/perl.yaml +58 -0
- package/apps/jsmdcui/runtime/syntax/php.yaml +60 -0
- package/apps/jsmdcui/runtime/syntax/pkg-config.yaml +12 -0
- package/apps/jsmdcui/runtime/syntax/po.yaml +12 -0
- package/apps/jsmdcui/runtime/syntax/pony.yaml +37 -0
- package/apps/jsmdcui/runtime/syntax/pov.yaml +21 -0
- package/apps/jsmdcui/runtime/syntax/privoxy-action.yaml +14 -0
- package/apps/jsmdcui/runtime/syntax/privoxy-config.yaml +10 -0
- package/apps/jsmdcui/runtime/syntax/privoxy-filter.yaml +12 -0
- package/apps/jsmdcui/runtime/syntax/proto.yaml +40 -0
- package/apps/jsmdcui/runtime/syntax/prql.yaml +84 -0
- package/apps/jsmdcui/runtime/syntax/puppet.yaml +22 -0
- package/apps/jsmdcui/runtime/syntax/python2.yaml +60 -0
- package/apps/jsmdcui/runtime/syntax/python3.yaml +80 -0
- package/apps/jsmdcui/runtime/syntax/r.yaml +32 -0
- package/apps/jsmdcui/runtime/syntax/raku.yaml +42 -0
- package/apps/jsmdcui/runtime/syntax/reST.yaml +18 -0
- package/apps/jsmdcui/runtime/syntax/renpy.yaml +15 -0
- package/apps/jsmdcui/runtime/syntax/rpmspec.yaml +43 -0
- package/apps/jsmdcui/runtime/syntax/ruby.yaml +73 -0
- package/apps/jsmdcui/runtime/syntax/rust.yaml +78 -0
- package/apps/jsmdcui/runtime/syntax/sage.yaml +60 -0
- package/apps/jsmdcui/runtime/syntax/scad.yaml +53 -0
- package/apps/jsmdcui/runtime/syntax/scala.yaml +33 -0
- package/apps/jsmdcui/runtime/syntax/sed.yaml +13 -0
- package/apps/jsmdcui/runtime/syntax/sh.yaml +69 -0
- package/apps/jsmdcui/runtime/syntax/sls.yaml +15 -0
- package/apps/jsmdcui/runtime/syntax/smalltalk.yaml +55 -0
- package/apps/jsmdcui/runtime/syntax/solidity.yaml +41 -0
- package/apps/jsmdcui/runtime/syntax/sql.yaml +35 -0
- package/apps/jsmdcui/runtime/syntax/stata.yaml +67 -0
- package/apps/jsmdcui/runtime/syntax/svelte.yaml +27 -0
- package/apps/jsmdcui/runtime/syntax/swift.yaml +103 -0
- package/apps/jsmdcui/runtime/syntax/systemd.yaml +16 -0
- package/apps/jsmdcui/runtime/syntax/tcl.yaml +18 -0
- package/apps/jsmdcui/runtime/syntax/terraform.yaml +87 -0
- package/apps/jsmdcui/runtime/syntax/tex.yaml +32 -0
- package/apps/jsmdcui/runtime/syntax/toml.yaml +56 -0
- package/apps/jsmdcui/runtime/syntax/twig.yaml +55 -0
- package/apps/jsmdcui/runtime/syntax/typescript.yaml +49 -0
- package/apps/jsmdcui/runtime/syntax/v.yaml +80 -0
- package/apps/jsmdcui/runtime/syntax/vala.yaml +26 -0
- package/apps/jsmdcui/runtime/syntax/verilog.yaml +60 -0
- package/apps/jsmdcui/runtime/syntax/vhdl.yaml +37 -0
- package/apps/jsmdcui/runtime/syntax/vi.yaml +31 -0
- package/apps/jsmdcui/runtime/syntax/vue.yaml +64 -0
- package/apps/jsmdcui/runtime/syntax/xml.yaml +37 -0
- package/apps/jsmdcui/runtime/syntax/xresources.yaml +14 -0
- package/apps/jsmdcui/runtime/syntax/yaml.yaml +34 -0
- package/apps/jsmdcui/runtime/syntax/yum.yaml +12 -0
- package/apps/jsmdcui/runtime/syntax/zig.yaml +52 -0
- package/apps/jsmdcui/runtime/syntax/zscript.yaml +72 -0
- package/apps/jsmdcui/runtime/syntax/zsh.yaml +52 -0
- package/apps/jsmdcui/single-exe/README.md +473 -0
- package/apps/jsmdcui/single-exe/assetsHelper.js +191 -0
- package/apps/jsmdcui/single-exe/assetsLoader.mjs +85 -0
- package/apps/jsmdcui/single-exe/compiled.js +212 -0
- package/apps/jsmdcui/single-exe/entry.mjs +10 -0
- package/apps/jsmdcui/single-exe/packAssets.sh +7 -0
- package/apps/jsmdcui/src/MDCUI_DEFAULT_EDIT +0 -0
- package/apps/jsmdcui/src/buffer/backup.js +165 -0
- package/apps/jsmdcui/src/buffer/buffer.js +126 -0
- package/apps/jsmdcui/src/buffer/fixed3-codec.js +140 -0
- package/apps/jsmdcui/src/buffer/loc.js +38 -0
- package/apps/jsmdcui/src/buffer/message.js +29 -0
- package/apps/jsmdcui/src/build-args.js +40 -0
- package/apps/jsmdcui/src/config/clean.js +172 -0
- package/apps/jsmdcui/src/config/colorscheme.js +99 -0
- package/apps/jsmdcui/src/config/config.js +125 -0
- package/apps/jsmdcui/src/config/defaults.js +109 -0
- package/apps/jsmdcui/src/cui/fence-events.mjs +144 -0
- package/apps/jsmdcui/src/cui/heading-ids.mjs +1568 -0
- package/apps/jsmdcui/src/cui/id-collision.mjs +111 -0
- package/apps/jsmdcui/src/cui/identity.mjs +26 -0
- package/apps/jsmdcui/src/cui/kitty-debug.mjs +25 -0
- package/apps/jsmdcui/src/cui/kitty-images.mjs +280 -0
- package/apps/jsmdcui/src/cui/kitty-mode.mjs +6 -0
- package/apps/jsmdcui/src/cui/rerender-queue.mjs +66 -0
- package/apps/jsmdcui/src/cui/rpc.mjs +1525 -0
- package/apps/jsmdcui/src/cui/server.mjs +128 -0
- package/apps/jsmdcui/src/cui/table-render.mjs +286 -0
- package/apps/jsmdcui/src/cui/table-row-edit.mjs +226 -0
- package/apps/jsmdcui/src/cui/task-checkbox.mjs +60 -0
- package/apps/jsmdcui/src/cui/template-components.mjs +253 -0
- package/apps/jsmdcui/src/cui/text-block-resize.mjs +177 -0
- package/apps/jsmdcui/src/cui/tui-links.mjs +560 -0
- package/apps/jsmdcui/src/display/ansi-style.js +60 -0
- package/apps/jsmdcui/src/highlight/highlighter.js +243 -0
- package/apps/jsmdcui/src/highlight/parser.js +225 -0
- package/apps/jsmdcui/src/index.js +9573 -0
- package/apps/jsmdcui/src/lua/engine.js +68 -0
- package/apps/jsmdcui/src/platform/archive.js +50 -0
- package/apps/jsmdcui/src/platform/clipboard.js +278 -0
- package/apps/jsmdcui/src/platform/commands.js +221 -0
- package/apps/jsmdcui/src/platform/terminal.js +5 -0
- package/apps/jsmdcui/src/plugins/js-bridge.js +3377 -0
- package/apps/jsmdcui/src/plugins/manager.js +674 -0
- package/apps/jsmdcui/src/runtime/encodings.js +10 -0
- package/apps/jsmdcui/src/runtime/registry.js +134 -0
- package/apps/jsmdcui/src/screen/cell-buffer.js +81 -0
- package/apps/jsmdcui/src/screen/events.js +263 -0
- package/apps/jsmdcui/src/screen/screen.js +249 -0
- package/apps/jsmdcui/src/screen/vt100.js +571 -0
- package/apps/jsmdcui/src/shell/shell.js +70 -0
- package/apps/jsmdcui/testapp.md +78 -0
- package/apps/jsmdcui/tests/assets-helper.test.js +150 -0
- package/apps/jsmdcui/tests/backup.test.js +158 -0
- package/apps/jsmdcui/tests/cat-markdown.test.js +139 -0
- package/apps/jsmdcui/tests/cmphex3b64.js +95 -0
- package/apps/jsmdcui/tests/compiled-runtime.test.js +139 -0
- package/apps/jsmdcui/tests/config-settings.test.js +52 -0
- package/apps/jsmdcui/tests/demo.test.js +447 -0
- package/apps/jsmdcui/tests/docs-sync.test.js +14 -0
- package/apps/jsmdcui/tests/fence-events.test.js +1293 -0
- package/apps/jsmdcui/tests/heading-ids.test.js +559 -0
- package/apps/jsmdcui/tests/heading-list-selector.test.js +2393 -0
- package/apps/jsmdcui/tests/id-collision.test.js +514 -0
- package/apps/jsmdcui/tests/js-plugin-prompts.test.js +110 -0
- package/apps/jsmdcui/tests/key-event.md +10 -0
- package/apps/jsmdcui/tests/kitty-demo.md +184 -0
- package/apps/jsmdcui/tests/kitty-images.test.js +288 -0
- package/apps/jsmdcui/tests/kitty-mode.test.js +14 -0
- package/apps/jsmdcui/tests/platform-commands.test.js +18 -0
- package/apps/jsmdcui/tests/platform-terminal.test.js +8 -0
- package/apps/jsmdcui/tests/pty-demo.js +492 -0
- package/apps/jsmdcui/tests/rerender-queue.test.js +130 -0
- package/apps/jsmdcui/tests/table-render.test.js +150 -0
- package/apps/jsmdcui/tests/table-row-edit.test.js +138 -0
- package/apps/jsmdcui/tests/task-checkbox.test.js +33 -0
- package/apps/jsmdcui/tests/template-components.test.js +422 -0
- package/apps/jsmdcui/tests/text-block-resize.test.js +222 -0
- package/apps/jsmdcui/tests/textarea.md +8 -0
- package/apps/jsmdcui/tests/tui-links.test.js +298 -0
- package/apps/jsmdcui/tests/wui-responsive-images.test.js +60 -0
- package/apps/jsmdcui/tests/wui.test.js +108 -0
- package/apps/jsmdcui/tests/wv-client.js +96 -0
- package/apps/jsmdcui/tui +7 -0
- package/apps/jsmdcui/wui +9 -0
- package/apps/musl-la/LICENSES/Apache-2.0_LLVM_Exceptions_license.txt +311 -0
- package/apps/musl-la/LICENSES/Apache-2.0_license.txt +177 -0
- package/apps/musl-la/LICENSES/BSD-3-Clause_license.txt +43 -0
- package/apps/musl-la/LICENSES/GPL-3.0.txt +674 -0
- package/apps/musl-la/LICENSES/LGPL-3.0.txt +165 -0
- package/apps/musl-la/LICENSES/MIT.txt +21 -0
- package/apps/musl-la/LICENSES/curl_license.txt +22 -0
- package/apps/musl-la/LICENSES/gcc_runtime_exception.txt +73 -0
- package/apps/musl-la/LICENSES/zlib_license.txt +22 -0
- package/apps/musl-la/LICENSE_musl.txt +193 -0
- package/apps/musl-la/NOTICE +56 -0
- package/apps/musl-la/ldmusl +0 -0
- package/apps/musl-la/libgcc_s.so.1 +0 -0
- package/apps/musl-la/libstdc++.so.6 +0 -0
- package/apps/musl-la/musl-la.sh +5 -0
- package/bin/bun.sh +57 -0
- package/bin/glow.sh +5 -0
- package/bin/init.js +395 -0
- package/bin/jmi.sh +5 -0
- package/bin/jsgotty.sh +5 -0
- package/bin/libsh-loader.c +135 -0
- package/bin/libsh-loader.so +0 -0
- package/bin/multicall.sh +90 -0
- package/bin/shc.js +5 -0
- package/bin/switch_to_android.sh +9 -0
- package/bin/switch_to_linux.sh +7 -0
- package/icon.png +0 -0
- package/package.json +31 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
```text#character
|
|
2
|
+
🧱😀🧱🧱🧱🧱🧱🧱🧱🧱🧱🧱
|
|
3
|
+
🧱 🧱 🧱
|
|
4
|
+
🧱 🧱🧱🧱 🧱 🧱🧱🧱🧱
|
|
5
|
+
🧱 🧱 🧱 🧱
|
|
6
|
+
🧱🧱🧱 🧱🧱🧱🧱🧱 🧱🧱
|
|
7
|
+
🧱 🧱 🧱 🧱
|
|
8
|
+
🧱 🧱🧱🧱 🧱 🧱 🧱🧱
|
|
9
|
+
🧱 🧱 🧱 🧱
|
|
10
|
+
🧱 🧱🧱🧱🧱🧱🧱🧱 🧱🧱
|
|
11
|
+
🧱 🧱 🧱
|
|
12
|
+
🧱 🧱 🧱🧱🧱 🧱🧱🧱🧱
|
|
13
|
+
🧱 🧱 🧱
|
|
14
|
+
🧱🧱🧱🧱🧱🧱🧱🧱🧱 🧱🧱
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```text#controls @keydown.prevent="handle(event)"
|
|
18
|
+
Put the cursor here, then press:
|
|
19
|
+
將遊標放在這裡,然後按:
|
|
20
|
+
|
|
21
|
+
L't half of QWERTY ← move left
|
|
22
|
+
R't half of QWERTY → move right
|
|
23
|
+
T / Y ↑ move up
|
|
24
|
+
Space ↓ move down
|
|
25
|
+
|
|
26
|
+
鍵盤左半邊 ← 向左移動
|
|
27
|
+
鍵盤右半邊 → 向右移動
|
|
28
|
+
T / Y 向上移動
|
|
29
|
+
空白鍵向下移動
|
|
30
|
+
|
|
31
|
+
Arrow keys ←↑→↓ / 正常方向移動
|
|
32
|
+
Ctrl-R Reset maze / 重新開始
|
|
33
|
+
|
|
34
|
+
Do not hit 🧱 / 不能撞牆
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```text#last-key
|
|
38
|
+
Waiting for input / 等待輸入
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
[🔄 Reset maze / 重新開始](javascript:reset())
|
|
42
|
+
|
|
43
|
+
```js front
|
|
44
|
+
const LEFT_KEYS = new Set([
|
|
45
|
+
...'`12345qwerasdfgzxcvb',
|
|
46
|
+
'escape', 'tab',
|
|
47
|
+
]);
|
|
48
|
+
const RIGHT_KEYS = new Set([
|
|
49
|
+
...'67890-=uiop[]\\hjkl;\'nm,./',
|
|
50
|
+
'backspace', 'enter', 'delete',
|
|
51
|
+
'home', 'end', 'pageup', 'pagedown',
|
|
52
|
+
]);
|
|
53
|
+
const MAZE = [
|
|
54
|
+
'# ##########',
|
|
55
|
+
'# # #',
|
|
56
|
+
'# ### # ####',
|
|
57
|
+
'# # # #',
|
|
58
|
+
'### ##### ##',
|
|
59
|
+
'# # # #',
|
|
60
|
+
'# ### # # ##',
|
|
61
|
+
'# # # #',
|
|
62
|
+
'# ####### ##',
|
|
63
|
+
'# # #',
|
|
64
|
+
'# # ### ####',
|
|
65
|
+
'# # #',
|
|
66
|
+
'######### ##',
|
|
67
|
+
];
|
|
68
|
+
const GOAL = { row: MAZE.length - 1, col: 9 };
|
|
69
|
+
const player = { row: 0, col: 1 };
|
|
70
|
+
let completed = false;
|
|
71
|
+
|
|
72
|
+
function drawMaze() {
|
|
73
|
+
const screen = MAZE.map((line, row) => [...line].map((cell, col) => {
|
|
74
|
+
if (row === player.row && col === player.col) return '😀';
|
|
75
|
+
return cell === '#' ? '🧱' : ' ';
|
|
76
|
+
}).join('')).join('\n');
|
|
77
|
+
$('#character').val(screen);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function reset() {
|
|
81
|
+
player.row = 0;
|
|
82
|
+
player.col = 1;
|
|
83
|
+
completed = false;
|
|
84
|
+
drawMaze();
|
|
85
|
+
$('#last-key').val('Waiting for input / 等待輸入');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function handle(event) {
|
|
89
|
+
const key = String(event.key ?? '').toLowerCase();
|
|
90
|
+
if (event.ctrlKey && key === 'r') {
|
|
91
|
+
reset();
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (completed) return;
|
|
95
|
+
|
|
96
|
+
let row = player.row;
|
|
97
|
+
let col = player.col;
|
|
98
|
+
let direction;
|
|
99
|
+
|
|
100
|
+
if (key === 't' || key === 'y' || key === 'arrowup') {
|
|
101
|
+
row--;
|
|
102
|
+
direction = 'up / 上';
|
|
103
|
+
} else if (key === ' ' || key === 'arrowdown') {
|
|
104
|
+
row++;
|
|
105
|
+
direction = 'down / 下';
|
|
106
|
+
} else if (key === 'arrowleft' || LEFT_KEYS.has(key)) {
|
|
107
|
+
col--;
|
|
108
|
+
direction = 'left / 左';
|
|
109
|
+
} else if (key === 'arrowright' || RIGHT_KEYS.has(key)) {
|
|
110
|
+
col++;
|
|
111
|
+
direction = 'right / 右';
|
|
112
|
+
} else {
|
|
113
|
+
$('#last-key').val(`Ignored / 忽略:${event.key}`);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (MAZE[row]?.[col] !== ' ') {
|
|
118
|
+
$('#last-key').val(`${event.key === ' ' ? 'Space' : event.key} → 🧱 Wall / 撞牆`);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
player.row = row;
|
|
123
|
+
player.col = col;
|
|
124
|
+
drawMaze();
|
|
125
|
+
|
|
126
|
+
if (row === GOAL.row && col === GOAL.col) {
|
|
127
|
+
completed = true;
|
|
128
|
+
$('#last-key').val('🎉🏆🌟 Escaped the maze! / 成功走出迷宮!🌟🏆🎉');
|
|
129
|
+
$('#character').val([
|
|
130
|
+
'',
|
|
131
|
+
'🎆🎇🎉 恭 喜 過 關 ! 🎉🎇🎆',
|
|
132
|
+
'',
|
|
133
|
+
'🥳 你成功逃出迷宮了! 🥳',
|
|
134
|
+
'👑 🏆 ⭐ 🌟 💫 🌈 🦄',
|
|
135
|
+
'👏👏👏 AMAZING! 👏👏👏',
|
|
136
|
+
'🎈 🎊 🎁 🪩 🎁 🎊 🎈',
|
|
137
|
+
'',
|
|
138
|
+
'🚀 ESCAPED THE MAZE! 🚀',
|
|
139
|
+
'',
|
|
140
|
+
'Press Ctrl-R to reset',
|
|
141
|
+
'按 Ctrl-R 重新開始',
|
|
142
|
+
''
|
|
143
|
+
].join('\n'));
|
|
144
|
+
} else {
|
|
145
|
+
const label = event.key === ' ' ? 'Space' : event.key;
|
|
146
|
+
$('#last-key').val(`${label} → ${direction} (${row}, ${col})`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env jsmdcui
|
|
2
|
+
|
|
3
|
+
# Reactive Template Demo / 響應式模板示範
|
|
4
|
+
|
|
5
|
+
Type a name below. After you stop typing for 200 ms, the template updates in
|
|
6
|
+
both the TUI and WUI.
|
|
7
|
+
|
|
8
|
+
在下方輸入名字;停止輸入 200 毫秒後,TUI 與 WUI 中的模板都會自動更新。
|
|
9
|
+
|
|
10
|
+
```text#reactive-name @input="updateReactiveName(event)"
|
|
11
|
+
Johnny
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Reactive Result
|
|
15
|
+
|
|
16
|
+
````md template
|
|
17
|
+
---
|
|
18
|
+
name: Johnny
|
|
19
|
+
---
|
|
20
|
+
恭喜你,**${data.name}**,成就金仙!
|
|
21
|
+
|
|
22
|
+
Congratulations, **${data.name}**! You have attained the Golden Immortal realm.
|
|
23
|
+
````
|
|
24
|
+
|
|
25
|
+
```js front
|
|
26
|
+
let reactiveNameTimer = null;
|
|
27
|
+
|
|
28
|
+
export function updateReactiveName(event) {
|
|
29
|
+
|
|
30
|
+
const name = $(event.target).val().trim() || '無名道友 / Nameless Daoist';
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
clearTimeout(reactiveNameTimer);
|
|
34
|
+
reactiveNameTimer = setTimeout(() => {
|
|
35
|
+
|
|
36
|
+
$('#reactive-result').data('name', name);
|
|
37
|
+
|
|
38
|
+
}, 200);
|
|
39
|
+
}
|
|
40
|
+
```
|
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
#!/usr/bin/env jsmdcui
|
|
2
|
+
|
|
3
|
+
# File List Reader / 檔案列表閱讀器
|
|
4
|
+
|
|
5
|
+
Enter a local directory or web page URL, then press Enter or choose **List**.
|
|
6
|
+
Tab completes local directories. 輸入本機目錄或網頁網址後按 Enter 或選擇
|
|
7
|
+
「列出」;Tab 可補全本機目錄。
|
|
8
|
+
|
|
9
|
+
```text#directory @keydown="directoryKey(event)"
|
|
10
|
+
.
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
- [List files or links / 列出檔案或連結](javascript:listDirectory())
|
|
14
|
+
|
|
15
|
+
## File List / 檔案列表
|
|
16
|
+
|
|
17
|
+
````js template
|
|
18
|
+
---
|
|
19
|
+
filelist: []
|
|
20
|
+
listPage: 0
|
|
21
|
+
---
|
|
22
|
+
const size = 10
|
|
23
|
+
const files = Array.isArray(data.filelist) ? data.filelist : []
|
|
24
|
+
const pages = Math.max(1, Math.ceil(files.length / size))
|
|
25
|
+
const page = Math.max(0, Math.min(Number(data.listPage) || 0, pages - 1))
|
|
26
|
+
let markdown = `Page ${page + 1} / ${pages} · ${files.length} files\n\n`
|
|
27
|
+
for (const file of files.slice(page * size, page * size + size)) {
|
|
28
|
+
const label = String(file.name).replaceAll('\\', '\\\\').replaceAll('[', '\\[').replaceAll(']', '\\]')
|
|
29
|
+
const value = encodeURIComponent(String(file.value))
|
|
30
|
+
markdown += `- [${label}](javascript:selectFile(decodeURIComponent('${value}')))\n`
|
|
31
|
+
}
|
|
32
|
+
if (!files.length) markdown += '- *(No files / 沒有檔案)*\n'
|
|
33
|
+
return markdown
|
|
34
|
+
````
|
|
35
|
+
|
|
36
|
+
## Selected File/URL 已選檔案/網址
|
|
37
|
+
|
|
38
|
+
```text#selected
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Controls / 控制
|
|
43
|
+
|
|
44
|
+
| Previous page | Page | Go | Next page | Clear selection |
|
|
45
|
+
| --- | --- | --- | --- | --- |
|
|
46
|
+
| [上一頁](javascript:changeListPage(-1)) | 1 | [跳轉](javascript:jumpListPage(this)) | [下一頁](javascript:changeListPage(1)) | [清除已選](javascript:clearSelection()) |
|
|
47
|
+
| [🚀載入](javascript:loadSelected()) | [⏮上一章](javascript:loadRelative(-1)) | [⏭下一章](javascript:loadRelative(1)) | [⏹停止朗讀](javascript:stopReading()) | [📢朗讀](javascript:readFromCurrentPage()) |
|
|
48
|
+
|
|
49
|
+
## Document Reader / 文件閱讀器
|
|
50
|
+
- asdf = prev page
|
|
51
|
+
- hjkl = next page
|
|
52
|
+
|
|
53
|
+
### More info click 'M' 更多說明按'M'
|
|
54
|
+
|
|
55
|
+
Focus the reader and use the left half of QWERTY, Left/Up, or PageUp for the
|
|
56
|
+
previous page. Use the right half of QWERTY, Right/Down, or PageDown for the
|
|
57
|
+
next page.
|
|
58
|
+
|
|
59
|
+
將遊標放在閱讀框;QWERTY 左半邊、左/上方向鍵或 PageUp 切到上一頁,右半邊、
|
|
60
|
+
右/下方向鍵或 PageDown 切到下一頁。
|
|
61
|
+
|
|
62
|
+
To replace text while loading, use `replace.json`. For a local file, place it
|
|
63
|
+
beside that file; for a URL, place it in `process.cwd()`. It is parsed as JSON5
|
|
64
|
+
and must contain an array of two-item arrays. The first item is passed to
|
|
65
|
+
`new RegExp(target, "g")`; the second item is inserted as literal replacement
|
|
66
|
+
text. Invalid or unparseable rules are ignored.
|
|
67
|
+
|
|
68
|
+
載入本機檔案時,可在檔案同一目錄放置 `replace.json`;載入 URL 時則使用
|
|
69
|
+
`process.cwd()` 下的 `replace.json`。檔案會以 JSON5 解析,格式為二項陣列所組成
|
|
70
|
+
的陣列;第一項會傳給 `new RegExp(target, "g")`,第二項是純文字取代結果。
|
|
71
|
+
無效或無法解析時會忽略規則並正常載入原文。
|
|
72
|
+
|
|
73
|
+
```json5
|
|
74
|
+
[
|
|
75
|
+
["old\\s+name", "new name"],
|
|
76
|
+
["第[零〇]章", "序章"],
|
|
77
|
+
]
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Button translations / 按鈕翻譯:
|
|
81
|
+
|
|
82
|
+
- `上一頁` — Previous page
|
|
83
|
+
- `跳轉` — Go to the entered page
|
|
84
|
+
- `下一頁` — Next page
|
|
85
|
+
- `清除已選` — Clear selection
|
|
86
|
+
- `🚀載入` — Load the selected file or URL
|
|
87
|
+
- `⏮上一章` — Previous chapter
|
|
88
|
+
- `⏭下一章` — Next chapter
|
|
89
|
+
- `⏹停止朗讀` — Stop reading aloud
|
|
90
|
+
- `📢朗讀` — Start reading aloud from the current page
|
|
91
|
+
- `速度` — Speech speed
|
|
92
|
+
- `音高` — Speech pitch
|
|
93
|
+
- `套用` — Apply
|
|
94
|
+
|
|
95
|
+
### Document content
|
|
96
|
+
|
|
97
|
+
```textarea#reader @keydown.prevent="readerKey(event)"
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Reader controls / 閱讀控制
|
|
113
|
+
|
|
114
|
+
| Prev page / Speed | Page | Go / Pitch | Next page |
|
|
115
|
+
| --- | --- | --- | --- |
|
|
116
|
+
| [上一頁](javascript:previousReaderPage()) | 1 | [跳轉](javascript:jumpReaderPage(this)) | [下一頁](javascript:nextReaderPage()) |
|
|
117
|
+
| 速度: [1.5](javascript:applySpeechSetting(this,'speed',false)) | [套用 / Apply](javascript:applySpeechSetting(this,'speed')) | 音高: [1.0](javascript:applySpeechSetting(this,'pitch',false)) | [套用 / Apply](javascript:applySpeechSetting(this,'pitch')) |
|
|
118
|
+
|
|
119
|
+
```text#reader-status
|
|
120
|
+
Not loaded / 尚未載入
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
```js front
|
|
124
|
+
const PAGE_ROWS = 12;
|
|
125
|
+
const PAGE_COLUMNS = 64;
|
|
126
|
+
const LEFT_KEYS = new Set([
|
|
127
|
+
...'`12345qwerasdfgzxcvb',
|
|
128
|
+
'escape', 'tab',
|
|
129
|
+
]);
|
|
130
|
+
const RIGHT_KEYS = new Set([
|
|
131
|
+
...'67890-=uiop[]\\hjkl;\'nm,./',
|
|
132
|
+
'backspace', 'enter', 'delete', 'home', 'end',
|
|
133
|
+
]);
|
|
134
|
+
|
|
135
|
+
let pages = [''];
|
|
136
|
+
let pageIndex = 0;
|
|
137
|
+
let selectedIndex = -1;
|
|
138
|
+
let readingRevision = 0;
|
|
139
|
+
let loadedSource = '';
|
|
140
|
+
let speechSpeed = 1.5;
|
|
141
|
+
let speechPitch = 1.0;
|
|
142
|
+
|
|
143
|
+
function message(text) {
|
|
144
|
+
$('#reader-status').val(String(text));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function fileState() {
|
|
148
|
+
return $('#file-list').data();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function pageCount() {
|
|
152
|
+
return Math.max(1, Math.ceil((fileState().filelist?.length || 0) / 10));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function selectedValue() {
|
|
156
|
+
return $('#selected').val().trim();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function wrapText(text) {
|
|
160
|
+
const rows = [];
|
|
161
|
+
for (const rawLine of String(text ?? '').replace(/\r\n?/g, '\n').split('\n')) {
|
|
162
|
+
const characters = [...rawLine];
|
|
163
|
+
if (!characters.length) {
|
|
164
|
+
rows.push('');
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
for (let offset = 0; offset < characters.length; offset += PAGE_COLUMNS)
|
|
168
|
+
rows.push(characters.slice(offset, offset + PAGE_COLUMNS).join(''));
|
|
169
|
+
}
|
|
170
|
+
if (!rows.length) rows.push('');
|
|
171
|
+
const result = [];
|
|
172
|
+
for (let offset = 0; offset < rows.length; offset += PAGE_ROWS)
|
|
173
|
+
result.push(rows.slice(offset, offset + PAGE_ROWS).join('\n'));
|
|
174
|
+
return result.length ? result : [''];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function showReaderPage(nextPage = pageIndex) {
|
|
178
|
+
pageIndex = Math.max(0, Math.min(Number(nextPage) || 0, pages.length - 1));
|
|
179
|
+
const rows = String(pages[pageIndex] ?? '').split('\n');
|
|
180
|
+
while (rows.length < PAGE_ROWS) rows.push('');
|
|
181
|
+
$('#reader').val(rows.slice(0, PAGE_ROWS).join('\n'));
|
|
182
|
+
$('#reader-controls').cell(1, 1).text(String(pageIndex + 1));
|
|
183
|
+
message(`${loadedSource || 'Reader'} · Page ${pageIndex + 1} / ${pages.length}`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function trailingNumber(text) {
|
|
187
|
+
const match = String(text ?? '').trim().match(/(-?(?:\d+(?:\.\d*)?|\.\d+))\s*$/u);
|
|
188
|
+
return match ? Number(match[1]) : NaN;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function jumpReaderPage(link) {
|
|
192
|
+
const value = trailingNumber($(link).parent()?.left()?.text());
|
|
193
|
+
if (!Number.isFinite(value)) {
|
|
194
|
+
message('Invalid page number / 頁碼無效');
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
showReaderPage(Math.trunc(value) - 1);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export function applySpeechSetting(link, kind, fromLeft = true) {
|
|
201
|
+
const cell = $(link).parent();
|
|
202
|
+
const value = trailingNumber((fromLeft ? cell?.left() : cell)?.text());
|
|
203
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
204
|
+
message(`Invalid ${kind} / ${kind === 'speed' ? '速度' : '音高'}無效`);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (kind === 'speed') speechSpeed = value;
|
|
208
|
+
else speechPitch = value;
|
|
209
|
+
message(`${kind === 'speed' ? 'Speed / 速度' : 'Pitch / 音高'}: ${value}`);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function sentences(text) {
|
|
213
|
+
return String(text ?? '')
|
|
214
|
+
.split(/(?<=[.!?。!?…;;])\s*|[\r\n]+/u)
|
|
215
|
+
.map(value => value.trim())
|
|
216
|
+
.filter(Boolean);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export async function onMdcuiLoad() {
|
|
220
|
+
$("#more-info-click-m-m").hide();
|
|
221
|
+
await listDirectory();
|
|
222
|
+
showReaderPage(0);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export function directoryKey(event) {
|
|
226
|
+
if (event.key === 'Tab') {
|
|
227
|
+
event.preventDefault();
|
|
228
|
+
return completeDirectory();
|
|
229
|
+
}
|
|
230
|
+
if (event.key === 'Enter') {
|
|
231
|
+
event.preventDefault();
|
|
232
|
+
return listDirectory();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export async function completeDirectory() {
|
|
237
|
+
try {
|
|
238
|
+
const result = await rpc.completeReaderDirectory($('#directory').val());
|
|
239
|
+
if (result.matches > 0) $('#directory').val(result.directory);
|
|
240
|
+
message(result.matches > 0
|
|
241
|
+
? `Directory completion: ${result.matches} match${result.matches === 1 ? '' : 'es'}`
|
|
242
|
+
: 'No matching directory / 找不到符合的目錄');
|
|
243
|
+
} catch (error) {
|
|
244
|
+
message(`Completion failed: ${error?.message || error}`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export async function listDirectory() {
|
|
249
|
+
try {
|
|
250
|
+
const result = await rpc.listReaderDirectory($('#directory').val().trim());
|
|
251
|
+
$('#directory').val(result.directory);
|
|
252
|
+
selectedIndex = -1;
|
|
253
|
+
$('#file-list').data({ filelist: result.files, listPage: 0 });
|
|
254
|
+
$('#controls').cell(1, 1).text('1');
|
|
255
|
+
message(`Listed ${result.files.length} files from ${result.directory}`);
|
|
256
|
+
} catch (error) {
|
|
257
|
+
message(`List failed: ${error?.message || error}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export function selectFile(value) {
|
|
262
|
+
const files = fileState().filelist || [];
|
|
263
|
+
selectedIndex = files.findIndex(file => file.value === value);
|
|
264
|
+
$('#selected').val(value);
|
|
265
|
+
if (selectedIndex >= 0) setListPage(Math.floor(selectedIndex / 10));
|
|
266
|
+
message(`Selected: ${value}`);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function setListPage(nextPage) {
|
|
270
|
+
const data = fileState();
|
|
271
|
+
const next = Math.max(0, Math.min(Number(nextPage) || 0, pageCount() - 1));
|
|
272
|
+
$('#file-list').data('listPage', next);
|
|
273
|
+
$('#controls').cell(1, 1).text(String(next + 1));
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export function changeListPage(delta) {
|
|
277
|
+
setListPage((Number(fileState().listPage) || 0) + delta);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export function jumpListPage(link) {
|
|
281
|
+
const value = trailingNumber($(link).parent()?.left()?.text());
|
|
282
|
+
if (!Number.isFinite(value)) {
|
|
283
|
+
message('Invalid list page number / 檔案列表頁碼無效');
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
setListPage(Math.trunc(value) - 1);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export function selectRelative(delta) {
|
|
290
|
+
const files = fileState().filelist || [];
|
|
291
|
+
if (!files.length) return;
|
|
292
|
+
if (selectedIndex < 0) {
|
|
293
|
+
const current = selectedValue();
|
|
294
|
+
selectedIndex = files.findIndex(file => file.value === current);
|
|
295
|
+
}
|
|
296
|
+
selectedIndex = Math.max(0, Math.min(
|
|
297
|
+
selectedIndex < 0 ? (delta > 0 ? 0 : files.length - 1) : selectedIndex + delta,
|
|
298
|
+
files.length - 1,
|
|
299
|
+
));
|
|
300
|
+
selectFile(files[selectedIndex].value);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export function clearSelection() {
|
|
304
|
+
selectedIndex = -1;
|
|
305
|
+
$('#selected').val('');
|
|
306
|
+
message('Selection cleared / 已清除選取');
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function numberedSibling(value, delta) {
|
|
310
|
+
const source = String(value ?? '');
|
|
311
|
+
const suffixAt = source.search(/[?#]/u);
|
|
312
|
+
const path = suffixAt < 0 ? source : source.slice(0, suffixAt);
|
|
313
|
+
const suffix = suffixAt < 0 ? '' : source.slice(suffixAt);
|
|
314
|
+
const separatorAt = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
|
|
315
|
+
const directory = path.slice(0, separatorAt + 1);
|
|
316
|
+
const filename = path.slice(separatorAt + 1);
|
|
317
|
+
const matches = [...filename.matchAll(/\d+/gu)];
|
|
318
|
+
const match = matches.at(-1);
|
|
319
|
+
if (!match) return null;
|
|
320
|
+
const current = BigInt(match[0]);
|
|
321
|
+
const next = current + BigInt(delta);
|
|
322
|
+
if (next < 0n) return null;
|
|
323
|
+
const replacement = String(next).padStart(match[0].length, '0');
|
|
324
|
+
return directory
|
|
325
|
+
+ filename.slice(0, match.index)
|
|
326
|
+
+ replacement
|
|
327
|
+
+ filename.slice(match.index + match[0].length)
|
|
328
|
+
+ suffix;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export async function loadSelected() {
|
|
332
|
+
const value = selectedValue();
|
|
333
|
+
if (!value) {
|
|
334
|
+
message('Load failed: select a file or enter a URL first');
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
stopReading();
|
|
338
|
+
try {
|
|
339
|
+
const result = await rpc.loadReaderResource(value);
|
|
340
|
+
loadedSource = result.source;
|
|
341
|
+
pages = wrapText(result.text);
|
|
342
|
+
pageIndex = 0;
|
|
343
|
+
showReaderPage(0);
|
|
344
|
+
} catch (error) {
|
|
345
|
+
message(`Load failed: ${error?.message || error}`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export async function loadRelative(delta) {
|
|
350
|
+
const numbered = numberedSibling(selectedValue(), delta);
|
|
351
|
+
if (numbered) selectFile(numbered);
|
|
352
|
+
else selectRelative(delta);
|
|
353
|
+
await loadSelected();
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export function previousReaderPage() {
|
|
357
|
+
showReaderPage(pageIndex - 1);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
export function nextReaderPage() {
|
|
361
|
+
showReaderPage(pageIndex + 1);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
export function readerKey(event) {
|
|
365
|
+
const key = String(event.key ?? '').toLowerCase();
|
|
366
|
+
if (key === 'pageup' || key === 'arrowleft' || key === 'arrowup' || LEFT_KEYS.has(key)) {
|
|
367
|
+
previousReaderPage();
|
|
368
|
+
} else if (
|
|
369
|
+
key === 'pagedown' || key === 'arrowright' || key === 'arrowdown' || RIGHT_KEYS.has(key)
|
|
370
|
+
) {
|
|
371
|
+
nextReaderPage();
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
export function stopReading() {
|
|
376
|
+
readingRevision++;
|
|
377
|
+
$.tts.stop?.();
|
|
378
|
+
message('Reading stopped / 已停止朗讀');
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
export function readFromCurrentPage() {
|
|
382
|
+
const revision = ++readingRevision;
|
|
383
|
+
void runReading(revision);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
async function runReading(revision) {
|
|
387
|
+
for (let current = pageIndex; current < pages.length; current++) {
|
|
388
|
+
if (revision !== readingRevision) return;
|
|
389
|
+
showReaderPage(current);
|
|
390
|
+
for (const sentence of sentences(pages[current])) {
|
|
391
|
+
if (revision !== readingRevision) return;
|
|
392
|
+
const error = await $.tts(sentence, speechPitch, speechSpeed);
|
|
393
|
+
if (error) {
|
|
394
|
+
message(error);
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (revision === readingRevision)
|
|
400
|
+
message(`Reading complete: ${loadedSource}`);
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
```js back
|
|
405
|
+
import { readdir } from 'node:fs/promises';
|
|
406
|
+
import { basename, dirname, resolve, sep } from 'node:path';
|
|
407
|
+
|
|
408
|
+
export async function completeReaderDirectory(input) {
|
|
409
|
+
const raw = String(input ?? '').trim();
|
|
410
|
+
if (/^https?:\/\//iu.test(raw)) return { directory: raw, matches: 0 };
|
|
411
|
+
const resolved = resolve(raw || process.cwd());
|
|
412
|
+
const endsWithSeparator = /[\\/]$/u.test(raw);
|
|
413
|
+
const parent = endsWithSeparator ? resolved : dirname(resolved);
|
|
414
|
+
const prefix = endsWithSeparator ? '' : basename(resolved);
|
|
415
|
+
const entries = await readdir(parent, { withFileTypes: true });
|
|
416
|
+
const matches = entries
|
|
417
|
+
.filter(entry => entry.isDirectory() && entry.name.startsWith(prefix))
|
|
418
|
+
.map(entry => entry.name)
|
|
419
|
+
.sort((left, right) => left.localeCompare(right));
|
|
420
|
+
if (!matches.length) return { directory: raw, matches: 0 };
|
|
421
|
+
let common = matches[0];
|
|
422
|
+
for (const name of matches.slice(1)) {
|
|
423
|
+
let length = 0;
|
|
424
|
+
while (length < common.length && common[length] === name[length]) length++;
|
|
425
|
+
common = common.slice(0, length);
|
|
426
|
+
}
|
|
427
|
+
let directory = common ? resolve(parent, common) : `${resolved}${sep}`;
|
|
428
|
+
if (matches.length === 1) directory += sep;
|
|
429
|
+
return { directory, matches: matches.length };
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
export async function listReaderDirectory(input) {
|
|
433
|
+
const value = String(input ?? '').trim();
|
|
434
|
+
if (/^https?:\/\//iu.test(value)) {
|
|
435
|
+
const response = await fetch(value);
|
|
436
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
437
|
+
const directory = response.url || value;
|
|
438
|
+
const links = [];
|
|
439
|
+
let currentLink = null;
|
|
440
|
+
await new HTMLRewriter()
|
|
441
|
+
.on('a[href]', {
|
|
442
|
+
element(element) {
|
|
443
|
+
const href = element.getAttribute('href')?.trim();
|
|
444
|
+
currentLink = href ? { href, text: '' } : null;
|
|
445
|
+
if (currentLink) links.push(currentLink);
|
|
446
|
+
},
|
|
447
|
+
text(chunk) {
|
|
448
|
+
if (currentLink) currentLink.text += chunk.text;
|
|
449
|
+
},
|
|
450
|
+
})
|
|
451
|
+
.transform(response)
|
|
452
|
+
.text();
|
|
453
|
+
const seen = new Set();
|
|
454
|
+
const files = [];
|
|
455
|
+
for (const link of links) {
|
|
456
|
+
let url;
|
|
457
|
+
try { url = new URL(link.href, directory); } catch { continue; }
|
|
458
|
+
if (!/^https?:$/iu.test(url.protocol) || seen.has(url.href)) continue;
|
|
459
|
+
seen.add(url.href);
|
|
460
|
+
files.push({ name: link.text.trim() || link.href, value: url.href });
|
|
461
|
+
}
|
|
462
|
+
return { directory, files };
|
|
463
|
+
}
|
|
464
|
+
const directory = resolve(value || process.cwd());
|
|
465
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
466
|
+
const files = entries
|
|
467
|
+
.filter(entry => entry.isFile())
|
|
468
|
+
.map(entry => ({
|
|
469
|
+
name: entry.name,
|
|
470
|
+
value: resolve(directory, entry.name),
|
|
471
|
+
}))
|
|
472
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
473
|
+
return { directory, files };
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
async function applyReaderReplacements(text, directory) {
|
|
477
|
+
const replacementFile = Bun.file(resolve(directory, 'replace.json'));
|
|
478
|
+
if (!await replacementFile.exists()) return text;
|
|
479
|
+
try {
|
|
480
|
+
const rules = Bun.JSON5.parse(await replacementFile.text());
|
|
481
|
+
if (!Array.isArray(rules)) return text;
|
|
482
|
+
for (const rule of rules) {
|
|
483
|
+
if (!Array.isArray(rule) || rule.length !== 2) continue;
|
|
484
|
+
try {
|
|
485
|
+
const pattern = new RegExp(String(rule[0]), 'g');
|
|
486
|
+
const replacement = String(rule[1]);
|
|
487
|
+
text = text.replace(pattern, () => replacement);
|
|
488
|
+
} catch {}
|
|
489
|
+
}
|
|
490
|
+
} catch {}
|
|
491
|
+
return text;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
export async function loadReaderResource(input) {
|
|
495
|
+
const value = String(input ?? '').trim();
|
|
496
|
+
if (!value) throw new Error('Select a file or enter a URL first');
|
|
497
|
+
if (/^https?:\/\//iu.test(value)) {
|
|
498
|
+
const response = await fetch(value);
|
|
499
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
500
|
+
return {
|
|
501
|
+
source: response.url || value,
|
|
502
|
+
text: await applyReaderReplacements(await response.text(), process.cwd()),
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
const source = resolve(value);
|
|
506
|
+
const file = Bun.file(source);
|
|
507
|
+
if (!await file.exists()) throw new Error(`File not found: ${source}`);
|
|
508
|
+
return {
|
|
509
|
+
source,
|
|
510
|
+
text: await applyReaderReplacements(await file.text(), dirname(source)),
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
```
|