mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
Merge pull request #2108 from ghostty-org/yeet-usingns
Yeet Usingnamespace (Partial)
This commit is contained in:
@ -1042,6 +1042,9 @@ fn addDeps(
|
|||||||
step.linkLibC();
|
step.linkLibC();
|
||||||
step.addIncludePath(b.path("src/stb"));
|
step.addIncludePath(b.path("src/stb"));
|
||||||
step.addCSourceFiles(.{ .files = &.{"src/stb/stb.c"} });
|
step.addCSourceFiles(.{ .files = &.{"src/stb/stb.c"} });
|
||||||
|
if (step.rootModuleTarget().os.tag == .linux) {
|
||||||
|
step.addIncludePath(b.path("src/apprt/gtk"));
|
||||||
|
}
|
||||||
|
|
||||||
// C++ files
|
// C++ files
|
||||||
step.linkLibCpp();
|
step.linkLibCpp();
|
||||||
|
@ -20,9 +20,9 @@ const builtin = @import("builtin");
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||||
|
const global_state = &@import("global.zig").state;
|
||||||
const oni = @import("oniguruma");
|
const oni = @import("oniguruma");
|
||||||
const unicode = @import("unicode/main.zig");
|
const unicode = @import("unicode/main.zig");
|
||||||
const main = @import("main.zig");
|
|
||||||
const renderer = @import("renderer.zig");
|
const renderer = @import("renderer.zig");
|
||||||
const termio = @import("termio.zig");
|
const termio = @import("termio.zig");
|
||||||
const objc = @import("objc");
|
const objc = @import("objc");
|
||||||
@ -448,7 +448,7 @@ pub fn init(
|
|||||||
.shell_integration = config.@"shell-integration",
|
.shell_integration = config.@"shell-integration",
|
||||||
.shell_integration_features = config.@"shell-integration-features",
|
.shell_integration_features = config.@"shell-integration-features",
|
||||||
.working_directory = config.@"working-directory",
|
.working_directory = config.@"working-directory",
|
||||||
.resources_dir = main.state.resources_dir,
|
.resources_dir = global_state.resources_dir,
|
||||||
.term = config.term,
|
.term = config.term,
|
||||||
|
|
||||||
// Get the cgroup if we're on linux and have the decl. I'd love
|
// Get the cgroup if we're on linux and have the decl. I'd love
|
||||||
|
@ -12,7 +12,8 @@ const std = @import("std");
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const build_config = @import("build_config.zig");
|
const build_config = @import("build_config.zig");
|
||||||
|
|
||||||
pub usingnamespace @import("apprt/structs.zig");
|
const structs = @import("apprt/structs.zig");
|
||||||
|
|
||||||
pub const glfw = @import("apprt/glfw.zig");
|
pub const glfw = @import("apprt/glfw.zig");
|
||||||
pub const gtk = @import("apprt/gtk.zig");
|
pub const gtk = @import("apprt/gtk.zig");
|
||||||
pub const none = @import("apprt/none.zig");
|
pub const none = @import("apprt/none.zig");
|
||||||
@ -20,6 +21,18 @@ pub const browser = @import("apprt/browser.zig");
|
|||||||
pub const embedded = @import("apprt/embedded.zig");
|
pub const embedded = @import("apprt/embedded.zig");
|
||||||
pub const surface = @import("apprt/surface.zig");
|
pub const surface = @import("apprt/surface.zig");
|
||||||
|
|
||||||
|
pub const ContentScale = structs.ContentScale;
|
||||||
|
pub const Clipboard = structs.Clipboard;
|
||||||
|
pub const ClipboardRequest = structs.ClipboardRequest;
|
||||||
|
pub const ClipboardRequestType = structs.ClipboardRequestType;
|
||||||
|
pub const ColorScheme = structs.ColorScheme;
|
||||||
|
pub const CursorPos = structs.CursorPos;
|
||||||
|
pub const DesktopNotification = structs.DesktopNotification;
|
||||||
|
pub const IMEPos = structs.IMEPos;
|
||||||
|
pub const Selection = structs.Selection;
|
||||||
|
pub const SplitDirection = structs.SplitDirection;
|
||||||
|
pub const SurfaceSize = structs.SurfaceSize;
|
||||||
|
|
||||||
/// The implementation to use for the app runtime. This is comptime chosen
|
/// The implementation to use for the app runtime. This is comptime chosen
|
||||||
/// so that every build has exactly one application runtime implementation.
|
/// so that every build has exactly one application runtime implementation.
|
||||||
/// Note: it is very rare to use Runtime directly; most usage will use
|
/// Note: it is very rare to use Runtime directly; most usage will use
|
||||||
|
@ -1386,7 +1386,7 @@ pub const Inspector = struct {
|
|||||||
|
|
||||||
// C API
|
// C API
|
||||||
pub const CAPI = struct {
|
pub const CAPI = struct {
|
||||||
const global = &@import("../main.zig").state;
|
const global = &@import("../global.zig").state;
|
||||||
|
|
||||||
/// This is the same as Surface.KeyEvent but this is the raw C API version.
|
/// This is the same as Surface.KeyEvent but this is the raw C API version.
|
||||||
const KeyEvent = extern struct {
|
const KeyEvent = extern struct {
|
||||||
@ -1427,6 +1427,14 @@ pub const CAPI = struct {
|
|||||||
cell_height_px: u32,
|
cell_height_px: u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Reference the conditional exports based on target platform
|
||||||
|
// so they're included in the C API.
|
||||||
|
comptime {
|
||||||
|
if (builtin.target.isDarwin()) {
|
||||||
|
_ = Darwin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new app.
|
/// Create a new app.
|
||||||
export fn ghostty_app_new(
|
export fn ghostty_app_new(
|
||||||
opts: *const apprt.runtime.App.Options,
|
opts: *const apprt.runtime.App.Options,
|
||||||
@ -1830,8 +1838,112 @@ pub const CAPI = struct {
|
|||||||
ptr.freeInspector();
|
ptr.freeInspector();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inspector Metal APIs are only available on Apple systems
|
export fn ghostty_inspector_set_size(ptr: *Inspector, w: u32, h: u32) void {
|
||||||
usingnamespace if (builtin.target.isDarwin()) struct {
|
ptr.updateSize(w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn ghostty_inspector_set_content_scale(ptr: *Inspector, x: f64, y: f64) void {
|
||||||
|
ptr.updateContentScale(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn ghostty_inspector_mouse_button(
|
||||||
|
ptr: *Inspector,
|
||||||
|
action: input.MouseButtonState,
|
||||||
|
button: input.MouseButton,
|
||||||
|
mods: c_int,
|
||||||
|
) void {
|
||||||
|
ptr.mouseButtonCallback(
|
||||||
|
action,
|
||||||
|
button,
|
||||||
|
@bitCast(@as(
|
||||||
|
input.Mods.Backing,
|
||||||
|
@truncate(@as(c_uint, @bitCast(mods))),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn ghostty_inspector_mouse_pos(ptr: *Inspector, x: f64, y: f64) void {
|
||||||
|
ptr.cursorPosCallback(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn ghostty_inspector_mouse_scroll(
|
||||||
|
ptr: *Inspector,
|
||||||
|
x: f64,
|
||||||
|
y: f64,
|
||||||
|
scroll_mods: c_int,
|
||||||
|
) void {
|
||||||
|
ptr.scrollCallback(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
@bitCast(@as(u8, @truncate(@as(c_uint, @bitCast(scroll_mods))))),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn ghostty_inspector_key(
|
||||||
|
ptr: *Inspector,
|
||||||
|
action: input.Action,
|
||||||
|
key: input.Key,
|
||||||
|
c_mods: c_int,
|
||||||
|
) void {
|
||||||
|
ptr.keyCallback(
|
||||||
|
action,
|
||||||
|
key,
|
||||||
|
@bitCast(@as(
|
||||||
|
input.Mods.Backing,
|
||||||
|
@truncate(@as(c_uint, @bitCast(c_mods))),
|
||||||
|
)),
|
||||||
|
) catch |err| {
|
||||||
|
log.err("error processing key event err={}", .{err});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn ghostty_inspector_text(
|
||||||
|
ptr: *Inspector,
|
||||||
|
str: [*:0]const u8,
|
||||||
|
) void {
|
||||||
|
ptr.textCallback(std.mem.sliceTo(str, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn ghostty_inspector_set_focus(ptr: *Inspector, focused: bool) void {
|
||||||
|
ptr.focusCallback(focused);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the window background blur on macOS to the desired value.
|
||||||
|
/// I do this in Zig as an extern function because I don't know how to
|
||||||
|
/// call these functions in Swift.
|
||||||
|
///
|
||||||
|
/// This uses an undocumented, non-public API because this is what
|
||||||
|
/// every terminal appears to use, including Terminal.app.
|
||||||
|
export fn ghostty_set_window_background_blur(
|
||||||
|
app: *App,
|
||||||
|
window: *anyopaque,
|
||||||
|
) void {
|
||||||
|
// This is only supported on macOS
|
||||||
|
if (comptime builtin.target.os.tag != .macos) return;
|
||||||
|
|
||||||
|
const config = app.config;
|
||||||
|
|
||||||
|
// Do nothing if we don't have background transparency enabled
|
||||||
|
if (config.@"background-opacity" >= 1.0) return;
|
||||||
|
|
||||||
|
// Do nothing if our blur value is zero
|
||||||
|
if (config.@"background-blur-radius" == 0) return;
|
||||||
|
|
||||||
|
const nswindow = objc.Object.fromId(window);
|
||||||
|
_ = CGSSetWindowBackgroundBlurRadius(
|
||||||
|
CGSDefaultConnectionForThread(),
|
||||||
|
nswindow.msgSend(usize, objc.sel("windowNumber"), .{}),
|
||||||
|
@intCast(config.@"background-blur-radius"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See ghostty_set_window_background_blur
|
||||||
|
extern "c" fn CGSSetWindowBackgroundBlurRadius(*anyopaque, usize, c_int) i32;
|
||||||
|
extern "c" fn CGSDefaultConnectionForThread() *anyopaque;
|
||||||
|
|
||||||
|
// Darwin-only C APIs.
|
||||||
|
const Darwin = struct {
|
||||||
export fn ghostty_surface_set_display_id(ptr: *Surface, display_id: u32) void {
|
export fn ghostty_surface_set_display_id(ptr: *Surface, display_id: u32) void {
|
||||||
const surface = &ptr.core_surface;
|
const surface = &ptr.core_surface;
|
||||||
_ = surface.renderer_thread.mailbox.push(
|
_ = surface.renderer_thread.mailbox.push(
|
||||||
@ -1984,109 +2096,5 @@ pub const CAPI = struct {
|
|||||||
ptr.backend = null;
|
ptr.backend = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else struct {};
|
};
|
||||||
|
|
||||||
export fn ghostty_inspector_set_size(ptr: *Inspector, w: u32, h: u32) void {
|
|
||||||
ptr.updateSize(w, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn ghostty_inspector_set_content_scale(ptr: *Inspector, x: f64, y: f64) void {
|
|
||||||
ptr.updateContentScale(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn ghostty_inspector_mouse_button(
|
|
||||||
ptr: *Inspector,
|
|
||||||
action: input.MouseButtonState,
|
|
||||||
button: input.MouseButton,
|
|
||||||
mods: c_int,
|
|
||||||
) void {
|
|
||||||
ptr.mouseButtonCallback(
|
|
||||||
action,
|
|
||||||
button,
|
|
||||||
@bitCast(@as(
|
|
||||||
input.Mods.Backing,
|
|
||||||
@truncate(@as(c_uint, @bitCast(mods))),
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn ghostty_inspector_mouse_pos(ptr: *Inspector, x: f64, y: f64) void {
|
|
||||||
ptr.cursorPosCallback(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn ghostty_inspector_mouse_scroll(
|
|
||||||
ptr: *Inspector,
|
|
||||||
x: f64,
|
|
||||||
y: f64,
|
|
||||||
scroll_mods: c_int,
|
|
||||||
) void {
|
|
||||||
ptr.scrollCallback(
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
@bitCast(@as(u8, @truncate(@as(c_uint, @bitCast(scroll_mods))))),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn ghostty_inspector_key(
|
|
||||||
ptr: *Inspector,
|
|
||||||
action: input.Action,
|
|
||||||
key: input.Key,
|
|
||||||
c_mods: c_int,
|
|
||||||
) void {
|
|
||||||
ptr.keyCallback(
|
|
||||||
action,
|
|
||||||
key,
|
|
||||||
@bitCast(@as(
|
|
||||||
input.Mods.Backing,
|
|
||||||
@truncate(@as(c_uint, @bitCast(c_mods))),
|
|
||||||
)),
|
|
||||||
) catch |err| {
|
|
||||||
log.err("error processing key event err={}", .{err});
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn ghostty_inspector_text(
|
|
||||||
ptr: *Inspector,
|
|
||||||
str: [*:0]const u8,
|
|
||||||
) void {
|
|
||||||
ptr.textCallback(std.mem.sliceTo(str, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
export fn ghostty_inspector_set_focus(ptr: *Inspector, focused: bool) void {
|
|
||||||
ptr.focusCallback(focused);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the window background blur on macOS to the desired value.
|
|
||||||
/// I do this in Zig as an extern function because I don't know how to
|
|
||||||
/// call these functions in Swift.
|
|
||||||
///
|
|
||||||
/// This uses an undocumented, non-public API because this is what
|
|
||||||
/// every terminal appears to use, including Terminal.app.
|
|
||||||
export fn ghostty_set_window_background_blur(
|
|
||||||
app: *App,
|
|
||||||
window: *anyopaque,
|
|
||||||
) void {
|
|
||||||
// This is only supported on macOS
|
|
||||||
if (comptime builtin.target.os.tag != .macos) return;
|
|
||||||
|
|
||||||
const config = app.config;
|
|
||||||
|
|
||||||
// Do nothing if we don't have background transparency enabled
|
|
||||||
if (config.@"background-opacity" >= 1.0) return;
|
|
||||||
|
|
||||||
// Do nothing if our blur value is zero
|
|
||||||
if (config.@"background-blur-radius" == 0) return;
|
|
||||||
|
|
||||||
const nswindow = objc.Object.fromId(window);
|
|
||||||
_ = CGSSetWindowBackgroundBlurRadius(
|
|
||||||
CGSDefaultConnectionForThread(),
|
|
||||||
nswindow.msgSend(usize, objc.sel("windowNumber"), .{}),
|
|
||||||
@intCast(config.@"background-blur-radius"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// See ghostty_set_window_background_blur
|
|
||||||
extern "c" fn CGSSetWindowBackgroundBlurRadius(*anyopaque, usize, c_int) i32;
|
|
||||||
extern "c" fn CGSDefaultConnectionForThread() *anyopaque;
|
|
||||||
};
|
};
|
||||||
|
@ -28,7 +28,7 @@ const Surface = @import("Surface.zig");
|
|||||||
const Window = @import("Window.zig");
|
const Window = @import("Window.zig");
|
||||||
const ConfigErrorsWindow = @import("ConfigErrorsWindow.zig");
|
const ConfigErrorsWindow = @import("ConfigErrorsWindow.zig");
|
||||||
const ClipboardConfirmationWindow = @import("ClipboardConfirmationWindow.zig");
|
const ClipboardConfirmationWindow = @import("ClipboardConfirmationWindow.zig");
|
||||||
const c = @import("c.zig");
|
const c = @import("c.zig").c;
|
||||||
const inspector = @import("inspector.zig");
|
const inspector = @import("inspector.zig");
|
||||||
const key = @import("key.zig");
|
const key = @import("key.zig");
|
||||||
const x11 = @import("x11.zig");
|
const x11 = @import("x11.zig");
|
||||||
|
@ -8,7 +8,7 @@ const apprt = @import("../../apprt.zig");
|
|||||||
const CoreSurface = @import("../../Surface.zig");
|
const CoreSurface = @import("../../Surface.zig");
|
||||||
const App = @import("App.zig");
|
const App = @import("App.zig");
|
||||||
const View = @import("View.zig");
|
const View = @import("View.zig");
|
||||||
const c = @import("c.zig");
|
const c = @import("c.zig").c;
|
||||||
|
|
||||||
const log = std.log.scoped(.gtk);
|
const log = std.log.scoped(.gtk);
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ const Config = configpkg.Config;
|
|||||||
|
|
||||||
const App = @import("App.zig");
|
const App = @import("App.zig");
|
||||||
const View = @import("View.zig");
|
const View = @import("View.zig");
|
||||||
const c = @import("c.zig");
|
const c = @import("c.zig").c;
|
||||||
|
|
||||||
const log = std.log.scoped(.gtk);
|
const log = std.log.scoped(.gtk);
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ const std = @import("std");
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
|
|
||||||
const cimgui = @import("cimgui");
|
const cimgui = @import("cimgui");
|
||||||
const c = @import("c.zig");
|
const c = @import("c.zig").c;
|
||||||
const key = @import("key.zig");
|
const key = @import("key.zig");
|
||||||
const gl = @import("opengl");
|
const gl = @import("opengl");
|
||||||
const input = @import("../../input.zig");
|
const input = @import("../../input.zig");
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const ResizeOverlay = @This();
|
const ResizeOverlay = @This();
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const c = @import("c.zig");
|
const c = @import("c.zig").c;
|
||||||
const configpkg = @import("../../config.zig");
|
const configpkg = @import("../../config.zig");
|
||||||
const Surface = @import("Surface.zig");
|
const Surface = @import("Surface.zig");
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ const CoreSurface = @import("../../Surface.zig");
|
|||||||
|
|
||||||
const Surface = @import("Surface.zig");
|
const Surface = @import("Surface.zig");
|
||||||
const Tab = @import("Tab.zig");
|
const Tab = @import("Tab.zig");
|
||||||
const c = @import("c.zig");
|
const c = @import("c.zig").c;
|
||||||
|
|
||||||
const log = std.log.scoped(.gtk);
|
const log = std.log.scoped(.gtk);
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ const ClipboardConfirmationWindow = @import("ClipboardConfirmationWindow.zig");
|
|||||||
const ResizeOverlay = @import("ResizeOverlay.zig");
|
const ResizeOverlay = @import("ResizeOverlay.zig");
|
||||||
const inspector = @import("inspector.zig");
|
const inspector = @import("inspector.zig");
|
||||||
const gtk_key = @import("key.zig");
|
const gtk_key = @import("key.zig");
|
||||||
const c = @import("c.zig");
|
const c = @import("c.zig").c;
|
||||||
const x11 = @import("x11.zig");
|
const x11 = @import("x11.zig");
|
||||||
|
|
||||||
const log = std.log.scoped(.gtk_surface);
|
const log = std.log.scoped(.gtk_surface);
|
||||||
|
@ -12,7 +12,7 @@ const CoreSurface = @import("../../Surface.zig");
|
|||||||
|
|
||||||
const Surface = @import("Surface.zig");
|
const Surface = @import("Surface.zig");
|
||||||
const Window = @import("Window.zig");
|
const Window = @import("Window.zig");
|
||||||
const c = @import("c.zig");
|
const c = @import("c.zig").c;
|
||||||
|
|
||||||
const log = std.log.scoped(.gtk);
|
const log = std.log.scoped(.gtk);
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
const View = @This();
|
const View = @This();
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const c = @import("c.zig");
|
const c = @import("c.zig").c;
|
||||||
|
|
||||||
const log = std.log.scoped(.gtk);
|
const log = std.log.scoped(.gtk);
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ const App = @import("App.zig");
|
|||||||
const Color = configpkg.Config.Color;
|
const Color = configpkg.Config.Color;
|
||||||
const Surface = @import("Surface.zig");
|
const Surface = @import("Surface.zig");
|
||||||
const Tab = @import("Tab.zig");
|
const Tab = @import("Tab.zig");
|
||||||
const c = @import("c.zig");
|
const c = @import("c.zig").c;
|
||||||
|
|
||||||
const log = std.log.scoped(.gtk);
|
const log = std.log.scoped(.gtk);
|
||||||
|
|
||||||
|
@ -1,21 +1,19 @@
|
|||||||
const c = @cImport({
|
/// Imported C API directly from header files
|
||||||
|
pub const c = @cImport({
|
||||||
@cInclude("gtk/gtk.h");
|
@cInclude("gtk/gtk.h");
|
||||||
if (@import("build_options").libadwaita) @cInclude("libadwaita-1/adwaita.h");
|
if (@import("build_options").libadwaita) {
|
||||||
|
@cInclude("libadwaita-1/adwaita.h");
|
||||||
|
}
|
||||||
|
|
||||||
// Add in X11-specific GDK backend which we use for specific things (e.g.
|
// Add in X11-specific GDK backend which we use for specific things
|
||||||
// X11 window class).
|
// (e.g. X11 window class).
|
||||||
@cInclude("gdk/x11/gdkx.h");
|
@cInclude("gdk/x11/gdkx.h");
|
||||||
// Xkb for X11 state handling
|
// Xkb for X11 state handling
|
||||||
@cInclude("X11/XKBlib.h");
|
@cInclude("X11/XKBlib.h");
|
||||||
|
|
||||||
// generated header files
|
// generated header files
|
||||||
@cInclude("ghostty_resources.h");
|
@cInclude("ghostty_resources.h");
|
||||||
|
|
||||||
|
// compatibility
|
||||||
|
@cInclude("ghostty_gtk_compat.h");
|
||||||
});
|
});
|
||||||
|
|
||||||
pub usingnamespace c;
|
|
||||||
|
|
||||||
/// Compatibility with gobject < 2.74
|
|
||||||
pub usingnamespace if (@hasDecl(c, "G_CONNECT_DEFAULT")) struct {} else struct {
|
|
||||||
pub const G_CONNECT_DEFAULT = 0;
|
|
||||||
pub const G_APPLICATION_DEFAULT_FLAGS = c.G_APPLICATION_FLAGS_NONE;
|
|
||||||
};
|
|
||||||
|
@ -3,7 +3,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 c = @import("c.zig");
|
const c = @import("c.zig").c;
|
||||||
const App = @import("App.zig");
|
const App = @import("App.zig");
|
||||||
const internal_os = @import("../../os/main.zig");
|
const internal_os = @import("../../os/main.zig");
|
||||||
|
|
||||||
|
14
src/apprt/gtk/ghostty_gtk_compat.h
Normal file
14
src/apprt/gtk/ghostty_gtk_compat.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// This file is used to provide compatibility if necessary with
|
||||||
|
// older versions of GTK and GLib.
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
// Compatibility with gobject < 2.74
|
||||||
|
#ifndef G_CONNECT_DEFAULT
|
||||||
|
#define G_CONNECT_DEFAULT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Compatibility with gobject < 2.74
|
||||||
|
#ifndef G_APPLICATION_DEFAULT_FLAGS
|
||||||
|
#define G_APPLICATION_DEFAULT_FLAGS G_APPLICATION_FLAGS_NONE
|
||||||
|
#endif
|
@ -6,7 +6,7 @@ const App = @import("App.zig");
|
|||||||
const Surface = @import("Surface.zig");
|
const Surface = @import("Surface.zig");
|
||||||
const TerminalWindow = @import("Window.zig");
|
const TerminalWindow = @import("Window.zig");
|
||||||
const ImguiWidget = @import("ImguiWidget.zig");
|
const ImguiWidget = @import("ImguiWidget.zig");
|
||||||
const c = @import("c.zig");
|
const c = @import("c.zig").c;
|
||||||
const CoreInspector = @import("../../inspector/main.zig").Inspector;
|
const CoreInspector = @import("../../inspector/main.zig").Inspector;
|
||||||
|
|
||||||
const log = std.log.scoped(.inspector);
|
const log = std.log.scoped(.inspector);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const input = @import("../../input.zig");
|
const input = @import("../../input.zig");
|
||||||
const c = @import("c.zig");
|
const c = @import("c.zig").c;
|
||||||
|
|
||||||
/// Returns a GTK accelerator string from a trigger.
|
/// Returns a GTK accelerator string from a trigger.
|
||||||
pub fn accelFromTrigger(buf: []u8, trigger: input.Binding.Trigger) !?[:0]const u8 {
|
pub fn accelFromTrigger(buf: []u8, trigger: input.Binding.Trigger) !?[:0]const u8 {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/// Utility functions for X11 handling.
|
/// Utility functions for X11 handling.
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const c = @import("c.zig");
|
const c = @import("c.zig").c;
|
||||||
const input = @import("../../input.zig");
|
const input = @import("../../input.zig");
|
||||||
|
|
||||||
const log = std.log.scoped(.gtk_x11);
|
const log = std.log.scoped(.gtk_x11);
|
||||||
|
@ -5,7 +5,7 @@ const Action = @import("action.zig").Action;
|
|||||||
const Arena = std.heap.ArenaAllocator;
|
const Arena = std.heap.ArenaAllocator;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const Config = @import("../config/Config.zig");
|
const Config = @import("../config/Config.zig");
|
||||||
const global_state = &@import("../main.zig").state;
|
const global_state = &@import("../global.zig").state;
|
||||||
|
|
||||||
pub const Options = struct {
|
pub const Options = struct {
|
||||||
pub fn deinit(self: Options) void {
|
pub fn deinit(self: Options) void {
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
pub usingnamespace @import("config/key.zig");
|
const formatter = @import("config/formatter.zig");
|
||||||
pub usingnamespace @import("config/formatter.zig");
|
|
||||||
pub const Config = @import("config/Config.zig");
|
pub const Config = @import("config/Config.zig");
|
||||||
pub const string = @import("config/string.zig");
|
pub const string = @import("config/string.zig");
|
||||||
pub const edit = @import("config/edit.zig");
|
pub const edit = @import("config/edit.zig");
|
||||||
pub const url = @import("config/url.zig");
|
pub const url = @import("config/url.zig");
|
||||||
|
|
||||||
|
pub const FileFormatter = formatter.FileFormatter;
|
||||||
|
pub const entryFormatter = formatter.entryFormatter;
|
||||||
|
pub const formatEntry = formatter.formatEntry;
|
||||||
|
|
||||||
// Field types
|
// Field types
|
||||||
pub const ClipboardAccess = Config.ClipboardAccess;
|
pub const ClipboardAccess = Config.ClipboardAccess;
|
||||||
pub const CopyOnSelect = Config.CopyOnSelect;
|
pub const CopyOnSelect = Config.CopyOnSelect;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const cli = @import("../cli.zig");
|
const cli = @import("../cli.zig");
|
||||||
const inputpkg = @import("../input.zig");
|
const inputpkg = @import("../input.zig");
|
||||||
const global = &@import("../main.zig").state;
|
const global = &@import("../global.zig").state;
|
||||||
|
|
||||||
const Config = @import("Config.zig");
|
const Config = @import("Config.zig");
|
||||||
const c_get = @import("c_get.zig");
|
const c_get = @import("c_get.zig");
|
||||||
|
@ -15,7 +15,7 @@ const builtin = @import("builtin");
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||||
const global_state = &@import("../main.zig").state;
|
const global_state = &@import("../global.zig").state;
|
||||||
const fontpkg = @import("../font/main.zig");
|
const fontpkg = @import("../font/main.zig");
|
||||||
const inputpkg = @import("../input.zig");
|
const inputpkg = @import("../input.zig");
|
||||||
const terminal = @import("../terminal/main.zig");
|
const terminal = @import("../terminal/main.zig");
|
||||||
|
@ -300,9 +300,6 @@ pub fn clear(self: *Atlas) void {
|
|||||||
/// The wasm-compatible API. This lacks documentation unless the API differs
|
/// The wasm-compatible API. This lacks documentation unless the API differs
|
||||||
/// from the standard Zig API. To learn what a function does, just look one
|
/// from the standard Zig API. To learn what a function does, just look one
|
||||||
/// level deeper to what Zig function is called and read the documentation there.
|
/// level deeper to what Zig function is called and read the documentation there.
|
||||||
///
|
|
||||||
/// To export this from Zig, use `usingnamespace Wasm` in some top-level
|
|
||||||
/// space and it will be exported.
|
|
||||||
pub const Wasm = struct {
|
pub const Wasm = struct {
|
||||||
// If you're copying this file (Atlas.zig) out to a separate project,
|
// If you're copying this file (Atlas.zig) out to a separate project,
|
||||||
// just replace this with the allocator you want to use.
|
// just replace this with the allocator you want to use.
|
||||||
|
@ -2,6 +2,8 @@ const std = @import("std");
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const build_config = @import("../build_config.zig");
|
const build_config = @import("../build_config.zig");
|
||||||
|
|
||||||
|
const library = @import("library.zig");
|
||||||
|
|
||||||
pub const Atlas = @import("Atlas.zig");
|
pub const Atlas = @import("Atlas.zig");
|
||||||
pub const discovery = @import("discovery.zig");
|
pub const discovery = @import("discovery.zig");
|
||||||
pub const face = @import("face.zig");
|
pub const face = @import("face.zig");
|
||||||
@ -23,15 +25,17 @@ pub const Sprite = sprite.Sprite;
|
|||||||
pub const SpriteFace = sprite.Face;
|
pub const SpriteFace = sprite.Face;
|
||||||
pub const Descriptor = discovery.Descriptor;
|
pub const Descriptor = discovery.Descriptor;
|
||||||
pub const Discover = discovery.Discover;
|
pub const Discover = discovery.Discover;
|
||||||
pub usingnamespace @import("library.zig");
|
pub const Library = library.Library;
|
||||||
|
|
||||||
/// If we're targeting wasm then we export some wasm APIs.
|
// If we're targeting wasm then we export some wasm APIs.
|
||||||
pub usingnamespace if (builtin.target.isWasm()) struct {
|
comptime {
|
||||||
pub usingnamespace Atlas.Wasm;
|
if (builtin.target.isWasm()) {
|
||||||
pub usingnamespace DeferredFace.Wasm;
|
_ = Atlas.Wasm;
|
||||||
pub usingnamespace face.web_canvas.Wasm;
|
_ = DeferredFace.Wasm;
|
||||||
pub usingnamespace shape.web_canvas.Wasm;
|
_ = face.web_canvas.Wasm;
|
||||||
} else struct {};
|
_ = shape.web_canvas.Wasm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Build options
|
/// Build options
|
||||||
pub const options: struct {
|
pub const options: struct {
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const options = @import("main.zig").options;
|
const options = @import("main.zig").options;
|
||||||
|
const run = @import("shaper/run.zig");
|
||||||
pub const noop = @import("shaper/noop.zig");
|
pub const noop = @import("shaper/noop.zig");
|
||||||
pub const harfbuzz = @import("shaper/harfbuzz.zig");
|
pub const harfbuzz = @import("shaper/harfbuzz.zig");
|
||||||
pub const coretext = @import("shaper/coretext.zig");
|
pub const coretext = @import("shaper/coretext.zig");
|
||||||
pub const web_canvas = @import("shaper/web_canvas.zig");
|
pub const web_canvas = @import("shaper/web_canvas.zig");
|
||||||
pub usingnamespace @import("shaper/run.zig");
|
|
||||||
pub const Cache = @import("shaper/Cache.zig");
|
pub const Cache = @import("shaper/Cache.zig");
|
||||||
|
pub const TextRun = run.TextRun;
|
||||||
|
pub const RunIterator = run.RunIterator;
|
||||||
|
|
||||||
/// Shaper implementation for our compile options.
|
/// Shaper implementation for our compile options.
|
||||||
pub const Shaper = switch (options.backend) {
|
pub const Shaper = switch (options.backend) {
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
pub usingnamespace @import("sprite/canvas.zig");
|
const canvas = @import("sprite/canvas.zig");
|
||||||
pub const Face = @import("sprite/Face.zig");
|
pub const Face = @import("sprite/Face.zig");
|
||||||
|
|
||||||
|
pub const Box = canvas.Box;
|
||||||
|
pub const Canvas = canvas.Canvas;
|
||||||
|
pub const Color = canvas.Color;
|
||||||
|
|
||||||
/// Sprites are represented as special codepoints outside of the Unicode
|
/// Sprites are represented as special codepoints outside of the Unicode
|
||||||
/// codepoint range. Unicode maxes out at U+10FFFF (21 bits), and we use the
|
/// codepoint range. Unicode maxes out at U+10FFFF (21 bits), and we use the
|
||||||
/// high 11 bits to hide our special characters.
|
/// high 11 bits to hide our special characters.
|
||||||
|
147
src/global.zig
Normal file
147
src/global.zig
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const build_config = @import("build_config.zig");
|
||||||
|
const cli = @import("cli.zig");
|
||||||
|
const internal_os = @import("os/main.zig");
|
||||||
|
const fontconfig = @import("fontconfig");
|
||||||
|
const glslang = @import("glslang");
|
||||||
|
const harfbuzz = @import("harfbuzz");
|
||||||
|
const oni = @import("oniguruma");
|
||||||
|
const renderer = @import("renderer.zig");
|
||||||
|
const xev = @import("xev");
|
||||||
|
|
||||||
|
/// Global process state. This is initialized in main() for exe artifacts
|
||||||
|
/// and by ghostty_init() for lib artifacts. This should ONLY be used by
|
||||||
|
/// the C API. The Zig API should NOT use any global state and should
|
||||||
|
/// rely on allocators being passed in as parameters.
|
||||||
|
pub var state: GlobalState = undefined;
|
||||||
|
|
||||||
|
/// This represents the global process state. There should only
|
||||||
|
/// be one of these at any given moment. This is extracted into a dedicated
|
||||||
|
/// struct because it is reused by main and the static C lib.
|
||||||
|
pub const GlobalState = struct {
|
||||||
|
const GPA = std.heap.GeneralPurposeAllocator(.{});
|
||||||
|
|
||||||
|
gpa: ?GPA,
|
||||||
|
alloc: std.mem.Allocator,
|
||||||
|
action: ?cli.Action,
|
||||||
|
logging: Logging,
|
||||||
|
|
||||||
|
/// The app resources directory, equivalent to zig-out/share when we build
|
||||||
|
/// from source. This is null if we can't detect it.
|
||||||
|
resources_dir: ?[]const u8,
|
||||||
|
|
||||||
|
/// Where logging should go
|
||||||
|
pub const Logging = union(enum) {
|
||||||
|
disabled: void,
|
||||||
|
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
|
||||||
|
// the log function uses the global state.
|
||||||
|
self.* = .{
|
||||||
|
.gpa = null,
|
||||||
|
.alloc = undefined,
|
||||||
|
.action = null,
|
||||||
|
.logging = .{ .stderr = {} },
|
||||||
|
.resources_dir = null,
|
||||||
|
};
|
||||||
|
errdefer self.deinit();
|
||||||
|
|
||||||
|
self.gpa = gpa: {
|
||||||
|
// Use the libc allocator if it is available because it is WAY
|
||||||
|
// faster than GPA. We only do this in release modes so that we
|
||||||
|
// can get easy memory leak detection in debug modes.
|
||||||
|
if (builtin.link_libc) {
|
||||||
|
if (switch (builtin.mode) {
|
||||||
|
.ReleaseSafe, .ReleaseFast => true,
|
||||||
|
|
||||||
|
// We also use it if we can detect we're running under
|
||||||
|
// Valgrind since Valgrind only instruments the C allocator
|
||||||
|
else => std.valgrind.runningOnValgrind() > 0,
|
||||||
|
}) break :gpa null;
|
||||||
|
}
|
||||||
|
|
||||||
|
break :gpa GPA{};
|
||||||
|
};
|
||||||
|
|
||||||
|
self.alloc = if (self.gpa) |*value|
|
||||||
|
value.allocator()
|
||||||
|
else if (builtin.link_libc)
|
||||||
|
std.heap.c_allocator
|
||||||
|
else
|
||||||
|
unreachable;
|
||||||
|
|
||||||
|
// We first try to parse any action that we may be executing.
|
||||||
|
self.action = try cli.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 = {} };
|
||||||
|
|
||||||
|
// For lib mode we always disable stderr logging by default.
|
||||||
|
if (comptime build_config.app_runtime == .none) {
|
||||||
|
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,
|
||||||
|
// maybe once for logging) so for now this is an easy way to do
|
||||||
|
// this. Env vars are useful for logging too because they are
|
||||||
|
// easy to set.
|
||||||
|
if ((try internal_os.getenv(self.alloc, "GHOSTTY_LOG"))) |v| {
|
||||||
|
defer v.deinit(self.alloc);
|
||||||
|
if (v.value.len > 0) {
|
||||||
|
self.logging = .{ .stderr = {} };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output some debug information right away
|
||||||
|
std.log.info("ghostty version={s}", .{build_config.version_string});
|
||||||
|
std.log.info("ghostty build optimize={s}", .{build_config.mode_string});
|
||||||
|
std.log.info("runtime={}", .{build_config.app_runtime});
|
||||||
|
std.log.info("font_backend={}", .{build_config.font_backend});
|
||||||
|
if (comptime build_config.font_backend.hasHarfbuzz()) {
|
||||||
|
std.log.info("dependency harfbuzz={s}", .{harfbuzz.versionString()});
|
||||||
|
}
|
||||||
|
if (comptime build_config.font_backend.hasFontconfig()) {
|
||||||
|
std.log.info("dependency fontconfig={d}", .{fontconfig.version()});
|
||||||
|
}
|
||||||
|
std.log.info("renderer={}", .{renderer.Renderer});
|
||||||
|
std.log.info("libxev backend={}", .{xev.backend});
|
||||||
|
|
||||||
|
// First things first, we fix our file descriptors
|
||||||
|
internal_os.fixMaxFiles();
|
||||||
|
|
||||||
|
// We need to make sure the process locale is set properly. Locale
|
||||||
|
// affects a lot of behaviors in a shell.
|
||||||
|
try internal_os.ensureLocale(self.alloc);
|
||||||
|
|
||||||
|
// Initialize glslang for shader compilation
|
||||||
|
try glslang.init();
|
||||||
|
|
||||||
|
// Initialize oniguruma for regex
|
||||||
|
try oni.init(&.{oni.Encoding.utf8});
|
||||||
|
|
||||||
|
// Find our resources directory once for the app so every launch
|
||||||
|
// hereafter can use this cached value.
|
||||||
|
self.resources_dir = try internal_os.resourcesDir(self.alloc);
|
||||||
|
errdefer if (self.resources_dir) |dir| self.alloc.free(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cleans up the global state. This doesn't _need_ to be called but
|
||||||
|
/// doing so in dev modes will check for memory leaks.
|
||||||
|
pub fn deinit(self: *GlobalState) void {
|
||||||
|
if (self.resources_dir) |dir| self.alloc.free(dir);
|
||||||
|
|
||||||
|
if (self.gpa) |*value| {
|
||||||
|
// We want to ensure that we deinit the GPA because this is
|
||||||
|
// the point at which it will output if there were safety violations.
|
||||||
|
_ = value.deinit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -1,15 +1,26 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
pub usingnamespace @import("input/mouse.zig");
|
const mouse = @import("input/mouse.zig");
|
||||||
pub usingnamespace @import("input/key.zig");
|
const key = @import("input/key.zig");
|
||||||
|
|
||||||
pub const function_keys = @import("input/function_keys.zig");
|
pub const function_keys = @import("input/function_keys.zig");
|
||||||
pub const keycodes = @import("input/keycodes.zig");
|
pub const keycodes = @import("input/keycodes.zig");
|
||||||
pub const kitty = @import("input/kitty.zig");
|
pub const kitty = @import("input/kitty.zig");
|
||||||
|
|
||||||
|
pub const ctrlOrSuper = key.ctrlOrSuper;
|
||||||
|
pub const Action = key.Action;
|
||||||
pub const Binding = @import("input/Binding.zig");
|
pub const Binding = @import("input/Binding.zig");
|
||||||
pub const Link = @import("input/Link.zig");
|
pub const Link = @import("input/Link.zig");
|
||||||
|
pub const Key = key.Key;
|
||||||
pub const KeyEncoder = @import("input/KeyEncoder.zig");
|
pub const KeyEncoder = @import("input/KeyEncoder.zig");
|
||||||
|
pub const KeyEvent = key.KeyEvent;
|
||||||
pub const InspectorMode = Binding.Action.InspectorMode;
|
pub const InspectorMode = Binding.Action.InspectorMode;
|
||||||
|
pub const Mods = key.Mods;
|
||||||
|
pub const MouseButton = mouse.Button;
|
||||||
|
pub const MouseButtonState = mouse.ButtonState;
|
||||||
|
pub const MousePressureStage = mouse.PressureStage;
|
||||||
|
pub const ScrollMods = mouse.ScrollMods;
|
||||||
pub const SplitFocusDirection = Binding.Action.SplitFocusDirection;
|
pub const SplitFocusDirection = Binding.Action.SplitFocusDirection;
|
||||||
pub const SplitResizeDirection = Binding.Action.SplitResizeDirection;
|
pub const SplitResizeDirection = Binding.Action.SplitResizeDirection;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ const std = @import("std");
|
|||||||
/// This is backed by a c_int so we can use this as-is for our embedding API.
|
/// This is backed by a c_int so we can use this as-is for our embedding API.
|
||||||
///
|
///
|
||||||
/// IMPORTANT: Any changes here update include/ghostty.h
|
/// IMPORTANT: Any changes here update include/ghostty.h
|
||||||
pub const MouseButtonState = enum(c_int) {
|
pub const ButtonState = enum(c_int) {
|
||||||
release,
|
release,
|
||||||
press,
|
press,
|
||||||
};
|
};
|
||||||
@ -20,7 +20,7 @@ pub const MouseButtonState = enum(c_int) {
|
|||||||
/// This is backed by a c_int so we can use this as-is for our embedding API.
|
/// This is backed by a c_int so we can use this as-is for our embedding API.
|
||||||
///
|
///
|
||||||
/// IMPORTANT: Any changes here update include/ghostty.h
|
/// IMPORTANT: Any changes here update include/ghostty.h
|
||||||
pub const MouseButton = enum(c_int) {
|
pub const Button = enum(c_int) {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
/// The maximum value in this enum. This can be used to create a densely
|
/// The maximum value in this enum. This can be used to create a densely
|
||||||
@ -53,7 +53,7 @@ pub const MouseButton = enum(c_int) {
|
|||||||
/// This is used to handle "inertial scrolling" (i.e. flicking).
|
/// This is used to handle "inertial scrolling" (i.e. flicking).
|
||||||
///
|
///
|
||||||
/// https://developer.apple.com/documentation/appkit/nseventphase
|
/// https://developer.apple.com/documentation/appkit/nseventphase
|
||||||
pub const MouseMomentum = enum(u3) {
|
pub const Momentum = enum(u3) {
|
||||||
none = 0,
|
none = 0,
|
||||||
began = 1,
|
began = 1,
|
||||||
stationary = 2,
|
stationary = 2,
|
||||||
@ -66,7 +66,7 @@ pub const MouseMomentum = enum(u3) {
|
|||||||
/// The pressure stage of a pressure-sensitive input device.
|
/// The pressure stage of a pressure-sensitive input device.
|
||||||
///
|
///
|
||||||
/// This currently only supports the stages that macOS supports.
|
/// This currently only supports the stages that macOS supports.
|
||||||
pub const MousePressureStage = enum(u2) {
|
pub const PressureStage = enum(u2) {
|
||||||
/// The input device is unpressed.
|
/// The input device is unpressed.
|
||||||
none = 0,
|
none = 0,
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ pub const ScrollMods = packed struct(u8) {
|
|||||||
|
|
||||||
/// The momentum phase (if available, supported) of the scroll event.
|
/// The momentum phase (if available, supported) of the scroll event.
|
||||||
/// This is used to handle "inertial scrolling" (i.e. flicking).
|
/// This is used to handle "inertial scrolling" (i.e. flicking).
|
||||||
momentum: MouseMomentum = .none,
|
momentum: Momentum = .none,
|
||||||
|
|
||||||
_padding: u4 = 0,
|
_padding: u4 = 0,
|
||||||
|
|
||||||
|
11
src/main.zig
11
src/main.zig
@ -1,7 +1,7 @@
|
|||||||
const build_config = @import("build_config.zig");
|
const build_config = @import("build_config.zig");
|
||||||
|
|
||||||
// See build_config.ExeEntrypoint for why we do this.
|
/// See build_config.ExeEntrypoint for why we do this.
|
||||||
pub usingnamespace switch (build_config.exe_entrypoint) {
|
const entrypoint = switch (build_config.exe_entrypoint) {
|
||||||
.ghostty => @import("main_ghostty.zig"),
|
.ghostty => @import("main_ghostty.zig"),
|
||||||
.helpgen => @import("helpgen.zig"),
|
.helpgen => @import("helpgen.zig"),
|
||||||
.mdgen_ghostty_1 => @import("build/mdgen/main_ghostty_1.zig"),
|
.mdgen_ghostty_1 => @import("build/mdgen/main_ghostty_1.zig"),
|
||||||
@ -12,3 +12,10 @@ pub usingnamespace switch (build_config.exe_entrypoint) {
|
|||||||
.bench_grapheme_break => @import("bench/grapheme-break.zig"),
|
.bench_grapheme_break => @import("bench/grapheme-break.zig"),
|
||||||
.bench_page_init => @import("bench/page-init.zig"),
|
.bench_page_init => @import("bench/page-init.zig"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// The main entrypoint for the program.
|
||||||
|
pub const main = entrypoint.main;
|
||||||
|
|
||||||
|
test {
|
||||||
|
_ = entrypoint;
|
||||||
|
}
|
||||||
|
@ -12,7 +12,8 @@ const assert = std.debug.assert;
|
|||||||
const posix = std.posix;
|
const posix = std.posix;
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const build_config = @import("build_config.zig");
|
const build_config = @import("build_config.zig");
|
||||||
const main = @import("main.zig");
|
const main = @import("main_ghostty.zig");
|
||||||
|
const state = &@import("global.zig").state;
|
||||||
const apprt = @import("apprt.zig");
|
const apprt = @import("apprt.zig");
|
||||||
|
|
||||||
// Some comptime assertions that our C API depends on.
|
// Some comptime assertions that our C API depends on.
|
||||||
@ -23,8 +24,12 @@ comptime {
|
|||||||
/// Global options so we can log. This is identical to main.
|
/// Global options so we can log. This is identical to main.
|
||||||
pub const std_options = main.std_options;
|
pub const std_options = main.std_options;
|
||||||
|
|
||||||
pub usingnamespace @import("config.zig").CAPI;
|
comptime {
|
||||||
pub usingnamespace apprt.runtime.CAPI;
|
// These structs need to be referenced so the `export` functions
|
||||||
|
// are truly exported by the C API lib.
|
||||||
|
_ = @import("config.zig").CAPI;
|
||||||
|
_ = apprt.runtime.CAPI;
|
||||||
|
}
|
||||||
|
|
||||||
/// ghostty_info_s
|
/// ghostty_info_s
|
||||||
const Info = extern struct {
|
const Info = extern struct {
|
||||||
@ -51,7 +56,7 @@ export fn ghostty_init() c_int {
|
|||||||
var argv: [0][*:0]u8 = .{};
|
var argv: [0][*:0]u8 = .{};
|
||||||
std.os.argv = &argv;
|
std.os.argv = &argv;
|
||||||
|
|
||||||
main.state.init() catch |err| {
|
state.init() catch |err| {
|
||||||
std.log.err("failed to initialize ghostty error={}", .{err});
|
std.log.err("failed to initialize ghostty error={}", .{err});
|
||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
|
@ -21,12 +21,7 @@ const apprt = @import("apprt.zig");
|
|||||||
|
|
||||||
const App = @import("App.zig");
|
const App = @import("App.zig");
|
||||||
const Ghostty = @import("main_c.zig").Ghostty;
|
const Ghostty = @import("main_c.zig").Ghostty;
|
||||||
|
const state = &@import("global.zig").state;
|
||||||
/// Global process state. This is initialized in main() for exe artifacts
|
|
||||||
/// and by ghostty_init() for lib artifacts. This should ONLY be used by
|
|
||||||
/// the C API. The Zig API should NOT use any global state and should
|
|
||||||
/// rely on allocators being passed in as parameters.
|
|
||||||
pub var state: GlobalState = undefined;
|
|
||||||
|
|
||||||
/// The return type for main() depends on the build artifact. The lib build
|
/// 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
|
/// also calls "main" in order to run the CLI actions, but it calls it as
|
||||||
@ -172,136 +167,6 @@ pub const std_options: std.Options = .{
|
|||||||
.logFn = logFn,
|
.logFn = logFn,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This represents the global process state. There should only
|
|
||||||
/// be one of these at any given moment. This is extracted into a dedicated
|
|
||||||
/// struct because it is reused by main and the static C lib.
|
|
||||||
pub const GlobalState = struct {
|
|
||||||
const GPA = std.heap.GeneralPurposeAllocator(.{});
|
|
||||||
|
|
||||||
gpa: ?GPA,
|
|
||||||
alloc: std.mem.Allocator,
|
|
||||||
action: ?cli.Action,
|
|
||||||
logging: Logging,
|
|
||||||
|
|
||||||
/// The app resources directory, equivalent to zig-out/share when we build
|
|
||||||
/// from source. This is null if we can't detect it.
|
|
||||||
resources_dir: ?[]const u8,
|
|
||||||
|
|
||||||
/// Where logging should go
|
|
||||||
pub const Logging = union(enum) {
|
|
||||||
disabled: void,
|
|
||||||
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
|
|
||||||
// the log function uses the global state.
|
|
||||||
self.* = .{
|
|
||||||
.gpa = null,
|
|
||||||
.alloc = undefined,
|
|
||||||
.action = null,
|
|
||||||
.logging = .{ .stderr = {} },
|
|
||||||
.resources_dir = null,
|
|
||||||
};
|
|
||||||
errdefer self.deinit();
|
|
||||||
|
|
||||||
self.gpa = gpa: {
|
|
||||||
// Use the libc allocator if it is available because it is WAY
|
|
||||||
// faster than GPA. We only do this in release modes so that we
|
|
||||||
// can get easy memory leak detection in debug modes.
|
|
||||||
if (builtin.link_libc) {
|
|
||||||
if (switch (builtin.mode) {
|
|
||||||
.ReleaseSafe, .ReleaseFast => true,
|
|
||||||
|
|
||||||
// We also use it if we can detect we're running under
|
|
||||||
// Valgrind since Valgrind only instruments the C allocator
|
|
||||||
else => std.valgrind.runningOnValgrind() > 0,
|
|
||||||
}) break :gpa null;
|
|
||||||
}
|
|
||||||
|
|
||||||
break :gpa GPA{};
|
|
||||||
};
|
|
||||||
|
|
||||||
self.alloc = if (self.gpa) |*value|
|
|
||||||
value.allocator()
|
|
||||||
else if (builtin.link_libc)
|
|
||||||
std.heap.c_allocator
|
|
||||||
else
|
|
||||||
unreachable;
|
|
||||||
|
|
||||||
// We first try to parse any action that we may be executing.
|
|
||||||
self.action = try cli.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 = {} };
|
|
||||||
|
|
||||||
// For lib mode we always disable stderr logging by default.
|
|
||||||
if (comptime build_config.app_runtime == .none) {
|
|
||||||
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,
|
|
||||||
// maybe once for logging) so for now this is an easy way to do
|
|
||||||
// this. Env vars are useful for logging too because they are
|
|
||||||
// easy to set.
|
|
||||||
if ((try internal_os.getenv(self.alloc, "GHOSTTY_LOG"))) |v| {
|
|
||||||
defer v.deinit(self.alloc);
|
|
||||||
if (v.value.len > 0) {
|
|
||||||
self.logging = .{ .stderr = {} };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output some debug information right away
|
|
||||||
std.log.info("ghostty version={s}", .{build_config.version_string});
|
|
||||||
std.log.info("ghostty build optimize={s}", .{build_config.mode_string});
|
|
||||||
std.log.info("runtime={}", .{build_config.app_runtime});
|
|
||||||
std.log.info("font_backend={}", .{build_config.font_backend});
|
|
||||||
if (comptime build_config.font_backend.hasHarfbuzz()) {
|
|
||||||
std.log.info("dependency harfbuzz={s}", .{harfbuzz.versionString()});
|
|
||||||
}
|
|
||||||
if (comptime build_config.font_backend.hasFontconfig()) {
|
|
||||||
std.log.info("dependency fontconfig={d}", .{fontconfig.version()});
|
|
||||||
}
|
|
||||||
std.log.info("renderer={}", .{renderer.Renderer});
|
|
||||||
std.log.info("libxev backend={}", .{xev.backend});
|
|
||||||
|
|
||||||
// First things first, we fix our file descriptors
|
|
||||||
internal_os.fixMaxFiles();
|
|
||||||
|
|
||||||
// We need to make sure the process locale is set properly. Locale
|
|
||||||
// affects a lot of behaviors in a shell.
|
|
||||||
try internal_os.ensureLocale(self.alloc);
|
|
||||||
|
|
||||||
// Initialize glslang for shader compilation
|
|
||||||
try glslang.init();
|
|
||||||
|
|
||||||
// Initialize oniguruma for regex
|
|
||||||
try oni.init(&.{oni.Encoding.utf8});
|
|
||||||
|
|
||||||
// Find our resources directory once for the app so every launch
|
|
||||||
// hereafter can use this cached value.
|
|
||||||
self.resources_dir = try internal_os.resourcesDir(self.alloc);
|
|
||||||
errdefer if (self.resources_dir) |dir| self.alloc.free(dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cleans up the global state. This doesn't _need_ to be called but
|
|
||||||
/// doing so in dev modes will check for memory leaks.
|
|
||||||
pub fn deinit(self: *GlobalState) void {
|
|
||||||
if (self.resources_dir) |dir| self.alloc.free(dir);
|
|
||||||
|
|
||||||
if (self.gpa) |*value| {
|
|
||||||
// We want to ensure that we deinit the GPA because this is
|
|
||||||
// the point at which it will output if there were safety violations.
|
|
||||||
_ = value.deinit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
test {
|
test {
|
||||||
_ = @import("circ_buf.zig");
|
_ = @import("circ_buf.zig");
|
||||||
_ = @import("pty.zig");
|
_ = @import("pty.zig");
|
||||||
|
@ -3,11 +3,13 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
pub usingnamespace @import("os/wasm.zig");
|
comptime {
|
||||||
pub usingnamespace @import("font/main.zig");
|
_ = @import("os/wasm.zig");
|
||||||
pub usingnamespace @import("terminal/main.zig");
|
_ = @import("font/main.zig");
|
||||||
pub usingnamespace @import("config.zig").Wasm;
|
_ = @import("terminal/main.zig");
|
||||||
pub usingnamespace @import("App.zig").Wasm;
|
_ = @import("config.zig").Wasm;
|
||||||
|
_ = @import("App.zig").Wasm;
|
||||||
|
}
|
||||||
|
|
||||||
pub const std_options = struct {
|
pub const std_options = struct {
|
||||||
// Set our log level. We try to get as much logging as possible but in
|
// Set our log level. We try to get as much logging as possible but in
|
||||||
|
@ -2,20 +2,42 @@
|
|||||||
//! system. These aren't restricted to syscalls or low-level operations, but
|
//! system. These aren't restricted to syscalls or low-level operations, but
|
||||||
//! also OS-specific features and conventions.
|
//! also OS-specific features and conventions.
|
||||||
|
|
||||||
pub usingnamespace @import("env.zig");
|
const desktop = @import("desktop.zig");
|
||||||
pub usingnamespace @import("desktop.zig");
|
const env = @import("env.zig");
|
||||||
pub usingnamespace @import("file.zig");
|
const file = @import("file.zig");
|
||||||
pub usingnamespace @import("flatpak.zig");
|
const flatpak = @import("flatpak.zig");
|
||||||
pub usingnamespace @import("homedir.zig");
|
const homedir = @import("homedir.zig");
|
||||||
pub usingnamespace @import("locale.zig");
|
const locale = @import("locale.zig");
|
||||||
pub usingnamespace @import("macos_version.zig");
|
const macos_version = @import("macos_version.zig");
|
||||||
pub usingnamespace @import("mouse.zig");
|
const mouse = @import("mouse.zig");
|
||||||
pub usingnamespace @import("open.zig");
|
const openpkg = @import("open.zig");
|
||||||
pub usingnamespace @import("pipe.zig");
|
const pipepkg = @import("pipe.zig");
|
||||||
pub usingnamespace @import("resourcesdir.zig");
|
const resourcesdir = @import("resourcesdir.zig");
|
||||||
pub const CFReleaseThread = @import("cf_release_thread.zig");
|
|
||||||
pub const TempDir = @import("TempDir.zig");
|
// Namespaces
|
||||||
pub const cgroup = @import("cgroup.zig");
|
pub const cgroup = @import("cgroup.zig");
|
||||||
pub const passwd = @import("passwd.zig");
|
pub const passwd = @import("passwd.zig");
|
||||||
pub const xdg = @import("xdg.zig");
|
pub const xdg = @import("xdg.zig");
|
||||||
pub const windows = @import("windows.zig");
|
pub const windows = @import("windows.zig");
|
||||||
|
|
||||||
|
// Functions and types
|
||||||
|
pub const CFReleaseThread = @import("cf_release_thread.zig");
|
||||||
|
pub const TempDir = @import("TempDir.zig");
|
||||||
|
pub const PATH_SEP = env.PATH_SEP;
|
||||||
|
pub const appendEnv = env.appendEnv;
|
||||||
|
pub const appendEnvAlways = env.appendEnvAlways;
|
||||||
|
pub const getenv = env.getenv;
|
||||||
|
pub const setenv = env.setenv;
|
||||||
|
pub const unsetenv = env.unsetenv;
|
||||||
|
pub const launchedFromDesktop = desktop.launchedFromDesktop;
|
||||||
|
pub const fixMaxFiles = file.fixMaxFiles;
|
||||||
|
pub const allocTmpDir = file.allocTmpDir;
|
||||||
|
pub const freeTmpDir = file.freeTmpDir;
|
||||||
|
pub const isFlatpak = flatpak.isFlatpak;
|
||||||
|
pub const home = homedir.home;
|
||||||
|
pub const ensureLocale = locale.ensureLocale;
|
||||||
|
pub const macosVersionAtLeast = macos_version.macosVersionAtLeast;
|
||||||
|
pub const clickInterval = mouse.clickInterval;
|
||||||
|
pub const open = openpkg.open;
|
||||||
|
pub const pipe = pipepkg.pipe;
|
||||||
|
pub const resourcesDir = resourcesdir.resourcesDir;
|
||||||
|
@ -4,9 +4,9 @@ const wasm = @import("../wasm.zig");
|
|||||||
const wasm_target = @import("target.zig");
|
const wasm_target = @import("target.zig");
|
||||||
|
|
||||||
// Use the correct implementation
|
// Use the correct implementation
|
||||||
pub usingnamespace if (wasm_target.target) |target| switch (target) {
|
pub const log = if (wasm_target.target) |target| switch (target) {
|
||||||
.browser => Browser,
|
.browser => Browser.log,
|
||||||
} else struct {};
|
} else @compileError("wasm target required");
|
||||||
|
|
||||||
/// Browser implementation calls an extern "log" function.
|
/// Browser implementation calls an extern "log" function.
|
||||||
pub const Browser = struct {
|
pub const Browser = struct {
|
||||||
|
@ -1,7 +1,33 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const windows = std.os.windows;
|
const windows = std.os.windows;
|
||||||
|
|
||||||
pub usingnamespace std.os.windows;
|
// Export any constants or functions we need from the Windows API so
|
||||||
|
// we can just import one file.
|
||||||
|
pub const kernel32 = windows.kernel32;
|
||||||
|
pub const unexpectedError = windows.unexpectedError;
|
||||||
|
pub const OpenFile = windows.OpenFile;
|
||||||
|
pub const SetHandleInformation = windows.SetHandleInformation;
|
||||||
|
pub const DWORD = windows.DWORD;
|
||||||
|
pub const FILE_ATTRIBUTE_NORMAL = windows.FILE_ATTRIBUTE_NORMAL;
|
||||||
|
pub const FILE_FLAG_OVERLAPPED = windows.FILE_FLAG_OVERLAPPED;
|
||||||
|
pub const FILE_SHARE_READ = windows.FILE_SHARE_READ;
|
||||||
|
pub const GENERIC_READ = windows.GENERIC_READ;
|
||||||
|
pub const HANDLE = windows.HANDLE;
|
||||||
|
pub const HANDLE_FLAG_INHERIT = windows.HANDLE_FLAG_INHERIT;
|
||||||
|
pub const INFINITE = windows.INFINITE;
|
||||||
|
pub const INVALID_HANDLE_VALUE = windows.INVALID_HANDLE_VALUE;
|
||||||
|
pub const OPEN_EXISTING = windows.OPEN_EXISTING;
|
||||||
|
pub const PIPE_ACCESS_OUTBOUND = windows.PIPE_ACCESS_OUTBOUND;
|
||||||
|
pub const PIPE_TYPE_BYTE = windows.PIPE_TYPE_BYTE;
|
||||||
|
pub const PROCESS_INFORMATION = windows.PROCESS_INFORMATION;
|
||||||
|
pub const S_OK = windows.S_OK;
|
||||||
|
pub const SECURITY_ATTRIBUTES = windows.SECURITY_ATTRIBUTES;
|
||||||
|
pub const STARTUPINFOW = windows.STARTUPINFOW;
|
||||||
|
pub const STARTF_USESTDHANDLES = windows.STARTF_USESTDHANDLES;
|
||||||
|
pub const SYNCHRONIZE = windows.SYNCHRONIZE;
|
||||||
|
pub const WAIT_FAILED = windows.WAIT_FAILED;
|
||||||
|
pub const FALSE = windows.FALSE;
|
||||||
|
pub const TRUE = windows.TRUE;
|
||||||
|
|
||||||
pub const exp = struct {
|
pub const exp = struct {
|
||||||
pub const HPCON = windows.LPVOID;
|
pub const HPCON = windows.LPVOID;
|
||||||
|
20
src/pty.zig
20
src/pty.zig
@ -63,17 +63,15 @@ const PosixPty = struct {
|
|||||||
const TIOCSWINSZ = if (builtin.os.tag == .macos) 2148037735 else c.TIOCSWINSZ;
|
const TIOCSWINSZ = if (builtin.os.tag == .macos) 2148037735 else c.TIOCSWINSZ;
|
||||||
const TIOCGWINSZ = if (builtin.os.tag == .macos) 1074295912 else c.TIOCGWINSZ;
|
const TIOCGWINSZ = if (builtin.os.tag == .macos) 1074295912 else c.TIOCGWINSZ;
|
||||||
extern "c" fn setsid() std.c.pid_t;
|
extern "c" fn setsid() std.c.pid_t;
|
||||||
const c = struct {
|
const c = switch (builtin.os.tag) {
|
||||||
usingnamespace switch (builtin.os.tag) {
|
.macos => @cImport({
|
||||||
.macos => @cImport({
|
@cInclude("sys/ioctl.h"); // ioctl and constants
|
||||||
@cInclude("sys/ioctl.h"); // ioctl and constants
|
@cInclude("util.h"); // openpty()
|
||||||
@cInclude("util.h"); // openpty()
|
}),
|
||||||
}),
|
else => @cImport({
|
||||||
else => @cImport({
|
@cInclude("sys/ioctl.h"); // ioctl and constants
|
||||||
@cInclude("sys/ioctl.h"); // ioctl and constants
|
@cInclude("pty.h");
|
||||||
@cInclude("pty.h");
|
}),
|
||||||
}),
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The file descriptors for the master and slave side of the pty.
|
/// The file descriptors for the master and slave side of the pty.
|
||||||
|
@ -12,9 +12,9 @@ const builtin = @import("builtin");
|
|||||||
const build_config = @import("build_config.zig");
|
const build_config = @import("build_config.zig");
|
||||||
const WasmTarget = @import("os/wasm/target.zig").Target;
|
const WasmTarget = @import("os/wasm/target.zig").Target;
|
||||||
|
|
||||||
pub usingnamespace @import("renderer/cursor.zig");
|
const cursor = @import("renderer/cursor.zig");
|
||||||
pub usingnamespace @import("renderer/message.zig");
|
const message = @import("renderer/message.zig");
|
||||||
pub usingnamespace @import("renderer/size.zig");
|
const size = @import("renderer/size.zig");
|
||||||
pub const shadertoy = @import("renderer/shadertoy.zig");
|
pub const shadertoy = @import("renderer/shadertoy.zig");
|
||||||
pub const Metal = @import("renderer/Metal.zig");
|
pub const Metal = @import("renderer/Metal.zig");
|
||||||
pub const OpenGL = @import("renderer/OpenGL.zig");
|
pub const OpenGL = @import("renderer/OpenGL.zig");
|
||||||
@ -22,6 +22,13 @@ pub const WebGL = @import("renderer/WebGL.zig");
|
|||||||
pub const Options = @import("renderer/Options.zig");
|
pub const Options = @import("renderer/Options.zig");
|
||||||
pub const Thread = @import("renderer/Thread.zig");
|
pub const Thread = @import("renderer/Thread.zig");
|
||||||
pub const State = @import("renderer/State.zig");
|
pub const State = @import("renderer/State.zig");
|
||||||
|
pub const CursorStyle = cursor.Style;
|
||||||
|
pub const Message = message.Message;
|
||||||
|
pub const CellSize = size.CellSize;
|
||||||
|
pub const ScreenSize = size.ScreenSize;
|
||||||
|
pub const GridSize = size.GridSize;
|
||||||
|
pub const Padding = size.Padding;
|
||||||
|
pub const cursorStyle = cursor.style;
|
||||||
|
|
||||||
/// Possible implementations, used for build options.
|
/// Possible implementations, used for build options.
|
||||||
pub const Impl = enum {
|
pub const Impl = enum {
|
||||||
|
@ -5,15 +5,15 @@ const State = @import("State.zig");
|
|||||||
/// Available cursor styles for drawing that renderers must support.
|
/// Available cursor styles for drawing that renderers must support.
|
||||||
/// This is a superset of terminal cursor styles since the renderer supports
|
/// This is a superset of terminal cursor styles since the renderer supports
|
||||||
/// some additional cursor states such as the hollow block.
|
/// some additional cursor states such as the hollow block.
|
||||||
pub const CursorStyle = enum {
|
pub const Style = enum {
|
||||||
block,
|
block,
|
||||||
block_hollow,
|
block_hollow,
|
||||||
bar,
|
bar,
|
||||||
underline,
|
underline,
|
||||||
|
|
||||||
/// Create a cursor style from the terminal style request.
|
/// Create a cursor style from the terminal style request.
|
||||||
pub fn fromTerminal(style: terminal.CursorStyle) ?CursorStyle {
|
pub fn fromTerminal(term: terminal.CursorStyle) ?Style {
|
||||||
return switch (style) {
|
return switch (term) {
|
||||||
.bar => .bar,
|
.bar => .bar,
|
||||||
.block => .block,
|
.block => .block,
|
||||||
.underline => .underline,
|
.underline => .underline,
|
||||||
@ -23,11 +23,11 @@ pub const CursorStyle = enum {
|
|||||||
|
|
||||||
/// Returns the cursor style to use for the current render state or null
|
/// Returns the cursor style to use for the current render state or null
|
||||||
/// if a cursor should not be rendered at all.
|
/// if a cursor should not be rendered at all.
|
||||||
pub fn cursorStyle(
|
pub fn style(
|
||||||
state: *State,
|
state: *State,
|
||||||
focused: bool,
|
focused: bool,
|
||||||
blink_visible: bool,
|
blink_visible: bool,
|
||||||
) ?CursorStyle {
|
) ?Style {
|
||||||
// Note the order of conditionals below is important. It represents
|
// Note the order of conditionals below is important. It represents
|
||||||
// a priority system of how we determine what state overrides cursor
|
// a priority system of how we determine what state overrides cursor
|
||||||
// visibility and style.
|
// visibility and style.
|
||||||
@ -57,7 +57,7 @@ pub fn cursorStyle(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, we use whatever style the terminal wants.
|
// Otherwise, we use whatever style the terminal wants.
|
||||||
return CursorStyle.fromTerminal(state.terminal.screen.cursor.cursor_style);
|
return Style.fromTerminal(state.terminal.screen.cursor.cursor_style);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "cursor: default uses configured style" {
|
test "cursor: default uses configured style" {
|
||||||
@ -75,10 +75,10 @@ test "cursor: default uses configured style" {
|
|||||||
.preedit = null,
|
.preedit = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
try testing.expect(cursorStyle(&state, true, true) == .bar);
|
try testing.expect(style(&state, true, true) == .bar);
|
||||||
try testing.expect(cursorStyle(&state, false, true) == .block_hollow);
|
try testing.expect(style(&state, false, true) == .block_hollow);
|
||||||
try testing.expect(cursorStyle(&state, false, false) == .block_hollow);
|
try testing.expect(style(&state, false, false) == .block_hollow);
|
||||||
try testing.expect(cursorStyle(&state, true, false) == null);
|
try testing.expect(style(&state, true, false) == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "cursor: blinking disabled" {
|
test "cursor: blinking disabled" {
|
||||||
@ -96,10 +96,10 @@ test "cursor: blinking disabled" {
|
|||||||
.preedit = null,
|
.preedit = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
try testing.expect(cursorStyle(&state, true, true) == .bar);
|
try testing.expect(style(&state, true, true) == .bar);
|
||||||
try testing.expect(cursorStyle(&state, true, false) == .bar);
|
try testing.expect(style(&state, true, false) == .bar);
|
||||||
try testing.expect(cursorStyle(&state, false, true) == .block_hollow);
|
try testing.expect(style(&state, false, true) == .block_hollow);
|
||||||
try testing.expect(cursorStyle(&state, false, false) == .block_hollow);
|
try testing.expect(style(&state, false, false) == .block_hollow);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "cursor: explicitly not visible" {
|
test "cursor: explicitly not visible" {
|
||||||
@ -118,10 +118,10 @@ test "cursor: explicitly not visible" {
|
|||||||
.preedit = null,
|
.preedit = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
try testing.expect(cursorStyle(&state, true, true) == null);
|
try testing.expect(style(&state, true, true) == null);
|
||||||
try testing.expect(cursorStyle(&state, true, false) == null);
|
try testing.expect(style(&state, true, false) == null);
|
||||||
try testing.expect(cursorStyle(&state, false, true) == null);
|
try testing.expect(style(&state, false, true) == null);
|
||||||
try testing.expect(cursorStyle(&state, false, false) == null);
|
try testing.expect(style(&state, false, false) == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "cursor: always block with preedit" {
|
test "cursor: always block with preedit" {
|
||||||
@ -137,18 +137,18 @@ test "cursor: always block with preedit" {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// In any bool state
|
// In any bool state
|
||||||
try testing.expect(cursorStyle(&state, false, false) == .block);
|
try testing.expect(style(&state, false, false) == .block);
|
||||||
try testing.expect(cursorStyle(&state, true, false) == .block);
|
try testing.expect(style(&state, true, false) == .block);
|
||||||
try testing.expect(cursorStyle(&state, true, true) == .block);
|
try testing.expect(style(&state, true, true) == .block);
|
||||||
try testing.expect(cursorStyle(&state, false, true) == .block);
|
try testing.expect(style(&state, false, true) == .block);
|
||||||
|
|
||||||
// If we're scrolled though, then we don't show the cursor.
|
// If we're scrolled though, then we don't show the cursor.
|
||||||
for (0..100) |_| try term.index();
|
for (0..100) |_| try term.index();
|
||||||
try term.scrollViewport(.{ .top = {} });
|
try term.scrollViewport(.{ .top = {} });
|
||||||
|
|
||||||
// In any bool state
|
// In any bool state
|
||||||
try testing.expect(cursorStyle(&state, false, false) == null);
|
try testing.expect(style(&state, false, false) == null);
|
||||||
try testing.expect(cursorStyle(&state, true, false) == null);
|
try testing.expect(style(&state, true, false) == null);
|
||||||
try testing.expect(cursorStyle(&state, true, true) == null);
|
try testing.expect(style(&state, true, true) == null);
|
||||||
try testing.expect(cursorStyle(&state, false, true) == null);
|
try testing.expect(style(&state, false, true) == null);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
pub usingnamespace @import("codepoint_width.zig");
|
const codepoint_width = @import("codepoint_width.zig");
|
||||||
pub const base64 = @import("base64.zig");
|
pub const base64 = @import("base64.zig");
|
||||||
pub const index_of = @import("index_of.zig");
|
pub const index_of = @import("index_of.zig");
|
||||||
pub const vt = @import("vt.zig");
|
pub const vt = @import("vt.zig");
|
||||||
|
pub const codepointWidth = codepoint_width.codepointWidth;
|
||||||
|
|
||||||
test {
|
test {
|
||||||
@import("std").testing.refAllDecls(@This());
|
@import("std").testing.refAllDecls(@This());
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
pub usingnamespace @cImport({
|
const c = @cImport({
|
||||||
@cInclude("stb_image.h");
|
@cInclude("stb_image.h");
|
||||||
@cInclude("stb_image_resize.h");
|
@cInclude("stb_image_resize.h");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// We'll just add the exports of the functions or types we actually use
|
||||||
|
// here, no need to export everything from the C lib if we don't use it.
|
||||||
|
pub const stbi_load_from_memory = c.stbi_load_from_memory;
|
||||||
|
pub const stbi_image_free = c.stbi_image_free;
|
||||||
|
pub const stbir_resize_uint8 = c.stbir_resize_uint8;
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
//! Types and functions related to Kitty protocols.
|
//! Types and functions related to Kitty protocols.
|
||||||
|
|
||||||
|
const key = @import("kitty/key.zig");
|
||||||
pub const graphics = @import("kitty/graphics.zig");
|
pub const graphics = @import("kitty/graphics.zig");
|
||||||
pub usingnamespace @import("kitty/key.zig");
|
|
||||||
|
pub const KeyFlags = key.Flags;
|
||||||
|
pub const KeyFlagStack = key.FlagStack;
|
||||||
|
pub const KeySetMode = key.SetMode;
|
||||||
|
|
||||||
test {
|
test {
|
||||||
@import("std").testing.refAllDecls(@This());
|
@import("std").testing.refAllDecls(@This());
|
||||||
|
@ -17,12 +17,19 @@
|
|||||||
//! though and I think we can go back through and fix this up.
|
//! though and I think we can go back through and fix this up.
|
||||||
|
|
||||||
const render = @import("graphics_render.zig");
|
const render = @import("graphics_render.zig");
|
||||||
pub usingnamespace @import("graphics_command.zig");
|
const command = @import("graphics_command.zig");
|
||||||
pub usingnamespace @import("graphics_exec.zig");
|
const exec = @import("graphics_exec.zig");
|
||||||
pub usingnamespace @import("graphics_image.zig");
|
const image = @import("graphics_image.zig");
|
||||||
pub usingnamespace @import("graphics_storage.zig");
|
const storage = @import("graphics_storage.zig");
|
||||||
pub const unicode = @import("graphics_unicode.zig");
|
pub const unicode = @import("graphics_unicode.zig");
|
||||||
|
pub const Command = command.Command;
|
||||||
|
pub const CommandParser = command.Parser;
|
||||||
|
pub const Image = image.Image;
|
||||||
|
pub const ImageStorage = storage.ImageStorage;
|
||||||
pub const RenderPlacement = render.Placement;
|
pub const RenderPlacement = render.Placement;
|
||||||
|
pub const Response = command.Response;
|
||||||
|
|
||||||
|
pub const execute = exec.execute;
|
||||||
|
|
||||||
test {
|
test {
|
||||||
@import("std").testing.refAllDecls(@This());
|
@import("std").testing.refAllDecls(@This());
|
||||||
|
@ -15,7 +15,7 @@ const log = std.log.scoped(.kitty_gfx);
|
|||||||
const KV = std.AutoHashMapUnmanaged(u8, u32);
|
const KV = std.AutoHashMapUnmanaged(u8, u32);
|
||||||
|
|
||||||
/// Command parser parses the Kitty graphics protocol escape sequence.
|
/// Command parser parses the Kitty graphics protocol escape sequence.
|
||||||
pub const CommandParser = struct {
|
pub const Parser = struct {
|
||||||
/// The memory used by the parser is stored in an arena because it is
|
/// The memory used by the parser is stored in an arena because it is
|
||||||
/// all freed at the end of the command.
|
/// all freed at the end of the command.
|
||||||
arena: ArenaAllocator,
|
arena: ArenaAllocator,
|
||||||
@ -54,7 +54,7 @@ pub const CommandParser = struct {
|
|||||||
|
|
||||||
/// Initialize the parser. The allocator given will be used for both
|
/// Initialize the parser. The allocator given will be used for both
|
||||||
/// temporary data and long-lived values such as the final image blob.
|
/// temporary data and long-lived values such as the final image blob.
|
||||||
pub fn init(alloc: Allocator) CommandParser {
|
pub fn init(alloc: Allocator) Parser {
|
||||||
var arena = ArenaAllocator.init(alloc);
|
var arena = ArenaAllocator.init(alloc);
|
||||||
errdefer arena.deinit();
|
errdefer arena.deinit();
|
||||||
return .{
|
return .{
|
||||||
@ -63,7 +63,7 @@ pub const CommandParser = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *CommandParser) void {
|
pub fn deinit(self: *Parser) void {
|
||||||
// We don't free the hash map because its in the arena
|
// We don't free the hash map because its in the arena
|
||||||
self.arena.deinit();
|
self.arena.deinit();
|
||||||
self.data.deinit();
|
self.data.deinit();
|
||||||
@ -74,7 +74,7 @@ pub const CommandParser = struct {
|
|||||||
/// The first byte to start parsing should be the byte immediately following
|
/// The first byte to start parsing should be the byte immediately following
|
||||||
/// the "G" in the APC sequence, i.e. "\x1b_G123" the first byte should
|
/// the "G" in the APC sequence, i.e. "\x1b_G123" the first byte should
|
||||||
/// be "1".
|
/// be "1".
|
||||||
pub fn feed(self: *CommandParser, c: u8) !void {
|
pub fn feed(self: *Parser, c: u8) !void {
|
||||||
switch (self.state) {
|
switch (self.state) {
|
||||||
.control_key => switch (c) {
|
.control_key => switch (c) {
|
||||||
// '=' means the key is complete and we're moving to the value.
|
// '=' means the key is complete and we're moving to the value.
|
||||||
@ -119,7 +119,7 @@ pub const CommandParser = struct {
|
|||||||
///
|
///
|
||||||
/// The allocator given will be used for the long-lived data
|
/// The allocator given will be used for the long-lived data
|
||||||
/// of the final command.
|
/// of the final command.
|
||||||
pub fn complete(self: *CommandParser) !Command {
|
pub fn complete(self: *Parser) !Command {
|
||||||
switch (self.state) {
|
switch (self.state) {
|
||||||
// We can't ever end in the control key state and be valid.
|
// We can't ever end in the control key state and be valid.
|
||||||
// This means the command looked something like "a=1,b"
|
// This means the command looked something like "a=1,b"
|
||||||
@ -175,7 +175,7 @@ pub const CommandParser = struct {
|
|||||||
/// Decodes the payload data from base64 and returns it as a slice.
|
/// Decodes the payload data from base64 and returns it as a slice.
|
||||||
/// This function will destroy the contents of self.data, it should
|
/// This function will destroy the contents of self.data, it should
|
||||||
/// only be used once we are done collecting payload bytes.
|
/// only be used once we are done collecting payload bytes.
|
||||||
fn decodeData(self: *CommandParser) ![]const u8 {
|
fn decodeData(self: *Parser) ![]const u8 {
|
||||||
if (self.data.items.len == 0) {
|
if (self.data.items.len == 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -202,7 +202,7 @@ pub const CommandParser = struct {
|
|||||||
return try self.data.toOwnedSlice();
|
return try self.data.toOwnedSlice();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accumulateValue(self: *CommandParser, c: u8, overflow_state: State) !void {
|
fn accumulateValue(self: *Parser, c: u8, overflow_state: State) !void {
|
||||||
const idx = self.kv_temp_len;
|
const idx = self.kv_temp_len;
|
||||||
self.kv_temp_len += 1;
|
self.kv_temp_len += 1;
|
||||||
if (self.kv_temp_len > self.kv_temp.len) {
|
if (self.kv_temp_len > self.kv_temp.len) {
|
||||||
@ -213,7 +213,7 @@ pub const CommandParser = struct {
|
|||||||
self.kv_temp[idx] = c;
|
self.kv_temp[idx] = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finishValue(self: *CommandParser, next_state: State) !void {
|
fn finishValue(self: *Parser, next_state: State) !void {
|
||||||
const alloc = self.arena.allocator();
|
const alloc = self.arena.allocator();
|
||||||
|
|
||||||
// We can move states right away, we don't use it.
|
// We can move states right away, we don't use it.
|
||||||
@ -896,7 +896,7 @@ pub const CompositionMode = enum {
|
|||||||
test "transmission command" {
|
test "transmission command" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var p = CommandParser.init(alloc);
|
var p = Parser.init(alloc);
|
||||||
defer p.deinit();
|
defer p.deinit();
|
||||||
|
|
||||||
const input = "f=24,s=10,v=20";
|
const input = "f=24,s=10,v=20";
|
||||||
@ -914,7 +914,7 @@ test "transmission command" {
|
|||||||
test "query command" {
|
test "query command" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var p = CommandParser.init(alloc);
|
var p = Parser.init(alloc);
|
||||||
defer p.deinit();
|
defer p.deinit();
|
||||||
|
|
||||||
const input = "i=31,s=1,v=1,a=q,t=d,f=24;QUFBQQ";
|
const input = "i=31,s=1,v=1,a=q,t=d,f=24;QUFBQQ";
|
||||||
@ -934,7 +934,7 @@ test "query command" {
|
|||||||
test "display command" {
|
test "display command" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var p = CommandParser.init(alloc);
|
var p = Parser.init(alloc);
|
||||||
defer p.deinit();
|
defer p.deinit();
|
||||||
|
|
||||||
const input = "a=p,U=1,i=31,c=80,r=120";
|
const input = "a=p,U=1,i=31,c=80,r=120";
|
||||||
@ -952,7 +952,7 @@ test "display command" {
|
|||||||
test "delete command" {
|
test "delete command" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var p = CommandParser.init(alloc);
|
var p = Parser.init(alloc);
|
||||||
defer p.deinit();
|
defer p.deinit();
|
||||||
|
|
||||||
const input = "a=d,d=p,x=3,y=4";
|
const input = "a=d,d=p,x=3,y=4";
|
||||||
@ -972,7 +972,7 @@ test "delete command" {
|
|||||||
test "ignore unknown keys (long)" {
|
test "ignore unknown keys (long)" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var p = CommandParser.init(alloc);
|
var p = Parser.init(alloc);
|
||||||
defer p.deinit();
|
defer p.deinit();
|
||||||
|
|
||||||
const input = "f=24,s=10,v=20,hello=world";
|
const input = "f=24,s=10,v=20,hello=world";
|
||||||
@ -990,7 +990,7 @@ test "ignore unknown keys (long)" {
|
|||||||
test "ignore very long values" {
|
test "ignore very long values" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var p = CommandParser.init(alloc);
|
var p = Parser.init(alloc);
|
||||||
defer p.deinit();
|
defer p.deinit();
|
||||||
|
|
||||||
const input = "f=24,s=10,v=2000000000000000000000000000000000000000";
|
const input = "f=24,s=10,v=2000000000000000000000000000000000000000";
|
||||||
|
@ -5,23 +5,23 @@ const std = @import("std");
|
|||||||
/// Stack for the key flags. This implements the push/pop behavior
|
/// Stack for the key flags. This implements the push/pop behavior
|
||||||
/// of the CSI > u and CSI < u sequences. We implement the stack as
|
/// of the CSI > u and CSI < u sequences. We implement the stack as
|
||||||
/// fixed size to avoid heap allocation.
|
/// fixed size to avoid heap allocation.
|
||||||
pub const KeyFlagStack = struct {
|
pub const FlagStack = struct {
|
||||||
const len = 8;
|
const len = 8;
|
||||||
|
|
||||||
flags: [len]KeyFlags = .{.{}} ** len,
|
flags: [len]Flags = .{.{}} ** len,
|
||||||
idx: u3 = 0,
|
idx: u3 = 0,
|
||||||
|
|
||||||
/// Return the current stack value
|
/// Return the current stack value
|
||||||
pub fn current(self: KeyFlagStack) KeyFlags {
|
pub fn current(self: FlagStack) Flags {
|
||||||
return self.flags[self.idx];
|
return self.flags[self.idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform the "set" operation as described in the spec for
|
/// Perform the "set" operation as described in the spec for
|
||||||
/// the CSI = u sequence.
|
/// the CSI = u sequence.
|
||||||
pub fn set(
|
pub fn set(
|
||||||
self: *KeyFlagStack,
|
self: *FlagStack,
|
||||||
mode: KeySetMode,
|
mode: SetMode,
|
||||||
v: KeyFlags,
|
v: Flags,
|
||||||
) void {
|
) void {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
.set => self.flags[self.idx] = v,
|
.set => self.flags[self.idx] = v,
|
||||||
@ -36,7 +36,7 @@ pub const KeyFlagStack = struct {
|
|||||||
|
|
||||||
/// Push a new set of flags onto the stack. If the stack is full
|
/// Push a new set of flags onto the stack. If the stack is full
|
||||||
/// then the oldest entry is evicted.
|
/// then the oldest entry is evicted.
|
||||||
pub fn push(self: *KeyFlagStack, flags: KeyFlags) void {
|
pub fn push(self: *FlagStack, flags: Flags) void {
|
||||||
// Overflow and wrap around if we're full, which evicts
|
// Overflow and wrap around if we're full, which evicts
|
||||||
// the oldest entry.
|
// the oldest entry.
|
||||||
self.idx +%= 1;
|
self.idx +%= 1;
|
||||||
@ -45,7 +45,7 @@ pub const KeyFlagStack = struct {
|
|||||||
|
|
||||||
/// Pop `n` entries from the stack. This will just wrap around
|
/// Pop `n` entries from the stack. This will just wrap around
|
||||||
/// if `n` is greater than the amount in the stack.
|
/// if `n` is greater than the amount in the stack.
|
||||||
pub fn pop(self: *KeyFlagStack, n: usize) void {
|
pub fn pop(self: *FlagStack, n: usize) void {
|
||||||
// If n is more than our length then we just reset the stack.
|
// If n is more than our length then we just reset the stack.
|
||||||
// This also avoids a DoS vector where a malicious client
|
// This also avoids a DoS vector where a malicious client
|
||||||
// could send a huge number of pop commands to waste cpu.
|
// could send a huge number of pop commands to waste cpu.
|
||||||
@ -64,7 +64,7 @@ pub const KeyFlagStack = struct {
|
|||||||
// Make sure we the overflow works as expected
|
// Make sure we the overflow works as expected
|
||||||
test {
|
test {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
var stack: KeyFlagStack = .{};
|
var stack: FlagStack = .{};
|
||||||
stack.idx = stack.flags.len - 1;
|
stack.idx = stack.flags.len - 1;
|
||||||
stack.idx +%= 1;
|
stack.idx +%= 1;
|
||||||
try testing.expect(stack.idx == 0);
|
try testing.expect(stack.idx == 0);
|
||||||
@ -76,14 +76,14 @@ pub const KeyFlagStack = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// The possible flags for the Kitty keyboard protocol.
|
/// The possible flags for the Kitty keyboard protocol.
|
||||||
pub const KeyFlags = packed struct(u5) {
|
pub const Flags = packed struct(u5) {
|
||||||
disambiguate: bool = false,
|
disambiguate: bool = false,
|
||||||
report_events: bool = false,
|
report_events: bool = false,
|
||||||
report_alternates: bool = false,
|
report_alternates: bool = false,
|
||||||
report_all: bool = false,
|
report_all: bool = false,
|
||||||
report_associated: bool = false,
|
report_associated: bool = false,
|
||||||
|
|
||||||
pub fn int(self: KeyFlags) u5 {
|
pub fn int(self: Flags) u5 {
|
||||||
return @bitCast(self);
|
return @bitCast(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,50 +93,50 @@ pub const KeyFlags = packed struct(u5) {
|
|||||||
|
|
||||||
try testing.expectEqual(
|
try testing.expectEqual(
|
||||||
@as(u5, 0b1),
|
@as(u5, 0b1),
|
||||||
(KeyFlags{ .disambiguate = true }).int(),
|
(Flags{ .disambiguate = true }).int(),
|
||||||
);
|
);
|
||||||
try testing.expectEqual(
|
try testing.expectEqual(
|
||||||
@as(u5, 0b10),
|
@as(u5, 0b10),
|
||||||
(KeyFlags{ .report_events = true }).int(),
|
(Flags{ .report_events = true }).int(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The possible modes for setting the key flags.
|
/// The possible modes for setting the key flags.
|
||||||
pub const KeySetMode = enum { set, @"or", not };
|
pub const SetMode = enum { set, @"or", not };
|
||||||
|
|
||||||
test "KeyFlagStack: push pop" {
|
test "FlagStack: push pop" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
var stack: KeyFlagStack = .{};
|
var stack: FlagStack = .{};
|
||||||
stack.push(.{ .disambiguate = true });
|
stack.push(.{ .disambiguate = true });
|
||||||
try testing.expectEqual(
|
try testing.expectEqual(
|
||||||
KeyFlags{ .disambiguate = true },
|
Flags{ .disambiguate = true },
|
||||||
stack.current(),
|
stack.current(),
|
||||||
);
|
);
|
||||||
|
|
||||||
stack.pop(1);
|
stack.pop(1);
|
||||||
try testing.expectEqual(KeyFlags{}, stack.current());
|
try testing.expectEqual(Flags{}, stack.current());
|
||||||
}
|
}
|
||||||
|
|
||||||
test "KeyFlagStack: pop big number" {
|
test "FlagStack: pop big number" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
var stack: KeyFlagStack = .{};
|
var stack: FlagStack = .{};
|
||||||
stack.pop(100);
|
stack.pop(100);
|
||||||
try testing.expectEqual(KeyFlags{}, stack.current());
|
try testing.expectEqual(Flags{}, stack.current());
|
||||||
}
|
}
|
||||||
|
|
||||||
test "KeyFlagStack: set" {
|
test "FlagStack: set" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
var stack: KeyFlagStack = .{};
|
var stack: FlagStack = .{};
|
||||||
stack.set(.set, .{ .disambiguate = true });
|
stack.set(.set, .{ .disambiguate = true });
|
||||||
try testing.expectEqual(
|
try testing.expectEqual(
|
||||||
KeyFlags{ .disambiguate = true },
|
Flags{ .disambiguate = true },
|
||||||
stack.current(),
|
stack.current(),
|
||||||
);
|
);
|
||||||
|
|
||||||
stack.set(.@"or", .{ .report_events = true });
|
stack.set(.@"or", .{ .report_events = true });
|
||||||
try testing.expectEqual(
|
try testing.expectEqual(
|
||||||
KeyFlags{
|
Flags{
|
||||||
.disambiguate = true,
|
.disambiguate = true,
|
||||||
.report_events = true,
|
.report_events = true,
|
||||||
},
|
},
|
||||||
@ -145,7 +145,7 @@ test "KeyFlagStack: set" {
|
|||||||
|
|
||||||
stack.set(.not, .{ .report_events = true });
|
stack.set(.not, .{ .report_events = true });
|
||||||
try testing.expectEqual(
|
try testing.expectEqual(
|
||||||
KeyFlags{ .disambiguate = true },
|
Flags{ .disambiguate = true },
|
||||||
stack.current(),
|
stack.current(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
pub usingnamespace @import("sanitize.zig");
|
|
||||||
|
|
||||||
const charsets = @import("charsets.zig");
|
const charsets = @import("charsets.zig");
|
||||||
|
const sanitize = @import("sanitize.zig");
|
||||||
const stream = @import("stream.zig");
|
const stream = @import("stream.zig");
|
||||||
const ansi = @import("ansi.zig");
|
const ansi = @import("ansi.zig");
|
||||||
const csi = @import("csi.zig");
|
const csi = @import("csi.zig");
|
||||||
@ -57,6 +56,8 @@ pub const EraseLine = csi.EraseLine;
|
|||||||
pub const TabClear = csi.TabClear;
|
pub const TabClear = csi.TabClear;
|
||||||
pub const Attribute = sgr.Attribute;
|
pub const Attribute = sgr.Attribute;
|
||||||
|
|
||||||
|
pub const isSafePaste = sanitize.isSafePaste;
|
||||||
|
|
||||||
test {
|
test {
|
||||||
@import("std").testing.refAllDecls(@This());
|
@import("std").testing.refAllDecls(@This());
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
const stream_handler = @import("termio/stream_handler.zig");
|
const stream_handler = @import("termio/stream_handler.zig");
|
||||||
|
|
||||||
pub usingnamespace @import("termio/message.zig");
|
const message = @import("termio/message.zig");
|
||||||
pub const backend = @import("termio/backend.zig");
|
pub const backend = @import("termio/backend.zig");
|
||||||
pub const mailbox = @import("termio/mailbox.zig");
|
pub const mailbox = @import("termio/mailbox.zig");
|
||||||
pub const Exec = @import("termio/Exec.zig");
|
pub const Exec = @import("termio/Exec.zig");
|
||||||
@ -29,6 +29,8 @@ pub const Thread = @import("termio/Thread.zig");
|
|||||||
pub const Backend = backend.Backend;
|
pub const Backend = backend.Backend;
|
||||||
pub const DerivedConfig = Termio.DerivedConfig;
|
pub const DerivedConfig = Termio.DerivedConfig;
|
||||||
pub const Mailbox = mailbox.Mailbox;
|
pub const Mailbox = mailbox.Mailbox;
|
||||||
|
pub const Message = message.Message;
|
||||||
|
pub const MessageData = message.MessageData;
|
||||||
pub const StreamHandler = stream_handler.StreamHandler;
|
pub const StreamHandler = stream_handler.StreamHandler;
|
||||||
|
|
||||||
test {
|
test {
|
||||||
|
Reference in New Issue
Block a user