mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-20 10:46:07 +03:00
config: add "theme" config, track inputs
This commit is contained in:
@ -67,6 +67,11 @@ pub fn parse(comptime T: type, alloc: Allocator, dst: *T, iter: anytype) !void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
while (iter.next()) |arg| {
|
while (iter.next()) |arg| {
|
||||||
|
// If an _inputs fields exist we keep track of the inputs.
|
||||||
|
if (@hasField(T, "_inputs")) {
|
||||||
|
try dst._inputs.append(arena_alloc, try arena_alloc.dupe(u8, arg));
|
||||||
|
}
|
||||||
|
|
||||||
// Do manual parsing if we have a hook for it.
|
// Do manual parsing if we have a hook for it.
|
||||||
if (@hasDecl(T, "parseManuallyHook")) {
|
if (@hasDecl(T, "parseManuallyHook")) {
|
||||||
if (!try dst.parseManuallyHook(arena_alloc, arg, iter)) return;
|
if (!try dst.parseManuallyHook(arena_alloc, arg, iter)) return;
|
||||||
@ -381,6 +386,30 @@ test "parse: error tracking" {
|
|||||||
try testing.expect(!data._errors.empty());
|
try testing.expect(!data._errors.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "parse: input tracking" {
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
var data: struct {
|
||||||
|
a: []const u8 = "",
|
||||||
|
b: enum { one } = .one,
|
||||||
|
|
||||||
|
_arena: ?ArenaAllocator = null,
|
||||||
|
_errors: ErrorList = .{},
|
||||||
|
_inputs: std.ArrayListUnmanaged([]const u8) = .{},
|
||||||
|
} = .{};
|
||||||
|
defer if (data._arena) |arena| arena.deinit();
|
||||||
|
|
||||||
|
var iter = try std.process.ArgIteratorGeneral(.{}).init(
|
||||||
|
testing.allocator,
|
||||||
|
"--what --a=42",
|
||||||
|
);
|
||||||
|
defer iter.deinit();
|
||||||
|
try parse(@TypeOf(data), testing.allocator, &data, &iter);
|
||||||
|
try testing.expect(data._arena != null);
|
||||||
|
try testing.expect(data._inputs.items.len == 2);
|
||||||
|
try testing.expectEqualStrings("--what", data._inputs.items[0]);
|
||||||
|
try testing.expectEqualStrings("--a=42", data._inputs.items[1]);
|
||||||
|
}
|
||||||
test "parseIntoField: ignore underscore-prefixed fields" {
|
test "parseIntoField: ignore underscore-prefixed fields" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
var arena = ArenaAllocator.init(testing.allocator);
|
var arena = ArenaAllocator.init(testing.allocator);
|
||||||
@ -732,6 +761,25 @@ pub fn lineIterator(reader: anytype) LineIterator(@TypeOf(reader)) {
|
|||||||
return .{ .r = reader };
|
return .{ .r = reader };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An iterator valid for arg parsing from a slice.
|
||||||
|
pub const SliceIterator = struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
slice: []const []const u8,
|
||||||
|
idx: usize = 0,
|
||||||
|
|
||||||
|
pub fn next(self: *Self) ?[]const u8 {
|
||||||
|
if (self.idx >= self.slice.len) return null;
|
||||||
|
defer self.idx += 1;
|
||||||
|
return self.slice[self.idx];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Construct a SliceIterator from a slice.
|
||||||
|
pub fn sliceIterator(slice: []const []const u8) SliceIterator {
|
||||||
|
return .{ .slice = slice };
|
||||||
|
}
|
||||||
|
|
||||||
test "LineIterator" {
|
test "LineIterator" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
var fbs = std.io.fixedBufferStream(
|
var fbs = std.io.fixedBufferStream(
|
||||||
|
@ -153,6 +153,19 @@ const c = @cImport({
|
|||||||
@"adjust-strikethrough-position": ?MetricModifier = null,
|
@"adjust-strikethrough-position": ?MetricModifier = null,
|
||||||
@"adjust-strikethrough-thickness": ?MetricModifier = null,
|
@"adjust-strikethrough-thickness": ?MetricModifier = null,
|
||||||
|
|
||||||
|
/// A named theme to use. The available themes are currently hardcoded to
|
||||||
|
/// the themes that ship with Ghostty. On macOS, this list is in the
|
||||||
|
/// `Ghostty.app/Contents/Resources/themes` directory. On Linux, this
|
||||||
|
/// list is in the `share/ghostty/themes` directory (wherever you installed
|
||||||
|
/// the Ghostty "share" directory.
|
||||||
|
///
|
||||||
|
/// Any additional colors specified via background, foreground, palette,
|
||||||
|
/// etc. will override the colors specified in the theme.
|
||||||
|
///
|
||||||
|
/// A future update will allow custom themes to be installed in
|
||||||
|
/// certain directories.
|
||||||
|
theme: ?[]const u8 = null,
|
||||||
|
|
||||||
/// Background color for the window.
|
/// Background color for the window.
|
||||||
background: Color = .{ .r = 0x28, .g = 0x2C, .b = 0x34 },
|
background: Color = .{ .r = 0x28, .g = 0x2C, .b = 0x34 },
|
||||||
|
|
||||||
@ -726,6 +739,10 @@ _arena: ?ArenaAllocator = null,
|
|||||||
/// configuration file.
|
/// configuration file.
|
||||||
_errors: ErrorList = .{},
|
_errors: ErrorList = .{},
|
||||||
|
|
||||||
|
/// The inputs that built up this configuration. This is used to reload
|
||||||
|
/// the configuration if we have to.
|
||||||
|
_inputs: std.ArrayListUnmanaged([]const u8) = .{},
|
||||||
|
|
||||||
pub fn deinit(self: *Config) void {
|
pub fn deinit(self: *Config) void {
|
||||||
if (self._arena) |arena| arena.deinit();
|
if (self._arena) |arena| arena.deinit();
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
@ -1182,6 +1199,16 @@ fn ctrlOrSuper(mods: inputpkg.Mods) inputpkg.Mods {
|
|||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Load configuration from an iterator that yields values that look like
|
||||||
|
/// command-line arguments, i.e. `--key=value`.
|
||||||
|
pub fn loadIter(
|
||||||
|
self: *Config,
|
||||||
|
alloc: Allocator,
|
||||||
|
iter: anytype,
|
||||||
|
) !void {
|
||||||
|
try cli.args.parse(Config, alloc, self, iter);
|
||||||
|
}
|
||||||
|
|
||||||
/// 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 {
|
||||||
@ -1195,7 +1222,7 @@ pub fn loadDefaultFiles(self: *Config, alloc: Allocator) !void {
|
|||||||
|
|
||||||
var buf_reader = std.io.bufferedReader(file.reader());
|
var buf_reader = std.io.bufferedReader(file.reader());
|
||||||
var iter = cli.args.lineIterator(buf_reader.reader());
|
var iter = cli.args.lineIterator(buf_reader.reader());
|
||||||
try cli.args.parse(Config, alloc, self, &iter);
|
try self.loadIter(alloc, &iter);
|
||||||
try self.expandPaths(std.fs.path.dirname(config_path).?);
|
try self.expandPaths(std.fs.path.dirname(config_path).?);
|
||||||
} else |err| switch (err) {
|
} else |err| switch (err) {
|
||||||
error.FileNotFound => std.log.info(
|
error.FileNotFound => std.log.info(
|
||||||
@ -1222,7 +1249,7 @@ pub fn loadCliArgs(self: *Config, alloc_gpa: Allocator) !void {
|
|||||||
// Parse the config from the CLI args
|
// Parse the config from the CLI args
|
||||||
var iter = try std.process.argsWithAllocator(alloc_gpa);
|
var iter = try std.process.argsWithAllocator(alloc_gpa);
|
||||||
defer iter.deinit();
|
defer iter.deinit();
|
||||||
try cli.args.parse(Config, alloc_gpa, self, &iter);
|
try self.loadIter(alloc_gpa, &iter);
|
||||||
|
|
||||||
// Config files loaded from the CLI args are relative to pwd
|
// Config files loaded from the CLI args are relative to pwd
|
||||||
if (self.@"config-file".value.list.items.len > 0) {
|
if (self.@"config-file".value.list.items.len > 0) {
|
||||||
@ -1279,7 +1306,7 @@ pub fn loadRecursiveFiles(self: *Config, alloc_gpa: Allocator) !void {
|
|||||||
log.info("loading config-file path={s}", .{path});
|
log.info("loading config-file path={s}", .{path});
|
||||||
var buf_reader = std.io.bufferedReader(file.reader());
|
var buf_reader = std.io.bufferedReader(file.reader());
|
||||||
var iter = cli.args.lineIterator(buf_reader.reader());
|
var iter = cli.args.lineIterator(buf_reader.reader());
|
||||||
try cli.args.parse(Config, alloc_gpa, self, &iter);
|
try self.loadIter(alloc_gpa, &iter);
|
||||||
try self.expandPaths(std.fs.path.dirname(path).?);
|
try self.expandPaths(std.fs.path.dirname(path).?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user