mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
fix(tui): reduce mouse tracking in terminal multiplexers
This commit is contained in:
parent
9b17fd5bb3
commit
fc3554e16d
3 changed files with 62 additions and 4 deletions
|
|
@ -5,6 +5,7 @@
|
|||
### Fixed
|
||||
|
||||
- Fixed LaTeX relation, multiplication, and named-operator spacing, and correctly composed matrices with stacked fractions, operator limits, and adjacent matrices.
|
||||
- Reduced fullscreen mouse event volume under tmux, Zellij, and GNU Screen by using button-motion tracking instead of all-motion tracking.
|
||||
|
||||
## [0.84.0] - 2026-08-06
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,8 @@ const ENTER_ALT_SCREEN = "\x1b[?1049h";
|
|||
const EXIT_ALT_SCREEN = "\x1b[?1049l";
|
||||
const DISABLE_AUTOWRAP = "\x1b[?7l";
|
||||
const ENABLE_AUTOWRAP = "\x1b[?7h";
|
||||
const ENABLE_MOUSE = "\x1b[?1000h\x1b[?1002h\x1b[?1003h\x1b[?1004h\x1b[?1006h";
|
||||
const ENABLE_BUTTON_MOTION_MOUSE = "\x1b[?1000h\x1b[?1002h\x1b[?1004h\x1b[?1006h";
|
||||
const ENABLE_ALL_MOTION_MOUSE = "\x1b[?1000h\x1b[?1002h\x1b[?1003h\x1b[?1004h\x1b[?1006h";
|
||||
const DISABLE_MOUSE = "\x1b[?1006l\x1b[?1004l\x1b[?1003l\x1b[?1002l\x1b[?1000l";
|
||||
const FOCUS_IN = "\x1b[I";
|
||||
const FOCUS_OUT = "\x1b[O";
|
||||
|
|
@ -201,8 +202,19 @@ export class TuiAltScreen extends TuiBase implements ViewportTUI {
|
|||
this.pressedUrl = undefined;
|
||||
this.selectionDragged = false;
|
||||
this.resetRenderState();
|
||||
const term = process.env.TERM?.toLowerCase() ?? "";
|
||||
// Multiplexers can lag when every pointer movement is forwarded. Button-motion
|
||||
// tracking preserves clicks, wheel events, selections, and scrollbar dragging.
|
||||
const mouseSequence =
|
||||
process.env.TMUX !== undefined ||
|
||||
process.env.ZELLIJ !== undefined ||
|
||||
process.env.STY !== undefined ||
|
||||
term.startsWith("tmux") ||
|
||||
term.startsWith("screen")
|
||||
? ENABLE_BUTTON_MOTION_MOUSE
|
||||
: ENABLE_ALL_MOTION_MOUSE;
|
||||
this.terminal.write(
|
||||
`${ENTER_ALT_SCREEN}${DISABLE_AUTOWRAP}${this.mouseEnabled ? ENABLE_MOUSE : ""}\x1b[2J\x1b[H\x1b[?25l`,
|
||||
`${ENTER_ALT_SCREEN}${DISABLE_AUTOWRAP}${this.mouseEnabled ? mouseSequence : ""}\x1b[2J\x1b[H\x1b[?25l`,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -161,6 +161,53 @@ describe("TuiAltScreen", () => {
|
|||
tui.stop();
|
||||
});
|
||||
|
||||
it("uses button-motion tracking inside terminal multiplexers", () => {
|
||||
const environmentKeys = ["TMUX", "ZELLIJ", "STY", "TERM"] as const;
|
||||
const previousEnvironment = new Map(environmentKeys.map((key) => [key, process.env[key]]));
|
||||
try {
|
||||
for (const key of environmentKeys) delete process.env[key];
|
||||
process.env.TERM = "xterm-256color";
|
||||
const directTerminal = new RecordingTerminal();
|
||||
const directTui = new TuiAltScreen(directTerminal);
|
||||
directTui.start();
|
||||
const directWrites = directTerminal.events
|
||||
.filter((event): event is { type: "write"; data: string } => event.type === "write")
|
||||
.map((event) => event.data)
|
||||
.join("");
|
||||
assert.ok(directWrites.includes("\x1b[?1003h"));
|
||||
directTui.stop();
|
||||
|
||||
const multiplexers = [
|
||||
{ name: "tmux environment", environment: { TMUX: "/tmp/tmux/default,1,0" } },
|
||||
{ name: "tmux TERM", environment: { TERM: "tmux-256color" } },
|
||||
{ name: "Zellij environment", environment: { ZELLIJ: "0" } },
|
||||
{ name: "Screen environment", environment: { STY: "123.session" } },
|
||||
{ name: "Screen TERM", environment: { TERM: "screen-256color" } },
|
||||
];
|
||||
for (const { name, environment } of multiplexers) {
|
||||
for (const key of environmentKeys) delete process.env[key];
|
||||
for (const [key, value] of Object.entries(environment)) process.env[key] = value;
|
||||
const terminal = new RecordingTerminal();
|
||||
const tui = new TuiAltScreen(terminal);
|
||||
tui.start();
|
||||
const writes = terminal.events
|
||||
.filter((event): event is { type: "write"; data: string } => event.type === "write")
|
||||
.map((event) => event.data)
|
||||
.join("");
|
||||
assert.ok(writes.includes("\x1b[?1002h"), `${name} should enable button-motion tracking`);
|
||||
assert.ok(!writes.includes("\x1b[?1003h"), `${name} should not enable all-motion tracking`);
|
||||
assert.ok(writes.includes("\x1b[?1006h"), `${name} should enable SGR mouse encoding`);
|
||||
tui.stop();
|
||||
}
|
||||
} finally {
|
||||
for (const key of environmentKeys) {
|
||||
const value = previousEnvironment.get(key);
|
||||
if (value === undefined) delete process.env[key];
|
||||
else process.env[key] = value;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("drags a visible scrollbar thumb and keeps it visible until release", async () => {
|
||||
const terminal = new RecordingTerminal(10, 5);
|
||||
const tui = new TuiAltScreen(terminal);
|
||||
|
|
@ -214,9 +261,7 @@ describe("TuiAltScreen", () => {
|
|||
assert.strictEqual(scrollView.isScrollbarVisible, false);
|
||||
|
||||
assert.ok(terminal.events.every((event) => event.type !== "write" || !event.data.includes("\x1b]52;c;")));
|
||||
assert.ok(terminal.events.some((event) => event.type === "write" && event.data.includes("\x1b[?1003h")));
|
||||
tui.stop();
|
||||
assert.ok(terminal.events.some((event) => event.type === "write" && event.data.includes("\x1b[?1003l")));
|
||||
});
|
||||
|
||||
it("keeps the scrollbar column selectable while the thumb is hidden", async () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue