Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

config: window-inherit-working-directory options #1694

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/ghostty.h
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ typedef struct {
float font_size;
const char* working_directory;
const char* command;
void* _arena;
} ghostty_surface_config_s;

typedef void (*ghostty_runtime_wakeup_cb)(void*);
Expand Down
7 changes: 7 additions & 0 deletions src/Surface.zig
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@ config: DerivedConfig,
/// This is used to determine if we need to confirm, hold open, etc.
child_exited: bool = false,

/// The kind of surface.
pub const Kind = enum {
split,
tab,
window,
};

/// The effect of an input event. This can be used by callers to take
/// the appropriate action after an input event. For example, key
/// input can be forwarded to the OS for further processing if it
Expand Down
51 changes: 47 additions & 4 deletions src/apprt/embedded.zig
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const std = @import("std");
const builtin = @import("builtin");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator;
const objc = @import("objc");
const apprt = @import("../apprt.zig");
const font = @import("../font/main.zig");
Expand Down Expand Up @@ -329,6 +330,17 @@ pub const Surface = struct {
/// the "wait-after-command" option is also automatically set to true,
/// since this is used for scripting.
command: [*:0]const u8 = "",

_arena: ?*anyopaque = null,

pub fn deinit(self: *Options) void {
if (self._arena) |ptr| {
const arena: *ArenaAllocator = @ptrCast(@alignCast(ptr));
const alloc = arena.child_allocator;
arena.deinit();
alloc.destroy(arena);
}
}
};

/// This is the key event sent for ghostty_surface_key.
Expand Down Expand Up @@ -473,7 +485,7 @@ pub const Surface = struct {
return;
};

const options = self.newSurfaceOptions();
const options = try self.newSurfaceOptions(.split);
func(self.userdata, direction, options);
}

Expand Down Expand Up @@ -1024,7 +1036,7 @@ pub const Surface = struct {
return;
};

const options = self.newSurfaceOptions();
const options = try self.newSurfaceOptions(.tab);
func(self.userdata, options);
}

Expand All @@ -1034,7 +1046,7 @@ pub const Surface = struct {
return;
};

const options = self.newSurfaceOptions();
const options = try self.newSurfaceOptions(.window);
func(self.userdata, options);
}

Expand Down Expand Up @@ -1065,14 +1077,44 @@ pub const Surface = struct {
func(self.userdata, width, height);
}

fn newSurfaceOptions(self: *const Surface) apprt.Surface.Options {
fn newSurfaceOptions(self: *const Surface, kind: CoreSurface.Kind) !apprt.Surface.Options {
const font_size: f32 = font_size: {
if (!self.app.config.@"window-inherit-font-size") break :font_size 0;
break :font_size self.core_surface.font_size.points;
};

const working_directory: [*:0]const u8, const arena: ?*ArenaAllocator = dir: {
const prev = self.app.core_app.focusedSurface();
if (prev) |p| {
const inherit_pwd: bool = switch (kind) {
.split => self.app.config.@"window-inherit-working-directory".split,
.tab => self.app.config.@"window-inherit-working-directory".tab,
.window => self.app.config.@"window-inherit-working-directory".window,
};
if (inherit_pwd) {
const app_alloc = self.app.core_app.alloc;

var arena = try app_alloc.create(ArenaAllocator);
errdefer app_alloc.destroy(arena);

arena.* = ArenaAllocator.init(app_alloc);
errdefer arena.deinit();

const arena_alloc = arena.allocator();

if (try p.pwd(app_alloc)) |pwd| {
defer app_alloc.free(pwd);
break :dir .{ try arena_alloc.dupeZ(u8, pwd), arena };
}
}
}
break :dir .{ "", null };
};

return .{
.font_size = font_size,
.working_directory = working_directory,
._arena = arena,
};
}

Expand Down Expand Up @@ -1499,6 +1541,7 @@ pub const CAPI = struct {
app: *App,
opts: *const apprt.Surface.Options,
) !*Surface {
defer @constCast(opts).deinit();
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I acknowledge this is gross for multiple reasons.

return try app.newSurface(opts.*);
}

Expand Down
17 changes: 1 addition & 16 deletions src/apprt/surface.zig
Original file line number Diff line number Diff line change
Expand Up @@ -87,20 +87,5 @@ pub const Mailbox = struct {
/// after the surface is initialized.
pub fn newConfig(app: *const App, config: *const Config) !Config {
// Create a shallow clone
var copy = config.shallowClone(app.alloc);

// Our allocator is our config's arena
const alloc = copy._arena.?.allocator();

// Get our previously focused surface for some inherited values.
const prev = app.focusedSurface();
if (prev) |p| {
if (config.@"window-inherit-working-directory") {
if (try p.pwd(alloc)) |pwd| {
copy.@"working-directory" = pwd;
}
}
}

return copy;
return config.shallowClone(app.alloc);
}
1 change: 1 addition & 0 deletions src/config.zig
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub const RepeatableCodepointMap = Config.RepeatableCodepointMap;
pub const RepeatableFontVariation = Config.RepeatableFontVariation;
pub const RepeatableString = Config.RepeatableString;
pub const ShellIntegrationFeatures = Config.ShellIntegrationFeatures;
pub const WindowInheritWorkingDirectory = Config.WindowInheritWorkingDirectory;

// Alternate APIs
pub const CAPI = @import("config/CAPI.zig");
Expand Down
26 changes: 22 additions & 4 deletions src/config/Config.zig
Original file line number Diff line number Diff line change
Expand Up @@ -679,10 +679,21 @@ keybind: Keybinds = .{},
/// This setting is only supported currently on macOS.
@"window-vsync": bool = true,

/// If true, new windows and tabs will inherit the working directory of the
/// previously focused window. If no window was previously focused, the default
/// working directory will be used (the `working-directory` option).
@"window-inherit-working-directory": bool = true,
/// Controls whether new splits, tabs, and windows will inherit the working
/// directory of the previously focused window. If no window was previously
/// focused, the default working directory will be used (the `working-directory`
/// option).
///
/// The format is a list of values to enable, separated by commas. If you
/// prefix a value with `no-` then it is disabled. If you omit a feature,
/// its default value is used, so you must explicitly disable features you
/// don't want. You can also use `true` or `false` to turn all values on or
/// off.
///
/// Valid values are `split`, `tab`, and `window`.
///
/// `split` and `tab` are currently only supported on macOS.
@"window-inherit-working-directory": WindowInheritWorkingDirectory = .{},

/// If true, new windows and tabs will inherit the font size of the previously
/// focused window. If no window was previously focused, the default font size
Expand Down Expand Up @@ -3740,6 +3751,13 @@ pub const WindowNewTabPosition = enum {
end,
};

/// See window-inherit-working-directory
pub const WindowInheritWorkingDirectory = packed struct {
split: bool = true,
tab: bool = true,
window: bool = true,
};

/// See grapheme-width-method
pub const GraphemeWidthMethod = enum {
legacy,
Expand Down