diff options
Diffstat (limited to 'main.zig')
| -rw-r--r-- | main.zig | 141 |
1 files changed, 133 insertions, 8 deletions
@@ -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], ¤t_path, ¤t_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], ¤t_path, ¤t_path_len) catch {}; + loadFile(io, gpa, found_path, &display_lines[FILE_PANE], &rendered_lines[FILE_PANE], ¤t_path, ¤t_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; |
