Merge remote-tracking branch 'upstream/main'

This commit is contained in:
Raiden1411
2023-11-03 09:38:45 +00:00
16 changed files with 127 additions and 23 deletions

View File

@ -132,7 +132,7 @@ jobs:
run: nix develop -c zig build -Dapp-runtime=none test run: nix develop -c zig build -Dapp-runtime=none test
- name: Test GTK Build - name: Test GTK Build
run: nix develop -c zig build -Dapp-runtime=gtk run: nix develop -c zig build -Dapp-runtime=gtk -Dgtk-libadwaita=true
- name: Test GLFW Build - name: Test GLFW Build
run: nix develop -c zig build -Dapp-runtime=glfw run: nix develop -c zig build -Dapp-runtime=glfw

6
.gitignore vendored
View File

@ -1,5 +1,9 @@
*~
.*.swp
.swp
*.log
.DS_Store .DS_Store
.vscode .vscode/
.direnv/ .direnv/
.flatpak-builder/ .flatpak-builder/
zig-cache/ zig-cache/

View File

@ -39,6 +39,7 @@ var flatpak: bool = false;
var app_runtime: apprt.Runtime = .none; var app_runtime: apprt.Runtime = .none;
var renderer_impl: renderer.Impl = .opengl; var renderer_impl: renderer.Impl = .opengl;
var font_backend: font.Backend = .freetype; var font_backend: font.Backend = .freetype;
var libadwaita: bool = false;
pub fn build(b: *std.Build) !void { pub fn build(b: *std.Build) !void {
const optimize = b.standardOptimizeOption(.{}); const optimize = b.standardOptimizeOption(.{});
@ -87,6 +88,12 @@ pub fn build(b: *std.Build) !void {
"The app runtime to use. Not all values supported on all platforms.", "The app runtime to use. Not all values supported on all platforms.",
) orelse apprt.Runtime.default(target); ) orelse apprt.Runtime.default(target);
libadwaita = b.option(
bool,
"gtk-libadwaita",
"Enables the use of libadwaita when using the gtk rendering backend.",
) orelse true;
renderer_impl = b.option( renderer_impl = b.option(
renderer.Impl, renderer.Impl,
"renderer", "renderer",
@ -203,6 +210,7 @@ pub fn build(b: *std.Build) !void {
exe_options.addOption(apprt.Runtime, "app_runtime", app_runtime); exe_options.addOption(apprt.Runtime, "app_runtime", app_runtime);
exe_options.addOption(font.Backend, "font_backend", font_backend); exe_options.addOption(font.Backend, "font_backend", font_backend);
exe_options.addOption(renderer.Impl, "renderer", renderer_impl); exe_options.addOption(renderer.Impl, "renderer", renderer_impl);
exe_options.addOption(bool, "libadwaita", libadwaita);
// Exe // Exe
if (exe_) |exe| { if (exe_) |exe| {
@ -669,6 +677,10 @@ fn addDeps(
.@"enable-freetype" = true, .@"enable-freetype" = true,
.@"enable-coretext" = font_backend.hasCoretext(), .@"enable-coretext" = font_backend.hasCoretext(),
}); });
const ziglyph_dep = b.dependency("ziglyph", .{
.target = step.target,
.optimize = step.optimize,
});
// Wasm we do manually since it is such a different build. // Wasm we do manually since it is such a different build.
if (step.target.getCpuArch() == .wasm32) { if (step.target.getCpuArch() == .wasm32) {
@ -716,6 +728,7 @@ fn addDeps(
step.addModule("xev", libxev_dep.module("xev")); step.addModule("xev", libxev_dep.module("xev"));
step.addModule("pixman", pixman_dep.module("pixman")); step.addModule("pixman", pixman_dep.module("pixman"));
step.addModule("utf8proc", utf8proc_dep.module("utf8proc")); step.addModule("utf8proc", utf8proc_dep.module("utf8proc"));
step.addModule("ziglyph", ziglyph_dep.module("ziglyph"));
// Mac Stuff // Mac Stuff
if (step.target.isDarwin()) { if (step.target.isDarwin()) {
@ -814,6 +827,7 @@ fn addDeps(
.gtk => { .gtk => {
step.linkSystemLibrary2("gtk4", dynamic_link_opts); step.linkSystemLibrary2("gtk4", dynamic_link_opts);
if (libadwaita) step.linkSystemLibrary2("adwaita-1", dynamic_link_opts);
}, },
} }
} }

View File

@ -4,6 +4,10 @@
.paths = .{""}, .paths = .{""},
.dependencies = .{ .dependencies = .{
// Zig libs // Zig libs
.glfw = .{
.url = "https://pkg.machengine.org/glfw/14181bd28aa65915262ac3b4549bbd2dc70bbaa5.tar.gz",
.hash = "1220c6bb317ae3948b95161b9706777dde0509e72e8b35b62b92898aef801897d904",
},
.libxev = .{ .libxev = .{
.url = "https://github.com/mitchellh/libxev/archive/5ecbc871f3bfa80fb7bf0fa853866cb93b99bc18.tar.gz", .url = "https://github.com/mitchellh/libxev/archive/5ecbc871f3bfa80fb7bf0fa853866cb93b99bc18.tar.gz",
.hash = "1220416854e424601ecc9814afb461a5dc9cf95db5917d82f794594a58ffc723b82c", .hash = "1220416854e424601ecc9814afb461a5dc9cf95db5917d82f794594a58ffc723b82c",
@ -20,10 +24,9 @@
.url = "https://github.com/mitchellh/zig-js/archive/60ac42ab137461cdba2b38cc6c5e16376470aae6.tar.gz", .url = "https://github.com/mitchellh/zig-js/archive/60ac42ab137461cdba2b38cc6c5e16376470aae6.tar.gz",
.hash = "1220319b42fbc0116f3f198343256018e9f1da9483cef259201afe4ebab0ce0d8f6a", .hash = "1220319b42fbc0116f3f198343256018e9f1da9483cef259201afe4ebab0ce0d8f6a",
}, },
.ziglyph = .{
.glfw = .{ .url = "https://codeberg.org/dude_the_builder/ziglyph/archive/v0.11.1.tar.gz",
.url = "https://pkg.machengine.org/glfw/14181bd28aa65915262ac3b4549bbd2dc70bbaa5.tar.gz", .hash = "1220dee955839b7f267c1bb21e0ee60888c08f408c30f0722b243cabcc8cce8b7508",
.hash = "1220c6bb317ae3948b95161b9706777dde0509e72e8b35b62b92898aef801897d904",
}, },
// C libs // C libs

View File

@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
8503D7C72A549C66006CFF3D /* FullScreenHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8503D7C62A549C66006CFF3D /* FullScreenHandler.swift */; }; 8503D7C72A549C66006CFF3D /* FullScreenHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8503D7C62A549C66006CFF3D /* FullScreenHandler.swift */; };
857F63812A5E64F200CA4815 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 857F63802A5E64F200CA4815 /* MainMenu.xib */; }; 857F63812A5E64F200CA4815 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 857F63802A5E64F200CA4815 /* MainMenu.xib */; };
A51B78472AF4B58B00F3EDB9 /* TerminalWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51B78462AF4B58B00F3EDB9 /* TerminalWindow.swift */; };
A5278A9B2AA05B2600CD3039 /* Ghostty.Input.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5278A9A2AA05B2600CD3039 /* Ghostty.Input.swift */; }; A5278A9B2AA05B2600CD3039 /* Ghostty.Input.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5278A9A2AA05B2600CD3039 /* Ghostty.Input.swift */; };
A53426352A7DA53D00EBB7A2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53426342A7DA53D00EBB7A2 /* AppDelegate.swift */; }; A53426352A7DA53D00EBB7A2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53426342A7DA53D00EBB7A2 /* AppDelegate.swift */; };
A535B9DA299C569B0017E2E4 /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A535B9D9299C569B0017E2E4 /* ErrorView.swift */; }; A535B9DA299C569B0017E2E4 /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A535B9D9299C569B0017E2E4 /* ErrorView.swift */; };
@ -45,6 +46,7 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
8503D7C62A549C66006CFF3D /* FullScreenHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullScreenHandler.swift; sourceTree = "<group>"; }; 8503D7C62A549C66006CFF3D /* FullScreenHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullScreenHandler.swift; sourceTree = "<group>"; };
857F63802A5E64F200CA4815 /* MainMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = "<group>"; }; 857F63802A5E64F200CA4815 /* MainMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = "<group>"; };
A51B78462AF4B58B00F3EDB9 /* TerminalWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalWindow.swift; sourceTree = "<group>"; };
A5278A9A2AA05B2600CD3039 /* Ghostty.Input.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.Input.swift; sourceTree = "<group>"; }; A5278A9A2AA05B2600CD3039 /* Ghostty.Input.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.Input.swift; sourceTree = "<group>"; };
A53426342A7DA53D00EBB7A2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; A53426342A7DA53D00EBB7A2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
A535B9D9299C569B0017E2E4 /* ErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = "<group>"; }; A535B9D9299C569B0017E2E4 /* ErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = "<group>"; };
@ -171,6 +173,7 @@
A596309F2AEF6AEB00D64628 /* TerminalManager.swift */, A596309F2AEF6AEB00D64628 /* TerminalManager.swift */,
A596309B2AEE1C9E00D64628 /* TerminalController.swift */, A596309B2AEE1C9E00D64628 /* TerminalController.swift */,
A596309D2AEE1D6C00D64628 /* TerminalView.swift */, A596309D2AEE1D6C00D64628 /* TerminalView.swift */,
A51B78462AF4B58B00F3EDB9 /* TerminalWindow.swift */,
A535B9D9299C569B0017E2E4 /* ErrorView.swift */, A535B9D9299C569B0017E2E4 /* ErrorView.swift */,
); );
path = Terminal; path = Terminal;
@ -313,6 +316,7 @@
A59630A22AF0415000D64628 /* Ghostty.TerminalSplit.swift in Sources */, A59630A22AF0415000D64628 /* Ghostty.TerminalSplit.swift in Sources */,
A5FEB3002ABB69450068369E /* main.swift in Sources */, A5FEB3002ABB69450068369E /* main.swift in Sources */,
A55B7BB829B6F53A0055DE60 /* Package.swift in Sources */, A55B7BB829B6F53A0055DE60 /* Package.swift in Sources */,
A51B78472AF4B58B00F3EDB9 /* TerminalWindow.swift in Sources */,
A55B7BB629B6F47F0055DE60 /* AppState.swift in Sources */, A55B7BB629B6F47F0055DE60 /* AppState.swift in Sources */,
A5CEAFDC29B8009000646FDA /* SplitView.swift in Sources */, A5CEAFDC29B8009000646FDA /* SplitView.swift in Sources */,
A5CDF1932AAF9E0800513312 /* ConfigurationErrorsController.swift in Sources */, A5CDF1932AAF9E0800513312 /* ConfigurationErrorsController.swift in Sources */,

