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,15 +43,26 @@ pub fn get_default(allocator: std.mem.Allocator, file_type_name: []const u8) ![]
|
||||||
return content.toOwnedSlice(allocator);
|
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;
|
const cache_allocator = std.heap.c_allocator;
|
||||||
var cache_mutex: std.Thread.Mutex = .{};
|
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() {
|
pub fn get(file_type_name: []const u8) !?@This() {
|
||||||
cache_mutex.lock();
|
cache_mutex.lock();
|
||||||
defer cache_mutex.unlock();
|
defer cache_mutex.unlock();
|
||||||
|
|
||||||
const self = if (cache.get(file_type_name)) |self| self.* else blk: {
|
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);
|
const file_name = try get_config_file_path(cache_allocator, file_type_name);
|
||||||
defer cache_allocator.free(file_name);
|
defer cache_allocator.free(file_name);
|
||||||
|
|
||||||
|
@ -66,14 +77,25 @@ pub fn get(file_type_name: []const u8) !?@This() {
|
||||||
var self: @This() = .{};
|
var self: @This() = .{};
|
||||||
var bufs_: [][]const u8 = &.{}; // cached, no need to free
|
var bufs_: [][]const u8 = &.{}; // cached, no need to free
|
||||||
try root.parse_text_config_file(@This(), cache_allocator, &self, &bufs_, file_name, buf);
|
try root.parse_text_config_file(@This(), cache_allocator, &self, &bufs_, file_name, buf);
|
||||||
break :blk self;
|
break :file_type self;
|
||||||
} else break :blk if (syntax.FileType.get_by_name_static(file_type_name)) |ft| from_file_type(ft) else null;
|
} 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);
|
var stream = std.ArrayList(u8).init(allocator);
|
||||||
const writer = stream.writer();
|
const writer = stream.writer();
|
||||||
_ = try writer.writeAll(try root.get_config_dir());
|
_ = 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 => {},
|
error.PathAlreadyExists => {},
|
||||||
else => return e,
|
else => return e,
|
||||||
};
|
};
|
||||||
_ = try writer.writeAll(file_type);
|
|
||||||
_ = try writer.writeAll(".conf");
|
|
||||||
return stream.toOwnedSlice();
|
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() {
|
pub fn guess_file_type(file_path: ?[]const u8, content: []const u8) ?@This() {
|
||||||
return guess(file_path, content);
|
return guess(file_path, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn guess(file_path: ?[]const u8, content: []const u8) ?@This() {
|
fn guess(file_path: ?[]const u8, content: []const u8) ?@This() {
|
||||||
if (guess_first_line(content)) |ft| return ft;
|
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;
|
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))
|
if (file_path) |fp| if (syntax.FileType.match_file_type(file_type.extensions orelse static_file_type.extensions, fp))
|
||||||
return file_type;
|
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() {
|
fn guess_first_line(content: []const u8) ?@This() {
|
||||||
const first_line = if (std.mem.indexOf(u8, content, "\n")) |pos| content[0..pos] else content;
|
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;
|
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))
|
if (syntax.FileType.match_first_line(file_type.first_line_matches_prefix, file_type.first_line_matches_content, first_line))
|
||||||
return file_type;
|
return file_type;
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const syntax = @import("syntax");
|
|
||||||
const file_type_config = @import("file_type_config");
|
const file_type_config = @import("file_type_config");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const RGB = @import("color").RGB;
|
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_formatter_len: usize = 0;
|
||||||
var max_extensions_len: usize = 0;
|
var max_extensions_len: usize = 0;
|
||||||
|
|
||||||
for (syntax.FileType.static_file_types) |static_file_type| {
|
for (file_type_config.get_all_names()) |file_type_name| {
|
||||||
const file_type = try file_type_config.get(static_file_type.name) orelse unreachable;
|
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_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_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));
|
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 tty_config.setColor(writer, .reset);
|
||||||
try writer.writeAll("\n");
|
try writer.writeAll("\n");
|
||||||
|
|
||||||
for (syntax.FileType.static_file_types) |static_file_type| {
|
for (file_type_config.get_all_names()) |file_type_name| {
|
||||||
const file_type = try file_type_config.get(static_file_type.name) orelse unreachable;
|
const file_type = try file_type_config.get(file_type_name) orelse unreachable;
|
||||||
try writer.writeAll(" ");
|
try writer.writeAll(" ");
|
||||||
try setColorRgb(writer, file_type.color orelse static_file_type.color);
|
try setColorRgb(writer, file_type.color orelse file_type_config.default.color);
|
||||||
try writer.writeAll(file_type.icon orelse static_file_type.icon);
|
try writer.writeAll(file_type.icon orelse file_type_config.default.icon);
|
||||||
try tty_config.setColor(writer, .reset);
|
try tty_config.setColor(writer, .reset);
|
||||||
try writer.writeAll(" ");
|
try writer.writeAll(" ");
|
||||||
try write_string(writer, file_type.name, max_language_len + 1);
|
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;
|
break :blk null;
|
||||||
};
|
};
|
||||||
|
|
||||||
for (file_type_config.get_all()) |static_file_type| {
|
for (file_type_config.get_all_names()) |file_type_name| {
|
||||||
const file_type = try file_type_config.get(static_file_type.name) orelse unreachable;
|
const file_type = try file_type_config.get(file_type_name) orelse unreachable;
|
||||||
idx += 1;
|
idx += 1;
|
||||||
(try palette.entries.addOne()).* = .{
|
(try palette.entries.addOne()).* = .{
|
||||||
.label = file_type.description orelse file_type_config.default.description,
|
.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,
|
.icon = file_type.icon orelse file_type_config.default.icon,
|
||||||
.color = file_type.color orelse file_type_config.default.color,
|
.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;
|
palette.initial_selected = idx;
|
||||||
};
|
};
|
||||||
longest_hint = @max(longest_hint, file_type.name.len);
|
longest_hint = @max(longest_hint, file_type.name.len);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue