summaryrefslogtreecommitdiff
path: root/src/File.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-10-01 10:09:54 -0300
committerGabriel Schneider <[email protected]>2026-10-01 10:36:28 -0300
commitedad6d960dc0fc1165cbb3b801e0538045b2247f (patch)
tree0bedfbb9cd371e5d77cb697438c5198c688653c5 /src/File.zig
parent4db57bf5bd788a292fcf2cfbea3b6d8b281510f0 (diff)
downloadpardes-edad6d960dc0fc1165cbb3b801e0538045b2247f.tar.gz
pardes-edad6d960dc0fc1165cbb3b801e0538045b2247f.zip
A +Pager keeps its program's colours: the session parses what /pager is written after its directory with ghostty-vt, SGR becomes spans drawn over the plain text, every other escape is dropped, and PagerColor off pages it plain
Diffstat (limited to 'src/File.zig')
-rw-r--r--src/File.zig40
1 files changed, 39 insertions, 1 deletions
diff --git a/src/File.zig b/src/File.zig
index 4fac0073..b3c28290 100644
--- a/src/File.zig
+++ b/src/File.zig
@@ -75,6 +75,11 @@ pub const State = struct {
/// A +Pager pane (`pardes -`) whose text is a diff (`git diff`, `show`,
/// `log -p`): drawn and looked at as a diff (Pane.colorAlgo).
pager_diff: bool = false,
+ /// A +Pager's colours, as its program printed them (pager.zig): drawn
+ /// over its text by recolorSyntax, never read over 9P. ponytail: any
+ /// edit drops them (setContentSpan); shifting them through the splice,
+ /// as pane.zig's shiftOne moves dot, would keep them.
+ pager_spans: []pardes.pager.Span = &.{},
/// Seconds of the last content change, for the filesystem's stat; zero until edited.
mtime: u32 = 0,
/// Non-null for a generated output buffer rather than an on-disk file.
@@ -982,6 +987,7 @@ pub fn deinit(p: *Pardes, pane: *Pane, file: *State) void {
if (file.mini) |*mini| mini.deinit(p.gpa);
if (file.line_starts.len > 0) p.gpa.free(file.line_starts);
if (file.highlights.len > 0) p.tree_sitter_gpa.free(file.highlights);
+ p.gpa.free(file.pager_spans);
locations.freeRows(p.gpa, file.location_rows);
if (file.context_declarations.len > 0) p.tree_sitter_gpa.free(file.context_declarations);
if (file.node_tree) |tree| syntax.freeTree(tree);
@@ -1010,6 +1016,8 @@ pub fn setContent(p: *Pardes, f: *State, new: []u8) void {
pub fn setContentSpan(p: *Pardes, f: *State, new: []u8, span: ?Span) void {
locations.freeRows(p.gpa, f.location_rows);
f.location_rows = &.{};
+ p.gpa.free(f.pager_spans);
+ f.pager_spans = &.{};
for (p.panes) |slot| if (slot) |pane| {
if (pane.file) |*file| if (file == f) {
for (0..pane.sel.len) |button| {
@@ -1483,7 +1491,8 @@ fn synStyle(p: *Pardes, sy: syntax.Syn) ?SynStyle {
pub fn recolorSyntax(p: *Pardes, s: *Surface, pane: *Pane, f: *State, r: pardes.Rect, tx: u16, tw: u16, body_h: u16) void {
const highlights = if (f.mini) |mini| mini.colors else f.highlights;
const highlight_start = if (f.mini != null) 0 else f.highlight_start;
- if (highlights.len == 0 and f.output == null) return;
+ const spans = f.pager_spans;
+ if (highlights.len == 0 and f.output == null and spans.len == 0) return;
const prefix_width = gutterWidth(pane);
const tz_recolor = tracy.zone(@src(), "synRecolor");
defer tz_recolor.end();
@@ -1526,6 +1535,14 @@ pub fn recolorSyntax(p: *Pardes, s: *Surface, pane: *Pane, f: *State, r: pardes.
else
null else null;
if (tint) |t| if (prefix_width < tw) tintRow(s, tx + @as(u16, @intCast(prefix_width)), body_y + vr, tx + tw, t.bg);
+ // A +Pager's own colours (pager.zig) on every row but one the diff
+ // look tints: an added or removed line is drawn as pardes draws a
+ // diff, and git's red and green on it would only fight the tint.
+ var span_at = if (tint != null) spans.len else std.sort.partitionPoint(pardes.pager.Span, spans, base + hs, struct {
+ fn before(at: usize, span: pardes.pager.Span) bool {
+ return span.end <= at;
+ }
+ }.before);
var c: usize = 0;
var screen_c: usize = 0;
while (hs + c < limit and prefix_width + screen_c < tw) {
@@ -1562,6 +1579,27 @@ pub fn recolorSyntax(p: *Pardes, s: *Surface, pane: *Pane, f: *State, r: pardes.
if (style.bg != .default) cell.style.bg = style.bg;
}
}
+ while (span_at < spans.len and spans[span_at].end <= idx) span_at += 1;
+ if (span_at < spans.len and spans[span_at].start <= idx) {
+ const st = spans[span_at].style;
+ var fill: usize = 0;
+ while (fill < cells and prefix_width + screen_c + fill < tw) : (fill += 1) {
+ const cell = s.at(tx + @as(u16, @intCast(prefix_width + screen_c + fill)), body_y + vr);
+ if (cell.default) continue;
+ // A palette colour through the theme's sixteen, as a
+ // terminal pane's cell; truecolor as it is.
+ if (st.fg != .default) cell.style.fg = if (st.fg == .index) terminal.palColor(p, st.fg.index) else st.fg;
+ if (st.bg != .default) cell.style.bg = if (st.bg == .index) terminal.palColor(p, st.bg.index) else st.bg;
+ cell.style.bold = cell.style.bold or st.bold;
+ cell.style.dim = st.dim;
+ cell.style.italic = st.italic;
+ cell.style.blink = st.blink;
+ cell.style.reverse = st.reverse;
+ cell.style.invisible = st.invisible;
+ cell.style.strikethrough = st.strikethrough;
+ if (st.ul != .off) cell.style.ul = st.ul;
+ }
+ }
screen_c += cells;
c = grapheme_end - hs;
}