summaryrefslogtreecommitdiff
path: root/term.zig
diff options
context:
space:
mode:
Diffstat (limited to 'term.zig')
-rw-r--r--term.zig213
1 files changed, 0 insertions, 213 deletions
diff --git a/term.zig b/term.zig
deleted file mode 100644
index 7201c7c7..00000000
--- a/term.zig
+++ /dev/null
@@ -1,213 +0,0 @@
-const std = @import("std");
-const ghostty_vt = @import("ghostty-vt");
-const image_mod = @import("image.zig");
-
-/// One text selection (block-shaped), in pane-local coords; the row carries the
-/// scrollback offset. .none == nothing selected.
-pub const Sel = struct {
- state: enum { none, dragging, done } = .none,
- c0: i32 = 0,
- c1: i32 = 0,
- r0: i32 = 0,
- r1: i32 = 0,
-};
-
-/// 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;
-/// v/x select; Esc collapses the selection; configured Ctrl key -> tty (terminals).
-/// insert -> keys insert text at the cursor (acme click-and-type); Esc -> normal.
-/// tty -> keys -> pty as terminal sequences. The mouse stays usable here (it
-/// selects/copies without dropping you back to normal); the configured Ctrl key exits.
-pub const Mode = enum { normal, insert, tty };
-
-/// A modal line selection (helix `x` extends the selection down line by line).
-/// r0/r1 are ABSOLUTE body rows (visual + scroll off). active == false means the
-/// cursor is a plain 1-char selection (normal mode default).
-pub const LineSel = struct {
- active: bool = false,
- r0: i32 = 0,
- 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
-
-/// A file pane's backing state (see the `file` field below).
-pub const File = struct {
- path: []const u8, // gpa-owned absolute path
- content: []u8, // gpa-owned file bytes
- scroll: usize = 0, // top visible file line
- /// tree-sitter syntax styles, one byte per `content` byte (0 = none). Empty
- /// when the file's language isn't highlighted. gpa-owned. `highlight_start`
- /// is the content byte offset represented by `highlights[0]`.
- highlights: []u8 = &.{},
- highlight_start: usize = 0,
- /// The content or viewport changed since `highlights` was refreshed for the
- /// visible byte window.
- syntax_dirty: bool = false,
- /// 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
-/// spliced in *before* — the run shifts the underlying row right, it doesn't
-/// overwrite. `row`/`col` are pane-local (row carries the BOX_H tag offset).
-pub const Edit = struct {
- row: i32 = 0,
- col: i32 = 0,
- len: u16 = 0,
- 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,
-};
-
-pub const CwdOscState = enum { normal, esc, osc, osc7, collect, st_esc };
-
-/// 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.
-///
-/// Heap-allocate these and never move them: `stream`'s handler holds a pointer
-/// back into `term`, so the address must stay stable for parser state split
-/// across pty reads to keep working.
-pub const Term = @This();
-
-pty: std.Io.File,
-pid: std.posix.pid_t, // shell child; Linux uses /proc/<pid>/cwd for live cwd tags
-term: ghostty_vt.Terminal,
-stream: ghostty_vt.TerminalStream,
-reader: std.Io.Future(anyerror!void),
-/// Last known shell cwd for platforms without Linux procfs. macOS updates this
-/// from OSC 7 emitted by our shell rc; BSDs use the spawn cwd as a fallback.
-cwd: ?[]u8 = null,
-cwd_osc_state: CwdOscState = .normal,
-cwd_osc: std.ArrayList(u8) = .empty,
-
-/// When set, this pane is a (read/editable) text FILE view, not a terminal: its
-/// body comes from `content` instead of the emulator, and all the tty-specific
-/// handling (pty io, modes, prompt hiding) is skipped. Everything else — layout,
-/// selection, char-mode editing — is shared. pty.handle is -1, reader is a no-op.
-file: ?File = null,
-
-/// When set, this pane displays an image (kitty graphics) instead of text. Like a
-/// file pane it has no pty/reader (handle -1) and a stub emulator; the render loop
-/// transmits + draws it. See image.zig. Mutually exclusive with `file`.
-image: ?image_mod.View = null,
-
-/// A freshly forked terminal greets with `ls` once it has its real geometry. Set
-/// at fork; the resize loop fires the `ls` after sizing the pty, so the listing
-/// wraps to the right width (sending it at fork time uses the wrong, full size).
-greet: bool = false,
-
-/// current emulator grid size; we only push a resize when it actually changes.
-cols: u16,
-rows: u16,
-
-/// Raw bytes read from the pty and fed into ghostty. Dump/replay uses this as the
-/// backend-neutral terminal recording instead of serialized rendered cells.
-tty_stream: std.ArrayList(u8) = .empty,
-
-/// vertical weight within the column (siblings split the column height by this).
-vweight: f32 = 1,
-
-/// One independent selection per mouse button: 0=left, 1=middle, 2=right.
-sel: [3]Sel = .{ .{}, .{}, .{} },
-
-/// modal input mode (see Mode). DEFAULT is normal (helix): a block cursor that
-/// moves with hjkl; i/a/o enter insert; Esc reaches tty on terminals.
-mode: Mode = .normal,
-/// one pending prefix codepoint (0 = none): `g` (gg/ge/...) and `z` (zt/zz/zb).
-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
-/// user clicks or types, while which the cursor tracks the shell's cursor.
-///
-/// For terminals in normal mode cur_col is a VISUAL column; in insert mode it is
-/// the original-tty column the run is anchored at (renderedCol maps it to visual).
-/// For file panes cur_col is a content column (no edit runs; edits stay empty).
-cur_pinned: bool = false,
-cur_row: i32 = 0,
-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,
-
-/// Editable "tail" of the tag line: everything after the live mode + cwd/path
-/// prefix (the builtin command names and anything the user types). Seeded with
-/// the default builtins the first time the tag is edited (`tag_init`), then
-/// freely editable — no newlines. `tag_col` is the cursor's byte index within
-/// the tail; `tag_edit` is true while the tag is focused for editing. Image
-/// panes keep a live (non-editable) tag, so these stay unused for them.
-tag_tail: std.ArrayList(u8) = .empty,
-tag_col: u16 = 0,
-tag_init: bool = false,
-tag_edit: bool = false,
-/// helix `v` char-select within the tag: inclusive [anchor, tag_col]. The tag
-/// shares the pane's `mode` (normal/insert), so no separate mode is kept.
-tag_sel: bool = false,
-tag_anchor: u16 = 0,
-
-/// A real shell pane (has a pty/emulator), as opposed to a file or image view.
-pub fn isTerminal(self: *const Term) bool {
- return self.file == null and self.image == null;
-}
-
-pub fn deinit(self: *Term, io: std.Io, gpa: std.mem.Allocator) void {
- 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);
- image_mod.deinitView(iv, gpa);
- } else {
- _ = self.reader.cancel(io) catch {};
- self.pty.close(io);
- }
- self.tty_stream.deinit(gpa);
- if (self.cwd) |cwd| gpa.free(cwd);
- self.cwd_osc.deinit(gpa);
- self.ed_undo.deinit(gpa);
- self.ed_redo.deinit(gpa);
- self.tag_tail.deinit(gpa);
- self.stream.deinit();
- self.term.deinit(gpa);
-}