diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-15 18:41:15 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:14 -0300 |
| commit | 02ea4db25f9802e76112f3b4e69aa75e5a9464dc (patch) | |
| tree | daa17ec75135e055a60eff982d97057dcd109c25 /src/syntax.zig | |
| parent | 505dedb2459e7b51cbdb0c066698c6e5596d19dd (diff) | |
| download | pardes-02ea4db25f9802e76112f3b4e69aa75e5a9464dc.tar.gz pardes-02ea4db25f9802e76112f3b4e69aa75e5a9464dc.zip | |
Default location results to stacked addresses and source previews
Diffstat (limited to 'src/syntax.zig')
| -rw-r--r-- | src/syntax.zig | 111 |
1 files changed, 73 insertions, 38 deletions
diff --git a/src/syntax.zig b/src/syntax.zig index bd6a64a0..9e31669f 100644 --- a/src/syntax.zig +++ b/src/syntax.zig @@ -630,48 +630,58 @@ pub fn highlightLocationRows(gpa: std.mem.Allocator, content: []const u8, rows: defer gpa.free(code); const colors = try gpa.alloc(u8, content.len); defer gpa.free(colors); - var painted = false; - var row_index: usize = 0; + const SourceRow = struct { index: usize, start: usize, len: usize }; + const sources = try gpa.alloc(SourceRow, rows.len); + defer gpa.free(sources); + var source_count: usize = 0; var offset: usize = 0; - while (row_index < rows.len and offset < content.len) { - const first = row_index; - const group_start = offset; - const selected = (forExt(std.fs.path.extension(rows[first].path)) catch null); - var code_len: usize = 0; - while (row_index < rows.len and offset < content.len) { - const row = rows[row_index]; - if (row_index > first and (!std.mem.eql(u8, row.path, rows[first].path) or - row.at.line != rows[row_index - 1].at.line +| 1)) break; - const end = std.mem.indexOfScalarPos(u8, content, offset, '\n') orelse content.len; - const source_start = offset + @min(row.code_start, end - offset); - if (row_index > first) { - code[code_len] = '\n'; - code_len += 1; - } - @memcpy(code[code_len..][0 .. end - source_start], content[source_start..end]); - code_len += end - source_start; - offset = @min(end + 1, content.len); - row_index += 1; + for (rows, 0..) |row, index| { + if (offset >= content.len) break; + const end = std.mem.indexOfScalarPos(u8, content, offset, '\n') orelse content.len; + const source_start = offset + @min(row.code_start, end - offset); + var address_only = false; + if (comptime @hasField(@TypeOf(row), "location_end")) { + address_only = row.location_end > 0 and source_start == end; } - const language = selected orelse continue; - if (offset > 0 and content[offset - 1] == '\n') { - code[code_len] = '\n'; - code_len += 1; + if (!address_only) { + sources[source_count] = .{ .index = index, .start = source_start, .len = end - source_start }; + source_count += 1; } - if (code_len == 0) continue; - @memset(colors[0..code_len], 0); - paint(colors[0..code_len], code[0..code_len], language); - painted = true; - var target = group_start; - var source_offset: usize = 0; - for (rows[first..row_index]) |row| { - const end = std.mem.indexOfScalarPos(u8, content, target, '\n') orelse content.len; - const source_start = target + @min(row.code_start, end - target); - const len = end - source_start; - @memcpy(styles[source_start..end], colors[source_offset..][0..len]); - source_offset += len + 1; - target = @min(end + 1, content.len); + offset = @min(end + 1, content.len); + } + var painted = false; + var first: usize = 0; + while (first < source_count) { + const first_row = rows[sources[first].index]; + var end = first + 1; + while (end < source_count) : (end += 1) { + const row = rows[sources[end].index]; + const previous = rows[sources[end - 1].index]; + if (!std.mem.eql(u8, row.path, first_row.path) or row.at.line != previous.at.line +| 1) break; } + const language = (forExt(std.fs.path.extension(first_row.path)) catch null); + if (language) |selected| { + var code_len: usize = 0; + for (sources[first..end]) |source| { + @memcpy(code[code_len..][0..source.len], content[source.start..][0..source.len]); + code_len += source.len; + if (code_len < code.len) { + code[code_len] = '\n'; + code_len += 1; + } + } + if (code_len > 0) { + @memset(colors[0..code_len], 0); + paint(colors[0..code_len], code[0..code_len], selected); + painted = true; + var at: usize = 0; + for (sources[first..end]) |source| { + @memcpy(styles[source.start..][0..source.len], colors[at..][0..source.len]); + at += source.len + 1; + } + } + } + first = end; } // A shown context range can begin inside a comment/string whose opener was // omitted. Formatter snapshots from the complete source take precedence, @@ -1244,3 +1254,28 @@ test "syntax declaration locations clear snapshots without muting ordinary conte for (styles[3..][0..header.len]) |style| try std.testing.expectEqual(@as(u8, 0), style); try std.testing.expectEqual(@intFromEnum(Syn.number), styles[std.mem.indexOf(u8, content, "42").?]); } + +test "syntax stacked addresses do not split multiline source groups" { + if (!enabled or (!minimal_grammars and !full_grammars)) return; + const gpa = std.testing.allocator; + start(gpa); + defer stop(); + const Row = struct { path: []const u8 = "a.c", code_start: usize, location_end: usize, at: look.Spot }; + const content = "a.c:1:1\n/* open\na.c:2:1\nint value = 42;\na.c:3:1\n*/ int other = 7;\n"; + const rows = [_]Row{ + .{ .code_start = 7, .location_end = 7, .at = .{ .line = 1 } }, + .{ .code_start = 0, .location_end = 0, .at = .{ .line = 1 } }, + .{ .code_start = 7, .location_end = 7, .at = .{ .line = 2 } }, + .{ .code_start = 0, .location_end = 0, .at = .{ .line = 2 } }, + .{ .code_start = 7, .location_end = 7, .at = .{ .line = 3 } }, + .{ .code_start = 0, .location_end = 0, .at = .{ .line = 3 } }, + }; + const styles = try highlightLocationRows(gpa, content, &rows); + defer gpa.free(styles); + try std.testing.expectEqual(@intFromEnum(Syn.comment), styles[std.mem.indexOf(u8, content, "42").?]); + try std.testing.expectEqual(@intFromEnum(Syn.number), styles[std.mem.indexOf(u8, content, "7;").?]); + for ([_][]const u8{ "a.c:1:1", "a.c:2:1", "a.c:3:1" }) |label| { + const at = std.mem.indexOf(u8, content, label).?; + for (styles[at..][0..label.len]) |style| try std.testing.expectEqual(@intFromEnum(Syn.none), style); + } +} |
