mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-19 10:16:12 +03:00

This introduces a syntax for `command` and `initial-command` that allows the user to specify whether it should be run via `/bin/sh -c` or not. The syntax is a prefix `direct:` or `shell:` prior to the command, with no prefix implying a default behavior as documented. Previously, we unconditionally ran commands via `/bin/sh -c`, primarily to avoid having to do any shell expansion ourselves. We also leaned on it as a crutch for PATH-expansion but this is an easy problem compared to shell expansion. For the principle of least surprise, this worked well for configurations specified via the config file, and is still the default. However, these configurations are also set via the `-e` special flag to the CLI, and it is very much not the principle of least surprise to have the command run via `/bin/sh -c` in that scenario since a shell has already expanded all the arguments and given them to us in a nice separated format. But we had no way to toggle this behavior. This commit introduces the ability to do this, and changes the defaults so that `-e` doesn't shell expand. Further, we also do PATH lookups ourselves for the non-shell expanded case because thats easy (using execvpe style extensions but implemented as part of the Zig stdlib). We don't do path expansion (e.g. `~/`) because thats a shell expansion. So to be clear, there are no two polar opposite behavioes here with clear semantics: 1. Direct commands are passed to `execvpe` directly, space separated. This will not handle quoted strings, environment variables, path expansion (e.g. `~/`), command expansion (e.g. `$()`), etc. 2. Shell commands are passed to `/bin/sh -c` and will be shell expanded as per the shell's rules. This will handle everything that `sh` supports. In doing this work, I also stumbled upon a variety of smaller improvements that could be made: - A number of allocations have been removed from the startup path that only existed to add a null terminator to various strings. We now have null terminators from the beginning since we are almost always on a system that's going to need it anyways. - For bash shell integration, we no longer wrap the new bash command in a shell since we've formed a full parsed command line. - The process of creating the command to execute by termio is now unit tested, so we can test the various complex cases particularly on macOS of wrapping commands in the login command. - `xdg-terminal-exec` on Linux uses the `direct:` method by default since it is also assumed to be executed via a shell environment.
46 lines
1.9 KiB
Zig
46 lines
1.9 KiB
Zig
const builtin = @import("builtin");
|
|
|
|
const formatter = @import("config/formatter.zig");
|
|
pub const Config = @import("config/Config.zig");
|
|
pub const conditional = @import("config/conditional.zig");
|
|
pub const string = @import("config/string.zig");
|
|
pub const edit = @import("config/edit.zig");
|
|
pub const url = @import("config/url.zig");
|
|
|
|
pub const ConditionalState = conditional.State;
|
|
pub const FileFormatter = formatter.FileFormatter;
|
|
pub const entryFormatter = formatter.entryFormatter;
|
|
pub const formatEntry = formatter.formatEntry;
|
|
|
|
// Field types
|
|
pub const ClipboardAccess = Config.ClipboardAccess;
|
|
pub const Command = Config.Command;
|
|
pub const ConfirmCloseSurface = Config.ConfirmCloseSurface;
|
|
pub const CopyOnSelect = Config.CopyOnSelect;
|
|
pub const CustomShaderAnimation = Config.CustomShaderAnimation;
|
|
pub const FontSyntheticStyle = Config.FontSyntheticStyle;
|
|
pub const FontStyle = Config.FontStyle;
|
|
pub const FreetypeLoadFlags = Config.FreetypeLoadFlags;
|
|
pub const Keybinds = Config.Keybinds;
|
|
pub const MouseShiftCapture = Config.MouseShiftCapture;
|
|
pub const NonNativeFullscreen = Config.NonNativeFullscreen;
|
|
pub const OptionAsAlt = Config.OptionAsAlt;
|
|
pub const RepeatableCodepointMap = Config.RepeatableCodepointMap;
|
|
pub const RepeatableFontVariation = Config.RepeatableFontVariation;
|
|
pub const RepeatableString = Config.RepeatableString;
|
|
pub const RepeatableStringMap = @import("config/RepeatableStringMap.zig");
|
|
pub const RepeatablePath = Config.RepeatablePath;
|
|
pub const ShellIntegrationFeatures = Config.ShellIntegrationFeatures;
|
|
pub const WindowPaddingColor = Config.WindowPaddingColor;
|
|
|
|
// Alternate APIs
|
|
pub const CAPI = @import("config/CAPI.zig");
|
|
pub const Wasm = if (!builtin.target.cpu.arch.isWasm()) struct {} else @import("config/Wasm.zig");
|
|
|
|
test {
|
|
@import("std").testing.refAllDecls(@This());
|
|
|
|
// Vim syntax file, not used at runtime but we want to keep it tested.
|
|
_ = @import("config/vim.zig");
|
|
}
|