View File

@ -13,7 +13,7 @@
</customObject> </customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/> <customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="👻 Ghostty" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g"> <window title="👻 Ghostty" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="TerminalWindow" customModule="Ghostty" customModuleProvider="target">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/> <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="0.0" y="0.0" width="800" height="600"/> <rect key="contentRect" x="0.0" y="0.0" width="800" height="600"/>

View File

@ -28,13 +28,6 @@ class TerminalController: NSWindowController, NSWindowDelegate, TerminalViewDele
/// True when an alert is active so we don't overlap multiple. /// True when an alert is active so we don't overlap multiple.
private var alert: NSAlert? = nil private var alert: NSAlert? = nil
/// The style mask to use for the new window
private var styleMask: NSWindow.StyleMask {
var mask: NSWindow.StyleMask = [.resizable, .closable, .miniaturizable]
if (ghostty.windowDecorations) { mask.insert(.titled) }
return mask
}
init(_ ghostty: Ghostty.AppState, withBaseConfig base: Ghostty.SurfaceConfiguration? = nil) { init(_ ghostty: Ghostty.AppState, withBaseConfig base: Ghostty.SurfaceConfiguration? = nil) {
self.ghostty = ghostty self.ghostty = ghostty
super.init(window: nil) super.init(window: nil)
@ -76,7 +69,9 @@ class TerminalController: NSWindowController, NSWindowDelegate, TerminalViewDele
override func windowDidLoad() { override func windowDidLoad() {
guard let window = window else { return } guard let window = window else { return }
window.styleMask = self.styleMask
// If window decorations are disabled, remove our title
if (!ghostty.windowDecorations) { window.styleMask.remove(.titled) }
// Terminals typically operate in sRGB color space and macOS defaults // Terminals typically operate in sRGB color space and macOS defaults
// to "native" which is typically P3. There is a lot more resources // to "native" which is typically P3. There is a lot more resources

View File

@ -0,0 +1,8 @@
import Cocoa
class TerminalWindow: NSWindow {
// Both of these must be true for windows without decorations to be able to
// still become key/main and receive events.
override var canBecomeKey: Bool { return true }
override var canBecomeMain: Bool { return true }
}

View File

@ -28,6 +28,7 @@
, freetype , freetype
, glib , glib
, gtk4 , gtk4
, libadwaita
, harfbuzz , harfbuzz
, libpng , libpng
, libGL , libGL
@ -59,6 +60,7 @@ let
libXi libXi
libXrandr libXrandr
libadwaita
gtk4 gtk4
glib glib
]; ];
@ -120,6 +122,7 @@ in mkShell rec {
libXrandr libXrandr
# Only needed for GTK builds # Only needed for GTK builds
libadwaita
gtk4 gtk4
glib glib
]; ];

View File

@ -2169,19 +2169,19 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
.reload_config => try self.app.reloadConfig(self.rt_app), .reload_config => try self.app.reloadConfig(self.rt_app),
.csi => |data| { .csi, .esc => |data| {
// We need to send the CSI sequence as a single write request. // We need to send the CSI/ESC sequence as a single write request.
// If you split it across two then the shell can interpret it // If you split it across two then the shell can interpret it
// as two literals. // as two literals.
var buf: [128]u8 = undefined; var buf: [128]u8 = undefined;
const full_data = try std.fmt.bufPrint(&buf, "\x1b[{s}", .{data}); const full_data = try std.fmt.bufPrint(&buf, "\x1b{s}{s}", .{if(action==.csi)"["else"", data});
_ = self.io_thread.mailbox.push(try termio.Message.writeReq( _ = self.io_thread.mailbox.push(try termio.Message.writeReq(
self.alloc, self.alloc,
full_data, full_data,
), .{ .forever = {} }); ), .{ .forever = {} });
try self.io_thread.wakeup.notify(); try self.io_thread.wakeup.notify();
// CSI triggers a scroll. // CSI/ESC triggers a scroll.
{ {
self.renderer_state.mutex.lock(); self.renderer_state.mutex.lock();
defer self.renderer_state.mutex.unlock(); defer self.renderer_state.mutex.unlock();

View File

@ -353,6 +353,7 @@ pub const Surface = struct {
win.setScrollCallback(scrollCallback); win.setScrollCallback(scrollCallback);
win.setCursorPosCallback(cursorPosCallback); win.setCursorPosCallback(cursorPosCallback);
win.setMouseButtonCallback(mouseButtonCallback); win.setMouseButtonCallback(mouseButtonCallback);
win.setDropCallback(dropCallback);
// Build our result // Build our result
self.* = .{ self.* = .{
@ -964,4 +965,39 @@ pub const Surface = struct {
return; return;
}; };
} }
fn dropCallback(window: glfw.Window, paths: [][*:0]const u8) void {
const tracy = trace(@src());
defer tracy.end();
const surface = window.getUserPointer(CoreSurface) orelse return;
var list = std.ArrayList(u8).init(surface.alloc);
defer list.deinit();
for (paths) |path| {
const path_slice = std.mem.span(path);
// preallocate worst case of escaping every char + space
list.ensureTotalCapacity(path_slice.len * 2 + 1) catch |err| {
log.err("error in drop callback err={}", .{err});
return;
};
const writer = list.writer();
for (path_slice) |c| {
if (std.mem.indexOfScalar(u8, "\\ ()[]{}<>\"'`!#$&;|*?\t", c)) |_| {
writer.print("\\{c}", .{c}) catch unreachable; // memory preallocated
} else writer.writeByte(c) catch unreachable; // same here
}
writer.writeByte(' ') catch unreachable; // separate paths
surface.textCallback(list.items) catch |err| {
log.err("error in drop callback err={}", .{err});
return;
};
list.clearRetainingCapacity(); // avoid unnecessary reallocations
}
}
}; };

View File

@ -19,6 +19,7 @@ const internal_os = @import("../../os/main.zig");
const Config = configpkg.Config; const Config = configpkg.Config;
const CoreApp = @import("../../App.zig"); const CoreApp = @import("../../App.zig");
const CoreSurface = @import("../../Surface.zig"); const CoreSurface = @import("../../Surface.zig");
const build_options = @import("build_options");
const Surface = @import("Surface.zig"); const Surface = @import("Surface.zig");
const Window = @import("Window.zig"); const Window = @import("Window.zig");
@ -52,6 +53,9 @@ running: bool = true,
pub fn init(core_app: *CoreApp, opts: Options) !App { pub fn init(core_app: *CoreApp, opts: Options) !App {
_ = opts; _ = opts;
// Initialize libadwaita
if (build_options.libadwaita) c.adw_init();
// Load our configuration // Load our configuration
var config = try Config.load(core_app.alloc); var config = try Config.load(core_app.alloc);
errdefer config.deinit(); errdefer config.deinit();
@ -63,6 +67,18 @@ pub fn init(core_app: *CoreApp, opts: Options) !App {
} }
} }
// Set the style based on our configuration file
if (build_options.libadwaita) {
c.adw_style_manager_set_color_scheme(
c.adw_style_manager_get_default(),
switch (config.@"window-theme") {
.system => c.ADW_COLOR_SCHEME_PREFER_LIGHT,
.dark => c.ADW_COLOR_SCHEME_FORCE_DARK,
.light => c.ADW_COLOR_SCHEME_FORCE_LIGHT,
},
);
}
// The "none" cursor is used for hiding the cursor // The "none" cursor is used for hiding the cursor
const cursor_none = c.gdk_cursor_new_from_name("none", null); const cursor_none = c.gdk_cursor_new_from_name("none", null);
errdefer if (cursor_none) |cursor| c.g_object_unref(cursor); errdefer if (cursor_none) |cursor| c.g_object_unref(cursor);

View File

@ -1,5 +1,6 @@
const c = @cImport({ const c = @cImport({
@cInclude("gtk/gtk.h"); @cInclude("gtk/gtk.h");
@cInclude("libadwaita-1/adwaita.h");
}); });
pub usingnamespace c; pub usingnamespace c;

View File

@ -321,6 +321,8 @@ command: ?[]const u8 = null,
/// is removed, and the key will be sent through to the child command /// is removed, and the key will be sent through to the child command
/// if it is printable. /// if it is printable.
/// - "csi:text" - Send a CSI sequence. i.e. "csi:A" sends "cursor up". /// - "csi:text" - Send a CSI sequence. i.e. "csi:A" sends "cursor up".
/// - "esc:text" - Send an Escape sequence. i.e. "esc:d" deletes to the
/// end of the word to the right.
/// ///
/// Some notes for the action: /// Some notes for the action:
/// ///
@ -378,7 +380,7 @@ keybind: Keybinds = .{},
/// also be set to "light" or "dark" to force a specific theme regardless /// also be set to "light" or "dark" to force a specific theme regardless
/// of the system settings. /// of the system settings.
/// ///
/// This is currently only supported on macOS. /// This is currently only supported on macOS and linux.
@"window-theme": WindowTheme = .system, @"window-theme": WindowTheme = .system,
/// The initial window size. This size is in terminal grid cells by default. /// The initial window size. This size is in terminal grid cells by default.

View File

@ -1,6 +1,7 @@
const std = @import("std"); const std = @import("std");
const assert = std.debug.assert; const assert = std.debug.assert;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const ziglyph = @import("ziglyph");
const font = @import("../main.zig"); const font = @import("../main.zig");
const shape = @import("../shape.zig"); const shape = @import("../shape.zig");
const terminal = @import("../../terminal/main.zig"); const terminal = @import("../../terminal/main.zig");
@ -109,12 +110,20 @@ pub const RunIterator = struct {
// presentation format must be directly adjacent to the codepoint. // presentation format must be directly adjacent to the codepoint.
var it = self.row.codepointIterator(j); var it = self.row.codepointIterator(j);
if (it.next()) |cp| { if (it.next()) |cp| {
if (cp == 0xFE0E) break :p font.Presentation.text; if (cp == 0xFE0E) break :p .text;
if (cp == 0xFE0F) break :p font.Presentation.emoji; if (cp == 0xFE0F) break :p .emoji;
} }
break :p null; break :p null;
} else null; } else emoji: {
// If we're not a grapheme, our individual char could be
// an emoji so we want to check if we expect emoji presentation.
if (ziglyph.emoji.isEmojiPresentation(@intCast(cell.char))) {
break :emoji .emoji;
}
break :emoji .text;
};
// If our cursor is on this line then we break the run around the // If our cursor is on this line then we break the run around the
// cursor. This means that any row with a cursor has at least // cursor. This means that any row with a cursor has at least

View File

@ -117,6 +117,9 @@ pub const Action = union(enum) {
/// without the CSI header ("ESC ]" or "\x1b]"). /// without the CSI header ("ESC ]" or "\x1b]").
csi: []const u8, csi: []const u8,
/// Send an ESC sequence.
esc: []const u8,
/// Send data to the pty depending on whether cursor key mode is /// Send data to the pty depending on whether cursor key mode is
/// enabled ("application") or disabled ("normal"). /// enabled ("application") or disabled ("normal").
cursor_key: CursorKey, cursor_key: CursorKey,
@ -665,6 +668,12 @@ test "parse: action with string" {
try testing.expect(binding.action == .csi); try testing.expect(binding.action == .csi);
try testing.expectEqualStrings("A", binding.action.csi); try testing.expectEqualStrings("A", binding.action.csi);
} }
// parameter
{
const binding = try parse("a=esc:A");
try testing.expect(binding.action == .esc);
try testing.expectEqualStrings("A", binding.action.esc);
}
} }
test "parse: action with enum" { test "parse: action with enum" {