mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 00:36:07 +03:00
terminal/PageList: add method for logging debug diagrams
This commit is contained in:
@ -2548,6 +2548,213 @@ pub fn getCell(self: *const PageList, pt: point.Point) ?Cell {
|
||||
};
|
||||
}
|
||||
|
||||
/// Log a debug diagram of the page list to the provided writer.
|
||||
///
|
||||
/// EXAMPLE:
|
||||
///
|
||||
/// +-----+ = PAGE 0
|
||||
/// ... | |
|
||||
/// 50 | foo |
|
||||
/// ... | |
|
||||
/// +--------+ ACTIVE
|
||||
/// 124 | | | 0
|
||||
/// 125 |Text | | 1
|
||||
/// : ^ : : = PIN 0
|
||||
/// 126 |Wrapp… | 2
|
||||
/// +-----+ :
|
||||
/// +-----+ : = PAGE 1
|
||||
/// 0 …ed | | 3
|
||||
/// 1 | etc.| | 4
|
||||
/// +-----+ :
|
||||
/// +--------+
|
||||
pub fn diagram(self: *const PageList, writer: anytype) !void {
|
||||
const active_pin = self.getTopLeft(.active);
|
||||
|
||||
var active = false;
|
||||
var active_index: usize = 0;
|
||||
|
||||
var page_index: usize = 0;
|
||||
var cols: usize = 0;
|
||||
|
||||
var it = self.pageIterator(.right_down, .{ .screen = .{} }, null);
|
||||
while (it.next()) |chunk| : (page_index += 1) {
|
||||
cols = chunk.page.data.size.cols;
|
||||
|
||||
// Whether we've just skipped some number of rows and drawn
|
||||
// an ellipsis row (this is reset when a row is not skipped).
|
||||
var skipped = false;
|
||||
|
||||
for (0..chunk.page.data.size.rows) |y| {
|
||||
// Active header
|
||||
if (!active and
|
||||
chunk.page == active_pin.page and
|
||||
active_pin.y == y)
|
||||
{
|
||||
active = true;
|
||||
try writer.writeAll(" +-");
|
||||
try writer.writeByteNTimes('-', cols);
|
||||
try writer.writeAll("--+ ACTIVE");
|
||||
try writer.writeByte('\n');
|
||||
}
|
||||
|
||||
// Page header
|
||||
if (y == 0) {
|
||||
try writer.writeAll(" +");
|
||||
try writer.writeByteNTimes('-', cols);
|
||||
try writer.writeByte('+');
|
||||
if (active) try writer.writeAll(" :");
|
||||
try writer.print(" = PAGE {}", .{page_index});
|
||||
try writer.writeByte('\n');
|
||||
}
|
||||
|
||||
// Row contents
|
||||
{
|
||||
const row = chunk.page.data.getRow(y);
|
||||
const cells = chunk.page.data.getCells(row)[0..cols];
|
||||
|
||||
var row_has_content = false;
|
||||
|
||||
for (cells) |cell| {
|
||||
if (cell.hasText()) {
|
||||
row_has_content = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We don't want to print this row's contents
|
||||
// unless it has text or is in the active area.
|
||||
if (!active and !row_has_content) {
|
||||
// If we haven't, draw an ellipsis row.
|
||||
if (!skipped) {
|
||||
try writer.writeAll(" ... :");
|
||||
try writer.writeByteNTimes(' ', cols);
|
||||
try writer.writeByte(':');
|
||||
if (active) try writer.writeAll(" :");
|
||||
try writer.writeByte('\n');
|
||||
}
|
||||
skipped = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
skipped = false;
|
||||
|
||||
// Left pad row number to 5 wide
|
||||
const y_digits = if (y == 0) 0 else std.math.log10_int(y);
|
||||
try writer.writeByteNTimes(' ', 4 - y_digits);
|
||||
try writer.print("{} ", .{y});
|
||||
|
||||
// Left edge or wrap continuation marker
|
||||
try writer.writeAll(if (row.wrap_continuation) "…" else "|");
|
||||
|
||||
// Row text
|
||||
if (row_has_content) {
|
||||
for (cells) |*cell| {
|
||||
// Skip spacer tails, since wide cells are, well, wide.
|
||||
if (cell.wide == .spacer_tail) continue;
|
||||
|
||||
// Write non-printing bytes as base36, for convenience.
|
||||
if (cell.codepoint() < ' ') {
|
||||
try writer.writeByte("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[cell.codepoint()]);
|
||||
continue;
|
||||
}
|
||||
try writer.print("{u}", .{cell.codepoint()});
|
||||
if (cell.hasGrapheme()) {
|
||||
const grapheme = chunk.page.data.lookupGrapheme(cell).?;
|
||||
for (grapheme) |cp| {
|
||||
try writer.print("{u}", .{cp});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try writer.writeByteNTimes(' ', cols);
|
||||
}
|
||||
|
||||
// Right edge or wrap marker
|
||||
try writer.writeAll(if (row.wrap) "…" else "|");
|
||||
if (active) {
|
||||
try writer.print(" | {}", .{active_index});
|
||||
active_index += 1;
|
||||
}
|
||||
|
||||
try writer.writeByte('\n');
|
||||
}
|
||||
|
||||
// Tracked pin marker(s)
|
||||
pins: {
|
||||
// If we have more than 16 tracked pins in a row, oh well,
|
||||
// don't wanna bother making this function allocating.
|
||||
var pin_buf: [16]*Pin = undefined;
|
||||
var pin_count: usize = 0;
|
||||
var pin_it = self.tracked_pins.keyIterator();
|
||||
while (pin_it.next()) |p_ptr| {
|
||||
const p = p_ptr.*;
|
||||
if (p.page != chunk.page) continue;
|
||||
if (p.y != y) continue;
|
||||
pin_buf[pin_count] = p;
|
||||
pin_count += 1;
|
||||
if (pin_count >= pin_buf.len) return error.TooManyTrackedPinsInRow;
|
||||
}
|
||||
|
||||
if (pin_count == 0) break :pins;
|
||||
|
||||
const pins = pin_buf[0..pin_count];
|
||||
std.mem.sort(
|
||||
*Pin,
|
||||
pins,
|
||||
{},
|
||||
struct {
|
||||
fn lt(_: void, a: *Pin, b: *Pin) bool {
|
||||
return a.x < b.x;
|
||||
}
|
||||
}.lt,
|
||||
);
|
||||
|
||||
try writer.writeAll(" :");
|
||||
var x: usize = 0;
|
||||
|
||||
for (pins) |p| {
|
||||
if (x > p.x) continue;
|
||||
try writer.writeByteNTimes(' ', p.x - x);
|
||||
try writer.writeByte('^');
|
||||
x = p.x + 1;
|
||||
}
|
||||
|
||||
try writer.writeByteNTimes(' ', cols - x);
|
||||
try writer.writeByte(':');
|
||||
|
||||
if (active) try writer.writeAll(" :");
|
||||
|
||||
try writer.print(" = PIN{s}", .{if (pin_count > 1) "S" else ""});
|
||||
|
||||
x = pins[0].x;
|
||||
for (pins, 0..) |p, i| {
|
||||
if (p.x != x) try writer.writeByte(',');
|
||||
try writer.print(" {}", .{i});
|
||||
}
|
||||
|
||||
try writer.writeByte('\n');
|
||||
}
|
||||
}
|
||||
|
||||
// Page footer
|
||||
{
|
||||
try writer.writeAll(" +");
|
||||
try writer.writeByteNTimes('-', cols);
|
||||
try writer.writeByte('+');
|
||||
if (active) try writer.writeAll(" :");
|
||||
try writer.writeByte('\n');
|
||||
}
|
||||
}
|
||||
|
||||
// Active footer
|
||||
{
|
||||
try writer.writeAll(" +-");
|
||||
try writer.writeByteNTimes('-', cols);
|
||||
try writer.writeAll("--+");
|
||||
try writer.writeByte('\n');
|
||||
}
|
||||
}
|
||||
|
||||
/// Direction that iterators can move.
|
||||
pub const Direction = enum { left_up, right_down };
|
||||
|
||||
|
Reference in New Issue
Block a user