buninu 0.5.0 → 0.7.0
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/CHANGELOG.md +47 -0
- package/apps/jsgotty/LICENSES/MIT-jsmdcui.txt +22 -0
- package/apps/jsgotty/NOTICE +5 -0
- package/apps/jsgotty/README.en.md +21 -0
- package/apps/jsgotty/README.md +21 -0
- package/apps/jsgotty/client-modes.mjs +117 -0
- package/apps/jsgotty/client.mjs +100 -10
- package/apps/jsgotty/clipboard-powershell.js +18 -0
- package/apps/jsgotty/clipboard.js +148 -0
- package/apps/jsgotty/gotty.js +13 -0
- package/apps/jsgotty/package-lock.json +2 -2
- package/apps/jsgotty/package.json +1 -1
- package/apps/jsgotty/static/css/index.css +14 -1
- package/apps/jsgotty/static/js/gotty.js +107 -8
- package/apps/jsgotty/static/js/kitty.js +115 -7
- package/apps/jsgotty/terminal-modes.js +332 -0
- package/apps/jsgotty/tests/client-exit.test.mjs +45 -0
- package/apps/jsgotty/tests/client-modes.test.mjs +105 -0
- package/apps/jsgotty/tests/clipboard-browser.test.js +81 -0
- package/apps/jsgotty/tests/clipboard.test.js +75 -0
- package/apps/jsgotty/tests/manual/zoom-collector.cjs +55 -0
- package/apps/jsgotty/tests/manual/zoom-debug.js +39 -0
- package/apps/jsgotty/tests/manual-touch-diagnostics.js +33 -0
- package/apps/jsgotty/tests/manual-touch-diagnostics.mjs +22 -0
- package/apps/jsgotty/tests/nested-cli-pty.test.mjs +116 -0
- package/apps/jsgotty/tests/reconnect-modes-browser.test.js +144 -0
- package/apps/jsgotty/tests/reconnect-modes.md +44 -0
- package/apps/jsgotty/tests/reconnect-modes.test.js +166 -0
- package/apps/jsgotty/tests/touch-drag-browser.test.js +106 -0
- package/apps/jsgotty/tests/wheel-browser.test.js +60 -0
- package/apps/jsmdcui/CHANGELOG.md +44 -0
- package/apps/jsmdcui/package.json +1 -1
- package/apps/jsmdcui/src/highlight/go-regexp.js +83 -0
- package/apps/jsmdcui/src/highlight/highlighter.js +49 -62
- package/apps/jsmdcui/src/highlight/parser.js +8 -5
- package/apps/jsmdcui/tests/go-regexp.test.js +98 -0
- package/apps/jsmdcui/tests/heading-ids.test.js +21 -16
- package/apps/jsmdcui/tests/highlight-regions.test.js +73 -0
- package/apps/jsmdcui/tests/id-collision.test.js +32 -9
- package/apps/jsmdcui/tests/markdown-behavior.mjs +9 -0
- package/apps/jsmdcui/tests/syntax-parity/NORMAL-HTML.md +46 -0
- package/apps/jsmdcui/tests/syntax-parity/README.md +85 -0
- package/apps/jsmdcui/tests/syntax-parity/REPORT.md +328 -0
- package/apps/jsmdcui/tests/syntax-parity/compare.mjs +75 -0
- package/apps/jsmdcui/tests/syntax-parity/go.mod +5 -0
- package/apps/jsmdcui/tests/syntax-parity/normal-html-report.json +619 -0
- package/apps/jsmdcui/tests/syntax-parity/normal-html.html +9 -0
- package/apps/jsmdcui/tests/syntax-parity/oracle.go +49 -0
- package/apps/jsmdcui/tests/syntax-parity/report.json +2174 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/PowerShell.txt +39 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/ada.txt +25 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/apacheconf.txt +49 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/arduino.txt +38 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/asciidoc.txt +33 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/asm.txt +77 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/ats.txt +48 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/awk.txt +28 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/b.txt +27 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/bat.txt +39 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/c.txt +34 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/caddyfile.txt +14 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/cake.txt +7 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/clojure.txt +18 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/cmake.txt +20 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/coffeescript.txt +32 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/colortest.txt +19 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/conky.txt +12 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/cpp.txt +46 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/crontab.txt +16 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/crystal.txt +28 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/csharp.txt +28 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/css.txt +19 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/csx.txt +7 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/cuda.txt +37 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/cython.txt +22 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/d.txt +52 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/dart.txt +27 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/default.txt +8 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/dockerfile.txt +10 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/dot.txt +15 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/elixir.txt +23 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/elm.txt +20 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/erb.txt +32 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/erlang.txt +23 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/fish.txt +20 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/forth.txt +17 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/fortran.txt +40 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/freebsd-kernel.txt +10 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/fsharp.txt +27 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/gdscript.txt +26 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/gemini.txt +11 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/gentoo-ebuild.txt +28 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/gentoo-etc-portage.txt +14 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/git-commit.txt +19 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/git-config.txt +11 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/git-rebase-todo.txt +10 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/gleam.txt +44 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/glsl.txt +18 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/gnuplot.txt +11 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/go.txt +33 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/godoc.txt +9 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/golo.txt +50 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/gomod.txt +16 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/graphql.txt +20 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/groff.txt +18 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/groovy.txt +42 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/haml.txt +16 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/hare.txt +31 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/haskell.txt +26 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/hc.txt +28 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/html.txt +26 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/html4.txt +20 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/html5.txt +20 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/ini.txt +16 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/inputrc.txt +14 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/java.txt +18 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/javascript.txt +41 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/jinja2.txt +13 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/json.txt +21 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/jsonnet.txt +28 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/julia.txt +24 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/justfile.txt +26 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/keymap.txt +15 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/kickstart.txt +16 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/kotlin.txt +30 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/kvlang.txt +37 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/ledger.txt +13 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/lfe.txt +17 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/lilypond.txt +15 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/lisp.txt +17 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/log.txt +45 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/lua.txt +48 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/mail.txt +17 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/makefile.txt +25 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/man.txt +12 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/markdown.txt +21 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/mc.txt +11 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/meson.txt +29 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/micro.txt +25 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/mpdconf.txt +13 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/msbuild.txt +7 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/nanorc.txt +16 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/nftables.txt +22 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/nginx.txt +17 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/nim.txt +23 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/nix.txt +15 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/nu.txt +92 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/objc.txt +36 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/ocaml.txt +25 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/octave.txt +35 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/odin.txt +35 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/pascal.txt +22 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/patch.txt +13 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/peg.txt +16 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/perl.txt +27 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/php.txt +44 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/pkg-config.txt +12 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/po.txt +12 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/pony.txt +29 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/pov.txt +17 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/privoxy-action.txt +14 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/privoxy-config.txt +10 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/privoxy-filter.txt +12 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/proto.txt +22 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/prql.txt +42 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/puppet.txt +22 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/python2.txt +24 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/python3.txt +28 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/r.txt +16 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/raku.txt +19 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/reST.txt +18 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/renpy.txt +11 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/rpmspec.txt +31 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/ruby.txt +34 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/rust.txt +27 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/sage.txt +24 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/scad.txt +23 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/scala.txt +16 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/sed.txt +12 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/sh.txt +20 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/sls.txt +15 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/smalltalk.txt +28 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/solidity.txt +26 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/sql.txt +35 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/stata.txt +32 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/svelte.txt +10 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/swift.txt +53 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/systemd.txt +15 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/tcl.txt +17 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/terraform.txt +28 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/tex.txt +15 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/toml.txt +31 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/twig.txt +29 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/typescript.txt +32 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/v.txt +47 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/vala.txt +22 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/verilog.txt +37 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/vhdl.txt +37 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/vi.txt +17 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/vue.txt +29 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/xml.txt +14 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/xresources.txt +14 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/yaml.txt +19 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/yum.txt +12 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/zig.txt +24 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/zscript.txt +31 -0
- package/apps/jsmdcui/tests/syntax-parity/samples/zsh.txt +21 -0
- package/package.json +1 -1
package/apps/jsgotty/gotty.js
CHANGED
|
@@ -12,7 +12,10 @@ const crypto = require("crypto");
|
|
|
12
12
|
const zlib = require("zlib");
|
|
13
13
|
const { constants: fsConstants } = require("fs");
|
|
14
14
|
const WebSocket = require("ws");
|
|
15
|
+
const { TerminalModeTracker } = require("./terminal-modes.js");
|
|
15
16
|
const { WebSocketServer } = WebSocket;
|
|
17
|
+
const { ClipboardHost, handleOSC52 } = require("./clipboard.js");
|
|
18
|
+
const clipboardHost = new ClipboardHost();
|
|
16
19
|
|
|
17
20
|
const MSG_INPUT = "1";
|
|
18
21
|
const MSG_PING = "2";
|
|
@@ -34,6 +37,7 @@ const MSG_ZMODEM_MODE = "z";
|
|
|
34
37
|
const MSG_ZMODEM_OUTPUT = "y";
|
|
35
38
|
const MSG_ZMODEM_ACK = "Y";
|
|
36
39
|
const MSG_KITTY_DEBUG = "K";
|
|
40
|
+
const MSG_RESTORE_MODES = "m";
|
|
37
41
|
const KITTY_TRACE = /^(1|true|yes|on)$/i.test(String(process.env.JSGOTTY_KITTY_DEBUG || ""));
|
|
38
42
|
const WINDOWS_BRIDGE_TRACE = process.env.WINDOWS_BRIDGE_TRACE === "1";
|
|
39
43
|
const WINDOWS_BRIDGE_PREFIX = Buffer.from("@@GOTTYCTL:", "ascii");
|
|
@@ -1680,6 +1684,7 @@ class PtySession {
|
|
|
1680
1684
|
this.supportsWindowsBridge = process.platform === "win32";
|
|
1681
1685
|
this.cursorTracker = new CursorStateTracker();
|
|
1682
1686
|
this.cursorTracker.setDimensions(this.columns || 80);
|
|
1687
|
+
this.modeTracker = new TerminalModeTracker();
|
|
1683
1688
|
this.kittyParser = new KittyGraphicsParser();
|
|
1684
1689
|
this.windowsBridgeParser = this.supportsWindowsBridge ? new WindowsBridgeParser("incoming") : null;
|
|
1685
1690
|
this.outgoingWindowsBridgeParser = this.supportsWindowsBridge ? new WindowsBridgeParser("outgoing") : null;
|
|
@@ -1759,6 +1764,7 @@ class PtySession {
|
|
|
1759
1764
|
if (!this.supportsWindowsBridge) {
|
|
1760
1765
|
const cursorBefore = this.cursorTracker.snapshot();
|
|
1761
1766
|
this.cursorTracker.consume(filteredChunk);
|
|
1767
|
+
this.modeTracker.consume(filteredChunk);
|
|
1762
1768
|
const cursorAfter = this.cursorTracker.snapshot();
|
|
1763
1769
|
const controls = cursorControls(filteredChunk);
|
|
1764
1770
|
if (controls.length > 0) {
|
|
@@ -1776,6 +1782,7 @@ class PtySession {
|
|
|
1776
1782
|
if (bridged.plain.length > 0) {
|
|
1777
1783
|
const cursorBefore = this.cursorTracker.snapshot();
|
|
1778
1784
|
this.cursorTracker.consume(bridged.plain);
|
|
1785
|
+
this.modeTracker.consume(bridged.plain);
|
|
1779
1786
|
const cursorAfter = this.cursorTracker.snapshot();
|
|
1780
1787
|
const controls = cursorControls(bridged.plain);
|
|
1781
1788
|
if (controls.length > 0) {
|
|
@@ -1855,6 +1862,9 @@ class PtySession {
|
|
|
1855
1862
|
this.writerWs = ws;
|
|
1856
1863
|
}
|
|
1857
1864
|
this.sendSessionMetadata(ws, remoteAddr);
|
|
1865
|
+
// Queued ahead of live output; the client applies only modes that differ,
|
|
1866
|
+
// which also clears modes a program turned off while the socket was down.
|
|
1867
|
+
this.send(MSG_RESTORE_MODES, JSON.stringify(this.modeTracker.snapshot()), ws);
|
|
1858
1868
|
this.startWebSocketHandlers(ws);
|
|
1859
1869
|
this.notifyRoles();
|
|
1860
1870
|
return true;
|
|
@@ -2442,6 +2452,9 @@ class PtySession {
|
|
|
2442
2452
|
}
|
|
2443
2453
|
|
|
2444
2454
|
switch (type) {
|
|
2455
|
+
case "C":
|
|
2456
|
+
handleOSC52(this, ws, payload, clipboardHost);
|
|
2457
|
+
break;
|
|
2445
2458
|
case MSG_INPUT:
|
|
2446
2459
|
if (!this.isWriter(ws) || payload.length === 0) {
|
|
2447
2460
|
return;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jsgotty",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "jsgotty",
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.4.0",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"node-addon-api": "^7.1.1",
|
|
12
12
|
"ws": "^8.18.3"
|
|
@@ -10,4 +10,17 @@ html, body, #terminal {
|
|
|
10
10
|
transition: unset;
|
|
11
11
|
transition-duration: 0.1s;
|
|
12
12
|
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
13
|
-
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* Keep touch taps available to xterm even with a widened WebView viewport.
|
|
16
|
+
Include the viewport (a scroll container); preserve panning and pinch zoom. */
|
|
17
|
+
#terminal, #terminal .xterm, #terminal .xterm-viewport, #terminal .xterm-screen {
|
|
18
|
+
touch-action: manipulation;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* Chromium skips focused-editable auto-zoom when that element disallows
|
|
22
|
+
pinch zoom. Restrict only the hidden input, not the terminal canvas:
|
|
23
|
+
native paste/IME remain available and the visible terminal can still pinch. */
|
|
24
|
+
#terminal .xterm-helper-textarea {
|
|
25
|
+
touch-action: none;
|
|
26
|
+
}
|
|
@@ -12168,7 +12168,8 @@
|
|
|
12168
12168
|
(t.msgSetWindowTitle = "3"),
|
|
12169
12169
|
(t.msgSetPreferences = "4"),
|
|
12170
12170
|
(t.msgSetReconnect = "5"),
|
|
12171
|
-
(t.msgSetBufferSize = "6")
|
|
12171
|
+
(t.msgSetBufferSize = "6"),
|
|
12172
|
+
(t.msgRestoreModes = "m"));
|
|
12172
12173
|
t.WebTTY = class {
|
|
12173
12174
|
term;
|
|
12174
12175
|
connectionFactory;
|
|
@@ -12193,6 +12194,9 @@
|
|
|
12193
12194
|
this.reconnectDeadline = 0;
|
|
12194
12195
|
this.reconnectAttempts = 0;
|
|
12195
12196
|
this.zmodemExpectedSeq = 0;
|
|
12197
|
+
this.term.onClipboard?.(data => {
|
|
12198
|
+
if (!this.disconnected) this.connection.send("C" + data);
|
|
12199
|
+
});
|
|
12196
12200
|
}
|
|
12197
12201
|
open() {
|
|
12198
12202
|
let e;
|
|
@@ -12330,6 +12334,9 @@
|
|
|
12330
12334
|
const e = JSON.parse(i);
|
|
12331
12335
|
this.term.setPreferences(e);
|
|
12332
12336
|
break;
|
|
12337
|
+
case t.msgRestoreModes:
|
|
12338
|
+
this.term.applySessionModes(JSON.parse(i));
|
|
12339
|
+
break;
|
|
12333
12340
|
case t.msgSetReconnect:
|
|
12334
12341
|
const r = JSON.parse(i);
|
|
12335
12342
|
"number" == typeof r
|
|
@@ -12540,12 +12547,30 @@
|
|
|
12540
12547
|
})),
|
|
12541
12548
|
(this.fitAddOn = new s.FitAddon()),
|
|
12542
12549
|
(this.zmodemAddon = new a.ZModemAddon({
|
|
12543
|
-
toTerminal: (e) => this.
|
|
12550
|
+
toTerminal: (e) => this.writeTerminal(e),
|
|
12544
12551
|
toServer: (e) => this.sendInput(e),
|
|
12545
12552
|
})),
|
|
12546
12553
|
(this.kittyKeyboard = new globalThis.GoTTYKittyKeyboard.KittyKeyboard(this.term, {
|
|
12547
12554
|
android: /Android/i.test(navigator.userAgent),
|
|
12548
12555
|
})),
|
|
12556
|
+
this.term.parser.registerOscHandler(52, data => {
|
|
12557
|
+
if (!this.disconnected && data.length <= 1048576) this.clipboardHandler?.(data);
|
|
12558
|
+
return true;
|
|
12559
|
+
}),
|
|
12560
|
+
this.term.parser.registerOscHandler(777, data => {
|
|
12561
|
+
const match = /^jsgotty-modes;([a-f0-9]{32})$/.exec(data);
|
|
12562
|
+
if (!match) {
|
|
12563
|
+
const restore = /^jsgotty-kitty-v1;(normal|alternate);(\d{1,2});(\d{1,2}(?:,\d{1,2})*)?$/.exec(data);
|
|
12564
|
+
if (!restore) return false;
|
|
12565
|
+
const flags = +restore[2], stack = restore[3] ? restore[3].split(',').map(Number) : [];
|
|
12566
|
+
if (flags > 31 || stack.length > 32 || stack.some(n => n > 31)) return true;
|
|
12567
|
+
this.kittyKeyboard.states[restore[1]] = {flags: flags & 11, stack: stack.map(n => n & 11)};
|
|
12568
|
+
return true;
|
|
12569
|
+
}
|
|
12570
|
+
this.term.input("\x1b]777;jsgotty-modes;" + match[1] + ";" +
|
|
12571
|
+
btoa(JSON.stringify({...this.sessionModes(), kittyRestore: 1})) + "\x07", false);
|
|
12572
|
+
return true;
|
|
12573
|
+
}),
|
|
12549
12574
|
this.term.attachCustomKeyEventHandler((event) =>
|
|
12550
12575
|
this.kittyKeyboard.handle(event) && this.handleAndroidAltKey(event),
|
|
12551
12576
|
),
|
|
@@ -12676,8 +12701,73 @@
|
|
|
12676
12701
|
getMessage() {
|
|
12677
12702
|
return this.message;
|
|
12678
12703
|
}
|
|
12704
|
+
enqueueTerminal(task) {
|
|
12705
|
+
this.terminalTasks ||= [];
|
|
12706
|
+
this.terminalTasks.push(task);
|
|
12707
|
+
if (this.terminalBusy) return;
|
|
12708
|
+
this.terminalBusy = true;
|
|
12709
|
+
const next = () => {
|
|
12710
|
+
const task = this.terminalTasks.shift();
|
|
12711
|
+
if (!task) { this.terminalBusy = false; return; }
|
|
12712
|
+
task(next);
|
|
12713
|
+
};
|
|
12714
|
+
next();
|
|
12715
|
+
}
|
|
12716
|
+
writeTerminal(data) {
|
|
12717
|
+
this.enqueueTerminal(done => this.term.write(data, done));
|
|
12718
|
+
}
|
|
12719
|
+
onClipboard(handler) {
|
|
12720
|
+
this.clipboardHandler = handler;
|
|
12721
|
+
}
|
|
12722
|
+
sessionModes() {
|
|
12723
|
+
const core = this.term._core;
|
|
12724
|
+
return {dec: {...core.coreService.decPrivateModes},
|
|
12725
|
+
mouse: core.coreMouseService.activeProtocol,
|
|
12726
|
+
encoding: core.coreMouseService.activeEncoding,
|
|
12727
|
+
cursorHidden: !!core.coreService.isCursorHidden,
|
|
12728
|
+
alternate: this.term.buffer.active.type === "alternate",
|
|
12729
|
+
kitty: JSON.parse(JSON.stringify(this.kittyKeyboard.states))};
|
|
12730
|
+
}
|
|
12731
|
+
applySessionModes(state) {
|
|
12732
|
+
this.enqueueTerminal(done => this.term.write("", () => this.restoreSessionModes(state, done)));
|
|
12733
|
+
}
|
|
12734
|
+
restoreSessionModes(state, done) {
|
|
12735
|
+
if (!state || !state.dec) { done(); return; }
|
|
12736
|
+
const core = this.term._core;
|
|
12737
|
+
const dec = core.coreService.decPrivateModes;
|
|
12738
|
+
const mouse = core.coreMouseService;
|
|
12739
|
+
// A socket-only reconnect keeps xterm's modes, so send only differences:
|
|
12740
|
+
// DECOM homes the cursor and 1049 overwrites the saved cursor.
|
|
12741
|
+
let sequence = "";
|
|
12742
|
+
const alternate = this.term.buffer.active.type === "alternate";
|
|
12743
|
+
if (!!state.alternate !== alternate) sequence += `\x1b[?1049${state.alternate ? "h" : "l"}`;
|
|
12744
|
+
const flags = {1:"applicationCursorKeys", 6:"origin", 7:"wraparound", 45:"reverseWraparound",
|
|
12745
|
+
66:"applicationKeypad", 1004:"sendFocus", 2004:"bracketedPasteMode"};
|
|
12746
|
+
for (const [mode, name] of Object.entries(flags))
|
|
12747
|
+
if (!!state.dec[name] !== !!dec[name]) sequence += `\x1b[?${mode}${state.dec[name] ? "h" : "l"}`;
|
|
12748
|
+
if (!!state.cursorHidden !== !!core.coreService.isCursorHidden)
|
|
12749
|
+
sequence += `\x1b[?25${state.cursorHidden ? "l" : "h"}`;
|
|
12750
|
+
if (state.mouse !== mouse.activeProtocol) {
|
|
12751
|
+
const modes = {X10:9, VT200:1000, DRAG:1002, ANY:1003};
|
|
12752
|
+
sequence += modes[state.mouse] ? `\x1b[?${modes[state.mouse]}h` : "\x1b[?1000l";
|
|
12753
|
+
}
|
|
12754
|
+
if (state.encoding !== mouse.activeEncoding) {
|
|
12755
|
+
const modes = {SGR:1006, SGR_PIXELS:1016};
|
|
12756
|
+
sequence += modes[state.encoding] ? `\x1b[?${modes[state.encoding]}h` : "\x1b[?1006l";
|
|
12757
|
+
}
|
|
12758
|
+
const complete = () => {
|
|
12759
|
+
// Assigned rather than replayed so the push stack never doubles; the server
|
|
12760
|
+
// keeps every flag, so mask to the ones kitty-keyboard.js implements.
|
|
12761
|
+
const supported = (s) => ({flags: s.flags & 11, stack: s.stack.map((f) => f & 11)});
|
|
12762
|
+
if (state.kitty?.normal && state.kitty?.alternate)
|
|
12763
|
+
this.kittyKeyboard.states = {normal: supported(state.kitty.normal), alternate: supported(state.kitty.alternate)};
|
|
12764
|
+
done();
|
|
12765
|
+
};
|
|
12766
|
+
if (sequence) this.term.write(sequence, complete);
|
|
12767
|
+
else complete();
|
|
12768
|
+
}
|
|
12679
12769
|
setDisconnected(e) {
|
|
12680
|
-
if (e) this.kittyKeyboard.
|
|
12770
|
+
if (e) this.kittyKeyboard.clearHeld(false);
|
|
12681
12771
|
this.disconnected = !!e;
|
|
12682
12772
|
}
|
|
12683
12773
|
setReconnectAction(e) {
|
|
@@ -12789,7 +12879,8 @@
|
|
|
12789
12879
|
this.term.blur();
|
|
12790
12880
|
}
|
|
12791
12881
|
reset() {
|
|
12792
|
-
|
|
12882
|
+
// Reconnecting the transport does not reset the running PTY's modes.
|
|
12883
|
+
this.kittyKeyboard.clearHeld(false);
|
|
12793
12884
|
(this.removeMessage(), this.term.clear());
|
|
12794
12885
|
}
|
|
12795
12886
|
close() {
|
|
@@ -15906,8 +15997,15 @@
|
|
|
15906
15997
|
!1 === e._customWheelEventHandler(t)
|
|
15907
15998
|
)
|
|
15908
15999
|
return !1;
|
|
15909
|
-
|
|
15910
|
-
|
|
16000
|
+
// Preserve both axes of diagonal wheel/touch gestures.
|
|
16001
|
+
// CoreMouseService already encodes wheel actions 2/3 as 66/67.
|
|
16002
|
+
if (t.deltaX) e.coreMouseService.triggerMouseEvent({
|
|
16003
|
+
col: i.col, row: i.row, x: i.x, y: i.y,
|
|
16004
|
+
button: 4, action: t.deltaX < 0 ? 2 : 3,
|
|
16005
|
+
ctrl: t.ctrlKey, alt: t.altKey, shift: t.shiftKey,
|
|
16006
|
+
});
|
|
16007
|
+
if (0 === e.viewport.getLinesScrolled(t, true))
|
|
16008
|
+
return !!t.deltaX;
|
|
15911
16009
|
((s = t.deltaY < 0 ? 0 : 1), (r = 4));
|
|
15912
16010
|
break;
|
|
15913
16011
|
default:
|
|
@@ -16881,8 +16979,9 @@
|
|
|
16881
16979
|
}
|
|
16882
16980
|
return { bufferElements: s, cursorElement: i };
|
|
16883
16981
|
}
|
|
16884
|
-
getLinesScrolled(e) {
|
|
16885
|
-
|
|
16982
|
+
getLinesScrolled(e, mouseReporting = false) {
|
|
16983
|
+
// Shift belongs to the remote application while mouse reporting is active.
|
|
16984
|
+
if (0 === e.deltaY || (e.shiftKey && !mouseReporting)) return 0;
|
|
16886
16985
|
let t = this._applyScrollModifier(e.deltaY, e);
|
|
16887
16986
|
return (
|
|
16888
16987
|
e.deltaMode === WheelEvent.DOM_DELTA_PIXEL
|
|
@@ -561,6 +561,26 @@
|
|
|
561
561
|
state.renderBound = state.renderDisposables.length > 0;
|
|
562
562
|
}
|
|
563
563
|
|
|
564
|
+
// Touch gestures report mouse input without DOM mousedown: xterm's DOM
|
|
565
|
+
// handler focuses its hidden textarea, which can zoom Android WebView.
|
|
566
|
+
function reportTouchMouse(type, point, button = 0) {
|
|
567
|
+
const core = terminal?.__gottyXterm?._core;
|
|
568
|
+
if (!core?.coreMouseService?.areMouseEventsActive) return;
|
|
569
|
+
const screen = core.screenElement;
|
|
570
|
+
if (!screen) return;
|
|
571
|
+
const rect = screen.getBoundingClientRect();
|
|
572
|
+
const coords = core._mouseService.getMouseReportCoords({
|
|
573
|
+
clientX: Math.max(rect.left, Math.min(rect.right - 1, point.clientX)),
|
|
574
|
+
clientY: Math.max(rect.top, Math.min(rect.bottom - 1, point.clientY)),
|
|
575
|
+
}, screen);
|
|
576
|
+
if (!coords) return;
|
|
577
|
+
core.coreMouseService.triggerMouseEvent({
|
|
578
|
+
...coords, button,
|
|
579
|
+
action: type === "mousedown" ? 1 : type === "mousemove" ? 32 : 0,
|
|
580
|
+
ctrl: false, alt: false, shift: false,
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
|
|
564
584
|
function dispatchSyntheticWheel(target, touch, deltaX, deltaY) {
|
|
565
585
|
if (!target) {
|
|
566
586
|
return;
|
|
@@ -597,22 +617,69 @@
|
|
|
597
617
|
return screen || viewport || xterm || terminal;
|
|
598
618
|
};
|
|
599
619
|
|
|
620
|
+
let lastTap = null;
|
|
621
|
+
let drag = null;
|
|
622
|
+
const mouse = (type, point) => reportTouchMouse(type, point);
|
|
623
|
+
const releaseDrag = () => {
|
|
624
|
+
if (drag) {
|
|
625
|
+
const point = drag;
|
|
626
|
+
drag = null;
|
|
627
|
+
mouse("mouseup", point);
|
|
628
|
+
}
|
|
629
|
+
};
|
|
630
|
+
const cancelGesture = () => {
|
|
631
|
+
releaseDrag();
|
|
632
|
+
lastTap = null;
|
|
633
|
+
state.touchScroll = null;
|
|
634
|
+
};
|
|
635
|
+
state.cancelTouchGesture = cancelGesture;
|
|
636
|
+
bindTarget.addEventListener("contextmenu", (event) => {
|
|
637
|
+
if (drag) { event.preventDefault(); event.stopImmediatePropagation(); }
|
|
638
|
+
}, true);
|
|
639
|
+
window.addEventListener("blur", cancelGesture);
|
|
640
|
+
document.addEventListener("visibilitychange", () => {
|
|
641
|
+
if (document.hidden) cancelGesture();
|
|
642
|
+
});
|
|
643
|
+
|
|
600
644
|
bindTarget.addEventListener("touchstart", (event) => {
|
|
601
645
|
if (event.touches.length !== 1) {
|
|
602
|
-
|
|
646
|
+
cancelGesture();
|
|
603
647
|
return;
|
|
604
648
|
}
|
|
605
649
|
const touch = event.touches[0];
|
|
650
|
+
const reporting = terminal.__gottyXterm?._core?.coreMouseService?.areMouseEventsActive;
|
|
651
|
+
if (reporting && window.touchDoubleTapDrag !== false && lastTap &&
|
|
652
|
+
performance.now() - lastTap.time < 350 &&
|
|
653
|
+
Math.hypot(touch.clientX - lastTap.x, touch.clientY - lastTap.y) < 24) {
|
|
654
|
+
lastTap = null;
|
|
655
|
+
state.touchScroll = null;
|
|
656
|
+
drag = { identifier: touch.identifier, clientX: touch.clientX, clientY: touch.clientY };
|
|
657
|
+
// Cancel compatibility mouse events: this is the second press, not a third click.
|
|
658
|
+
event.preventDefault();
|
|
659
|
+
mouse("mousedown", drag);
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
lastTap = null;
|
|
606
663
|
state.touchScroll = {
|
|
664
|
+
startX: touch.clientX, startY: touch.clientY, startTime: performance.now(), moved: false,
|
|
607
665
|
identifier: touch.identifier,
|
|
608
666
|
lastX: touch.clientX,
|
|
609
667
|
lastY: touch.clientY,
|
|
610
668
|
residualX: 0,
|
|
611
669
|
residualY: 0
|
|
612
670
|
};
|
|
613
|
-
}, { passive:
|
|
671
|
+
}, { passive: false });
|
|
614
672
|
|
|
615
673
|
bindTarget.addEventListener("touchmove", (event) => {
|
|
674
|
+
if (drag) {
|
|
675
|
+
const touch = Array.from(event.touches).find(t => t.identifier === drag.identifier);
|
|
676
|
+
if (!touch || event.touches.length !== 1) { cancelGesture(); return; }
|
|
677
|
+
event.preventDefault();
|
|
678
|
+
drag.clientX = touch.clientX;
|
|
679
|
+
drag.clientY = touch.clientY;
|
|
680
|
+
mouse("mousemove", drag);
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
616
683
|
if (!state.touchScroll) {
|
|
617
684
|
return;
|
|
618
685
|
}
|
|
@@ -621,6 +688,8 @@
|
|
|
621
688
|
return;
|
|
622
689
|
}
|
|
623
690
|
|
|
691
|
+
if (Math.hypot(touch.clientX - state.touchScroll.startX,
|
|
692
|
+
touch.clientY - state.touchScroll.startY) > 8) state.touchScroll.moved = true;
|
|
624
693
|
const deltaX = state.touchScroll.lastX - touch.clientX;
|
|
625
694
|
const deltaY = state.touchScroll.lastY - touch.clientY;
|
|
626
695
|
state.touchScroll.lastX = touch.clientX;
|
|
@@ -653,11 +722,20 @@
|
|
|
653
722
|
state.touchScroll.residualY -= ticksY * threshold * stepY;
|
|
654
723
|
}, { passive: false });
|
|
655
724
|
|
|
656
|
-
|
|
725
|
+
bindTarget.addEventListener("touchend", (event) => {
|
|
726
|
+
if (drag) {
|
|
727
|
+
event.preventDefault();
|
|
728
|
+
releaseDrag();
|
|
729
|
+
} else {
|
|
730
|
+
const scroll = state.touchScroll;
|
|
731
|
+
if (scroll && !scroll.moved && event.touches.length === 0 &&
|
|
732
|
+
performance.now() - scroll.startTime < 350) {
|
|
733
|
+
lastTap = { x: scroll.lastX, y: scroll.lastY, time: performance.now() };
|
|
734
|
+
}
|
|
735
|
+
}
|
|
657
736
|
state.touchScroll = null;
|
|
658
|
-
};
|
|
659
|
-
bindTarget.addEventListener("
|
|
660
|
-
bindTarget.addEventListener("touchcancel", clearTouchScroll, { passive: true });
|
|
737
|
+
}, { passive: false });
|
|
738
|
+
bindTarget.addEventListener("touchcancel", cancelGesture, { passive: true });
|
|
661
739
|
state.touchBound = true;
|
|
662
740
|
}
|
|
663
741
|
|
|
@@ -676,9 +754,25 @@
|
|
|
676
754
|
removeButton.textContent = "Remove image";
|
|
677
755
|
menu.appendChild(removeButton);
|
|
678
756
|
|
|
757
|
+
const separator = document.createElement("hr");
|
|
758
|
+
const rightButton = document.createElement("button");
|
|
759
|
+
rightButton.type = "button";
|
|
760
|
+
rightButton.className = "kitty-context-menu__item";
|
|
761
|
+
rightButton.textContent = "Right click";
|
|
762
|
+
menu.append(separator, rightButton);
|
|
763
|
+
rightButton.addEventListener("click", (event) => {
|
|
764
|
+
event.preventDefault();
|
|
765
|
+
event.stopPropagation();
|
|
766
|
+
const point = state.contextMenu?.point;
|
|
767
|
+
hideContextMenu();
|
|
768
|
+
if (!point || !terminal.__gottyXterm?._core?.coreMouseService?.areMouseEventsActive) return;
|
|
769
|
+
reportTouchMouse("mousedown", { clientX: point.x, clientY: point.y }, 2);
|
|
770
|
+
reportTouchMouse("mouseup", { clientX: point.x, clientY: point.y }, 2);
|
|
771
|
+
});
|
|
772
|
+
|
|
679
773
|
state.contextMenu = {
|
|
680
774
|
root: menu,
|
|
681
|
-
removeButton,
|
|
775
|
+
removeButton, rightButton, separator,
|
|
682
776
|
targetKey: null
|
|
683
777
|
};
|
|
684
778
|
|
|
@@ -722,6 +816,9 @@
|
|
|
722
816
|
function showContextMenu(x, y, key) {
|
|
723
817
|
const menu = ensureContextMenu();
|
|
724
818
|
menu.targetKey = key;
|
|
819
|
+
menu.point = { x, y };
|
|
820
|
+
const reporting = !!terminal.__gottyXterm?._core?.coreMouseService?.areMouseEventsActive;
|
|
821
|
+
menu.rightButton.hidden = menu.separator.hidden = !reporting;
|
|
725
822
|
menu.root.hidden = false;
|
|
726
823
|
|
|
727
824
|
const margin = 10;
|
|
@@ -1004,6 +1101,15 @@
|
|
|
1004
1101
|
return false;
|
|
1005
1102
|
}
|
|
1006
1103
|
|
|
1104
|
+
const watchedSockets = new WeakSet();
|
|
1105
|
+
function watchTouchSocket(socket) {
|
|
1106
|
+
if (watchedSockets.has(socket)) return;
|
|
1107
|
+
watchedSockets.add(socket);
|
|
1108
|
+
socket.addEventListener("close", () => {
|
|
1109
|
+
if (state.socket === socket) state.cancelTouchGesture?.();
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1007
1113
|
const nativeSend = WebSocket.prototype.send;
|
|
1008
1114
|
const nativeOnOpen = WebSocket.prototype.addEventListener;
|
|
1009
1115
|
WebSocket.prototype.addEventListener = function (type, listener, options) {
|
|
@@ -1012,6 +1118,7 @@
|
|
|
1012
1118
|
}
|
|
1013
1119
|
const wrapped = function (event) {
|
|
1014
1120
|
state.socket = this;
|
|
1121
|
+
watchTouchSocket(this);
|
|
1015
1122
|
inspectTerminalOutput(event.data);
|
|
1016
1123
|
if (typeof event.data === "string" && event.data[0] === MSG_KITTY) {
|
|
1017
1124
|
if (handleKittyMessage(event.data.slice(1))) {
|
|
@@ -1058,6 +1165,7 @@
|
|
|
1058
1165
|
}
|
|
1059
1166
|
const wrapped = function (event) {
|
|
1060
1167
|
state.socket = this;
|
|
1168
|
+
watchTouchSocket(this);
|
|
1061
1169
|
inspectTerminalOutput(event.data);
|
|
1062
1170
|
if (typeof event.data === "string" && event.data[0] === MSG_KITTY) {
|
|
1063
1171
|
if (handleKittyMessage(event.data.slice(1))) {
|