buninu-linux 0.14.57 → 0.16.59

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.
Files changed (299) hide show
  1. package/LICENSES/linux-firmware/LICENCE.nvidia +131 -0
  2. package/LICENSES/linux-firmware/LICENSE.amdgpu +51 -0
  3. package/LICENSES/linux-firmware/LICENSE.amdisp +31 -0
  4. package/LICENSES/linux-firmware/LICENSE.i915 +39 -0
  5. package/LICENSES/linux-firmware/LICENSE.radeon +51 -0
  6. package/LICENSES/linux-firmware/LICENSE.xe +39 -0
  7. package/LICENSES/linux-firmware/WHENCE +10280 -0
  8. package/NOTICE.md +64 -46
  9. package/README.md +378 -87
  10. package/README.zh.md +2041 -0
  11. package/build-image.sh +10 -1
  12. package/build-uki.sh +3 -1
  13. package/fetch-alpine.sh +14 -0
  14. package/graphics.md +31 -0
  15. package/index.js +28 -11
  16. package/initramfs/bin/buninu-browser +4 -1
  17. package/initramfs/bin/buninu-land +1 -1
  18. package/initramfs/bin/bunterm +3 -3
  19. package/initramfs/bin/chroot +13 -0
  20. package/initramfs/bin/chvt +11 -0
  21. package/initramfs/bin/mount +4 -0
  22. package/initramfs/bin/umount +6 -0
  23. package/initramfs/bin/xdg-open +33 -0
  24. package/initramfs/buninu/CHANGELOG.md +66 -0
  25. package/initramfs/buninu/apps/bunmsh/CHANGELOG.md +4 -0
  26. package/initramfs/buninu/apps/bunmsh/package.json +1 -1
  27. package/initramfs/buninu/apps/bunmsh/src/main.js +1 -1
  28. package/initramfs/buninu/apps/jsgotty/LICENSES/MIT-jsmdcui.txt +22 -0
  29. package/initramfs/buninu/apps/jsgotty/NOTICE +5 -0
  30. package/initramfs/buninu/apps/jsgotty/README.en.md +61 -0
  31. package/initramfs/buninu/apps/jsgotty/README.md +61 -0
  32. package/initramfs/buninu/apps/jsgotty/client-modes.mjs +117 -0
  33. package/initramfs/buninu/apps/jsgotty/client.mjs +100 -10
  34. package/initramfs/buninu/apps/jsgotty/clipboard-powershell.js +18 -0
  35. package/initramfs/buninu/apps/jsgotty/clipboard.js +148 -0
  36. package/initramfs/buninu/apps/jsgotty/gotty.js +13 -0
  37. package/initramfs/buninu/apps/jsgotty/package-lock.json +2 -2
  38. package/initramfs/buninu/apps/jsgotty/package.json +1 -1
  39. package/initramfs/buninu/apps/jsgotty/static/css/index.css +14 -1
  40. package/initramfs/buninu/apps/jsgotty/static/index.html +1 -0
  41. package/initramfs/buninu/apps/jsgotty/static/js/gotty.js +187 -23
  42. package/initramfs/buninu/apps/jsgotty/static/js/kitty-keyboard.js +193 -0
  43. package/initramfs/buninu/apps/jsgotty/static/js/kitty.js +115 -7
  44. package/initramfs/buninu/apps/jsgotty/terminal-modes.js +332 -0
  45. package/initramfs/buninu/apps/jsgotty/tests/android-alt.test.js +115 -0
  46. package/initramfs/buninu/apps/jsgotty/tests/arrow-modifiers.test.js +80 -0
  47. package/initramfs/buninu/apps/jsgotty/tests/client-exit.test.mjs +45 -0
  48. package/initramfs/buninu/apps/jsgotty/tests/client-modes.test.mjs +105 -0
  49. package/initramfs/buninu/apps/jsgotty/tests/clipboard-browser.test.js +81 -0
  50. package/initramfs/buninu/apps/jsgotty/tests/clipboard.test.js +75 -0
  51. package/initramfs/buninu/apps/jsgotty/tests/kitty-keyboard-browser.test.js +53 -0
  52. package/initramfs/buninu/apps/jsgotty/tests/kitty-keyboard.test.js +102 -0
  53. package/initramfs/buninu/apps/jsgotty/tests/manual/README.md +20 -0
  54. package/initramfs/buninu/apps/jsgotty/tests/manual/keyboard-collector.cjs +55 -0
  55. package/initramfs/buninu/apps/jsgotty/tests/manual/keyboard-debug.js +74 -0
  56. package/initramfs/buninu/apps/jsgotty/tests/manual/kitty-keyboard.js +80 -0
  57. package/initramfs/buninu/apps/jsgotty/tests/manual/zoom-collector.cjs +55 -0
  58. package/initramfs/buninu/apps/jsgotty/tests/manual/zoom-debug.js +39 -0
  59. package/initramfs/buninu/apps/jsgotty/tests/manual-touch-diagnostics.js +33 -0
  60. package/initramfs/buninu/apps/jsgotty/tests/manual-touch-diagnostics.mjs +22 -0
  61. package/initramfs/buninu/apps/jsgotty/tests/nested-cli-pty.test.mjs +116 -0
  62. package/initramfs/buninu/apps/jsgotty/tests/reconnect-modes-browser.test.js +144 -0
  63. package/initramfs/buninu/apps/jsgotty/tests/reconnect-modes.md +44 -0
  64. package/initramfs/buninu/apps/jsgotty/tests/reconnect-modes.test.js +166 -0
  65. package/initramfs/buninu/apps/jsgotty/tests/touch-drag-browser.test.js +106 -0
  66. package/initramfs/buninu/apps/jsgotty/tests/wheel-browser.test.js +60 -0
  67. package/initramfs/buninu/apps/jsmdcui/CHANGELOG.md +44 -0
  68. package/initramfs/buninu/apps/jsmdcui/package.json +1 -1
  69. package/initramfs/buninu/apps/jsmdcui/src/highlight/go-regexp.js +83 -0
  70. package/initramfs/buninu/apps/jsmdcui/src/highlight/highlighter.js +49 -62
  71. package/initramfs/buninu/apps/jsmdcui/src/highlight/parser.js +8 -5
  72. package/initramfs/buninu/apps/jsmdcui/tests/go-regexp.test.js +98 -0
  73. package/initramfs/buninu/apps/jsmdcui/tests/heading-ids.test.js +21 -16
  74. package/initramfs/buninu/apps/jsmdcui/tests/highlight-regions.test.js +73 -0
  75. package/initramfs/buninu/apps/jsmdcui/tests/id-collision.test.js +32 -9
  76. package/initramfs/buninu/apps/jsmdcui/tests/markdown-behavior.mjs +9 -0
  77. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/NORMAL-HTML.md +46 -0
  78. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/README.md +85 -0
  79. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/REPORT.md +328 -0
  80. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/compare.mjs +75 -0
  81. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/go.mod +5 -0
  82. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/normal-html-report.json +619 -0
  83. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/normal-html.html +9 -0
  84. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/oracle.go +49 -0
  85. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/report.json +2174 -0
  86. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/PowerShell.txt +39 -0
  87. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/ada.txt +25 -0
  88. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/apacheconf.txt +49 -0
  89. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/arduino.txt +38 -0
  90. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/asciidoc.txt +33 -0
  91. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/asm.txt +77 -0
  92. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/ats.txt +48 -0
  93. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/awk.txt +28 -0
  94. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/b.txt +27 -0
  95. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/bat.txt +39 -0
  96. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/c.txt +34 -0
  97. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/caddyfile.txt +14 -0
  98. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/cake.txt +7 -0
  99. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/clojure.txt +18 -0
  100. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/cmake.txt +20 -0
  101. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/coffeescript.txt +32 -0
  102. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/colortest.txt +19 -0
  103. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/conky.txt +12 -0
  104. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/cpp.txt +46 -0
  105. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/crontab.txt +16 -0
  106. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/crystal.txt +28 -0
  107. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/csharp.txt +28 -0
  108. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/css.txt +19 -0
  109. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/csx.txt +7 -0
  110. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/cuda.txt +37 -0
  111. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/cython.txt +22 -0
  112. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/d.txt +52 -0
  113. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/dart.txt +27 -0
  114. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/default.txt +8 -0
  115. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/dockerfile.txt +10 -0
  116. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/dot.txt +15 -0
  117. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/elixir.txt +23 -0
  118. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/elm.txt +20 -0
  119. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/erb.txt +32 -0
  120. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/erlang.txt +23 -0
  121. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/fish.txt +20 -0
  122. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/forth.txt +17 -0
  123. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/fortran.txt +40 -0
  124. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/freebsd-kernel.txt +10 -0
  125. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/fsharp.txt +27 -0
  126. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/gdscript.txt +26 -0
  127. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/gemini.txt +11 -0
  128. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/gentoo-ebuild.txt +28 -0
  129. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/gentoo-etc-portage.txt +14 -0
  130. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/git-commit.txt +19 -0
  131. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/git-config.txt +11 -0
  132. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/git-rebase-todo.txt +10 -0
  133. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/gleam.txt +44 -0
  134. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/glsl.txt +18 -0
  135. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/gnuplot.txt +11 -0
  136. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/go.txt +33 -0
  137. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/godoc.txt +9 -0
  138. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/golo.txt +50 -0
  139. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/gomod.txt +16 -0
  140. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/graphql.txt +20 -0
  141. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/groff.txt +18 -0
  142. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/groovy.txt +42 -0
  143. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/haml.txt +16 -0
  144. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/hare.txt +31 -0
  145. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/haskell.txt +26 -0
  146. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/hc.txt +28 -0
  147. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/html.txt +26 -0
  148. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/html4.txt +20 -0
  149. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/html5.txt +20 -0
  150. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/ini.txt +16 -0
  151. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/inputrc.txt +14 -0
  152. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/java.txt +18 -0
  153. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/javascript.txt +41 -0
  154. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/jinja2.txt +13 -0
  155. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/json.txt +21 -0
  156. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/jsonnet.txt +28 -0
  157. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/julia.txt +24 -0
  158. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/justfile.txt +26 -0
  159. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/keymap.txt +15 -0
  160. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/kickstart.txt +16 -0
  161. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/kotlin.txt +30 -0
  162. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/kvlang.txt +37 -0
  163. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/ledger.txt +13 -0
  164. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/lfe.txt +17 -0
  165. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/lilypond.txt +15 -0
  166. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/lisp.txt +17 -0
  167. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/log.txt +45 -0
  168. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/lua.txt +48 -0
  169. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/mail.txt +17 -0
  170. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/makefile.txt +25 -0
  171. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/man.txt +12 -0
  172. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/markdown.txt +21 -0
  173. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/mc.txt +11 -0
  174. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/meson.txt +29 -0
  175. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/micro.txt +25 -0
  176. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/mpdconf.txt +13 -0
  177. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/msbuild.txt +7 -0
  178. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/nanorc.txt +16 -0
  179. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/nftables.txt +22 -0
  180. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/nginx.txt +17 -0
  181. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/nim.txt +23 -0
  182. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/nix.txt +15 -0
  183. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/nu.txt +92 -0
  184. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/objc.txt +36 -0
  185. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/ocaml.txt +25 -0
  186. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/octave.txt +35 -0
  187. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/odin.txt +35 -0
  188. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/pascal.txt +22 -0
  189. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/patch.txt +13 -0
  190. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/peg.txt +16 -0
  191. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/perl.txt +27 -0
  192. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/php.txt +44 -0
  193. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/pkg-config.txt +12 -0
  194. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/po.txt +12 -0
  195. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/pony.txt +29 -0
  196. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/pov.txt +17 -0
  197. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/privoxy-action.txt +14 -0
  198. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/privoxy-config.txt +10 -0
  199. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/privoxy-filter.txt +12 -0
  200. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/proto.txt +22 -0
  201. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/prql.txt +42 -0
  202. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/puppet.txt +22 -0
  203. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/python2.txt +24 -0
  204. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/python3.txt +28 -0
  205. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/r.txt +16 -0
  206. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/raku.txt +19 -0
  207. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/reST.txt +18 -0
  208. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/renpy.txt +11 -0
  209. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/rpmspec.txt +31 -0
  210. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/ruby.txt +34 -0
  211. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/rust.txt +27 -0
  212. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/sage.txt +24 -0
  213. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/scad.txt +23 -0
  214. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/scala.txt +16 -0
  215. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/sed.txt +12 -0
  216. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/sh.txt +20 -0
  217. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/sls.txt +15 -0
  218. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/smalltalk.txt +28 -0
  219. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/solidity.txt +26 -0
  220. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/sql.txt +35 -0
  221. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/stata.txt +32 -0
  222. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/svelte.txt +10 -0
  223. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/swift.txt +53 -0
  224. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/systemd.txt +15 -0
  225. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/tcl.txt +17 -0
  226. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/terraform.txt +28 -0
  227. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/tex.txt +15 -0
  228. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/toml.txt +31 -0
  229. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/twig.txt +29 -0
  230. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/typescript.txt +32 -0
  231. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/v.txt +47 -0
  232. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/vala.txt +22 -0
  233. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/verilog.txt +37 -0
  234. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/vhdl.txt +37 -0
  235. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/vi.txt +17 -0
  236. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/vue.txt +29 -0
  237. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/xml.txt +14 -0
  238. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/xresources.txt +14 -0
  239. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/yaml.txt +19 -0
  240. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/yum.txt +12 -0
  241. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/zig.txt +24 -0
  242. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/zscript.txt +31 -0
  243. package/initramfs/buninu/apps/jsmdcui/tests/syntax-parity/samples/zsh.txt +21 -0
  244. package/initramfs/buninu/package.json +1 -1
  245. package/initramfs/init.js +19 -3
  246. package/initramfs/lib/bunterm/clipboard.js +14 -0
  247. package/initramfs/lib/bunterm/commands.js +37 -0
  248. package/initramfs/lib/bunterm/fps.js +38 -0
  249. package/initramfs/lib/bunterm/images.js +14 -6
  250. package/initramfs/lib/bunterm/input.js +58 -15
  251. package/initramfs/lib/bunterm/keyboard.js +62 -0
  252. package/initramfs/lib/bunterm/keycodes.js +104 -0
  253. package/initramfs/lib/bunterm/kitty-keyboard.cjs +195 -0
  254. package/initramfs/lib/bunterm/raw-protocol.js +111 -0
  255. package/initramfs/lib/bunterm/renderer.js +116 -28
  256. package/initramfs/lib/bunterm/selection.js +60 -0
  257. package/initramfs/lib/bunterm/terminal.js +157 -12
  258. package/initramfs/lib/bunterm/vt-menu.js +181 -0
  259. package/initramfs/lib/bunterm/vt.js +27 -1
  260. package/initramfs/lib/canvas.js +99 -0
  261. package/initramfs/lib/chvt.js +31 -0
  262. package/initramfs/lib/fbdev.js +32 -8
  263. package/initramfs/lib/gpu.js +77 -0
  264. package/initramfs/lib/mapped-frame.js +28 -0
  265. package/initramfs/lib/raw-image.js +71 -0
  266. package/initramfs/lib/xdg-open.js +42 -0
  267. package/initramfs/usr/share/doc/buninu-linux/bunterm.md +85 -11
  268. package/initramfs/usr/share/doc/buninu-linux/chvt.md +34 -0
  269. package/initramfs/usr/share/doc/buninu-linux/xdg-open.md +43 -0
  270. package/package.json +1 -1
  271. package/scripts/arch.js +7 -5
  272. package/scripts/arch.sh +5 -5
  273. package/scripts/build.js +16 -3
  274. package/scripts/fetch-gpu.js +105 -0
  275. package/scripts/fetch.js +11 -1
  276. package/scripts/gpu-firmware.json +22 -0
  277. package/scripts/modules.js +4 -1
  278. package/scripts/npm-packages.md +18 -17
  279. package/test/bunterm-fps.test.js +17 -0
  280. package/test/bunterm-image-bytes.test.js +15 -0
  281. package/test/bunterm-keyboard.test.js +116 -0
  282. package/test/bunterm-mapped-lifetime.test.js +147 -0
  283. package/test/bunterm-next-vt.test.js +9 -0
  284. package/test/bunterm-raw-protocol.test.js +39 -0
  285. package/test/bunterm-renderer.test.js +167 -0
  286. package/test/bunterm-selection.test.js +38 -0
  287. package/test/bunterm-vt-menu.test.js +178 -0
  288. package/test/chroot-bind.test.js +40 -2
  289. package/test/chvt.test.js +46 -0
  290. package/test/fbdev-sync.test.js +42 -0
  291. package/test/fetch-npm.test.js +2 -2
  292. package/test/gpu.test.js +155 -0
  293. package/test/image-size.test.js +17 -0
  294. package/test/manual-bunterm-image-paths.js +31 -0
  295. package/test/mount-libc-lifetime.test.js +50 -0
  296. package/test/no-gpu.test.js +43 -0
  297. package/test/readme-cli.test.js +29 -0
  298. package/test/stage-npm.test.js +11 -4
  299. package/test/xdg-open.test.js +55 -0
