aboutsummaryrefslogtreecommitdiff
path: root/vendor/libghostty-vt/src/inspector/Inspector.zig
diff options
context:
space:
mode:
authorCan Celik <ogulcancelik@gmail.com>2026-04-04 19:22:04 +0300
committerCan Celik <ogulcancelik@gmail.com>2026-04-05 01:23:06 +0300
commit41dd733ca7123c9ac4bfc6c781697a660e95b052 (patch)
tree3fc91815ca139ef2e0b281bba0abda4ef15175f4 /vendor/libghostty-vt/src/inspector/Inspector.zig
parent55c138263e190a1e79d4b997bfb9397306c0ec1f (diff)
feat: finish ghostty pane backend integration
Diffstat (limited to 'vendor/libghostty-vt/src/inspector/Inspector.zig')
-rw-r--r--vendor/libghostty-vt/src/inspector/Inspector.zig131
1 files changed, 131 insertions, 0 deletions
diff --git a/vendor/libghostty-vt/src/inspector/Inspector.zig b/vendor/libghostty-vt/src/inspector/Inspector.zig
new file mode 100644
index 00000000..22d763f7
--- /dev/null
+++ b/vendor/libghostty-vt/src/inspector/Inspector.zig
@@ -0,0 +1,131 @@
+//! The Inspector is a development tool to debug the terminal. This is
+//! useful for terminal application developers as well as people potentially
+//! debugging issues in Ghostty itself.
+const Inspector = @This();
+
+const std = @import("std");
+const assert = @import("../quirks.zig").inlineAssert;
+const Allocator = std.mem.Allocator;
+const builtin = @import("builtin");
+const cimgui = @import("dcimgui");
+const Surface = @import("../Surface.zig");
+const font = @import("../font/main.zig");
+const terminal = @import("../terminal/main.zig");
+const inspector = @import("main.zig");
+const widgets = @import("widgets.zig");
+
+/// Mouse state that we track in addition to normal mouse states that
+/// Ghostty always knows about.
+mouse: widgets.surface.Mouse = .{},
+
+// ImGui state
+gui: widgets.surface.Inspector,
+
+/// Setup the ImGui state. This requires an ImGui context to be set.
+pub fn setup() void {
+ const io: *cimgui.c.ImGuiIO = cimgui.c.ImGui_GetIO();
+
+ // Enable docking, which we use heavily for the UI.
+ io.ConfigFlags |= cimgui.c.ImGuiConfigFlags_DockingEnable;
+
+ // Our colorspace is sRGB.
+ io.ConfigFlags |= cimgui.c.ImGuiConfigFlags_IsSRGB;
+
+ // Disable the ini file to save layout
+ io.IniFilename = null;
+ io.LogFilename = null;
+
+ // Use our own embedded font
+ {
+ // TODO: This will have to be recalculated for different screen DPIs.
+ // This is currently hardcoded to a 2x content scale.
+ const font_size = 16 * 2;
+
+ var font_config: cimgui.c.ImFontConfig = undefined;
+ cimgui.ext.ImFontConfig_ImFontConfig(&font_config);
+ font_config.FontDataOwnedByAtlas = false;
+ _ = cimgui.c.ImFontAtlas_AddFontFromMemoryTTF(
+ io.Fonts,
+ @ptrCast(@constCast(font.embedded.regular.ptr)),
+ @intCast(font.embedded.regular.len),
+ font_size,
+ &font_config,
+ null,
+ );
+ }
+}
+
+pub fn init(alloc: Allocator) !Inspector {
+ var gui: widgets.surface.Inspector = try .init(alloc);
+ errdefer gui.deinit(alloc);
+ return .{ .gui = gui };
+}
+
+pub fn deinit(self: *Inspector, alloc: Allocator) void {
+ self.gui.deinit(alloc);
+}
+
+/// Returns the renderer info panel. This is a convenience function
+/// to access and find this state to read and modify.
+pub fn rendererInfo(self: *Inspector) *widgets.renderer.Info {
+ return &self.gui.renderer_info;
+}
+
+/// Record a keyboard event.
+pub fn recordKeyEvent(
+ self: *Inspector,
+ alloc: Allocator,
+ ev: inspector.KeyEvent,
+) Allocator.Error!void {
+ const max_capacity = 50;
+
+ const events: *widgets.key.EventRing = &self.gui.key_stream.events;
+ events.append(ev) catch |err| switch (err) {
+ error.OutOfMemory => if (events.capacity() < max_capacity) {
+ // We're out of memory, but we can allocate to our capacity.
+ const new_capacity = @min(events.capacity() * 2, max_capacity);
+ try events.resize(alloc, new_capacity);
+ try events.append(ev);
+ } else {
+ var it = events.iterator(.forward);
+ if (it.next()) |old_ev| old_ev.deinit(alloc);
+ events.deleteOldest(1);
+ try events.append(ev);
+ },
+
+ else => return err,
+ };
+}
+
+/// Record data read from the pty.
+pub fn recordPtyRead(
+ self: *Inspector,
+ alloc: Allocator,
+ t: *terminal.Terminal,
+ data: []const u8,
+) !void {
+ try self.gui.vt_stream.recordPtyRead(
+ alloc,
+ t,
+ data,
+ );
+}
+
+/// Render the frame.
+pub fn render(
+ self: *Inspector,
+ surface: *Surface,
+) void {
+ // Draw the UI
+ self.gui.draw(
+ surface,
+ self.mouse,
+ );
+
+ // We always trigger a rebuild of the surface when the inspector
+ // is focused because modifying the inspector can change the terminal
+ // state. This is KIND OF expensive (wasted CPU if nothing was done)
+ // but the inspector is a development tool and it expressly costs
+ // more resources while open so its okay.
+ surface.renderer_thread.wakeup.notify() catch {};
+}