mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00

This deletes the GLFW apprt from the Ghostty codebase. The GLFW apprt was the original apprt used by Ghostty (well, before Ghostty even had the concept of an "apprt" -- it was all just a single application then). It let me iterate on the core terminal features, rendering, etc. without bothering about the UI. It was a good way to get started. But it has long since outlived its usefulness. We've had a stable GTK apprt for Linux (and Windows via WSL) and a native macOS app via libghostty for awhile now. The GLFW apprt only remained within the tree for a few reasons: 1. Primarily, it provided a faster feedback loop on macOS because building the macOS app historically required us to hop out of the zig build system and into Xcode, which is slow and cumbersome. 2. It was a convenient way to narrow whether a bug was in the core Ghostty codebase or in the apprt itself. If a bug was in both the glfw and macOS app then it was likely in the core. 3. It provided us a way on macOS to test OpenGL. All of these reasons are no longer valid. Respectively: 1. Our Zig build scripts now execute the `xcodebuild` CLI directly and can open the resulting app, stream logs, etc. This is the same experience we have on Linux. (Xcode has always been a dependency of building on macOS in general, so this is not cumbersome.) 2. We have a healthy group of maintainers, many of which have access to both macOS and Linux, so we can quickly narrow down bugs regardless of the apprt. 3. Our OpenGL renderer hasn't been compatible with macOS for some time now, so this is no longer a useful feature. At this point, the GLFW apprt is just a burden. It adds complexity across the board, and some people try to run Ghostty with it in the real world and get confused when it doesn't work (it's always been lacking in features and buggy compared to the other apprts). So, it's time to say goodbye. Its bittersweet because it is a big part of Ghostty's history, but we've grown up now and it's time to move on. Thank you, goodbye. (NOTE: If you are a user of the GLFW apprt, then please fork the project prior to this commit or start a new project based on it. We've warned against using it for a very, very long time now.)
194 lines
6.7 KiB
Zig
194 lines
6.7 KiB
Zig
//! The main entrypoint for the `ghostty` application. This also serves
|
|
//! as the process initialization code for the `libghostty` library.
|
|
|
|
const std = @import("std");
|
|
const builtin = @import("builtin");
|
|
const Allocator = std.mem.Allocator;
|
|
const posix = std.posix;
|
|
const build_config = @import("build_config.zig");
|
|
const options = @import("build_options");
|
|
const glslang = @import("glslang");
|
|
const macos = @import("macos");
|
|
const oni = @import("oniguruma");
|
|
const cli = @import("cli.zig");
|
|
const internal_os = @import("os/main.zig");
|
|
const fontconfig = @import("fontconfig");
|
|
const harfbuzz = @import("harfbuzz");
|
|
const renderer = @import("renderer.zig");
|
|
const apprt = @import("apprt.zig");
|
|
|
|
const App = @import("App.zig");
|
|
const Ghostty = @import("main_c.zig").Ghostty;
|
|
const state = &@import("global.zig").state;
|
|
|
|
/// The return type for main() depends on the build artifact. The lib build
|
|
/// also calls "main" in order to run the CLI actions, but it calls it as
|
|
/// an API and not an entrypoint.
|
|
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;
|
|
// no other Zig code should EVER access the global state.
|
|
state.init() catch |err| {
|
|
const stderr = std.io.getStdErr().writer();
|
|
defer posix.exit(1);
|
|
const ErrSet = @TypeOf(err) || error{Unknown};
|
|
switch (@as(ErrSet, @errorCast(err))) {
|
|
error.MultipleActions => try stderr.print(
|
|
"Error: multiple CLI actions specified. You must specify only one\n" ++
|
|
"action starting with the `+` character.\n",
|
|
.{},
|
|
),
|
|
|
|
error.InvalidAction => try stderr.print(
|
|
"Error: unknown CLI action specified. CLI actions are specified with\n" ++
|
|
"the '+' character.\n\n" ++
|
|
"All valid CLI actions can be listed with `ghostty +help`\n",
|
|
.{},
|
|
),
|
|
|
|
else => try stderr.print("invalid CLI invocation err={}\n", .{err}),
|
|
}
|
|
};
|
|
defer state.deinit();
|
|
const alloc = state.alloc;
|
|
|
|
if (comptime builtin.mode == .Debug) {
|
|
std.log.warn("This is a debug build. Performance will be very poor.", .{});
|
|
std.log.warn("You should only use a debug build for developing Ghostty.", .{});
|
|
std.log.warn("Otherwise, please rebuild in a release mode.", .{});
|
|
}
|
|
|
|
// Execute our action if we have one
|
|
if (state.action) |action| {
|
|
std.log.info("executing CLI action={}", .{action});
|
|
posix.exit(action.run(alloc) catch |err| err: {
|
|
std.log.err("CLI action failed error={}", .{err});
|
|
break :err 1;
|
|
});
|
|
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.
|
|
\\
|
|
\\On macOS, the terminal can also be launched using `open -na Ghostty.app`,
|
|
\\or `open -na Ghostty.app --args --foo=bar --baz=qux` to pass arguments.
|
|
\\
|
|
\\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.
|
|
\\
|
|
,
|
|
.{},
|
|
);
|
|
|
|
posix.exit(0);
|
|
}
|
|
|
|
// Create our app state
|
|
const app: *App = try App.create(alloc);
|
|
defer app.destroy();
|
|
|
|
// Create our runtime app
|
|
var app_runtime: apprt.App = undefined;
|
|
try app_runtime.init(app, .{});
|
|
defer app_runtime.terminate();
|
|
|
|
// Since - by definition - there are no surfaces when first started, the
|
|
// quit timer may need to be started. The start timer will get cancelled if/
|
|
// when the first surface is created.
|
|
if (@hasDecl(apprt.App, "startQuitTimer")) app_runtime.startQuitTimer();
|
|
|
|
// Run the GUI event loop
|
|
try app_runtime.run();
|
|
}
|
|
|
|
// The function std.log will call.
|
|
fn logFn(
|
|
comptime level: std.log.Level,
|
|
comptime scope: @TypeOf(.EnumLiteral),
|
|
comptime format: []const u8,
|
|
args: anytype,
|
|
) void {
|
|
// Stuff we can do before the lock
|
|
const level_txt = comptime level.asText();
|
|
const prefix = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
|
|
|
|
// Lock so we are thread-safe
|
|
std.debug.lockStdErr();
|
|
defer std.debug.unlockStdErr();
|
|
|
|
// On Mac, we use unified logging. To view this:
|
|
//
|
|
// sudo log stream --level debug --predicate 'subsystem=="com.mitchellh.ghostty"'
|
|
//
|
|
if (builtin.target.os.tag.isDarwin()) {
|
|
// Convert our levels to Mac levels
|
|
const mac_level: macos.os.LogType = switch (level) {
|
|
.debug => .debug,
|
|
.info => .info,
|
|
.warn => .err,
|
|
.err => .fault,
|
|
};
|
|
|
|
// Initialize a logger. This is slow to do on every operation
|
|
// but we shouldn't be logging too much.
|
|
const logger = macos.os.Log.create(build_config.bundle_id, @tagName(scope));
|
|
defer logger.release();
|
|
logger.log(std.heap.c_allocator, mac_level, format, args);
|
|
}
|
|
|
|
switch (state.logging) {
|
|
.disabled => {},
|
|
|
|
.stderr => {
|
|
// Always try default to send to stderr
|
|
const stderr = std.io.getStdErr().writer();
|
|
nosuspend stderr.print(level_txt ++ prefix ++ format ++ "\n", args) catch return;
|
|
},
|
|
}
|
|
}
|
|
|
|
pub const std_options: std.Options = .{
|
|
// Our log level is always at least info in every build mode.
|
|
.log_level = switch (builtin.mode) {
|
|
.Debug => .debug,
|
|
else => .info,
|
|
},
|
|
|
|
.logFn = logFn,
|
|
};
|
|
|
|
test {
|
|
_ = @import("pty.zig");
|
|
_ = @import("Command.zig");
|
|
_ = @import("font/main.zig");
|
|
_ = @import("apprt.zig");
|
|
_ = @import("renderer.zig");
|
|
_ = @import("termio.zig");
|
|
_ = @import("input.zig");
|
|
_ = @import("cli.zig");
|
|
_ = @import("surface_mouse.zig");
|
|
|
|
// Libraries
|
|
_ = @import("crash/main.zig");
|
|
_ = @import("datastruct/main.zig");
|
|
_ = @import("inspector/main.zig");
|
|
_ = @import("terminal/main.zig");
|
|
_ = @import("terminfo/main.zig");
|
|
_ = @import("simd/main.zig");
|
|
_ = @import("synthetic/main.zig");
|
|
_ = @import("unicode/main.zig");
|
|
}
|