From d200fdd5816c7c9e978d0c3f0ace03441afa7981 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Mon, 14 Jul 2025 13:12:40 +0200 Subject: [PATCH 1/7] feat: update cbor to add support for allocating extraction of arrays --- src/ts_serializer.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ts_serializer.zig b/src/ts_serializer.zig index 973c1f7..90c5865 100644 --- a/src/ts_serializer.zig +++ b/src/ts_serializer.zig @@ -280,6 +280,7 @@ pub const DeserializeError = error{ JsonIncompatibleType, InvalidQueryCbor, NotAnObject, + BadArrayAllocExtract, }; pub fn fromCbor(cb: []const u8, allocator: std.mem.Allocator) DeserializeError!struct { *TSQuery, *std.heap.ArenaAllocator } { From 8bb8ebb5447b8a53810629b50bab535b3d51eae4 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Mon, 14 Jul 2025 13:22:15 +0200 Subject: [PATCH 2/7] refactor: remove obsolete syntax.file_type member --- src/syntax.zig | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/syntax.zig b/src/syntax.zig index 2e5096e..55e0feb 100644 --- a/src/syntax.zig +++ b/src/syntax.zig @@ -21,7 +21,6 @@ pub const Node = treez.Node; allocator: std.mem.Allocator, lang: *const Language, -file_type: *const FileType, parser: *Parser, query: *Query, errors_query: *Query, @@ -36,7 +35,6 @@ pub fn create(file_type: *const FileType, allocator: std.mem.Allocator, query_ca self.* = .{ .allocator = allocator, .lang = file_type.lang_fn() orelse std.debug.panic("tree-sitter parser function failed for language: {s}", .{file_type.name}), - .file_type = file_type, .parser = try Parser.create(), .query = query, .errors_query = errors_query, From 6969727e076a232ce56aba70909d4bd79e1e5ee2 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Mon, 14 Jul 2025 13:22:48 +0200 Subject: [PATCH 3/7] refactor: mark static file types as static to differentiate from configured file types --- src/file_type.zig | 31 ++++++++++++++++--------------- src/syntax.zig | 8 ++++---- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/file_type.zig b/src/file_type.zig index 4c45c64..ce5600c 100644 --- a/src/file_type.zig +++ b/src/file_type.zig @@ -20,43 +20,44 @@ comment: []const u8, formatter: ?[]const []const u8, language_server: ?[]const []const u8, -pub fn get_by_name(name: []const u8) ?*const FileType { - for (file_types) |*file_type| +pub fn get_by_name_static(name: []const u8) ?*const FileType { + for (static_file_types) |*file_type| if (std.mem.eql(u8, file_type.name, name)) return file_type; return null; } -pub fn guess(file_path: ?[]const u8, content: []const u8) ?*const FileType { - if (guess_first_line(content)) |ft| return ft; - for (file_types) |*file_type| - if (file_path) |fp| if (match_file_type(file_type, fp)) +pub fn guess_static(file_path: ?[]const u8, content: []const u8) ?*const FileType { + if (guess_first_line_static(content)) |ft| return ft; + for (static_file_types) |*file_type| + if (file_path) |fp| if (match_file_type(file_type.extensions, fp)) return file_type; return null; } -fn guess_first_line(content: []const u8) ?*const FileType { +fn guess_first_line_static(content: []const u8) ?*const FileType { const first_line = if (std.mem.indexOf(u8, content, "\n")) |pos| content[0..pos] else content; - for (file_types) |*file_type| + for (static_file_types) |*file_type| if (file_type.first_line_matches) |match| - if (match_first_line(match, first_line)) + if (match_first_line(match.prefix, match.content, first_line)) return file_type; return null; } -fn match_first_line(match: FirstLineMatch, first_line: []const u8) bool { - if (match.prefix) |prefix| +pub fn match_first_line(match_prefix: ?[]const u8, match_content: ?[]const u8, first_line: []const u8) bool { + if (match_prefix == null and match_content == null) return false; + if (match_prefix) |prefix| if (prefix.len > first_line.len or !std.mem.eql(u8, first_line[0..prefix.len], prefix)) return false; - if (match.content) |content| + if (match_content) |content| if (std.mem.indexOf(u8, first_line, content)) |_| {} else return false; return true; } -fn match_file_type(file_type: *const FileType, file_path: []const u8) bool { +pub fn match_file_type(extensions: []const []const u8, file_path: []const u8) bool { const basename = std.fs.path.basename(file_path); const extension = std.fs.path.extension(file_path); - return for (file_type.extensions) |ext| { + return for (extensions) |ext| { if (ext.len == basename.len and std.mem.eql(u8, ext, basename)) return true; if (extension.len > 0 and ext.len == extension.len - 1 and std.mem.eql(u8, ext, extension[1..])) @@ -92,7 +93,7 @@ pub const FirstLineMatch = struct { content: ?[]const u8 = null, }; -pub const file_types = load_file_types(@import("file_types.zig")); +pub const static_file_types = load_file_types(@import("file_types.zig")); fn vec(comptime args: anytype) []const []const u8 { var cmd: []const []const u8 = &[_][]const u8{}; diff --git a/src/syntax.zig b/src/syntax.zig index 55e0feb..6af76a2 100644 --- a/src/syntax.zig +++ b/src/syntax.zig @@ -45,13 +45,13 @@ pub fn create(file_type: *const FileType, allocator: std.mem.Allocator, query_ca return self; } -pub fn create_file_type(allocator: std.mem.Allocator, lang_name: []const u8, query_cache: *QueryCache) !*Self { - const file_type = FileType.get_by_name(lang_name) orelse return error.NotFound; +pub fn static_create_file_type(allocator: std.mem.Allocator, lang_name: []const u8, query_cache: *QueryCache) !*Self { + const file_type = FileType.get_by_name_static(lang_name) orelse return error.NotFound; return create(file_type, allocator, query_cache); } -pub fn create_guess_file_type(allocator: std.mem.Allocator, content: []const u8, file_path: ?[]const u8, query_cache: *QueryCache) !*Self { - const file_type = FileType.guess(file_path, content) orelse return error.NotFound; +pub fn static_create_guess_file_type_static(allocator: std.mem.Allocator, content: []const u8, file_path: ?[]const u8, query_cache: *QueryCache) !*Self { + const file_type = FileType.guess_static(file_path, content) orelse return error.NotFound; return create(file_type, allocator, query_cache); } From 54069d1301c6b2211b3f58a5c949d30fca995524 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Mon, 14 Jul 2025 14:40:58 +0200 Subject: [PATCH 4/7] refactor: store static file types in a StaticStringMap instead of a plain list --- src/QueryCache.zig | 14 ++++++++------ src/file_type.zig | 32 ++++++++++++++++++-------------- src/syntax.zig | 2 +- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/QueryCache.zig b/src/QueryCache.zig index a9dad05..816d8bc 100644 --- a/src/QueryCache.zig +++ b/src/QueryCache.zig @@ -24,7 +24,8 @@ const CacheEntry = struct { query: ?*Query, query_arena: ?*std.heap.ArenaAllocator, query_type: QueryType, - file_type: *const FileType, + file_type_name: []const u8, + lang_fn: FileType.LangFn, fn destroy(self: *@This(), allocator: std.mem.Allocator) void { if (self.query_arena) |a| { @@ -101,7 +102,7 @@ fn release_cache_entry_hash_map(allocator: std.mem.Allocator, hash_map: *std.Str hash_map.deinit(allocator); } -fn get_cache_entry(self: *Self, file_type: *const FileType, comptime query_type: QueryType) CacheError!*CacheEntry { +fn get_cache_entry(self: *Self, file_type: FileType, comptime query_type: QueryType) CacheError!*CacheEntry { if (self.mutex) |*mtx| mtx.lock(); defer if (self.mutex) |*mtx| mtx.unlock(); @@ -119,7 +120,8 @@ fn get_cache_entry(self: *Self, file_type: *const FileType, comptime query_type: .query = null, .query_arena = null, .mutex = if (self.mutex) |_| .{} else null, - .file_type = file_type, + .lang_fn = file_type.lang_fn, + .file_type_name = file_type.name, .query_type = query_type, }; entry_.value_ptr.* = q; @@ -133,8 +135,8 @@ fn get_cached_query(self: *Self, entry: *CacheEntry) Error!?*Query { defer if (entry.mutex) |*mtx| mtx.unlock(); return if (entry.query) |query| query else blk: { - const lang = entry.file_type.lang_fn() orelse std.debug.panic("tree-sitter parser function failed for language: {s}", .{entry.file_type.name}); - const queries = FileType.queries.get(entry.file_type.name) orelse return null; + const lang = entry.lang_fn() orelse std.debug.panic("tree-sitter parser function failed for language: {s}", .{entry.file_type_name}); + const queries = FileType.queries.get(entry.file_type_name) orelse return null; const query_bin = switch (entry.query_type) { .highlights => queries.highlights_bin, .errors => queries.errors_bin, @@ -166,7 +168,7 @@ fn ReturnType(comptime query_type: QueryType) type { }; } -pub fn get(self: *Self, file_type: *const FileType, comptime query_type: QueryType) Error!ReturnType(query_type) { +pub fn get(self: *Self, file_type: FileType, comptime query_type: QueryType) Error!ReturnType(query_type) { const query = try self.get_cached_query(try self.get_cache_entry(file_type, query_type)); self.add_ref_locked(); return switch (@typeInfo(ReturnType(query_type))) { diff --git a/src/file_type.zig b/src/file_type.zig index ce5600c..8030272 100644 --- a/src/file_type.zig +++ b/src/file_type.zig @@ -20,22 +20,23 @@ comment: []const u8, formatter: ?[]const []const u8, language_server: ?[]const []const u8, -pub fn get_by_name_static(name: []const u8) ?*const FileType { - for (static_file_types) |*file_type| - if (std.mem.eql(u8, file_type.name, name)) - return file_type; - return null; +pub fn get_by_name_static(name: []const u8) ?FileType { + return FileType.static_file_types.get(name); } -pub fn guess_static(file_path: ?[]const u8, content: []const u8) ?*const FileType { +pub fn get_all() []const FileType { + return FileType.static_file_types.values(); +} + +pub fn guess_static(file_path: ?[]const u8, content: []const u8) ?FileType { if (guess_first_line_static(content)) |ft| return ft; - for (static_file_types) |*file_type| + for (static_file_types.values()) |*file_type| if (file_path) |fp| if (match_file_type(file_type.extensions, fp)) return file_type; return null; } -fn guess_first_line_static(content: []const u8) ?*const FileType { +fn guess_first_line_static(content: []const u8) ?FileType { const first_line = if (std.mem.indexOf(u8, content, "\n")) |pos| content[0..pos] else content; for (static_file_types) |*file_type| if (file_type.first_line_matches) |match| @@ -86,14 +87,15 @@ fn ft_func_name(comptime lang: []const u8) []const u8 { return &func_name; } -const LangFn = *const fn () callconv(.C) ?*const treez.Language; +pub const LangFn = *const fn () callconv(.C) ?*const treez.Language; pub const FirstLineMatch = struct { prefix: ?[]const u8 = null, content: ?[]const u8 = null, }; -pub const static_file_types = load_file_types(@import("file_types.zig")); +const static_file_type_list = load_file_types(@import("file_types.zig")); +const static_file_types = std.static_string_map.StaticStringMap(FileType).initComptime(static_file_type_list); fn vec(comptime args: anytype) []const []const u8 { var cmd: []const []const u8 = &[_][]const u8{}; @@ -103,7 +105,9 @@ fn vec(comptime args: anytype) []const []const u8 { return cmd; } -fn load_file_types(comptime Namespace: type) []const FileType { +const ListEntry = struct { []const u8, FileType }; + +fn load_file_types(comptime Namespace: type) []const ListEntry { comptime switch (@typeInfo(Namespace)) { .@"struct" => |info| { var count = 0; @@ -111,12 +115,12 @@ fn load_file_types(comptime Namespace: type) []const FileType { // @compileLog(decl.name, @TypeOf(@field(Namespace, decl.name))); count += 1; } - var construct_types: [count]FileType = undefined; + var construct_types: [count]ListEntry = undefined; var i = 0; for (info.decls) |decl| { const lang = decl.name; const args = @field(Namespace, lang); - construct_types[i] = .{ + construct_types[i] = .{ lang, .{ .color = if (@hasField(@TypeOf(args), "color")) args.color else 0xffffff, .icon = if (@hasField(@TypeOf(args), "icon")) args.icon else "󱀫", .name = lang, @@ -127,7 +131,7 @@ fn load_file_types(comptime Namespace: type) []const FileType { .first_line_matches = if (@hasField(@TypeOf(args), "first_line_matches")) args.first_line_matches else null, .formatter = if (@hasField(@TypeOf(args), "formatter")) vec(args.formatter) else null, .language_server = if (@hasField(@TypeOf(args), "language_server")) vec(args.language_server) else null, - }; + } }; i += 1; } const types = construct_types; diff --git a/src/syntax.zig b/src/syntax.zig index 6af76a2..bd67ccf 100644 --- a/src/syntax.zig +++ b/src/syntax.zig @@ -27,7 +27,7 @@ errors_query: *Query, injections: ?*Query, tree: ?*treez.Tree = null, -pub fn create(file_type: *const FileType, allocator: std.mem.Allocator, query_cache: *QueryCache) !*Self { +pub fn create(file_type: FileType, allocator: std.mem.Allocator, query_cache: *QueryCache) !*Self { const query = try query_cache.get(file_type, .highlights); const errors_query = try query_cache.get(file_type, .errors); const injections = try query_cache.get(file_type, .injections); From a547d6ee4907f0e75c76196362226ac34ce8c22a Mon Sep 17 00:00:00 2001 From: Yappaholic <153394729+Yappaholic@users.noreply.github.com> Date: Mon, 14 Jul 2025 22:00:20 +0300 Subject: [PATCH 5/7] update nix and web-based langs --- src/file_types.zig | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/file_types.zig b/src/file_types.zig index e19b5e5..14f3649 100644 --- a/src/file_types.zig +++ b/src/file_types.zig @@ -88,6 +88,7 @@ pub const css = .{ .icon = "󰌜", .extensions = .{"css"}, .comment = "//", + .language_server = .{ "vscode-css-language-server", "--stdio" }, }; pub const diff = .{ @@ -230,15 +231,16 @@ pub const javascript = .{ .extensions = .{"js"}, .comment = "//", .injections = "tree-sitter-javascript/queries/injections.scm", - .language_server = .{ "deno", "lsp" }, + .language_server = .{ "typescript-language-server", "--stdio" }, + .formatter = .{"prettier"}, }; pub const json = .{ .description = "JSON", .extensions = .{"json"}, .comment = "//", - .language_server = .{ "deno", "lsp" }, - .formatter = .{ "hjson", "-j" }, + .language_server = .{ "vscode-json-language-server", "--stdio" }, + .formatter = .{"prettier"}, }; pub const julia = .{ @@ -293,7 +295,8 @@ pub const markdown = .{ .comment = "