termio: use DerivedConfig

This commit is contained in:
Mitchell Hashimoto
2023-03-19 10:09:17 -07:00
parent 7eda21d544
commit 8f0be3ad9e
5 changed files with 72 additions and 8 deletions

View File

@ -362,7 +362,8 @@ pub fn init(
var io = try termio.Impl.init(alloc, .{ var io = try termio.Impl.init(alloc, .{
.grid_size = grid_size, .grid_size = grid_size,
.screen_size = screen_size, .screen_size = screen_size,
.config = config, .full_config = config,
.config = try termio.Impl.DerivedConfig.init(alloc, config),
.renderer_state = &self.renderer_state, .renderer_state = &self.renderer_state,
.renderer_wakeup = render_thread.wakeup, .renderer_wakeup = render_thread.wakeup,
.renderer_mailbox = render_thread.mailbox, .renderer_mailbox = render_thread.mailbox,
@ -572,11 +573,22 @@ fn changeConfig(self: *Surface, config: *const configpkg.Config) !void {
// then send them a message to update. // then send them a message to update.
var renderer_config = try Renderer.DerivedConfig.init(self.alloc, config); var renderer_config = try Renderer.DerivedConfig.init(self.alloc, config);
errdefer renderer_config.deinit(); errdefer renderer_config.deinit();
// TODO: termio config var termio_config = try termio.Impl.DerivedConfig.init(self.alloc, config);
errdefer termio_config.deinit();
_ = self.renderer_thread.mailbox.push(.{ _ = self.renderer_thread.mailbox.push(.{
.change_config = renderer_config, .change_config = renderer_config,
}, .{ .forever = {} }); }, .{ .forever = {} });
_ = self.io_thread.mailbox.push(.{
.change_config = termio_config,
}, .{ .forever = {} });
// With mailbox messages sent, we have to wake them up so they process it.
self.queueRender() catch |err| {
log.warn("failed to notify renderer of config change err={}", .{err});
};
self.io_thread.wakeup.notify() catch |err| {
log.warn("failed to notify io thread of config change err={}", .{err});
};
} }
/// Returns the x/y coordinate of where the IME (Input Method Editor) /// Returns the x/y coordinate of where the IME (Input Method Editor)

View File

@ -6,6 +6,7 @@ const builtin = @import("builtin");
const build_config = @import("../build_config.zig"); const build_config = @import("../build_config.zig");
const assert = std.debug.assert; const assert = std.debug.assert;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator;
const EnvMap = std.process.EnvMap; const EnvMap = std.process.EnvMap;
const termio = @import("../termio.zig"); const termio = @import("../termio.zig");
const Command = @import("../Command.zig"); const Command = @import("../Command.zig");
@ -19,6 +20,7 @@ const trace = tracy.trace;
const apprt = @import("../apprt.zig"); const apprt = @import("../apprt.zig");
const fastmem = @import("../fastmem.zig"); const fastmem = @import("../fastmem.zig");
const internal_os = @import("../os/main.zig"); const internal_os = @import("../os/main.zig");
const configpkg = @import("../config.zig");
const log = std.log.scoped(.io_exec); const log = std.log.scoped(.io_exec);
@ -62,9 +64,35 @@ grid_size: renderer.GridSize,
/// The data associated with the currently running thread. /// The data associated with the currently running thread.
data: ?*EventData, data: ?*EventData,
/// The configuration for this IO that is derived from the main
/// configuration. This must be exported so that we don't need to
/// pass around Config pointers which makes memory management a pain.
pub const DerivedConfig = struct {
palette: terminal.color.Palette,
pub fn init(
alloc_gpa: Allocator,
config: *const configpkg.Config,
) !DerivedConfig {
_ = alloc_gpa;
return .{
.palette = config.palette.value,
};
}
pub fn deinit(self: *DerivedConfig) void {
_ = self;
}
};
/// Initialize the exec implementation. This will also start the child /// Initialize the exec implementation. This will also start the child
/// process. /// process.
pub fn init(alloc: Allocator, opts: termio.Options) !Exec { pub fn init(alloc: Allocator, opts: termio.Options) !Exec {
// Clean up our derived config because we don't need it after this.
var config = opts.config;
defer config.deinit();
// Create our terminal // Create our terminal
var term = try terminal.Terminal.init( var term = try terminal.Terminal.init(
alloc, alloc,
@ -72,7 +100,7 @@ pub fn init(alloc: Allocator, opts: termio.Options) !Exec {
opts.grid_size.rows, opts.grid_size.rows,
); );
errdefer term.deinit(alloc); errdefer term.deinit(alloc);
term.color_palette = opts.config.palette.value; term.color_palette = opts.config.palette;
var subprocess = try Subprocess.init(alloc, opts); var subprocess = try Subprocess.init(alloc, opts);
errdefer subprocess.deinit(); errdefer subprocess.deinit();
@ -189,6 +217,14 @@ pub fn threadExit(self: *Exec, data: ThreadData) void {
data.read_thread.join(); data.read_thread.join();
} }
/// Update the configuration.
pub fn changeConfig(self: *Exec, config: DerivedConfig) !void {
var copy = config;
defer copy.deinit();
self.terminal.color_palette = config.palette;
}
/// Resize the terminal. /// Resize the terminal.
pub fn resize( pub fn resize(
self: *Exec, self: *Exec,
@ -413,7 +449,7 @@ const Subprocess = struct {
const alloc = arena.allocator(); const alloc = arena.allocator();
// Determine the path to the binary we're executing // Determine the path to the binary we're executing
const path = (try Command.expandPath(alloc, opts.config.command orelse "sh")) orelse const path = (try Command.expandPath(alloc, opts.full_config.command orelse "sh")) orelse
return error.CommandNotFound; return error.CommandNotFound;
// On macOS, we launch the program as a login shell. This is a Mac-specific // On macOS, we launch the program as a login shell. This is a Mac-specific
@ -487,10 +523,17 @@ const Subprocess = struct {
break :args try args.toOwnedSlice(); break :args try args.toOwnedSlice();
}; };
// We have to copy the cwd because there is no guarantee that
// pointers in full_config remain valid.
var cwd: ?[]u8 = if (opts.full_config.@"working-directory") |cwd|
try alloc.dupe(u8, cwd)
else
null;
return .{ return .{
.arena = arena, .arena = arena,
.env = env, .env = env,
.cwd = opts.config.@"working-directory", .cwd = cwd,
.path = if (internal_os.isFlatpak()) args[0] else path, .path = if (internal_os.isFlatpak()) args[0] else path,
.args = args, .args = args,
.grid_size = opts.grid_size, .grid_size = opts.grid_size,

View File

@ -4,6 +4,7 @@ const xev = @import("xev");
const apprt = @import("../apprt.zig"); const apprt = @import("../apprt.zig");
const renderer = @import("../renderer.zig"); const renderer = @import("../renderer.zig");
const Config = @import("../config.zig").Config; const Config = @import("../config.zig").Config;
const termio = @import("../termio.zig");
/// The size of the terminal grid. /// The size of the terminal grid.
grid_size: renderer.GridSize, grid_size: renderer.GridSize,
@ -11,10 +12,13 @@ grid_size: renderer.GridSize,
/// The size of the viewport in pixels. /// The size of the viewport in pixels.
screen_size: renderer.ScreenSize, screen_size: renderer.ScreenSize,
/// The app configuration. This must NOT be stored by any termio implementation. /// The full app configuration. This is only available during initialization.
/// The memory it points to is NOT stable after the init call so any values /// The memory it points to is NOT stable after the init call so any values
/// in here must be copied. /// in here must be copied.
config: *const Config, full_config: *const Config,
/// The derived configuration for this termio implementation.
config: termio.Impl.DerivedConfig,
/// The render state. The IO implementation can modify anything here. The /// The render state. The IO implementation can modify anything here. The
/// surface thread will setup the initial "terminal" pointer but the IO impl /// surface thread will setup the initial "terminal" pointer but the IO impl

View File

@ -150,6 +150,7 @@ fn drainMailbox(self: *Thread) !void {
log.debug("mailbox message={}", .{message}); log.debug("mailbox message={}", .{message});
switch (message) { switch (message) {
.change_config => |config| try self.impl.changeConfig(config),
.resize => |v| self.handleResize(v), .resize => |v| self.handleResize(v),
.clear_screen => |v| try self.impl.clearScreen(v.history), .clear_screen => |v| try self.impl.clearScreen(v.history),
.write_small => |v| try self.impl.queueWrite(v.data[0..v.len]), .write_small => |v| try self.impl.queueWrite(v.data[0..v.len]),

View File

@ -3,6 +3,7 @@ const assert = std.debug.assert;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const renderer = @import("../renderer.zig"); const renderer = @import("../renderer.zig");
const terminal = @import("../terminal/main.zig"); const terminal = @import("../terminal/main.zig");
const termio = @import("../termio.zig");
/// The messages that can be sent to an IO thread. /// The messages that can be sent to an IO thread.
/// ///
@ -28,6 +29,9 @@ pub const Message = union(enum) {
padding: renderer.Padding, padding: renderer.Padding,
}; };
/// The derived configuration to update the implementation with.
change_config: termio.Impl.DerivedConfig,
/// Resize the window. /// Resize the window.
resize: Resize, resize: Resize,