diff --git a/build.zig b/build.zig index bff622b..7e63171 100644 --- a/build.zig +++ b/build.zig @@ -11,7 +11,7 @@ pub fn build(b: *std.Build) void { const syntax_mod = b.createModule(.{ .root_source_file = .{ .path = "src/syntax.zig" }, .imports = &.{ - .{ .name = "tree-sitter", .module = tree_sitter_dep.module("tree-sitter") }, + .{ .name = "treez", .module = tree_sitter_dep.module("treez") }, file_module(b, tree_sitter_dep, "tree-sitter-agda/queries/highlights.scm"), file_module(b, tree_sitter_dep, "tree-sitter-bash/queries/highlights.scm"), file_module(b, tree_sitter_dep, "tree-sitter-c-sharp/queries/highlights.scm"), diff --git a/build.zig.zon b/build.zig.zon index 59f263b..2abb521 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -3,8 +3,8 @@ .version = "0.0.1", .dependencies = .{ .@"tree-sitter" = .{ - .url = "https://github.com/neurocyte/tree-sitter/releases/download/master-e3b53d698b82a380581551bf1cd2b4e69f116597/source.tar.gz", - .hash = "1220bb4acc4ac336f3e0b8700682dfe26beb7dd00cce2c2f61802a4a6144735b1bf5", + .url = "https://github.com/neurocyte/tree-sitter/releases/download/master-496b22b033527f75d8481077219168d768fa5ec0/source.tar.gz", + .hash = "1220a3e19dcb1d02293378eaf1be27e7304c7126f99eddfe6a51953db7b8e8db83f0", }, .clap = .{ .url = "https://github.com/Hejsil/zig-clap/archive/9c23bcb5aebe0c2542b4de4472f60959974e2222.tar.gz", diff --git a/src/file_type.zig b/src/file_type.zig index 4b2c5b5..bba91e4 100644 --- a/src/file_type.zig +++ b/src/file_type.zig @@ -1,5 +1,5 @@ const std = @import("std"); -const ts = @import("tree-sitter"); +const treez = @import("treez"); pub const FileType = @This(); color: u24, @@ -72,7 +72,7 @@ fn ft_func_name(comptime lang: []const u8) []const u8 { return &func_name; } -const LangFn = *const fn () callconv(.C) ?*const ts.Language; +const LangFn = *const fn () callconv(.C) ?*const treez.Language; const FirstLineMatch = struct { prefix: ?[]const u8 = null, diff --git a/src/file_types.zig b/src/file_types.zig index 21c324c..98bebab 100644 --- a/src/file_types.zig +++ b/src/file_types.zig @@ -27,7 +27,7 @@ pub const @"c-sharp" = .{ pub const conf = .{ .color = 0x000000, .icon = "", - .extensions = &[_][]const u8{ "conf", "config" }, + .extensions = &[_][]const u8{ "conf", "config", ".gitconfig" }, .highlights = fish.highlights, .comment = "#", .parser = fish.parser, @@ -257,7 +257,7 @@ pub const @"ssh-config" = .{ }; pub const toml = .{ - .extensions = &[_][]const u8{"toml"}, + .extensions = &[_][]const u8{ "toml" }, .comment = "#", }; diff --git a/src/main.zig b/src/main.zig index 5185ef4..a28ab55 100644 --- a/src/main.zig +++ b/src/main.zig @@ -130,7 +130,7 @@ fn render_file(a: std.mem.Allocator, writer: anytype, content: []const u8, file_ } }; var ctx: Ctx = .{ .writer = writer, .content = content, .theme = theme }; - try parser.render(&ctx, Ctx.cb); + try parser.render(&ctx, Ctx.cb, null); try ctx.writer.writeAll(content[ctx.last_pos..]); } diff --git a/src/syntax.zig b/src/syntax.zig index f89c6c1..ef4bf54 100644 --- a/src/syntax.zig +++ b/src/syntax.zig @@ -1,20 +1,24 @@ const std = @import("std"); -const ts = @import("tree-sitter"); +const treez = @import("treez"); const Self = @This(); -pub const Edit = ts.InputEdit; +pub const Edit = treez.InputEdit; pub const FileType = @import("file_type.zig"); -pub const Range = ts.Range; +pub const Range = treez.Range; +pub const Point = treez.Point; +const Language = treez.Language; +const Parser = treez.Parser; +const Query = treez.Query; +const Tree = treez.Tree; a: std.mem.Allocator, -lang: *const ts.Language, +lang: *const Language, file_type: *const FileType, -parser: *ts.Parser, -query: *ts.Query, -injections: *ts.Query, -tree: ?*ts.Tree = null, -content: []const u8, +parser: *Parser, +query: *Query, +injections: *Query, +tree: ?*Tree = null, pub fn create(file_type: *const FileType, a: std.mem.Allocator, content: []const u8) !*Self { const self = try a.create(Self); @@ -22,14 +26,13 @@ pub fn create(file_type: *const FileType, a: std.mem.Allocator, content: []const .a = a, .lang = file_type.lang_fn() orelse std.debug.panic("tree-sitter parser function failed for language: {d}", .{file_type.name}), .file_type = file_type, - .parser = try ts.Parser.create(), - .query = try ts.Query.create(self.lang, file_type.highlights), - .injections = try ts.Query.create(self.lang, file_type.highlights), - .content = content, + .parser = try Parser.create(), + .query = try Query.create(self.lang, file_type.highlights), + .injections = try Query.create(self.lang, file_type.highlights), }; errdefer self.destroy(); try self.parser.setLanguage(self.lang); - try self.parse(); + try self.parse(content); return self; } @@ -50,27 +53,60 @@ pub fn destroy(self: *Self) void { self.a.destroy(self); } -fn parse(self: *Self) !void { +fn parse(self: *Self, content: []const u8) !void { if (self.tree) |tree| tree.destroy(); - self.tree = try self.parser.parseString(null, self.content); + self.tree = try self.parser.parseString(null, content); +} + +pub fn refresh_full(self: *Self, content: []const u8) !void { + return self.parse(content); +} + +pub fn edit(self: *Self, ed: Edit) void { + if (self.tree) |tree| tree.edit(&ed); +} + +pub fn refresh(self: *Self, content: []const u8) !void { + const old_tree = self.tree; + defer if (old_tree) |tree| tree.destroy(); + self.tree = try self.parser.parseString(old_tree, content); } fn CallBack(comptime T: type) type { - return fn (ctx: T, sel: Range, scope: []const u8, id: u32, idx: usize) error{Stop}!void; + return fn (ctx: T, sel: Range, scope: []const u8, id: u32, capture_idx: usize) error{Stop}!void; } -pub fn render(self: *const Self, ctx: anytype, comptime cb: CallBack(@TypeOf(ctx))) !void { - const cursor = try ts.Query.Cursor.create(); +pub fn render(self: *const Self, ctx: anytype, comptime cb: CallBack(@TypeOf(ctx)), range: ?Range) !void { + const cursor = try Query.Cursor.create(); defer cursor.destroy(); const tree = if (self.tree) |p| p else return; cursor.execute(self.query, tree.getRootNode()); + if (range) |r| cursor.setPointRange(r.start_point, r.end_point); while (cursor.nextMatch()) |match| { var idx: usize = 0; for (match.captures()) |capture| { - const range = capture.node.getRange(); - const scope = self.query.getCaptureNameForId(capture.id); - try cb(ctx, range, scope, capture.id, idx); + try cb(ctx, capture.node.getRange(), self.query.getCaptureNameForId(capture.id), capture.id, idx); idx += 1; } } } + +pub fn highlights_at_point(self: *const Self, ctx: anytype, comptime cb: CallBack(@TypeOf(ctx)), point: Point) void { + const cursor = Query.Cursor.create() catch return; + defer cursor.destroy(); + const tree = if (self.tree) |p| p else return; + cursor.execute(self.query, tree.getRootNode()); + cursor.setPointRange(.{ .row = point.row, .column = 0 }, .{ .row = point.row + 1, .column = 0 }); + while (cursor.nextMatch()) |match| { + for (match.captures()) |capture| { + const range = capture.node.getRange(); + const start = range.start_point; + const end = range.end_point; + const scope = self.query.getCaptureNameForId(capture.id); + if (start.row == point.row and start.row <= point.column and point.column < end.column) + cb(ctx, range, scope, capture.id, 0) catch return; + break; + } + } + return; +}