diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-30 20:23:31 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:17 -0300 |
| commit | 68dd567218505838814d73473460a0c0ff8e97b3 (patch) | |
| tree | babe029d3940c9dd6f7ef7b385086f2fabefe6aa /src | |
| parent | f8fe738416fe3a40a7136f2cb5528e8fd57f40df (diff) | |
| parent | f99806de546c837ab6f2d5b1e3e8accc95e63a7e (diff) | |
| download | pardes-68dd567218505838814d73473460a0c0ff8e97b3.tar.gz pardes-68dd567218505838814d73473460a0c0ff8e97b3.zip | |
Release Pardes 0.12
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src')
| -rw-r--r-- | src/CHANGELOG.md | 25 | ||||
| -rw-r--r-- | src/gui/gui.zig | 12 | ||||
| -rw-r--r-- | src/mouse.zig | 47 |
3 files changed, 73 insertions, 11 deletions
diff --git a/src/CHANGELOG.md b/src/CHANGELOG.md index 0d9c42f4..ae796a4d 100644 --- a/src/CHANGELOG.md +++ b/src/CHANGELOG.md @@ -1,5 +1,30 @@ # Changelog +## 0.0.12 + +- A selection deep in a very long line no longer slows every frame: a 5 MB + line with the selection at its end redraws in milliseconds, not seconds. +- `Joincol` is refused when the joined column cannot give each pane its tag + and 2 rows. Save on a PDF or image pane is refused. A builtin made for + one kind of pane (Petscii, PdfTint, Togglettymode, …) is refused on any + other; `Mode` and `TreeContext` say why when they cannot act. +- After `ThemeFile`, `/ctl`, DumpConfig and a Dump read `ThemeFile <path>`. + DumpConfig's unsupported settings are `# … unsupported` comments, so the + whole report writes back to `/ctl`. Every bad setting value names what + the setting takes. +- A refused write to `dot` changes nothing; an edit that changes nothing + makes no undo step; the jump list never holds one place twice in a row; + `Jumplist` refills its one `+Jumps`; a look miss cuts a long path in its + middle. +- A look past a PDF's last page is a miss; PdfSections on a PDF with no + outline says so; a Rename that finds nothing says so and fails; a theme + file error names its path; Recent keeps PDFs and images, and an open + file's row is where its dot is now. +- Over a program that tracks the mouse, B2 and B3 are pardes's execute and + look again, sweeps and chords included; Shift-B2 and Shift-B3 go to the + program as its buttons 2 and 3. B1 and the wheel stay the program's, and + Shift keeps them pardes's. + ## 0.0.11 - A look on a diff names a file as the repository does: git's `a/`/`b/` diff --git a/src/gui/gui.zig b/src/gui/gui.zig index 1e58d3ba..ea0e2862 100644 --- a/src/gui/gui.zig +++ b/src/gui/gui.zig @@ -5042,7 +5042,7 @@ test "a wheel's notch is whole lines, a touchpad's fraction is not" { try std.testing.expectEqual(@as(?i32, null), notchOf(std.math.nan(f32), 1)); } -test "a click over codex in a terminal reaches its pty with its modifiers; with Shift it is pardes's" { +test "a click over codex in a terminal reaches its pty with its modifiers; Shift swaps B1 to pardes and B2 to the program" { if (comptime !pardes.panes.terminal.enabled) return error.SkipZigTest; const gpa = std.testing.allocator; const core = try pardes.Pardes.init(gpa, .{ .cols = 60, .rows = 16, .tty_only = true }); @@ -5077,9 +5077,17 @@ test "a click over codex in a terminal reaches its pty with its modifiers; with try std.testing.expectEqualStrings("\x1b[<32;7;4M", try take(core, &sent)); in.post(.{ .mouse = pointerMouse(.left, .release, next, .{}) }); try std.testing.expectEqualStrings("\x1b[<0;7;4m", try take(core, &sent)); + // Shift-B1 is pardes's select; B2 is pardes's execute and Shift-B2 + // the program's, reported without the Shift. + in.post(.{ .mouse = pointerMouse(.left, .press, mc, .{ .shift = true }) }); + in.post(.{ .mouse = pointerMouse(.left, .release, mc, .{ .shift = true }) }); + try std.testing.expectEqualStrings("", try take(core, &sent)); + in.post(.{ .mouse = pointerMouse(.middle, .press, mc, .{}) }); + in.post(.{ .mouse = pointerMouse(.middle, .release, mc, .{}) }); + try std.testing.expectEqualStrings("", try take(core, &sent)); in.post(.{ .mouse = pointerMouse(.middle, .press, mc, .{ .shift = true }) }); in.post(.{ .mouse = pointerMouse(.middle, .release, mc, .{ .shift = true }) }); - try std.testing.expectEqualStrings("", try take(core, &sent)); + try std.testing.expectEqualStrings("\x1b[<1;6;4M\x1b[<1;6;4m", try take(core, &sent)); } test "a wheel over codex in a terminal reaches its pty as the mouse reports it asked for" { diff --git a/src/mouse.zig b/src/mouse.zig index ecb9bb57..41362249 100644 --- a/src/mouse.zig +++ b/src/mouse.zig @@ -335,7 +335,14 @@ fn programWheel(p: *Pardes, id: usize, m: Mouse, col: u16, row: u16) bool { return true; } -pub const Grab = struct { id: usize, serial: u32, held: u3 = 0 }; +pub const Grab = struct { + id: usize, + serial: u32, + held: u3 = 0, + /// Taken by Shift-B2 or Shift-B3: the Shift chose the program, so its + /// reports leave it out. + unshift: bool = false, +}; /// The 0-based cell of a terminal program's grid under screen cell /// `col`,`row`, or null over chrome (tag, gutter, scrollbar, anything past @@ -360,8 +367,10 @@ fn tracksMouse(pane: *const Pane) bool { /// it: presses, releases, drags with a button down (1002) and, under 1003, /// every move, once per cell. A press it took keeps its drag and release /// wherever the pointer goes. Tags, gutters and the rest of pardes's -/// chrome are never its, and Shift keeps pardes's own select, execute and -/// look. True when the event was the program's. +/// chrome are never its. B1 is the program's and Shift-B1 pardes's select; +/// B2 and B3 are pardes's execute and look, and Shift-B2 and Shift-B3 the +/// program's, reported without the Shift that chose it. True when the +/// event was the program's. fn programMouse(p: *Pardes, m: Mouse) bool { const button: ?panes.terminal.MouseButton = switch (m.button) { .left => .left, @@ -372,9 +381,10 @@ fn programMouse(p: *Pardes, m: Mouse) bool { }; const bit: u3 = if (button) |b| @as(u3, 1) << @intCast(@intFromEnum(b)) else 0; const at = p.presentation.pointer(p.screen_w, p.screen_h, @min(m.col, p.screen_w -| 1), @min(m.row, p.screen_h -| 1)); - const mods: panes.terminal.MouseMods = .{ .shift = m.shift, .alt = m.alt, .ctrl = m.ctrl }; + var mods: panes.terminal.MouseMods = .{ .shift = m.shift, .alt = m.alt, .ctrl = m.ctrl }; var buf: [64]u8 = undefined; if (p.mouse_grab) |*grab| { + if (grab.unshift) mods.shift = false; const pane = p.panes[grab.id] orelse { p.mouse_grab = null; return false; @@ -400,7 +410,10 @@ fn programMouse(p: *Pardes, m: Mouse) bool { if (grab.held == 0) p.mouse_grab = null; return true; } - if (m.shift or p.drag != .none or p.header_drag or p.header_sweep != null) return false; + if (p.drag != .none or p.header_drag or p.header_sweep != null) return false; + const shifted_to_program = m.button == .middle or m.button == .right; + if (m.shift != shifted_to_program) return false; + if (shifted_to_program) mods.shift = false; const mapped = at orelse return false; const id = paneAt(p, mapped.col, mapped.row) orelse return false; const pane = p.panes[id].?; @@ -415,7 +428,7 @@ fn programMouse(p: *Pardes, m: Mouse) bool { p.active = id; pane.focus = .body; pane.closePrompt(); - p.mouse_grab = .{ .id = id, .serial = pane.serial, .held = bit }; + p.mouse_grab = .{ .id = id, .serial = pane.serial, .held = bit, .unshift = shifted_to_program }; const bytes = panes.terminal.mouseBytes(pane, &buf, .press, button, mods, cell.col, cell.row, true); if (bytes.len > 0) p.emitWrite(id, bytes); return true; @@ -2033,9 +2046,17 @@ test "a program tracking the mouse gets its clicks, drags and moves over its gri // 1000 has no drags; the release is reported where it lands. try std.testing.expectEqualStrings("", try send(p, &out, col, row, .{ .button = .left, .kind = .drag, .dx = 1 })); try std.testing.expectEqualStrings("\x1b[<0;7;4m", try send(p, &out, col, row, .{ .button = .left, .kind = .release, .dx = 1 })); - // Right with meta and ctrl: 2 + 8 + 16. - try std.testing.expectEqualStrings("\x1b[<26;6;4M", try send(p, &out, col, row, .{ .button = .right, .kind = .press, .alt = true, .ctrl = true })); - try std.testing.expectEqualStrings("\x1b[<2;6;4m", try send(p, &out, col, row, .{ .button = .right, .kind = .release })); + // B2 and B3 are pardes's execute and look, as in any pane. + try std.testing.expectEqualStrings("", try send(p, &out, col, row, .{ .button = .right, .kind = .press })); + try std.testing.expect(p.drag == .select); + try std.testing.expectEqualStrings("", try send(p, &out, col, row, .{ .button = .right, .kind = .release })); + try std.testing.expect(p.drag == .none); + // Shift-B3 is the program's, the Shift that chose it left out: meta + // and ctrl, 2 + 8 + 16. + try std.testing.expectEqualStrings("\x1b[<26;6;4M", try send(p, &out, col, row, .{ .button = .right, .kind = .press, .shift = true, .alt = true, .ctrl = true })); + try std.testing.expectEqualStrings("\x1b[<2;6;4m", try send(p, &out, col, row, .{ .button = .right, .kind = .release, .shift = true })); + try std.testing.expectEqualStrings("\x1b[<1;6;4M", try send(p, &out, col, row, .{ .button = .middle, .kind = .press, .shift = true })); + try std.testing.expectEqualStrings("\x1b[<1;6;4m", try send(p, &out, col, row, .{ .button = .middle, .kind = .release })); // Moves are no 1000 program's business: pardes hovers. try std.testing.expectEqualStrings("", try send(p, &out, col, row, .{ .button = .none, .kind = .motion })); // Shift: pardes's own sweep, the program hears nothing of it. @@ -2066,6 +2087,14 @@ test "a program tracking the mouse gets its clicks, drags and moves over its gri try std.testing.expect(p.mouse_grab == null); // Over the tag a bare move is pardes's. try std.testing.expectEqualStrings("", try send(p, &out, col, tag_row, .{ .button = .none, .kind = .motion })); + // B2 held for pardes: its sweep's moves are not the program's; held + // for the program with Shift, they are its button-2 drags. + try std.testing.expectEqualStrings("", try send(p, &out, col, row, .{ .button = .middle, .kind = .press })); + try std.testing.expectEqualStrings("", try send(p, &out, col, row, .{ .button = .middle, .kind = .drag, .dx = 1 })); + try std.testing.expectEqualStrings("", try send(p, &out, col, row, .{ .button = .middle, .kind = .release, .dx = 1 })); + try std.testing.expectEqualStrings("\x1b[<1;6;4M", try send(p, &out, col, row, .{ .button = .middle, .kind = .press, .shift = true })); + try std.testing.expectEqualStrings("\x1b[<33;7;4M", try send(p, &out, col, row, .{ .button = .middle, .kind = .drag, .dx = 1, .shift = true })); + try std.testing.expectEqualStrings("\x1b[<1;7;4m", try send(p, &out, col, row, .{ .button = .middle, .kind = .release, .dx = 1, .shift = true })); // Legacy X10 bytes: a release is button 3. (Turning 1003 off turns // tracking off, as xterm's one tracking mode goes.) |
