refactor: store static file types in a StaticStringMap instead of a plain list

This commit is contained in:
CJ van den Berg 2025-07-14 14:40:58 +02:00
parent 2ebd684d29
commit 924b3a2a75
Signed by: neurocyte
GPG key ID: 8EB1E1BB660E3FB9
3 changed files with 27 additions and 21 deletions

View file

@ -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))) {

View file

@ -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;

View file

@ -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);