summaryrefslogtreecommitdiff
path: root/term.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-06-30 20:29:05 -0300
committerGabriel Schneider <[email protected]>2026-06-30 20:29:27 -0300
commit8b60c2c29c016c7db0fa6ee63769cea1defd9b3c (patch)
tree24935a622521142b3754df6de0a95c6cef5a5e18 /term.zig
parent1f65d7368c9a31427b145f683eb891da16181b73 (diff)
downloadpardes-8b60c2c29c016c7db0fa6ee63769cea1defd9b3c.tar.gz
pardes-8b60c2c29c016c7db0fa6ee63769cea1defd9b3c.zip
minor fixes
Diffstat (limited to 'term.zig')
-rw-r--r--term.zig47
1 files changed, 44 insertions, 3 deletions
diff --git a/term.zig b/term.zig
index c4fe0d93..9ef6ff02 100644
--- a/term.zig
+++ b/term.zig
@@ -15,9 +15,10 @@ pub const Sel = struct {
/// Modal input mode. normal/insert are the helix-style text-editing modes; tty
/// forwards keys to the shell (terminal panes only — file panes never use it).
/// normal -> helix NORMAL: hjkl/w/b/e/... move a block cursor; i/a/o -> insert;
-/// Esc -> tty (terminals) or stays (files).
+/// v/x select; Esc collapses the selection; Ctrl-b -> tty (terminals).
/// insert -> keys insert text at the cursor (acme click-and-type); Esc -> normal.
-/// tty -> keys -> pty as terminal sequences; a body left-click returns to normal.
+/// tty -> keys -> pty as terminal sequences. The mouse stays usable here (it
+/// selects/copies without dropping you back to normal); Ctrl-b exits.
pub const Mode = enum { normal, insert, tty };
/// A modal line selection (helix `x` extends the selection down line by line).
@@ -29,6 +30,16 @@ pub const LineSel = struct {
r1: i32 = 0,
};
+/// A modal character-range selection (helix `v` select mode). The anchor is here
+/// (row/col in the same coords as the cursor: ABSOLUTE body row; content col for
+/// files, visual col for terminals); the head is the cursor. Motions extend it;
+/// d/c/y act on [anchor, cursor] inclusive. Mutually exclusive with LineSel.
+pub const CharSel = struct {
+ active: bool = false,
+ row: i32 = 0,
+ col: i32 = 0,
+};
+
pub const EDIT_CAP = 128; // max chars in one insertion run
pub const MAX_EDITS = 16; // max concurrent insertion runs per window
@@ -40,6 +51,11 @@ pub const File = struct {
/// tree-sitter syntax styles, one byte per `content` byte (0 = none). Empty
/// when the file's language isn't highlighted. gpa-owned. See main.highlightFile.
highlights: []u8 = &.{},
+ /// dumb whole-content undo/redo: each entry is a gpa-owned snapshot of
+ /// `content`. main.pushUndo snapshots before an edit (one per insert session /
+ /// delete / paste); `u`/`U` move between them. Bounded (oldest dropped).
+ undo: std.ArrayList([]u8) = .empty,
+ redo: std.ArrayList([]u8) = .empty,
};
/// A run of inserted ("char mode") text. `col` is the ORIGINAL tty column it is
@@ -52,6 +68,17 @@ pub const Edit = struct {
text: [EDIT_CAP]u8 = undefined,
};
+/// A dumb whole-state snapshot of a terminal pane's char-mode insertions, for
+/// undo/redo (the terminal analogue of File's content snapshots). Plain value —
+/// the edits array has no pointers — so it copies by assignment, no allocation.
+pub const EditSnap = struct {
+ edits: [MAX_EDITS]Edit,
+ nedits: usize,
+ cur_row: i32,
+ cur_col: i32,
+ cur_off: u16,
+};
+
/// Persistent per-terminal state: the pty handle, the ghostty emulator and its
/// (stateful) VT parser, the background reader task, plus its layout weight and
/// text selection.
@@ -100,6 +127,9 @@ mode: Mode = .normal,
pending: u21 = 0,
/// modal line selection from `x` (helix extend-line). In absolute body rows.
msel: LineSel = .{},
+/// modal character-range selection from `v` (helix select). Anchor is here, head
+/// is the cursor. Mutually exclusive with `msel`.
+vsel: CharSel = .{},
/// cursor and edits are anchored at ABSOLUTE body rows (visual row + scroll
/// offset) so they ride the scrollback, not the screen. `cur_off` is the offset
/// into the run sitting at (cur_row, cur_col). `cur_pinned` is false until the
@@ -114,6 +144,11 @@ cur_col: i32 = 0,
cur_off: u16 = 0,
nedits: usize = 0,
edits: [MAX_EDITS]Edit = @splat(.{}),
+/// terminal char-mode undo/redo: snapshots of the edit state, one per edit op
+/// (insert session / delete / paste). File panes use File.undo/redo instead;
+/// these stay empty for them. See main.pushUndo/doUndo.
+ed_undo: std.ArrayList(EditSnap) = .empty,
+ed_redo: std.ArrayList(EditSnap) = .empty,
/// A real shell pane (has a pty/emulator), as opposed to a file or image view.
pub fn isTerminal(self: *const Term) bool {
@@ -121,16 +156,22 @@ pub fn isTerminal(self: *const Term) bool {
}
pub fn deinit(self: *Term, io: std.Io, gpa: std.mem.Allocator) void {
- if (self.file) |f| {
+ if (self.file) |*f| {
gpa.free(f.path);
gpa.free(f.content);
if (f.highlights.len > 0) gpa.free(f.highlights);
+ for (f.undo.items) |s| gpa.free(s);
+ for (f.redo.items) |s| gpa.free(s);
+ f.undo.deinit(gpa);
+ f.redo.deinit(gpa);
} else if (self.image) |iv| {
gpa.free(iv.path);
} else {
_ = self.reader.cancel(io) catch {};
self.pty.close(io);
}
+ self.ed_undo.deinit(gpa);
+ self.ed_redo.deinit(gpa);
self.stream.deinit();
self.term.deinit(gpa);
}