macos: Default working directory to home dir if launched from app

This also introduces a `--working-directory` config flag.
This commit is contained in:
Mitchell Hashimoto
2022-11-01 18:10:30 -07:00
parent 63fab367fe
commit df50aacff1
2 changed files with 44 additions and 6 deletions

View File

@ -399,6 +399,7 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
.path = path, .path = path,
.args = &[_][]const u8{path}, .args = &[_][]const u8{path},
.env = &env, .env = &env,
.cwd = config.@"working-directory",
.pre_exec = (struct { .pre_exec = (struct {
fn callback(c: *Command) void { fn callback(c: *Command) void {
const p = c.getData(Pty) orelse unreachable; const p = c.getData(Pty) orelse unreachable;

View File

@ -7,6 +7,11 @@ const passwd = @import("passwd.zig");
const log = std.log.scoped(.config); const log = std.log.scoped(.config);
/// Used on Unixes for some defaults.
const c = @cImport({
@cInclude("unistd.h");
});
/// Config is the main config struct. These fields map directly to the /// Config is the main config struct. These fields map directly to the
/// CLI flag names hence we use a lot of `@""` syntax to support hyphens. /// CLI flag names hence we use a lot of `@""` syntax to support hyphens.
pub const Config = struct { pub const Config = struct {
@ -34,6 +39,20 @@ pub const Config = struct {
/// ///
command: ?[]const u8 = null, command: ?[]const u8 = null,
/// The directory to change to after starting the command.
///
/// The default is "inherit" except in special scenarios listed next.
/// If ghostty can detect it is launched on macOS from launchd
/// (double-clicked), then it defaults to "home".
///
/// The value of this must be an absolute value or one of the special
/// values below:
///
/// - "home" - The home directory of the executing user.
/// - "inherit" - The working directory of the launching process.
///
@"working-directory": ?[]const u8 = null,
/// Key bindings. The format is "trigger=action". Duplicate triggers /// Key bindings. The format is "trigger=action". Duplicate triggers
/// will overwrite previously set values. /// will overwrite previously set values.
/// ///
@ -154,25 +173,43 @@ pub const Config = struct {
} }
} }
// The default for the working directory depends on the system.
const wd_default = switch (builtin.os.tag) {
.macos => if (c.getppid() == 1) "home" else "inherit",
else => "inherit",
};
// If we are missing either a command or home directory, we need // If we are missing either a command or home directory, we need
// to look up defaults which is kind of expensive. // to look up defaults which is kind of expensive.
if (self.command == null) command: { const wd_home = std.mem.eql(u8, "home", self.@"working-directory" orelse wd_default);
if (self.command == null or wd_home) command: {
const alloc = self._arena.?.allocator(); const alloc = self._arena.?.allocator();
// First look up the command using the SHELL env var. // First look up the command using the SHELL env var.
if (std.process.getEnvVarOwned(alloc, "SHELL")) |value| { if (std.process.getEnvVarOwned(alloc, "SHELL")) |value| {
log.debug("default shell source=env value={s}", .{value}); log.debug("default shell source=env value={s}", .{value});
self.command = value; self.command = value;
break :command;
// If we don't need the working directory, then we can exit now.
if (!wd_home) break :command;
} else |_| {} } else |_| {}
// Get the shell from the passwd entry // We need the passwd entry for the remainder
const pw = try passwd.get(alloc); const pw = try passwd.get(alloc);
if (self.command == null) {
if (pw.shell) |sh| { if (pw.shell) |sh| {
log.debug("default shell src=passwd value={s}", .{sh}); log.debug("default shell src=passwd value={s}", .{sh});
self.command = sh; self.command = sh;
} }
} }
if (wd_home) {
if (pw.home) |home| {
log.debug("default working directory src=passwd value={s}", .{home});
self.@"working-directory" = home;
}
}
}
} }
}; };