feat: merge configured and static file type lists
This allows adding of new file types by adding config files.
This commit is contained in:
parent
abd1e683a3
commit
f7cea96844
3 changed files with 97 additions and 34 deletions
|
@ -43,37 +43,59 @@ pub fn get_default(allocator: std.mem.Allocator, file_type_name: []const u8) ![]
|
|||
return content.toOwnedSlice(allocator);
|
||||
}
|
||||
|
||||
pub fn get_all_names() []const []const u8 {
|
||||
cache_mutex.lock();
|
||||
defer cache_mutex.unlock();
|
||||
if (cache_list.len == 0)
|
||||
cache_list = load_all(cache_allocator) catch &.{};
|
||||
return cache_list;
|
||||
}
|
||||
|
||||
const cache_allocator = std.heap.c_allocator;
|
||||
var cache_mutex: std.Thread.Mutex = .{};
|
||||
var cache: std.StringHashMapUnmanaged(*@This()) = .{};
|
||||
var cache: CacheType = .empty;
|
||||
const CacheType = std.StringHashMapUnmanaged(?@This());
|
||||
var cache_list: []const []const u8 = &.{};
|
||||
|
||||
pub fn get(file_type_name: []const u8) !?@This() {
|
||||
cache_mutex.lock();
|
||||
defer cache_mutex.unlock();
|
||||
|
||||
const self = if (cache.get(file_type_name)) |self| self.* else blk: {
|
||||
const file_name = try get_config_file_path(cache_allocator, file_type_name);
|
||||
defer cache_allocator.free(file_name);
|
||||
return if (cache.get(file_type_name)) |self| self else self: {
|
||||
const file_type = file_type: {
|
||||
const file_name = try get_config_file_path(cache_allocator, file_type_name);
|
||||
defer cache_allocator.free(file_name);
|
||||
|
||||
const file: ?std.fs.File = std.fs.openFileAbsolute(file_name, .{ .mode = .read_only }) catch null;
|
||||
if (file) |f| {
|
||||
defer f.close();
|
||||
const stat = try f.stat();
|
||||
const buf = try cache_allocator.alloc(u8, @intCast(stat.size));
|
||||
defer cache_allocator.free(buf);
|
||||
const size = try f.readAll(buf);
|
||||
std.debug.assert(size == stat.size);
|
||||
var self: @This() = .{};
|
||||
var bufs_: [][]const u8 = &.{}; // cached, no need to free
|
||||
try root.parse_text_config_file(@This(), cache_allocator, &self, &bufs_, file_name, buf);
|
||||
break :blk self;
|
||||
} else break :blk if (syntax.FileType.get_by_name_static(file_type_name)) |ft| from_file_type(ft) else null;
|
||||
const file: ?std.fs.File = std.fs.openFileAbsolute(file_name, .{ .mode = .read_only }) catch null;
|
||||
if (file) |f| {
|
||||
defer f.close();
|
||||
const stat = try f.stat();
|
||||
const buf = try cache_allocator.alloc(u8, @intCast(stat.size));
|
||||
defer cache_allocator.free(buf);
|
||||
const size = try f.readAll(buf);
|
||||
std.debug.assert(size == stat.size);
|
||||
var self: @This() = .{};
|
||||
var bufs_: [][]const u8 = &.{}; // cached, no need to free
|
||||
try root.parse_text_config_file(@This(), cache_allocator, &self, &bufs_, file_name, buf);
|
||||
break :file_type self;
|
||||
} else {
|
||||
break :file_type if (syntax.FileType.get_by_name_static(file_type_name)) |ft| from_file_type(ft) else null;
|
||||
}
|
||||
};
|
||||
try cache.put(cache_allocator, file_type_name, file_type);
|
||||
break :self file_type;
|
||||
};
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn get_config_file_path(allocator: std.mem.Allocator, file_type: []const u8) ![]const u8 {
|
||||
pub fn get_config_file_path(allocator: std.mem.Allocator, file_type: []const u8) ![]u8 {
|
||||
var stream = std.ArrayList(u8).fromOwnedSlice(allocator, try get_config_dir_path(allocator));
|
||||
const writer = stream.writer();
|
||||
_ = try writer.writeAll(file_type);
|
||||
_ = try writer.writeAll(".conf");
|
||||
return stream.toOwnedSlice();
|
||||
}
|
||||
|
||||
fn get_config_dir_path(allocator: std.mem.Allocator) ![]u8 {
|
||||
var stream = std.ArrayList(u8).init(allocator);
|
||||
const writer = stream.writer();
|
||||
_ = try writer.writeAll(try root.get_config_dir());
|
||||
|
@ -84,18 +106,60 @@ pub fn get_config_file_path(allocator: std.mem.Allocator, file_type: []const u8)
|
|||
error.PathAlreadyExists => {},
|
||||
else => return e,
|
||||
};
|
||||
_ = try writer.writeAll(file_type);
|
||||
_ = try writer.writeAll(".conf");
|
||||
return stream.toOwnedSlice();
|
||||
}
|
||||
|
||||
const extension = ".conf";
|
||||
|
||||
fn load_all(allocator: std.mem.Allocator) ![]const []const u8 {
|
||||
const dir_path = try get_config_dir_path(allocator);
|
||||
defer allocator.free(dir_path);
|
||||
|
||||
var dir = try std.fs.cwd().openDir(dir_path, .{ .iterate = true });
|
||||
defer dir.close();
|
||||
|
||||
var names: std.StringHashMapUnmanaged(void) = .empty;
|
||||
defer names.deinit(allocator);
|
||||
|
||||
var iter = dir.iterate();
|
||||
while (try iter.next()) |entry| {
|
||||
if (entry.kind != .file) continue;
|
||||
if (!std.mem.endsWith(u8, entry.name, extension)) continue;
|
||||
const file_type_name = entry.name[0 .. entry.name.len - extension.len];
|
||||
if (!names.contains(file_type_name))
|
||||
try names.put(allocator, try allocator.dupe(u8, file_type_name), {});
|
||||
}
|
||||
|
||||
for (syntax.FileType.get_all()) |static_file_type| {
|
||||
if (!names.contains(static_file_type.name))
|
||||
try names.put(allocator, try allocator.dupe(u8, static_file_type.name), {});
|
||||
}
|
||||
|
||||
var list: std.ArrayListUnmanaged([]const u8) = .empty;
|
||||
defer list.deinit(allocator);
|
||||
|
||||
var names_iter = names.keyIterator();
|
||||
while (names_iter.next()) |key| {
|
||||
(try list.addOne(allocator)).* = key.*;
|
||||
}
|
||||
|
||||
const less_fn = struct {
|
||||
fn less_fn(_: void, lhs: []const u8, rhs: []const u8) bool {
|
||||
return std.mem.order(u8, lhs, rhs) == .lt;
|
||||
}
|
||||
}.less_fn;
|
||||
std.mem.sort([]const u8, list.items, {}, less_fn);
|
||||
|
||||
return list.toOwnedSlice(allocator);
|
||||
}
|
||||
|
||||
pub fn guess_file_type(file_path: ?[]const u8, content: []const u8) ?@This() {
|
||||
return guess(file_path, content);
|
||||
}
|
||||
|
||||
fn guess(file_path: ?[]const u8, content: []const u8) ?@This() {
|
||||
if (guess_first_line(content)) |ft| return ft;
|
||||
for (syntax.FileType.static_file_types) |*static_file_type| {
|
||||
for (syntax.FileType.get_all()) |static_file_type| {
|
||||
const file_type = get(static_file_type.name) catch unreachable orelse unreachable;
|
||||
if (file_path) |fp| if (syntax.FileType.match_file_type(file_type.extensions orelse static_file_type.extensions, fp))
|
||||
return file_type;
|
||||
|
@ -105,7 +169,7 @@ fn guess(file_path: ?[]const u8, content: []const u8) ?@This() {
|
|||
|
||||
fn guess_first_line(content: []const u8) ?@This() {
|
||||
const first_line = if (std.mem.indexOf(u8, content, "\n")) |pos| content[0..pos] else content;
|
||||
for (syntax.FileType.static_file_types) |*static_file_type| {
|
||||
for (syntax.FileType.get_all()) |static_file_type| {
|
||||
const file_type = get(static_file_type.name) catch unreachable orelse unreachable;
|
||||
if (syntax.FileType.match_first_line(file_type.first_line_matches_prefix, file_type.first_line_matches_content, first_line))
|
||||
return file_type;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
const std = @import("std");
|
||||
const syntax = @import("syntax");
|
||||
const file_type_config = @import("file_type_config");
|
||||
const builtin = @import("builtin");
|
||||
const RGB = @import("color").RGB;
|
||||
|
@ -17,8 +16,8 @@ pub fn list(allocator: std.mem.Allocator, writer: anytype, tty_config: std.io.tt
|
|||
var max_formatter_len: usize = 0;
|
||||
var max_extensions_len: usize = 0;
|
||||
|
||||
for (syntax.FileType.static_file_types) |static_file_type| {
|
||||
const file_type = try file_type_config.get(static_file_type.name) orelse unreachable;
|
||||
for (file_type_config.get_all_names()) |file_type_name| {
|
||||
const file_type = try file_type_config.get(file_type_name) orelse unreachable;
|
||||
max_language_len = @max(max_language_len, file_type.name.len);
|
||||
max_langserver_len = @max(max_langserver_len, args_string_length(file_type.language_server));
|
||||
max_formatter_len = @max(max_formatter_len, args_string_length(file_type.formatter));
|
||||
|
@ -33,11 +32,11 @@ pub fn list(allocator: std.mem.Allocator, writer: anytype, tty_config: std.io.tt
|
|||
try tty_config.setColor(writer, .reset);
|
||||
try writer.writeAll("\n");
|
||||
|
||||
for (syntax.FileType.static_file_types) |static_file_type| {
|
||||
const file_type = try file_type_config.get(static_file_type.name) orelse unreachable;
|
||||
for (file_type_config.get_all_names()) |file_type_name| {
|
||||
const file_type = try file_type_config.get(file_type_name) orelse unreachable;
|
||||
try writer.writeAll(" ");
|
||||
try setColorRgb(writer, file_type.color orelse static_file_type.color);
|
||||
try writer.writeAll(file_type.icon orelse static_file_type.icon);
|
||||
try setColorRgb(writer, file_type.color orelse file_type_config.default.color);
|
||||
try writer.writeAll(file_type.icon orelse file_type_config.default.icon);
|
||||
try tty_config.setColor(writer, .reset);
|
||||
try writer.writeAll(" ");
|
||||
try write_string(writer, file_type.name, max_language_len + 1);
|
||||
|
|
|
@ -40,8 +40,8 @@ pub fn Variant(comptime command: []const u8, comptime label_: []const u8, allow_
|
|||
break :blk null;
|
||||
};
|
||||
|
||||
for (file_type_config.get_all()) |static_file_type| {
|
||||
const file_type = try file_type_config.get(static_file_type.name) orelse unreachable;
|
||||
for (file_type_config.get_all_names()) |file_type_name| {
|
||||
const file_type = try file_type_config.get(file_type_name) orelse unreachable;
|
||||
idx += 1;
|
||||
(try palette.entries.addOne()).* = .{
|
||||
.label = file_type.description orelse file_type_config.default.description,
|
||||
|
@ -49,7 +49,7 @@ pub fn Variant(comptime command: []const u8, comptime label_: []const u8, allow_
|
|||
.icon = file_type.icon orelse file_type_config.default.icon,
|
||||
.color = file_type.color orelse file_type_config.default.color,
|
||||
};
|
||||
if (previous_file_type) |file_type_name| if (std.mem.eql(u8, file_type.name, file_type_name)) {
|
||||
if (previous_file_type) |previous_name| if (std.mem.eql(u8, file_type.name, previous_name)) {
|
||||
palette.initial_selected = idx;
|
||||
};
|
||||
longest_hint = @max(longest_hint, file_type.name.len);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue