@fleetagent/pi-tui 0.1.8 → 0.2.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/README.md +47 -7
- package/dist/autocomplete.d.ts +17 -23
- package/dist/autocomplete.d.ts.map +1 -1
- package/dist/autocomplete.js +129 -195
- package/dist/autocomplete.js.map +1 -1
- package/dist/components/alt-screen-flash.d.ts +13 -0
- package/dist/components/alt-screen-flash.d.ts.map +1 -0
- package/dist/components/alt-screen-flash.js +37 -0
- package/dist/components/alt-screen-flash.js.map +1 -0
- package/dist/components/editor.d.ts +47 -4
- package/dist/components/editor.d.ts.map +1 -1
- package/dist/components/editor.js +615 -585
- package/dist/components/editor.js.map +1 -1
- package/dist/components/h-stack.d.ts +7 -0
- package/dist/components/h-stack.d.ts.map +1 -0
- package/dist/components/h-stack.js +43 -0
- package/dist/components/h-stack.js.map +1 -0
- package/dist/components/image.d.ts +4 -0
- package/dist/components/image.d.ts.map +1 -1
- package/dist/components/image.js +38 -51
- package/dist/components/image.js.map +1 -1
- package/dist/components/input.d.ts +9 -0
- package/dist/components/input.d.ts.map +1 -1
- package/dist/components/input.js +121 -147
- package/dist/components/input.js.map +1 -1
- package/dist/components/markdown.d.ts +34 -0
- package/dist/components/markdown.d.ts.map +1 -1
- package/dist/components/markdown.js +491 -429
- package/dist/components/markdown.js.map +1 -1
- package/dist/components/scroll-view.d.ts +53 -0
- package/dist/components/scroll-view.d.ts.map +1 -0
- package/dist/components/scroll-view.js +173 -0
- package/dist/components/scroll-view.js.map +1 -0
- package/dist/components/select-list.d.ts.map +1 -1
- package/dist/components/select-list.js.map +1 -1
- package/dist/components/settings-list.d.ts +2 -0
- package/dist/components/settings-list.d.ts.map +1 -1
- package/dist/components/settings-list.js +31 -29
- package/dist/components/settings-list.js.map +1 -1
- package/dist/components/stack.d.ts +32 -0
- package/dist/components/stack.d.ts.map +1 -0
- package/dist/components/stack.js +122 -0
- package/dist/components/stack.js.map +1 -0
- package/dist/components/v-stack.d.ts +8 -0
- package/dist/components/v-stack.d.ts.map +1 -0
- package/dist/components/v-stack.js +27 -0
- package/dist/components/v-stack.js.map +1 -0
- package/dist/fuzzy.d.ts.map +1 -1
- package/dist/fuzzy.js +37 -46
- package/dist/fuzzy.js.map +1 -1
- package/dist/index.d.ts +10 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -2
- package/dist/index.js.map +1 -1
- package/dist/keybindings.d.ts +54 -4
- package/dist/keybindings.d.ts.map +1 -1
- package/dist/keybindings.js +39 -4
- package/dist/keybindings.js.map +1 -1
- package/dist/keys.d.ts.map +1 -1
- package/dist/keys.js +359 -479
- package/dist/keys.js.map +1 -1
- package/dist/kill-ring.d.ts +6 -4
- package/dist/kill-ring.d.ts.map +1 -1
- package/dist/kill-ring.js +0 -7
- package/dist/kill-ring.js.map +1 -1
- package/dist/latex.d.ts +10 -0
- package/dist/latex.d.ts.map +1 -0
- package/dist/latex.js +1406 -0
- package/dist/latex.js.map +1 -0
- package/dist/layout-node.d.ts +43 -0
- package/dist/layout-node.d.ts.map +1 -0
- package/dist/layout-node.js +6 -0
- package/dist/layout-node.js.map +1 -0
- package/dist/layout.d.ts +40 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +386 -0
- package/dist/layout.js.map +1 -0
- package/dist/stdin-buffer.d.ts +8 -0
- package/dist/stdin-buffer.d.ts.map +1 -1
- package/dist/stdin-buffer.js +116 -159
- package/dist/stdin-buffer.js.map +1 -1
- package/dist/terminal-image.d.ts +41 -19
- package/dist/terminal-image.d.ts.map +1 -1
- package/dist/terminal-image.js +171 -32
- package/dist/terminal-image.js.map +1 -1
- package/dist/terminal.d.ts +3 -0
- package/dist/terminal.d.ts.map +1 -1
- package/dist/terminal.js +27 -23
- package/dist/terminal.js.map +1 -1
- package/dist/tui-alt-screen.d.ts +114 -0
- package/dist/tui-alt-screen.d.ts.map +1 -0
- package/dist/tui-alt-screen.js +950 -0
- package/dist/tui-alt-screen.js.map +1 -0
- package/dist/tui-main-screen.d.ts +52 -0
- package/dist/tui-main-screen.d.ts.map +1 -0
- package/dist/tui-main-screen.js +511 -0
- package/dist/tui-main-screen.js.map +1 -0
- package/dist/tui.d.ts +112 -44
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +489 -699
- package/dist/tui.js.map +1 -1
- package/dist/utils.d.ts +29 -17
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +605 -528
- package/dist/utils.js.map +1 -1
- package/dist/word-navigation.d.ts.map +1 -1
- package/dist/word-navigation.js +37 -39
- package/dist/word-navigation.js.map +1 -1
- package/package.json +1 -1
package/dist/terminal.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terminal.js","sourceRoot":"","sources":["../src/terminal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,8BAA8B,EAAE,MAAM,uBAAuB,CAAC;AAEvE,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;AAElD,MAAM,8BAA8B,GAAG,IAAI,CAAC;AAC5C,MAAM,iCAAiC,GAAG,gBAAgB,CAAC;AAC3D,MAAM,gCAAgC,GAAG,iBAAiB,CAAC;AAC3D,MAAM,mCAAmC,GAAG,YAAY,CAAC;AACzD,MAAM,qCAAqC,GAAG,CAAC,CAAC;AAChD,MAAM,2CAA2C,GAAG,GAAG,CAAC;AACxD,MAAM,8CAA8C,GAAG,GAAG,CAAC;AAC3D,MAAM,6BAA6B,GAAG,SAAS,qCAAqC,gBAAgB,CAAC;AAMrG,MAAM,UAAU,wCAAwC,CACvD,QAAgB,EACkC;IAClD,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IACtD,IAAI,UAAU,EAAE,CAAC;QAChB,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC,EAAE,CAAC;IAC5E,CAAC;IACD,IAAI,mBAAmB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxC,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAC;IACtC,CAAC;IACD,OAAO,SAAS,CAAC;AAAA,CACjB;AAED,SAAS,2CAA2C,CAAC,QAAgB,EAAE,qBAA8B,EAAW;IAC/G,OAAO,CAAC,qBAAqB,IAAI,QAAQ,KAAK,MAAM,CAAC,IAAI,QAAQ,KAAK,OAAO,IAAI,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAAA,CACnH;AAED,MAAM,UAAU,sBAAsB,GAAY;IACjD,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,gBAAgB,CAAC;AAAA,CACtF;AAED,MAAM,UAAU,2BAA2B,CAAC,IAAY,EAAE,eAAwB,EAAE,cAAuB,EAAU;IACpH,IAAI,eAAe,IAAI,IAAI,KAAK,IAAI,IAAI,cAAc;QAAE,OAAO,mCAAmC,CAAC;IACnG,OAAO,IAAI,CAAC;AAAA,CACZ;AAiDD;;GAEG;AACH,MAAM,OAAO,eAAe;IACnB,MAAM,GAAG,KAAK,CAAC;IACf,OAAO,GAAG,KAAK,CAAC;IAChB,YAAY,CAA0B;IACtC,aAAa,CAAc;IAC3B,oBAAoB,GAAG,KAAK,CAAC;IAC7B,sBAAsB,GAAG,KAAK,CAAC;IAC/B,sBAAsB,GAAG,KAAK,CAAC;IAC/B,kCAAkC,GAAG,KAAK,CAAC;IAC3C,mCAAmC,GAAG,KAAK,CAAC;IAC5C,iCAAiC,GAAG,EAAE,CAAC;IACvC,6BAA6B,CAAiC;IAC9D,gCAAgC,CAAiC;IACjE,WAAW,CAAe;IAC1B,gBAAgB,CAA0B;IAC1C,gBAAgB,CAAkC;IAClD,YAAY,GAAG,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,EAAE,CAAC;QAC/C,IAAI,CAAC,GAAG;YAAE,OAAO,EAAE,CAAC;QACpB,IAAI,CAAC;YACJ,IAAI,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;gBACpC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC,WAAW,EAAE,IAAI,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;gBAChQ,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;YACvD,CAAC;QACF,CAAC;QAAC,MAAM,CAAC;YACR,oDAAoD;QACrD,CAAC;QACD,OAAO,GAAG,CAAC;IAAA,CACX,CAAC,EAAE,CAAC;IAEL,IAAI,mBAAmB,GAAY;QAClC,OAAO,IAAI,CAAC,oBAAoB,CAAC;IAAA,CACjC;IAED,KAAK,CAAC,OAA+B,EAAE,QAAoB,EAAQ;QAClE,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC;YAC5B,IAAI,IAAI,CAAC,aAAa,KAAK,QAAQ,EAAE,CAAC;gBACrC,IAAI,IAAI,CAAC,aAAa;oBAAE,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;gBACpF,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC;gBAC9B,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACvC,CAAC;YACD,OAAO;QACR,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC;QAC5B,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC;QAC9B,0CAA0C;QAC1C,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC;QAC3C,IAAI,OAAO,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;YAC9B,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAClC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QAEvB,qFAAqF;QACrF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAEpC,oCAAoC;QACpC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QAEhD,uEAAuE;QACvE,0DAA0D;QAC1D,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YAClC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QACvC,CAAC;QAED,wEAAwE;QACxE,yEAAyE;QACzE,yEAAyE;QACzE,wCAAwC;QACxC,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAE5B,2CAA2C;QAC3C,mFAAmF;QACnF,0DAA0D;QAC1D,IAAI,CAAC,2BAA2B,EAAE,CAAC;IAAA,CACnC;IAED;;;;;;;OAOG;IACK,gBAAgB,GAAS;QAChC,IAAI,CAAC,WAAW,GAAG,IAAI,WAAW,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;QAEpD,oDAAoD;QACpD,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;YACzC,IAAI,IAAI,CAAC,kCAAkC,EAAE,CAAC;gBAC7C,MAAM,mBAAmB,GAAG,IAAI,CAAC,uCAAuC,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;gBACzF,IAAI,mBAAmB,KAAK,SAAS,EAAE,CAAC;oBACvC,OAAO,CAAC,qDAAqD;gBAC9D,CAAC;gBACD,IAAI,IAAI,CAAC,yCAAyC,CAAC,mBAAmB,CAAC,EAAE,CAAC;oBACzE,OAAO;gBACR,CAAC;YACF,CAAC;YAED,IAAI,IAAI,CAAC,mCAAmC,EAAE,CAAC;gBAC9C,MAAM,mBAAmB,GAAG,IAAI,CAAC,uCAAuC,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;gBAC1F,IAAI,mBAAmB,KAAK,SAAS,EAAE,CAAC;oBACvC,IAAI,CAAC,8CAA8C,EAAE,CAAC;oBACtD,OAAO,CAAC,0DAA0D;gBACnE,CAAC;gBACD,IAAI,IAAI,CAAC,yCAAyC,CAAC,mBAAmB,CAAC,EAAE,CAAC;oBACzE,OAAO;gBACR,CAAC;YACF,CAAC;YAED,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;QAAA,CACpC,CAAC,CAAC;QAEH,kFAAkF;QAClF,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC;YACzC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;gBACvB,IAAI,CAAC,YAAY,CAAC,YAAY,OAAO,WAAW,CAAC,CAAC;YACnD,CAAC;QAAA,CACD,CAAC,CAAC;QAEH,mDAAmD;QACnD,IAAI,CAAC,gBAAgB,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC;YACzC,IAAI,CAAC,WAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAAA,CAChC,CAAC;IAAA,CACF;IAED;;;;;;;;;;;;;OAaG;IACK,2BAA2B,GAAS;QAC3C,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACxB,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,gBAAiB,CAAC,CAAC;QACjD,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC;QACnC,IAAI,CAAC,kCAAkC,GAAG,IAAI,CAAC;QAC/C,IAAI,CAAC,mCAAmC,GAAG,KAAK,CAAC;QACjD,IAAI,CAAC,sCAAsC,EAAE,CAAC;QAC9C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACpD,IAAI,CAAC,6BAA6B,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC;YACrD,IAAI,CAAC,6BAA6B,GAAG,SAAS,CAAC;YAC/C,IAAI,CAAC,kCAAkC,GAAG,KAAK,CAAC;YAChD,IAAI,CAAC,mCAAmC,GAAG,IAAI,CAAC;YAChD,IAAI,IAAI,CAAC,iCAAiC,KAAK,MAAM,EAAE,CAAC;gBACvD,IAAI,CAAC,6CAA6C,EAAE,CAAC;YACtD,CAAC;iBAAM,CAAC;gBACP,IAAI,CAAC,8CAA8C,EAAE,CAAC;YACvD,CAAC;YACD,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAAA,CAC7B,EAAE,2CAA2C,CAAC,CAAC;IAAA,CAChD;IAEO,yCAAyC,CAChD,mBAAoE,EAC1D;QACV,IAAI,CAAC,mBAAmB;YAAE,OAAO,KAAK,CAAC;QACvC,IAAI,mBAAmB,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YAChD,IAAI,mBAAmB,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,CAAC;gBACnE,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC;gBACjC,sBAAsB,CAAC,IAAI,CAAC,CAAC;gBAC7B,IAAI,CAAC,kCAAkC,GAAG,KAAK,CAAC;gBAChD,IAAI,CAAC,mCAAmC,GAAG,IAAI,CAAC;gBAChD,IAAI,CAAC,sCAAsC,EAAE,CAAC;gBAC9C,IAAI,CAAC,kCAAkC,EAAE,CAAC;YAC3C,CAAC;YACD,OAAO,IAAI,CAAC;QACb,CAAC;QAED,IAAI,CAAC,kCAAkC,GAAG,KAAK,CAAC;QAChD,IAAI,CAAC,mCAAmC,GAAG,IAAI,CAAC;QAChD,IAAI,CAAC,sCAAsC,EAAE,CAAC;QAC9C,IAAI,CAAC,kCAAkC,EAAE,CAAC;QAC1C,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IAAA,CACZ;IAEO,uCAAuC,CAC9C,QAAgB,EAChB,qBAA8B,EACgC;QAC9D,IAAI,IAAI,CAAC,iCAAiC,EAAE,CAAC;YAC5C,MAAM,gBAAgB,GAAG,IAAI,CAAC,iCAAiC,GAAG,QAAQ,CAAC;YAC3E,MAAM,mBAAmB,GAAG,wCAAwC,CAAC,gBAAgB,CAAC,CAAC;YACvF,IAAI,mBAAmB,EAAE,CAAC;gBACzB,IAAI,CAAC,sCAAsC,EAAE,CAAC;gBAC9C,OAAO,mBAAmB,CAAC;YAC5B,CAAC;YACD,IAAI,2CAA2C,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,EAAE,CAAC;gBAC1F,IAAI,CAAC,oCAAoC,CAAC,gBAAgB,CAAC,CAAC;gBAC5D,OAAO,SAAS,CAAC;YAClB,CAAC;YACD,IAAI,CAAC,6CAA6C,EAAE,CAAC;QACtD,CAAC;QAED,MAAM,mBAAmB,GAAG,wCAAwC,CAAC,QAAQ,CAAC,CAAC;QAC/E,IAAI,mBAAmB;YAAE,OAAO,mBAAmB,CAAC;QACpD,IAAI,2CAA2C,CAAC,QAAQ,EAAE,qBAAqB,CAAC,EAAE,CAAC;YAClF,IAAI,CAAC,oCAAoC,CAAC,QAAQ,CAAC,CAAC;YACpD,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,OAAO,SAAS,CAAC;IAAA,CACjB;IAEO,oCAAoC,CAAC,QAAgB,EAAQ;QACpE,IAAI,CAAC,gDAAgD,EAAE,CAAC;QACxD,IAAI,CAAC,iCAAiC,GAAG,QAAQ,CAAC;IAAA,CAClD;IAEO,sCAAsC,GAAS;QACtD,IAAI,CAAC,gDAAgD,EAAE,CAAC;QACxD,IAAI,CAAC,iCAAiC,GAAG,EAAE,CAAC;IAAA,CAC5C;IAEO,6CAA6C,GAAS;QAC7D,IAAI,CAAC,IAAI,CAAC,iCAAiC;YAAE,OAAO;QACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,iCAAiC,CAAC;QACxD,IAAI,CAAC,sCAAsC,EAAE,CAAC;QAC9C,IAAI,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAAA,CACpC;IAEO,8CAA8C,GAAS;QAC9D,IAAI,CAAC,IAAI,CAAC,iCAAiC,IAAI,IAAI,CAAC,gCAAgC;YAAE,OAAO;QAC7F,IAAI,CAAC,gCAAgC,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC;YACxD,IAAI,CAAC,gCAAgC,GAAG,SAAS,CAAC;YAClD,IAAI,CAAC,6CAA6C,EAAE,CAAC;QAAA,CACrD,EAAE,8CAA8C,CAAC,CAAC;IAAA,CACnD;IAEO,gDAAgD,GAAS;QAChE,IAAI,CAAC,IAAI,CAAC,gCAAgC;YAAE,OAAO;QACnD,YAAY,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;QACpD,IAAI,CAAC,gCAAgC,GAAG,SAAS,CAAC;IAAA,CAClD;IAEO,oBAAoB,CAAC,QAAgB,EAAQ;QACpD,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO;QAC/B,MAAM,eAAe,GAAG,QAAQ,KAAK,IAAI,IAAI,sBAAsB,EAAE,CAAC;QACtE,MAAM,KAAK,GAAG,2BAA2B,CACxC,QAAQ,EACR,eAAe,EACf,eAAe,IAAI,uBAAuB,CAAC,OAAO,CAAC,CACnD,CAAC;QACF,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAAA,CACzB;IAEO,qBAAqB,GAAS;QACrC,IAAI,IAAI,CAAC,oBAAoB,IAAI,IAAI,CAAC,sBAAsB;YAAE,OAAO;QACrE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QACnC,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC;IAAA,CACnC;IAEO,kCAAkC,GAAS;QAClD,IAAI,CAAC,IAAI,CAAC,6BAA6B;YAAE,OAAO;QAChD,YAAY,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;QACjD,IAAI,CAAC,6BAA6B,GAAG,SAAS,CAAC;IAAA,CAC/C;IAED;;;;;OAKG;IACK,oBAAoB,GAAS;QACpC,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;YAAE,OAAO;QACzC,IAAI,CAAC;YACJ,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;YAC1B,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,OAAO;gBAAE,OAAO;YAE/C,0EAA0E;YAC1E,0EAA0E;YAC1E,4DAA4D;YAC5D,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAC/D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,IAAI,EAAE,EAAE,yBAAyB,CAAC,CAAC;YACzG,MAAM,UAAU,GAAG;gBAClB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,UAAU,CAAC;gBACtC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;gBAChC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC;aACrD,CAAC;YACF,KAAK,MAAM,UAAU,IAAI,UAAU,EAAE,CAAC;gBACrC,IAAI,CAAC;oBACJ,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAmD,CAAC;oBACxF,MAAM,CAAC,0BAA0B,EAAE,EAAE,CAAC;oBACtC,OAAO;gBACR,CAAC;gBAAC,MAAM,CAAC;oBACR,4CAA4C;gBAC7C,CAAC;YACF,CAAC;QACF,CAAC;QAAC,MAAM,CAAC;YACR,+EAA6E;QAC9E,CAAC;IAAA,CACD;IAED,KAAK,CAAC,UAAU,CAAC,KAAK,GAAG,IAAI,EAAE,MAAM,GAAG,EAAE,EAAiB;QAC1D,MAAM,0BAA0B,GAC/B,IAAI,CAAC,sBAAsB,IAAI,IAAI,CAAC,oBAAoB,IAAI,IAAI,CAAC,kCAAkC,CAAC;QACrG,IAAI,CAAC,mCAAmC,GAAG,KAAK,CAAC;QACjD,IAAI,CAAC,sCAAsC,EAAE,CAAC;QAC9C,IAAI,CAAC,kCAAkC,EAAE,CAAC;QAC1C,IAAI,0BAA0B,EAAE,CAAC;YAChC,iEAAiE;YACjE,8CAA8C;YAC9C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAChC,IAAI,CAAC,sBAAsB,GAAG,KAAK,CAAC;YACpC,IAAI,CAAC,oBAAoB,GAAG,KAAK,CAAC;YAClC,sBAAsB,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;QACD,IAAI,CAAC,kCAAkC,GAAG,KAAK,CAAC;QAChD,IAAI,IAAI,CAAC,sBAAsB,EAAE,CAAC;YACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;YACnC,IAAI,CAAC,sBAAsB,GAAG,KAAK,CAAC;QACrC,CAAC;QAED,MAAM,eAAe,GAAG,IAAI,CAAC,YAAY,CAAC;QAC1C,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC;QAE9B,IAAI,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC;YACpB,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAAA,CAC1B,CAAC;QAEF,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QAEnC,IAAI,CAAC;YACJ,OAAO,IAAI,EAAE,CAAC;gBACb,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACvB,MAAM,QAAQ,GAAG,OAAO,GAAG,GAAG,CAAC;gBAC/B,IAAI,QAAQ,IAAI,CAAC;oBAAE,MAAM;gBACzB,IAAI,GAAG,GAAG,YAAY,IAAI,MAAM;oBAAE,MAAM;gBACxC,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;YACjF,CAAC;QACF,CAAC;gBAAS,CAAC;YACV,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAC7C,IAAI,CAAC,YAAY,GAAG,eAAe,CAAC;QACrC,CAAC;IAAA,CACD;IAED,IAAI,GAAS;QACZ,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,IAAI,CAAC,qBAAqB,EAAE,EAAE,CAAC;YAClC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACxD,CAAC;QAED,+BAA+B;QAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAEpC,MAAM,0BAA0B,GAC/B,IAAI,CAAC,sBAAsB,IAAI,IAAI,CAAC,oBAAoB,IAAI,IAAI,CAAC,kCAAkC,CAAC;QACrG,IAAI,CAAC,mCAAmC,GAAG,KAAK,CAAC;QACjD,IAAI,CAAC,sCAAsC,EAAE,CAAC;QAC9C,IAAI,CAAC,kCAAkC,EAAE,CAAC;QAE1C,sEAAsE;QACtE,IAAI,0BAA0B,EAAE,CAAC;YAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAChC,IAAI,CAAC,sBAAsB,GAAG,KAAK,CAAC;YACpC,IAAI,CAAC,oBAAoB,GAAG,KAAK,CAAC;YAClC,sBAAsB,CAAC,KAAK,CAAC,CAAC;QAC/B,CAAC;QACD,IAAI,CAAC,kCAAkC,GAAG,KAAK,CAAC;QAChD,IAAI,IAAI,CAAC,sBAAsB,EAAE,CAAC;YACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;YACnC,IAAI,CAAC,sBAAsB,GAAG,KAAK,CAAC;QACrC,CAAC;QAED,uBAAuB;QACvB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;YAC3B,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;QAC9B,CAAC;QAED,wBAAwB;QACxB,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC3B,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC;YAC5D,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC;QACnC,CAAC;QACD,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC;QAC9B,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACxB,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;YAC5D,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;QAChC,CAAC;QAED,sEAAsE;QACtE,yEAAyE;QACzE,sDAAsD;QACtD,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAEtB,yBAAyB;QACzB,IAAI,OAAO,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;YAC9B,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvC,CAAC;IAAA,CACD;IAED,KAAK,CAAC,IAAY,EAAQ;QACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACvB,IAAI,CAAC;gBACJ,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;YAClE,CAAC;YAAC,MAAM,CAAC;gBACR,wBAAwB;YACzB,CAAC;QACF,CAAC;IAAA,CACD;IAED,IAAI,OAAO,GAAW;QACrB,OAAO,OAAO,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IAAA,CACnE;IAED,IAAI,IAAI,GAAW;QAClB,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IAAA,CAC9D;IAED,MAAM,CAAC,KAAa,EAAQ;QAC3B,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACf,YAAY;YACZ,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,KAAK,GAAG,CAAC,CAAC;QACxC,CAAC;aAAM,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACtB,UAAU;YACV,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC;QACzC,CAAC;QACD,2BAA2B;IAD1B,CAED;IAED,UAAU,GAAS;QAClB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAAA,CAClC;IAED,UAAU,GAAS;QAClB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAAA,CAClC;IAED,SAAS,GAAS;QACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAAA,CAC/B;IAED,eAAe,GAAS;QACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAAA,CAC/B;IAED,WAAW,GAAS;QACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,sCAAsC;IAAvC,CACtC;IAED,QAAQ,CAAC,KAAa,EAAQ;QAC7B,8CAA8C;QAC9C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,8BAA8B,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAAA,CAC5E;IAED,WAAW,CAAC,MAAe,EAAQ;QAClC,IAAI,MAAM,EAAE,CAAC;YACZ,qCAAqC;YACrC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;YACxD,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBAC5B,IAAI,CAAC,gBAAgB,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;oBACzC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;gBAAA,CACxD,EAAE,8BAA8B,CAAC,CAAC;YACpC,CAAC;QACF,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,qBAAqB,EAAE,CAAC;YAC7B,6BAA6B;YAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACxD,CAAC;IAAA,CACD;IAEO,qBAAqB,GAAY;QACxC,IAAI,CAAC,IAAI,CAAC,gBAAgB;YAAE,OAAO,KAAK,CAAC;QACzC,aAAa,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QACrC,IAAI,CAAC,gBAAgB,GAAG,SAAS,CAAC;QAClC,OAAO,IAAI,CAAC;IAAA,CACZ;CACD","sourcesContent":["import * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { setKittyProtocolActive } from \"./keys.ts\";\nimport { isNativeModifierPressed } from \"./native-modifiers.ts\";\nimport { StdinBuffer } from \"./stdin-buffer.ts\";\nimport { sanitizeTerminalControlPayload } from \"./terminal-control.ts\";\n\nconst cjsRequire = createRequire(import.meta.url);\n\nconst TERMINAL_PROGRESS_KEEPALIVE_MS = 1000;\nconst TERMINAL_PROGRESS_ACTIVE_SEQUENCE = \"\\x1b]9;4;3\\x07\";\nconst TERMINAL_PROGRESS_CLEAR_SEQUENCE = \"\\x1b]9;4;0;\\x07\";\nconst APPLE_TERMINAL_SHIFT_ENTER_SEQUENCE = \"\\x1b[13;2u\";\nconst DESIRED_KITTY_KEYBOARD_PROTOCOL_FLAGS = 7;\nconst KITTY_KEYBOARD_PROTOCOL_FALLBACK_TIMEOUT_MS = 150;\nconst KEYBOARD_PROTOCOL_RESPONSE_FRAGMENT_TIMEOUT_MS = 150;\nconst KITTY_KEYBOARD_PROTOCOL_QUERY = `\\x1b[>${DESIRED_KITTY_KEYBOARD_PROTOCOL_FLAGS}u\\x1b[?u\\x1b[c`;\n\nexport type KeyboardProtocolNegotiationSequence =\n\t| { type: \"kitty-flags\"; flags: number }\n\t| { type: \"device-attributes\" };\n\nexport function parseKeyboardProtocolNegotiationSequence(\n\tsequence: string,\n): KeyboardProtocolNegotiationSequence | undefined {\n\tconst kittyFlags = sequence.match(/^\\x1b\\[\\?(\\d+)u$/);\n\tif (kittyFlags) {\n\t\treturn { type: \"kitty-flags\", flags: Number.parseInt(kittyFlags[1]!, 10) };\n\t}\n\tif (/^\\x1b\\[\\?[\\d;]*c$/.test(sequence)) {\n\t\treturn { type: \"device-attributes\" };\n\t}\n\treturn undefined;\n}\n\nfunction isKeyboardProtocolNegotiationSequencePrefix(sequence: string, allowBareEscapePrefix: boolean): boolean {\n\treturn (allowBareEscapePrefix && sequence === \"\\x1b\") || sequence === \"\\x1b[\" || /^\\x1b\\[\\?[\\d;]*$/.test(sequence);\n}\n\nexport function isAppleTerminalSession(): boolean {\n\treturn process.platform === \"darwin\" && process.env.TERM_PROGRAM === \"Apple_Terminal\";\n}\n\nexport function normalizeAppleTerminalInput(data: string, isAppleTerminal: boolean, isShiftPressed: boolean): string {\n\tif (isAppleTerminal && data === \"\\r\" && isShiftPressed) return APPLE_TERMINAL_SHIFT_ENTER_SEQUENCE;\n\treturn data;\n}\n\n/**\n * Minimal terminal interface for TUI\n */\nexport interface Terminal {\n\t// Start the terminal with input and resize handlers\n\tstart(onInput: (data: string) => void, onResize: () => void): void;\n\n\t// Stop the terminal and restore state\n\tstop(): void;\n\n\t/**\n\t * Drain stdin before exiting to prevent Kitty key release events from\n\t * leaking to the parent shell over slow SSH connections.\n\t * @param maxMs - Maximum time to drain (default: 1000ms)\n\t * @param idleMs - Exit early if no input arrives within this time (default: 50ms)\n\t */\n\tdrainInput(maxMs?: number, idleMs?: number): Promise<void>;\n\n\t// Write output to terminal\n\twrite(data: string): void;\n\n\t// Get terminal dimensions\n\tget columns(): number;\n\tget rows(): number;\n\n\t// Whether Kitty keyboard protocol is active\n\tget kittyProtocolActive(): boolean;\n\n\t// Cursor positioning (relative to current position)\n\tmoveBy(lines: number): void; // Move cursor up (negative) or down (positive) by N lines\n\n\t// Cursor visibility\n\thideCursor(): void; // Hide the cursor\n\tshowCursor(): void; // Show the cursor\n\n\t// Clear operations\n\tclearLine(): void; // Clear current line\n\tclearFromCursor(): void; // Clear from cursor to end of screen\n\tclearScreen(): void; // Clear entire screen and move cursor to (0,0)\n\n\t// Title operations\n\tsetTitle(title: string): void; // Set terminal window title\n\n\t// Progress indicator (OSC 9;4)\n\tsetProgress(active: boolean): void;\n}\n\n/**\n * Real terminal using process.stdin/stdout\n */\nexport class ProcessTerminal implements Terminal {\n\tprivate wasRaw = false;\n\tprivate started = false;\n\tprivate inputHandler?: (data: string) => void;\n\tprivate resizeHandler?: () => void;\n\tprivate _kittyProtocolActive = false;\n\tprivate _modifyOtherKeysActive = false;\n\tprivate keyboardProtocolPushed = false;\n\tprivate keyboardProtocolNegotiationPending = false;\n\tprivate keyboardProtocolLateResponsePending = false;\n\tprivate keyboardProtocolNegotiationBuffer = \"\";\n\tprivate keyboardProtocolFallbackTimer?: ReturnType<typeof setTimeout>;\n\tprivate keyboardProtocolBufferFlushTimer?: ReturnType<typeof setTimeout>;\n\tprivate stdinBuffer?: StdinBuffer;\n\tprivate stdinDataHandler?: (data: string) => void;\n\tprivate progressInterval?: ReturnType<typeof setInterval>;\n\tprivate writeLogPath = (() => {\n\t\tconst env = process.env.PI_TUI_WRITE_LOG || \"\";\n\t\tif (!env) return \"\";\n\t\ttry {\n\t\t\tif (fs.statSync(env).isDirectory()) {\n\t\t\t\tconst now = new Date();\n\t\t\t\tconst ts = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, \"0\")}-${String(now.getDate()).padStart(2, \"0\")}_${String(now.getHours()).padStart(2, \"0\")}-${String(now.getMinutes()).padStart(2, \"0\")}-${String(now.getSeconds()).padStart(2, \"0\")}`;\n\t\t\t\treturn path.join(env, `tui-${ts}-${process.pid}.log`);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Not an existing directory - use as-is (file path)\n\t\t}\n\t\treturn env;\n\t})();\n\n\tget kittyProtocolActive(): boolean {\n\t\treturn this._kittyProtocolActive;\n\t}\n\n\tstart(onInput: (data: string) => void, onResize: () => void): void {\n\t\tif (this.started) {\n\t\t\tthis.inputHandler = onInput;\n\t\t\tif (this.resizeHandler !== onResize) {\n\t\t\t\tif (this.resizeHandler) process.stdout.removeListener(\"resize\", this.resizeHandler);\n\t\t\t\tthis.resizeHandler = onResize;\n\t\t\t\tprocess.stdout.on(\"resize\", onResize);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tthis.started = true;\n\t\tthis.inputHandler = onInput;\n\t\tthis.resizeHandler = onResize;\n\t\t// Save previous state and enable raw mode\n\t\tthis.wasRaw = process.stdin.isRaw || false;\n\t\tif (process.stdin.setRawMode) {\n\t\t\tprocess.stdin.setRawMode(true);\n\t\t}\n\t\tprocess.stdin.setEncoding(\"utf8\");\n\t\tprocess.stdin.resume();\n\n\t\t// Enable bracketed paste mode - terminal will wrap pastes in \\x1b[200~ ... \\x1b[201~\n\t\tprocess.stdout.write(\"\\x1b[?2004h\");\n\n\t\t// Set up resize handler immediately\n\t\tprocess.stdout.on(\"resize\", this.resizeHandler);\n\n\t\t// Refresh terminal dimensions - they may be stale after suspend/resume\n\t\t// (SIGWINCH is lost while process is stopped). Unix only.\n\t\tif (process.platform !== \"win32\") {\n\t\t\tprocess.kill(process.pid, \"SIGWINCH\");\n\t\t}\n\n\t\t// On Windows, enable ENABLE_VIRTUAL_TERMINAL_INPUT so the console sends\n\t\t// VT escape sequences (e.g. \\x1b[Z for Shift+Tab) instead of raw console\n\t\t// events that lose modifier information. Must run AFTER setRawMode(true)\n\t\t// since that resets console mode flags.\n\t\tthis.enableWindowsVTInput();\n\n\t\t// Query and enable Kitty keyboard protocol\n\t\t// The query handler intercepts input temporarily, then installs the user's handler\n\t\t// See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/\n\t\tthis.queryAndEnableKittyProtocol();\n\t}\n\n\t/**\n\t * Set up StdinBuffer to split batched input into individual sequences.\n\t * This ensures components receive single events, making matchesKey/isKeyRelease work correctly.\n\t *\n\t * Also watches for Kitty protocol response and enables it when detected.\n\t * This is done here (after stdinBuffer parsing) rather than on raw stdin\n\t * to handle the case where the response arrives split across multiple events.\n\t */\n\tprivate setupStdinBuffer(): void {\n\t\tthis.stdinBuffer = new StdinBuffer({ timeout: 10 });\n\n\t\t// Forward individual sequences to the input handler\n\t\tthis.stdinBuffer.on(\"data\", (sequence) => {\n\t\t\tif (this.keyboardProtocolNegotiationPending) {\n\t\t\t\tconst negotiationSequence = this.readKeyboardProtocolNegotiationSequence(sequence, true);\n\t\t\t\tif (negotiationSequence === \"pending\") {\n\t\t\t\t\treturn; // Wait for the rest of a split negotiation response.\n\t\t\t\t}\n\t\t\t\tif (this.handleKeyboardProtocolNegotiationSequence(negotiationSequence)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.keyboardProtocolLateResponsePending) {\n\t\t\t\tconst negotiationSequence = this.readKeyboardProtocolNegotiationSequence(sequence, false);\n\t\t\t\tif (negotiationSequence === \"pending\") {\n\t\t\t\t\tthis.scheduleKeyboardProtocolNegotiationBufferFlush();\n\t\t\t\t\treturn; // Wait for the rest of a split late negotiation response.\n\t\t\t\t}\n\t\t\t\tif (this.handleKeyboardProtocolNegotiationSequence(negotiationSequence)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.forwardInputSequence(sequence);\n\t\t});\n\n\t\t// Re-wrap paste content with bracketed paste markers for existing editor handling\n\t\tthis.stdinBuffer.on(\"paste\", (content) => {\n\t\t\tif (this.inputHandler) {\n\t\t\t\tthis.inputHandler(`\\x1b[200~${content}\\x1b[201~`);\n\t\t\t}\n\t\t});\n\n\t\t// Handler that pipes stdin data through the buffer\n\t\tthis.stdinDataHandler = (data: string) => {\n\t\t\tthis.stdinBuffer!.process(data);\n\t\t};\n\t}\n\n\t/**\n\t * Query terminal for Kitty keyboard protocol support and enable it if available.\n\t *\n\t * Kitty's progressive enhancement detection requires requesting the desired\n\t * flags before querying them. The trailing DA query is a sentinel supported by\n\t * terminals that do not know Kitty keyboard protocol. A short timeout remains\n\t * as a backup for terminals, PTYs, and SSH sessions that delay, split, or drop\n\t * the DA response.\n\t *\n\t * The requested flags are:\n\t * - 1 = disambiguate escape codes\n\t * - 2 = report event types (press/repeat/release)\n\t * - 4 = report alternate keys (shifted key, base layout key)\n\t */\n\tprivate queryAndEnableKittyProtocol(): void {\n\t\tthis.setupStdinBuffer();\n\t\tprocess.stdin.on(\"data\", this.stdinDataHandler!);\n\t\tthis.keyboardProtocolPushed = true;\n\t\tthis.keyboardProtocolNegotiationPending = true;\n\t\tthis.keyboardProtocolLateResponsePending = false;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tprocess.stdout.write(KITTY_KEYBOARD_PROTOCOL_QUERY);\n\t\tthis.keyboardProtocolFallbackTimer = setTimeout(() => {\n\t\t\tthis.keyboardProtocolFallbackTimer = undefined;\n\t\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\t\tthis.keyboardProtocolLateResponsePending = true;\n\t\t\tif (this.keyboardProtocolNegotiationBuffer === \"\\x1b\") {\n\t\t\t\tthis.flushKeyboardProtocolNegotiationBufferAsInput();\n\t\t\t} else {\n\t\t\t\tthis.scheduleKeyboardProtocolNegotiationBufferFlush();\n\t\t\t}\n\t\t\tthis.enableModifyOtherKeys();\n\t\t}, KITTY_KEYBOARD_PROTOCOL_FALLBACK_TIMEOUT_MS);\n\t}\n\n\tprivate handleKeyboardProtocolNegotiationSequence(\n\t\tnegotiationSequence: KeyboardProtocolNegotiationSequence | undefined,\n\t): boolean {\n\t\tif (!negotiationSequence) return false;\n\t\tif (negotiationSequence.type === \"kitty-flags\") {\n\t\t\tif (negotiationSequence.flags !== 0 && !this._kittyProtocolActive) {\n\t\t\t\tthis._kittyProtocolActive = true;\n\t\t\t\tsetKittyProtocolActive(true);\n\t\t\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\t\t\tthis.keyboardProtocolLateResponsePending = true;\n\t\t\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\t\t\tthis.clearKeyboardProtocolFallbackTimer();\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\tthis.keyboardProtocolLateResponsePending = true;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.clearKeyboardProtocolFallbackTimer();\n\t\tthis.enableModifyOtherKeys();\n\t\treturn true;\n\t}\n\n\tprivate readKeyboardProtocolNegotiationSequence(\n\t\tsequence: string,\n\t\tallowBareEscapePrefix: boolean,\n\t): KeyboardProtocolNegotiationSequence | \"pending\" | undefined {\n\t\tif (this.keyboardProtocolNegotiationBuffer) {\n\t\t\tconst bufferedSequence = this.keyboardProtocolNegotiationBuffer + sequence;\n\t\t\tconst negotiationSequence = parseKeyboardProtocolNegotiationSequence(bufferedSequence);\n\t\t\tif (negotiationSequence) {\n\t\t\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\t\t\treturn negotiationSequence;\n\t\t\t}\n\t\t\tif (isKeyboardProtocolNegotiationSequencePrefix(bufferedSequence, allowBareEscapePrefix)) {\n\t\t\t\tthis.setKeyboardProtocolNegotiationBuffer(bufferedSequence);\n\t\t\t\treturn \"pending\";\n\t\t\t}\n\t\t\tthis.flushKeyboardProtocolNegotiationBufferAsInput();\n\t\t}\n\n\t\tconst negotiationSequence = parseKeyboardProtocolNegotiationSequence(sequence);\n\t\tif (negotiationSequence) return negotiationSequence;\n\t\tif (isKeyboardProtocolNegotiationSequencePrefix(sequence, allowBareEscapePrefix)) {\n\t\t\tthis.setKeyboardProtocolNegotiationBuffer(sequence);\n\t\t\treturn \"pending\";\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate setKeyboardProtocolNegotiationBuffer(sequence: string): void {\n\t\tthis.clearKeyboardProtocolNegotiationBufferFlushTimer();\n\t\tthis.keyboardProtocolNegotiationBuffer = sequence;\n\t}\n\n\tprivate clearKeyboardProtocolNegotiationBuffer(): void {\n\t\tthis.clearKeyboardProtocolNegotiationBufferFlushTimer();\n\t\tthis.keyboardProtocolNegotiationBuffer = \"\";\n\t}\n\n\tprivate flushKeyboardProtocolNegotiationBufferAsInput(): void {\n\t\tif (!this.keyboardProtocolNegotiationBuffer) return;\n\t\tconst sequence = this.keyboardProtocolNegotiationBuffer;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.forwardInputSequence(sequence);\n\t}\n\n\tprivate scheduleKeyboardProtocolNegotiationBufferFlush(): void {\n\t\tif (!this.keyboardProtocolNegotiationBuffer || this.keyboardProtocolBufferFlushTimer) return;\n\t\tthis.keyboardProtocolBufferFlushTimer = setTimeout(() => {\n\t\t\tthis.keyboardProtocolBufferFlushTimer = undefined;\n\t\t\tthis.flushKeyboardProtocolNegotiationBufferAsInput();\n\t\t}, KEYBOARD_PROTOCOL_RESPONSE_FRAGMENT_TIMEOUT_MS);\n\t}\n\n\tprivate clearKeyboardProtocolNegotiationBufferFlushTimer(): void {\n\t\tif (!this.keyboardProtocolBufferFlushTimer) return;\n\t\tclearTimeout(this.keyboardProtocolBufferFlushTimer);\n\t\tthis.keyboardProtocolBufferFlushTimer = undefined;\n\t}\n\n\tprivate forwardInputSequence(sequence: string): void {\n\t\tif (!this.inputHandler) return;\n\t\tconst isAppleTerminal = sequence === \"\\r\" && isAppleTerminalSession();\n\t\tconst input = normalizeAppleTerminalInput(\n\t\t\tsequence,\n\t\t\tisAppleTerminal,\n\t\t\tisAppleTerminal && isNativeModifierPressed(\"shift\"),\n\t\t);\n\t\tthis.inputHandler(input);\n\t}\n\n\tprivate enableModifyOtherKeys(): void {\n\t\tif (this._kittyProtocolActive || this._modifyOtherKeysActive) return;\n\t\tprocess.stdout.write(\"\\x1b[>4;2m\");\n\t\tthis._modifyOtherKeysActive = true;\n\t}\n\n\tprivate clearKeyboardProtocolFallbackTimer(): void {\n\t\tif (!this.keyboardProtocolFallbackTimer) return;\n\t\tclearTimeout(this.keyboardProtocolFallbackTimer);\n\t\tthis.keyboardProtocolFallbackTimer = undefined;\n\t}\n\n\t/**\n\t * On Windows, add ENABLE_VIRTUAL_TERMINAL_INPUT (0x0200) to the stdin\n\t * console handle so the terminal sends VT sequences for modified keys\n\t * (e.g. \\x1b[Z for Shift+Tab). Without this, libuv's ReadConsoleInputW\n\t * discards modifier state and Shift+Tab arrives as plain \\t.\n\t */\n\tprivate enableWindowsVTInput(): void {\n\t\tif (process.platform !== \"win32\") return;\n\t\ttry {\n\t\t\tconst arch = process.arch;\n\t\t\tif (arch !== \"x64\" && arch !== \"arm64\") return;\n\n\t\t\t// Dynamic require so non-Windows and bundled/browser paths never load the\n\t\t\t// native helper. In the npm package native/ is next to dist/; in compiled\n\t\t\t// binary archives native/ is copied next to the executable.\n\t\t\tconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\n\t\t\tconst nativePath = path.join(\"native\", \"win32\", \"prebuilds\", `win32-${arch}`, \"win32-console-mode.node\");\n\t\t\tconst candidates = [\n\t\t\t\tpath.join(moduleDir, \"..\", nativePath),\n\t\t\t\tpath.join(moduleDir, nativePath),\n\t\t\t\tpath.join(path.dirname(process.execPath), nativePath),\n\t\t\t];\n\t\t\tfor (const modulePath of candidates) {\n\t\t\t\ttry {\n\t\t\t\t\tconst helper = cjsRequire(modulePath) as { enableVirtualTerminalInput?: () => boolean };\n\t\t\t\t\thelper.enableVirtualTerminalInput?.();\n\t\t\t\t\treturn;\n\t\t\t\t} catch {\n\t\t\t\t\t// Try the next possible packaging location.\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Native helper not available — Shift+Tab won't be distinguishable from Tab.\n\t\t}\n\t}\n\n\tasync drainInput(maxMs = 1000, idleMs = 50): Promise<void> {\n\t\tconst shouldDisableKittyProtocol =\n\t\t\tthis.keyboardProtocolPushed || this._kittyProtocolActive || this.keyboardProtocolNegotiationPending;\n\t\tthis.keyboardProtocolLateResponsePending = false;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.clearKeyboardProtocolFallbackTimer();\n\t\tif (shouldDisableKittyProtocol) {\n\t\t\t// Disable Kitty keyboard protocol first so any late key releases\n\t\t\t// do not generate new Kitty escape sequences.\n\t\t\tprocess.stdout.write(\"\\x1b[<u\");\n\t\t\tthis.keyboardProtocolPushed = false;\n\t\t\tthis._kittyProtocolActive = false;\n\t\t\tsetKittyProtocolActive(false);\n\t\t}\n\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\tif (this._modifyOtherKeysActive) {\n\t\t\tprocess.stdout.write(\"\\x1b[>4;0m\");\n\t\t\tthis._modifyOtherKeysActive = false;\n\t\t}\n\n\t\tconst previousHandler = this.inputHandler;\n\t\tthis.inputHandler = undefined;\n\n\t\tlet lastDataTime = Date.now();\n\t\tconst onData = () => {\n\t\t\tlastDataTime = Date.now();\n\t\t};\n\n\t\tprocess.stdin.on(\"data\", onData);\n\t\tconst endTime = Date.now() + maxMs;\n\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tconst now = Date.now();\n\t\t\t\tconst timeLeft = endTime - now;\n\t\t\t\tif (timeLeft <= 0) break;\n\t\t\t\tif (now - lastDataTime >= idleMs) break;\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, Math.min(idleMs, timeLeft)));\n\t\t\t}\n\t\t} finally {\n\t\t\tprocess.stdin.removeListener(\"data\", onData);\n\t\t\tthis.inputHandler = previousHandler;\n\t\t}\n\t}\n\n\tstop(): void {\n\t\tthis.started = false;\n\t\tif (this.clearProgressInterval()) {\n\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_CLEAR_SEQUENCE);\n\t\t}\n\n\t\t// Disable bracketed paste mode\n\t\tprocess.stdout.write(\"\\x1b[?2004l\");\n\n\t\tconst shouldDisableKittyProtocol =\n\t\t\tthis.keyboardProtocolPushed || this._kittyProtocolActive || this.keyboardProtocolNegotiationPending;\n\t\tthis.keyboardProtocolLateResponsePending = false;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.clearKeyboardProtocolFallbackTimer();\n\n\t\t// Disable Kitty keyboard protocol if not already done by drainInput()\n\t\tif (shouldDisableKittyProtocol) {\n\t\t\tprocess.stdout.write(\"\\x1b[<u\");\n\t\t\tthis.keyboardProtocolPushed = false;\n\t\t\tthis._kittyProtocolActive = false;\n\t\t\tsetKittyProtocolActive(false);\n\t\t}\n\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\tif (this._modifyOtherKeysActive) {\n\t\t\tprocess.stdout.write(\"\\x1b[>4;0m\");\n\t\t\tthis._modifyOtherKeysActive = false;\n\t\t}\n\n\t\t// Clean up StdinBuffer\n\t\tif (this.stdinBuffer) {\n\t\t\tthis.stdinBuffer.destroy();\n\t\t\tthis.stdinBuffer = undefined;\n\t\t}\n\n\t\t// Remove event handlers\n\t\tif (this.stdinDataHandler) {\n\t\t\tprocess.stdin.removeListener(\"data\", this.stdinDataHandler);\n\t\t\tthis.stdinDataHandler = undefined;\n\t\t}\n\t\tthis.inputHandler = undefined;\n\t\tif (this.resizeHandler) {\n\t\t\tprocess.stdout.removeListener(\"resize\", this.resizeHandler);\n\t\t\tthis.resizeHandler = undefined;\n\t\t}\n\n\t\t// Pause stdin to prevent any buffered input (e.g., Ctrl+D) from being\n\t\t// re-interpreted after raw mode is disabled. This fixes a race condition\n\t\t// where Ctrl+D could close the parent shell over SSH.\n\t\tprocess.stdin.pause();\n\n\t\t// Restore raw mode state\n\t\tif (process.stdin.setRawMode) {\n\t\t\tprocess.stdin.setRawMode(this.wasRaw);\n\t\t}\n\t}\n\n\twrite(data: string): void {\n\t\tprocess.stdout.write(data);\n\t\tif (this.writeLogPath) {\n\t\t\ttry {\n\t\t\t\tfs.appendFileSync(this.writeLogPath, data, { encoding: \"utf8\" });\n\t\t\t} catch {\n\t\t\t\t// Ignore logging errors\n\t\t\t}\n\t\t}\n\t}\n\n\tget columns(): number {\n\t\treturn process.stdout.columns || Number(process.env.COLUMNS) || 80;\n\t}\n\n\tget rows(): number {\n\t\treturn process.stdout.rows || Number(process.env.LINES) || 24;\n\t}\n\n\tmoveBy(lines: number): void {\n\t\tif (lines > 0) {\n\t\t\t// Move down\n\t\t\tprocess.stdout.write(`\\x1b[${lines}B`);\n\t\t} else if (lines < 0) {\n\t\t\t// Move up\n\t\t\tprocess.stdout.write(`\\x1b[${-lines}A`);\n\t\t}\n\t\t// lines === 0: no movement\n\t}\n\n\thideCursor(): void {\n\t\tprocess.stdout.write(\"\\x1b[?25l\");\n\t}\n\n\tshowCursor(): void {\n\t\tprocess.stdout.write(\"\\x1b[?25h\");\n\t}\n\n\tclearLine(): void {\n\t\tprocess.stdout.write(\"\\x1b[K\");\n\t}\n\n\tclearFromCursor(): void {\n\t\tprocess.stdout.write(\"\\x1b[J\");\n\t}\n\n\tclearScreen(): void {\n\t\tprocess.stdout.write(\"\\x1b[2J\\x1b[H\"); // Clear screen and move to home (1,1)\n\t}\n\n\tsetTitle(title: string): void {\n\t\t// OSC 0;title BEL - set terminal window title\n\t\tprocess.stdout.write(`\\x1b]0;${sanitizeTerminalControlPayload(title)}\\x07`);\n\t}\n\n\tsetProgress(active: boolean): void {\n\t\tif (active) {\n\t\t\t// OSC 9;4;3 - indeterminate progress\n\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_ACTIVE_SEQUENCE);\n\t\t\tif (!this.progressInterval) {\n\t\t\t\tthis.progressInterval = setInterval(() => {\n\t\t\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_ACTIVE_SEQUENCE);\n\t\t\t\t}, TERMINAL_PROGRESS_KEEPALIVE_MS);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.clearProgressInterval();\n\t\t\t// OSC 9;4;0 - clear progress\n\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_CLEAR_SEQUENCE);\n\t\t}\n\t}\n\n\tprivate clearProgressInterval(): boolean {\n\t\tif (!this.progressInterval) return false;\n\t\tclearInterval(this.progressInterval);\n\t\tthis.progressInterval = undefined;\n\t\treturn true;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"terminal.js","sourceRoot":"","sources":["../src/terminal.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { setKittyProtocolActive } from \"./keys.ts\";\nimport { isNativeModifierPressed } from \"./native-modifiers.ts\";\nimport { StdinBuffer } from \"./stdin-buffer.ts\";\nimport { sanitizeTerminalControlPayload } from \"./terminal-control.ts\";\n\nconst cjsRequire = createRequire(import.meta.url);\n\nconst TERMINAL_PROGRESS_KEEPALIVE_MS = 1000;\nconst TERMINAL_PROGRESS_ACTIVE_SEQUENCE = \"\\x1b]9;4;3\\x07\";\nconst TERMINAL_PROGRESS_CLEAR_SEQUENCE = \"\\x1b]9;4;0\\x07\";\nconst APPLE_TERMINAL_SHIFT_ENTER_SEQUENCE = \"\\x1b[13;2u\";\nconst DESIRED_KITTY_KEYBOARD_PROTOCOL_FLAGS = 7;\nconst KITTY_KEYBOARD_PROTOCOL_FALLBACK_TIMEOUT_MS = 150;\nconst KEYBOARD_PROTOCOL_RESPONSE_FRAGMENT_TIMEOUT_MS = 150;\nconst KITTY_KEYBOARD_PROTOCOL_QUERY = `\\x1b[>${DESIRED_KITTY_KEYBOARD_PROTOCOL_FLAGS}u\\x1b[?u\\x1b[c`;\n\nexport type KeyboardProtocolNegotiationSequence =\n\t| { type: \"kitty-flags\"; flags: number }\n\t| { type: \"device-attributes\" };\n\nexport function parseKeyboardProtocolNegotiationSequence(\n\tsequence: string,\n): KeyboardProtocolNegotiationSequence | undefined {\n\tconst kittyFlags = sequence.match(/^\\x1b\\[\\?(\\d+)u$/);\n\tif (kittyFlags) {\n\t\treturn { type: \"kitty-flags\", flags: Number.parseInt(kittyFlags[1]!, 10) };\n\t}\n\tif (/^\\x1b\\[\\?[\\d;]*c$/.test(sequence)) {\n\t\treturn { type: \"device-attributes\" };\n\t}\n\treturn undefined;\n}\n\nfunction isKeyboardProtocolNegotiationSequencePrefix(sequence: string, allowBareEscapePrefix: boolean): boolean {\n\treturn (allowBareEscapePrefix && sequence === \"\\x1b\") || sequence === \"\\x1b[\" || /^\\x1b\\[\\?[\\d;]*$/.test(sequence);\n}\n\nexport function isAppleTerminalSession(): boolean {\n\treturn process.platform === \"darwin\" && process.env.TERM_PROGRAM === \"Apple_Terminal\";\n}\n\nexport function normalizeAppleTerminalInput(data: string, isAppleTerminal: boolean, isShiftPressed: boolean): string {\n\tif (isAppleTerminal && data === \"\\r\" && isShiftPressed) return APPLE_TERMINAL_SHIFT_ENTER_SEQUENCE;\n\treturn data;\n}\n\n/**\n * Minimal terminal interface for TUI\n */\nexport interface Terminal {\n\t// Start the terminal with input and resize handlers\n\tstart(onInput: (data: string) => void, onResize: () => void): void;\n\n\t// Stop the terminal and restore state\n\tstop(): void;\n\n\t/**\n\t * Drain stdin before exiting to prevent Kitty key release events from\n\t * leaking to the parent shell over slow SSH connections.\n\t * @param maxMs - Maximum time to drain (default: 1000ms)\n\t * @param idleMs - Exit early if no input arrives within this time (default: 50ms)\n\t */\n\tdrainInput(maxMs?: number, idleMs?: number): Promise<void>;\n\n\t// Write output to terminal\n\twrite(data: string): void;\n\n\t// Get terminal dimensions\n\tget columns(): number;\n\tget rows(): number;\n\n\t// Whether Kitty keyboard protocol is active\n\tget kittyProtocolActive(): boolean;\n\n\t// Cursor positioning (relative to current position)\n\tmoveBy(lines: number): void; // Move cursor up (negative) or down (positive) by N lines\n\n\t// Cursor visibility\n\thideCursor(): void; // Hide the cursor\n\tshowCursor(): void; // Show the cursor\n\n\t// Clear operations\n\tclearLine(): void; // Clear current line\n\tclearFromCursor(): void; // Clear from cursor to end of screen\n\tclearScreen(): void; // Clear entire screen and move cursor to (0,0)\n\n\t// Title operations\n\tsetTitle(title: string): void; // Set terminal window title\n\n\t// Progress indicator (OSC 9;4)\n\tsetProgress(active: boolean): void;\n}\n\n/**\n * Real terminal using process.stdin/stdout\n */\nexport class ProcessTerminal implements Terminal {\n\tprivate wasRaw = false;\n\tprivate started = false;\n\tprivate inputHandler?: (data: string) => void;\n\tprivate resizeHandler?: () => void;\n\tprivate _kittyProtocolActive = false;\n\tprivate _modifyOtherKeysActive = false;\n\tprivate keyboardProtocolPushed = false;\n\tprivate keyboardProtocolNegotiationPending = false;\n\tprivate keyboardProtocolLateResponsePending = false;\n\tprivate keyboardProtocolNegotiationBuffer = \"\";\n\tprivate keyboardProtocolFallbackTimer?: ReturnType<typeof setTimeout>;\n\tprivate keyboardProtocolBufferFlushTimer?: ReturnType<typeof setTimeout>;\n\tprivate stdinBuffer?: StdinBuffer;\n\tprivate stdinDataHandler?: (data: string) => void;\n\tprivate progressInterval?: ReturnType<typeof setInterval>;\n\tprivate writeLogPath = (() => {\n\t\tconst env = process.env.PI_TUI_WRITE_LOG || \"\";\n\t\tif (!env) return \"\";\n\t\ttry {\n\t\t\tif (fs.statSync(env).isDirectory()) {\n\t\t\t\tconst now = new Date();\n\t\t\t\tconst ts = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, \"0\")}-${String(now.getDate()).padStart(2, \"0\")}_${String(now.getHours()).padStart(2, \"0\")}-${String(now.getMinutes()).padStart(2, \"0\")}-${String(now.getSeconds()).padStart(2, \"0\")}`;\n\t\t\t\treturn path.join(env, `tui-${ts}-${process.pid}.log`);\n\t\t\t}\n\t\t} catch {\n\t\t\t// Not an existing directory - use as-is (file path)\n\t\t}\n\t\treturn env;\n\t})();\n\n\tget kittyProtocolActive(): boolean {\n\t\treturn this._kittyProtocolActive;\n\t}\n\n\tstart(onInput: (data: string) => void, onResize: () => void): void {\n\t\tif (this.started) {\n\t\t\tthis.inputHandler = onInput;\n\t\t\tif (this.resizeHandler !== onResize) {\n\t\t\t\tif (this.resizeHandler) process.stdout.removeListener(\"resize\", this.resizeHandler);\n\t\t\t\tthis.resizeHandler = onResize;\n\t\t\t\tprocess.stdout.on(\"resize\", onResize);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tthis.started = true;\n\t\tthis.inputHandler = onInput;\n\t\tthis.resizeHandler = onResize;\n\t\t// Save previous state and enable raw mode\n\t\tthis.wasRaw = process.stdin.isRaw || false;\n\t\tif (process.stdin.setRawMode) {\n\t\t\tprocess.stdin.setRawMode(true);\n\t\t}\n\t\tprocess.stdin.setEncoding(\"utf8\");\n\t\tprocess.stdin.resume();\n\n\t\t// Enable bracketed paste mode - terminal will wrap pastes in \\x1b[200~ ... \\x1b[201~\n\t\tprocess.stdout.write(\"\\x1b[?2004h\");\n\n\t\t// Set up resize handler immediately\n\t\tprocess.stdout.on(\"resize\", this.resizeHandler);\n\n\t\t// Refresh terminal dimensions - they may be stale after suspend/resume\n\t\t// (SIGWINCH is lost while process is stopped). Unix only.\n\t\tif (process.platform !== \"win32\") {\n\t\t\tprocess.kill(process.pid, \"SIGWINCH\");\n\t\t}\n\n\t\t// On Windows, enable ENABLE_VIRTUAL_TERMINAL_INPUT so the console sends\n\t\t// VT escape sequences (e.g. \\x1b[Z for Shift+Tab) instead of raw console\n\t\t// events that lose modifier information. Must run AFTER setRawMode(true)\n\t\t// since that resets console mode flags.\n\t\tthis.enableWindowsVTInput();\n\n\t\t// Query and enable Kitty keyboard protocol\n\t\t// The query handler intercepts input temporarily, then installs the user's handler\n\t\t// See: https://sw.kovidgoyal.net/kitty/keyboard-protocol/\n\t\tthis.queryAndEnableKittyProtocol();\n\t}\n\n\tprivate handleInitialKeyboardProtocolInput(sequence: string): boolean {\n\t\tif (!this.keyboardProtocolNegotiationPending) return false;\n\t\tconst negotiationSequence = this.readKeyboardProtocolNegotiationSequence(sequence, true);\n\t\tif (negotiationSequence === \"pending\") return true;\n\t\treturn this.handleKeyboardProtocolNegotiationSequence(negotiationSequence);\n\t}\n\n\tprivate handleLateKeyboardProtocolInput(sequence: string): boolean {\n\t\tif (!this.keyboardProtocolLateResponsePending) return false;\n\t\tconst negotiationSequence = this.readKeyboardProtocolNegotiationSequence(sequence, false);\n\t\tif (negotiationSequence === \"pending\") {\n\t\t\tthis.scheduleKeyboardProtocolNegotiationBufferFlush();\n\t\t\treturn true;\n\t\t}\n\t\treturn this.handleKeyboardProtocolNegotiationSequence(negotiationSequence);\n\t}\n\n\tprivate handleBufferedInputSequence(sequence: string): void {\n\t\tif (this.handleInitialKeyboardProtocolInput(sequence)) return;\n\t\tif (this.handleLateKeyboardProtocolInput(sequence)) return;\n\t\tthis.forwardInputSequence(sequence);\n\t}\n\n\t/**\n\t * Set up StdinBuffer to split batched input into individual sequences.\n\t * This ensures components receive single events, making matchesKey/isKeyRelease work correctly.\n\t *\n\t * Also watches for Kitty protocol response and enables it when detected.\n\t * This is done here (after stdinBuffer parsing) rather than on raw stdin\n\t * to handle the case where the response arrives split across multiple events.\n\t */\n\tprivate setupStdinBuffer(): void {\n\t\tthis.stdinBuffer = new StdinBuffer({ timeout: 10 });\n\n\t\t// Forward individual sequences to the input handler\n\t\tthis.stdinBuffer.on(\"data\", (sequence) => this.handleBufferedInputSequence(sequence));\n\n\t\t// Re-wrap paste content with bracketed paste markers for existing editor handling\n\t\tthis.stdinBuffer.on(\"paste\", (content) => {\n\t\t\tif (this.inputHandler) {\n\t\t\t\tthis.inputHandler(`\\x1b[200~${content}\\x1b[201~`);\n\t\t\t}\n\t\t});\n\n\t\t// Handler that pipes stdin data through the buffer\n\t\tthis.stdinDataHandler = (data: string) => {\n\t\t\tthis.stdinBuffer!.process(data);\n\t\t};\n\t}\n\n\t/**\n\t * Query terminal for Kitty keyboard protocol support and enable it if available.\n\t *\n\t * Kitty's progressive enhancement detection requires requesting the desired\n\t * flags before querying them. The trailing DA query is a sentinel supported by\n\t * terminals that do not know Kitty keyboard protocol. A short timeout remains\n\t * as a backup for terminals, PTYs, and SSH sessions that delay, split, or drop\n\t * the DA response.\n\t *\n\t * The requested flags are:\n\t * - 1 = disambiguate escape codes\n\t * - 2 = report event types (press/repeat/release)\n\t * - 4 = report alternate keys (shifted key, base layout key)\n\t */\n\tprivate queryAndEnableKittyProtocol(): void {\n\t\tthis.setupStdinBuffer();\n\t\tprocess.stdin.on(\"data\", this.stdinDataHandler!);\n\t\tthis.keyboardProtocolPushed = true;\n\t\tthis.keyboardProtocolNegotiationPending = true;\n\t\tthis.keyboardProtocolLateResponsePending = false;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tprocess.stdout.write(KITTY_KEYBOARD_PROTOCOL_QUERY);\n\t\tthis.keyboardProtocolFallbackTimer = setTimeout(() => {\n\t\t\tthis.keyboardProtocolFallbackTimer = undefined;\n\t\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\t\tthis.keyboardProtocolLateResponsePending = true;\n\t\t\tif (this.keyboardProtocolNegotiationBuffer === \"\\x1b\") {\n\t\t\t\tthis.flushKeyboardProtocolNegotiationBufferAsInput();\n\t\t\t} else {\n\t\t\t\tthis.scheduleKeyboardProtocolNegotiationBufferFlush();\n\t\t\t}\n\t\t\tthis.enableModifyOtherKeys();\n\t\t}, KITTY_KEYBOARD_PROTOCOL_FALLBACK_TIMEOUT_MS);\n\t}\n\n\tprivate handleKeyboardProtocolNegotiationSequence(\n\t\tnegotiationSequence: KeyboardProtocolNegotiationSequence | undefined,\n\t): boolean {\n\t\tif (!negotiationSequence) return false;\n\t\tif (negotiationSequence.type === \"kitty-flags\") {\n\t\t\tif (negotiationSequence.flags !== 0 && !this._kittyProtocolActive) {\n\t\t\t\tthis._kittyProtocolActive = true;\n\t\t\t\tsetKittyProtocolActive(true);\n\t\t\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\t\t\tthis.keyboardProtocolLateResponsePending = true;\n\t\t\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\t\t\tthis.clearKeyboardProtocolFallbackTimer();\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\tthis.keyboardProtocolLateResponsePending = true;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.clearKeyboardProtocolFallbackTimer();\n\t\tthis.enableModifyOtherKeys();\n\t\treturn true;\n\t}\n\n\tprivate readKeyboardProtocolNegotiationSequence(\n\t\tsequence: string,\n\t\tallowBareEscapePrefix: boolean,\n\t): KeyboardProtocolNegotiationSequence | \"pending\" | undefined {\n\t\tif (this.keyboardProtocolNegotiationBuffer) {\n\t\t\tconst bufferedSequence = this.keyboardProtocolNegotiationBuffer + sequence;\n\t\t\tconst negotiationSequence = parseKeyboardProtocolNegotiationSequence(bufferedSequence);\n\t\t\tif (negotiationSequence) {\n\t\t\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\t\t\treturn negotiationSequence;\n\t\t\t}\n\t\t\tif (isKeyboardProtocolNegotiationSequencePrefix(bufferedSequence, allowBareEscapePrefix)) {\n\t\t\t\tthis.setKeyboardProtocolNegotiationBuffer(bufferedSequence);\n\t\t\t\treturn \"pending\";\n\t\t\t}\n\t\t\tthis.flushKeyboardProtocolNegotiationBufferAsInput();\n\t\t}\n\n\t\tconst negotiationSequence = parseKeyboardProtocolNegotiationSequence(sequence);\n\t\tif (negotiationSequence) return negotiationSequence;\n\t\tif (isKeyboardProtocolNegotiationSequencePrefix(sequence, allowBareEscapePrefix)) {\n\t\t\tthis.setKeyboardProtocolNegotiationBuffer(sequence);\n\t\t\treturn \"pending\";\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate setKeyboardProtocolNegotiationBuffer(sequence: string): void {\n\t\tthis.clearKeyboardProtocolNegotiationBufferFlushTimer();\n\t\tthis.keyboardProtocolNegotiationBuffer = sequence;\n\t}\n\n\tprivate clearKeyboardProtocolNegotiationBuffer(): void {\n\t\tthis.clearKeyboardProtocolNegotiationBufferFlushTimer();\n\t\tthis.keyboardProtocolNegotiationBuffer = \"\";\n\t}\n\n\tprivate flushKeyboardProtocolNegotiationBufferAsInput(): void {\n\t\tif (!this.keyboardProtocolNegotiationBuffer) return;\n\t\tconst sequence = this.keyboardProtocolNegotiationBuffer;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.forwardInputSequence(sequence);\n\t}\n\n\tprivate scheduleKeyboardProtocolNegotiationBufferFlush(): void {\n\t\tif (!this.keyboardProtocolNegotiationBuffer || this.keyboardProtocolBufferFlushTimer) return;\n\t\tthis.keyboardProtocolBufferFlushTimer = setTimeout(() => {\n\t\t\tthis.keyboardProtocolBufferFlushTimer = undefined;\n\t\t\tthis.flushKeyboardProtocolNegotiationBufferAsInput();\n\t\t}, KEYBOARD_PROTOCOL_RESPONSE_FRAGMENT_TIMEOUT_MS);\n\t}\n\n\tprivate clearKeyboardProtocolNegotiationBufferFlushTimer(): void {\n\t\tif (!this.keyboardProtocolBufferFlushTimer) return;\n\t\tclearTimeout(this.keyboardProtocolBufferFlushTimer);\n\t\tthis.keyboardProtocolBufferFlushTimer = undefined;\n\t}\n\n\tprivate forwardInputSequence(sequence: string): void {\n\t\tif (!this.inputHandler) return;\n\t\tconst isAppleTerminal = sequence === \"\\r\" && isAppleTerminalSession();\n\t\tconst input = normalizeAppleTerminalInput(\n\t\t\tsequence,\n\t\t\tisAppleTerminal,\n\t\t\tisAppleTerminal && isNativeModifierPressed(\"shift\"),\n\t\t);\n\t\tthis.inputHandler(input);\n\t}\n\n\tprivate enableModifyOtherKeys(): void {\n\t\tif (this._kittyProtocolActive || this._modifyOtherKeysActive) return;\n\t\tprocess.stdout.write(\"\\x1b[>4;2m\");\n\t\tthis._modifyOtherKeysActive = true;\n\t}\n\n\tprivate clearKeyboardProtocolFallbackTimer(): void {\n\t\tif (!this.keyboardProtocolFallbackTimer) return;\n\t\tclearTimeout(this.keyboardProtocolFallbackTimer);\n\t\tthis.keyboardProtocolFallbackTimer = undefined;\n\t}\n\n\t/**\n\t * On Windows, add ENABLE_VIRTUAL_TERMINAL_INPUT (0x0200) to the stdin\n\t * console handle so the terminal sends VT sequences for modified keys\n\t * (e.g. \\x1b[Z for Shift+Tab). Without this, libuv's ReadConsoleInputW\n\t * discards modifier state and Shift+Tab arrives as plain \\t.\n\t */\n\tprivate enableWindowsVTInput(): void {\n\t\tif (process.platform !== \"win32\") return;\n\t\ttry {\n\t\t\tconst arch = process.arch;\n\t\t\tif (arch !== \"x64\" && arch !== \"arm64\") return;\n\n\t\t\t// Dynamic require so non-Windows and bundled/browser paths never load the\n\t\t\t// native helper. In the npm package native/ is next to dist/; in compiled\n\t\t\t// binary archives native/ is copied next to the executable.\n\t\t\tconst moduleDir = path.dirname(fileURLToPath(import.meta.url));\n\t\t\tconst nativePath = path.join(\"native\", \"win32\", \"prebuilds\", `win32-${arch}`, \"win32-console-mode.node\");\n\t\t\tconst candidates = [\n\t\t\t\tpath.join(moduleDir, \"..\", nativePath),\n\t\t\t\tpath.join(moduleDir, nativePath),\n\t\t\t\tpath.join(path.dirname(process.execPath), nativePath),\n\t\t\t];\n\t\t\tfor (const modulePath of candidates) {\n\t\t\t\ttry {\n\t\t\t\t\tconst helper = cjsRequire(modulePath) as { enableVirtualTerminalInput?: () => boolean };\n\t\t\t\t\thelper.enableVirtualTerminalInput?.();\n\t\t\t\t\treturn;\n\t\t\t\t} catch {\n\t\t\t\t\t// Try the next possible packaging location.\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Native helper not available — Shift+Tab won't be distinguishable from Tab.\n\t\t}\n\t}\n\n\tasync drainInput(maxMs = 1000, idleMs = 50): Promise<void> {\n\t\tconst shouldDisableKittyProtocol =\n\t\t\tthis.keyboardProtocolPushed || this._kittyProtocolActive || this.keyboardProtocolNegotiationPending;\n\t\tthis.keyboardProtocolLateResponsePending = false;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.clearKeyboardProtocolFallbackTimer();\n\t\tif (shouldDisableKittyProtocol) {\n\t\t\t// Disable Kitty keyboard protocol first so any late key releases\n\t\t\t// do not generate new Kitty escape sequences.\n\t\t\tprocess.stdout.write(\"\\x1b[<u\");\n\t\t\tthis.keyboardProtocolPushed = false;\n\t\t\tthis._kittyProtocolActive = false;\n\t\t\tsetKittyProtocolActive(false);\n\t\t}\n\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\tif (this._modifyOtherKeysActive) {\n\t\t\tprocess.stdout.write(\"\\x1b[>4;0m\");\n\t\t\tthis._modifyOtherKeysActive = false;\n\t\t}\n\n\t\tconst previousHandler = this.inputHandler;\n\t\tthis.inputHandler = undefined;\n\n\t\tlet lastDataTime = Date.now();\n\t\tconst onData = () => {\n\t\t\tlastDataTime = Date.now();\n\t\t};\n\n\t\tprocess.stdin.on(\"data\", onData);\n\t\tconst endTime = Date.now() + maxMs;\n\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tconst now = Date.now();\n\t\t\t\tconst timeLeft = endTime - now;\n\t\t\t\tif (timeLeft <= 0) break;\n\t\t\t\tif (now - lastDataTime >= idleMs) break;\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, Math.min(idleMs, timeLeft)));\n\t\t\t}\n\t\t} finally {\n\t\t\tprocess.stdin.removeListener(\"data\", onData);\n\t\t\tthis.inputHandler = previousHandler;\n\t\t}\n\t}\n\n\tstop(): void {\n\t\tthis.started = false;\n\t\tif (this.clearProgressInterval()) {\n\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_CLEAR_SEQUENCE);\n\t\t}\n\n\t\t// Disable bracketed paste mode\n\t\tprocess.stdout.write(\"\\x1b[?2004l\");\n\n\t\tconst shouldDisableKittyProtocol =\n\t\t\tthis.keyboardProtocolPushed || this._kittyProtocolActive || this.keyboardProtocolNegotiationPending;\n\t\tthis.keyboardProtocolLateResponsePending = false;\n\t\tthis.clearKeyboardProtocolNegotiationBuffer();\n\t\tthis.clearKeyboardProtocolFallbackTimer();\n\n\t\t// Disable Kitty keyboard protocol if not already done by drainInput()\n\t\tif (shouldDisableKittyProtocol) {\n\t\t\tprocess.stdout.write(\"\\x1b[<u\");\n\t\t\tthis.keyboardProtocolPushed = false;\n\t\t\tthis._kittyProtocolActive = false;\n\t\t\tsetKittyProtocolActive(false);\n\t\t}\n\t\tthis.keyboardProtocolNegotiationPending = false;\n\t\tif (this._modifyOtherKeysActive) {\n\t\t\tprocess.stdout.write(\"\\x1b[>4;0m\");\n\t\t\tthis._modifyOtherKeysActive = false;\n\t\t}\n\n\t\t// Clean up StdinBuffer\n\t\tif (this.stdinBuffer) {\n\t\t\tthis.stdinBuffer.destroy();\n\t\t\tthis.stdinBuffer = undefined;\n\t\t}\n\n\t\t// Remove event handlers\n\t\tif (this.stdinDataHandler) {\n\t\t\tprocess.stdin.removeListener(\"data\", this.stdinDataHandler);\n\t\t\tthis.stdinDataHandler = undefined;\n\t\t}\n\t\tthis.inputHandler = undefined;\n\t\tif (this.resizeHandler) {\n\t\t\tprocess.stdout.removeListener(\"resize\", this.resizeHandler);\n\t\t\tthis.resizeHandler = undefined;\n\t\t}\n\n\t\t// Pause stdin to prevent any buffered input (e.g., Ctrl+D) from being\n\t\t// re-interpreted after raw mode is disabled. This fixes a race condition\n\t\t// where Ctrl+D could close the parent shell over SSH.\n\t\tprocess.stdin.pause();\n\n\t\t// Restore raw mode state\n\t\tif (process.stdin.setRawMode) {\n\t\t\tprocess.stdin.setRawMode(this.wasRaw);\n\t\t}\n\t}\n\n\twrite(data: string): void {\n\t\tprocess.stdout.write(data);\n\t\tif (this.writeLogPath) {\n\t\t\ttry {\n\t\t\t\tfs.appendFileSync(this.writeLogPath, data, { encoding: \"utf8\" });\n\t\t\t} catch {\n\t\t\t\t// Ignore logging errors\n\t\t\t}\n\t\t}\n\t}\n\n\tget columns(): number {\n\t\treturn process.stdout.columns || Number(process.env.COLUMNS) || 80;\n\t}\n\n\tget rows(): number {\n\t\treturn process.stdout.rows || Number(process.env.LINES) || 24;\n\t}\n\n\tmoveBy(lines: number): void {\n\t\tif (lines > 0) {\n\t\t\t// Move down\n\t\t\tprocess.stdout.write(`\\x1b[${lines}B`);\n\t\t} else if (lines < 0) {\n\t\t\t// Move up\n\t\t\tprocess.stdout.write(`\\x1b[${-lines}A`);\n\t\t}\n\t\t// lines === 0: no movement\n\t}\n\n\thideCursor(): void {\n\t\tprocess.stdout.write(\"\\x1b[?25l\");\n\t}\n\n\tshowCursor(): void {\n\t\tprocess.stdout.write(\"\\x1b[?25h\");\n\t}\n\n\tclearLine(): void {\n\t\tprocess.stdout.write(\"\\x1b[K\");\n\t}\n\n\tclearFromCursor(): void {\n\t\tprocess.stdout.write(\"\\x1b[J\");\n\t}\n\n\tclearScreen(): void {\n\t\tprocess.stdout.write(\"\\x1b[2J\\x1b[H\"); // Clear screen and move to home (1,1)\n\t}\n\n\tsetTitle(title: string): void {\n\t\t// OSC 0;title BEL - set terminal window title\n\t\tprocess.stdout.write(`\\x1b]0;${sanitizeTerminalControlPayload(title)}\\x07`);\n\t}\n\n\tsetProgress(active: boolean): void {\n\t\tif (active) {\n\t\t\t// OSC 9;4;3 - indeterminate progress\n\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_ACTIVE_SEQUENCE);\n\t\t\tif (!this.progressInterval) {\n\t\t\t\tthis.progressInterval = setInterval(() => {\n\t\t\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_ACTIVE_SEQUENCE);\n\t\t\t\t}, TERMINAL_PROGRESS_KEEPALIVE_MS);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.clearProgressInterval();\n\t\t\t// OSC 9;4;0 - clear progress\n\t\t\tprocess.stdout.write(TERMINAL_PROGRESS_CLEAR_SEQUENCE);\n\t\t}\n\t}\n\n\tprivate clearProgressInterval(): boolean {\n\t\tif (!this.progressInterval) return false;\n\t\tclearInterval(this.progressInterval);\n\t\tthis.progressInterval = undefined;\n\t\treturn true;\n\t}\n}\n"]}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type { Terminal } from "./terminal.ts";
|
|
2
|
+
import { type Component, TuiBase, type TuiStopOptions, VIEWPORT_TUI, type ViewportTUI } from "./tui.ts";
|
|
3
|
+
export interface TuiAltScreenOptions {
|
|
4
|
+
/** Number of logical lines moved for each mouse-wheel event. */
|
|
5
|
+
wheelScrollLines?: number;
|
|
6
|
+
/** Capture mouse events for viewport scrolling and application-owned text selection. */
|
|
7
|
+
mouse?: boolean;
|
|
8
|
+
/** Open an OSC 8 hyperlink activated with a primary-button click. */
|
|
9
|
+
openUrl?: (url: string) => void;
|
|
10
|
+
/** Handle an unmodified secondary-button press for clipboard paste. Currently enabled on Windows only. */
|
|
11
|
+
onRightClickPaste?: () => void;
|
|
12
|
+
}
|
|
13
|
+
/** Alternate-screen TUI with a scrollable, application-owned viewport. */
|
|
14
|
+
export declare class TuiAltScreen extends TuiBase implements ViewportTUI {
|
|
15
|
+
readonly mode: "fullscreen";
|
|
16
|
+
readonly [VIEWPORT_TUI]: true;
|
|
17
|
+
private previousScreen;
|
|
18
|
+
private lastDocument;
|
|
19
|
+
private previousScreenWidth;
|
|
20
|
+
private previousScreenHeight;
|
|
21
|
+
private layoutRoot;
|
|
22
|
+
private currentLayout;
|
|
23
|
+
private readonly implicitDocument;
|
|
24
|
+
private readonly implicitScrollView;
|
|
25
|
+
private altScreenActive;
|
|
26
|
+
private imageProtocol;
|
|
27
|
+
private savedCapabilities?;
|
|
28
|
+
private readonly uploadedKittyImages;
|
|
29
|
+
private readonly flashes;
|
|
30
|
+
private selectionAnchor?;
|
|
31
|
+
private selectionFocus?;
|
|
32
|
+
private selectionGranularity;
|
|
33
|
+
private selectionInitialRange?;
|
|
34
|
+
private lastClick?;
|
|
35
|
+
private selectionPressActive;
|
|
36
|
+
private selectionDragPointer?;
|
|
37
|
+
private selectionAutoScrollDirection;
|
|
38
|
+
private selectionAutoScrollTimer?;
|
|
39
|
+
private scrollbarDrag?;
|
|
40
|
+
private scrollbarHover?;
|
|
41
|
+
private pressedUrl?;
|
|
42
|
+
private selectionDragged;
|
|
43
|
+
private readonly wheelScrollLines;
|
|
44
|
+
private readonly mouseEnabled;
|
|
45
|
+
private readonly openUrl?;
|
|
46
|
+
private readonly onRightClickPaste?;
|
|
47
|
+
constructor(terminal: Terminal, showHardwareCursor?: boolean, logDirectory?: string, options?: TuiAltScreenOptions);
|
|
48
|
+
get viewportTop(): number;
|
|
49
|
+
get isFollowingOutput(): boolean;
|
|
50
|
+
setLayoutRoot(component: Component | undefined): void;
|
|
51
|
+
render(width: number): string[];
|
|
52
|
+
protected getMountedRoots(): readonly Component[];
|
|
53
|
+
private getPrimaryScrollView;
|
|
54
|
+
private cancelActivePointerInteraction;
|
|
55
|
+
protected onTerminalResize(): void;
|
|
56
|
+
protected onOverlayStackChanged(): void;
|
|
57
|
+
protected beforeTerminalStart(): void;
|
|
58
|
+
protected beforeTerminalStop(): void;
|
|
59
|
+
protected afterTerminalStop(options?: TuiStopOptions): void;
|
|
60
|
+
private deleteKittyImages;
|
|
61
|
+
private prepareKittyScreen;
|
|
62
|
+
protected resetRenderState(): void;
|
|
63
|
+
scrollBy(lines: number): void;
|
|
64
|
+
scrollToTop(): void;
|
|
65
|
+
scrollToBottom(): void;
|
|
66
|
+
private scrollToPrompt;
|
|
67
|
+
/** Show a transient message in the alternate-screen flash stack. */
|
|
68
|
+
flash(message: string, durationMs?: number): void;
|
|
69
|
+
private handleFocusOut;
|
|
70
|
+
private handleWheelInput;
|
|
71
|
+
private handleMouseInput;
|
|
72
|
+
private handleViewportNavigationInput;
|
|
73
|
+
private handleViewportInput;
|
|
74
|
+
private parseWheelEvent;
|
|
75
|
+
private routeWheel;
|
|
76
|
+
private parseSgrMouseEvent;
|
|
77
|
+
private handleRightClickPaste;
|
|
78
|
+
private getScrollbarTargetAt;
|
|
79
|
+
private setScrollbarHover;
|
|
80
|
+
private updateScrollbarHover;
|
|
81
|
+
private stopScrollbarHover;
|
|
82
|
+
private handleScrollbarMouseEvent;
|
|
83
|
+
private stopScrollbarDrag;
|
|
84
|
+
private getScrollSelectionPoint;
|
|
85
|
+
private getSelectionPoint;
|
|
86
|
+
private getSelectionSourceLine;
|
|
87
|
+
private getWordSelection;
|
|
88
|
+
private getLineSelection;
|
|
89
|
+
private updateSelectionFocus;
|
|
90
|
+
private getClickCount;
|
|
91
|
+
private updateSelectionAutoScroll;
|
|
92
|
+
private autoScrollSelection;
|
|
93
|
+
private stopSelectionAutoScroll;
|
|
94
|
+
private activatePressedUrl;
|
|
95
|
+
private completeSelectionPress;
|
|
96
|
+
private updateSelectionDrag;
|
|
97
|
+
private startSelectionPress;
|
|
98
|
+
private handleSelectionMouseEvent;
|
|
99
|
+
private getSelectionBounds;
|
|
100
|
+
private getSelectionColumns;
|
|
101
|
+
private copySelectionToClipboard;
|
|
102
|
+
private applySelectionHighlight;
|
|
103
|
+
private applySelection;
|
|
104
|
+
private isMouseSequence;
|
|
105
|
+
private compositeFlashes;
|
|
106
|
+
private prepareRenderFrame;
|
|
107
|
+
private prepareRedrawPlan;
|
|
108
|
+
private createImageRedrawSequence;
|
|
109
|
+
private appendChangedScreenRows;
|
|
110
|
+
private appendCursorState;
|
|
111
|
+
private createScreenUpdateBuffer;
|
|
112
|
+
protected doRender(): void;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=tui-alt-screen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tui-alt-screen.d.ts","sourceRoot":"","sources":["../src/tui-alt-screen.ts"],"names":[],"mappings":"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","sourcesContent":["import { AltScreenFlashContainer } from \"./components/alt-screen-flash.ts\";\nimport { ScrollView } from \"./components/scroll-view.ts\";\nimport { getKeybindings, type Keybinding } from \"./keybindings.ts\";\nimport { isKeyRelease } from \"./keys.ts\";\nimport {\n\tgetScrollbarGeometry,\n\tgetScrollViewBox,\n\tgetScrollViewsAt,\n\ttype LayoutFrame,\n\trenderLayoutFrame,\n\ttype ScrollbarGeometry,\n} from \"./layout.ts\";\nimport type { Terminal } from \"./terminal.ts\";\nimport {\n\tdeleteAllKittyImages,\n\tdeleteAllKittyPlacements,\n\tdeleteKittyImage,\n\tgetCapabilities,\n\tgetKittyImagePlacement,\n\ttype ImageProtocol,\n\tisImageLine,\n\tsetCapabilities,\n\ttype TerminalCapabilities,\n} from \"./terminal-image.ts\";\nimport {\n\ttype Component,\n\tCURSOR_MARKER,\n\tcompositeTuiLine,\n\ttype RenderedCursorPosition,\n\tTuiBase,\n\ttype TuiInputListenerResult,\n\ttype TuiStopOptions,\n\tVIEWPORT_TUI,\n\ttype ViewportTUI,\n} from \"./tui.ts\";\nimport {\n\textractAnsiCode,\n\tgetGraphemeCellRange,\n\tgetOsc8LinkAtColumn,\n\tgetWordSegmenter,\n\tsliceByColumn,\n\tstripTerminalSequences,\n\tvisibleWidth,\n} from \"./utils.ts\";\n\nconst ENTER_ALT_SCREEN = \"\\x1b[?1049h\";\nconst EXIT_ALT_SCREEN = \"\\x1b[?1049l\";\nconst DISABLE_AUTOWRAP = \"\\x1b[?7l\";\nconst ENABLE_AUTOWRAP = \"\\x1b[?7h\";\nconst ENABLE_BUTTON_MOTION_MOUSE = \"\\x1b[?1000h\\x1b[?1002h\\x1b[?1004h\\x1b[?1006h\";\nconst ENABLE_ALL_MOTION_MOUSE = \"\\x1b[?1000h\\x1b[?1002h\\x1b[?1003h\\x1b[?1004h\\x1b[?1006h\";\nconst DISABLE_MOUSE = \"\\x1b[?1006l\\x1b[?1004l\\x1b[?1003l\\x1b[?1002l\\x1b[?1000l\";\nconst FOCUS_IN = \"\\x1b[I\";\nconst FOCUS_OUT = \"\\x1b[O\";\nconst BEGIN_SYNCHRONIZED_OUTPUT = \"\\x1b[?2026h\";\nconst END_SYNCHRONIZED_OUTPUT = \"\\x1b[?2026l\";\nconst OSC133_ZONE_PREFIX = /^(?:\\x1b\\]133;[ABC](?:\\x07|\\x1b\\\\))+/;\nconst OSC133_PROMPT_START = /^\\x1b\\]133;A(?:\\x07|\\x1b\\\\)/;\nconst PAGE_SCROLL_OVERLAP = 4;\nconst MAX_CACHED_OFFSCREEN_KITTY_IMAGES = 16;\nconst MAX_CACHED_OFFSCREEN_KITTY_TRANSMISSION_BYTES = 32 * 1024 * 1024;\nconst MAX_CACHED_OFFSCREEN_KITTY_DECODED_BYTES = 64 * 1024 * 1024;\nconst DOUBLE_CLICK_INTERVAL_MS = 500;\nconst wordSegmenter = getWordSegmenter();\n\ninterface CachedKittyImage {\n\ttransmissionGeneration: number;\n\ttransmissionBytes: number;\n\testimatedDecodedBytes: number;\n}\n\ninterface PreparedKittyScreen {\n\tlines: string[];\n\tevictedImageDeletion: string;\n}\n\ninterface PreparedAltScreenFrame {\n\tlayout: LayoutFrame;\n\tscreen: string[];\n\tcursorPosition: RenderedCursorPosition | null;\n}\n\ninterface AltScreenRedrawPlan {\n\tfullRedraw: boolean;\n\timagesNeedRedraw: boolean;\n\thadUploadedKittyImages: boolean;\n\tpreparedKittyScreen: PreparedKittyScreen;\n}\n\ninterface SelectionColumns {\n\tstart: number;\n\tend: number;\n}\n\ninterface SelectionPoint {\n\trow: number;\n\tcol: number;\n\tscrollView?: ScrollView;\n\t/** Whether this point lies between terminal cells rather than on a cell. */\n\tboundary?: boolean;\n}\n\ninterface SelectionRange {\n\tstart: SelectionPoint;\n\tend: SelectionPoint;\n}\n\ntype SelectionGranularity = \"character\" | \"word\" | \"line\";\n\ninterface ClickTarget {\n\ttimestamp: number;\n\tcount: number;\n\trow: number;\n\tscrollView?: ScrollView;\n\twordStart: number;\n\twordEnd: number;\n}\n\ninterface SgrMouseEvent {\n\tbutton: number;\n\tx: number;\n\ty: number;\n\trelease: boolean;\n}\n\ninterface WheelEvent {\n\tdirection: -1 | 1;\n\tx: number;\n\ty: number;\n}\n\nfunction createWheelEvent(button: number, x: number, y: number): WheelEvent | undefined {\n\tif ((button & 64) === 0) return undefined;\n\tconst direction = button & 3;\n\tif (direction !== 0 && direction !== 1) return undefined;\n\treturn { direction: direction === 0 ? -1 : 1, x, y };\n}\n\ninterface ScrollbarDrag {\n\tscrollView: ScrollView;\n\tgrabOffset: number;\n}\n\ninterface ViewportNavigationBinding {\n\tkeybinding: Keybinding;\n\tnavigate: () => void;\n}\n\ninterface ScrollbarTarget {\n\tscrollView: ScrollView;\n\tgeometry: ScrollbarGeometry;\n}\n\nexport interface TuiAltScreenOptions {\n\t/** Number of logical lines moved for each mouse-wheel event. */\n\twheelScrollLines?: number;\n\t/** Capture mouse events for viewport scrolling and application-owned text selection. */\n\tmouse?: boolean;\n\t/** Open an OSC 8 hyperlink activated with a primary-button click. */\n\topenUrl?: (url: string) => void;\n\t/** Handle an unmodified secondary-button press for clipboard paste. Currently enabled on Windows only. */\n\tonRightClickPaste?: () => void;\n}\n\n/** Alternate-screen TUI with a scrollable, application-owned viewport. */\nexport class TuiAltScreen extends TuiBase implements ViewportTUI {\n\treadonly mode = \"fullscreen\" as const;\n\treadonly [VIEWPORT_TUI] = true as const;\n\tprivate previousScreen: string[] = [];\n\tprivate lastDocument: string[] = [];\n\tprivate previousScreenWidth = 0;\n\tprivate previousScreenHeight = 0;\n\tprivate layoutRoot: Component | undefined;\n\tprivate currentLayout: LayoutFrame | undefined;\n\tprivate readonly implicitDocument: Component;\n\tprivate readonly implicitScrollView: ScrollView;\n\tprivate altScreenActive = false;\n\tprivate imageProtocol: ImageProtocol = null;\n\tprivate savedCapabilities?: TerminalCapabilities;\n\tprivate readonly uploadedKittyImages = new Map<number, CachedKittyImage>();\n\tprivate readonly flashes: AltScreenFlashContainer;\n\tprivate selectionAnchor?: SelectionPoint;\n\tprivate selectionFocus?: SelectionPoint;\n\tprivate selectionGranularity: SelectionGranularity = \"character\";\n\tprivate selectionInitialRange?: SelectionRange;\n\tprivate lastClick?: ClickTarget;\n\tprivate selectionPressActive = false;\n\tprivate selectionDragPointer?: { x: number; y: number };\n\tprivate selectionAutoScrollDirection: -1 | 0 | 1 = 0;\n\tprivate selectionAutoScrollTimer?: NodeJS.Timeout;\n\tprivate scrollbarDrag?: ScrollbarDrag;\n\tprivate scrollbarHover?: ScrollView;\n\tprivate pressedUrl?: string;\n\tprivate selectionDragged = false;\n\tprivate readonly wheelScrollLines: number;\n\tprivate readonly mouseEnabled: boolean;\n\tprivate readonly openUrl?: (url: string) => void;\n\tprivate readonly onRightClickPaste?: () => void;\n\n\tconstructor(\n\t\tterminal: Terminal,\n\t\tshowHardwareCursor?: boolean,\n\t\tlogDirectory?: string,\n\t\toptions: TuiAltScreenOptions = {},\n\t) {\n\t\tsuper(terminal, showHardwareCursor, logDirectory);\n\t\tthis.implicitDocument = {\n\t\t\trender: (width) => super.render(width),\n\t\t\tinvalidate: () => {\n\t\t\t\tfor (const child of this.children) child.invalidate();\n\t\t\t},\n\t\t};\n\t\tthis.implicitScrollView = new ScrollView(this.implicitDocument, { follow: \"end\", primary: true });\n\t\tthis.wheelScrollLines = Math.max(1, Math.floor(options.wheelScrollLines ?? 1));\n\t\tthis.mouseEnabled = options.mouse ?? true;\n\t\tthis.openUrl = options.openUrl;\n\t\tthis.onRightClickPaste = options.onRightClickPaste;\n\t\tthis.flashes = new AltScreenFlashContainer(() => this.requestRender());\n\t\tthis.addInputListener((data) => this.handleViewportInput(data));\n\t}\n\n\tget viewportTop(): number {\n\t\treturn this.getPrimaryScrollView().scrollTop;\n\t}\n\n\tget isFollowingOutput(): boolean {\n\t\treturn this.getPrimaryScrollView().isFollowingEnd;\n\t}\n\n\tsetLayoutRoot(component: Component | undefined): void {\n\t\tif (this.layoutRoot === component) return;\n\t\tthis.layoutRoot = component;\n\t\tthis.currentLayout = undefined;\n\t\tthis.requestRender();\n\t}\n\n\toverride render(width: number): string[] {\n\t\treturn this.layoutRoot?.render(width) ?? super.render(width);\n\t}\n\n\tprotected override getMountedRoots(): readonly Component[] {\n\t\treturn this.layoutRoot ? [this.layoutRoot] : this.children;\n\t}\n\n\tprivate getPrimaryScrollView(): ScrollView {\n\t\treturn this.currentLayout?.primaryScrollView ?? this.implicitScrollView;\n\t}\n\n\tprivate cancelActivePointerInteraction(): void {\n\t\tconst hadActiveSelection = this.selectionPressActive;\n\t\tthis.stopSelectionAutoScroll();\n\t\tthis.stopScrollbarHover();\n\t\tthis.stopScrollbarDrag();\n\t\tthis.selectionPressActive = false;\n\t\tthis.pressedUrl = undefined;\n\t\tthis.selectionDragged = false;\n\t\tthis.lastClick = undefined;\n\t\tif (!hadActiveSelection) return;\n\t\tthis.selectionAnchor = undefined;\n\t\tthis.selectionFocus = undefined;\n\t\tthis.selectionGranularity = \"character\";\n\t\tthis.selectionInitialRange = undefined;\n\t}\n\n\tprotected override onTerminalResize(): void {\n\t\tthis.cancelActivePointerInteraction();\n\t}\n\n\tprotected override onOverlayStackChanged(): void {\n\t\tif (this.hasCapturingOverlay()) this.cancelActivePointerInteraction();\n\t}\n\n\tprotected override beforeTerminalStart(): void {\n\t\tthis.stopSelectionAutoScroll();\n\t\tthis.stopScrollbarHover();\n\t\tthis.stopScrollbarDrag();\n\t\tthis.flashes.dispose();\n\t\tthis.altScreenActive = true;\n\t\tconst capabilities = getCapabilities();\n\t\tthis.imageProtocol = capabilities.images;\n\t\tthis.uploadedKittyImages.clear();\n\t\tif (capabilities.images === \"iterm2\") {\n\t\t\tthis.savedCapabilities = capabilities;\n\t\t\tsetCapabilities({ ...capabilities, images: null });\n\t\t\tthis.invalidate();\n\t\t}\n\t\tthis.lastDocument = [];\n\t\tthis.selectionAnchor = undefined;\n\t\tthis.selectionFocus = undefined;\n\t\tthis.selectionGranularity = \"character\";\n\t\tthis.selectionInitialRange = undefined;\n\t\tthis.lastClick = undefined;\n\t\tthis.pressedUrl = undefined;\n\t\tthis.selectionDragged = false;\n\t\tthis.selectionPressActive = false;\n\t\tthis.resetRenderState();\n\t\tconst term = process.env.TERM?.toLowerCase() ?? \"\";\n\t\tconst mouseSequence =\n\t\t\tprocess.env.TMUX !== undefined ||\n\t\t\tprocess.env.ZELLIJ !== undefined ||\n\t\t\tprocess.env.STY !== undefined ||\n\t\t\tterm.startsWith(\"tmux\") ||\n\t\t\tterm.startsWith(\"screen\")\n\t\t\t\t? ENABLE_BUTTON_MOTION_MOUSE\n\t\t\t\t: ENABLE_ALL_MOTION_MOUSE;\n\t\tthis.terminal.write(\n\t\t\t`${ENTER_ALT_SCREEN}${DISABLE_AUTOWRAP}${this.mouseEnabled ? mouseSequence : \"\"}\\x1b[2J\\x1b[H\\x1b[?25l`,\n\t\t);\n\t}\n\n\tprotected override beforeTerminalStop(): void {\n\t\tthis.stopSelectionAutoScroll();\n\t\tthis.stopScrollbarHover();\n\t\tthis.stopScrollbarDrag();\n\t\tthis.flashes.dispose();\n\t\tthis.selectionPressActive = false;\n\t\tif (!this.altScreenActive) return;\n\t\tthis.terminal.write(\n\t\t\t`${BEGIN_SYNCHRONIZED_OUTPUT}${this.deleteKittyImages()}${this.mouseEnabled ? DISABLE_MOUSE : \"\"}${ENABLE_AUTOWRAP}${END_SYNCHRONIZED_OUTPUT}`,\n\t\t);\n\t\tthis.uploadedKittyImages.clear();\n\t}\n\n\tprotected override afterTerminalStop(options?: TuiStopOptions): void {\n\t\tif (!this.altScreenActive) return;\n\t\tthis.altScreenActive = false;\n\t\ttry {\n\t\t\tlet buffer = `${BEGIN_SYNCHRONIZED_OUTPUT}${EXIT_ALT_SCREEN}`;\n\t\t\tif (!options?.preserveScreen) {\n\t\t\t\tconst width = Math.max(1, this.terminal.columns);\n\t\t\t\tconst documentLines = this.render(width).map((line) => line.replace(OSC133_ZONE_PREFIX, \"\"));\n\t\t\t\tthis.lastDocument = this.applyLineResets(\n\t\t\t\t\tdocumentLines.map((line) => line.replaceAll(CURSOR_MARKER, \"\")),\n\t\t\t\t).map((line) =>\n\t\t\t\t\tisImageLine(line) || visibleWidth(line) <= width ? line : sliceByColumn(line, 0, width, true),\n\t\t\t\t);\n\t\t\t\tbuffer += DISABLE_AUTOWRAP;\n\t\t\t\tfor (let row = 0; row < this.lastDocument.length; row++) {\n\t\t\t\t\tif (row > 0) buffer += \"\\r\\n\";\n\t\t\t\t\tbuffer += `\\r\\x1b[2K${this.lastDocument[row] ?? \"\"}`;\n\t\t\t\t}\n\t\t\t\tbuffer += \"\\x1b[0m\";\n\t\t\t}\n\t\t\tbuffer += `${ENABLE_AUTOWRAP}${options?.preserveScreen ? \"\" : \"\\r\\n\"}\\x1b[?25h${END_SYNCHRONIZED_OUTPUT}`;\n\t\t\tthis.terminal.write(buffer);\n\t\t} finally {\n\t\t\tif (this.savedCapabilities) {\n\t\t\t\tsetCapabilities(this.savedCapabilities);\n\t\t\t\tthis.savedCapabilities = undefined;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate deleteKittyImages(): string {\n\t\treturn this.imageProtocol === \"kitty\" ? deleteAllKittyImages() : \"\";\n\t}\n\n\tprivate prepareKittyScreen(screen: string[]): PreparedKittyScreen {\n\t\tconst visibleImageIds = new Set<number>();\n\t\tconst lines = screen.map((line) => {\n\t\t\tconst placement = getKittyImagePlacement(line);\n\t\t\tif (!placement) return line;\n\t\t\tvisibleImageIds.add(placement.imageId);\n\n\t\t\tconst cachedImage = this.uploadedKittyImages.get(placement.imageId);\n\t\t\tconst nextCachedImage = {\n\t\t\t\ttransmissionGeneration: placement.transmissionGeneration,\n\t\t\t\ttransmissionBytes: placement.transmissionBytes,\n\t\t\t\testimatedDecodedBytes: placement.estimatedDecodedBytes,\n\t\t\t};\n\t\t\tif (cachedImage) this.uploadedKittyImages.delete(placement.imageId);\n\t\t\tthis.uploadedKittyImages.set(placement.imageId, nextCachedImage);\n\n\t\t\treturn cachedImage?.transmissionGeneration === placement.transmissionGeneration\n\t\t\t\t? placement.replacementLine\n\t\t\t\t: line;\n\t\t});\n\n\t\tlet cachedOffscreenImageCount = 0;\n\t\tlet cachedOffscreenTransmissionBytes = 0;\n\t\tlet cachedOffscreenDecodedBytes = 0;\n\t\tfor (const [imageId, cachedImage] of this.uploadedKittyImages) {\n\t\t\tif (visibleImageIds.has(imageId)) continue;\n\t\t\tcachedOffscreenImageCount += 1;\n\t\t\tcachedOffscreenTransmissionBytes += cachedImage.transmissionBytes;\n\t\t\tcachedOffscreenDecodedBytes += cachedImage.estimatedDecodedBytes;\n\t\t}\n\n\t\tlet evictedImageDeletion = \"\";\n\t\tfor (const [imageId, cachedImage] of this.uploadedKittyImages) {\n\t\t\tif (\n\t\t\t\tcachedOffscreenImageCount <= MAX_CACHED_OFFSCREEN_KITTY_IMAGES &&\n\t\t\t\tcachedOffscreenTransmissionBytes <= MAX_CACHED_OFFSCREEN_KITTY_TRANSMISSION_BYTES &&\n\t\t\t\tcachedOffscreenDecodedBytes <= MAX_CACHED_OFFSCREEN_KITTY_DECODED_BYTES\n\t\t\t) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (visibleImageIds.has(imageId)) continue;\n\t\t\tevictedImageDeletion += deleteKittyImage(imageId);\n\t\t\tthis.uploadedKittyImages.delete(imageId);\n\t\t\tcachedOffscreenImageCount -= 1;\n\t\t\tcachedOffscreenTransmissionBytes -= cachedImage.transmissionBytes;\n\t\t\tcachedOffscreenDecodedBytes -= cachedImage.estimatedDecodedBytes;\n\t\t}\n\t\treturn { lines, evictedImageDeletion };\n\t}\n\n\tprotected override resetRenderState(): void {\n\t\tthis.previousScreen = [];\n\t\tthis.previousScreenWidth = 0;\n\t\tthis.previousScreenHeight = 0;\n\t\tthis.currentLayout = undefined;\n\t}\n\n\tscrollBy(lines: number): void {\n\t\tthis.getPrimaryScrollView().scrollBy(lines);\n\t\tthis.requestRender();\n\t}\n\n\tscrollToTop(): void {\n\t\tthis.getPrimaryScrollView().scrollToStart();\n\t\tthis.requestRender();\n\t}\n\n\tscrollToBottom(): void {\n\t\tthis.getPrimaryScrollView().scrollToEnd();\n\t\tthis.requestRender();\n\t}\n\n\tprivate scrollToPrompt(direction: -1 | 1): void {\n\t\tif (!this.currentLayout) return;\n\t\tconst scrollView = this.getPrimaryScrollView();\n\t\tconst lines = getScrollViewBox(this.currentLayout, scrollView)?.scrollContentLines;\n\t\tif (!lines) return;\n\n\t\tfor (let row = scrollView.scrollTop + direction; row >= 0 && row < lines.length; row += direction) {\n\t\t\tif (!OSC133_PROMPT_START.test(lines[row] ?? \"\")) continue;\n\t\t\tscrollView.scrollTo(row);\n\t\t\tthis.requestRender();\n\t\t\treturn;\n\t\t}\n\t}\n\n\t/** Show a transient message in the alternate-screen flash stack. */\n\tflash(message: string, durationMs?: number): void {\n\t\tthis.flashes.flash(message, durationMs);\n\t}\n\n\tprivate handleFocusOut(): TuiInputListenerResult {\n\t\tif (!this.mouseEnabled) return undefined;\n\t\tthis.stopSelectionAutoScroll();\n\t\tthis.stopScrollbarHover();\n\t\tthis.stopScrollbarDrag();\n\t\tconst hadActiveSelection = this.selectionPressActive;\n\t\tthis.selectionPressActive = false;\n\t\tthis.pressedUrl = undefined;\n\t\tthis.selectionDragged = false;\n\t\tif (hadActiveSelection) {\n\t\t\tthis.selectionAnchor = undefined;\n\t\t\tthis.selectionFocus = undefined;\n\t\t\tthis.selectionGranularity = \"character\";\n\t\t\tthis.selectionInitialRange = undefined;\n\t\t\tthis.requestRender();\n\t\t}\n\t\tthis.lastClick = undefined;\n\t\treturn { consume: true };\n\t}\n\n\tprivate handleWheelInput(event: WheelEvent, overlayActive: boolean): TuiInputListenerResult {\n\t\tif (!this.mouseEnabled) return undefined;\n\t\tif (!overlayActive) this.routeWheel(event);\n\t\treturn { consume: true };\n\t}\n\n\tprivate handleMouseInput(event: SgrMouseEvent, overlayActive: boolean): TuiInputListenerResult {\n\t\tif (!this.mouseEnabled) return undefined;\n\t\tif (this.handleRightClickPaste(event)) return { consume: true };\n\t\tif (overlayActive) return { consume: true };\n\t\tconst handled = this.handleScrollbarMouseEvent(event);\n\t\tif (!this.scrollbarDrag) this.updateScrollbarHover(event.x, event.y);\n\t\tif (!handled) this.handleSelectionMouseEvent(event);\n\t\treturn { consume: true };\n\t}\n\n\tprivate handleViewportNavigationInput(data: string): TuiInputListenerResult {\n\t\tconst keybindings = getKeybindings();\n\t\tconst bindings: ViewportNavigationBinding[] = [\n\t\t\t{\n\t\t\t\tkeybinding: \"tui.altScreen.pageUp\",\n\t\t\t\tnavigate: () =>\n\t\t\t\t\tthis.scrollBy(-Math.max(1, this.getPrimaryScrollView().viewportHeight - PAGE_SCROLL_OVERLAP)),\n\t\t\t},\n\t\t\t{\n\t\t\t\tkeybinding: \"tui.altScreen.pageDown\",\n\t\t\t\tnavigate: () =>\n\t\t\t\t\tthis.scrollBy(Math.max(1, this.getPrimaryScrollView().viewportHeight - PAGE_SCROLL_OVERLAP)),\n\t\t\t},\n\t\t\t{\n\t\t\t\tkeybinding: \"tui.altScreen.halfPageUp\",\n\t\t\t\tnavigate: () => this.scrollBy(-Math.max(1, Math.floor(this.getPrimaryScrollView().viewportHeight / 2))),\n\t\t\t},\n\t\t\t{\n\t\t\t\tkeybinding: \"tui.altScreen.halfPageDown\",\n\t\t\t\tnavigate: () => this.scrollBy(Math.max(1, Math.floor(this.getPrimaryScrollView().viewportHeight / 2))),\n\t\t\t},\n\t\t\t{ keybinding: \"tui.altScreen.previousPrompt\", navigate: () => this.scrollToPrompt(-1) },\n\t\t\t{ keybinding: \"tui.altScreen.nextPrompt\", navigate: () => this.scrollToPrompt(1) },\n\t\t\t{ keybinding: \"tui.altScreen.top\", navigate: () => this.scrollToTop() },\n\t\t\t{ keybinding: \"tui.altScreen.bottom\", navigate: () => this.scrollToBottom() },\n\t\t];\n\t\tconst binding = bindings.find(({ keybinding }) => keybindings.matches(data, keybinding));\n\t\tif (!binding) return undefined;\n\t\tif (!isKeyRelease(data)) binding.navigate();\n\t\treturn { consume: true };\n\t}\n\n\tprivate handleViewportInput(data: string): TuiInputListenerResult {\n\t\tif (data === FOCUS_OUT) return this.handleFocusOut();\n\t\tif (data === FOCUS_IN) return this.mouseEnabled ? { consume: true } : undefined;\n\n\t\tconst overlayActive = this.hasCapturingOverlay();\n\t\tconst wheelEvent = this.parseWheelEvent(data);\n\t\tif (wheelEvent) return this.handleWheelInput(wheelEvent, overlayActive);\n\n\t\tconst mouseEvent = this.parseSgrMouseEvent(data);\n\t\tif (mouseEvent) return this.handleMouseInput(mouseEvent, overlayActive);\n\n\t\tif (this.isMouseSequence(data)) return this.mouseEnabled ? { consume: true } : undefined;\n\t\treturn overlayActive ? undefined : this.handleViewportNavigationInput(data);\n\t}\n\n\tprivate parseWheelEvent(data: string): WheelEvent | undefined {\n\t\tconst sgr = /^\\x1b\\[<(\\d+);(\\d+);(\\d+)[Mm]$/.exec(data);\n\t\tif (sgr) {\n\t\t\treturn createWheelEvent(\n\t\t\t\tNumber.parseInt(sgr[1], 10),\n\t\t\t\tNumber.parseInt(sgr[2], 10) - 1,\n\t\t\t\tNumber.parseInt(sgr[3], 10) - 1,\n\t\t\t);\n\t\t}\n\t\tif (data.length !== 6 || !data.startsWith(\"\\x1b[M\")) return undefined;\n\t\treturn createWheelEvent(data.charCodeAt(3) - 32, data.charCodeAt(4) - 33, data.charCodeAt(5) - 33);\n\t}\n\tprivate routeWheel(event: WheelEvent): void {\n\t\tlet remaining = event.direction * this.wheelScrollLines;\n\t\tconst seen = new Set<ScrollView>();\n\t\tlet contained = false;\n\t\tfor (const scrollView of this.currentLayout ? getScrollViewsAt(this.currentLayout, event.x, event.y) : []) {\n\t\t\tseen.add(scrollView);\n\t\t\tremaining = scrollView.scrollBy(remaining);\n\t\t\tif (remaining === 0) break;\n\t\t\tif (scrollView.overscroll === \"contain\") {\n\t\t\t\tcontained = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tconst primary = this.getPrimaryScrollView();\n\t\tif (remaining !== 0 && !contained && !seen.has(primary)) primary.scrollBy(remaining);\n\t\tthis.updateScrollbarHover(event.x, event.y);\n\t\tthis.requestRender();\n\t}\n\n\tprivate parseSgrMouseEvent(data: string): SgrMouseEvent | undefined {\n\t\tconst match = /^\\x1b\\[<(\\d+);(\\d+);(\\d+)([Mm])$/.exec(data);\n\t\tif (!match) return undefined;\n\t\treturn {\n\t\t\tbutton: Number.parseInt(match[1], 10),\n\t\t\tx: Number.parseInt(match[2], 10) - 1,\n\t\t\ty: Number.parseInt(match[3], 10) - 1,\n\t\t\trelease: match[4] === \"m\",\n\t\t};\n\t}\n\n\tprivate handleRightClickPaste(event: SgrMouseEvent): boolean {\n\t\tif (!this.onRightClickPaste || process.platform !== \"win32\" || event.release || event.button !== 2) {\n\t\t\treturn false;\n\t\t}\n\t\ttry {\n\t\t\tthis.onRightClickPaste();\n\t\t} catch {\n\t\t\t// Clipboard paste is best-effort.\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate getScrollbarTargetAt(x: number, y: number): ScrollbarTarget | undefined {\n\t\tif (this.hasCapturingOverlay() || !this.currentLayout) return undefined;\n\t\tfor (const scrollView of getScrollViewsAt(this.currentLayout, x, y)) {\n\t\t\tconst box = getScrollViewBox(this.currentLayout, scrollView);\n\t\t\tconst geometry = box ? getScrollbarGeometry(box) : undefined;\n\t\t\tif (\n\t\t\t\tgeometry &&\n\t\t\t\tx === geometry.column &&\n\t\t\t\ty >= geometry.thumbTop &&\n\t\t\t\ty < geometry.thumbTop + geometry.thumbHeight\n\t\t\t) {\n\t\t\t\treturn { scrollView, geometry };\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate setScrollbarHover(scrollView: ScrollView | undefined): void {\n\t\tif (scrollView === this.scrollbarHover) return;\n\t\tthis.scrollbarHover?.setScrollbarActive(false);\n\t\tthis.scrollbarHover = scrollView;\n\t\tthis.scrollbarHover?.setScrollbarActive(true);\n\t}\n\n\tprivate updateScrollbarHover(x: number, y: number): void {\n\t\tthis.setScrollbarHover(this.getScrollbarTargetAt(x, y)?.scrollView);\n\t}\n\n\tprivate stopScrollbarHover(): void {\n\t\tthis.setScrollbarHover(undefined);\n\t}\n\n\tprivate handleScrollbarMouseEvent(event: SgrMouseEvent): boolean {\n\t\tif (this.scrollbarDrag) {\n\t\t\tif (event.release) {\n\t\t\t\tthis.stopScrollbarDrag();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tconst box = this.currentLayout\n\t\t\t\t? getScrollViewBox(this.currentLayout, this.scrollbarDrag.scrollView)\n\t\t\t\t: undefined;\n\t\t\tconst geometry = box ? getScrollbarGeometry(box) : undefined;\n\t\t\tif (geometry) {\n\t\t\t\tconst maxThumbOffset = geometry.trackHeight - geometry.thumbHeight;\n\t\t\t\tconst thumbOffset = Math.max(\n\t\t\t\t\t0,\n\t\t\t\t\tMath.min(maxThumbOffset, event.y - geometry.trackTop - this.scrollbarDrag.grabOffset),\n\t\t\t\t);\n\t\t\t\tconst scrollTop =\n\t\t\t\t\tmaxThumbOffset === 0 ? 0 : Math.round((thumbOffset / maxThumbOffset) * geometry.maxScrollTop);\n\t\t\t\tthis.scrollbarDrag.scrollView.scrollTo(scrollTop);\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tif (event.release || (event.button & 32) !== 0 || (event.button & 3) !== 0) return false;\n\t\tconst target = this.getScrollbarTargetAt(event.x, event.y);\n\t\tif (!target) return false;\n\t\tthis.stopSelectionAutoScroll();\n\t\tthis.selectionPressActive = false;\n\t\tthis.selectionAnchor = undefined;\n\t\tthis.selectionFocus = undefined;\n\t\tthis.selectionGranularity = \"character\";\n\t\tthis.selectionInitialRange = undefined;\n\t\tthis.lastClick = undefined;\n\t\tthis.pressedUrl = undefined;\n\t\tthis.selectionDragged = false;\n\t\tthis.setScrollbarHover(target.scrollView);\n\t\tthis.scrollbarDrag = {\n\t\t\tscrollView: target.scrollView,\n\t\t\tgrabOffset: event.y - target.geometry.thumbTop,\n\t\t};\n\t\treturn true;\n\t}\n\n\tprivate stopScrollbarDrag(): void {\n\t\tthis.scrollbarDrag = undefined;\n\t}\n\n\tprivate getScrollSelectionPoint(scrollView: ScrollView, x: number, y: number): SelectionPoint | undefined {\n\t\tif (!this.currentLayout) return undefined;\n\t\tconst box = getScrollViewBox(this.currentLayout, scrollView);\n\t\tif (!box || box.rect.height <= 0 || box.clip.height <= 0) return undefined;\n\t\tconst visibleTop = Math.max(0, box.rect.y, box.clip.y);\n\t\tconst visibleBottom = Math.min(\n\t\t\tthis.terminal.rows - 1,\n\t\t\tbox.rect.y + box.rect.height - 1,\n\t\t\tbox.clip.y + box.clip.height - 1,\n\t\t);\n\t\tif (visibleBottom < visibleTop) return undefined;\n\t\tconst pointerRow = Math.max(visibleTop, Math.min(visibleBottom, y));\n\t\tconst maxContentRow = Math.max(0, (box.scrollContentLines?.length ?? 1) - 1);\n\t\treturn {\n\t\t\trow: Math.max(0, Math.min(maxContentRow, scrollView.scrollTop + pointerRow - box.rect.y)),\n\t\t\tcol: Math.max(0, Math.min(box.rect.width - 1, x - box.rect.x)),\n\t\t\tscrollView,\n\t\t};\n\t}\n\n\tprivate getSelectionPoint(event: SgrMouseEvent, scrollView?: ScrollView): SelectionPoint {\n\t\tif (scrollView) {\n\t\t\tconst point = this.getScrollSelectionPoint(scrollView, event.x, event.y);\n\t\t\tif (point) return point;\n\t\t}\n\t\treturn {\n\t\t\trow: Math.max(0, Math.min(this.terminal.rows - 1, event.y)),\n\t\t\tcol: Math.max(0, Math.min(this.terminal.columns - 1, event.x)),\n\t\t};\n\t}\n\n\tprivate getSelectionSourceLine(point: SelectionPoint): string {\n\t\tif (point.scrollView && this.currentLayout) {\n\t\t\tconst lines = getScrollViewBox(this.currentLayout, point.scrollView)?.scrollContentLines;\n\t\t\tif (lines) return lines[point.row] ?? \"\";\n\t\t}\n\t\treturn this.previousScreen[point.row] ?? \"\";\n\t}\n\n\tprivate getWordSelection(point: SelectionPoint): SelectionRange | undefined {\n\t\tconst line = stripTerminalSequences(this.getSelectionSourceLine(point));\n\t\tlet start = 0;\n\t\tfor (const segment of wordSegmenter.segment(line)) {\n\t\t\tconst end = start + visibleWidth(segment.segment);\n\t\t\tif (point.col >= start && point.col < end) {\n\t\t\t\treturn {\n\t\t\t\t\tstart: { ...point, col: start },\n\t\t\t\t\tend: { ...point, col: end, boundary: true },\n\t\t\t\t};\n\t\t\t}\n\t\t\tstart = end;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate getLineSelection(point: SelectionPoint): SelectionRange {\n\t\treturn {\n\t\t\tstart: { ...point, col: 0 },\n\t\t\tend: { ...point, col: visibleWidth(this.getSelectionSourceLine(point)), boundary: true },\n\t\t};\n\t}\n\n\tprivate updateSelectionFocus(point: SelectionPoint): void {\n\t\tif (this.selectionGranularity === \"character\" || !this.selectionInitialRange) {\n\t\t\tthis.selectionFocus = point;\n\t\t\treturn;\n\t\t}\n\t\tconst range = this.selectionGranularity === \"word\" ? this.getWordSelection(point) : this.getLineSelection(point);\n\t\tif (!range) return;\n\t\tconst initial = this.selectionInitialRange;\n\t\tconst targetBeforeInitial =\n\t\t\trange.start.row < initial.start.row ||\n\t\t\t(range.start.row === initial.start.row && range.start.col < initial.start.col);\n\t\tif (targetBeforeInitial) {\n\t\t\tthis.selectionAnchor = initial.end;\n\t\t\tthis.selectionFocus = range.start;\n\t\t} else {\n\t\t\tthis.selectionAnchor = initial.start;\n\t\t\tthis.selectionFocus = range.end;\n\t\t}\n\t}\n\n\tprivate getClickCount(point: SelectionPoint, word: SelectionRange | undefined): number {\n\t\tconst now = Date.now();\n\t\tconst previous = this.lastClick;\n\t\tconst count =\n\t\t\tword &&\n\t\t\tprevious &&\n\t\t\tnow - previous.timestamp <= DOUBLE_CLICK_INTERVAL_MS &&\n\t\t\tprevious.row === point.row &&\n\t\t\tprevious.scrollView === point.scrollView &&\n\t\t\tprevious.wordStart === word.start.col &&\n\t\t\tprevious.wordEnd === word.end.col\n\t\t\t\t? (previous.count % 3) + 1\n\t\t\t\t: 1;\n\t\tthis.lastClick = word\n\t\t\t? {\n\t\t\t\t\ttimestamp: now,\n\t\t\t\t\tcount,\n\t\t\t\t\trow: point.row,\n\t\t\t\t\tscrollView: point.scrollView,\n\t\t\t\t\twordStart: word.start.col,\n\t\t\t\t\twordEnd: word.end.col,\n\t\t\t\t}\n\t\t\t: undefined;\n\t\treturn count;\n\t}\n\n\tprivate updateSelectionAutoScroll(event: SgrMouseEvent): void {\n\t\tconst scrollView = this.selectionAnchor?.scrollView;\n\t\tif (!scrollView || !this.currentLayout) {\n\t\t\tthis.stopSelectionAutoScroll();\n\t\t\treturn;\n\t\t}\n\t\tconst box = getScrollViewBox(this.currentLayout, scrollView);\n\t\tif (!box || box.rect.height <= 0 || box.clip.height <= 0) {\n\t\t\tthis.stopSelectionAutoScroll();\n\t\t\treturn;\n\t\t}\n\t\tconst visibleTop = Math.max(0, box.rect.y, box.clip.y);\n\t\tconst visibleBottom = Math.min(\n\t\t\tthis.terminal.rows - 1,\n\t\t\tbox.rect.y + box.rect.height - 1,\n\t\t\tbox.clip.y + box.clip.height - 1,\n\t\t);\n\t\tthis.selectionDragPointer = { x: event.x, y: event.y };\n\t\tthis.selectionAutoScrollDirection = event.y <= visibleTop ? -1 : event.y >= visibleBottom ? 1 : 0;\n\t\tif (this.selectionAutoScrollDirection === 0) {\n\t\t\tthis.stopSelectionAutoScroll();\n\t\t\treturn;\n\t\t}\n\t\tif (this.selectionAutoScrollTimer) return;\n\t\tthis.selectionAutoScrollTimer = setInterval(() => this.autoScrollSelection(), 50);\n\t\tthis.selectionAutoScrollTimer.unref();\n\t}\n\n\tprivate autoScrollSelection(): void {\n\t\tconst scrollView = this.selectionAnchor?.scrollView;\n\t\tconst pointer = this.selectionDragPointer;\n\t\tconst direction = this.selectionAutoScrollDirection;\n\t\tif (!scrollView || !pointer || direction === 0) {\n\t\t\tthis.stopSelectionAutoScroll();\n\t\t\treturn;\n\t\t}\n\t\tconst remaining = scrollView.scrollBy(direction);\n\t\tif (remaining === direction) {\n\t\t\tthis.stopSelectionAutoScroll();\n\t\t\treturn;\n\t\t}\n\t\tconst point = this.getScrollSelectionPoint(scrollView, pointer.x, pointer.y);\n\t\tif (point) this.updateSelectionFocus(point);\n\t\tthis.requestRender();\n\t}\n\n\tprivate stopSelectionAutoScroll(): void {\n\t\tif (this.selectionAutoScrollTimer) {\n\t\t\tclearInterval(this.selectionAutoScrollTimer);\n\t\t\tthis.selectionAutoScrollTimer = undefined;\n\t\t}\n\t\tthis.selectionAutoScrollDirection = 0;\n\t\tthis.selectionDragPointer = undefined;\n\t}\n\n\tprivate activatePressedUrl(point: SelectionPoint): boolean {\n\t\tconst anchor = this.selectionAnchor;\n\t\tconst clickedUrl =\n\t\t\tanchor &&\n\t\t\t!this.selectionDragged &&\n\t\t\tanchor.scrollView === point.scrollView &&\n\t\t\tanchor.row === point.row &&\n\t\t\tanchor.col === point.col\n\t\t\t\t? this.pressedUrl\n\t\t\t\t: undefined;\n\t\tthis.pressedUrl = undefined;\n\t\tif (!clickedUrl || !this.openUrl) return false;\n\t\tthis.selectionAnchor = undefined;\n\t\tthis.selectionFocus = undefined;\n\t\ttry {\n\t\t\tthis.openUrl(clickedUrl);\n\t\t} catch {\n\t\t\t// URL activation is best-effort.\n\t\t}\n\t\tthis.requestRender();\n\t\treturn true;\n\t}\n\n\tprivate completeSelectionPress(point: SelectionPoint): void {\n\t\tif (!this.selectionPressActive) return;\n\t\tthis.selectionPressActive = false;\n\t\tthis.stopSelectionAutoScroll();\n\t\tif (!this.selectionAnchor) return;\n\t\tthis.updateSelectionFocus(point);\n\t\tif (this.activatePressedUrl(point)) return;\n\t\tthis.copySelectionToClipboard();\n\t\tthis.requestRender();\n\t}\n\n\tprivate updateSelectionDrag(event: SgrMouseEvent, point: SelectionPoint): void {\n\t\tif (!this.selectionPressActive || !this.selectionAnchor) return;\n\t\tthis.selectionDragged = true;\n\t\tthis.lastClick = undefined;\n\t\tthis.pressedUrl = undefined;\n\t\tthis.updateSelectionFocus(point);\n\t\tthis.updateSelectionAutoScroll(event);\n\t\tthis.requestRender();\n\t}\n\n\tprivate startSelectionPress(event: SgrMouseEvent): void {\n\t\tthis.stopSelectionAutoScroll();\n\t\tthis.selectionPressActive = true;\n\t\tconst scrollView =\n\t\t\t!this.hasCapturingOverlay() && this.currentLayout\n\t\t\t\t? getScrollViewsAt(this.currentLayout, event.x, event.y)[0]\n\t\t\t\t: undefined;\n\t\tconst anchor = this.getSelectionPoint(event, scrollView);\n\t\tconst word = this.getWordSelection(anchor);\n\t\tconst clickCount = this.getClickCount(anchor, word);\n\t\tconst range = clickCount === 2 ? word : clickCount === 3 ? this.getLineSelection(anchor) : undefined;\n\t\tthis.selectionGranularity = range ? (clickCount === 2 ? \"word\" : \"line\") : \"character\";\n\t\tthis.selectionInitialRange = range;\n\t\tthis.selectionAnchor = range?.start ?? anchor;\n\t\tthis.selectionFocus = range?.end ?? anchor;\n\t\tthis.selectionDragged = false;\n\t\tthis.pressedUrl = range\n\t\t\t? undefined\n\t\t\t: getOsc8LinkAtColumn(\n\t\t\t\t\tthis.previousScreen[Math.max(0, Math.min(this.terminal.rows - 1, event.y))] ?? \"\",\n\t\t\t\t\tMath.max(0, Math.min(this.terminal.columns - 1, event.x)),\n\t\t\t\t);\n\t\tthis.requestRender();\n\t}\n\n\tprivate handleSelectionMouseEvent(event: SgrMouseEvent): void {\n\t\tif ((event.button & 3) !== 0) return;\n\t\tconst point = this.getSelectionPoint(event, this.selectionAnchor?.scrollView);\n\t\tif (event.release) {\n\t\t\tthis.completeSelectionPress(point);\n\t\t\treturn;\n\t\t}\n\t\tif ((event.button & 32) !== 0) {\n\t\t\tthis.updateSelectionDrag(event, point);\n\t\t\treturn;\n\t\t}\n\t\tthis.startSelectionPress(event);\n\t}\n\n\tprivate getSelectionBounds(): SelectionRange | undefined {\n\t\tif (!this.selectionAnchor || !this.selectionFocus) return undefined;\n\t\tif (this.selectionAnchor.scrollView !== this.selectionFocus.scrollView) return undefined;\n\t\tconst anchorBeforeFocus =\n\t\t\tthis.selectionAnchor.row < this.selectionFocus.row ||\n\t\t\t(this.selectionAnchor.row === this.selectionFocus.row && this.selectionAnchor.col < this.selectionFocus.col);\n\t\tif (\n\t\t\tthis.selectionAnchor.row === this.selectionFocus.row &&\n\t\t\tthis.selectionAnchor.col === this.selectionFocus.col\n\t\t) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn anchorBeforeFocus\n\t\t\t? { start: this.selectionAnchor, end: this.selectionFocus }\n\t\t\t: { start: this.selectionFocus, end: this.selectionAnchor };\n\t}\n\n\tprivate getSelectionColumns(\n\t\tline: string,\n\t\trow: number,\n\t\tselection: SelectionRange,\n\t\tminColumn = 0,\n\t\tmaxColumn = visibleWidth(line),\n\t): SelectionColumns {\n\t\tconst lineWidth = visibleWidth(line);\n\t\tlet start = Math.max(0, minColumn);\n\t\tlet end = Math.min(lineWidth, maxColumn);\n\t\tif (row === selection.start.row) {\n\t\t\tstart = getGraphemeCellRange(line, selection.start.col)?.start ?? Math.min(selection.start.col, lineWidth);\n\t\t}\n\t\tif (row === selection.end.row) {\n\t\t\tend = selection.end.boundary\n\t\t\t\t? Math.min(selection.end.col, lineWidth)\n\t\t\t\t: (getGraphemeCellRange(line, selection.end.col)?.end ?? Math.min(selection.end.col + 1, lineWidth));\n\t\t}\n\t\treturn { start: Math.max(minColumn, start), end: Math.min(maxColumn, end) };\n\t}\n\n\tprivate copySelectionToClipboard(): void {\n\t\tconst selection = this.getSelectionBounds();\n\t\tif (!selection) return;\n\t\tlet sourceLines: readonly string[] = this.previousScreen;\n\t\tif (selection.start.scrollView) {\n\t\t\tif (!this.currentLayout) return;\n\t\t\tconst box = getScrollViewBox(this.currentLayout, selection.start.scrollView);\n\t\t\tif (!box?.scrollContentLines) return;\n\t\t\tsourceLines = box.scrollContentLines;\n\t\t}\n\t\tconst lines: string[] = [];\n\t\tfor (let row = selection.start.row; row <= selection.end.row; row++) {\n\t\t\tconst line = sourceLines[row] ?? \"\";\n\t\t\tconst columns = this.getSelectionColumns(line, row, selection);\n\t\t\tlines.push(\n\t\t\t\tstripTerminalSequences(\n\t\t\t\t\tsliceByColumn(line, columns.start, Math.max(0, columns.end - columns.start), true),\n\t\t\t\t).trimEnd(),\n\t\t\t);\n\t\t}\n\t\tconst text = lines.join(\"\\n\");\n\t\tif (text.length === 0) return;\n\t\tthis.terminal.write(`\\x1b]52;c;${Buffer.from(text).toString(\"base64\")}\\x07`);\n\t\tthis.flash(\"Copied!\");\n\t}\n\n\tprivate applySelectionHighlight(text: string): string {\n\t\tlet result = \"\\x1b[7m\";\n\t\tlet index = 0;\n\t\twhile (index < text.length) {\n\t\t\tconst ansi = extractAnsiCode(text, index);\n\t\t\tif (!ansi) {\n\t\t\t\tresult += text[index];\n\t\t\t\tindex++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tresult += ansi.code;\n\t\t\tif (ansi.code.endsWith(\"m\")) result += \"\\x1b[7m\";\n\t\t\tindex += ansi.length;\n\t\t}\n\t\treturn `${result}\\x1b[27m`;\n\t}\n\n\tprivate applySelection(screen: string[], layout = this.currentLayout): string[] {\n\t\tconst selection = this.getSelectionBounds();\n\t\tif (!selection) return screen;\n\t\tlet screenSelection = selection;\n\t\tlet minRow = 0;\n\t\tlet maxRow = screen.length - 1;\n\t\tlet minColumn = 0;\n\t\tlet maxColumn = this.terminal.columns;\n\t\tif (selection.start.scrollView) {\n\t\t\tif (!layout) return screen;\n\t\t\tconst box = getScrollViewBox(layout, selection.start.scrollView);\n\t\t\tif (!box) return screen;\n\t\t\tminRow = Math.max(0, box.rect.y, box.clip.y);\n\t\t\tmaxRow = Math.min(screen.length - 1, box.rect.y + box.rect.height - 1, box.clip.y + box.clip.height - 1);\n\t\t\tminColumn = Math.max(0, box.rect.x, box.clip.x);\n\t\t\tmaxColumn = Math.min(this.terminal.columns, box.rect.x + box.rect.width, box.clip.x + box.clip.width);\n\t\t\tscreenSelection = {\n\t\t\t\tstart: {\n\t\t\t\t\t...selection.start,\n\t\t\t\t\trow: box.rect.y + selection.start.row - selection.start.scrollView.scrollTop,\n\t\t\t\t\tcol: box.rect.x + selection.start.col,\n\t\t\t\t},\n\t\t\t\tend: {\n\t\t\t\t\t...selection.end,\n\t\t\t\t\trow: box.rect.y + selection.end.row - selection.start.scrollView.scrollTop,\n\t\t\t\t\tcol: box.rect.x + selection.end.col,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\treturn screen.map((line, row) => {\n\t\t\tif (\n\t\t\t\trow < minRow ||\n\t\t\t\trow > maxRow ||\n\t\t\t\trow < screenSelection.start.row ||\n\t\t\t\trow > screenSelection.end.row ||\n\t\t\t\tisImageLine(line)\n\t\t\t) {\n\t\t\t\treturn line;\n\t\t\t}\n\t\t\tconst lineWidth = visibleWidth(line);\n\t\t\tconst columns = this.getSelectionColumns(line, row, screenSelection, minColumn, maxColumn);\n\t\t\tif (columns.end <= columns.start) return line;\n\t\t\tconst before = sliceByColumn(line, 0, columns.start, true);\n\t\t\tconst selected = sliceByColumn(line, columns.start, columns.end - columns.start, true);\n\t\t\tconst after = sliceByColumn(line, columns.end, Math.max(0, lineWidth - columns.end), true);\n\t\t\treturn `${before}${this.applySelectionHighlight(selected)}${after}`;\n\t\t});\n\t}\n\n\tprivate isMouseSequence(data: string): boolean {\n\t\treturn /^\\x1b\\[<\\d+;\\d+;\\d+[Mm]$/.test(data) || (data.length === 6 && data.startsWith(\"\\x1b[M\"));\n\t}\n\n\tprivate compositeFlashes(screen: string[], width: number, height: number): string[] {\n\t\tconst flashLines = this.flashes.render(width).slice(-height);\n\t\tif (flashLines.length === 0) return screen;\n\t\tconst result = [...screen];\n\t\twhile (result.length < height) result.push(\"\");\n\t\tfor (let row = 0; row < flashLines.length; row++) {\n\t\t\tconst line = flashLines[row]!;\n\t\t\tconst flashWidth = visibleWidth(line);\n\t\t\tif (flashWidth === 0) continue;\n\t\t\tresult[row] = compositeTuiLine(result[row] ?? \"\", line, width - flashWidth, flashWidth, width);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate prepareRenderFrame(width: number, height: number): PreparedAltScreenFrame {\n\t\tconst root = this.layoutRoot ?? this.implicitScrollView;\n\t\tconst layout = renderLayoutFrame(root, width, height, () => this.requestRender());\n\t\tlet screen = layout.lines.map((line) => line.replace(OSC133_ZONE_PREFIX, \"\"));\n\t\tscreen = this.compositeOverlays(screen, width, height);\n\t\tif (screen.length > height) screen = screen.slice(screen.length - height);\n\t\tscreen = this.applySelection(screen, layout);\n\t\tscreen = this.compositeFlashes(screen, width, height);\n\t\tconst cursorPosition = this.extractCursorPosition(screen, height);\n\t\tscreen = this.applyLineResets(screen).map((line) => {\n\t\t\tif (isImageLine(line) || visibleWidth(line) <= width) return line;\n\t\t\treturn sliceByColumn(line, 0, width, true);\n\t\t});\n\t\treturn { layout, screen, cursorPosition };\n\t}\n\n\tprivate prepareRedrawPlan(screen: string[], width: number, height: number): AltScreenRedrawPlan {\n\t\tconst fullRedraw =\n\t\t\tthis.previousScreen.length === 0 || this.previousScreenWidth !== width || this.previousScreenHeight !== height;\n\t\tconst imagesNeedRedraw = screen.some(\n\t\t\t(line, row) =>\n\t\t\t\tline !== this.previousScreen[row] && (isImageLine(line) || isImageLine(this.previousScreen[row] ?? \"\")),\n\t\t);\n\t\tconst redrawImages = fullRedraw || imagesNeedRedraw;\n\t\tconst hadUploadedKittyImages = this.uploadedKittyImages.size > 0;\n\t\tconst preparedKittyScreen =\n\t\t\tredrawImages && this.imageProtocol === \"kitty\"\n\t\t\t\t? this.prepareKittyScreen(screen)\n\t\t\t\t: { lines: screen, evictedImageDeletion: \"\" };\n\t\treturn { fullRedraw, imagesNeedRedraw, hadUploadedKittyImages, preparedKittyScreen };\n\t}\n\n\tprivate createImageRedrawSequence(plan: AltScreenRedrawPlan): string {\n\t\tif (plan.fullRedraw) {\n\t\t\tthis.fullRedrawCount += 1;\n\t\t\tconst clearImages =\n\t\t\t\tthis.imageProtocol === \"kitty\" && plan.hadUploadedKittyImages\n\t\t\t\t\t? deleteAllKittyPlacements()\n\t\t\t\t\t: this.deleteKittyImages();\n\t\t\treturn `${clearImages}\\x1b[2J`;\n\t\t}\n\t\tif (!plan.imagesNeedRedraw) return \"\";\n\t\tif (this.imageProtocol === \"iterm2\") return \"\\x1b[2J\";\n\t\treturn this.imageProtocol === \"kitty\" ? deleteAllKittyPlacements() : \"\";\n\t}\n\n\tprivate appendChangedScreenRows(\n\t\tbuffer: string,\n\t\tscreen: string[],\n\t\tpreparedLines: string[],\n\t\theight: number,\n\t\tredrawAllRows: boolean,\n\t): string {\n\t\tfor (let row = 0; row < height; row++) {\n\t\t\tif (!redrawAllRows && screen[row] === this.previousScreen[row]) continue;\n\t\t\tbuffer += `\\x1b[${row + 1};1H\\x1b[2K${preparedLines[row] ?? \"\"}`;\n\t\t}\n\t\treturn buffer;\n\t}\n\n\tprivate appendCursorState(buffer: string, cursorPosition: RenderedCursorPosition | null, width: number): string {\n\t\tif (!cursorPosition) return `${buffer}\\x1b[?25l`;\n\t\tconst position = `\\x1b[${cursorPosition.row + 1};${Math.min(width, cursorPosition.col) + 1}H`;\n\t\tconst visibility = this.getShowHardwareCursor() ? \"\\x1b[?25h\" : \"\\x1b[?25l\";\n\t\treturn buffer + position + visibility;\n\t}\n\n\tprivate createScreenUpdateBuffer(\n\t\tframe: PreparedAltScreenFrame,\n\t\tplan: AltScreenRedrawPlan,\n\t\twidth: number,\n\t\theight: number,\n\t): string {\n\t\tlet buffer = BEGIN_SYNCHRONIZED_OUTPUT + this.createImageRedrawSequence(plan);\n\t\tbuffer += plan.preparedKittyScreen.evictedImageDeletion;\n\t\tbuffer = this.appendChangedScreenRows(\n\t\t\tbuffer,\n\t\t\tframe.screen,\n\t\t\tplan.preparedKittyScreen.lines,\n\t\t\theight,\n\t\t\tplan.fullRedraw || plan.imagesNeedRedraw,\n\t\t);\n\t\treturn this.appendCursorState(buffer, frame.cursorPosition, width) + END_SYNCHRONIZED_OUTPUT;\n\t}\n\n\tprotected override doRender(): void {\n\t\tif (this.stopped || !this.altScreenActive) return;\n\t\tconst width = Math.max(1, this.terminal.columns);\n\t\tconst height = Math.max(1, this.terminal.rows);\n\t\tconst frame = this.prepareRenderFrame(width, height);\n\t\tconst redrawPlan = this.prepareRedrawPlan(frame.screen, width, height);\n\t\tthis.terminal.write(this.createScreenUpdateBuffer(frame, redrawPlan, width, height));\n\t\tthis.previousScreen = frame.screen;\n\t\tthis.previousScreenWidth = width;\n\t\tthis.previousScreenHeight = height;\n\t\tthis.currentLayout = frame.layout;\n\t}\n}\n"]}
|