From 962be81f710b50df9ab005ec64546c9459bc0e49 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 5 Jan 2024 21:03:37 -0800 Subject: [PATCH 1/9] core: add Apple Color Emoji on macOS if its available --- src/Surface.zig | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/Surface.zig b/src/Surface.zig index 0ed3b47d3..dbc800654 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -410,6 +410,21 @@ pub fn init( _ = try group.addFace(.bold_italic, .{ .deferred = face }); } else log.warn("font-family-bold-italic not found: {s}", .{family}); } + + // On macOS, always search for and add the Apple Emoji font + // as our preferred emoji font for fallback. We do this in case + // people add other emoji fonts to their system, we always want to + // prefer the official one. Users can override this by explicitly + // specifying a font-family for emoji. + if (comptime builtin.os.tag == .macos) { + var disco_it = try disco.discover(alloc, .{ + .family = "Apple Color Emoji", + }); + defer disco_it.deinit(); + if (try disco_it.next()) |face| { + _ = try group.addFace(.regular, .{ .fallback_deferred = face }); + } + } } // Our built-in font will be used as a backup From efd196e5c92b1b6d8c03373e07018d0dc2125f56 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 5 Jan 2024 21:08:39 -0800 Subject: [PATCH 2/9] pkg/freetype: unknown errors should be reported, not unreachable --- pkg/freetype/errors.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/freetype/errors.zig b/pkg/freetype/errors.zig index e4f98db87..3fe6dccb8 100644 --- a/pkg/freetype/errors.zig +++ b/pkg/freetype/errors.zig @@ -94,6 +94,7 @@ pub const Error = error{ BbxTooBig, CorruptedFontHeader, CorruptedFontGlyphs, + UnknownFreetypeError, }; pub fn intToError(err: c_int) Error!void { @@ -188,7 +189,7 @@ pub fn intToError(err: c_int) Error!void { c.FT_Err_Bbx_Too_Big => Error.BbxTooBig, c.FT_Err_Corrupted_Font_Header => Error.CorruptedFontHeader, c.FT_Err_Corrupted_Font_Glyphs => Error.CorruptedFontGlyphs, - else => unreachable, + else => Error.UnknownFreetypeError, }; } From 0200f7955432ddcda8dc7d1c2acc583d28df54e8 Mon Sep 17 00:00:00 2001 From: "Jeffrey C. Ollie" Date: Fri, 5 Jan 2024 23:44:53 -0600 Subject: [PATCH 3/9] Include the git commit hash in the Nix package. --- flake.nix | 2 ++ nix/package.nix | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index b3bcd07c9..0536b5247 100644 --- a/flake.nix +++ b/flake.nix @@ -31,6 +31,7 @@ }; outputs = { + self, nixpkgs-unstable, nixpkgs-stable, nixpkgs-zig-0-12, @@ -54,6 +55,7 @@ packages.${system} = rec { ghostty = pkgs-stable.callPackage ./nix/package.nix { inherit (pkgs-zig-0-12) zig_0_12; + revision = self.shortRev or self.dirtyShortRev or "dirty"; }; default = ghostty; }; diff --git a/nix/package.nix b/nix/package.nix index ea471dd0e..6b86ea75b 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -1,4 +1,5 @@ { + self, lib, stdenv, bzip2, @@ -23,6 +24,7 @@ ncurses, pkg-config, zig_0_12, + revision ? "dirty", }: let # The Zig hook has no way to select the release type without actual # overriding of the default flags. @@ -121,7 +123,7 @@ in dontConfigure = true; - zigBuildFlags = "-Dversion-string=${finalAttrs.version}"; + zigBuildFlags = "-Dversion-string=${finalAttrs.version}-${revision}"; preBuild = '' rm -rf $ZIG_GLOBAL_CACHE_DIR From f09901f236bc6b423f2a5e96fc674465684b81da Mon Sep 17 00:00:00 2001 From: "Jeffrey C. Ollie" Date: Sat, 6 Jan 2024 00:08:30 -0600 Subject: [PATCH 4/9] Include '-nix' in the version string to distinguish Nix builds. --- nix/package.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/package.nix b/nix/package.nix index 6b86ea75b..0e4d1d4b7 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -123,7 +123,7 @@ in dontConfigure = true; - zigBuildFlags = "-Dversion-string=${finalAttrs.version}-${revision}"; + zigBuildFlags = "-Dversion-string=${finalAttrs.version}-${revision}-nix"; preBuild = '' rm -rf $ZIG_GLOBAL_CACHE_DIR From 8a816dc5ef328472b443f22160dd1c902b1c623d Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 6 Jan 2024 12:30:44 -0800 Subject: [PATCH 5/9] os: mac app launched with bundle env var is treated as desktop launch --- src/os/desktop.zig | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/os/desktop.zig b/src/os/desktop.zig index ed4f977d9..6475c278e 100644 --- a/src/os/desktop.zig +++ b/src/os/desktop.zig @@ -19,7 +19,15 @@ pub fn launchedFromDesktop() bool { return switch (builtin.os.tag) { // macOS apps launched from finder or `open` always have the init // process as their parent. - .macos => c.getppid() == 1, + .macos => macos: { + // This special case is so that if we launch the app via the + // app bundle (i.e. via open) then we still treat it as if it + // was launched from the desktop. + if (build_config.artifact == .lib and + std.os.getenv("GHOSTTY_MAC_APP") != null) break :macos true; + + break :macos c.getppid() == 1; + }, // On Linux, GTK sets GIO_LAUNCHED_DESKTOP_FILE and // GIO_LAUNCHED_DESKTOP_FILE_PID. We only check the latter to see if From d65fbba39e57f723fa6a93c393768b9c9dd2d60a Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 6 Jan 2024 12:31:01 -0800 Subject: [PATCH 6/9] config: do not load command from SHELL when launched from desktop Fixes #139 From the issue: Looking into this now, I think I figured out the broken logic. When launching from open, the parent process of Ghostty is launchd which appears to set your SHELL env var to your configured shell when logging in. That's why a restart fixes it. However, I believe directory services (the macOS equivalent to /etc/passwd) is updated in real time. Ghostty does read directory services but at a lower priority than SHELL. This logic makes sense for CLI-launched terminals but not desktop-launched. From a CLI you want the terminal you're launching to probably inherit the shell from the CLI you launched it from. (Note that using open explicitly forces a launchd-style launch so it quacks as if it was double-clicked on the desktop). In conclusion, I believe the correct logic is to invert the priority on SHELL vs directory services when Ghostty detects it was launched from launchd. We already have this detection logic in Ghostty because we use it for a number of other things as well, so this should be easy to fix. I'll work on it later today. --- src/config/Config.zig | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/config/Config.zig b/src/config/Config.zig index 025d09412..9881580b9 100644 --- a/src/config/Config.zig +++ b/src/config/Config.zig @@ -1674,16 +1674,22 @@ pub fn finalize(self: *Config) !void { // set to /bin/sh. if (self.command) |cmd| log.info("shell src=config value={s}", .{cmd}) - else { - if (!internal_os.isFlatpak()) { - if (std.process.getEnvVarOwned(alloc, "SHELL")) |value| { - log.info("default shell source=env value={s}", .{value}); - self.command = value; + else shell_env: { + // Flatpak always gets its shell from outside the sandbox + if (internal_os.isFlatpak()) break :shell_env; - // If we don't need the working directory, then we can exit now. - if (!wd_home) break :command; - } else |_| {} - } + // If we were launched from the desktop, our SHELL env var + // will represent our SHELL at login time. We want to use the + // latest shell from /etc/passwd or directory services. + if (internal_os.launchedFromDesktop()) break :shell_env; + + if (std.process.getEnvVarOwned(alloc, "SHELL")) |value| { + log.info("default shell source=env value={s}", .{value}); + self.command = value; + + // If we don't need the working directory, then we can exit now. + if (!wd_home) break :command; + } else |_| {} } switch (builtin.os.tag) { From 6626c315d7f92cda0c10d3c09e1187fabdd42404 Mon Sep 17 00:00:00 2001 From: "Jeffrey C. Ollie" Date: Sat, 6 Jan 2024 16:30:40 -0600 Subject: [PATCH 7/9] In some cases, 'self' would not be passed to the package. It's not necessary so remove it. --- nix/package.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/nix/package.nix b/nix/package.nix index 0e4d1d4b7..62d28b934 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -1,5 +1,4 @@ { - self, lib, stdenv, bzip2, From f447e6f9df87fd7942630261151935b8dedcad65 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 6 Jan 2024 18:57:42 -0800 Subject: [PATCH 8/9] font: insert blank cells for multi-cell ligatures for styling Up to this point, every font I've experienced with ligatures has replaced the codepoints that were replaced for combining with a space. For example, if a font has a ligature for "!=" to turn it into a glyph, it'd shape to `[not equal glyph, space]`, so it'd still take up two cells, allowing us to style both. Monaspace, however, does not do this. It turns "!=" into `[not equal glyph]` so styles like backgrounds, underlines, etc. were not extending. This commit detects multi-cell glyphs and inserts synthetic blank cells so that styling returns. I decided to do this via synthetic blank cells instead of introducing a `cell_width` to the shaper result because this simplifies the renderers to assume each shaper cell is one cell. We can change this later if we need to. Annoyingly, this does make the shaper slightly slower for EVERYONE to accomodate one known font that behaves this way. I haven't benchmarked it but my belief is that the performance impact will be negligible because to figure out cell width we're only accessing subsequent cells so they're likely to be in the CPU cache and also 99% of cells are going to be width 1. --- src/font/res/MonaspaceNeon-Regular.otf | Bin 0 -> 73232 bytes src/font/shape.zig | 5 +- src/font/shaper/coretext.zig | 4 + src/font/shaper/harfbuzz.zig | 104 ++++++++++++++++++++++--- src/font/test.zig | 4 + src/renderer/Metal.zig | 4 +- src/renderer/OpenGL.zig | 4 +- 7 files changed, 110 insertions(+), 15 deletions(-) create mode 100644 src/font/res/MonaspaceNeon-Regular.otf diff --git a/src/font/res/MonaspaceNeon-Regular.otf b/src/font/res/MonaspaceNeon-Regular.otf new file mode 100644 index 0000000000000000000000000000000000000000..75aeb627f06eb3359fd646e972a9578b295d6e24 GIT binary patch literal 73232 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 1) { + // To make the renderer implementations simpler, we convert + // the extra spaces for width to blank cells. + for (1..cell_width) |j| { + try self.cell_buf.append(self.alloc, .{ + .x = @intCast(info_v.cluster + j), + .glyph_index = null, + }); + } + } + // const i = self.cell_buf.items.len - 1; // log.warn("i={} info={} pos={} cell={}", .{ i, info_v, pos_v, self.cell_buf.items[i] }); } @@ -334,7 +371,9 @@ test "shape inconsolata ligs" { count += 1; const cells = try shaper.shape(run); - try testing.expectEqual(@as(usize, 1), cells.len); + try testing.expectEqual(@as(usize, 2), cells.len); + try testing.expect(cells[0].glyph_index != null); + try testing.expect(cells[1].glyph_index == null); } try testing.expectEqual(@as(usize, 1), count); } @@ -351,7 +390,38 @@ test "shape inconsolata ligs" { count += 1; const cells = try shaper.shape(run); - try testing.expectEqual(@as(usize, 1), cells.len); + try testing.expectEqual(@as(usize, 3), cells.len); + try testing.expect(cells[0].glyph_index != null); + try testing.expect(cells[1].glyph_index == null); + try testing.expect(cells[2].glyph_index == null); + } + try testing.expectEqual(@as(usize, 1), count); + } +} + +test "shape monaspace ligs" { + const testing = std.testing; + const alloc = testing.allocator; + + var testdata = try testShaperWithFont(alloc, .monaspace_neon); + defer testdata.deinit(); + + { + var screen = try terminal.Screen.init(alloc, 3, 5, 0); + defer screen.deinit(); + try screen.testWriteString("==="); + + var shaper = &testdata.shaper; + var it = shaper.runIterator(testdata.cache, screen.getRow(.{ .screen = 0 }), null, null); + var count: usize = 0; + while (try it.next(alloc)) |run| { + count += 1; + + const cells = try shaper.shape(run); + try testing.expectEqual(@as(usize, 3), cells.len); + try testing.expect(cells[0].glyph_index != null); + try testing.expect(cells[1].glyph_index == null); + try testing.expect(cells[2].glyph_index == null); } try testing.expectEqual(@as(usize, 1), count); } @@ -376,7 +446,7 @@ test "shape emoji width" { count += 1; const cells = try shaper.shape(run); - try testing.expectEqual(@as(usize, 1), cells.len); + try testing.expectEqual(@as(usize, 2), cells.len); } try testing.expectEqual(@as(usize, 1), count); } @@ -411,7 +481,9 @@ test "shape emoji width long" { try testing.expectEqual(@as(u32, 4), shaper.hb_buf.getLength()); const cells = try shaper.shape(run); - try testing.expectEqual(@as(usize, 1), cells.len); + + // screen.testWriteString isn't grapheme aware, otherwise this is two + try testing.expectEqual(@as(usize, 5), cells.len); } try testing.expectEqual(@as(usize, 1), count); } @@ -574,9 +646,9 @@ test "shape box glyphs" { try testing.expectEqual(@as(u32, 2), shaper.hb_buf.getLength()); const cells = try shaper.shape(run); try testing.expectEqual(@as(usize, 2), cells.len); - try testing.expectEqual(@as(u32, 0x2500), cells[0].glyph_index); + try testing.expectEqual(@as(u32, 0x2500), cells[0].glyph_index.?); try testing.expectEqual(@as(u16, 0), cells[0].x); - try testing.expectEqual(@as(u32, 0x2501), cells[1].glyph_index); + try testing.expectEqual(@as(u32, 0x2501), cells[1].glyph_index.?); try testing.expectEqual(@as(u16, 1), cells[1].x); } try testing.expectEqual(@as(usize, 1), count); @@ -902,11 +974,23 @@ const TestShaper = struct { } }; +const TestFont = enum { + inconsolata, + monaspace_neon, +}; + /// Helper to return a fully initialized shaper. fn testShaper(alloc: Allocator) !TestShaper { - const testFont = @import("../test.zig").fontRegular; + return try testShaperWithFont(alloc, .inconsolata); +} + +fn testShaperWithFont(alloc: Allocator, font_req: TestFont) !TestShaper { const testEmoji = @import("../test.zig").fontEmoji; const testEmojiText = @import("../test.zig").fontEmojiText; + const testFont = switch (font_req) { + .inconsolata => @import("../test.zig").fontRegular, + .monaspace_neon => @import("../test.zig").fontMonaspaceNeon, + }; var lib = try Library.init(); errdefer lib.deinit(); diff --git a/src/font/test.zig b/src/font/test.zig index 06bdc40d2..09909691e 100644 --- a/src/font/test.zig +++ b/src/font/test.zig @@ -15,3 +15,7 @@ pub const fontVariable = @embedFile("res/Lilex-VF.ttf"); /// Cozette is a unique font because it embeds some emoji characters /// but has a text presentation. pub const fontCozette = @embedFile("res/CozetteVector.ttf"); + +/// Monaspace has weird ligature behaviors we want to test in our shapers +/// so we embed it here. +pub const fontMonaspaceNeon = @embedFile("res/MonaspaceNeon-Regular.otf"); diff --git a/src/renderer/Metal.zig b/src/renderer/Metal.zig index 81518c6e6..9c17702e0 100644 --- a/src/renderer/Metal.zig +++ b/src/renderer/Metal.zig @@ -1796,12 +1796,12 @@ fn updateCell( }; // If the cell has a character, draw it - if (cell.char > 0) { + if (cell.char > 0) fg: { // Render const glyph = try self.font_group.renderGlyph( self.alloc, shaper_run.font_index, - shaper_cell.glyph_index, + shaper_cell.glyph_index orelse break :fg, .{ .grid_metrics = self.grid_metrics, .thicken = self.config.font_thicken, diff --git a/src/renderer/OpenGL.zig b/src/renderer/OpenGL.zig index aea6991df..66fd966ee 100644 --- a/src/renderer/OpenGL.zig +++ b/src/renderer/OpenGL.zig @@ -1504,12 +1504,12 @@ fn updateCell( }; // If the cell has a character, draw it - if (cell.char > 0) { + if (cell.char > 0) fg: { // Render const glyph = try self.font_group.renderGlyph( self.alloc, shaper_run.font_index, - shaper_cell.glyph_index, + shaper_cell.glyph_index orelse break :fg, .{ .grid_metrics = self.grid_metrics, .thicken = self.config.font_thicken, From 383b7c5870bdebefeaa0aedbc0ae0f53170b09cb Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 7 Jan 2024 07:54:42 -0800 Subject: [PATCH 9/9] core: clear_screen binding doesn't consume on alt screen The clear_screen binding does nothing on the alternate screen already, but we were still marking the action as "performed" which caused the binding to be consumed. This meant that alt screen applications like neovim, tmux, etc. couldn't see "cmd+k" (default binding for clear_screen on macOS) without the Ghostty user unbinding it completely. We already have other bindings that do not consume only when they do not perform, such as `previous_tab` and `next_tab`. This extends the framework we built for that to this action. --- src/Surface.zig | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Surface.zig b/src/Surface.zig index dbc800654..c78959288 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -2788,6 +2788,17 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool }, .clear_screen => { + // This is a duplicate of some of the logic in termio.clearScreen + // but we need to do this here so we can know the answer before + // we send the message. If the currently active screen is on the + // alternate screen then clear screen does nothing so we want to + // return false so the keybind can be unconsumed. + { + self.renderer_state.mutex.lock(); + defer self.renderer_state.mutex.unlock(); + if (self.io.terminal.active_screen == .alternate) return false; + } + _ = self.io_thread.mailbox.push(.{ .clear_screen = .{ .history = true }, }, .{ .forever = {} });