diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-15 13:01:28 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-09-15 17:24:42 -0300 |
| commit | ffc700d14d61fd5e6ca874a186932300c447c836 (patch) | |
| tree | 364b733b061f4fec14cef0a12862fa125cbde35b /src/panes.zig | |
| parent | fc2738eea560769c8d150a7cc955fe8d54121298 (diff) | |
| download | pardes-ffc700d14d61fd5e6ca874a186932300c447c836.tar.gz pardes-ffc700d14d61fd5e6ca874a186932300c447c836.zip | |
Mirror raw terminal mouse selections for text transfer
Diffstat (limited to 'src/panes.zig')
| -rw-r--r-- | src/panes.zig | 44 |
1 files changed, 38 insertions, 6 deletions
diff --git a/src/panes.zig b/src/panes.zig index a39afe01..b2f05cdf 100644 --- a/src/panes.zig +++ b/src/panes.zig @@ -44,10 +44,13 @@ pub const Pane = struct { hi: usize, prefix: [32]u8 = @splat(0), prefix_len: u8 = 0, + raw_terminal: bool = false, + prompt_bytes: usize = 0, }; pub const PointerSelection = struct { gesture: Sel, rows: []PointerRow, + raw_text: ?[]u8 = null, }; /// A modal line selection (helix `x`): whole rows [r0, r1], absolute. @@ -174,10 +177,21 @@ pub const Pane = struct { msg_len: u16 = 0, pub fn clearPointerSelection(pane: *Pane, slot: usize) void { - if (pane.pointer_selections[slot]) |selection| pane.gpa.free(selection.rows); + if (pane.pointer_selections[slot]) |selection| { + pane.gpa.free(selection.rows); + if (selection.raw_text) |text| pane.gpa.free(text); + } pane.pointer_selections[slot] = null; } + pub fn rawPointerText(pane: *const Pane, gesture: Sel) ?[]const u8 { + if (gesture.state != .done or gesture.source_id == 0) return null; + for (pane.pointer_selections) |selection| { + if (selection) |saved| if (std.meta.eql(saved.gesture, gesture)) return saved.raw_text; + } + return null; + } + pub fn pointerSelection(pane: *const Pane, gesture: Sel) ?[]PointerRow { if (gesture.state != .done or gesture.source_id == 0) return null; for (pane.pointer_selections) |selection| { @@ -6330,7 +6344,7 @@ pub const Terminal = struct { var index: usize = 0; for (pane.sel) |gesture| if (pane.pointerSelection(gesture)) |rows| { for (rows) |*row| { - pins[index] = trackPosition(pages, &row.row, overlay, &failed); + pins[index] = trackPosition(pages, &row.row, if (row.raw_terminal) null else overlay, &failed); index += 1; } }; @@ -6482,7 +6496,8 @@ pub const Terminal = struct { pub fn enterTty(p: *Pardes, id: usize) void { const pane = p.panes[id] orelse return; - if (comptime enabled) if (pane.terminal != null and pane.cur_pinned and pane.terminal.?.vt.cursorIsAtPrompt()) handoff: { + const selected = pane.rawPointerText(pane.sel[@intFromEnum(config.select_button)]) != null; + if (comptime enabled) if (!selected and pane.terminal != null and pane.cur_pinned and pane.terminal.?.vt.cursorIsAtPrompt()) handoff: { const screen = pane.terminal.?.vt.screens.active; const goff: i32 = @intCast(screen.pages.scrollbar().offset); const vp_row = pane.gridRow(pane.cur_row) - goff; @@ -6511,9 +6526,9 @@ pub const Terminal = struct { pane.msel.active = false; pane.vsel.active = false; pane.nsel = 0; - // A pinned row scrolls away. Raw mode must follow the program's live - // cursor, and Last must not restore a stale modal spot on the way back. - pane.cur_pinned = false; + // The raw renderer follows the live cursor. A captured mouse selection + // keeps its modal endpoint for the next return to editor mode. + pane.cur_pinned = selected; pane.select = false; pane.append_at = null; pane.sticky_col = -1; @@ -6590,6 +6605,19 @@ pub const Terminal = struct { return .{ .cut = cols }; } + pub fn promptPrefixBytes(pane: *Pane, row: i32, raw: []const u8) usize { + if (comptime !enabled) return 0; + if (row < 0) return 0; + const state = pane.terminal orelse return 0; + const pin = state.vt.screens.active.pages.pin(.{ .screen = .{ .x = 0, .y = @intCast(row) } }) orelse return 0; + if (pin.rowAndCell().row.semantic_prompt == .none) return 0; + return switch (promptCut(pin)) { + .keep => 0, + .blank => raw.len, + .cut => |cols| @min(raw.len, File.rawAtDisplay(raw, cols)), + }; + } + fn promptRow(pin: ghostty_vt.Pin, raw: []const u8) []const u8 { const cols = switch (promptCut(pin)) { .keep => return raw, @@ -6765,6 +6793,10 @@ pub const Terminal = struct { /// Consume a rewritten overlay, freeing the terminal edit text it replaces. pub fn setEditText(p: *Pardes, pane: *Pane, new: []u8) void { const overlay = if (pane.ovl) |*value| value else return p.gpa.free(new); + for (0..pane.sel.len) |button| { + pane.clearPointerSelection(button); + pane.sel[button].state = .none; + } p.gpa.free(overlay.text); overlay.text = new; } |