@@ -0,0 +1,37 @@
1
+ // Local bunterm commands. Deliberately separate from the child shell.
2
+ export function createCommands({fontSize, setFontSize, copy, paste, switchVT}) {
3
+ const commands = new Map([
4
+ ["help", () => "font SIZE / + / - | copy | paste | vt NUMBER | help"],
5
+ ["font", args => {
6
+ if (args.length !== 1) throw new Error("Usage: font SIZE / + / -");
7
+ const size = args[0] === "+" ? fontSize()+1 : args[0] === "-" ? fontSize()-1 : Number(args[0]);
8
+ setFontSize(size);
9
+ return `Font: ${fontSize()}`;
10
+ }],
11
+ ["copy", async args => {
12
+ if (args.length) throw new Error("Usage: copy");
13
+ await copy();
14
+ return "Copied";
15
+ }],
16
+ ["paste", async args => {
17
+ if (args.length) throw new Error("Usage: paste");
18
+ await paste();
19
+ return "Pasted";
20
+ }],
21
+ ["vt", async args => {
22
+ if (args.length !== 1 || !/^[1-9]\d*$/.test(args[0]) || Number(args[0]) > 63) throw new Error("Usage: vt 1..63");
23
+ await switchVT(Number(args[0]));
24
+ return "";
25
+ }],
26
+ ]);
27
+ return {
28
+ commands,
29
+ async execute(line) {
30
+ const [name, ...args] = line.trim().split(/\s+/);
31
+ if (!name) return "";
32
+ const command = commands.get(name);
33
+ if (!command) throw new Error(`Unknown command: ${name}; try help`);
34
+ return await command(args);
35
+ },
36
+ };
37
+ }
@@ -0,0 +1,38 @@
1
+ // Count newly presented Kitty images, not pointer, menu or counter repaints.
2
+ export function createFpsMeter(now = () => performance.now()) {
3
+ let enabled = false, seen = new WeakSet(), frames = 0, since = 0, value = 0;
4
+ return {
5
+ get enabled() { return enabled; },
6
+ get value() { return value; },
7
+ toggle(images = []) {
8
+ enabled = !enabled;
9
+ seen = new WeakSet(images.map(({image}) => image)); frames = 0; value = 0; since = now();
10
+ return enabled;
11
+ },
12
+ presented(images) {
13
+ if (!enabled) return;
14
+ let fresh = false;
15
+ for (const {image} of images) {
16
+ if (!seen.has(image)) { seen.add(image); fresh = true; }
17
+ }
18
+ if (fresh) frames++;
19
+ },
20
+ sample() {
21
+ const time = now(), elapsed = time - since;
22
+ value = enabled && elapsed > 0 ? frames * 1000 / elapsed : 0;
23
+ frames = 0; since = time;
24
+ return value;
25
+ },
26
+ draw(renderer) {
27
+ if (!enabled) return;
28
+ const label = `FPS ${value.toFixed(1)}`;
29
+ const columns = Math.min(renderer.columns, label.length + 2);
30
+ const width = columns * renderer.cellWidth;
31
+ const x = renderer.offsetX + renderer.columns * renderer.cellWidth - width;
32
+ const y = renderer.offsetY;
33
+ renderer.canvas.drawRect(renderer.CanvasKit.XYWHRect(x,y,width,renderer.cellHeight),
34
+ renderer.paintFor([20,25,30]));
35
+ renderer.drawText(label,x,y,columns,[65,220,230],{align:"center"});
36
+ },
37
+ };
38
+ }
@@ -1,3 +1,4 @@
1
+ import {createRawImage} from '../raw-image.js';
1
2
  // /lib/bunterm/images.js — kitty graphics protocol placements on the cell
