diff options
| author | Gabriel Schneider <[email protected]> | 2026-07-08 09:56:53 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-08-01 15:02:07 -0300 |
| commit | b91e5ebf8b529d0ced0bf18e83b17df0bd2374ce (patch) | |
| tree | 58122968971bee42ef7144a0d3c1315c5158d636 /src/pardes.zig | |
| parent | 32041350ab22935724b950794c5c1d71374dc76b (diff) | |
| download | pardes-b91e5ebf8b529d0ced0bf18e83b17df0bd2374ce.tar.gz pardes-b91e5ebf8b529d0ced0bf18e83b17df0bd2374ce.zip | |
chord polish: the selection a 1-2/1-3 chord leaves behind is dismissed by the next left click instead of stretching to it (explicit v/x selections keep click-extend), and in a tty-mode shell 1-3 now pastes into the pty like a terminal emulator — the click is forwarded first (SGR or X10, only when the app listens for mouse) so mouse-aware programs paste at the click point, then the register arrives bracketed (mode 2004) or with \n->\r when unbracketed; 1-2 stays inert there. chordcut.snap pins both (a cat -v probe shows the exact wire bytes); tutor updated.
Diffstat (limited to 'src/pardes.zig')
| -rw-r--r-- | src/pardes.zig | 53 |
1 files changed, 51 insertions, 2 deletions
diff --git a/src/pardes.zig b/src/pardes.zig index fc216b24..994b0785 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -3805,6 +3805,10 @@ pub const Pardes = struct { if (!pane.isTerminal()) pane.mode = .normal; pane.msel.active = false; pane.pending = 0; + // a chord/motion selection is residue: a fresh click + // dismisses it rather than dragging the anchored span + // to the click (explicit v/x keeps vim's click-extend) + if (!pane.vsel.explicit) pane.vsel.active = false; } } else { // acme execute (middle) / look (right): a no-drag click @@ -3829,14 +3833,60 @@ pub const Pardes = struct { /// selection; Paste replaces it with the yank register, or splices the /// register in literally at a bare cursor — so 1-2 then 1-3 in one hold /// nets out to Snarf (copy: the text returns, the register keeps it). + /// In a tty-mode shell 1-3 instead pastes into the pty (forwarded click + /// + bracketed paste) and 1-2 is inert. fn chordCutPaste(p: *Pardes, cut: bool) void { const s = &p.drag.select; const pane = p.panes[s.id] orelse return; + if (pane.mode == .tty) { + // tty: nothing can be cut — 1-2 stays inert; the pty owns the + // screen. 1-3 pastes like a terminal emulator: the click is + // forwarded first (only when the app listens for mouse) so + // mouse-aware programs put their cursor under it, then the + // register is typed — bracketed when the app set mode 2004 + // (readline/vim/helix strip the markers), else with \n turned + // to \r like any unbracketed paste. + if (!s.chorded) { + s.chorded = true; + pane.sel[0].state = .none; // drop the sweep highlight + } + if (cut) return; + const y = p.yank orelse return; + if (y.len == 0) return; + const m = &pane.vt.modes; + if (m.get(.mouse_event_normal) or m.get(.mouse_event_button) or m.get(.mouse_event_any)) { + // dragUpdate keeps sel[0] tracking the held left button, so + // the click lands where the mouse is at this tap; 1-based, + // body-relative (the tag row is ours, not the app's) + const col: u16 = @intCast(std.math.clamp(pane.sel[0].c1 + 1, 1, 9999)); + const row: u16 = @intCast(std.math.clamp(pane.sel[0].r1 - @as(i32, BOX_H) + 1, 1, 9999)); + var mb: [32]u8 = undefined; + if (m.get(.mouse_format_sgr)) { + p.emitWrite(s.id, std.fmt.bufPrint(&mb, "\x1b[<0;{d};{d}M\x1b[<0;{d};{d}m", .{ col, row, col, row }) catch return); + } else { + // ponytail: legacy X10 bytes; add utf8/urxvt formats if an app ever wants them + const cb: u8 = @intCast(32 + @min(col, 222)); + const rb: u8 = @intCast(32 + @min(row, 222)); + p.emitWrite(s.id, &[_]u8{ 0x1b, '[', 'M', 32, cb, rb, 0x1b, '[', 'M', 35, cb, rb }); + } + } + if (m.get(.bracketed_paste)) { + p.emitWrite(s.id, "\x1b[200~"); + p.emitWrite(s.id, y); + p.emitWrite(s.id, "\x1b[201~"); + } else { + const cp = p.scratch.allocator().dupe(u8, y) catch return; + for (cp) |*c| { + if (c.* == '\n') c.* = '\r'; + } + p.emitWrite(s.id, cp); + } + return; + } if (!s.chorded) { s.chorded = true; const sl = pane.sel[0]; pane.sel[0].state = .none; - if (pane.mode == .tty) return; // the pty owns the cursor there const pfx: i32 = if (pane.file != null) PREFIX_W else 0; const hs: i32 = if (pane.file != null) pane.hscroll else 0; const row0 = @max(0, sl.r0 - @as(i32, BOX_H)) + pane.scroll(); @@ -3852,7 +3902,6 @@ pub const Pardes = struct { if (!pane.isTerminal()) pane.mode = .normal; pane.vsel = .{ .active = row0 != row1 or col0 != col1, .row = row0, .col = col0, .explicit = false }; } - if (pane.mode == .tty) return; if (cut) { if (pane.vsel.active) p.normalDelete(pane, true); } else if (pane.vsel.active) { |
