diff options
| author | Gabriel Schneider <[email protected]> | 2026-07-02 20:06:25 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-08-01 15:02:07 -0300 |
| commit | bead9f0b78380d1428f40fdab339c1c8f88fa626 (patch) | |
| tree | 960255de5a2cef661ec5d0ad3220a4b2b1738842 /main.zig | |
| parent | 62ef1882ab7878210f05f06504796849e412c318 (diff) | |
| download | pardes-bead9f0b78380d1428f40fdab339c1c8f88fa626.tar.gz pardes-bead9f0b78380d1428f40fdab339c1c8f88fa626.zip | |
sdl ui backend
Diffstat (limited to 'main.zig')
| -rw-r--r-- | main.zig | 54 |
1 files changed, 39 insertions, 15 deletions
@@ -1,5 +1,5 @@ const std = @import("std"); -const vaxis = @import("vaxis"); +const vaxis = @import("ui"); const ghostty_vt = @import("ghostty-vt"); const Term = @import("term.zig"); const modal = @import("modal.zig"); @@ -191,6 +191,7 @@ const MINW: u16 = 10; // min pane width (cells) const MINH: u16 = 3; // min pane height (cells) const MAX_TERMS: usize = 16; const MAX_COLS: usize = 6; +const MAX_PTY_DRAIN_EVENTS: usize = 128; const PREFIX_W: u16 = 5; // file-pane line-number prefix width: "%4d " const Rect = struct { x: u16, y: u16, w: u16, h: u16 }; @@ -767,10 +768,10 @@ fn pty_set_size(pty: std.Io.File, rows: u16, cols: u16) void { // One reader task per terminal. Tags each chunk with the terminal's slot id so // the main loop knows which emulator to feed; posts pty_eof when the shell exits. fn readPty(io: std.Io, gpa: std.mem.Allocator, pty: std.Io.File, id: usize, loop: *Loop) anyerror!void { - var read_buf: [0x1000]u8 = undefined; + var read_buf: [0x10000]u8 = undefined; var reader = pty.readerStreaming(io, &read_buf); while (true) { - var buf: [0x1000]u8 = undefined; + var buf: [0x10000]u8 = undefined; var vec = [_][]u8{&buf}; const n = reader.interface.readVec(&vec) catch break; if (n == 0) break; @@ -783,6 +784,19 @@ fn readPty(io: std.Io, gpa: std.mem.Allocator, pty: std.Io.File, id: usize, loop loop.postEvent(.{ .pty_eof = id }) catch {}; } +fn feedPtyRead(gpa: std.mem.Allocator, terms: *[MAX_TERMS]?*Term, active: usize, pr: PtyRead) void { + defer gpa.free(pr.bytes); + if (pr.id >= MAX_TERMS) return; + if (terms[pr.id]) |t| { + t.stream.nextSlice(pr.bytes); + // follow new output to the bottom, so a command's result shows even in a + // pane you didn't focus. Exception: the pane you're actively navigating + // in a text mode — don't yank the cursor out from under you. + if (!(pr.id == active and t.mode != .tty)) + t.term.screens.active.scroll(.active); + } +} + // fork the pty + boot the emulator. Forking is the dangerous part in a // multithreaded process, so this does NOT start the reader task (no new // threads) — call startReader once the term is wired in. @@ -3054,9 +3068,14 @@ pub fn main(init: std.process.Init) !void { // middle release, freed on overwrite / app exit. var chord_arg: ?[]u8 = null; defer if (chord_arg) |a| gpa.free(a); + var pending_event: ?@TypeOf(Command.value) = null; while (true) { - const event = try loop.nextEvent(); + const event = if (pending_event) |ev| blk: { + pending_event = null; + break :blk ev; + } else try loop.nextEvent(); + var drain_pty_after = false; switch (event) { .mouse => |mouse| { const mcol: u16 = if (mouse.col < 0) 0 else @min(@as(u16, @intCast(mouse.col)), screen_w -| 1); @@ -3341,7 +3360,6 @@ pub fn main(init: std.process.Init) !void { } }, .key_press => |key| kpress: { - if (terms[active]) |at| { // Ctrl-w prefix: helix-style pane focus (Ctrl-w h/j/k/l). if (ctrl_w_pending) { @@ -3461,16 +3479,8 @@ pub fn main(init: std.process.Init) !void { } }, .pty_read => |pr| { - defer gpa.free(pr.bytes); - if (terms[pr.id]) |t| { - t.stream.nextSlice(pr.bytes); - // follow new output to the bottom, so a command's result shows - // even in a pane you didn't focus. Exception: the pane you're - // actively navigating in a text mode — don't yank the cursor out - // from under you (it still tracks the bottom on its own there). - if (!(pr.id == active and t.mode != .tty)) - t.term.screens.active.scroll(.active); - } + feedPtyRead(gpa, &terms, active, pr); + drain_pty_after = true; }, .pty_eof => |id| { if (terms[id]) |t| { @@ -3507,6 +3517,20 @@ pub fn main(init: std.process.Init) !void { else => {}, } + if (drain_pty_after) { + var drained: usize = 0; + while (drained < MAX_PTY_DRAIN_EVENTS) : (drained += 1) { + const next = try loop.tryEvent() orelse break; + switch (next) { + .pty_read => |pr| feedPtyRead(gpa, &terms, active, pr), + else => { + pending_event = next; + break; + }, + } + } + } + // a fresh yank (y/d/c) mirrors out to the system clipboard via OSC 52. Emit // here where the tty writer + vx are in scope; the vx.render() below flushes. // ponytail: OSC 52 has a per-terminal size cap, so a huge yank may be |
