mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-06-02 09:58:09 +00:00
132 lines
4.0 KiB
Zig
132 lines
4.0 KiB
Zig
//! 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 {};
|
|
}
|