diff options
| author | Can Celik <ogulcancelik@gmail.com> | 2026-09-10 21:51:57 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-10 21:51:57 +0300 |
| commit | 425c86179791cd32e2d4ce0ae7f269940b4b0663 (patch) | |
| tree | e52c4383a6d69216cbe2a32638bf90841d7e2189 /vendor/libghostty-vt/src/inspector | |
| parent | 90e947a6e26e02f10ec7f1694c4eb5b78a86406b (diff) | |
chore: upgrade libghostty and preserve terminal behavior (#3906)
Diffstat (limited to 'vendor/libghostty-vt/src/inspector')
7 files changed, 104 insertions, 112 deletions
diff --git a/vendor/libghostty-vt/src/inspector/Inspector.zig b/vendor/libghostty-vt/src/inspector/Inspector.zig index 22d763f7..d1dc04f1 100644 --- a/vendor/libghostty-vt/src/inspector/Inspector.zig +++ b/vendor/libghostty-vt/src/inspector/Inspector.zig @@ -92,8 +92,6 @@ pub fn recordKeyEvent( events.deleteOldest(1); try events.append(ev); }, - - else => return err, }; } diff --git a/vendor/libghostty-vt/src/inspector/widgets.zig b/vendor/libghostty-vt/src/inspector/widgets.zig index dd8ebc00..970ca081 100644 --- a/vendor/libghostty-vt/src/inspector/widgets.zig +++ b/vendor/libghostty-vt/src/inspector/widgets.zig @@ -136,92 +136,3 @@ pub const DetachableHeader = struct { return is_open; } }; - -pub const DetachableHeaderState = struct { - show_window: bool = false, - - /// Internal state. Don't touch. - first_show: bool = false, -}; - -/// Render a collapsing header that can be detached into its own window. -/// When detached, renders as a separate window with a close button. -/// When attached, renders as a collapsing header with a pop-out button. -pub fn detachableHeader( - label: [:0]const u8, - state: *DetachableHeaderState, - ctx: anytype, - comptime contentFn: fn (@TypeOf(ctx)) void, -) void { - cimgui.c.ImGui_PushID(label); - defer cimgui.c.ImGui_PopID(); - - if (state.show_window) { - // On first show, dock this window to the right of the parent window's dock. - // We only do this once so the user can freely reposition the window afterward - // without it snapping back to the right on every frame. - if (!state.first_show) { - state.first_show = true; - const current_dock_id = cimgui.c.ImGui_GetWindowDockID(); - if (current_dock_id != 0) { - var dock_id_right: cimgui.c.ImGuiID = 0; - var dock_id_left: cimgui.c.ImGuiID = 0; - _ = cimgui.ImGui_DockBuilderSplitNode( - current_dock_id, - cimgui.c.ImGuiDir_Right, - 0.3, - &dock_id_right, - &dock_id_left, - ); - cimgui.ImGui_DockBuilderDockWindow(label, dock_id_right); - cimgui.ImGui_DockBuilderFinish(current_dock_id); - } - } - - defer cimgui.c.ImGui_End(); - if (cimgui.c.ImGui_Begin( - label, - &state.show_window, - cimgui.c.ImGuiWindowFlags_NoFocusOnAppearing, - )) contentFn(ctx); - return; - } - - // Reset first_show when window is closed so next open docks again - state.first_show = false; - - cimgui.c.ImGui_SetNextItemAllowOverlap(); - const is_open = cimgui.c.ImGui_CollapsingHeader( - label, - cimgui.c.ImGuiTreeNodeFlags_None, - ); - - // Place pop-out button inside the header bar - const header_max = cimgui.c.ImGui_GetItemRectMax(); - const header_min = cimgui.c.ImGui_GetItemRectMin(); - const frame_height = cimgui.c.ImGui_GetFrameHeight(); - const button_size = frame_height - 4; - const padding = 4; - - cimgui.c.ImGui_SameLine(); - cimgui.c.ImGui_SetCursorScreenPos(.{ - .x = header_max.x - button_size - padding, - .y = header_min.y + 2, - }); - cimgui.c.ImGui_PushStyleVarImVec2( - cimgui.c.ImGuiStyleVar_FramePadding, - .{ .x = 0, .y = 0 }, - ); - if (cimgui.c.ImGui_ButtonEx( - ">>##detach", - .{ .x = button_size, .y = button_size }, - )) { - state.show_window = true; - } - cimgui.c.ImGui_PopStyleVar(); - if (cimgui.c.ImGui_IsItemHovered(cimgui.c.ImGuiHoveredFlags_DelayShort)) { - cimgui.c.ImGui_SetTooltip("Pop out into separate window"); - } - - if (is_open) contentFn(ctx); -} diff --git a/vendor/libghostty-vt/src/inspector/widgets/key.zig b/vendor/libghostty-vt/src/inspector/widgets/key.zig index 7d7188a6..2a3f531e 100644 --- a/vendor/libghostty-vt/src/inspector/widgets/key.zig +++ b/vendor/libghostty-vt/src/inspector/widgets/key.zig @@ -232,8 +232,7 @@ fn modsTooltip( mods: *const input.Mods, buf: []u8, ) ![:0]const u8 { - var stream = std.io.fixedBufferStream(buf); - const writer = stream.writer(); + var writer: std.Io.Writer = .fixed(buf); var first = true; if (mods.shift) { try writer.writeAll("Shift"); @@ -254,7 +253,7 @@ fn modsTooltip( try writer.writeAll("Super"); } try writer.writeByte(0); - const written = stream.getWritten(); + const written = writer.buffered(); return written[0 .. written.len - 1 :0]; } @@ -403,8 +402,7 @@ pub const Stream = struct { cimgui.c.ImGui_TextDisabled("-"); } else { var utf8_buf: [128]u8 = undefined; - var utf8_stream = std.io.fixedBufferStream(&utf8_buf); - const utf8_writer = utf8_stream.writer(); + var utf8_writer: std.Io.Writer = .fixed(&utf8_buf); if (std.unicode.Utf8View.init(ev.event.utf8)) |view| { var utf8_it = view.iterator(); while (utf8_it.nextCodepoint()) |cp| { @@ -423,8 +421,7 @@ pub const Stream = struct { cimgui.c.ImGui_TextDisabled("-"); } else { var pty_buf: [256]u8 = undefined; - var pty_stream = std.io.fixedBufferStream(&pty_buf); - const pty_writer = pty_stream.writer(); + var pty_writer: std.Io.Writer = .fixed(&pty_buf); for (ev.pty) |byte| { if (byte == 0x1B) { pty_writer.writeAll("ESC ") catch break; @@ -444,8 +441,7 @@ pub const Stream = struct { cimgui.c.ImGui_TextDisabled("-"); } else { var binding_buf: [256]u8 = undefined; - var binding_stream = std.io.fixedBufferStream(&binding_buf); - const binding_writer = binding_stream.writer(); + var binding_writer: std.Io.Writer = .fixed(&binding_buf); for (ev.binding, 0..) |action, i| { if (i > 0) binding_writer.writeAll(", ") catch break; binding_writer.writeAll(@tagName(action)) catch break; diff --git a/vendor/libghostty-vt/src/inspector/widgets/pagelist.zig b/vendor/libghostty-vt/src/inspector/widgets/pagelist.zig index 7e001289..2aecafd3 100644 --- a/vendor/libghostty-vt/src/inspector/widgets/pagelist.zig +++ b/vendor/libghostty-vt/src/inspector/widgets/pagelist.zig @@ -162,7 +162,7 @@ fn summaryTable(pages: *const PageList) void { ); _ = cimgui.c.ImGui_TableSetColumnIndex(2); var limit_buf: [64]u8 = undefined; - const limit = formatBytes(&limit_buf, pages.maxSize()); + const limit = formatBytes(&limit_buf, pages.limits.max(.bytes)); cimgui.c.ImGui_TextUnformatted(limit.ptr); cimgui.c.ImGui_TableNextRow(); diff --git a/vendor/libghostty-vt/src/inspector/widgets/screen.zig b/vendor/libghostty-vt/src/inspector/widgets/screen.zig index 41c113e7..6e66a142 100644 --- a/vendor/libghostty-vt/src/inspector/widgets/screen.zig +++ b/vendor/libghostty-vt/src/inspector/widgets/screen.zig @@ -353,7 +353,12 @@ pub fn internalStateTable( _ = cimgui.c.ImGui_TableSetColumnIndex(0); cimgui.c.ImGui_Text("Memory Limit"); _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_Text("%d bytes (%d KiB)", pages.maxSize(), units.toKibiBytes(pages.maxSize())); + const max_bytes = pages.limits.max(.bytes); + cimgui.c.ImGui_Text( + "%d bytes (%d KiB)", + max_bytes, + units.toKibiBytes(max_bytes), + ); cimgui.c.ImGui_TableNextRow(); _ = cimgui.c.ImGui_TableSetColumnIndex(0); diff --git a/vendor/libghostty-vt/src/inspector/widgets/surface.zig b/vendor/libghostty-vt/src/inspector/widgets/surface.zig index a630bad8..a23aebf0 100644 --- a/vendor/libghostty-vt/src/inspector/widgets/surface.zig +++ b/vendor/libghostty-vt/src/inspector/widgets/surface.zig @@ -9,6 +9,7 @@ const input = @import("../../input.zig"); const renderer = @import("../../renderer.zig"); const terminal = @import("../../terminal/main.zig"); const Surface = @import("../../Surface.zig"); +const global = @import("../../global.zig"); /// This is discovered via the hardcoded string in the ImGui demo window. const window_imgui_demo = "Dear ImGui Demo"; @@ -46,7 +47,7 @@ pub const Inspector = struct { pub fn draw( self: *Inspector, - surface: *const Surface, + surface: *Surface, mouse: Mouse, ) void { // Create our dockspace first. If we had to setup our dockspace, @@ -56,8 +57,8 @@ pub const Inspector = struct { // Draw everything that requires the terminal state mutex. { - surface.renderer_state.mutex.lock(); - defer surface.renderer_state.mutex.unlock(); + surface.renderer_state.mutex.lockUncancelable(global.io()); + defer surface.renderer_state.mutex.unlock(global.io()); const t = surface.renderer_state.terminal; // Terminal info window @@ -110,7 +111,7 @@ pub const Inspector = struct { defer cimgui.c.ImGui_End(); if (open) { self.vt_stream.draw( - surface.alloc, + surface, &t.colors.palette.current, ); } @@ -442,7 +443,7 @@ fn mouseTable( if (state != .press) continue; const button: input.MouseButton = @enumFromInt(i); cimgui.c.ImGui_SameLine(); - cimgui.c.ImGui_Text("%s", (switch (button) { + cimgui.c.ImGui_Text("%s", @as([*]const u8, @ptrCast(switch (button) { .unknown => "?", .left => "L", .middle => "M", @@ -455,7 +456,7 @@ fn mouseTable( .nine => "{9}", .ten => "{10}", .eleven => "{11}", - }).ptr); + }))); } } } diff --git a/vendor/libghostty-vt/src/inspector/widgets/termio.zig b/vendor/libghostty-vt/src/inspector/widgets/termio.zig index b721d942..2c94b1bf 100644 --- a/vendor/libghostty-vt/src/inspector/widgets/termio.zig +++ b/vendor/libghostty-vt/src/inspector/widgets/termio.zig @@ -7,6 +7,8 @@ const CircBuf = @import("../../datastruct/main.zig").CircBuf; const Surface = @import("../../Surface.zig"); const screen = @import("screen.zig"); +const log = std.log.scoped(.inspector_terminal_io); + /// VT event stream inspector widget. pub const Stream = struct { events: VTEvent.Ring, @@ -30,7 +32,10 @@ pub const Stream = struct { return .{ .events = events, - .parser_stream = .initAlloc(alloc, handler), + .parser_stream = .init(.{ + .allocator = alloc, + .handler = handler, + }), }; } @@ -59,9 +64,10 @@ pub const Stream = struct { pub fn draw( self: *Stream, - alloc: Allocator, + surface: *Surface, palette: *const terminal.color.Palette, ) void { + const alloc = surface.alloc; const events = &self.events; const handler = &self.parser_stream.handler; const popup_filter = "Filter"; @@ -93,6 +99,16 @@ pub const Stream = struct { handler.current_seq = 1; } + + cimgui.c.ImGui_SameLineEx(0, cimgui.c.ImGui_GetStyle().*.ItemInnerSpacing.x); + if (cimgui.c.ImGui_Button("Copy")) { + self.copyEvents(surface); + } + + cimgui.c.ImGui_SameLineEx(0, cimgui.c.ImGui_GetStyle().*.ItemInnerSpacing.x); + if (cimgui.c.ImGui_Button("Export to file")) { + self.exportEvents(surface); + } } } @@ -330,6 +346,73 @@ pub const Stream = struct { } } // filter popup } + + /// Copy all recorded events to the standard clipboard in chronological + /// order. + fn copyEvents( + self: *const Stream, + surface: *Surface, + ) void { + const alloc = surface.alloc; + const contents = self.formatEvents(alloc) catch |err| { + log.err("failed to format terminal IO events for copy err={}", .{err}); + return; + }; + defer alloc.free(contents); + + surface.rt_surface.setClipboard(.standard, &.{.{ + .mime = "text/plain", + .data = contents, + }}, false) catch |err| { + log.err("failed to copy terminal IO events err={}", .{err}); + }; + } + + /// Ask the application runtime to save all recorded events to a file. + fn exportEvents( + self: *const Stream, + surface: *Surface, + ) void { + const alloc = surface.alloc; + const contents = self.formatEvents(alloc) catch |err| { + log.err("failed to format terminal IO events for export err={}", .{err}); + return; + }; + defer alloc.free(contents); + + const handled = surface.rt_app.performAction( + .{ .surface = surface }, + .export_terminal_io, + .{ .contents = contents }, + ) catch |err| { + log.err("failed to export terminal IO events err={}", .{err}); + return; + }; + if (!handled) { + log.warn("application runtime does not support exporting terminal IO events", .{}); + } + } + + /// Format all recorded events as tab-separated text. Events are exported + /// oldest-first even though the inspector displays the newest event first. + fn formatEvents( + self: *const Stream, + alloc: Allocator, + ) ![:0]u8 { + var buf: std.Io.Writer.Allocating = .init(alloc); + errdefer buf.deinit(); + + try buf.writer.writeAll("Seq\tKind\tDescription\n"); + var it = self.events.iterator(.forward); + while (it.next()) |ev| { + try buf.writer.print( + "{d}\t{s}\t{s}\n", + .{ ev.seq, @tagName(ev.kind), ev.raw_description }, + ); + } + + return try buf.toOwnedSliceSentinel(0); + } }; /// Helper function to check keyboard state and determine navigation action. @@ -793,8 +876,6 @@ const VTHandler = struct { vt_events.deleteOldest(1); try vt_events.append(ev); }, - - else => return err, }; // Do NOT skip it, because we want to record more information |
