From 02ea4db25f9802e76112f3b4e69aa75e5a9464dc Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Tue, 15 Sep 2026 18:41:15 -0300 Subject: Default location results to stacked addresses and source previews --- src/locations.zig | 121 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 83 insertions(+), 38 deletions(-) (limited to 'src/locations.zig') diff --git a/src/locations.zig b/src/locations.zig index 0f580e34..97caf1d9 100644 --- a/src/locations.zig +++ b/src/locations.zig @@ -15,7 +15,7 @@ pub fn isContextLine(line: []const u8) bool { } pub const Row = struct { - kind: enum { match, context }, + kind: enum { match, context, preview }, declaration: bool = false, path: []u8, at: look.Spot, @@ -44,15 +44,16 @@ pub fn equalRows(a: []const Row, b: []const Row) bool { /// Compare native producer rows with an already formatted, context-free view. /// Identical refreshes retain allocations, syntax and selection state. -pub fn sameInput(input: []const u8, rendered: []const u8, rows: []const Row) bool { +pub fn sameInput(input: []const u8, rendered: []const u8, rows: []const Row, layout: Config.Layout) bool { if (rows.len == 0) return std.mem.eql(u8, input, rendered); - if (std.mem.endsWith(u8, input, "\n") != std.mem.endsWith(u8, rendered, "\n")) return false; var raw_lines = std.mem.splitScalar(u8, input, '\n'); var shown_lines = std.mem.splitScalar(u8, rendered, '\n'); var width: usize = 0; - for (rows, 0..) |row, index| { + var index: usize = 0; + while (index < rows.len) { + const row = rows[index]; if (row.kind != .match) return false; - if (index % alignment_entries == 0) { + if (layout == .@"inline" and index % alignment_entries == 0) { width = 0; var chunk = raw_lines; for (0..alignment_entries) |_| { @@ -64,9 +65,19 @@ pub fn sameInput(input: []const u8, rendered: []const u8, rows: []const Row) boo const raw = raw_lines.next() orelse return false; const shown = shown_lines.next() orelse return false; const target = parseRaw(raw); - if (target.end != row.location_end or row.code_start > shown.len or - !std.mem.eql(u8, raw[0..target.end], shown[0..row.location_end]) or - !std.mem.eql(u8, raw[target.code_start..], shown[row.code_start..])) return false; + if (target.end != row.location_end or row.location_end > shown.len or row.code_start > shown.len or + !std.mem.eql(u8, raw[0..target.end], shown[0..row.location_end])) return false; + if (layout == .stacked) { + if (shown.len != row.location_end or row.code_start != shown.len or index + 1 >= rows.len) return false; + const preview = rows[index + 1]; + if (preview.kind != .preview or preview.location_end != 0 or preview.code_start != 0 or + !std.meta.eql(row.at, preview.at) or !std.mem.eql(u8, row.path, preview.path)) return false; + const code = shown_lines.next() orelse return false; + if (!std.mem.eql(u8, raw[target.code_start..], code)) return false; + index += 2; + continue; + } + if (!std.mem.eql(u8, raw[target.code_start..], shown[row.code_start..])) return false; // A restored result may still have the old pane-wide padding. Do not // let the identical-input shortcut retain that layout when rerun. if (row.code_start <= row.location_end) return false; @@ -74,9 +85,14 @@ pub fn sameInput(input: []const u8, rendered: []const u8, rows: []const Row) boo if (padding.len != width - pardes.panes.File.displayWidth(raw[0..target.end]) + 1 or padding[padding.len - 1] != '\t') return false; for (padding[0 .. padding.len - 1]) |byte| if (byte != ' ') return false; + index += 1; } - if (raw_lines.next()) |tail| if (tail.len != 0) return false; - return raw_lines.next() == null; + const raw_tail = raw_lines.next(); + const shown_tail = shown_lines.next(); + if ((raw_tail == null) != (shown_tail == null)) return false; + if (raw_tail) |tail| if (tail.len != 0) return false; + if (shown_tail) |tail| if (tail.len != 0) return false; + return raw_lines.next() == null and shown_lines.next() == null; } pub const Parsed = struct { @@ -246,44 +262,73 @@ pub fn format(p: *pardes.Pardes, dir: []const u8, input: []const u8, anchor: ?us rows.deinit(p.gpa); } var mapped = anchor; - first = 0; - while (first < pending.items.len) { - const end = alignmentEnd(pending.items, first); - var width: usize = 0; - for (pending.items[first..end]) |row| width = @max(width, labelWidth(row)); - for (pending.items[first..end], first..) |row, index| { - const before = out.written().len; + if (p.locations_config.layout == .stacked) { + for (pending.items, 0..) |row, index| { const context = row.original == null; - try out.writer.writeAll(row.label); - const location_end = if (row.hidden) 0 else out.written().len - before; - if (row.depth > 0) { - try out.writer.writeByte(' '); - try out.writer.splatByteAll('*', row.depth); - } - try out.writer.splatByteAll(' ', width - labelWidth(row)); - try out.writer.writeByte('\t'); - const code_start = out.written().len - before; - try out.writer.writeAll(row.code); - if (row.declaration and index + 1 < pending.items.len) { - const next = pending.items[index + 1]; - if (std.mem.eql(u8, row.path, next.path) and next.at.line -| row.at.line > 1) - try out.writer.writeAll(" ..."); + if (anchor != null and row.original == anchor) mapped = rows.items.len; + if (!row.hidden) { + const before = out.written().len; + try out.writer.writeAll(row.label); + if (row.depth > 0) { + try out.writer.writeByte(' '); + try out.writer.splatByteAll('*', row.depth); + } + try appendMetadata(p.gpa, &rows, row, if (context) .context else .match, row.label.len, out.written().len - before, false); + try out.writer.writeByte('\n'); } + try writeCode(&out.writer, pending.items, index); + try appendMetadata(p.gpa, &rows, row, if (context) .context else .preview, 0, 0, true); if (index + 1 < pending.items.len or std.mem.endsWith(u8, input, "\n")) try out.writer.writeByte('\n'); - const owned_path = try p.gpa.dupe(u8, row.path); - errdefer p.gpa.free(owned_path); - const owned_colors = try p.gpa.dupe(u8, row.colors); - errdefer p.gpa.free(owned_colors); - try rows.append(p.gpa, .{ .kind = if (context) .context else .match, .declaration = row.declaration, .path = owned_path, .at = row.at, .location_end = location_end, .code_start = code_start, .colors = owned_colors }); - if (anchor != null and row.original == anchor) mapped = index; } - first = end; + } else { + first = 0; + while (first < pending.items.len) { + const end = alignmentEnd(pending.items, first); + var width: usize = 0; + for (pending.items[first..end]) |row| width = @max(width, labelWidth(row)); + for (pending.items[first..end], first..) |row, index| { + const before = out.written().len; + const context = row.original == null; + try out.writer.writeAll(row.label); + const location_end = if (row.hidden) 0 else out.written().len - before; + if (row.depth > 0) { + try out.writer.writeByte(' '); + try out.writer.splatByteAll('*', row.depth); + } + try out.writer.splatByteAll(' ', width - labelWidth(row)); + try out.writer.writeByte('\t'); + const code_start = out.written().len - before; + try writeCode(&out.writer, pending.items, index); + if (index + 1 < pending.items.len or std.mem.endsWith(u8, input, "\n")) try out.writer.writeByte('\n'); + try appendMetadata(p.gpa, &rows, row, if (context) .context else .match, location_end, code_start, true); + if (anchor != null and row.original == anchor) mapped = index; + } + first = end; + } } const owned_rows = try rows.toOwnedSlice(p.gpa); errdefer freeRows(p.gpa, owned_rows); return .{ .content = try out.toOwnedSlice(), .rows = owned_rows, .anchor = mapped }; } +fn writeCode(writer: *std.Io.Writer, rows: []const Pending, index: usize) !void { + const row = rows[index]; + try writer.writeAll(row.code); + if (row.declaration and index + 1 < rows.len) { + const next = rows[index + 1]; + if (std.mem.eql(u8, row.path, next.path) and next.at.line -| row.at.line > 1) + try writer.writeAll(" ..."); + } +} + +fn appendMetadata(gpa: std.mem.Allocator, rows: *std.ArrayList(Row), pending: Pending, kind: @FieldType(Row, "kind"), location_end: usize, code_start: usize, source: bool) !void { + const path = try gpa.dupe(u8, pending.path); + errdefer gpa.free(path); + const colors = try gpa.dupe(u8, if (source) pending.colors else &.{}); + errdefer gpa.free(colors); + try rows.append(gpa, .{ .kind = kind, .declaration = pending.declaration, .path = path, .at = pending.at, .location_end = location_end, .code_start = code_start, .colors = colors }); +} + const alignment_entries = 8; /// Keep neighboring context with the nearer match at a chunk boundary. Shared -- cgit v1.3