plumb through the resources dir to termio

This commit is contained in:
Mitchell Hashimoto
2023-08-08 09:29:38 -07:00
parent bd7cc4b71d
commit 6b45d931c3
5 changed files with 16 additions and 88 deletions

View File

@ -182,6 +182,7 @@ pub fn init(
alloc: Allocator, alloc: Allocator,
config: *const configpkg.Config, config: *const configpkg.Config,
app_mailbox: App.Mailbox, app_mailbox: App.Mailbox,
app_resources_dir: ?[]const u8,
rt_surface: *apprt.runtime.Surface, rt_surface: *apprt.runtime.Surface,
) !void { ) !void {
// Initialize our renderer with our initialized surface. // Initialize our renderer with our initialized surface.
@ -405,6 +406,7 @@ pub fn init(
.screen_size = screen_size, .screen_size = screen_size,
.full_config = config, .full_config = config,
.config = try termio.Impl.DerivedConfig.init(alloc, config), .config = try termio.Impl.DerivedConfig.init(alloc, config),
.resources_dir = app_resources_dir,
.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,

View File

@ -363,6 +363,7 @@ pub const Surface = struct {
app.app.alloc, app.app.alloc,
&config, &config,
.{ .rt_app = app, .mailbox = &app.app.mailbox }, .{ .rt_app = app, .mailbox = &app.app.mailbox },
app.app.resources_dir,
self, self,
); );
errdefer self.core_surface.deinit(); errdefer self.core_surface.deinit();

View File

@ -765,6 +765,7 @@ pub const Surface = struct {
self.app.core_app.alloc, self.app.core_app.alloc,
&config, &config,
.{ .rt_app = self.app, .mailbox = &self.app.core_app.mailbox }, .{ .rt_app = self.app, .mailbox = &self.app.core_app.mailbox },
self.app.core_app.resources_dir,
self, self,
); );
errdefer self.core_surface.deinit(); errdefer self.core_surface.deinit();

View File

@ -544,26 +544,12 @@ const Subprocess = struct {
}; };
errdefer env.deinit(); errdefer env.deinit();
// Get our bundled resources directory, if it exists. We use this // If we have a resources dir then set our env var
// for terminfo, shell-integration, etc.
const resources_key = "GHOSTTY_RESOURCES_DIR"; const resources_key = "GHOSTTY_RESOURCES_DIR";
const resources_dir = dir: { if (opts.resources_dir) |dir| {
if (env.get(resources_key)) |dir| { log.info("found Ghostty resources dir: {s}", .{dir});
if (dir.len > 0) { try env.put(resources_key, dir);
log.info("using Ghostty resources dir from env var: {s}", .{dir}); }
break :dir dir;
}
}
if (try resourcesDir(alloc)) |dir| {
log.info("found Ghostty resources dir: {s}", .{dir});
try env.put(resources_key, dir);
break :dir dir;
}
log.warn("Ghostty resources dir not found, some features disabled", .{});
break :dir null;
};
// Set our TERM var. This is a bit complicated because we want to use // Set our TERM var. This is a bit complicated because we want to use
// the ghostty TERM value but we want to only do that if we have // the ghostty TERM value but we want to only do that if we have
@ -571,7 +557,9 @@ const Subprocess = struct {
// //
// For now, we just look up a bundled dir but in the future we should // For now, we just look up a bundled dir but in the future we should
// also load the terminfo database and look for it. // also load the terminfo database and look for it.
if (try terminfoDir(alloc, resources_dir)) |dir| { if (opts.resources_dir) |base| {
var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
const dir = try std.fmt.bufPrint(&buf, "{s}/terminfo", .{base});
try env.put("TERM", "xterm-ghostty"); try env.put("TERM", "xterm-ghostty");
try env.put("COLORTERM", "truecolor"); try env.put("COLORTERM", "truecolor");
try env.put("TERMINFO", dir); try env.put("TERMINFO", dir);
@ -641,7 +629,7 @@ const Subprocess = struct {
.zsh => .zsh, .zsh => .zsh,
}; };
const dir = resources_dir orelse break :shell null; const dir = opts.resources_dir orelse break :shell null;
break :shell try shell_integration.setup( break :shell try shell_integration.setup(
dir, dir,
final_path, final_path,
@ -860,73 +848,6 @@ const Subprocess = struct {
fn killCommandFlatpak(command: *FlatpakHostCommand) !void { fn killCommandFlatpak(command: *FlatpakHostCommand) !void {
try command.signal(c.SIGHUP, true); try command.signal(c.SIGHUP, true);
} }
/// Gets the directory to the terminfo database, if it can be detected.
/// The memory returned can't be easily freed so the alloc should be
/// an arena or something similar.
fn terminfoDir(alloc: Allocator, base: ?[]const u8) !?[]const u8 {
const dir = base orelse return null;
return try tryDir(alloc, dir, "terminfo", "");
}
/// Gets the directory to the bundled resources directory, if it
/// exists (not all platforms or packages have it).
///
/// The memory returned can't be easily freed so the alloc should be
/// an arena or something similar.
fn resourcesDir(alloc: Allocator) !?[]const u8 {
// This is the sentinel value we look for in the path to know
// we've found the resources directory.
const sentinel = "terminfo/ghostty.termcap";
// Get the path to our running binary
var exe_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
var exe: []const u8 = std.fs.selfExePath(&exe_buf) catch return null;
// We have an exe path! Climb the tree looking for the terminfo
// bundle as we expect it.
while (std.fs.path.dirname(exe)) |dir| {
exe = dir;
// On MacOS, we look for the app bundle path.
if (comptime builtin.target.isDarwin()) {
if (try tryDir(alloc, dir, "Contents/Resources", sentinel)) |v| {
return v;
}
}
// On all platforms, we look for a /usr/share style path. This
// is valid even on Mac since there is nothing that requires
// Ghostty to be in an app bundle.
if (try tryDir(alloc, dir, "share", sentinel)) |v| {
return v;
}
}
return null;
}
/// Little helper to check if the "base/sub/suffix" directory exists and
/// if so, duplicate the "base/sub" path and return it.
fn tryDir(
alloc: Allocator,
base: []const u8,
sub: []const u8,
suffix: []const u8,
) !?[]const u8 {
var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
const path = try std.fmt.bufPrint(&buf, "{s}/{s}/{s}", .{ base, sub, suffix });
if (std.fs.accessAbsolute(path, .{})) {
const len = path.len - suffix.len - 1;
return try alloc.dupe(u8, path[0..len]);
} else |_| {
// Folder doesn't exist. If a different error happens its okay
// we just ignore it and move on.
}
return null;
}
}; };
/// The read thread sits in a loop doing the following pseudo code: /// The read thread sits in a loop doing the following pseudo code:

View File

@ -20,6 +20,9 @@ full_config: *const Config,
/// The derived configuration for this termio implementation. /// The derived configuration for this termio implementation.
config: termio.Impl.DerivedConfig, config: termio.Impl.DerivedConfig,
/// The application resources directory.
resources_dir: ?[]const u8,
/// 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
/// is free to change that if that is useful (i.e. doing some sort of dual /// is free to change that if that is useful (i.e. doing some sort of dual