summaryrefslogtreecommitdiff
path: root/main.zig
diff options
context:
space:
mode:
Diffstat (limited to 'main.zig')
-rw-r--r--main.zig141
1 files changed, 133 insertions, 8 deletions
diff --git a/main.zig b/main.zig
index 5ac51a42..13450063 100644
--- a/main.zig
+++ b/main.zig
@@ -1,6 +1,12 @@
const std = @import("std");
const vaxis = @import("vaxis");
const ghostty_vt = @import("ghostty-vt");
+const ts = @import("tree-sitter");
+const ts_queries = @import("ts_queries");
+
+extern fn tree_sitter_c() callconv(.c) *const ts.Language;
+extern fn tree_sitter_rust() callconv(.c) *const ts.Language;
+extern fn tree_sitter_zig() callconv(.c) *const ts.Language;
extern "c" fn forkpty(
amaster: *c_int,
@@ -46,6 +52,13 @@ const MAX_LINE_LEN: usize = 0x200;
const MAX_HISTORY: usize = 0x100;
const FILE_PANE: usize = 0;
const TTY_PANE: usize = 1;
+const TS_COMMENT: u8 = 1;
+const TS_STRING: u8 = 2;
+const TS_NUMBER: u8 = 3;
+const TS_KEYWORD: u8 = 4;
+const TS_TYPE: u8 = 5;
+const TS_FUNCTION: u8 = 6;
+const TS_BUILTIN: u8 = 7;
fn ticker(io: std.Io, loop: *Loop) void {
while (true) {
@@ -146,7 +159,10 @@ fn loadFile(
rendered_lines: *usize,
current_path: *[MAX_LINE_LEN]u8,
current_path_len: *usize,
+ file_text: *[]u8,
+ highlight_styles: *[MAX_LINES][MAX_LINE_LEN]u8,
) !void {
+ for (highlight_styles) |*row| @memset(row, 0);
const path_len = @min(path.len, MAX_LINE_LEN - 1);
@memcpy(current_path[0..path_len], path[0..path_len]);
current_path[path_len] = 0;
@@ -169,9 +185,69 @@ fn loadFile(
rendered_lines.* = 1;
return;
};
- defer gpa.free(text);
- rendered_lines.* = splitLines(lines, text);
+ if (file_text.*.len > 0) gpa.free(file_text.*);
+ file_text.* = text;
+ rendered_lines.* = splitLines(lines, file_text.*);
+
+ var language: ?*const ts.Language = null;
+ var query_text: []const u8 = "";
+ const ext = std.fs.path.extension(path);
+ if (std.mem.eql(u8, ext, ".c") or std.mem.eql(u8, ext, ".h")) {
+ language = tree_sitter_c();
+ query_text = ts_queries.c_highlights;
+ }
+ if (std.mem.eql(u8, ext, ".rs")) {
+ language = tree_sitter_rust();
+ query_text = ts_queries.rust_highlights;
+ }
+ if (std.mem.eql(u8, ext, ".zig") or std.mem.eql(u8, ext, ".zon")) {
+ language = tree_sitter_zig();
+ query_text = ts_queries.zig_highlights;
+ }
+
+ if (language) |lang| {
+ defer lang.destroy();
+ const parser = ts.Parser.create();
+ defer parser.destroy();
+ parser.setLanguage(lang) catch return;
+ const tree = parser.parseString(file_text.*, null) orelse return;
+ defer tree.destroy();
+
+ var error_offset: u32 = 0;
+ const query = ts.Query.create(lang, query_text, &error_offset) catch return;
+ defer query.destroy();
+ const cursor = ts.QueryCursor.create();
+ defer cursor.destroy();
+ cursor.exec(query, tree.rootNode());
+
+ while (cursor.nextMatch()) |match| {
+ for (match.captures) |capture| {
+ const capture_name = query.captureNameForId(capture.index) orelse "";
+ var style: u8 = 0;
+ if (std.mem.indexOf(u8, capture_name, "comment") != null) style = TS_COMMENT;
+ if (std.mem.indexOf(u8, capture_name, "string") != null or std.mem.indexOf(u8, capture_name, "character") != null) style = TS_STRING;
+ if (std.mem.indexOf(u8, capture_name, "number") != null or std.mem.indexOf(u8, capture_name, "float") != null or std.mem.indexOf(u8, capture_name, "boolean") != null) style = TS_NUMBER;
+ if (std.mem.indexOf(u8, capture_name, "keyword") != null or std.mem.indexOf(u8, capture_name, "include") != null or std.mem.indexOf(u8, capture_name, "operator") != null) style = TS_KEYWORD;
+ if (std.mem.indexOf(u8, capture_name, "type") != null or std.mem.indexOf(u8, capture_name, "constructor") != null) style = TS_TYPE;
+ if (std.mem.indexOf(u8, capture_name, "function") != null or std.mem.indexOf(u8, capture_name, "method") != null or std.mem.indexOf(u8, capture_name, "macro") != null) style = TS_FUNCTION;
+ if (std.mem.indexOf(u8, capture_name, "builtin") != null) style = TS_BUILTIN;
+ if (style == 0) continue;
+
+ const start = capture.node.startPoint();
+ const end = capture.node.endPoint();
+ var row: usize = start.row;
+ while (row <= end.row and row < MAX_LINES) : (row += 1) {
+ const start_col: usize = if (row == start.row) start.column else 0;
+ const end_col: usize = if (row == end.row) end.column else MAX_LINE_LEN - 1;
+ var col = @min(start_col, MAX_LINE_LEN - 1);
+ while (col < end_col and col < MAX_LINE_LEN - 1) : (col += 1) {
+ highlight_styles[row][col] = style;
+ }
+ }
+ }
+ }
+ }
}
fn ghostColor(color: ghostty_vt.Style.Color) vaxis.Color {
@@ -248,6 +324,9 @@ pub fn main(init: std.process.Init) !void {
var tty_buf: [0x10000]u8 = undefined;
var display_lines: [2][MAX_LINES][MAX_LINE_LEN]u8 = undefined;
var tty_render_lines: [MAX_LINES][MAX_LINE_LEN]u8 = undefined;
+ var highlight_styles: [MAX_LINES][MAX_LINE_LEN]u8 = undefined;
+ var file_text: []u8 = &.{};
+ defer if (file_text.len > 0) gpa.free(file_text);
var rendered_lines = [_]usize{ 0, 0 };
var line_nums: [MAX_LINES][8]u8 = undefined;
var file_scroll: usize = 0;
@@ -266,6 +345,8 @@ pub fn main(init: std.process.Init) !void {
&rendered_lines[FILE_PANE],
&current_path,
&current_path_len,
+ &file_text,
+ &highlight_styles,
);
var tty = try vaxis.Tty.init(io, &tty_buf);
@@ -394,7 +475,7 @@ pub fn main(init: std.process.Init) !void {
try writer.flush();
if (!mouse_on_left) term.scrollViewport(.bottom);
} else {
- loadFile(io, gpa, found_path, &display_lines[FILE_PANE], &rendered_lines[FILE_PANE], &current_path, &current_path_len) catch {};
+ loadFile(io, gpa, found_path, &display_lines[FILE_PANE], &rendered_lines[FILE_PANE], &current_path, &current_path_len, &file_text, &highlight_styles) catch {};
file_scroll = 0;
}
}
@@ -479,11 +560,55 @@ pub fn main(init: std.process.Init) !void {
.col_offset = 0,
.wrap = .none,
});
- _ = win_file.printSegment(.{ .text = display_lines[FILE_PANE][line_idx][0..len] }, .{
- .row_offset = @intCast(i + 1),
- .col_offset = 5,
- .wrap = .none,
- });
+ var col: usize = 0;
+ while (col < len) {
+ const style_id = highlight_styles[line_idx][col];
+ var end = col + 1;
+ while (end < len and highlight_styles[line_idx][end] == style_id) : (end += 1) {}
+
+ var style: vaxis.Style = .{};
+ var rgb = term.colors.palette.current[0];
+ switch (style_id) {
+ TS_COMMENT => {
+ rgb = term.colors.palette.current[8];
+ style = .{ .fg = .{ .rgb = .{ rgb.r, rgb.g, rgb.b } }, .dim = true, .italic = true };
+ },
+ TS_STRING => {
+ rgb = term.colors.palette.current[2];
+ style = .{ .fg = .{ .rgb = .{ rgb.r, rgb.g, rgb.b } } };
+ },
+ TS_NUMBER => {
+ rgb = term.colors.palette.current[3];
+ style = .{ .fg = .{ .rgb = .{ rgb.r, rgb.g, rgb.b } } };
+ },
+ TS_KEYWORD => {
+ rgb = term.colors.palette.current[5];
+ style = .{ .fg = .{ .rgb = .{ rgb.r, rgb.g, rgb.b } }, .bold = true };
+ },
+ TS_TYPE => {
+ rgb = term.colors.palette.current[6];
+ style = .{ .fg = .{ .rgb = .{ rgb.r, rgb.g, rgb.b } } };
+ },
+ TS_FUNCTION => {
+ rgb = term.colors.palette.current[4];
+ style = .{ .fg = .{ .rgb = .{ rgb.r, rgb.g, rgb.b } }, .bold = true };
+ },
+ TS_BUILTIN => {
+ rgb = term.colors.palette.current[13];
+ style = .{ .fg = .{ .rgb = .{ rgb.r, rgb.g, rgb.b } } };
+ },
+ else => {},
+ }
+ _ = win_file.printSegment(.{
+ .text = display_lines[FILE_PANE][line_idx][col..end],
+ .style = style,
+ }, .{
+ .row_offset = @intCast(i + 1),
+ .col_offset = @intCast(5 + col),
+ .wrap = .none,
+ });
+ col = end;
+ }
}
i = 0;