Skip to content

Commit

Permalink
Use JSON for config file
Browse files Browse the repository at this point in the history
  • Loading branch information
Arnau478 committed May 13, 2024
1 parent 3a4996c commit 2731955
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 44 deletions.
9 changes: 5 additions & 4 deletions src/DisplayOptions.zig
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
const std = @import("std");
const hevi = @import("hevi.zig");

const DisplayOptions = @This();

/// Whether to use color or not
Expand All @@ -14,7 +16,7 @@ show_ascii: bool,
/// Skip lines if they're the same as the one before and after it
skip_lines: bool,
/// Override the binary parser that is used
parser: ?OptionString = null,
parser: ?hevi.Parser = null,

pub const OptionString = struct {
is_allocated: bool = false,
Expand All @@ -30,7 +32,6 @@ pub const OptionString = struct {
};

pub fn deinit(self: DisplayOptions, allocator: std.mem.Allocator) void {
if (self.parser) |parser| {
if (parser.is_allocated) allocator.free(parser.string);
}
_ = self;
_ = allocator;
}
7 changes: 5 additions & 2 deletions src/argparse.zig
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub const ParseResult = struct {
show_offset: ?bool,
show_ascii: ?bool,
skip_lines: ?bool,
parser: ?[]const u8,
parser: ?hevi.Parser,
};

const Flag = union(enum) {
Expand Down Expand Up @@ -218,6 +218,9 @@ pub fn parse(args: [][]const u8) ParseResult {
.show_offset = show_offset,
.show_ascii = show_ascii,
.skip_lines = skip_lines,
.parser = parser,
.parser = if (parser) |p|
std.meta.stringToEnum(hevi.Parser, p) orelse printError("no parser named {s}", .{p})
else
null,
};
}
2 changes: 1 addition & 1 deletion src/hevi.zig
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ fn getColors(allocator: std.mem.Allocator, reader: std.io.AnyReader, options: Di

inline for (comptime std.enums.values(Parser)) |parser| {
if (options.parser) |p| {
if (std.mem.eql(u8, @tagName(parser), p.string)) {
if (parser == p) {
if (parser.matches(data)) {
parser.getColors(colors, data);
return colors;
Expand Down
57 changes: 20 additions & 37 deletions src/options.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ const argparse = @import("argparse.zig");
fn openConfigFile(allocator: std.mem.Allocator, env_map: std.process.EnvMap) ?std.meta.Tuple(&.{ std.fs.File, []const u8 }) {
const path: ?[]const u8 = switch (builtin.os.tag) {
.linux, .macos, .freebsd, .openbsd, .netbsd => if (env_map.get("XDG_CONFIG_HOME")) |xdg_config_home|
std.fs.path.join(allocator, &.{ xdg_config_home, "hevi/config.zon" }) catch null
std.fs.path.join(allocator, &.{ xdg_config_home, "hevi/config.json" }) catch null
else if (env_map.get("HOME")) |home|
std.fs.path.join(allocator, &.{ home, ".config/hevi/config.zon" }) catch null
std.fs.path.join(allocator, &.{ home, ".config/hevi/config.json" }) catch null
else
null,
.windows => if (env_map.get("APPDATA")) |appdata|
std.fs.path.join(allocator, &.{ appdata, "hevi/config.zon" }) catch null
std.fs.path.join(allocator, &.{ appdata, "hevi/config.json" }) catch null
else
null,
else => null,
Expand Down Expand Up @@ -51,43 +51,26 @@ pub fn getOptions(allocator: std.mem.Allocator, args: argparse.ParseResult, stdo
const source = try tuple[0].readToEndAllocOptions(allocator, std.math.maxInt(usize), null, 1, 0);
defer allocator.free(source);

var ast = try std.zig.Ast.parse(allocator, source, .zon);
defer ast.deinit(allocator);
const OptionalDisplayOptions = struct {
color: ?bool = null,
uppercase: ?bool = null,
show_size: ?bool = null,
show_offset: ?bool = null,
show_ascii: ?bool = null,
skip_lines: ?bool = null,
parser: ?hevi.Parser = null,

var buf: [2]std.zig.Ast.Node.Index = undefined;
const root = ast.fullStructInit(&buf, ast.nodes.items(.data)[0].lhs) orelse {
try stderr.writer().print("Error: Config file does not contain a struct literal\n", .{});
return error.InvalidConfig;
comptime {
std.debug.assert(std.meta.fields(@This()).len == std.meta.fields(hevi.DisplayOptions).len);
}
};

for (root.ast.fields) |field| {
const name = ast.tokenSlice(ast.firstToken(field) - 2);
const slice = ast.tokenSlice(ast.firstToken(field));
const value = if (ast.tokens.get(ast.firstToken(field)).tag == .identifier or ast.tokens.get(ast.firstToken(field)).tag == .string_literal)
slice
else {
try stderr.writer().print("Error: invalid config found\n", .{});
return error.InvalidConfig;
};
const parsed = try std.json.parseFromSlice(OptionalDisplayOptions, allocator, source, .{});
defer parsed.deinit();

inline for (std.meta.fields(hevi.DisplayOptions)) |opt_field| {
if (std.mem.eql(u8, name, opt_field.name)) {
@field(options, opt_field.name) = switch (opt_field.type) {
bool => if (std.mem.eql(u8, value, "false"))
false
else if (std.mem.eql(u8, value, "true"))
true
else {
try stderr.writer().print("Error: expected a bool for field {s} in config file\n", .{name});
return error.InvalidConfig;
},
hevi.DisplayOptions.OptionString, ?hevi.DisplayOptions.OptionString => .{ .is_allocated = true, .string = std.mem.trim(u8, try allocator.dupe(u8, value), "\"") },
else => {
try stderr.writer().print("Error: expected a {s} for field {s} in config file\n", .{ @typeName(opt_field.type), name });
return error.InvalidConfig;
},
};
}
inline for (std.meta.fields(OptionalDisplayOptions)) |field| {
if (@field(parsed.value, field.name)) |value| {
@field(options, field.name) = value;
}
}
}
Expand All @@ -104,7 +87,7 @@ pub fn getOptions(allocator: std.mem.Allocator, args: argparse.ParseResult, stdo
if (args.show_offset) |show_offset| options.show_offset = show_offset;
if (args.show_ascii) |show_ascii| options.show_ascii = show_ascii;
if (args.skip_lines) |skip_lines| options.skip_lines = skip_lines;
if (args.parser) |parser| hevi.DisplayOptions.OptionString.safeSet(allocator, &options, parser);
if (args.parser) |parser| options.parser = parser;

return options;
}

0 comments on commit 2731955

Please sign in to comment.