From 400d17aa0d00eea65cb4cb65ffe4fb660deb4947 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 30 Jan 2026 09:18:31 -0800 Subject: [PATCH] inspector: remove cell picker --- src/Surface.zig | 30 +---- src/inspector/Inspector.zig | 127 -------------------- src/inspector/cell.zig | 223 ------------------------------------ src/inspector/main.zig | 4 - 4 files changed, 1 insertion(+), 383 deletions(-) delete mode 100644 src/inspector/cell.zig diff --git a/src/Surface.zig b/src/Surface.zig index fc1e55ec5..fa9b04685 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -3874,36 +3874,8 @@ pub fn mouseButtonCallback( // log.debug("mouse action={} button={} mods={}", .{ action, button, mods }); // If we have an inspector, we always queue a render - if (self.inspector) |insp| { + if (self.inspector != null) { defer self.queueRender() catch {}; - - self.renderer_state.mutex.lock(); - defer self.renderer_state.mutex.unlock(); - - // If the inspector is requesting a cell, then we intercept - // left mouse clicks and send them to the inspector. - if (insp.cell == .requested and - button == .left and - action == .press) - { - const pos = try self.rt_surface.getCursorPos(); - const point = self.posToViewport(pos.x, pos.y); - const screen: *terminal.Screen = self.renderer_state.terminal.screens.active; - const p = screen.pages.pin(.{ .viewport = point }) orelse { - log.warn("failed to get pin for clicked point", .{}); - return false; - }; - - insp.cell.select( - self.alloc, - p, - point.x, - point.y, - ) catch |err| { - log.warn("error selecting cell for inspector err={}", .{err}); - }; - return false; - } } // Always record our latest mouse state diff --git a/src/inspector/Inspector.zig b/src/inspector/Inspector.zig index 8462a588a..6035e8c2b 100644 --- a/src/inspector/Inspector.zig +++ b/src/inspector/Inspector.zig @@ -14,76 +14,13 @@ const terminal = @import("../terminal/main.zig"); const inspector = @import("main.zig"); const widgets = @import("widgets.zig"); -/// The window names. These are used with docking so we need to have access. -const window_cell = "Cell"; -const window_termio = "Terminal IO"; -const window_imgui_demo = "Dear ImGui Demo"; - /// Mouse state that we track in addition to normal mouse states that /// Ghostty always knows about. mouse: widgets.surface.Mouse = .{}, -/// A selected cell. -cell: CellInspect = .{ .idle = {} }, - // ImGui state gui: widgets.surface.Inspector, -const CellInspect = union(enum) { - /// Idle, no cell inspection is requested - idle: void, - - /// Requested, a cell is being picked. - requested: void, - - /// The cell has been picked and set to this. This is a copy so that - /// if the cell contents change we still have the original cell. - selected: Selected, - - const Selected = struct { - alloc: Allocator, - row: usize, - col: usize, - cell: inspector.Cell, - }; - - pub fn deinit(self: *CellInspect) void { - switch (self.*) { - .idle, .requested => {}, - .selected => |*v| v.cell.deinit(v.alloc), - } - } - - pub fn request(self: *CellInspect) void { - switch (self.*) { - .idle => self.* = .requested, - .selected => |*v| { - v.cell.deinit(v.alloc); - self.* = .requested; - }, - .requested => {}, - } - } - - pub fn select( - self: *CellInspect, - alloc: Allocator, - pin: terminal.Pin, - x: usize, - y: usize, - ) !void { - assert(self.* == .requested); - const cell = try inspector.Cell.init(alloc, pin); - errdefer cell.deinit(alloc); - self.* = .{ .selected = .{ - .alloc = alloc, - .row = y, - .col = x, - .cell = cell, - } }; - } -}; - /// 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(); @@ -126,7 +63,6 @@ pub fn init(alloc: Allocator) !Inspector { pub fn deinit(self: *Inspector, alloc: Allocator) void { self.gui.deinit(alloc); - self.cell.deinit(); } /// Record a keyboard event. @@ -179,66 +115,3 @@ pub fn render( self.mouse, ); } - -/// TODO: OLD, REMOVE EVENTUALLY ONCE WE MIGRATE FUNCTIONALITY -fn renderCellWindow(self: *Inspector) void { - // Start our window. If we're collapsed we do nothing. - defer cimgui.c.ImGui_End(); - if (!cimgui.c.ImGui_Begin( - window_cell, - null, - cimgui.c.ImGuiWindowFlags_NoFocusOnAppearing, - )) return; - - // Our popup for the picker - const popup_picker = "Cell Picker"; - - if (cimgui.c.ImGui_Button("Picker")) { - // Request a cell - self.cell.request(); - - cimgui.c.ImGui_OpenPopup( - popup_picker, - cimgui.c.ImGuiPopupFlags_None, - ); - } - - if (cimgui.c.ImGui_BeginPopupModal( - popup_picker, - null, - cimgui.c.ImGuiWindowFlags_AlwaysAutoResize, - )) popup: { - defer cimgui.c.ImGui_EndPopup(); - - // Once we select a cell, close this popup. - if (self.cell == .selected) { - cimgui.c.ImGui_CloseCurrentPopup(); - break :popup; - } - - cimgui.c.ImGui_Text( - "Click on a cell in the terminal to inspect it.\n" ++ - "The click will be intercepted by the picker, \n" ++ - "so it won't be sent to the terminal.", - ); - cimgui.c.ImGui_Separator(); - - if (cimgui.c.ImGui_Button("Cancel")) { - cimgui.c.ImGui_CloseCurrentPopup(); - } - } // cell pick popup - - cimgui.c.ImGui_Separator(); - - if (self.cell != .selected) { - cimgui.c.ImGui_Text("No cell selected."); - return; - } - - const selected = self.cell.selected; - selected.cell.renderTable( - self.surface.renderer_state.terminal, - selected.col, - selected.row, - ); -} diff --git a/src/inspector/cell.zig b/src/inspector/cell.zig deleted file mode 100644 index 540e044fd..000000000 --- a/src/inspector/cell.zig +++ /dev/null @@ -1,223 +0,0 @@ -const std = @import("std"); -const assert = @import("../quirks.zig").inlineAssert; -const Allocator = std.mem.Allocator; -const cimgui = @import("dcimgui"); -const terminal = @import("../terminal/main.zig"); - -/// A cell being inspected. This duplicates much of the data in -/// the terminal data structure because we want the inspector to -/// not have a reference to the terminal state or to grab any -/// locks. -pub const Cell = struct { - /// The main codepoint for this cell. - codepoint: u21, - - /// Codepoints for this cell to produce a single grapheme cluster. - /// This is only non-empty if the cell is part of a multi-codepoint - /// grapheme cluster. This does NOT include the primary codepoint. - cps: []const u21, - - /// The style of this cell. - style: terminal.Style, - - /// Wide state of the terminal cell - wide: terminal.Cell.Wide, - - pub fn init( - alloc: Allocator, - pin: terminal.Pin, - ) !Cell { - const cell = pin.rowAndCell().cell; - const style = pin.style(cell); - const cps: []const u21 = if (cell.hasGrapheme()) cps: { - const src = pin.grapheme(cell).?; - assert(src.len > 0); - break :cps try alloc.dupe(u21, src); - } else &.{}; - errdefer if (cps.len > 0) alloc.free(cps); - - return .{ - .codepoint = cell.codepoint(), - .cps = cps, - .style = style, - .wide = cell.wide, - }; - } - - pub fn deinit(self: *Cell, alloc: Allocator) void { - if (self.cps.len > 0) alloc.free(self.cps); - } - - pub fn renderTable( - self: *const Cell, - t: *const terminal.Terminal, - x: usize, - y: usize, - ) void { - // We have a selected cell, show information about it. - _ = cimgui.c.ImGui_BeginTable( - "table_cursor", - 2, - cimgui.c.ImGuiTableFlags_None, - ); - defer cimgui.c.ImGui_EndTable(); - - { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Grid Position"); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_Text("row=%d col=%d", y, x); - } - } - - // NOTE: we don't currently write the character itself because - // we haven't hooked up imgui to our font system. That's hard! We - // can/should instead hook up our renderer to imgui and just render - // the single glyph in an image view so it looks _identical_ to the - // terminal. - codepoint: { - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Codepoints"); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - if (cimgui.c.ImGui_BeginListBox("##codepoints", .{ .x = 0, .y = 0 })) { - defer cimgui.c.ImGui_EndListBox(); - - if (self.codepoint == 0) { - _ = cimgui.c.ImGui_SelectableEx("(empty)", false, 0, .{}); - break :codepoint; - } - - // Primary codepoint - var buf: [256]u8 = undefined; - { - const key = std.fmt.bufPrintZ(&buf, "U+{X}", .{self.codepoint}) catch - ""; - _ = cimgui.c.ImGui_SelectableEx(key.ptr, false, 0, .{}); - } - - // All extras - for (self.cps) |cp| { - const key = std.fmt.bufPrintZ(&buf, "U+{X}", .{cp}) catch - ""; - _ = cimgui.c.ImGui_SelectableEx(key.ptr, false, 0, .{}); - } - } - } - } - - // Character width property - cimgui.c.ImGui_TableNextRow(); - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Width Property"); - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_Text(@tagName(self.wide)); - - // If we have a color then we show the color - cimgui.c.ImGui_TableNextRow(); - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Foreground Color"); - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - switch (self.style.fg_color) { - .none => cimgui.c.ImGui_Text("default"), - .palette => |idx| { - const rgb = t.colors.palette.current[idx]; - cimgui.c.ImGui_Text("Palette %d", idx); - var color: [3]f32 = .{ - @as(f32, @floatFromInt(rgb.r)) / 255, - @as(f32, @floatFromInt(rgb.g)) / 255, - @as(f32, @floatFromInt(rgb.b)) / 255, - }; - _ = cimgui.c.ImGui_ColorEdit3( - "color_fg", - &color, - cimgui.c.ImGuiColorEditFlags_DisplayHex | - cimgui.c.ImGuiColorEditFlags_NoPicker | - cimgui.c.ImGuiColorEditFlags_NoLabel, - ); - }, - - .rgb => |rgb| { - var color: [3]f32 = .{ - @as(f32, @floatFromInt(rgb.r)) / 255, - @as(f32, @floatFromInt(rgb.g)) / 255, - @as(f32, @floatFromInt(rgb.b)) / 255, - }; - _ = cimgui.c.ImGui_ColorEdit3( - "color_fg", - &color, - cimgui.c.ImGuiColorEditFlags_DisplayHex | - cimgui.c.ImGuiColorEditFlags_NoPicker | - cimgui.c.ImGuiColorEditFlags_NoLabel, - ); - }, - } - - cimgui.c.ImGui_TableNextRow(); - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text("Background Color"); - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - switch (self.style.bg_color) { - .none => cimgui.c.ImGui_Text("default"), - .palette => |idx| { - const rgb = t.colors.palette.current[idx]; - cimgui.c.ImGui_Text("Palette %d", idx); - var color: [3]f32 = .{ - @as(f32, @floatFromInt(rgb.r)) / 255, - @as(f32, @floatFromInt(rgb.g)) / 255, - @as(f32, @floatFromInt(rgb.b)) / 255, - }; - _ = cimgui.c.ImGui_ColorEdit3( - "color_bg", - &color, - cimgui.c.ImGuiColorEditFlags_DisplayHex | - cimgui.c.ImGuiColorEditFlags_NoPicker | - cimgui.c.ImGuiColorEditFlags_NoLabel, - ); - }, - - .rgb => |rgb| { - var color: [3]f32 = .{ - @as(f32, @floatFromInt(rgb.r)) / 255, - @as(f32, @floatFromInt(rgb.g)) / 255, - @as(f32, @floatFromInt(rgb.b)) / 255, - }; - _ = cimgui.c.ImGui_ColorEdit3( - "color_bg", - &color, - cimgui.c.ImGuiColorEditFlags_DisplayHex | - cimgui.c.ImGuiColorEditFlags_NoPicker | - cimgui.c.ImGuiColorEditFlags_NoLabel, - ); - }, - } - - // Boolean styles - const styles = .{ - "bold", "italic", "faint", "blink", - "inverse", "invisible", "strikethrough", - }; - inline for (styles) |style| style: { - if (!@field(self.style.flags, style)) break :style; - - cimgui.c.ImGui_TableNextRow(); - { - _ = cimgui.c.ImGui_TableSetColumnIndex(0); - cimgui.c.ImGui_Text(style.ptr); - } - { - _ = cimgui.c.ImGui_TableSetColumnIndex(1); - cimgui.c.ImGui_Text("true"); - } - } - - cimgui.c.ImGui_TextDisabled("(Any styles not shown are not currently set)"); - } -}; diff --git a/src/inspector/main.zig b/src/inspector/main.zig index 05e6e4ba2..ae185f479 100644 --- a/src/inspector/main.zig +++ b/src/inspector/main.zig @@ -1,7 +1,3 @@ -// TODO: Remove -pub const cell = @import("cell.zig"); -pub const Cell = cell.Cell; - pub const widgets = @import("widgets.zig"); pub const Inspector = @import("Inspector.zig");