apprt/embedded: ghostty_cli_main

This commit is contained in:
Mitchell Hashimoto
2023-09-20 12:35:52 -07:00
parent cdbf16e13b
commit 7059b4f74d
4 changed files with 55 additions and 10 deletions

View File

@ -351,6 +351,7 @@ typedef struct {
// Published API
int ghostty_init(void);
void ghostty_cli_main(uintptr_t, char **);
ghostty_info_s ghostty_info(void);
ghostty_config_t ghostty_config_new();

View File

@ -1,12 +1,14 @@
import AppKit
import Cocoa
import GhosttyKit
// We put the GHOSTTY_MAC_APP env var into the Info.plist to detect
// whether we launch from the app or not. A user can fake this if
// they want but they're doing so at their own detriment...
let process = ProcessInfo.processInfo
if (process.environment["GHOSTTY_MAC_APP"] == "") {
AppDelegate.logger.warning("NOT IN THE MAC APP")
ghostty_cli_main(UInt(CommandLine.argc), CommandLine.unsafeArgv)
exit(1)
}
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)

View File

@ -23,7 +23,13 @@ const Ghostty = @import("main_c.zig").Ghostty;
/// rely on allocators being passed in as parameters.
pub var state: GlobalState = undefined;
pub fn main() !void {
/// The return type for main() depends on the build artifact.
const MainReturn = switch (build_config.artifact) {
.lib => noreturn,
else => void,
};
pub fn main() !MainReturn {
// We first start by initializing our global state. This will setup
// process-level state we need to run the terminal. The reason we use
// a global is because the C API needs to be able to access this state;
@ -67,6 +73,24 @@ pub fn main() !void {
return;
}
if (comptime build_config.app_runtime == .none) {
const stdout = std.io.getStdOut().writer();
try stdout.print("Usage: ghostty +<action> [flags]\n\n", .{});
try stdout.print(
\\This is the Ghostty helper CLI that accompanies the graphical Ghostty app.
\\To launch the terminal directly, please launch the graphical app
\\(i.e. Ghostty.app on macOS). This CLI can be used to perform various
\\actions such as inspecting the version, listing fonts, etc.
\\
\\We don't have proper help output yet, sorry! Please refer to the
\\source code or Discord community for help for now. We'll fix this in time.
,
.{},
);
std.os.exit(0);
}
// Create our app state
var app = try App.create(alloc);
defer app.destroy();
@ -156,6 +180,7 @@ pub const GlobalState = struct {
stderr: void,
};
/// Initialize the global state.
pub fn init(self: *GlobalState) !void {
// Initialize ourself to nothing so we don't have any extra state.
// IMPORTANT: this MUST be initialized before any log output because
@ -201,15 +226,12 @@ pub const GlobalState = struct {
};
// We first try to parse any action that we may be executing.
// We do not execute this in the lib because os.argv is not set.
if (comptime build_config.artifact != .lib) {
self.action = try cli_action.Action.detectCLI(self.alloc);
self.action = try cli_action.Action.detectCLI(self.alloc);
// If we have an action executing, we disable logging by default
// since we write to stderr we don't want logs messing up our
// output.
if (self.action != null) self.logging = .{ .disabled = {} };
}
// If we have an action executing, we disable logging by default
// since we write to stderr we don't want logs messing up our
// output.
if (self.action != null) self.logging = .{ .disabled = {} };
// I don't love the env var name but I don't have it in my heart
// to parse CLI args 3 times (once for actions, once for config,

View File

@ -42,13 +42,33 @@ const Info = extern struct {
/// one global state but it has zero practical benefit.
export fn ghostty_init() c_int {
assert(builtin.link_libc);
// Since in the lib we don't go through start.zig, we need
// to populate argv so that inspecting std.os.argv doesn't
// touch uninitialized memory.
var argv: [0][*:0]u8 = .{};
std.os.argv = &argv;
main.state.init() catch |err| {
std.log.err("failed to initialize ghostty error={}", .{err});
return 1;
};
return 0;
}
/// This is the entrypoint for the CLI version of Ghostty. This
/// is mutually exclusive to ghostty_init. Do NOT run ghostty_init
/// if you are going to run this. This will not return.
export fn ghostty_cli_main(argc: usize, argv: [*][*:0]u8) noreturn {
std.os.argv = argv[0..argc];
main.main() catch |err| {
std.log.err("failed to run ghostty error={}", .{err});
std.os.exit(1);
};
}
/// Return metadata about Ghostty, such as version, build mode, etc.
export fn ghostty_info() Info {
return .{
.mode = switch (builtin.mode) {