feat: port to zig-0.16.0 and update flow-syntax and flow-themes
This commit is contained in:
parent
a62e5f7d5d
commit
720bc9bc5b
6 changed files with 153 additions and 138 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,3 +1,4 @@
|
|||
/.cache/
|
||||
/.zig-cache/
|
||||
/zig-out/
|
||||
/zig-pkg/
|
||||
|
|
|
|||
18
build.zig
18
build.zig
|
|
@ -51,11 +51,11 @@ fn build_release(
|
|||
};
|
||||
const optimize = .ReleaseFast;
|
||||
|
||||
var version = std.ArrayList(u8).init(b.allocator);
|
||||
var version: std.Io.Writer.Allocating = .init(b.allocator);
|
||||
defer version.deinit();
|
||||
gen_version(b, version.writer()) catch unreachable;
|
||||
gen_version(b, &version.writer) catch unreachable;
|
||||
const write_file_step = b.addWriteFiles();
|
||||
const version_file = write_file_step.add("version", version.items);
|
||||
const version_file = write_file_step.add("version", version.written());
|
||||
b.getInstallStep().dependOn(&b.addInstallFile(version_file, "version").step);
|
||||
|
||||
for (targets) |t| {
|
||||
|
|
@ -97,10 +97,12 @@ pub fn build_exe(
|
|||
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "zat",
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.strip = strip,
|
||||
}),
|
||||
});
|
||||
if (pie) |value| exe.pie = value;
|
||||
exe.root_module.addImport("syntax", syntax_dep.module("syntax"));
|
||||
|
|
@ -118,13 +120,13 @@ pub fn build_exe(
|
|||
run_step.dependOn(&run_cmd.step);
|
||||
}
|
||||
|
||||
fn gen_version(b: *std.Build, writer: anytype) !void {
|
||||
fn gen_version(b: *std.Build, writer: *std.Io.Writer) !void {
|
||||
var code: u8 = 0;
|
||||
|
||||
const describe = try b.runAllowFail(&[_][]const u8{ "git", "describe", "--always", "--tags" }, &code, .Ignore);
|
||||
const diff_ = try b.runAllowFail(&[_][]const u8{ "git", "diff", "--stat", "--patch", "HEAD" }, &code, .Ignore);
|
||||
const diff = std.mem.trimRight(u8, diff_, "\r\n ");
|
||||
const version = std.mem.trimRight(u8, describe, "\r\n ");
|
||||
const describe = try b.runAllowFail(&[_][]const u8{ "git", "describe", "--always", "--tags" }, &code, .ignore);
|
||||
const diff_ = try b.runAllowFail(&[_][]const u8{ "git", "diff", "--stat", "--patch", "HEAD" }, &code, .ignore);
|
||||
const diff = std.mem.trimEnd(u8, diff_, "\r\n ");
|
||||
const version = std.mem.trimEnd(u8, describe, "\r\n ");
|
||||
|
||||
try writer.print("{s}{s}", .{ version, if (diff.len > 0) "-dirty" else "" });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
0.14.0
|
||||
|
|
@ -1,20 +1,20 @@
|
|||
.{
|
||||
.name = .zat,
|
||||
.version = "1.0.0",
|
||||
.minimum_zig_version = "0.15.2",
|
||||
.minimum_zig_version = "0.16.0",
|
||||
.fingerprint = 0x8da9db57fa011a09,
|
||||
.dependencies = .{
|
||||
.clap = .{
|
||||
.url = "https://github.com/Hejsil/zig-clap/archive/0.10.0.tar.gz",
|
||||
.hash = "clap-0.10.0-oBajB434AQBDh-Ei3YtoKIRxZacVPF1iSwp3IX_ZB8f0",
|
||||
.url = "git+https://github.com/Hejsil/zig-clap?ref=master#fc1e5cc3f6d9d3001112385ee6256d694e959d2f",
|
||||
.hash = "clap-0.11.0-oBajB7foAQC3Iyn4IVCkUdYaOVVng5IZkSncySTjNig1",
|
||||
},
|
||||
.themes = .{
|
||||
.url = "https://github.com/neurocyte/flow-themes/releases/download/master-3d26d97bed7e603f3c3846cf5328e3e845df727c/flow-themes.tar.gz",
|
||||
.hash = "N-V-__8AAK88IwAuRxgh-x0ikK2KRhXCvCg8joy5mLlH0Ffk",
|
||||
.url = "https://github.com/neurocyte/flow-themes/releases/download/master-9114e2d9ff4e01064ba1da4f780b0c5448b0f0ef/flow-themes.tar.gz",
|
||||
.hash = "N-V-__8AAJZfLAAP6zSuW13nEIrBBHZM9pbeMRwhvQ-8qqx1",
|
||||
},
|
||||
.syntax = .{
|
||||
.url = "git+https://github.com/neurocyte/flow-syntax?ref=master#02c26ba48fbc962058097feb53dd15f2750b6dc9",
|
||||
.hash = "flow_syntax-0.7.2-X8jOobBCAQArXM2P0pqy2RXieTrYu2RbCo7FOO8NWvfv",
|
||||
.url = "git+https://github.com/neurocyte/flow-syntax?ref=master#fd10951562892a8f0f507140ada1dda201445cd6",
|
||||
.hash = "flow_syntax-0.7.2-X8jOoZJcAQDG_jcA_FMqGZ98xjrrq7W-GscGocAKzfsM",
|
||||
},
|
||||
.ansi_term = .{
|
||||
.url = "https://github.com/ziglibs/ansi-term/archive/c0e6ad093d4f6a9ed4e65d962d1e53b97888f989.tar.gz",
|
||||
|
|
|
|||
|
|
@ -6,15 +6,15 @@ const builtin = @import("builtin");
|
|||
|
||||
const application_name = "flow";
|
||||
|
||||
pub fn read_config(T: type, allocator: std.mem.Allocator) struct { T, [][]const u8 } {
|
||||
pub fn read_config(io: std.Io, env: *const std.process.Environ.Map, T: type, allocator: std.mem.Allocator) struct { T, [][]const u8 } {
|
||||
var bufs: [][]const u8 = &[_][]const u8{};
|
||||
const json_file_name = get_app_config_file_name(application_name, @typeName(T)) catch return .{ .{}, bufs };
|
||||
const json_file_name = get_app_config_file_name(io, env, application_name, @typeName(T)) catch return .{ .{}, bufs };
|
||||
const text_file_name = json_file_name[0 .. json_file_name.len - ".json".len];
|
||||
var conf: T = .{};
|
||||
if (!read_config_file(T, allocator, &conf, &bufs, text_file_name)) {
|
||||
_ = read_config_file(T, allocator, &conf, &bufs, json_file_name);
|
||||
if (!read_config_file(io, T, allocator, &conf, &bufs, text_file_name)) {
|
||||
_ = read_config_file(io, T, allocator, &conf, &bufs, json_file_name);
|
||||
}
|
||||
read_nested_include_files(T, allocator, &conf, &bufs);
|
||||
read_nested_include_files(io, T, allocator, &conf, &bufs);
|
||||
return .{ conf, bufs };
|
||||
}
|
||||
|
||||
|
|
@ -23,11 +23,11 @@ pub fn free_config(allocator: std.mem.Allocator, bufs: [][]const u8) void {
|
|||
}
|
||||
|
||||
// returns true if the file was found
|
||||
fn read_config_file(T: type, allocator: std.mem.Allocator, conf: *T, bufs: *[][]const u8, file_name: []const u8) bool {
|
||||
fn read_config_file(io: std.Io, T: type, allocator: std.mem.Allocator, conf: *T, bufs: *[][]const u8, file_name: []const u8) bool {
|
||||
std.log.info("loading {s}", .{file_name});
|
||||
const err: anyerror = blk: {
|
||||
if (std.mem.endsWith(u8, file_name, ".json")) if (read_json_config_file(T, allocator, conf, bufs, file_name)) return true else |e| break :blk e;
|
||||
if (read_text_config_file(T, allocator, conf, bufs, file_name)) return true else |e| break :blk e;
|
||||
if (std.mem.endsWith(u8, file_name, ".json")) if (read_json_config_file(io, T, allocator, conf, bufs, file_name)) return true else |e| break :blk e;
|
||||
if (read_text_config_file(io, T, allocator, conf, bufs, file_name)) return true else |e| break :blk e;
|
||||
};
|
||||
switch (err) {
|
||||
error.FileNotFound => return false,
|
||||
|
|
@ -36,33 +36,39 @@ fn read_config_file(T: type, allocator: std.mem.Allocator, conf: *T, bufs: *[][]
|
|||
return true;
|
||||
}
|
||||
|
||||
fn read_text_config_file(T: type, allocator: std.mem.Allocator, conf: *T, bufs_: *[][]const u8, file_name: []const u8) !void {
|
||||
var file = try std.fs.openFileAbsolute(file_name, .{ .mode = .read_only });
|
||||
defer file.close();
|
||||
const text = try file.readToEndAlloc(allocator, 64 * 1024);
|
||||
defer allocator.free(text);
|
||||
var cbor_buf = std.ArrayList(u8).init(allocator);
|
||||
fn read_text_config_file(io: std.Io, T: type, allocator: std.mem.Allocator, conf: *T, bufs_: *[][]const u8, file_name: []const u8) !void {
|
||||
var file = try std.Io.Dir.openFileAbsolute(io, file_name, .{ .mode = .read_only });
|
||||
defer file.close(io);
|
||||
var read_buf: [4096]u8 = undefined;
|
||||
var rdr = std.Io.File.reader(file, io, &read_buf);
|
||||
const content = try rdr.interface.allocRemaining(allocator, .limited(64 * 1024));
|
||||
defer allocator.free(content);
|
||||
return parse_text_config_file(T, allocator, conf, bufs_, file_name, content);
|
||||
}
|
||||
|
||||
pub fn parse_text_config_file(T: type, allocator: std.mem.Allocator, conf: *T, bufs_: *[][]const u8, file_name: []const u8, content: []const u8) !void {
|
||||
var cbor_buf: std.Io.Writer.Allocating = .init(allocator);
|
||||
defer cbor_buf.deinit();
|
||||
const writer = cbor_buf.writer();
|
||||
var it = std.mem.splitScalar(u8, text, '\n');
|
||||
const writer = &cbor_buf.writer;
|
||||
var it = std.mem.splitScalar(u8, content, '\n');
|
||||
var lineno: u32 = 0;
|
||||
while (it.next()) |line| {
|
||||
lineno += 1;
|
||||
if (line.len == 0 or line[0] == '#')
|
||||
continue;
|
||||
const sep = std.mem.indexOfScalar(u8, line, ' ') orelse {
|
||||
const spc = std.mem.indexOfScalar(u8, line, ' ') orelse {
|
||||
std.log.err("{s}:{}: {s} missing value", .{ file_name, lineno, line });
|
||||
continue;
|
||||
};
|
||||
const name = line[0..sep];
|
||||
const value_str = line[sep + 1 ..];
|
||||
const name = line[0..spc];
|
||||
const value_str = line[spc + 1 ..];
|
||||
const cb = cbor.fromJsonAlloc(allocator, value_str) catch {
|
||||
std.log.err("{s}:{}: {s} has bad value: {s}", .{ file_name, lineno, name, value_str });
|
||||
continue;
|
||||
};
|
||||
defer allocator.free(cb);
|
||||
try cbor.writeValue(writer, name);
|
||||
try cbor_buf.appendSlice(cb);
|
||||
try writer.writeAll(cb);
|
||||
}
|
||||
const cb = try cbor_buf.toOwnedSlice();
|
||||
var bufs = std.ArrayListUnmanaged([]const u8).fromOwnedSlice(bufs_.*);
|
||||
|
|
@ -71,10 +77,12 @@ fn read_text_config_file(T: type, allocator: std.mem.Allocator, conf: *T, bufs_:
|
|||
return read_cbor_config(T, conf, file_name, cb);
|
||||
}
|
||||
|
||||
fn read_json_config_file(T: type, allocator: std.mem.Allocator, conf: *T, bufs_: *[][]const u8, file_name: []const u8) !void {
|
||||
var file = try std.fs.openFileAbsolute(file_name, .{ .mode = .read_only });
|
||||
defer file.close();
|
||||
const json = try file.readToEndAlloc(allocator, 64 * 1024);
|
||||
fn read_json_config_file(io: std.Io, T: type, allocator: std.mem.Allocator, conf: *T, bufs_: *[][]const u8, file_name: []const u8) !void {
|
||||
var file = try std.Io.Dir.openFileAbsolute(io, file_name, .{ .mode = .read_only });
|
||||
defer file.close(io);
|
||||
var read_buf: [4096]u8 = undefined;
|
||||
var rdr = std.Io.File.reader(file, io, &read_buf);
|
||||
const json = try rdr.interface.allocRemaining(allocator, .limited(64 * 1024));
|
||||
defer allocator.free(json);
|
||||
const cbor_buf: []u8 = try allocator.alloc(u8, json.len);
|
||||
var bufs = std.ArrayListUnmanaged([]const u8).fromOwnedSlice(bufs_.*);
|
||||
|
|
@ -132,16 +140,16 @@ fn read_cbor_config(
|
|||
}
|
||||
}
|
||||
|
||||
fn read_nested_include_files(T: type, allocator: std.mem.Allocator, conf: *T, bufs: *[][]const u8) void {
|
||||
fn read_nested_include_files(io: std.Io, T: type, allocator: std.mem.Allocator, conf: *T, bufs: *[][]const u8) void {
|
||||
if (conf.include_files.len == 0) return;
|
||||
var it = std.mem.splitScalar(u8, conf.include_files, std.fs.path.delimiter);
|
||||
while (it.next()) |path| if (!read_config_file(T, allocator, conf, bufs, path)) {
|
||||
while (it.next()) |path| if (!read_config_file(io, T, allocator, conf, bufs, path)) {
|
||||
std.log.warn("config include file '{s}' is not found", .{path});
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_config_dir() ![]const u8 {
|
||||
return get_app_config_dir(application_name);
|
||||
pub fn get_config_dir(io: std.Io, env: *const std.process.Environ.Map) ![]const u8 {
|
||||
return get_app_config_dir(io, env, application_name);
|
||||
}
|
||||
|
||||
pub const ConfigDirError = error{
|
||||
|
|
@ -152,30 +160,26 @@ pub const ConfigDirError = error{
|
|||
AppConfigDirUnavailable,
|
||||
};
|
||||
|
||||
fn get_app_config_dir(appname: []const u8) ConfigDirError![]const u8 {
|
||||
const a = std.heap.c_allocator;
|
||||
fn get_app_config_dir(io: std.Io, env: *const std.process.Environ.Map, appname: []const u8) ConfigDirError![]const u8 {
|
||||
const local = struct {
|
||||
var config_dir_buffer: [std.posix.PATH_MAX]u8 = undefined;
|
||||
var config_dir: ?[]const u8 = null;
|
||||
};
|
||||
const config_dir = if (local.config_dir) |dir|
|
||||
dir
|
||||
else if (std.process.getEnvVarOwned(a, "XDG_CONFIG_HOME") catch null) |xdg| ret: {
|
||||
defer a.free(xdg);
|
||||
else if (env.get("XDG_CONFIG_HOME")) |xdg| ret: {
|
||||
break :ret try std.fmt.bufPrint(&local.config_dir_buffer, "{s}/{s}", .{ xdg, appname });
|
||||
} else if (std.process.getEnvVarOwned(a, "HOME") catch null) |home| ret: {
|
||||
defer a.free(home);
|
||||
} else if (env.get("HOME")) |home| ret: {
|
||||
const dir = try std.fmt.bufPrint(&local.config_dir_buffer, "{s}/.config", .{home});
|
||||
std.fs.makeDirAbsolute(dir) catch |e| switch (e) {
|
||||
std.Io.Dir.createDirAbsolute(io, dir, .default_dir) catch |e| switch (e) {
|
||||
error.PathAlreadyExists => {},
|
||||
else => return error.MakeHomeConfigDirFailed,
|
||||
};
|
||||
break :ret try std.fmt.bufPrint(&local.config_dir_buffer, "{s}/.config/{s}", .{ home, appname });
|
||||
} else if (builtin.os.tag == .windows) ret: {
|
||||
if (std.process.getEnvVarOwned(a, "APPDATA") catch null) |appdata| {
|
||||
defer a.free(appdata);
|
||||
if (env.get("APPDATA")) |appdata| {
|
||||
const dir = try std.fmt.bufPrint(&local.config_dir_buffer, "{s}/{s}", .{ appdata, appname });
|
||||
std.fs.makeDirAbsolute(dir) catch |e| switch (e) {
|
||||
std.Io.Dir.createDirAbsolute(io, dir, .default_dir) catch |e| switch (e) {
|
||||
error.PathAlreadyExists => {},
|
||||
else => return error.MakeAppConfigDirFailed,
|
||||
};
|
||||
|
|
@ -184,73 +188,73 @@ fn get_app_config_dir(appname: []const u8) ConfigDirError![]const u8 {
|
|||
} else return error.AppConfigDirUnavailable;
|
||||
|
||||
local.config_dir = config_dir;
|
||||
std.fs.makeDirAbsolute(config_dir) catch |e| switch (e) {
|
||||
std.Io.Dir.createDirAbsolute(io, config_dir, .default_dir) catch |e| switch (e) {
|
||||
error.PathAlreadyExists => {},
|
||||
else => return error.MakeConfigDirFailed,
|
||||
};
|
||||
|
||||
var theme_dir_buffer: [std.posix.PATH_MAX]u8 = undefined;
|
||||
std.fs.makeDirAbsolute(try std.fmt.bufPrint(&theme_dir_buffer, "{s}/{s}", .{ config_dir, theme_dir })) catch {};
|
||||
std.Io.Dir.createDirAbsolute(io, try std.fmt.bufPrint(&theme_dir_buffer, "{s}/{s}", .{ config_dir, theme_dir }), .default_dir) catch {};
|
||||
|
||||
return config_dir;
|
||||
}
|
||||
|
||||
fn get_app_config_file_name(appname: []const u8, comptime base_name: []const u8) ConfigDirError![]const u8 {
|
||||
return get_app_config_dir_file_name(appname, base_name ++ ".json");
|
||||
fn get_app_config_file_name(io: std.Io, env: *const std.process.Environ.Map, appname: []const u8, comptime base_name: []const u8) ConfigDirError![]const u8 {
|
||||
return get_app_config_dir_file_name(io, env, appname, base_name ++ ".json");
|
||||
}
|
||||
|
||||
fn get_app_config_dir_file_name(appname: []const u8, comptime config_file_name: []const u8) ConfigDirError![]const u8 {
|
||||
fn get_app_config_dir_file_name(io: std.Io, env: *const std.process.Environ.Map, appname: []const u8, comptime config_file_name: []const u8) ConfigDirError![]const u8 {
|
||||
const local = struct {
|
||||
var config_file_buffer: [std.posix.PATH_MAX]u8 = undefined;
|
||||
};
|
||||
return std.fmt.bufPrint(&local.config_file_buffer, "{s}/{s}", .{ try get_app_config_dir(appname), config_file_name });
|
||||
return std.fmt.bufPrint(&local.config_file_buffer, "{s}/{s}", .{ try get_app_config_dir(io, env, appname), config_file_name });
|
||||
}
|
||||
|
||||
const theme_dir = "themes";
|
||||
|
||||
fn get_theme_directory() ![]const u8 {
|
||||
fn get_theme_directory(io: std.Io, env: *const std.process.Environ.Map) ![]const u8 {
|
||||
const local = struct {
|
||||
var dir_buffer: [std.posix.PATH_MAX]u8 = undefined;
|
||||
};
|
||||
const a = std.heap.c_allocator;
|
||||
if (std.process.getEnvVarOwned(a, "FLOW_THEMES_DIR") catch null) |dir| {
|
||||
defer a.free(dir);
|
||||
if (env.get("FLOW_THEMES_DIR")) |dir| {
|
||||
return try std.fmt.bufPrint(&local.dir_buffer, "{s}", .{dir});
|
||||
}
|
||||
return try std.fmt.bufPrint(&local.dir_buffer, "{s}/{s}", .{ try get_app_config_dir(application_name), theme_dir });
|
||||
return try std.fmt.bufPrint(&local.dir_buffer, "{s}/{s}", .{ try get_app_config_dir(io, env, application_name), theme_dir });
|
||||
}
|
||||
|
||||
pub fn get_theme_file_name(theme_name: []const u8) ![]const u8 {
|
||||
const dir = try get_theme_directory();
|
||||
pub fn get_theme_file_name(io: std.Io, env: *const std.process.Environ.Map, theme_name: []const u8) ![]const u8 {
|
||||
const dir = try get_theme_directory(io, env);
|
||||
const local = struct {
|
||||
var file_buffer: [std.posix.PATH_MAX]u8 = undefined;
|
||||
};
|
||||
return try std.fmt.bufPrint(&local.file_buffer, "{s}/{s}.json", .{ dir, theme_name });
|
||||
}
|
||||
|
||||
fn read_theme(allocator: std.mem.Allocator, theme_name: []const u8) ?[]const u8 {
|
||||
const file_name = get_theme_file_name(theme_name) catch return null;
|
||||
var file = std.fs.openFileAbsolute(file_name, .{ .mode = .read_only }) catch return null;
|
||||
defer file.close();
|
||||
return file.readToEndAlloc(allocator, 64 * 1024) catch null;
|
||||
fn read_theme(io: std.Io, env: *const std.process.Environ.Map, allocator: std.mem.Allocator, theme_name: []const u8) ?[]const u8 {
|
||||
const file_name = get_theme_file_name(io, env, theme_name) catch return null;
|
||||
var file = std.Io.Dir.openFileAbsolute(io, file_name, .{ .mode = .read_only }) catch return null;
|
||||
defer file.close(io);
|
||||
var read_buf: [4096]u8 = undefined;
|
||||
var rdr = std.Io.File.reader(file, io, &read_buf);
|
||||
return rdr.interface.allocRemaining(allocator, .limited(64 * 1024)) catch null;
|
||||
}
|
||||
|
||||
fn load_theme_file(allocator: std.mem.Allocator, theme_name: []const u8) !?std.json.Parsed(Theme) {
|
||||
return load_theme_file_internal(allocator, theme_name) catch |e| {
|
||||
fn load_theme_file(io: std.Io, env: *const std.process.Environ.Map, allocator: std.mem.Allocator, theme_name: []const u8) !?std.json.Parsed(Theme) {
|
||||
return load_theme_file_internal(io, env, allocator, theme_name) catch |e| {
|
||||
std.log.err("loaded theme from file failed: {}", .{e});
|
||||
return e;
|
||||
};
|
||||
}
|
||||
|
||||
fn load_theme_file_internal(allocator: std.mem.Allocator, theme_name: []const u8) !?std.json.Parsed(Theme) {
|
||||
fn load_theme_file_internal(io: std.Io, env: *const std.process.Environ.Map, allocator: std.mem.Allocator, theme_name: []const u8) !?std.json.Parsed(Theme) {
|
||||
_ = std.json.Scanner;
|
||||
const json_str = read_theme(allocator, theme_name) orelse return null;
|
||||
const json_str = read_theme(io, env, allocator, theme_name) orelse return null;
|
||||
defer allocator.free(json_str);
|
||||
return try std.json.parseFromSlice(Theme, allocator, json_str, .{ .allocate = .alloc_always });
|
||||
}
|
||||
|
||||
pub fn get_theme_by_name(allocator: std.mem.Allocator, name: []const u8) ?struct { Theme, ?std.json.Parsed(Theme) } {
|
||||
if (load_theme_file(allocator, name) catch null) |parsed_theme| {
|
||||
pub fn get_theme_by_name(io: std.Io, env: *const std.process.Environ.Map, allocator: std.mem.Allocator, name: []const u8) ?struct { Theme, ?std.json.Parsed(Theme) } {
|
||||
if (load_theme_file(io, env, allocator, name) catch null) |parsed_theme| {
|
||||
std.log.info("loaded theme from file: {s}", .{name});
|
||||
return .{ parsed_theme.value, parsed_theme };
|
||||
}
|
||||
|
|
|
|||
121
src/main.zig
121
src/main.zig
|
|
@ -6,7 +6,7 @@ const themes = @import("themes");
|
|||
const term = @import("ansi_term");
|
||||
const config_loader = @import("config_loader.zig");
|
||||
|
||||
const Writer = std.io.BufferedWriter(4096, std.fs.File.Writer).Writer;
|
||||
const Writer = std.Io.Writer;
|
||||
const StyleCache = std.AutoHashMap(u32, ?Theme.Token);
|
||||
var style_cache: StyleCache = undefined;
|
||||
var lang_override: ?[]const u8 = null;
|
||||
|
|
@ -18,7 +18,7 @@ pub const std_options: std.Options = .{
|
|||
.log_level = if (builtin.mode == .Debug) .info else .err,
|
||||
};
|
||||
|
||||
pub fn main() !void {
|
||||
pub fn main(init: std.process.Init) !void {
|
||||
const params = comptime clap.parseParamsComptime(
|
||||
\\-h, --help Display this help and exit.
|
||||
\\-l, --language <name> Override the language.
|
||||
|
|
@ -38,10 +38,14 @@ pub fn main() !void {
|
|||
\\
|
||||
);
|
||||
|
||||
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .{};
|
||||
const a = gpa.allocator();
|
||||
const a = init.gpa;
|
||||
style_cache = StyleCache.init(a);
|
||||
|
||||
var stderr_buf: [4096]u8 = undefined;
|
||||
var stderr_file = std.Io.File.writer(std.Io.File.stderr(), init.io, &stderr_buf);
|
||||
const stderr = &stderr_file.interface;
|
||||
defer stderr_file.flush() catch {};
|
||||
|
||||
const parsers = comptime .{
|
||||
.name = clap.parsers.string,
|
||||
.file = clap.parsers.string,
|
||||
|
|
@ -49,36 +53,38 @@ pub fn main() !void {
|
|||
.lines = clap.parsers.int(usize, 10),
|
||||
};
|
||||
var diag = clap.Diagnostic{};
|
||||
var res = clap.parse(clap.Help, ¶ms, parsers, .{
|
||||
var res = clap.parse(clap.Help, ¶ms, parsers, init.minimal.args, .{
|
||||
.diagnostic = &diag,
|
||||
.allocator = a,
|
||||
}) catch |err| {
|
||||
diag.report(std.io.getStdErr().writer(), err) catch {};
|
||||
clap.help(std.io.getStdErr().writer(), clap.Help, ¶ms, .{}) catch {};
|
||||
diag.report(stderr, err) catch {};
|
||||
clap.help(stderr, clap.Help, ¶ms, .{}) catch {};
|
||||
std.process.exit(1);
|
||||
return err;
|
||||
};
|
||||
defer res.deinit();
|
||||
|
||||
const stdout_file = std.io.getStdOut();
|
||||
const stdout_writer = stdout_file.writer();
|
||||
var bw = std.io.bufferedWriter(stdout_writer);
|
||||
const writer = bw.writer();
|
||||
defer bw.flush() catch {};
|
||||
var stdout_buf: [4096]u8 = undefined;
|
||||
var stdout_file = std.Io.File.writer(std.Io.File.stdout(), init.io, &stdout_buf);
|
||||
const stdout = &stdout_file.interface;
|
||||
defer stdout_file.flush() catch {};
|
||||
|
||||
if (res.args.help != 0)
|
||||
return clap.help(std.io.getStdErr().writer(), clap.Help, ¶ms, .{});
|
||||
return clap.help(stderr, clap.Help, ¶ms, .{});
|
||||
|
||||
if (res.args.@"list-themes" != 0)
|
||||
return list_themes(writer);
|
||||
return list_themes(stdout);
|
||||
|
||||
if (res.args.@"list-languages" != 0)
|
||||
return list_langs(writer);
|
||||
return list_langs(stdout);
|
||||
|
||||
if (res.args.color == 0 and !stdout_file.supportsAnsiEscapeCodes())
|
||||
return plain_cat(res.positionals[0]);
|
||||
if (res.args.color == 0) {
|
||||
const tty_mode = std.Io.Terminal.Mode.detect(init.io, std.Io.File.stdout(), false, false) catch .no_color;
|
||||
if (tty_mode == .no_color)
|
||||
return plain_cat(init.io, stdout, res.positionals[0]);
|
||||
}
|
||||
|
||||
const conf, const conf_bufs = config_loader.read_config(@import("config.zig"), a);
|
||||
const conf, const conf_bufs = config_loader.read_config(init.io, init.environ_map, @import("config.zig"), a);
|
||||
defer config_loader.free_config(a, conf_bufs);
|
||||
const theme_name = if (res.args.theme) |theme| theme else conf.theme;
|
||||
const limit_lines = res.args.limit;
|
||||
|
|
@ -98,7 +104,7 @@ pub fn main() !void {
|
|||
std.process.exit(1);
|
||||
}
|
||||
|
||||
const theme, const parsed_theme = config_loader.get_theme_by_name(a, theme_name) orelse {
|
||||
const theme, const parsed_theme = config_loader.get_theme_by_name(init.io, init.environ_map, a, theme_name) orelse {
|
||||
std.log.err("theme \"{s}\" not found", .{theme_name});
|
||||
std.process.exit(1);
|
||||
};
|
||||
|
|
@ -111,20 +117,23 @@ pub fn main() !void {
|
|||
if (res.args.default) |default| lang_default = default;
|
||||
|
||||
if (res.args.html != 0)
|
||||
try write_html_preamble(writer, theme.editor);
|
||||
try write_html_preamble(stdout, theme.editor);
|
||||
|
||||
if (res.positionals[0].len > 0) {
|
||||
for (res.positionals[0]) |arg| {
|
||||
const file = if (std.mem.eql(u8, arg, "-"))
|
||||
std.io.getStdIn()
|
||||
std.Io.File.stdin()
|
||||
else
|
||||
try std.fs.cwd().openFile(arg, .{ .mode = .read_only });
|
||||
defer file.close();
|
||||
const content = try file.readToEndAlloc(a, std.math.maxInt(u32));
|
||||
try std.Io.Dir.cwd().openFile(init.io, arg, .{ .mode = .read_only });
|
||||
defer file.close(init.io);
|
||||
var file_read_buf: [4096]u8 = undefined;
|
||||
var file_rdr = std.Io.File.reader(file, init.io, &file_read_buf);
|
||||
const content = try file_rdr.interface.allocRemaining(a, .limited(std.math.maxInt(u32)));
|
||||
defer a.free(content);
|
||||
render_file(
|
||||
init.io,
|
||||
a,
|
||||
writer,
|
||||
stdout,
|
||||
content,
|
||||
arg,
|
||||
&theme,
|
||||
|
|
@ -139,14 +148,16 @@ pub fn main() !void {
|
|||
error.Stop => return,
|
||||
else => return e,
|
||||
};
|
||||
try bw.flush();
|
||||
}
|
||||
} else {
|
||||
const content = try std.io.getStdIn().readToEndAlloc(a, std.math.maxInt(u32));
|
||||
var stdin_read_buf: [4096]u8 = undefined;
|
||||
var stdin_rdr = std.Io.File.reader(std.Io.File.stdin(), init.io, &stdin_read_buf);
|
||||
const content = try stdin_rdr.interface.allocRemaining(a, .limited(std.math.maxInt(u32)));
|
||||
defer a.free(content);
|
||||
render_file(
|
||||
init.io,
|
||||
a,
|
||||
writer,
|
||||
stdout,
|
||||
content,
|
||||
"-",
|
||||
&theme,
|
||||
|
|
@ -164,7 +175,7 @@ pub fn main() !void {
|
|||
}
|
||||
|
||||
if (res.args.html != 0)
|
||||
try write_html_postamble(writer);
|
||||
try write_html_postamble(stdout);
|
||||
}
|
||||
|
||||
fn get_parser(a: std.mem.Allocator, content: []const u8, file_path: []const u8, query_cache: *syntax.QueryCache) struct { syntax.FileType, *syntax } {
|
||||
|
|
@ -184,11 +195,12 @@ fn unknown_file_type(name: []const u8) noreturn {
|
|||
std.process.exit(1);
|
||||
}
|
||||
|
||||
const StyleFn = *const fn (writer: Writer, style: Theme.Style) Writer.Error!void;
|
||||
const StyleFn = *const fn (writer: *Writer, style: Theme.Style) Writer.Error!void;
|
||||
|
||||
fn render_file(
|
||||
io: std.Io,
|
||||
a: std.mem.Allocator,
|
||||
writer: Writer,
|
||||
writer: *Writer,
|
||||
content: []const u8,
|
||||
file_path: []const u8,
|
||||
theme: *const Theme,
|
||||
|
|
@ -215,7 +227,7 @@ fn render_file(
|
|||
end_line = start_line + lines;
|
||||
}
|
||||
|
||||
const query_cache = try syntax.QueryCache.create(a, .{});
|
||||
const query_cache = try syntax.QueryCache.create(io, a, .{});
|
||||
const file_type, const parser = get_parser(a, content, file_path, query_cache);
|
||||
try parser.refresh_full(content);
|
||||
if (show_file_type) {
|
||||
|
|
@ -397,20 +409,21 @@ pub const fallbacks: []const FallBack = &[_]FallBack{
|
|||
.{ .ts = "field", .tm = "variable" },
|
||||
};
|
||||
|
||||
fn list_themes(writer: Writer) !void {
|
||||
fn list_themes(writer: *Writer) !void {
|
||||
var max_name_len: usize = 0;
|
||||
for (themes.themes) |theme|
|
||||
max_name_len = @max(max_name_len, theme.name.len);
|
||||
|
||||
for (themes.themes) |theme| {
|
||||
try writer.writeAll(theme.name);
|
||||
try writer.writeByteNTimes(' ', max_name_len + 2 - theme.name.len);
|
||||
for (0..max_name_len + 2 - theme.name.len) |_|
|
||||
try writer.writeByte(' ');
|
||||
try writer.writeAll(theme.description);
|
||||
try writer.writeAll("\n");
|
||||
}
|
||||
}
|
||||
|
||||
fn set_ansi_style(writer: Writer, style: Theme.Style) Writer.Error!void {
|
||||
fn set_ansi_style(writer: *Writer, style: Theme.Style) Writer.Error!void {
|
||||
const ansi_style: term.style.Style = .{
|
||||
.foreground = if (style.fg) |color| to_rgb_color(color.color) else .Default,
|
||||
.background = if (style.bg) |color| to_rgb_color(color.color) else .Default,
|
||||
|
|
@ -428,7 +441,7 @@ fn set_ansi_style(writer: Writer, style: Theme.Style) Writer.Error!void {
|
|||
|
||||
const unset_ansi_style = set_ansi_style;
|
||||
|
||||
fn write_html_preamble(writer: Writer, style: Theme.Style) !void {
|
||||
fn write_html_preamble(writer: *Writer, style: Theme.Style) !void {
|
||||
const color = if (style.fg) |color| color.color else 0;
|
||||
const background = if (style.bg) |background| background.color else 0xFFFFFF;
|
||||
try writer.writeAll("<div style=\"color:");
|
||||
|
|
@ -438,11 +451,11 @@ fn write_html_preamble(writer: Writer, style: Theme.Style) !void {
|
|||
try writer.writeAll(";\"><pre>");
|
||||
}
|
||||
|
||||
fn write_html_postamble(writer: Writer) !void {
|
||||
fn write_html_postamble(writer: *Writer) !void {
|
||||
try writer.writeAll("</pre></div>");
|
||||
}
|
||||
|
||||
fn set_html_style(writer: Writer, style: Theme.Style) !void {
|
||||
fn set_html_style(writer: *Writer, style: Theme.Style) !void {
|
||||
const color = if (style.fg) |color| color.color else 0;
|
||||
try writer.writeAll("<span style=\"color:");
|
||||
try write_hex_color(writer, color);
|
||||
|
|
@ -457,7 +470,7 @@ fn set_html_style(writer: Writer, style: Theme.Style) !void {
|
|||
try writer.writeAll(";\">");
|
||||
}
|
||||
|
||||
fn unset_html_style(writer: Writer, _: Theme.Style) !void {
|
||||
fn unset_html_style(writer: *Writer, _: Theme.Style) !void {
|
||||
try writer.writeAll("</span>");
|
||||
}
|
||||
|
||||
|
|
@ -468,18 +481,18 @@ fn to_rgb_color(color: u24) term.style.Color {
|
|||
return .{ .RGB = .{ .r = r, .g = g, .b = b } };
|
||||
}
|
||||
|
||||
fn write_hex_color(writer: Writer, color: u24) !void {
|
||||
fn write_hex_color(writer: *Writer, color: u24) !void {
|
||||
try writer.print("#{x:0>6}", .{color});
|
||||
}
|
||||
|
||||
fn list_langs(writer: Writer) !void {
|
||||
fn list_langs(writer: *Writer) !void {
|
||||
for (syntax.FileType.get_all()) |file_type| {
|
||||
try writer.writeAll(file_type.name);
|
||||
try writer.writeAll("\n");
|
||||
}
|
||||
}
|
||||
|
||||
fn render_file_type(writer: Writer, file_type: *const syntax.FileType, theme: *const Theme) !void {
|
||||
fn render_file_type(writer: *Writer, file_type: *const syntax.FileType, theme: *const Theme) !void {
|
||||
const style = theme.editor_selection;
|
||||
const reversed = Theme.Style{ .fg = theme.editor_selection.bg };
|
||||
const plain: Theme.Style = Theme.Style{ .fg = theme.editor.fg };
|
||||
|
|
@ -499,7 +512,7 @@ fn render_file_type(writer: Writer, file_type: *const syntax.FileType, theme: *c
|
|||
try writer.writeAll("\n");
|
||||
}
|
||||
|
||||
fn render_theme_indicator(writer: Writer, theme: *const Theme) !void {
|
||||
fn render_theme_indicator(writer: *Writer, theme: *const Theme) !void {
|
||||
const style = Theme.Style{ .bg = theme.editor_selection.bg, .fg = theme.editor.fg };
|
||||
const reversed = Theme.Style{ .fg = theme.editor_selection.bg };
|
||||
const plain: Theme.Style = Theme.Style{ .fg = theme.editor.fg };
|
||||
|
|
@ -513,26 +526,22 @@ fn render_theme_indicator(writer: Writer, theme: *const Theme) !void {
|
|||
try writer.writeAll("\n");
|
||||
}
|
||||
|
||||
fn plain_cat(files: []const []const u8) !void {
|
||||
const stdout = std.io.getStdOut();
|
||||
fn plain_cat(io: std.Io, stdout: *Writer, files: []const []const u8) !void {
|
||||
if (files.len == 0) {
|
||||
try plain_cat_file(stdout, "-");
|
||||
try plain_cat_file(io, stdout, "-");
|
||||
} else {
|
||||
for (files) |file| try plain_cat_file(stdout, file);
|
||||
for (files) |file| try plain_cat_file(io, stdout, file);
|
||||
}
|
||||
}
|
||||
|
||||
fn plain_cat_file(out_file: std.fs.File, in_file_name: []const u8) !void {
|
||||
fn plain_cat_file(io: std.Io, stdout: *Writer, in_file_name: []const u8) !void {
|
||||
var in_file = if (std.mem.eql(u8, in_file_name, "-"))
|
||||
std.io.getStdIn()
|
||||
std.Io.File.stdin()
|
||||
else
|
||||
try std.fs.cwd().openFile(in_file_name, .{});
|
||||
defer in_file.close();
|
||||
try std.Io.Dir.cwd().openFile(io, in_file_name, .{});
|
||||
defer in_file.close(io);
|
||||
|
||||
var buf: [std.heap.page_size_min]u8 = undefined;
|
||||
while (true) {
|
||||
const bytes_read = try in_file.read(&buf);
|
||||
if (bytes_read == 0) return;
|
||||
try out_file.writeAll(buf[0..bytes_read]);
|
||||
}
|
||||
var rdr = std.Io.File.reader(in_file, io, &buf);
|
||||
_ = try rdr.interface.streamRemaining(stdout);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue