mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
Merge pull request #1958 from remi-gelinas/remi-gelinas/config-validation-cli-action
feat: add validate-config action
This commit is contained in:
@ -9,6 +9,7 @@ const list_keybinds = @import("list_keybinds.zig");
|
|||||||
const list_themes = @import("list_themes.zig");
|
const list_themes = @import("list_themes.zig");
|
||||||
const list_colors = @import("list_colors.zig");
|
const list_colors = @import("list_colors.zig");
|
||||||
const show_config = @import("show_config.zig");
|
const show_config = @import("show_config.zig");
|
||||||
|
const validate_config = @import("validate_config.zig");
|
||||||
|
|
||||||
/// Special commands that can be invoked via CLI flags. These are all
|
/// Special commands that can be invoked via CLI flags. These are all
|
||||||
/// invoked by using `+<action>` as a CLI flag. The only exception is
|
/// invoked by using `+<action>` as a CLI flag. The only exception is
|
||||||
@ -35,6 +36,9 @@ pub const Action = enum {
|
|||||||
/// Dump the config to stdout
|
/// Dump the config to stdout
|
||||||
@"show-config",
|
@"show-config",
|
||||||
|
|
||||||
|
// Validate passed config file
|
||||||
|
@"validate-config",
|
||||||
|
|
||||||
pub const Error = error{
|
pub const Error = error{
|
||||||
/// Multiple actions were detected. You can specify at most one
|
/// Multiple actions were detected. You can specify at most one
|
||||||
/// action on the CLI otherwise the behavior desired is ambiguous.
|
/// action on the CLI otherwise the behavior desired is ambiguous.
|
||||||
@ -124,6 +128,7 @@ pub const Action = enum {
|
|||||||
.@"list-themes" => try list_themes.run(alloc),
|
.@"list-themes" => try list_themes.run(alloc),
|
||||||
.@"list-colors" => try list_colors.run(alloc),
|
.@"list-colors" => try list_colors.run(alloc),
|
||||||
.@"show-config" => try show_config.run(alloc),
|
.@"show-config" => try show_config.run(alloc),
|
||||||
|
.@"validate-config" => try validate_config.run(alloc),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
67
src/cli/validate_config.zig
Normal file
67
src/cli/validate_config.zig
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const args = @import("args.zig");
|
||||||
|
const Action = @import("action.zig").Action;
|
||||||
|
const Config = @import("../config.zig").Config;
|
||||||
|
const cli = @import("../cli.zig");
|
||||||
|
|
||||||
|
pub const Options = struct {
|
||||||
|
/// The path of the config file to validate. If this isn't specified,
|
||||||
|
/// then the default config file paths will be validated.
|
||||||
|
@"config-file": ?[:0]const u8 = null,
|
||||||
|
|
||||||
|
pub fn deinit(self: Options) void {
|
||||||
|
_ = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables "-h" and "--help" to work.
|
||||||
|
pub fn help(self: Options) !void {
|
||||||
|
_ = self;
|
||||||
|
return Action.help_error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The `validate-config` command is used to validate a Ghostty config file.
|
||||||
|
///
|
||||||
|
/// When executed without any arguments, this will load the config from the default location.
|
||||||
|
///
|
||||||
|
/// The `--config-file` argument can be passed to validate a specific target config
|
||||||
|
/// file in a non-default location.
|
||||||
|
pub fn run(alloc: std.mem.Allocator) !u8 {
|
||||||
|
var opts: Options = .{};
|
||||||
|
defer opts.deinit();
|
||||||
|
|
||||||
|
{
|
||||||
|
var iter = try std.process.argsWithAllocator(alloc);
|
||||||
|
defer iter.deinit();
|
||||||
|
try args.parse(Options, alloc, &opts, &iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
const stdout = std.io.getStdOut().writer();
|
||||||
|
|
||||||
|
var cfg = try Config.default(alloc);
|
||||||
|
defer cfg.deinit();
|
||||||
|
|
||||||
|
// If a config path is passed, validate it, otherwise validate default configs
|
||||||
|
if (opts.@"config-file") |config_path| {
|
||||||
|
var buf: [std.fs.max_path_bytes]u8 = undefined;
|
||||||
|
const abs_path = try std.fs.cwd().realpath(config_path, &buf);
|
||||||
|
|
||||||
|
try cfg.loadFile(alloc, abs_path);
|
||||||
|
try cfg.loadRecursiveFiles(alloc);
|
||||||
|
} else {
|
||||||
|
cfg = try Config.load(alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
try cfg.finalize();
|
||||||
|
|
||||||
|
if (!cfg._errors.empty()) {
|
||||||
|
for (cfg._errors.list.items) |err| {
|
||||||
|
try stdout.print("{s}\n", .{err.message});
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1785,22 +1785,30 @@ pub fn loadIter(
|
|||||||
try cli.args.parse(Config, alloc, self, iter);
|
try cli.args.parse(Config, alloc, self, iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Load configuration from the target config file at `path`.
|
||||||
|
///
|
||||||
|
/// `path` must be resolved and absolute.
|
||||||
|
pub fn loadFile(self: *Config, alloc: Allocator, path: []const u8) !void {
|
||||||
|
assert(std.fs.path.isAbsolute(path));
|
||||||
|
|
||||||
|
var file = try std.fs.cwd().openFile(path, .{});
|
||||||
|
defer file.close();
|
||||||
|
|
||||||
|
std.log.info("reading configuration file path={s}", .{path});
|
||||||
|
|
||||||
|
var buf_reader = std.io.bufferedReader(file.reader());
|
||||||
|
var iter = cli.args.lineIterator(buf_reader.reader());
|
||||||
|
try self.loadIter(alloc, &iter);
|
||||||
|
try self.expandPaths(std.fs.path.dirname(path).?);
|
||||||
|
}
|
||||||
|
|
||||||
/// Load the configuration from the default configuration file. The default
|
/// Load the configuration from the default configuration file. The default
|
||||||
/// configuration file is at `$XDG_CONFIG_HOME/ghostty/config`.
|
/// configuration file is at `$XDG_CONFIG_HOME/ghostty/config`.
|
||||||
pub fn loadDefaultFiles(self: *Config, alloc: Allocator) !void {
|
pub fn loadDefaultFiles(self: *Config, alloc: Allocator) !void {
|
||||||
const config_path = try internal_os.xdg.config(alloc, .{ .subdir = "ghostty/config" });
|
const config_path = try internal_os.xdg.config(alloc, .{ .subdir = "ghostty/config" });
|
||||||
defer alloc.free(config_path);
|
defer alloc.free(config_path);
|
||||||
|
|
||||||
const cwd = std.fs.cwd();
|
self.loadFile(alloc, config_path) catch |err| switch (err) {
|
||||||
if (cwd.openFile(config_path, .{})) |file| {
|
|
||||||
defer file.close();
|
|
||||||
std.log.info("reading configuration file path={s}", .{config_path});
|
|
||||||
|
|
||||||
var buf_reader = std.io.bufferedReader(file.reader());
|
|
||||||
var iter = cli.args.lineIterator(buf_reader.reader());
|
|
||||||
try self.loadIter(alloc, &iter);
|
|
||||||
try self.expandPaths(std.fs.path.dirname(config_path).?);
|
|
||||||
} else |err| switch (err) {
|
|
||||||
error.FileNotFound => std.log.info(
|
error.FileNotFound => std.log.info(
|
||||||
"homedir config not found, not loading path={s}",
|
"homedir config not found, not loading path={s}",
|
||||||
.{config_path},
|
.{config_path},
|
||||||
@ -1810,7 +1818,7 @@ pub fn loadDefaultFiles(self: *Config, alloc: Allocator) !void {
|
|||||||
"error reading config file, not loading err={} path={s}",
|
"error reading config file, not loading err={} path={s}",
|
||||||
.{ err, config_path },
|
.{ err, config_path },
|
||||||
),
|
),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load and parse the CLI args.
|
/// Load and parse the CLI args.
|
||||||
|
Reference in New Issue
Block a user