2
3
  // grid.
3
4
  //
@@ -15,12 +16,13 @@ const number = (value, fallback = 0) => {
15
16
  // Decodes a transferred image into a Skia Image. Format 100 is PNG (or any
16
17
  // encoded format Skia knows); 24 and 32 are raw RGB / RGBA. Bun.Image, when
17
18
  // present, transcodes encodings Skia cannot read on its own.
18
- export const decodeImage = async (CanvasKit, image) => {
19
+ export const decodeImage = async (CanvasKit, image, {deferRaw = false} = {}) => {
19
20
  // The local parser supplies bytes; retain compatibility with base64 callers.
20
21
  const bytes = typeof image.data === "string" ? Buffer.from(image.data, "base64") : image.data;
21
- if (image.format === 24 || image.format === 32) {
22
+ if (image.format === 24 || image.format === 32 || image.format === 0x42475241) {
22
23
  const { width, height } = image;
23
- if (!width || !height) throw new Error("raw image without dimensions");
24
+ if (!Number.isInteger(width)||!Number.isInteger(height)||width<1||height<1||width*height>16777216
25
+ ||bytes.byteLength!==width*height*(image.format===24?3:4)) throw new Error("invalid raw image dimensions or byte count");
24
26
  let pixels = bytes;
25
27
  if (image.format === 24) {
26
28
  pixels = Buffer.alloc(width * height * 4, 255);
@@ -30,9 +32,11 @@ export const decodeImage = async (CanvasKit, image) => {
30
32
  pixels[o + 2] = bytes[i + 2];
31
33
  }
32
34
  }
35
+ const colorType = image.format === 0x42475241 ? CanvasKit.ColorType.BGRA_8888 : CanvasKit.ColorType.RGBA_8888;
36
+ if (deferRaw) return createRawImage(CanvasKit, pixels, width, height, colorType);
33
37
  const decoded = CanvasKit.MakeImage({
34
38
  width, height,
35
- colorType: CanvasKit.ColorType.RGBA_8888,
39
+ colorType: image.format === 0x42475241 ? CanvasKit.ColorType.BGRA_8888 : CanvasKit.ColorType.RGBA_8888,
36
40
  alphaType: CanvasKit.AlphaType.Unpremul,
37
41
  colorSpace: CanvasKit.ColorSpace.SRGB,
38
42
  }, pixels, width * 4);
@@ -57,6 +61,7 @@ export class ImageStore {
57
61
  this.imageSources = new Map(); // image id → parser image object
58
62
  this.placements = new Map(); // placement key → placement
59
63
  this.counter = 0;
64
+ this.closed = false;
60
65
  this.coveredKey = "";
61
66
  this.coveredRows = new Set();
62
67
  }
@@ -64,7 +69,7 @@ export class ImageStore {
64
69
  // Handles one parsed graphic. Returns the control sequence that moves the
65
70
  // cursor past a placement (to be written to the terminal), or "".
66
71
  async handle(graphic) {
67
- if (!graphic) return "";
72
+ if (this.closed || !graphic) return "";
68
73
  if (graphic.kind === "delete") {
69
74
  this.remove(graphic.delete);
70
75
  return "";
@@ -75,7 +80,8 @@ export class ImageStore {
75
80
  const replacesImage = decoded && this.imageSources.get(image.id) !== image;
76
81
  if (!decoded || replacesImage) {
77
82
  try {
78
- const replacement = await decodeImage(this.CanvasKit, image);
83
+ const replacement = await decodeImage(this.CanvasKit, image, {deferRaw: true});
84
+ if (this.closed) { replacement.delete(); return ""; }
79
85
  if (replacesImage) {
80
86
  // Kitty requires retransmitting a non-zero image id to delete the
81
87
  // old image and all its placements. Screen-streaming clients such
@@ -232,6 +238,8 @@ export class ImageStore {
232
238
  }
233
239
 
234
240
  delete() {
241
+ if (this.closed) return;
242
+ this.closed = true;
235
243
  for (const placement of [...this.placements.values()]) placement.marker?.dispose();
236
244
  this.placements.clear();
237
245
  for (const image of this.images.values()) image.delete();
@@ -6,8 +6,9 @@
6
6
  // "linux" console sequences for a few keys are rewritten into the xterm
7
7
  // forms that programs seeing TERM=xterm-256color expect.
8
8
 
9
- import { closeSync, openSync, read } from "node:fs";
9
+ import { closeSync, openSync, readSync, constants } from "node:fs";
10
10
  import { libc, ptr, errno, strerror } from "../dlopen.js";
11
+ import { ConsoleKeys, MediumRawDecoder } from "./keycodes.js";
11
12
 
12
13
  const TCGETS = 0x5401;
13
14
  const TCSETS = 0x5402;
@@ -108,33 +109,75 @@ export const translateKeys = (text, { applicationCursorKeys = false } = {}) => {
108
109
  // Opens the keyboard: `device` names a console such as /dev/tty1; without
109
110
  // it the process's own stdin is used (it must be a terminal). `onData`
110
111
  // receives Buffers. close() restores the previous terminal settings.
111
- export const openKeyboard = ({ device = null, onData, onError = () => {} }) => {
112
- const fd = device ? openSync(device, "r+") : 0;
113
- const saved = getTermios(fd);
114
- setTermios(fd, rawTermios(saved));
112
+ export const openKeyboard = ({ device = null, onData, onKey = () => {}, onError = () => {} }) => {
113
+ // Own a nonblocking file description: no outstanding async read can deliver
114
+ // bytes from the previous keyboard mode after a protocol transition.
115
+ const fd = openSync(device || "/proc/self/fd/0", constants.O_RDWR | constants.O_NONBLOCK);
116
+ let saved;
117
+ try {
118
+ saved = getTermios(fd);
119
+ setTermios(fd, rawTermios(saved));
120
+ } catch (error) {
121
+ closeSync(fd);
122
+ throw error;
123
+ }
124
+ const originalMode = new Int32Array(1);
125
+ const canReadMode = libc.symbols.ioctl(fd, 0x4b44, ptr(originalMode)) === 0;
126
+ let enhanced = false, decoder, keys;
127
+ const setEnhanced = (enabled) => {
128
+ if (enabled === enhanced) return;
129
+ if (!canReadMode) throw new Error("Kitty keyboard needs a Linux virtual console (KDGKBMODE)");
130
+ const maps = [];
131
+ if (enabled) {
132
+ // Unicode keysyms can only be queried while the console is still in
133
+ // K_UNICODE, before switching to K_MEDIUMRAW.
134
+ for (let table = 0; table < 4; table++) {
135
+ maps[table] = [];
136
+ for (let number = 0; number < 256; number++) {
137
+ const entry = new Uint8Array([table,number,0,0]);
138
+ maps[table][number] = libc.symbols.ioctl(fd,0x4b46,ptr(entry)) === 0
139
+ ? new DataView(entry.buffer).getUint16(2,true) : null;
140
+ }
141
+ }
142
+ }
143
+ // Discard only console typeahead at the mode boundary, never PTY input.
144
+ if (libc.symbols.ioctl(fd, 0x540b, 0) === -1) fail("TCFLSH");
145
+ if (libc.symbols.ioctl(fd, 0x4b45, enabled ? 2 : originalMode[0]) === -1) fail("KDSKBMODE");
146
+ enhanced = enabled;
147
+ decoder = new MediumRawDecoder();
148
+ const leds = new Uint8Array(1);
149
+ libc.symbols.ioctl(fd, 0x4b64, ptr(leds));
150
+ keys = new ConsoleKeys({ leds: leds[0], lookup: (table, number) => maps[table]?.[number] });
151
+ };
115
152
  let open = true;
153
+ let timer;
116
154
  const chunk = Buffer.alloc(4096);
117
155
  const pump = () => {
118
156
  if (!open) return;
119
- read(fd, chunk, 0, chunk.length, null, (error, count) => {
120
- if (!open) return;
121
- if (error) {
122
- if (error.code === "EAGAIN") { setTimeout(pump, 10); return; }
123
- onError(error);
124
- return;
157
+ try {
158
+ for (let batch = 0; batch < 16; batch++) {
159
+ const count = readSync(fd, chunk, 0, chunk.length, null);
160
+ if (!count) break;
161
+ if (enhanced) decoder.feed(chunk.subarray(0, count), (code, down) => onKey(keys.event(code, down)));
162
+ else onData(Buffer.from(chunk.subarray(0, count)));
125
163
  }
126
- if (count > 0) onData(Buffer.from(chunk.subarray(0, count)));
127
- pump();
128
- });
164
+ } catch (error) {
165
+ if (error.code !== "EAGAIN" && error.code !== "EWOULDBLOCK") { onError(error); return; }
166
+ }
167
+ timer = setTimeout(pump, 4);
129
168
  };
130
169
  pump();
131
170
  return {
132
171
  fd,
172
+ setEnhanced,
173
+ clearHeld() { keys?.held.clear(); },
133
174
  close() {
134
175
  if (!open) return;
135
176
  open = false;
177
+ clearTimeout(timer);
178
+ try { setEnhanced(false); } catch (error) { onError(error); }
136
179
  try { setTermios(fd, saved); } catch {}
137
- if (device) closeSync(fd);
180
+ closeSync(fd);
138
181
  },
139
182
  };
140
183
  };
@@ -0,0 +1,62 @@
1
+ import { createRequire } from "node:module";
2
+ import { legacyKey } from "./keycodes.js";
3
+ const { KittyKeyboard } = createRequire(import.meta.url)("./kitty-keyboard.cjs");
4
+
5
+ // The same protocol engine as jsgotty, with a console-mode notification.
6
+ // Wait for the console to exist before installing handlers/advertising support.
7
+ export function attachKeyboard({term, write, setEnhanced, localInput = () => false,
8
+ switchVT = () => {}, switchRelative = () => {}, onError = () => {}}) {
9
+ let keyboard, enhanced = false;
10
+ const sync = () => {
11
+ const next = Boolean(keyboard?.flags);
12
+ if (next === enhanced) return;
13
+ try {
14
+ setEnhanced(next);
15
+ enhanced = next;
16
+ keyboard.clearHeld(false);
17
+ } catch (error) {
18
+ keyboard.reset();
19
+ onError(error);
20
+ }
21
+ };
22
+ const wrap = name => (id, fn) => term.parser[name](id, params => {
23
+ const result = fn(params);
24
+ sync();
25
+ return result;
26
+ });
27
+ keyboard = new KittyKeyboard({
28
+ parser: {registerCsiHandler:wrap("registerCsiHandler"),registerEscHandler:wrap("registerEscHandler")},
29
+ buffer:term.buffer,options:term.options,
30
+ input: text => write(text),
31
+ });
32
+ const bufferChange = term.buffer.onBufferChange(sync);
33
+ const reserved = new Set();
34
+ return {
35
+ get flags() { return keyboard.flags; },
36
+ event(event) {
37
+ // Mediumraw disables the kernel's console shortcuts. Keep Ctrl-Alt-Fn
38
+ // available even when a client has requested all keys.
39
+ if (event.type === "keydown" && event.ctrlKey && event.altKey && /^F([1-9]|1[0-2])$/.test(event.key)) {
40
+ reserved.add(event.code);
41
+ if (!event.repeat) switchVT(Number(event.key.slice(1)));
42
+ return;
43
+ }
44
+ if (event.type === "keydown" && event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey &&
45
+ ["ArrowLeft","ArrowRight"].includes(event.key)) {
46
+ reserved.add(event.code);
47
+ if (!event.repeat) switchRelative(event.key === "ArrowLeft" ? -1 : 1);
48
+ return;
49
+ }
50
+ if (event.type === "keyup" && reserved.delete(event.code)) return;
51
+ const text = legacyKey(event, Boolean(term._core?.coreService?.decPrivateModes?.applicationCursorKeys));
52
+ if (localInput(event, text)) { keyboard.clearHeld(); return; }
53
+ if (keyboard.handle(event) && text) write(text);
54
+ },
55
+ blur() { keyboard.clearHeld(); reserved.clear(); },
56
+ dispose() {
57
+ bufferChange.dispose();
58
+ keyboard.dispose();
59
+ if (enhanced) setEnhanced(false);
60
+ },
61
+ };
62
+ }
@@ -0,0 +1,104 @@
1
+ // Linux K_MEDIUMRAW -> browser-shaped key events for the shared Kitty encoder.
2
+ // The kernel keymap supplies text; these names identify physical/function keys.
3
+ const keys = {};
4
+ const row = (start, names) => names.split(" ").forEach((name, i) => { keys[start + i] = name; });
5
+ row(1, "Escape Digit1 Digit2 Digit3 Digit4 Digit5 Digit6 Digit7 Digit8 Digit9 Digit0 Minus Equal Backspace Tab");
6
+ row(16, "KeyQ KeyW KeyE KeyR KeyT KeyY KeyU KeyI KeyO KeyP BracketLeft BracketRight Enter ControlLeft");
7
+ row(30, "KeyA KeyS KeyD KeyF KeyG KeyH KeyJ KeyK KeyL Semicolon Quote Backquote ShiftLeft Backslash");
8
+ row(44, "KeyZ KeyX KeyC KeyV KeyB KeyN KeyM Comma Period Slash ShiftRight NumpadMultiply AltLeft Space CapsLock");
9
+ row(59, "F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 NumLock ScrollLock Numpad7 Numpad8 Numpad9 NumpadSubtract Numpad4 Numpad5 Numpad6 NumpadAdd Numpad1 Numpad2 Numpad3 Numpad0 NumpadDecimal");
10
+ row(86, "IntlBackslash F11 F12");
11
+ row(96, "NumpadEnter ControlRight NumpadDivide PrintScreen AltRight");
12
+ row(102, "Home ArrowUp PageUp ArrowLeft ArrowRight End ArrowDown PageDown Insert Delete");
13
+ Object.assign(keys, {113:"AudioVolumeMute",114:"AudioVolumeDown",115:"AudioVolumeUp",
14
+ 117:"NumpadEqual",119:"Pause",121:"NumpadComma",125:"MetaLeft",126:"MetaRight",
15
+ 127:"ContextMenu",163:"MediaTrackNext",164:"MediaPlayPause",165:"MediaTrackPrevious",
16
+ 166:"MediaStop",167:"MediaRecord",168:"MediaRewind",208:"MediaFastForward"});
17
+ row(183, "F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24");
18
+ const special = {NumpadEnter:"Enter",NumpadDivide:"/",NumpadMultiply:"*",NumpadAdd:"+",
19
+ NumpadSubtract:"-",NumpadDecimal:".",NumpadEqual:"=",NumpadComma:","};
20
+ const navigation = ["Insert","End","ArrowDown","PageDown","ArrowLeft","Clear","ArrowRight","Home","ArrowUp","PageUp"];
21
+
22
+ // Mediumraw encodes >=128 as prefix (0 or 128), then two 7-bit groups
23
+ // with bit 7 set. Preserve incomplete triples across read() boundaries.
24
+ export class MediumRawDecoder {
25
+ pending = [];
26
+ feed(bytes, emit) {
27
+ for (const byte of bytes) {
28
+ this.pending.push(byte);
29
+ const first = this.pending[0];
30
+ if ((first & 127) !== 0) {
31
+ emit(first & 127, !(first & 128));
32
+ this.pending = [];
33
+ } else if (this.pending.length === 3) {
34
+ emit(((this.pending[1] & 127) << 7) | (this.pending[2] & 127), !(first & 128));
35
+ this.pending = [];
36
+ }
37
+ }
38
+ }
39
+ }
40
+
41
+ export class ConsoleKeys {
42
+ constructor({ lookup, leds = 0 } = {}) {
43
+ this.lookup = lookup;
44
+ this.held = new Set();
45
+ this.caps = Boolean(leds & 4);
46
+ this.num = Boolean(leds & 2);
47
+ }
48
+ event(number, down) {
49
+ const repeat = down && this.held.has(number);
50
+ if (down) this.held.add(number); else this.held.delete(number);
51
+ if (down && !repeat && number === 58) this.caps = !this.caps;
52
+ if (down && !repeat && number === 69) this.num = !this.num;
53
+ const shiftKey = this.held.has(42) || this.held.has(54);
54
+ const ctrlKey = this.held.has(29) || this.held.has(97);
55
+ const altKey = this.held.has(56);
56
+ const altgr = this.held.has(100);
57
+ const metaKey = this.held.has(125) || this.held.has(126);
58
+ const code = keys[number] || `LinuxKey${number}`;
59
+ let key = code.replace(/^(Shift|Control|Alt|Meta)(Left|Right)$/, "$1");
60
+ if (number === 100) key = "AltGraph";
61
+ else if (special[code]) key = special[code];
62
+ else if (/^Numpad\d$/.test(code)) key = this.num !== shiftKey ? code.slice(6) : navigation[Number(code.slice(6))];
63
+ else if (/^(Key|Digit|Intl)/.test(code) || ["Space","Minus","Equal","BracketLeft","BracketRight",
64
+ "Backslash","Semicolon","Quote","Backquote","Comma","Period","Slash"].includes(code)) {
65
+ // Exclude Ctrl/Alt from translation: the encoder needs the character,
66
+ // not an already-collapsed control byte or an ESC prefix.
67
+ const table = (shiftKey ? 1 : 0) | (altgr ? 2 : 0);
68
+ let symbol = this.lookup?.(table, number);
69
+ if ((symbol >> 8) === 11 && this.caps) symbol = this.lookup?.(table ^ 1, number);
70
+ const type = symbol >> 8;
71
+ key = symbol == null ? "Unidentified"
72
+ : type === 0 || type === 11 ? String.fromCodePoint(symbol & 255)
73
+ : type >= 16 ? String.fromCodePoint(symbol ^ 0xf000)
74
+ : type === 4 || type === 13 ? "Dead" : "Unidentified";
75
+ }
76
+ return {type:down?"keydown":"keyup",code,key,repeat,shiftKey,ctrlKey,altKey,metaKey,
77
+ location:/^Numpad/.test(code)?3:/Right$/.test(code)?2:/Left$/.test(code)?1:0,
78
+ getModifierState: name => name === "CapsLock" ? this.caps : name === "NumLock" ? this.num : name === "AltGraph" && altgr,
79
+ preventDefault() {}, stopPropagation() {}};
80
+ }
81
+ }
82
+
83
+ // Recovery/plain-text path when the negotiated enhancements leave a key in
84
+ // legacy form. Used only in Kitty mode; normal console input stays unchanged.
85
+ export function legacyKey(event, applicationCursorKeys = false) {
86
+ if (event.type !== "keydown") return "";
87
+ const { key, ctrlKey, altKey, shiftKey } = event;
88
+ let text = ({Enter:"\r",Tab:shiftKey?"\x1b[Z":"\t",Backspace:"\x7f",Escape:"\x1b"})[key];
89
+ const cursor = {ArrowUp:"A",ArrowDown:"B",ArrowRight:"C",ArrowLeft:"D",Home:"H",End:"F"}[key];
90
+ if (cursor) text = `\x1b${applicationCursorKeys?"O":"["}${cursor}`;
91
+ const tilde = {Insert:2,Delete:3,PageUp:5,PageDown:6}[key];
92
+ if (tilde) text = `\x1b[${tilde}~`;
93
+ if (text === undefined && [...key].length === 1) {
94
+ text = key;
95
+ if (ctrlKey) {
96
+ const n = key.toUpperCase().codePointAt(0);
97
+ if (n >= 64 && n <= 95) text = String.fromCharCode(n & 31);
98
+ else if (key === " " || key === "2") text = "\0";
99
+ else if (key === "/" || key === "?") text = "\x1f";
100
+ else if (key === "8") text = "\x7f";
101
+ }
102
+ }
103
+ return text === undefined ? "" : (altKey ? "\x1b" : "") + text;
104
+ }
@@ -0,0 +1,195 @@
1
+ // Vendored from jsgotty 1.2.0, static/js/kitty-keyboard.js (MIT).
2
+ // Keep protocol behavior aligned with the browser terminal.
3
+ // Kitty keyboard transport for the shipped xterm wrapper (no build step).
4
+ // Spec: https://sw.kovidgoyal.net/kitty/keyboard-protocol/
5
+ (function (root) {
6
+ 'use strict';
7
+ // Supported progressive enhancements: disambiguation, event types, all keys.
8
+ // Do not advertise alternate-layout/text reporting until those are implemented.
9
+ const SUPPORTED = 1 | 2 | 8;
10
+ const functional = {
11
+ Escape:[27,'u'], Enter:[13,'u'], Tab:[9,'u'], Backspace:[127,'u'],
12
+ Insert:[2,'~'], Delete:[3,'~'], ArrowLeft:[1,'D'], ArrowRight:[1,'C'],
13
+ ArrowUp:[1,'A'], ArrowDown:[1,'B'], PageUp:[5,'~'], PageDown:[6,'~'],
14
+ Home:[1,'H'], End:[1,'F'], CapsLock:[57358,'u'], ScrollLock:[57359,'u'],
15
+ NumLock:[57360,'u'], PrintScreen:[57361,'u'], Pause:[57362,'u'], ContextMenu:[57363,'u'],
16
+ MediaPlay:[57428,'u'], MediaPause:[57429,'u'], MediaPlayPause:[57430,'u'],
17
+ MediaStop:[57432,'u'], MediaFastForward:[57433,'u'], MediaRewind:[57434,'u'],
18
+ MediaTrackNext:[57435,'u'], MediaTrackPrevious:[57436,'u'], MediaRecord:[57437,'u'],
19
+ AudioVolumeDown:[57438,'u'], AudioVolumeUp:[57439,'u'], AudioVolumeMute:[57440,'u'],
20
+ };
21
+ [11,12,13,14,15,17,18,19,20,21,23,24].forEach((n,i) => functional['F'+(i+1)] = [n,'~']);
22
+ for (let i=13;i<=35;i++) functional['F'+i] = [57376+i-13,'u'];
23
+ const punctuation = {
24
+ Backquote:['`','~'], Minus:['-','_'], Equal:['=','+'], BracketLeft:['[','{'],
25
+ BracketRight:[']','}'], Backslash:['\\','|'], Semicolon:[';',':'], Quote:["'",'"'],
26
+ Comma:[',','<'], Period:['.','>'], Slash:['/','?'], Space:[' ',' '],
27
+ };
28
+ const modifiers = {Shift:[1,57441], Control:[4,57442], Alt:[2,57443], Meta:[8,57444],
29
+ OS:[8,57444], Super:[8,57444], Hyper:[16,57445], AltGraph:[0,57453]};
30
+ const has = (object,key) => Object.prototype.hasOwnProperty.call(object,key);
31
+ const lock = (e,name) => Boolean(e.getModifierState?.(name));
32
+ function physicalCode(e) {
33
+ if (e.code && e.code !== 'Unidentified') return e.code;
34
+ if (e.keyCode>=65 && e.keyCode<=90) return 'Key'+String.fromCharCode(e.keyCode);
35
+ if (e.keyCode>=48 && e.keyCode<=57) return 'Digit'+String.fromCharCode(e.keyCode);
36
+ return ({32:'Space',186:'Semicolon',187:'Equal',188:'Comma',189:'Minus',190:'Period',
37
+ 191:'Slash',192:'Backquote',219:'BracketLeft',220:'Backslash',221:'BracketRight',222:'Quote'})[e.keyCode] || '';
38
+ }
39
+ function baseCharacter(e, android) {
40
+ const code=physicalCode(e);
41
+ // Android's Alt accent conversion must not turn an E/I/N/U shortcut into a dead key.
42
+ const recover=android && e.altKey && !lock(e,'AltGraph');
43
+ if (recover || ([...e.key || ''].length===1 && e.key.codePointAt(0)<32)) {
44
+ if (/^Key[A-Z]$/.test(code)) return code.slice(3).toLowerCase();
45
+ if (/^Digit[0-9]$/.test(code)) return code.slice(5);
46
+ if (has(punctuation,code)) return punctuation[code][0];
47
+ }
48
+ if ([...e.key || ''].length!==1) return null;
49
+ if (e.shiftKey) {
50
+ if (has(punctuation,code) && punctuation[code][1]===e.key) return punctuation[code][0];
51
+ if (/^Digit[0-9]$/.test(code) && ')!@#$%^&*('[Number(code.slice(5))]===e.key) return code.slice(5);
52
+ }
53
+ const lower=e.key.toLowerCase();
54
+ return [...lower].length===1 ? lower : e.key;
55
+ }
56
+ function keyDefinition(e, flags, android) {
57
+ if (has(modifiers,e.key)) {
58
+ const [bit,left]=modifiers[e.key];
59
+ const right=e.location===2 || /Right$/.test(e.code || '');
60
+ return {number:left+(right && e.key!=='AltGraph'?6:0),suffix:'u',modifier:bit};
61
+ }
62
+ if ((flags & 9) && (e.location===3 || /^Numpad/.test(e.code || ''))) {
63
+ const numpad={NumpadDecimal:57409,NumpadDivide:57410,NumpadMultiply:57411,
64
+ NumpadSubtract:57412,NumpadAdd:57413,NumpadEnter:57414,NumpadEqual:57415,
65
+ NumpadComma:57416};
66
+ const nav={ArrowLeft:57417,ArrowRight:57418,ArrowUp:57419,ArrowDown:57420,
67
+ PageUp:57421,PageDown:57422,Home:57423,End:57424,Insert:57425,Delete:57426,Clear:57427};
68
+ const number=has(nav,e.key)?nav[e.key]:/^Numpad[0-9]$/.test(e.code || '')
69
+ ?57399+Number(e.code.slice(6)):numpad[e.code];
70
+ if (number) return {number,suffix:'u'};
71
+ }
72
+ if (has(functional,e.key)) {
73
+ const [number,suffix]=functional[e.key];
74
+ return {number,suffix,recovery:['Enter','Tab','Backspace'].includes(e.key)};
75
+ }
76
+ const ch=baseCharacter(e,android);
77
+ return ch===null?null:{number:ch.codePointAt(0),suffix:'u',text:true};
78
+ }
79
+ class KittyKeyboard {
80
+ constructor(term, {android=false}={}) {
81
+ this.term=term; this.android=android; this.disposables=[];
82
+ this.metaKeys=new Set(); this.down=new Map(); this.suppressed=new Set(); this.reset();
83
+ const register=(prefix,fn) => this.disposables.push(term.parser.registerCsiHandler({prefix,final:'u'},p=>{fn(p);return true;}));
84
+ const value=(p,i,fallback=0) => Number.isInteger(p[i])?p[i]:fallback;
85
+ register('?',()=>term.input(`\x1b[?${this.flags}u`,false));
86
+ register('>',p=>{const s=this.state;s.stack.push(s.flags);if(s.stack.length>32)s.stack.shift();s.flags=value(p,0)&SUPPORTED;});
87
+ register('<',p=>{const s=this.state;let count=Math.min(value(p,0)||1,33);while(count--)s.flags=s.stack.pop()??0;});
88
+ register('=',p=>{const s=this.state,f=value(p,0)&SUPPORTED,m=value(p,1)||1;if(m===1)s.flags=f;else if(m===2)s.flags|=f;else if(m===3)s.flags&=~f;});
89
+ this.disposables.push(term.parser.registerEscHandler({final:'c'},()=>{this.reset();return false;}));
90
+ this.disposables.push(term.parser.registerCsiHandler({intermediates:'!',final:'p'},()=>{this.reset();return false;}));
91
+ }
92
+ get state() { return this.states[this.term.buffer.active.type==='alternate'?'alternate':'normal']; }
93
+ get flags() { return this.state.flags; }
94
+ reset() {
95
+ this.states={normal:{flags:0,stack:[]},alternate:{flags:0,stack:[]}};
96
+ this.clearHeld(false);
97
+ }
98
+ clearHeld(report=true) {
99
+ // Release keys reported to the client before losing focus, avoiding stuck remote keys.
100
+ if (report && (this.flags & 2)) for (const key of this.down.values()) {
101
+ if(key.reported) this.term.input(this.sequence(key.def,0,3),true);
102
+ }
103
+ this.metaKeys.clear();this.down.clear();this.suppressed.clear();this.suppressKeypress=false;
104
+ }
105
+ attach(element) {
106
+ const doc=element.ownerDocument, win=doc.defaultView;
107
+ const blur=()=>this.clearHeld();
108
+ const visibility=()=>{if(doc.hidden)this.clearHeld();};
109
+ element.addEventListener('blur',blur);win.addEventListener('blur',blur);
110
+ doc.addEventListener('visibilitychange',visibility);
111
+ this.disposables.push({dispose:()=>{element.removeEventListener('blur',blur);win.removeEventListener('blur',blur);doc.removeEventListener('visibilitychange',visibility);}});
112
+ }
113
+ dispose() {this.clearHeld(false);for(const d of this.disposables)d.dispose();}
114
+ sequence(def,bits,type) {
115
+ const event=(this.flags&2) && type!==1?':'+type:'';
116
+ const mods=bits+1;
117
+ if(def.suffix!=='u' && mods===1 && !event)
118
+ return '\x1b['+(def.number===1?'':def.number)+def.suffix;
119
+ return `\x1b[${def.number}${mods!==1||event?';'+mods+event:''}${def.suffix}`;
120
+ }
121
+ handle(event) {
122
+ if (!['keydown','keyup','keypress'].includes(event.type)) return true;
123
+ const identity=physicalCode(event)||event.key;
124
+ const metaKey=['Meta','OS','Super'].includes(event.key);
125
+ if(this.android && metaKey) {
126
+ if(event.type==='keydown')this.metaKeys.add(event.code||String(event.location||0));
127
+ if(event.type==='keyup')this.metaKeys.delete(event.code||String(event.location||0));
128
+ }
129
+ // Patch only this terminal's Android event, preserving the native DOM event.
130
+ if(this.android && this.metaKeys.size && !event.metaKey) {
131
+ const original=event.getModifierState?.bind(event);
132
+ Object.defineProperties(event,{
133
+ metaKey:{configurable:true,value:true},
134
+ getModifierState:{configurable:true,value:name=>name==='Meta'||Boolean(original?.(name))},
135
+ });
136
+ }
137
+ if(!this.flags || this.term.options.disableStdin) return true;
138
+ const consume=()=>{event.preventDefault();event.stopPropagation();return false;};
139
+ if(event.type==='keypress')return this.suppressKeypress?consume():true;
140
+ let previous=this.down.get(identity);
141
+ if(event.type==='keyup') {
142
+ // Some Android IMEs emit only the release of an Alt dead key. Recover
143
+ // that chord here too, never falling back to legacy ESC text in Kitty mode.
144
+ if(!previous && this.android && event.altKey && event.key==='Dead' &&
145
+ !event.isComposing && !lock(event,'AltGraph') && (this.flags&9)) {
146
+ const def=keyDefinition(event,this.flags,this.android);
147
+ if(def) {
148
+ this.term.input(this.sequence(def,this.bits(event),1),true);
149
+ previous={def,reported:true};this.suppressed.add(identity);
150
+ }
151
+ }
152
+ this.down.delete(identity);
153
+ const suppressed=this.suppressed.delete(identity);
154
+ this.suppressKeypress=false;
155
+ if(previous?.reported && (this.flags&2)) {
156
+ let bits=this.bits(event);
157
+ if(previous.def.modifier && ![...this.down.values()].some(k=>k.def.modifier===previous.def.modifier)) bits &= ~previous.def.modifier;
158
+ if(metaKey && this.metaKeys.size) bits|=8;
159
+ this.term.input(this.sequence(previous.def,bits,3),true);
160
+ }
161
+ return suppressed?consume():true;
162
+ }
163
+ this.suppressKeypress=false;
164
+ if(event.isComposing || event.keyCode===229 && event.key==='Unidentified')return true;
165
+ if(event.key==='Dead' && !(this.android && event.altKey && !lock(event,'AltGraph')))return true;
166
+ const def=keyDefinition(event,this.flags,this.android);
167
+ if(!def)return true;
168
+ let bits=this.bits(event);
169
+ if(def.modifier!==undefined) {
170
+ if(!(this.flags&8))return true;
171
+ bits|=def.modifier;
172
+ }
173
+ const all=Boolean(this.flags&8);
174
+ // Enter/Tab/Backspace remain recovery keys unless modified or report-all is requested.
175
+ if(!all && def.recovery && !(bits&~192))return true;
176
+ const shortcut=Boolean(bits&62);
177
+ if(def.text && !all && !(this.flags&1 && shortcut))return true;
178
+ // With only event reporting requested, leave legacy printable shortcuts untouched.
179
+ if(def.text && !all && !(this.flags&1))return true;
180
+ const type=event.repeat?2:1;
181
+ this.down.set(identity,{def,reported:!(def.recovery && !all)});this.suppressed.add(identity);this.suppressKeypress=true;
182
+ this.term.input(this.sequence(def,bits,type),true);
183
+ return consume();
184
+ }
185
+ bits(e) {
186
+ const altgr=lock(e,'AltGraph');
187
+ return (e.shiftKey?1:0)|(!altgr&&e.altKey?2:0)|(!altgr&&e.ctrlKey?4:0)|
188
+ (e.metaKey || this.android&&this.metaKeys.size?8:0)|
189
+ (lock(e,'Hyper')?16:0)|(lock(e,'CapsLock')?64:0)|(lock(e,'NumLock')?128:0);
190
+ }
191
+ }
192
+ const api={KittyKeyboard,SUPPORTED};
193
+ if(typeof module==='object' && module.exports)module.exports=api;
194
+ else root.GoTTYKittyKeyboard=api;
195
+ })(globalThis);