mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
config: introduce RepeatablePath to automatically expand
This commit is contained in:
@ -528,7 +528,7 @@ keybind: Keybinds = .{},
|
||||
///
|
||||
/// Cycles are not allowed. If a cycle is detected, an error will be logged
|
||||
/// and the configuration file will be ignored.
|
||||
@"config-file": RepeatableString = .{},
|
||||
@"config-file": RepeatablePath = .{},
|
||||
|
||||
/// Confirms that a surface should be closed before closing it. This defaults
|
||||
/// to true. If set to false, surfaces will close without any confirmation.
|
||||
@ -1139,7 +1139,7 @@ pub fn loadDefaultFiles(self: *Config, alloc: Allocator) !void {
|
||||
var buf_reader = std.io.bufferedReader(file.reader());
|
||||
var iter = cli.args.lineIterator(buf_reader.reader());
|
||||
try cli.args.parse(Config, alloc, self, &iter);
|
||||
try self.expandConfigFiles(std.fs.path.dirname(config_path).?);
|
||||
try self.expandPaths(std.fs.path.dirname(config_path).?);
|
||||
} else |err| switch (err) {
|
||||
error.FileNotFound => std.log.info(
|
||||
"homedir config not found, not loading path={s}",
|
||||
@ -1168,15 +1168,15 @@ pub fn loadCliArgs(self: *Config, alloc_gpa: Allocator) !void {
|
||||
try cli.args.parse(Config, alloc_gpa, self, &iter);
|
||||
|
||||
// Config files loaded from the CLI args are relative to pwd
|
||||
if (self.@"config-file".list.items.len > 0) {
|
||||
if (self.@"config-file".value.list.items.len > 0) {
|
||||
var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
||||
try self.expandConfigFiles(try std.fs.cwd().realpath(".", &buf));
|
||||
try self.expandPaths(try std.fs.cwd().realpath(".", &buf));
|
||||
}
|
||||
}
|
||||
|
||||
/// Load and parse the config files that were added in the "config-file" key.
|
||||
pub fn loadRecursiveFiles(self: *Config, alloc_gpa: Allocator) !void {
|
||||
if (self.@"config-file".list.items.len == 0) return;
|
||||
if (self.@"config-file".value.list.items.len == 0) return;
|
||||
const arena_alloc = self._arena.?.allocator();
|
||||
|
||||
// Keeps track of loaded files to prevent cycles.
|
||||
@ -1185,8 +1185,8 @@ pub fn loadRecursiveFiles(self: *Config, alloc_gpa: Allocator) !void {
|
||||
|
||||
const cwd = std.fs.cwd();
|
||||
var i: usize = 0;
|
||||
while (i < self.@"config-file".list.items.len) : (i += 1) {
|
||||
const path = self.@"config-file".list.items[i];
|
||||
while (i < self.@"config-file".value.list.items.len) : (i += 1) {
|
||||
const path = self.@"config-file".value.list.items[i];
|
||||
|
||||
// Error paths
|
||||
if (path.len == 0) continue;
|
||||
@ -1223,37 +1223,22 @@ pub fn loadRecursiveFiles(self: *Config, alloc_gpa: Allocator) !void {
|
||||
var buf_reader = std.io.bufferedReader(file.reader());
|
||||
var iter = cli.args.lineIterator(buf_reader.reader());
|
||||
try cli.args.parse(Config, alloc_gpa, self, &iter);
|
||||
try self.expandConfigFiles(std.fs.path.dirname(path).?);
|
||||
try self.expandPaths(std.fs.path.dirname(path).?);
|
||||
}
|
||||
}
|
||||
|
||||
/// Expand the relative paths in config-files to be absolute paths
|
||||
/// relative to the base directory.
|
||||
fn expandConfigFiles(self: *Config, base: []const u8) !void {
|
||||
assert(std.fs.path.isAbsolute(base));
|
||||
var dir = try std.fs.cwd().openDir(base, .{});
|
||||
defer dir.close();
|
||||
|
||||
fn expandPaths(self: *Config, base: []const u8) !void {
|
||||
const arena_alloc = self._arena.?.allocator();
|
||||
for (self.@"config-file".list.items, 0..) |path, i| {
|
||||
// If it is already absolute we can ignore it.
|
||||
if (path.len == 0 or std.fs.path.isAbsolute(path)) continue;
|
||||
|
||||
// If it isn't absolute, we need to make it absolute relative to the base.
|
||||
const abs = dir.realpathAlloc(arena_alloc, path) catch |err| {
|
||||
try self._errors.add(arena_alloc, .{
|
||||
.message = try std.fmt.allocPrintZ(
|
||||
arena_alloc,
|
||||
"error resolving config-file {s}: {}",
|
||||
.{ path, err },
|
||||
),
|
||||
});
|
||||
self.@"config-file".list.items[i] = "";
|
||||
continue;
|
||||
};
|
||||
|
||||
log.debug("expanding config-file path relative={s} abs={s}", .{ path, abs });
|
||||
self.@"config-file".list.items[i] = abs;
|
||||
inline for (@typeInfo(Config).Struct.fields) |field| {
|
||||
if (field.type == RepeatablePath) {
|
||||
try @field(self, field.name).expand(
|
||||
arena_alloc,
|
||||
base,
|
||||
&self._errors,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1885,6 +1870,69 @@ pub const RepeatableString = struct {
|
||||
}
|
||||
};
|
||||
|
||||
/// RepeatablePath is like repeatable string but represents a path value.
|
||||
/// The difference is that when loading the configuration any values for
|
||||
/// this will be automatically expanded relative to the path of the config
|
||||
/// file.
|
||||
pub const RepeatablePath = struct {
|
||||
const Self = @This();
|
||||
|
||||
value: RepeatableString = .{},
|
||||
|
||||
pub fn parseCLI(self: *Self, alloc: Allocator, input: ?[]const u8) !void {
|
||||
return self.value.parseCLI(alloc, input);
|
||||
}
|
||||
|
||||
/// Deep copy of the struct. Required by Config.
|
||||
pub fn clone(self: *const Self, alloc: Allocator) !Self {
|
||||
return .{
|
||||
.value = try self.value.clone(alloc),
|
||||
};
|
||||
}
|
||||
|
||||
/// Compare if two of our value are requal. Required by Config.
|
||||
pub fn equal(self: Self, other: Self) bool {
|
||||
return self.value.equal(other.value);
|
||||
}
|
||||
|
||||
/// Expand all the paths relative to the base directory.
|
||||
pub fn expand(
|
||||
self: *Self,
|
||||
alloc: Allocator,
|
||||
base: []const u8,
|
||||
errors: *ErrorList,
|
||||
) !void {
|
||||
assert(std.fs.path.isAbsolute(base));
|
||||
var dir = try std.fs.cwd().openDir(base, .{});
|
||||
defer dir.close();
|
||||
|
||||
for (self.value.list.items, 0..) |path, i| {
|
||||
// If it is already absolute we can ignore it.
|
||||
if (path.len == 0 or std.fs.path.isAbsolute(path)) continue;
|
||||
|
||||
// If it isn't absolute, we need to make it absolute relative
|
||||
// to the base.
|
||||
const abs = dir.realpathAlloc(alloc, path) catch |err| {
|
||||
try errors.add(alloc, .{
|
||||
.message = try std.fmt.allocPrintZ(
|
||||
alloc,
|
||||
"error resolving config-file {s}: {}",
|
||||
.{ path, err },
|
||||
),
|
||||
});
|
||||
self.value.list.items[i] = "";
|
||||
continue;
|
||||
};
|
||||
|
||||
log.debug(
|
||||
"expanding config-file path relative={s} abs={s}",
|
||||
.{ path, abs },
|
||||
);
|
||||
self.value.list.items[i] = abs;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// FontVariation is a repeatable configuration value that sets a single
|
||||
/// font variation value. Font variations are configurations for what
|
||||
/// are often called "variable fonts." The font files usually end in
|
||||
|
Reference in New Issue
Block a user