mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
terminal: PageList rename "page" to "node" everywhere
This is more correct: a pagelist is a linked list of nodes, not pages. The nodes themselves contain pages but we were previously calling the nodes "pages" which was confusing, especially as I plan some future changes to the way pages are stored.
This commit is contained in:
@ -3115,7 +3115,7 @@ fn processLinks(self: *Surface, pos: apprt.CursorPos) !bool {
|
||||
/// if there is no hyperlink.
|
||||
fn osc8URI(self: *Surface, pin: terminal.Pin) ?[]const u8 {
|
||||
_ = self;
|
||||
const page = &pin.page.data;
|
||||
const page = &pin.node.data;
|
||||
const cell = pin.rowAndCell().cell;
|
||||
const link_id = page.lookupHyperlink(cell) orelse return null;
|
||||
const entry = page.hyperlink_set.get(page.memory, link_id);
|
||||
|
@ -1040,7 +1040,7 @@ pub fn updateFrame(
|
||||
null,
|
||||
);
|
||||
while (it.next()) |chunk| {
|
||||
var dirty_set = chunk.page.data.dirtyBitSet();
|
||||
var dirty_set = chunk.node.data.dirtyBitSet();
|
||||
dirty_set.unsetAll();
|
||||
}
|
||||
}
|
||||
@ -2364,7 +2364,7 @@ fn rebuildCells(
|
||||
// True if this cell is selected
|
||||
const selected: bool = if (screen.selection) |sel|
|
||||
sel.contains(screen, .{
|
||||
.page = row.page,
|
||||
.node = row.node,
|
||||
.y = row.y,
|
||||
.x = @intCast(
|
||||
// Spacer tails should show the selection
|
||||
@ -2512,12 +2512,7 @@ fn rebuildCells(
|
||||
);
|
||||
};
|
||||
|
||||
if (style.flags.overline) self.addOverline(
|
||||
@intCast(x),
|
||||
@intCast(y),
|
||||
fg,
|
||||
alpha
|
||||
) catch |err| {
|
||||
if (style.flags.overline) self.addOverline(@intCast(x), @intCast(y), fg, alpha) catch |err| {
|
||||
log.warn(
|
||||
"error adding overline to cell, will be invalid x={} y={}, err={}",
|
||||
.{ x, y, err },
|
||||
|
@ -844,7 +844,7 @@ pub fn updateFrame(
|
||||
null,
|
||||
);
|
||||
while (it.next()) |chunk| {
|
||||
var dirty_set = chunk.page.data.dirtyBitSet();
|
||||
var dirty_set = chunk.node.data.dirtyBitSet();
|
||||
dirty_set.unsetAll();
|
||||
}
|
||||
}
|
||||
@ -1411,7 +1411,7 @@ pub fn rebuildCells(
|
||||
// True if this cell is selected
|
||||
const selected: bool = if (screen.selection) |sel|
|
||||
sel.contains(screen, .{
|
||||
.page = row.page,
|
||||
.node = row.node,
|
||||
.y = row.y,
|
||||
.x = @intCast(
|
||||
// Spacer tails should show the selection
|
||||
|
@ -70,7 +70,7 @@ pub fn fgMode(
|
||||
}
|
||||
|
||||
// If we are at the end of the screen its definitely constrained
|
||||
if (cell_pin.x == cell_pin.page.data.size.cols - 1) break :text .constrained;
|
||||
if (cell_pin.x == cell_pin.node.data.size.cols - 1) break :text .constrained;
|
||||
|
||||
// If we have a previous cell and it was PUA then we need to
|
||||
// also constrain. This is so that multiple PUA glyphs align.
|
||||
|
@ -122,7 +122,7 @@ pub const Set = struct {
|
||||
if (!mouse_cell.hyperlink) return;
|
||||
|
||||
// Get our hyperlink entry
|
||||
const page = &mouse_pin.page.data;
|
||||
const page: *terminal.Page = &mouse_pin.node.data;
|
||||
const link_id = page.lookupHyperlink(mouse_cell) orelse {
|
||||
log.warn("failed to find hyperlink for cell", .{});
|
||||
return;
|
||||
@ -165,7 +165,7 @@ pub const Set = struct {
|
||||
for (row_pin.cells(.right), 0..) |*cell, x| {
|
||||
const match = match: {
|
||||
if (cell.hyperlink) {
|
||||
if (row_pin.page.data.lookupHyperlink(cell)) |cell_link_id| {
|
||||
if (row_pin.node.data.lookupHyperlink(cell)) |cell_link_id| {
|
||||
break :match cell_link_id == link_id;
|
||||
}
|
||||
}
|
||||
@ -215,7 +215,7 @@ pub const Set = struct {
|
||||
// Expand it to the left.
|
||||
var it = mouse_pin.cellIterator(.left_up, null);
|
||||
while (it.next()) |cell_pin| {
|
||||
const page = &cell_pin.page.data;
|
||||
const page: *terminal.Page = &cell_pin.node.data;
|
||||
const rac = cell_pin.rowAndCell();
|
||||
const cell = rac.cell;
|
||||
|
||||
@ -241,7 +241,7 @@ pub const Set = struct {
|
||||
// Expand it to the right
|
||||
it = mouse_pin.cellIterator(.right_down, null);
|
||||
while (it.next()) |cell_pin| {
|
||||
const page = &cell_pin.page.data;
|
||||
const page: *terminal.Page = &cell_pin.node.data;
|
||||
const rac = cell_pin.rowAndCell();
|
||||
const cell = rac.cell;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -203,7 +203,7 @@ pub fn init(
|
||||
errdefer pages.deinit();
|
||||
|
||||
// Create our tracked pin for the cursor.
|
||||
const page_pin = try pages.trackPin(.{ .page = pages.pages.first.? });
|
||||
const page_pin = try pages.trackPin(.{ .node = pages.pages.first.? });
|
||||
errdefer pages.untrackPin(page_pin);
|
||||
const page_rac = page_pin.rowAndCell();
|
||||
|
||||
@ -331,7 +331,7 @@ pub fn clonePool(
|
||||
};
|
||||
}
|
||||
|
||||
const page_pin = try pages.trackPin(.{ .page = pages.pages.first.? });
|
||||
const page_pin = try pages.trackPin(.{ .node = pages.pages.first.? });
|
||||
const page_rac = page_pin.rowAndCell();
|
||||
break :cursor .{
|
||||
.x = 0,
|
||||
@ -376,7 +376,7 @@ pub fn clonePool(
|
||||
if (!sel.contains(self, clone_top)) break :sel null;
|
||||
}
|
||||
|
||||
break :start try pages.trackPin(.{ .page = pages.pages.first.? });
|
||||
break :start try pages.trackPin(.{ .node = pages.pages.first.? });
|
||||
};
|
||||
|
||||
const end_pin = pin_remap.get(ordered.br) orelse end: {
|
||||
@ -414,21 +414,21 @@ pub fn clonePool(
|
||||
/// cursor page.
|
||||
pub fn adjustCapacity(
|
||||
self: *Screen,
|
||||
page: *PageList.List.Node,
|
||||
node: *PageList.List.Node,
|
||||
adjustment: PageList.AdjustCapacity,
|
||||
) PageList.AdjustCapacityError!*PageList.List.Node {
|
||||
// If the page being modified isn't our cursor page then
|
||||
// this is a quick operation because we have no additional
|
||||
// accounting.
|
||||
if (page != self.cursor.page_pin.page) {
|
||||
return try self.pages.adjustCapacity(page, adjustment);
|
||||
if (node != self.cursor.page_pin.node) {
|
||||
return try self.pages.adjustCapacity(node, adjustment);
|
||||
}
|
||||
|
||||
// We're modifying the cursor page. When we adjust the
|
||||
// capacity below it will be short the ref count on our
|
||||
// current style and hyperlink, so we need to init those.
|
||||
const node = try self.pages.adjustCapacity(page, adjustment);
|
||||
const new_page = &node.data;
|
||||
const new_node = try self.pages.adjustCapacity(node, adjustment);
|
||||
const new_page: *Page = &new_node.data;
|
||||
|
||||
// All additions below have unreachable catches because when
|
||||
// we adjust cap we should have enough memory to fit the
|
||||
@ -460,7 +460,7 @@ pub fn adjustCapacity(
|
||||
// So our page row/cell and so on are all off.
|
||||
self.cursorReload();
|
||||
|
||||
return node;
|
||||
return new_node;
|
||||
}
|
||||
|
||||
pub fn cursorCellRight(self: *Screen, n: size.CellCountInt) *pagepkg.Cell {
|
||||
@ -636,13 +636,14 @@ pub fn cursorDownScroll(self: *Screen) !void {
|
||||
// so our cursor is in the correct place we just have to clear
|
||||
// the cells.
|
||||
if (self.pages.rows == 1) {
|
||||
const page: *Page = &self.cursor.page_pin.node.data;
|
||||
self.clearCells(
|
||||
&self.cursor.page_pin.page.data,
|
||||
page,
|
||||
self.cursor.page_row,
|
||||
self.cursor.page_pin.page.data.getCells(self.cursor.page_row),
|
||||
page.getCells(self.cursor.page_row),
|
||||
);
|
||||
|
||||
var dirty = self.cursor.page_pin.page.data.dirtyBitSet();
|
||||
var dirty = page.dirtyBitSet();
|
||||
dirty.set(0);
|
||||
} else {
|
||||
// eraseRow will shift everything below it up.
|
||||
@ -684,7 +685,7 @@ pub fn cursorDownScroll(self: *Screen) !void {
|
||||
// was on was pruned. In this case, grow() moves the pin to
|
||||
// the top-left of the new page. This effectively moves it by
|
||||
// one already, we just need to fix up the x value.
|
||||
const page_pin = if (old_pin.page == self.cursor.page_pin.page)
|
||||
const page_pin = if (old_pin.node == self.cursor.page_pin.node)
|
||||
self.cursor.page_pin.down(1).?
|
||||
else reuse: {
|
||||
var pin = self.cursor.page_pin.*;
|
||||
@ -714,10 +715,11 @@ pub fn cursorDownScroll(self: *Screen) !void {
|
||||
// Clear the new row so it gets our bg color. We only do this
|
||||
// if we have a bg color at all.
|
||||
if (self.cursor.style.bg_color != .none) {
|
||||
const page: *Page = &page_pin.node.data;
|
||||
self.clearCells(
|
||||
&page_pin.page.data,
|
||||
page,
|
||||
self.cursor.page_row,
|
||||
page_pin.page.data.getCells(self.cursor.page_row),
|
||||
page.getCells(self.cursor.page_row),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -753,15 +755,15 @@ pub fn cursorScrollAbove(self: *Screen) !void {
|
||||
} else {
|
||||
// In this case, it means grow() didn't allocate a new page.
|
||||
|
||||
if (self.cursor.page_pin.page == self.pages.pages.last) {
|
||||
if (self.cursor.page_pin.node == self.pages.pages.last) {
|
||||
// If we're on the last page we can do a very fast path because
|
||||
// all the rows we need to move around are within a single page.
|
||||
|
||||
assert(old_pin.page == self.cursor.page_pin.page);
|
||||
assert(old_pin.node == self.cursor.page_pin.node);
|
||||
self.cursor.page_pin.* = self.cursor.page_pin.down(1).?;
|
||||
|
||||
const pin = self.cursor.page_pin;
|
||||
const page = &self.cursor.page_pin.page.data;
|
||||
const page: *Page = &self.cursor.page_pin.node.data;
|
||||
|
||||
// Rotate the rows so that the newly created empty row is at the
|
||||
// beginning. e.g. [ 0 1 2 3 ] in to [ 3 0 1 2 ].
|
||||
@ -822,7 +824,7 @@ fn cursorScrollAboveRotate(self: *Screen) !void {
|
||||
// Go through each of the pages following our pin, shift all rows
|
||||
// down by one, and copy the last row of the previous page.
|
||||
var current = self.pages.pages.last.?;
|
||||
while (current != self.cursor.page_pin.page) : (current = current.prev.?) {
|
||||
while (current != self.cursor.page_pin.node) : (current = current.prev.?) {
|
||||
const prev = current.prev.?;
|
||||
const prev_page = &prev.data;
|
||||
const cur_page = ¤t.data;
|
||||
@ -846,7 +848,7 @@ fn cursorScrollAboveRotate(self: *Screen) !void {
|
||||
|
||||
// Our current is our cursor page, we need to rotate down from
|
||||
// our cursor and clear our row.
|
||||
assert(current == self.cursor.page_pin.page);
|
||||
assert(current == self.cursor.page_pin.node);
|
||||
const cur_page = ¤t.data;
|
||||
const cur_rows = cur_page.rows.ptr(cur_page.memory.ptr);
|
||||
fastmem.rotateOnceR(Row, cur_rows[self.cursor.page_pin.y..cur_page.size.rows]);
|
||||
@ -922,7 +924,7 @@ pub fn cursorCopy(self: *Screen, other: Cursor, opts: struct {
|
||||
// If the other cursor had a hyperlink, add it to ours.
|
||||
if (opts.hyperlink and other.hyperlink_id != 0) {
|
||||
// Get the hyperlink from the other cursor's page.
|
||||
const other_page = &other.page_pin.page.data;
|
||||
const other_page = &other.page_pin.node.data;
|
||||
const other_link = other_page.hyperlink_set.get(other_page.memory, other.hyperlink_id);
|
||||
|
||||
const uri = other_link.uri.offset.ptr(other_page.memory)[0..other_link.uri.len];
|
||||
@ -957,7 +959,7 @@ fn cursorChangePin(self: *Screen, new: Pin) void {
|
||||
|
||||
// If our pin is on the same page, then we can just update the pin.
|
||||
// We don't need to migrate any state.
|
||||
if (self.cursor.page_pin.page == new.page) {
|
||||
if (self.cursor.page_pin.node == new.node) {
|
||||
self.cursor.page_pin.* = new;
|
||||
return;
|
||||
}
|
||||
@ -974,7 +976,7 @@ fn cursorChangePin(self: *Screen, new: Pin) void {
|
||||
|
||||
// If we have a hyperlink then we need to release it from the old page.
|
||||
if (self.cursor.hyperlink != null) {
|
||||
const old_page = &self.cursor.page_pin.page.data;
|
||||
const old_page: *Page = &self.cursor.page_pin.node.data;
|
||||
old_page.hyperlink_set.release(old_page.memory, self.cursor.hyperlink_id);
|
||||
}
|
||||
|
||||
@ -1049,12 +1051,12 @@ pub fn cursorResetWrap(self: *Screen) void {
|
||||
|
||||
// If the last cell in the row is a spacer head we need to clear it.
|
||||
const cells = self.cursor.page_pin.cells(.all);
|
||||
const cell = cells[self.cursor.page_pin.page.data.size.cols - 1];
|
||||
const cell = cells[self.cursor.page_pin.node.data.size.cols - 1];
|
||||
if (cell.wide == .spacer_head) {
|
||||
self.clearCells(
|
||||
&self.cursor.page_pin.page.data,
|
||||
&self.cursor.page_pin.node.data,
|
||||
page_row,
|
||||
cells[self.cursor.page_pin.page.data.size.cols - 1 ..][0..1],
|
||||
cells[self.cursor.page_pin.node.data.size.cols - 1 ..][0..1],
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1144,22 +1146,22 @@ pub fn clearRows(
|
||||
var it = self.pages.pageIterator(.right_down, tl, bl);
|
||||
while (it.next()) |chunk| {
|
||||
// Mark everything in this chunk as dirty
|
||||
var dirty = chunk.page.data.dirtyBitSet();
|
||||
var dirty = chunk.node.data.dirtyBitSet();
|
||||
dirty.setRangeValue(.{ .start = chunk.start, .end = chunk.end }, true);
|
||||
|
||||
for (chunk.rows()) |*row| {
|
||||
const cells_offset = row.cells;
|
||||
const cells_multi: [*]Cell = row.cells.ptr(chunk.page.data.memory);
|
||||
const cells_multi: [*]Cell = row.cells.ptr(chunk.node.data.memory);
|
||||
const cells = cells_multi[0..self.pages.cols];
|
||||
|
||||
// Clear all cells
|
||||
if (protected) {
|
||||
self.clearUnprotectedCells(&chunk.page.data, row, cells);
|
||||
self.clearUnprotectedCells(&chunk.node.data, row, cells);
|
||||
// We need to preserve other row attributes since we only
|
||||
// cleared unprotected cells.
|
||||
row.cells = cells_offset;
|
||||
} else {
|
||||
self.clearCells(&chunk.page.data, row, cells);
|
||||
self.clearCells(&chunk.node.data, row, cells);
|
||||
row.* = .{ .cells = cells_offset };
|
||||
}
|
||||
}
|
||||
@ -1294,8 +1296,8 @@ pub fn clearPrompt(self: *Screen) void {
|
||||
var clear_it = top.rowIterator(.right_down, null);
|
||||
while (clear_it.next()) |p| {
|
||||
const row = p.rowAndCell().row;
|
||||
p.page.data.clearCells(row, 0, p.page.data.size.cols);
|
||||
p.page.data.assertIntegrity();
|
||||
p.node.data.clearCells(row, 0, p.node.data.size.cols);
|
||||
p.node.data.assertIntegrity();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1336,12 +1338,12 @@ pub fn splitCellBoundary(
|
||||
self: *Screen,
|
||||
x: size.CellCountInt,
|
||||
) void {
|
||||
const page = &self.cursor.page_pin.page.data;
|
||||
const page = &self.cursor.page_pin.node.data;
|
||||
|
||||
page.pauseIntegrityChecks(true);
|
||||
defer page.pauseIntegrityChecks(false);
|
||||
|
||||
const cols = self.cursor.page_pin.page.data.size.cols;
|
||||
const cols = self.cursor.page_pin.node.data.size.cols;
|
||||
|
||||
// `x` may be up to an INCLUDING `cols`, since that signifies splitting
|
||||
// the boundary to the right of the final cell in the row.
|
||||
@ -1385,12 +1387,12 @@ pub fn splitCellBoundary(
|
||||
if (self.cursor.page_pin.up(1)) |p_row| {
|
||||
const p_rac = p_row.rowAndCell();
|
||||
const p_cells = p_row.cells(.all);
|
||||
const p_cell = p_cells[p_row.page.data.size.cols - 1];
|
||||
const p_cell = p_cells[p_row.node.data.size.cols - 1];
|
||||
if (p_cell.wide == .spacer_head) {
|
||||
self.clearCells(
|
||||
&p_row.page.data,
|
||||
&p_row.node.data,
|
||||
p_rac.row,
|
||||
p_cells[p_row.page.data.size.cols - 1 ..][0..1],
|
||||
p_cells[p_row.node.data.size.cols - 1 ..][0..1],
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1506,7 +1508,7 @@ fn resizeInternal(
|
||||
if (self.cursor.hyperlink_id != 0) {
|
||||
// Note we do NOT use endHyperlink because we want to keep
|
||||
// our allocated self.cursor.hyperlink valid.
|
||||
var page = &self.cursor.page_pin.page.data;
|
||||
var page = &self.cursor.page_pin.node.data;
|
||||
page.hyperlink_set.release(page.memory, self.cursor.hyperlink_id);
|
||||
self.cursor.hyperlink_id = 0;
|
||||
self.cursor.hyperlink = null;
|
||||
@ -1701,7 +1703,7 @@ pub fn setAttribute(self: *Screen, attr: sgr.Attribute) !void {
|
||||
|
||||
/// Call this whenever you manually change the cursor style.
|
||||
pub fn manualStyleUpdate(self: *Screen) !void {
|
||||
var page = &self.cursor.page_pin.page.data;
|
||||
var page: *Page = &self.cursor.page_pin.node.data;
|
||||
|
||||
// std.log.warn("active styles={}", .{page.styles.count()});
|
||||
|
||||
@ -1730,7 +1732,7 @@ pub fn manualStyleUpdate(self: *Screen) !void {
|
||||
// and double the style capacity for it if it was
|
||||
// full.
|
||||
const node = try self.adjustCapacity(
|
||||
self.cursor.page_pin.page,
|
||||
self.cursor.page_pin.node,
|
||||
switch (err) {
|
||||
error.OutOfMemory => .{ .styles = page.capacity.styles * 2 },
|
||||
error.NeedsRehash => .{},
|
||||
@ -1749,8 +1751,8 @@ pub fn manualStyleUpdate(self: *Screen) !void {
|
||||
|
||||
/// Append a grapheme to the given cell within the current cursor row.
|
||||
pub fn appendGrapheme(self: *Screen, cell: *Cell, cp: u21) !void {
|
||||
defer self.cursor.page_pin.page.data.assertIntegrity();
|
||||
self.cursor.page_pin.page.data.appendGrapheme(
|
||||
defer self.cursor.page_pin.node.data.assertIntegrity();
|
||||
self.cursor.page_pin.node.data.appendGrapheme(
|
||||
self.cursor.page_row,
|
||||
cell,
|
||||
cp,
|
||||
@ -1768,7 +1770,7 @@ pub fn appendGrapheme(self: *Screen, cell: *Cell, cp: u21) !void {
|
||||
|
||||
// Adjust our capacity. This will update our cursor page pin and
|
||||
// force us to reload.
|
||||
const original_node = self.cursor.page_pin.page;
|
||||
const original_node = self.cursor.page_pin.node;
|
||||
const new_bytes = original_node.data.capacity.grapheme_bytes * 2;
|
||||
_ = try self.adjustCapacity(
|
||||
original_node,
|
||||
@ -1783,7 +1785,7 @@ pub fn appendGrapheme(self: *Screen, cell: *Cell, cp: u21) !void {
|
||||
.gt => self.cursorCellRight(@intCast(cell_idx - self.cursor.x)),
|
||||
};
|
||||
|
||||
try self.cursor.page_pin.page.data.appendGrapheme(
|
||||
try self.cursor.page_pin.node.data.appendGrapheme(
|
||||
self.cursor.page_row,
|
||||
reloaded_cell,
|
||||
cp,
|
||||
@ -1827,19 +1829,19 @@ pub fn startHyperlink(
|
||||
|
||||
// strings table is out of memory, adjust it up
|
||||
error.StringsOutOfMemory => _ = try self.adjustCapacity(
|
||||
self.cursor.page_pin.page,
|
||||
.{ .string_bytes = self.cursor.page_pin.page.data.capacity.string_bytes * 2 },
|
||||
self.cursor.page_pin.node,
|
||||
.{ .string_bytes = self.cursor.page_pin.node.data.capacity.string_bytes * 2 },
|
||||
),
|
||||
|
||||
// hyperlink set is out of memory, adjust it up
|
||||
error.SetOutOfMemory => _ = try self.adjustCapacity(
|
||||
self.cursor.page_pin.page,
|
||||
.{ .hyperlink_bytes = self.cursor.page_pin.page.data.capacity.hyperlink_bytes * 2 },
|
||||
self.cursor.page_pin.node,
|
||||
.{ .hyperlink_bytes = self.cursor.page_pin.node.data.capacity.hyperlink_bytes * 2 },
|
||||
),
|
||||
|
||||
// hyperlink set is too full, rehash it
|
||||
error.SetNeedsRehash => _ = try self.adjustCapacity(
|
||||
self.cursor.page_pin.page,
|
||||
self.cursor.page_pin.node,
|
||||
.{},
|
||||
),
|
||||
}
|
||||
@ -1866,7 +1868,7 @@ fn startHyperlinkOnce(
|
||||
errdefer link.deinit(self.alloc);
|
||||
|
||||
// Insert the hyperlink into page memory
|
||||
var page = &self.cursor.page_pin.page.data;
|
||||
var page = &self.cursor.page_pin.node.data;
|
||||
const id: hyperlink.Id = try page.insertHyperlink(link.*);
|
||||
|
||||
// Save it all
|
||||
@ -1893,7 +1895,7 @@ pub fn endHyperlink(self: *Screen) void {
|
||||
// how RefCountedSet works). This causes some memory fragmentation but
|
||||
// is fine because if it is ever pruned the context deleted callback
|
||||
// will be called.
|
||||
var page = &self.cursor.page_pin.page.data;
|
||||
var page: *Page = &self.cursor.page_pin.node.data;
|
||||
page.hyperlink_set.release(page.memory, self.cursor.hyperlink_id);
|
||||
self.cursor.hyperlink.?.deinit(self.alloc);
|
||||
self.alloc.destroy(self.cursor.hyperlink.?);
|
||||
@ -1905,7 +1907,7 @@ pub fn endHyperlink(self: *Screen) void {
|
||||
pub fn cursorSetHyperlink(self: *Screen) !void {
|
||||
assert(self.cursor.hyperlink_id != 0);
|
||||
|
||||
var page = &self.cursor.page_pin.page.data;
|
||||
var page = &self.cursor.page_pin.node.data;
|
||||
if (page.setHyperlink(
|
||||
self.cursor.page_row,
|
||||
self.cursor.page_cell,
|
||||
@ -1918,7 +1920,7 @@ pub fn cursorSetHyperlink(self: *Screen) !void {
|
||||
// hyperlink_map is out of space, realloc the page to be larger
|
||||
error.HyperlinkMapOutOfMemory => {
|
||||
_ = try self.adjustCapacity(
|
||||
self.cursor.page_pin.page,
|
||||
self.cursor.page_pin.node,
|
||||
.{ .hyperlink_bytes = page.capacity.hyperlink_bytes * 2 },
|
||||
);
|
||||
|
||||
@ -2021,7 +2023,7 @@ pub fn selectionString(self: *Screen, alloc: Allocator, opts: SelectionString) !
|
||||
while (page_it.next()) |chunk| {
|
||||
const rows = chunk.rows();
|
||||
for (rows, chunk.start..) |row, y| {
|
||||
const cells_ptr = row.cells.ptr(chunk.page.data.memory);
|
||||
const cells_ptr = row.cells.ptr(chunk.node.data.memory);
|
||||
|
||||
const start_x = if (row_count == 0 or sel_ordered.rectangle)
|
||||
sel_start.x
|
||||
@ -2048,20 +2050,20 @@ pub fn selectionString(self: *Screen, alloc: Allocator, opts: SelectionString) !
|
||||
try strbuilder.appendSlice(buf[0..encode_len]);
|
||||
if (mapbuilder) |*b| {
|
||||
for (0..encode_len) |_| try b.append(.{
|
||||
.page = chunk.page,
|
||||
.node = chunk.node,
|
||||
.y = @intCast(y),
|
||||
.x = @intCast(x),
|
||||
});
|
||||
}
|
||||
}
|
||||
if (cell.hasGrapheme()) {
|
||||
const cps = chunk.page.data.lookupGrapheme(cell).?;
|
||||
const cps = chunk.node.data.lookupGrapheme(cell).?;
|
||||
for (cps) |cp| {
|
||||
const encode_len = try std.unicode.utf8Encode(cp, &buf);
|
||||
try strbuilder.appendSlice(buf[0..encode_len]);
|
||||
if (mapbuilder) |*b| {
|
||||
for (0..encode_len) |_| try b.append(.{
|
||||
.page = chunk.page,
|
||||
.node = chunk.node,
|
||||
.y = @intCast(y),
|
||||
.x = @intCast(x),
|
||||
});
|
||||
@ -2070,16 +2072,16 @@ pub fn selectionString(self: *Screen, alloc: Allocator, opts: SelectionString) !
|
||||
}
|
||||
}
|
||||
|
||||
const is_final_row = chunk.page == sel_end.page and y == sel_end.y;
|
||||
const is_final_row = chunk.node == sel_end.node and y == sel_end.y;
|
||||
|
||||
if (!is_final_row and
|
||||
(!row.wrap or sel_ordered.rectangle))
|
||||
{
|
||||
try strbuilder.append('\n');
|
||||
if (mapbuilder) |*b| try b.append(.{
|
||||
.page = chunk.page,
|
||||
.node = chunk.node,
|
||||
.y = @intCast(y),
|
||||
.x = chunk.page.data.size.cols - 1,
|
||||
.x = chunk.node.data.size.cols - 1,
|
||||
});
|
||||
}
|
||||
|
||||
@ -2209,14 +2211,14 @@ pub fn selectLine(self: *const Screen, opts: SelectLine) ?Selection {
|
||||
const current_prompt = row.semantic_prompt.promptOrInput();
|
||||
if (current_prompt != v) {
|
||||
var prev = p.up(1).?;
|
||||
prev.x = p.page.data.size.cols - 1;
|
||||
prev.x = p.node.data.size.cols - 1;
|
||||
break :end_pin prev;
|
||||
}
|
||||
}
|
||||
|
||||
if (!row.wrap) {
|
||||
var copy = p;
|
||||
copy.x = p.page.data.size.cols - 1;
|
||||
copy.x = p.node.data.size.cols - 1;
|
||||
break :end_pin copy;
|
||||
}
|
||||
}
|
||||
@ -2417,7 +2419,7 @@ pub fn selectWord(self: *Screen, pin: Pin) ?Selection {
|
||||
|
||||
// If we are going to the next row and it isn't wrapped, we
|
||||
// return the previous.
|
||||
if (p.x == p.page.data.size.cols - 1 and !rac.row.wrap) {
|
||||
if (p.x == p.node.data.size.cols - 1 and !rac.row.wrap) {
|
||||
break :end p;
|
||||
}
|
||||
|
||||
@ -2437,7 +2439,7 @@ pub fn selectWord(self: *Screen, pin: Pin) ?Selection {
|
||||
|
||||
// If we are going to the next row and it isn't wrapped, we
|
||||
// return the previous.
|
||||
if (p.x == p.page.data.size.cols - 1 and !rac.row.wrap) {
|
||||
if (p.x == p.node.data.size.cols - 1 and !rac.row.wrap) {
|
||||
break :start prev;
|
||||
}
|
||||
|
||||
@ -2491,7 +2493,7 @@ pub fn selectOutput(self: *Screen, pin: Pin) ?Selection {
|
||||
switch (row.semantic_prompt) {
|
||||
.input, .prompt_continuation, .prompt => {
|
||||
var copy = it_prev;
|
||||
copy.x = it_prev.page.data.size.cols - 1;
|
||||
copy.x = it_prev.node.data.size.cols - 1;
|
||||
break :boundary copy;
|
||||
},
|
||||
else => {},
|
||||
@ -2504,10 +2506,10 @@ pub fn selectOutput(self: *Screen, pin: Pin) ?Selection {
|
||||
it = it_prev.rowIterator(.left_up, null);
|
||||
while (it.next()) |p| {
|
||||
const row = p.rowAndCell().row;
|
||||
const cells = p.page.data.getCells(row);
|
||||
const cells = p.node.data.getCells(row);
|
||||
if (Cell.hasTextAny(cells)) {
|
||||
var copy = p;
|
||||
copy.x = p.page.data.size.cols - 1;
|
||||
copy.x = p.node.data.size.cols - 1;
|
||||
break :boundary copy;
|
||||
}
|
||||
}
|
||||
@ -2598,7 +2600,7 @@ pub fn selectPrompt(self: *Screen, pin: Pin) ?Selection {
|
||||
const end: Pin = end: {
|
||||
var it = pin.rowIterator(.right_down, null);
|
||||
var it_prev = it.next().?;
|
||||
it_prev.x = it_prev.page.data.size.cols - 1;
|
||||
it_prev.x = it_prev.node.data.size.cols - 1;
|
||||
while (it.next()) |p| {
|
||||
const row = p.rowAndCell().row;
|
||||
switch (row.semantic_prompt) {
|
||||
@ -2610,7 +2612,7 @@ pub fn selectPrompt(self: *Screen, pin: Pin) ?Selection {
|
||||
}
|
||||
|
||||
it_prev = p;
|
||||
it_prev.x = it_prev.page.data.size.cols - 1;
|
||||
it_prev.x = it_prev.node.data.size.cols - 1;
|
||||
}
|
||||
|
||||
break :end it_prev;
|
||||
@ -2764,7 +2766,7 @@ pub fn dumpString(
|
||||
|
||||
.codepoint_grapheme => {
|
||||
try writer.print("{u}", .{cell.content.codepoint});
|
||||
const cps = row_offset.page.data.lookupGrapheme(cell).?;
|
||||
const cps = row_offset.node.data.lookupGrapheme(cell).?;
|
||||
for (cps) |cp| {
|
||||
try writer.print("{u}", .{cp});
|
||||
}
|
||||
@ -2843,7 +2845,7 @@ pub fn testWriteString(self: *Screen, text: []const u8) !void {
|
||||
break :cell cell;
|
||||
};
|
||||
|
||||
try self.cursor.page_pin.page.data.appendGrapheme(
|
||||
try self.cursor.page_pin.node.data.appendGrapheme(
|
||||
self.cursor.page_row,
|
||||
cell,
|
||||
c,
|
||||
@ -2872,7 +2874,7 @@ pub fn testWriteString(self: *Screen, text: []const u8) !void {
|
||||
|
||||
// If we have a ref-counted style, increase.
|
||||
if (self.cursor.style_id != style.default_id) {
|
||||
const page = self.cursor.page_pin.page.data;
|
||||
const page = self.cursor.page_pin.node.data;
|
||||
page.styles.use(page.memory, self.cursor.style_id);
|
||||
self.cursor.page_row.styled = true;
|
||||
}
|
||||
@ -2914,7 +2916,7 @@ pub fn testWriteString(self: *Screen, text: []const u8) !void {
|
||||
|
||||
// If we have a ref-counted style, increase twice.
|
||||
if (self.cursor.style_id != style.default_id) {
|
||||
const page = self.cursor.page_pin.page.data;
|
||||
const page = self.cursor.page_pin.node.data;
|
||||
page.styles.use(page.memory, self.cursor.style_id);
|
||||
page.styles.use(page.memory, self.cursor.style_id);
|
||||
self.cursor.page_row.styled = true;
|
||||
@ -3054,7 +3056,7 @@ test "Screen cursorCopy style deref" {
|
||||
|
||||
var s2 = try Screen.init(alloc, 10, 10, 0);
|
||||
defer s2.deinit();
|
||||
const page = &s2.cursor.page_pin.page.data;
|
||||
const page = &s2.cursor.page_pin.node.data;
|
||||
|
||||
// Bold should create our style
|
||||
try s2.setAttribute(.{ .bold = {} });
|
||||
@ -3110,12 +3112,12 @@ test "Screen cursorCopy style deref new page" {
|
||||
// +-------------+
|
||||
|
||||
// This should be PAGE 1
|
||||
const page = &s2.cursor.page_pin.page.data;
|
||||
const page = &s2.cursor.page_pin.node.data;
|
||||
|
||||
// It should be the last page in the list.
|
||||
try testing.expectEqual(&s2.pages.pages.last.?.data, page);
|
||||
// It should have a previous page.
|
||||
try testing.expect(s2.cursor.page_pin.page.prev != null);
|
||||
try testing.expect(s2.cursor.page_pin.node.prev != null);
|
||||
|
||||
// The cursor should be at 2, 9
|
||||
try testing.expect(s2.cursor.x == 2);
|
||||
@ -3132,7 +3134,7 @@ test "Screen cursorCopy style deref new page" {
|
||||
try testing.expect(!s2.cursor.style.flags.bold);
|
||||
try testing.expectEqual(@as(usize, 0), page.styles.count());
|
||||
// The page after the page the cursor is now in should be page 1.
|
||||
try testing.expectEqual(page, &s2.cursor.page_pin.page.next.?.data);
|
||||
try testing.expectEqual(page, &s2.cursor.page_pin.node.next.?.data);
|
||||
// The cursor should be at 0, 0
|
||||
try testing.expect(s2.cursor.x == 0);
|
||||
try testing.expect(s2.cursor.y == 0);
|
||||
@ -3148,7 +3150,7 @@ test "Screen cursorCopy style copy" {
|
||||
|
||||
var s2 = try Screen.init(alloc, 10, 10, 0);
|
||||
defer s2.deinit();
|
||||
const page = &s2.cursor.page_pin.page.data;
|
||||
const page = &s2.cursor.page_pin.node.data;
|
||||
try s2.cursorCopy(s.cursor, .{});
|
||||
try testing.expect(s2.cursor.style.flags.bold);
|
||||
try testing.expectEqual(@as(usize, 1), page.styles.count());
|
||||
@ -3163,7 +3165,7 @@ test "Screen cursorCopy hyperlink deref" {
|
||||
|
||||
var s2 = try Screen.init(alloc, 10, 10, 0);
|
||||
defer s2.deinit();
|
||||
const page = &s2.cursor.page_pin.page.data;
|
||||
const page = &s2.cursor.page_pin.node.data;
|
||||
|
||||
// Create a hyperlink for the cursor.
|
||||
try s2.startHyperlink("https://example.com/", null);
|
||||
@ -3219,12 +3221,12 @@ test "Screen cursorCopy hyperlink deref new page" {
|
||||
// +-------------+
|
||||
|
||||
// This should be PAGE 1
|
||||
const page = &s2.cursor.page_pin.page.data;
|
||||
const page = &s2.cursor.page_pin.node.data;
|
||||
|
||||
// It should be the last page in the list.
|
||||
try testing.expectEqual(&s2.pages.pages.last.?.data, page);
|
||||
// It should have a previous page.
|
||||
try testing.expect(s2.cursor.page_pin.page.prev != null);
|
||||
try testing.expect(s2.cursor.page_pin.node.prev != null);
|
||||
|
||||
// The cursor should be at 2, 9
|
||||
try testing.expect(s2.cursor.x == 2);
|
||||
@ -3241,7 +3243,7 @@ test "Screen cursorCopy hyperlink deref new page" {
|
||||
try testing.expectEqual(@as(usize, 0), page.hyperlink_set.count());
|
||||
try testing.expect(s2.cursor.hyperlink_id == 0);
|
||||
// The page after the page the cursor is now in should be page 1.
|
||||
try testing.expectEqual(page, &s2.cursor.page_pin.page.next.?.data);
|
||||
try testing.expectEqual(page, &s2.cursor.page_pin.node.next.?.data);
|
||||
// The cursor should be at 0, 0
|
||||
try testing.expect(s2.cursor.x == 0);
|
||||
try testing.expect(s2.cursor.y == 0);
|
||||
@ -3256,12 +3258,12 @@ test "Screen cursorCopy hyperlink copy" {
|
||||
|
||||
// Create a hyperlink for the cursor.
|
||||
try s.startHyperlink("https://example.com/", null);
|
||||
try testing.expectEqual(@as(usize, 1), s.cursor.page_pin.page.data.hyperlink_set.count());
|
||||
try testing.expectEqual(@as(usize, 1), s.cursor.page_pin.node.data.hyperlink_set.count());
|
||||
try testing.expect(s.cursor.hyperlink_id != 0);
|
||||
|
||||
var s2 = try Screen.init(alloc, 10, 10, 0);
|
||||
defer s2.deinit();
|
||||
const page = &s2.cursor.page_pin.page.data;
|
||||
const page = &s2.cursor.page_pin.node.data;
|
||||
|
||||
try testing.expectEqual(@as(usize, 0), page.hyperlink_set.count());
|
||||
try testing.expect(s2.cursor.hyperlink_id == 0);
|
||||
@ -3281,12 +3283,12 @@ test "Screen cursorCopy hyperlink copy disabled" {
|
||||
|
||||
// Create a hyperlink for the cursor.
|
||||
try s.startHyperlink("https://example.com/", null);
|
||||
try testing.expectEqual(@as(usize, 1), s.cursor.page_pin.page.data.hyperlink_set.count());
|
||||
try testing.expectEqual(@as(usize, 1), s.cursor.page_pin.node.data.hyperlink_set.count());
|
||||
try testing.expect(s.cursor.hyperlink_id != 0);
|
||||
|
||||
var s2 = try Screen.init(alloc, 10, 10, 0);
|
||||
defer s2.deinit();
|
||||
const page = &s2.cursor.page_pin.page.data;
|
||||
const page = &s2.cursor.page_pin.node.data;
|
||||
|
||||
try testing.expectEqual(@as(usize, 0), page.hyperlink_set.count());
|
||||
try testing.expect(s2.cursor.hyperlink_id == 0);
|
||||
@ -3303,7 +3305,7 @@ test "Screen style basics" {
|
||||
|
||||
var s = try Screen.init(alloc, 80, 24, 1000);
|
||||
defer s.deinit();
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(@as(usize, 0), page.styles.count());
|
||||
|
||||
// Set a new style
|
||||
@ -3325,7 +3327,7 @@ test "Screen style reset to default" {
|
||||
|
||||
var s = try Screen.init(alloc, 80, 24, 1000);
|
||||
defer s.deinit();
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(@as(usize, 0), page.styles.count());
|
||||
|
||||
// Set a new style
|
||||
@ -3345,7 +3347,7 @@ test "Screen style reset with unset" {
|
||||
|
||||
var s = try Screen.init(alloc, 80, 24, 1000);
|
||||
defer s.deinit();
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(@as(usize, 0), page.styles.count());
|
||||
|
||||
// Set a new style
|
||||
@ -3402,7 +3404,7 @@ test "Screen clearRows active styled line" {
|
||||
try s.setAttribute(.{ .unset = {} });
|
||||
|
||||
// We should have one style
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(@as(usize, 1), page.styles.count());
|
||||
|
||||
s.clearRows(.{ .active = .{} }, null, false);
|
||||
@ -3628,21 +3630,21 @@ test "Screen: cursorDown across pages preserves style" {
|
||||
// assertion fails then the bug is in the test: we should be scrolling
|
||||
// above enough for a new page to show up.
|
||||
{
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
try testing.expect(start_page != page);
|
||||
}
|
||||
|
||||
// Scroll back to the previous page
|
||||
s.cursorUp(1);
|
||||
{
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
try testing.expect(start_page == page);
|
||||
}
|
||||
|
||||
// Go back up, set a style
|
||||
try s.setAttribute(.{ .bold = {} });
|
||||
{
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
const styleval = page.styles.get(
|
||||
page.memory,
|
||||
s.cursor.style_id,
|
||||
@ -3653,7 +3655,7 @@ test "Screen: cursorDown across pages preserves style" {
|
||||
// Go back down into the next page and we should have that style
|
||||
s.cursorDown(1);
|
||||
{
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
const styleval = page.styles.get(
|
||||
page.memory,
|
||||
s.cursor.style_id,
|
||||
@ -3678,14 +3680,14 @@ test "Screen: cursorUp across pages preserves style" {
|
||||
// assertion fails then the bug is in the test: we should be scrolling
|
||||
// above enough for a new page to show up.
|
||||
{
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
try testing.expect(start_page != page);
|
||||
}
|
||||
|
||||
// Go back up, set a style
|
||||
try s.setAttribute(.{ .bold = {} });
|
||||
{
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
const styleval = page.styles.get(
|
||||
page.memory,
|
||||
s.cursor.style_id,
|
||||
@ -3696,7 +3698,7 @@ test "Screen: cursorUp across pages preserves style" {
|
||||
// Go back down into the prev page and we should have that style
|
||||
s.cursorUp(1);
|
||||
{
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
try testing.expect(start_page == page);
|
||||
|
||||
const styleval = page.styles.get(
|
||||
@ -3723,14 +3725,14 @@ test "Screen: cursorAbsolute across pages preserves style" {
|
||||
// assertion fails then the bug is in the test: we should be scrolling
|
||||
// above enough for a new page to show up.
|
||||
{
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
try testing.expect(start_page != page);
|
||||
}
|
||||
|
||||
// Go back up, set a style
|
||||
try s.setAttribute(.{ .bold = {} });
|
||||
{
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
const styleval = page.styles.get(
|
||||
page.memory,
|
||||
s.cursor.style_id,
|
||||
@ -3741,7 +3743,7 @@ test "Screen: cursorAbsolute across pages preserves style" {
|
||||
// Go back down into the prev page and we should have that style
|
||||
s.cursorAbsolute(1, 1);
|
||||
{
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
try testing.expect(start_page == page);
|
||||
|
||||
const styleval = page.styles.get(
|
||||
@ -4345,7 +4347,7 @@ test "Screen: scroll above same page but cursor on previous page" {
|
||||
s.pages.clearDirty();
|
||||
|
||||
// Ensure we're still on the first page and have a second
|
||||
try testing.expect(s.cursor.page_pin.page == s.pages.pages.first.?);
|
||||
try testing.expect(s.cursor.page_pin.node == s.pages.pages.first.?);
|
||||
try testing.expect(s.pages.pages.first.?.next != null);
|
||||
|
||||
// At this point:
|
||||
@ -4403,7 +4405,7 @@ test "Screen: scroll above same page but cursor on previous page last row" {
|
||||
s.pages.clearDirty();
|
||||
|
||||
// Ensure we're still on the first page and have a second
|
||||
try testing.expect(s.cursor.page_pin.page == s.pages.pages.first.?);
|
||||
try testing.expect(s.cursor.page_pin.node == s.pages.pages.first.?);
|
||||
try testing.expect(s.pages.pages.first.?.next != null);
|
||||
|
||||
// At this point:
|
||||
@ -4478,7 +4480,7 @@ test "Screen: scroll above creates new page" {
|
||||
s.pages.clearDirty();
|
||||
|
||||
// Ensure we're still on the first page
|
||||
try testing.expect(s.cursor.page_pin.page == s.pages.pages.first.?);
|
||||
try testing.expect(s.cursor.page_pin.node == s.pages.pages.first.?);
|
||||
try s.cursorScrollAbove();
|
||||
|
||||
{
|
||||
@ -8150,7 +8152,7 @@ test "Screen: selectionString with zero width joiner" {
|
||||
const cell = pin.rowAndCell().cell;
|
||||
try testing.expectEqual(@as(u21, 0x1F468), cell.content.codepoint);
|
||||
try testing.expectEqual(Cell.Wide.wide, cell.wide);
|
||||
const cps = pin.page.data.lookupGrapheme(cell).?;
|
||||
const cps = pin.node.data.lookupGrapheme(cell).?;
|
||||
try testing.expectEqual(@as(usize, 1), cps.len);
|
||||
}
|
||||
|
||||
@ -8381,21 +8383,21 @@ test "Screen: hyperlink start/end" {
|
||||
defer s.deinit();
|
||||
try testing.expect(s.cursor.hyperlink_id == 0);
|
||||
{
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(0, page.hyperlink_set.count());
|
||||
}
|
||||
|
||||
try s.startHyperlink("http://example.com", null);
|
||||
try testing.expect(s.cursor.hyperlink_id != 0);
|
||||
{
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(1, page.hyperlink_set.count());
|
||||
}
|
||||
|
||||
s.endHyperlink();
|
||||
try testing.expect(s.cursor.hyperlink_id == 0);
|
||||
{
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(0, page.hyperlink_set.count());
|
||||
}
|
||||
}
|
||||
@ -8409,7 +8411,7 @@ test "Screen: hyperlink reuse" {
|
||||
|
||||
try testing.expect(s.cursor.hyperlink_id == 0);
|
||||
{
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(0, page.hyperlink_set.count());
|
||||
}
|
||||
|
||||
@ -8422,14 +8424,14 @@ test "Screen: hyperlink reuse" {
|
||||
try s.startHyperlink("http://example.com", null);
|
||||
try testing.expectEqual(id, s.cursor.hyperlink_id);
|
||||
{
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(1, page.hyperlink_set.count());
|
||||
}
|
||||
|
||||
s.endHyperlink();
|
||||
try testing.expect(s.cursor.hyperlink_id == 0);
|
||||
{
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(0, page.hyperlink_set.count());
|
||||
}
|
||||
}
|
||||
@ -8449,7 +8451,7 @@ test "Screen: hyperlink cursor state on resize" {
|
||||
try s.startHyperlink("http://example.com", null);
|
||||
try testing.expect(s.cursor.hyperlink_id != 0);
|
||||
{
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(1, page.hyperlink_set.count());
|
||||
}
|
||||
|
||||
@ -8457,14 +8459,14 @@ test "Screen: hyperlink cursor state on resize" {
|
||||
try s.resize(10, 10);
|
||||
try testing.expect(s.cursor.hyperlink_id != 0);
|
||||
{
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(1, page.hyperlink_set.count());
|
||||
}
|
||||
|
||||
s.endHyperlink();
|
||||
try testing.expect(s.cursor.hyperlink_id == 0);
|
||||
{
|
||||
const page = &s.cursor.page_pin.page.data;
|
||||
const page = &s.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(0, page.hyperlink_set.count());
|
||||
}
|
||||
}
|
||||
@ -8489,8 +8491,8 @@ test "Screen: adjustCapacity cursor style ref count" {
|
||||
|
||||
// This forces the page to change.
|
||||
_ = try s.adjustCapacity(
|
||||
s.cursor.page_pin.page,
|
||||
.{ .grapheme_bytes = s.cursor.page_pin.page.data.capacity.grapheme_bytes * 2 },
|
||||
s.cursor.page_pin.node,
|
||||
.{ .grapheme_bytes = s.cursor.page_pin.node.data.capacity.grapheme_bytes * 2 },
|
||||
);
|
||||
|
||||
// Our ref counts should still be the same
|
||||
|
@ -372,7 +372,7 @@ pub fn adjust(
|
||||
var current = end_pin.*;
|
||||
while (current.down(1)) |next| : (current = next) {
|
||||
const rac = next.rowAndCell();
|
||||
const cells = next.page.data.getCells(rac.row);
|
||||
const cells = next.node.data.getCells(rac.row);
|
||||
if (page.Cell.hasTextAny(cells)) {
|
||||
end_pin.* = next;
|
||||
break;
|
||||
@ -434,7 +434,7 @@ pub fn adjust(
|
||||
);
|
||||
while (it.next()) |next| {
|
||||
const rac = next.rowAndCell();
|
||||
const cells = next.page.data.getCells(rac.row);
|
||||
const cells = next.node.data.getCells(rac.row);
|
||||
if (page.Cell.hasTextAny(cells)) {
|
||||
end_pin.* = next;
|
||||
end_pin.x = @intCast(cells.len - 1);
|
||||
@ -445,7 +445,7 @@ pub fn adjust(
|
||||
|
||||
.beginning_of_line => end_pin.x = 0,
|
||||
|
||||
.end_of_line => end_pin.x = end_pin.page.data.size.cols - 1,
|
||||
.end_of_line => end_pin.x = end_pin.node.data.size.cols - 1,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -313,7 +313,7 @@ pub fn print(self: *Terminal, c: u21) !void {
|
||||
var state: unicode.GraphemeBreakState = .{};
|
||||
var cp1: u21 = prev.cell.content.codepoint;
|
||||
if (prev.cell.hasGrapheme()) {
|
||||
const cps = self.screen.cursor.page_pin.page.data.lookupGrapheme(prev.cell).?;
|
||||
const cps = self.screen.cursor.page_pin.node.data.lookupGrapheme(prev.cell).?;
|
||||
for (cps) |cp2| {
|
||||
// log.debug("cp1={x} cp2={x}", .{ cp1, cp2 });
|
||||
assert(!unicode.graphemeBreak(cp1, cp2, &state));
|
||||
@ -567,7 +567,7 @@ fn printCell(
|
||||
|
||||
const spacer_cell = self.screen.cursorCellRight(1);
|
||||
self.screen.clearCells(
|
||||
&self.screen.cursor.page_pin.page.data,
|
||||
&self.screen.cursor.page_pin.node.data,
|
||||
self.screen.cursor.page_row,
|
||||
spacer_cell[0..1],
|
||||
);
|
||||
@ -588,7 +588,7 @@ fn printCell(
|
||||
|
||||
const wide_cell = self.screen.cursorCellLeft(1);
|
||||
self.screen.clearCells(
|
||||
&self.screen.cursor.page_pin.page.data,
|
||||
&self.screen.cursor.page_pin.node.data,
|
||||
self.screen.cursor.page_row,
|
||||
wide_cell[0..1],
|
||||
);
|
||||
@ -607,7 +607,7 @@ fn printCell(
|
||||
|
||||
// If the prior value had graphemes, clear those
|
||||
if (cell.hasGrapheme()) {
|
||||
self.screen.cursor.page_pin.page.data.clearGrapheme(
|
||||
self.screen.cursor.page_pin.node.data.clearGrapheme(
|
||||
self.screen.cursor.page_row,
|
||||
cell,
|
||||
);
|
||||
@ -617,7 +617,7 @@ fn printCell(
|
||||
// cell's new style will be different after writing.
|
||||
const style_changed = cell.style_id != self.screen.cursor.style_id;
|
||||
if (style_changed) {
|
||||
var page = &self.screen.cursor.page_pin.page.data;
|
||||
var page = &self.screen.cursor.page_pin.node.data;
|
||||
|
||||
// Release the old style.
|
||||
if (cell.style_id != style.default_id) {
|
||||
@ -639,7 +639,7 @@ fn printCell(
|
||||
};
|
||||
|
||||
if (style_changed) {
|
||||
var page = &self.screen.cursor.page_pin.page.data;
|
||||
var page = &self.screen.cursor.page_pin.node.data;
|
||||
|
||||
// Use the new style.
|
||||
if (cell.style_id != style.default_id) {
|
||||
@ -664,7 +664,7 @@ fn printCell(
|
||||
};
|
||||
} else if (had_hyperlink) {
|
||||
// If the previous cell had a hyperlink then we need to clear it.
|
||||
var page = &self.screen.cursor.page_pin.page.data;
|
||||
var page = &self.screen.cursor.page_pin.node.data;
|
||||
page.clearHyperlink(self.screen.cursor.page_row, cell);
|
||||
}
|
||||
}
|
||||
@ -1500,8 +1500,8 @@ pub fn insertLines(self: *Terminal, count: usize) void {
|
||||
const off_rac = off_p.rowAndCell();
|
||||
const off_row: *Row = off_rac.row;
|
||||
|
||||
self.rowWillBeShifted(&cur_p.page.data, cur_row);
|
||||
self.rowWillBeShifted(&off_p.page.data, off_row);
|
||||
self.rowWillBeShifted(&cur_p.node.data, cur_row);
|
||||
self.rowWillBeShifted(&off_p.node.data, off_row);
|
||||
|
||||
// If our scrolling region is full width, then we unset wrap.
|
||||
if (!left_right) {
|
||||
@ -1518,19 +1518,19 @@ pub fn insertLines(self: *Terminal, count: usize) void {
|
||||
|
||||
// If our page doesn't match, then we need to do a copy from
|
||||
// one page to another. This is the slow path.
|
||||
if (src_p.page != dst_p.page) {
|
||||
dst_p.page.data.clonePartialRowFrom(
|
||||
&src_p.page.data,
|
||||
if (src_p.node != dst_p.node) {
|
||||
dst_p.node.data.clonePartialRowFrom(
|
||||
&src_p.node.data,
|
||||
dst_row,
|
||||
src_row,
|
||||
self.scrolling_region.left,
|
||||
self.scrolling_region.right + 1,
|
||||
) catch |err| {
|
||||
const cap = dst_p.page.data.capacity;
|
||||
const cap = dst_p.node.data.capacity;
|
||||
// Adjust our page capacity to make
|
||||
// room for we didn't have space for
|
||||
_ = self.screen.adjustCapacity(
|
||||
dst_p.page,
|
||||
dst_p.node,
|
||||
switch (err) {
|
||||
// Rehash the sets
|
||||
error.StyleSetNeedsRehash,
|
||||
@ -1589,11 +1589,11 @@ pub fn insertLines(self: *Terminal, count: usize) void {
|
||||
src_row.* = dst;
|
||||
|
||||
// Ensure what we did didn't corrupt the page
|
||||
cur_p.page.data.assertIntegrity();
|
||||
cur_p.node.data.assertIntegrity();
|
||||
} else {
|
||||
// Left/right scroll margins we have to
|
||||
// copy cells, which is much slower...
|
||||
const page = &cur_p.page.data;
|
||||
const page = &cur_p.node.data;
|
||||
page.moveCells(
|
||||
src_row,
|
||||
self.scrolling_region.left,
|
||||
@ -1605,7 +1605,7 @@ pub fn insertLines(self: *Terminal, count: usize) void {
|
||||
}
|
||||
} else {
|
||||
// Clear the cells for this row, it has been shifted.
|
||||
const page = &cur_p.page.data;
|
||||
const page = &cur_p.node.data;
|
||||
const cells = page.getCells(cur_row);
|
||||
self.screen.clearCells(
|
||||
page,
|
||||
@ -1698,8 +1698,8 @@ pub fn deleteLines(self: *Terminal, count: usize) void {
|
||||
const off_rac = off_p.rowAndCell();
|
||||
const off_row: *Row = off_rac.row;
|
||||
|
||||
self.rowWillBeShifted(&cur_p.page.data, cur_row);
|
||||
self.rowWillBeShifted(&off_p.page.data, off_row);
|
||||
self.rowWillBeShifted(&cur_p.node.data, cur_row);
|
||||
self.rowWillBeShifted(&off_p.node.data, off_row);
|
||||
|
||||
// If our scrolling region is full width, then we unset wrap.
|
||||
if (!left_right) {
|
||||
@ -1716,19 +1716,19 @@ pub fn deleteLines(self: *Terminal, count: usize) void {
|
||||
|
||||
// If our page doesn't match, then we need to do a copy from
|
||||
// one page to another. This is the slow path.
|
||||
if (src_p.page != dst_p.page) {
|
||||
dst_p.page.data.clonePartialRowFrom(
|
||||
&src_p.page.data,
|
||||
if (src_p.node != dst_p.node) {
|
||||
dst_p.node.data.clonePartialRowFrom(
|
||||
&src_p.node.data,
|
||||
dst_row,
|
||||
src_row,
|
||||
self.scrolling_region.left,
|
||||
self.scrolling_region.right + 1,
|
||||
) catch |err| {
|
||||
const cap = dst_p.page.data.capacity;
|
||||
const cap = dst_p.node.data.capacity;
|
||||
// Adjust our page capacity to make
|
||||
// room for we didn't have space for
|
||||
_ = self.screen.adjustCapacity(
|
||||
dst_p.page,
|
||||
dst_p.node,
|
||||
switch (err) {
|
||||
// Rehash the sets
|
||||
error.StyleSetNeedsRehash,
|
||||
@ -1782,11 +1782,11 @@ pub fn deleteLines(self: *Terminal, count: usize) void {
|
||||
src_row.* = dst;
|
||||
|
||||
// Ensure what we did didn't corrupt the page
|
||||
cur_p.page.data.assertIntegrity();
|
||||
cur_p.node.data.assertIntegrity();
|
||||
} else {
|
||||
// Left/right scroll margins we have to
|
||||
// copy cells, which is much slower...
|
||||
const page = &cur_p.page.data;
|
||||
const page = &cur_p.node.data;
|
||||
page.moveCells(
|
||||
src_row,
|
||||
self.scrolling_region.left,
|
||||
@ -1798,7 +1798,7 @@ pub fn deleteLines(self: *Terminal, count: usize) void {
|
||||
}
|
||||
} else {
|
||||
// Clear the cells for this row, it's from out of bounds.
|
||||
const page = &cur_p.page.data;
|
||||
const page = &cur_p.node.data;
|
||||
const cells = page.getCells(cur_row);
|
||||
self.screen.clearCells(
|
||||
page,
|
||||
@ -1843,7 +1843,7 @@ pub fn insertBlanks(self: *Terminal, count: usize) void {
|
||||
|
||||
// left is just the cursor position but as a multi-pointer
|
||||
const left: [*]Cell = @ptrCast(self.screen.cursor.page_cell);
|
||||
var page = &self.screen.cursor.page_pin.page.data;
|
||||
var page = &self.screen.cursor.page_pin.node.data;
|
||||
|
||||
// If our X is a wide spacer tail then we need to erase the
|
||||
// previous cell too so we don't split a multi-cell character.
|
||||
@ -1914,7 +1914,7 @@ pub fn deleteChars(self: *Terminal, count_req: usize) void {
|
||||
|
||||
// left is just the cursor position but as a multi-pointer
|
||||
const left: [*]Cell = @ptrCast(self.screen.cursor.page_cell);
|
||||
var page = &self.screen.cursor.page_pin.page.data;
|
||||
var page = &self.screen.cursor.page_pin.node.data;
|
||||
|
||||
// Remaining cols from our cursor to the right margin.
|
||||
const rem = self.scrolling_region.right - self.screen.cursor.x + 1;
|
||||
@ -1995,7 +1995,7 @@ pub fn eraseChars(self: *Terminal, count_req: usize) void {
|
||||
// mode was not ISO we also always ignore protection attributes.
|
||||
if (self.screen.protected_mode != .iso) {
|
||||
self.screen.clearCells(
|
||||
&self.screen.cursor.page_pin.page.data,
|
||||
&self.screen.cursor.page_pin.node.data,
|
||||
self.screen.cursor.page_row,
|
||||
cells[0..end],
|
||||
);
|
||||
@ -2003,7 +2003,7 @@ pub fn eraseChars(self: *Terminal, count_req: usize) void {
|
||||
}
|
||||
|
||||
self.screen.clearUnprotectedCells(
|
||||
&self.screen.cursor.page_pin.page.data,
|
||||
&self.screen.cursor.page_pin.node.data,
|
||||
self.screen.cursor.page_row,
|
||||
cells[0..end],
|
||||
);
|
||||
@ -2075,7 +2075,7 @@ pub fn eraseLine(
|
||||
// to fill the entire line.
|
||||
if (!protected) {
|
||||
self.screen.clearCells(
|
||||
&self.screen.cursor.page_pin.page.data,
|
||||
&self.screen.cursor.page_pin.node.data,
|
||||
self.screen.cursor.page_row,
|
||||
cells[start..end],
|
||||
);
|
||||
@ -2083,7 +2083,7 @@ pub fn eraseLine(
|
||||
}
|
||||
|
||||
self.screen.clearUnprotectedCells(
|
||||
&self.screen.cursor.page_pin.page.data,
|
||||
&self.screen.cursor.page_pin.node.data,
|
||||
self.screen.cursor.page_row,
|
||||
cells[start..end],
|
||||
);
|
||||
@ -2257,7 +2257,7 @@ pub fn decaln(self: *Terminal) !void {
|
||||
|
||||
// Fill with Es by moving the cursor but reset it after.
|
||||
while (true) {
|
||||
const page = &self.screen.cursor.page_pin.page.data;
|
||||
const page = &self.screen.cursor.page_pin.node.data;
|
||||
const row = self.screen.cursor.page_row;
|
||||
const cells_multi: [*]Cell = row.cells.ptr(page.memory);
|
||||
const cells = cells_multi[0..page.size.cols];
|
||||
@ -2986,7 +2986,7 @@ test "Terminal: print over wide char with bold" {
|
||||
try t.print(0x1F600); // Smiley face
|
||||
// verify we have styles in our style map
|
||||
{
|
||||
const page = &t.screen.cursor.page_pin.page.data;
|
||||
const page = &t.screen.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(@as(usize, 1), page.styles.count());
|
||||
}
|
||||
|
||||
@ -2997,7 +2997,7 @@ test "Terminal: print over wide char with bold" {
|
||||
|
||||
// verify our style is gone
|
||||
{
|
||||
const page = &t.screen.cursor.page_pin.page.data;
|
||||
const page = &t.screen.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(@as(usize, 0), page.styles.count());
|
||||
}
|
||||
|
||||
@ -3016,7 +3016,7 @@ test "Terminal: print over wide char with bg color" {
|
||||
try t.print(0x1F600); // Smiley face
|
||||
// verify we have styles in our style map
|
||||
{
|
||||
const page = &t.screen.cursor.page_pin.page.data;
|
||||
const page = &t.screen.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(@as(usize, 1), page.styles.count());
|
||||
}
|
||||
|
||||
@ -3027,7 +3027,7 @@ test "Terminal: print over wide char with bg color" {
|
||||
|
||||
// verify our style is gone
|
||||
{
|
||||
const page = &t.screen.cursor.page_pin.page.data;
|
||||
const page = &t.screen.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(@as(usize, 0), page.styles.count());
|
||||
}
|
||||
|
||||
@ -3058,7 +3058,7 @@ test "Terminal: print multicodepoint grapheme, disabled mode 2027" {
|
||||
try testing.expectEqual(@as(u21, 0x1F468), cell.content.codepoint);
|
||||
try testing.expect(cell.hasGrapheme());
|
||||
try testing.expectEqual(Cell.Wide.wide, cell.wide);
|
||||
const cps = list_cell.page.data.lookupGrapheme(cell).?;
|
||||
const cps = list_cell.node.data.lookupGrapheme(cell).?;
|
||||
try testing.expectEqual(@as(usize, 1), cps.len);
|
||||
}
|
||||
{
|
||||
@ -3067,7 +3067,7 @@ test "Terminal: print multicodepoint grapheme, disabled mode 2027" {
|
||||
try testing.expectEqual(@as(u21, 0), cell.content.codepoint);
|
||||
try testing.expect(!cell.hasGrapheme());
|
||||
try testing.expectEqual(Cell.Wide.spacer_tail, cell.wide);
|
||||
try testing.expect(list_cell.page.data.lookupGrapheme(cell) == null);
|
||||
try testing.expect(list_cell.node.data.lookupGrapheme(cell) == null);
|
||||
}
|
||||
{
|
||||
const list_cell = t.screen.pages.getCell(.{ .screen = .{ .x = 2, .y = 0 } }).?;
|
||||
@ -3075,7 +3075,7 @@ test "Terminal: print multicodepoint grapheme, disabled mode 2027" {
|
||||
try testing.expectEqual(@as(u21, 0x1F469), cell.content.codepoint);
|
||||
try testing.expect(cell.hasGrapheme());
|
||||
try testing.expectEqual(Cell.Wide.wide, cell.wide);
|
||||
const cps = list_cell.page.data.lookupGrapheme(cell).?;
|
||||
const cps = list_cell.node.data.lookupGrapheme(cell).?;
|
||||
try testing.expectEqual(@as(usize, 1), cps.len);
|
||||
}
|
||||
{
|
||||
@ -3084,7 +3084,7 @@ test "Terminal: print multicodepoint grapheme, disabled mode 2027" {
|
||||
try testing.expectEqual(@as(u21, 0), cell.content.codepoint);
|
||||
try testing.expect(!cell.hasGrapheme());
|
||||
try testing.expectEqual(Cell.Wide.spacer_tail, cell.wide);
|
||||
try testing.expect(list_cell.page.data.lookupGrapheme(cell) == null);
|
||||
try testing.expect(list_cell.node.data.lookupGrapheme(cell) == null);
|
||||
}
|
||||
{
|
||||
const list_cell = t.screen.pages.getCell(.{ .screen = .{ .x = 4, .y = 0 } }).?;
|
||||
@ -3092,7 +3092,7 @@ test "Terminal: print multicodepoint grapheme, disabled mode 2027" {
|
||||
try testing.expectEqual(@as(u21, 0x1F467), cell.content.codepoint);
|
||||
try testing.expect(!cell.hasGrapheme());
|
||||
try testing.expectEqual(Cell.Wide.wide, cell.wide);
|
||||
try testing.expect(list_cell.page.data.lookupGrapheme(cell) == null);
|
||||
try testing.expect(list_cell.node.data.lookupGrapheme(cell) == null);
|
||||
}
|
||||
{
|
||||
const list_cell = t.screen.pages.getCell(.{ .screen = .{ .x = 5, .y = 0 } }).?;
|
||||
@ -3100,7 +3100,7 @@ test "Terminal: print multicodepoint grapheme, disabled mode 2027" {
|
||||
try testing.expectEqual(@as(u21, 0), cell.content.codepoint);
|
||||
try testing.expect(!cell.hasGrapheme());
|
||||
try testing.expectEqual(Cell.Wide.spacer_tail, cell.wide);
|
||||
try testing.expect(list_cell.page.data.lookupGrapheme(cell) == null);
|
||||
try testing.expect(list_cell.node.data.lookupGrapheme(cell) == null);
|
||||
}
|
||||
|
||||
try testing.expect(t.isDirty(.{ .screen = .{ .x = 0, .y = 0 } }));
|
||||
@ -3128,7 +3128,7 @@ test "Terminal: VS16 doesn't make character with 2027 disabled" {
|
||||
try testing.expectEqual(@as(u21, 0x2764), cell.content.codepoint);
|
||||
try testing.expect(cell.hasGrapheme());
|
||||
try testing.expectEqual(Cell.Wide.narrow, cell.wide);
|
||||
const cps = list_cell.page.data.lookupGrapheme(cell).?;
|
||||
const cps = list_cell.node.data.lookupGrapheme(cell).?;
|
||||
try testing.expectEqual(@as(usize, 1), cps.len);
|
||||
}
|
||||
}
|
||||
@ -3221,7 +3221,7 @@ test "Terminal: print multicodepoint grapheme, mode 2027" {
|
||||
try testing.expectEqual(@as(u21, 0x1F468), cell.content.codepoint);
|
||||
try testing.expect(cell.hasGrapheme());
|
||||
try testing.expectEqual(Cell.Wide.wide, cell.wide);
|
||||
const cps = list_cell.page.data.lookupGrapheme(cell).?;
|
||||
const cps = list_cell.node.data.lookupGrapheme(cell).?;
|
||||
try testing.expectEqual(@as(usize, 4), cps.len);
|
||||
}
|
||||
{
|
||||
@ -3288,7 +3288,7 @@ test "Terminal: VS15 to make narrow character" {
|
||||
try testing.expectEqual(@as(u21, 0x26C8), cell.content.codepoint);
|
||||
try testing.expect(cell.hasGrapheme());
|
||||
try testing.expectEqual(Cell.Wide.narrow, cell.wide);
|
||||
const cps = list_cell.page.data.lookupGrapheme(cell).?;
|
||||
const cps = list_cell.node.data.lookupGrapheme(cell).?;
|
||||
try testing.expectEqual(@as(usize, 1), cps.len);
|
||||
}
|
||||
}
|
||||
@ -3319,7 +3319,7 @@ test "Terminal: VS16 to make wide character with mode 2027" {
|
||||
try testing.expectEqual(@as(u21, 0x2764), cell.content.codepoint);
|
||||
try testing.expect(cell.hasGrapheme());
|
||||
try testing.expectEqual(Cell.Wide.wide, cell.wide);
|
||||
const cps = list_cell.page.data.lookupGrapheme(cell).?;
|
||||
const cps = list_cell.node.data.lookupGrapheme(cell).?;
|
||||
try testing.expectEqual(@as(usize, 1), cps.len);
|
||||
}
|
||||
}
|
||||
@ -3350,7 +3350,7 @@ test "Terminal: VS16 repeated with mode 2027" {
|
||||
try testing.expectEqual(@as(u21, 0x2764), cell.content.codepoint);
|
||||
try testing.expect(cell.hasGrapheme());
|
||||
try testing.expectEqual(Cell.Wide.wide, cell.wide);
|
||||
const cps = list_cell.page.data.lookupGrapheme(cell).?;
|
||||
const cps = list_cell.node.data.lookupGrapheme(cell).?;
|
||||
try testing.expectEqual(@as(usize, 1), cps.len);
|
||||
}
|
||||
{
|
||||
@ -3359,7 +3359,7 @@ test "Terminal: VS16 repeated with mode 2027" {
|
||||
try testing.expectEqual(@as(u21, 0x2764), cell.content.codepoint);
|
||||
try testing.expect(cell.hasGrapheme());
|
||||
try testing.expectEqual(Cell.Wide.wide, cell.wide);
|
||||
const cps = list_cell.page.data.lookupGrapheme(cell).?;
|
||||
const cps = list_cell.node.data.lookupGrapheme(cell).?;
|
||||
try testing.expectEqual(@as(usize, 1), cps.len);
|
||||
}
|
||||
}
|
||||
@ -3482,7 +3482,7 @@ test "Terminal: overwrite multicodepoint grapheme clears grapheme data" {
|
||||
try testing.expectEqual(@as(usize, 2), t.screen.cursor.x);
|
||||
|
||||
// We should have one cell with graphemes
|
||||
const page = &t.screen.cursor.page_pin.page.data;
|
||||
const page = &t.screen.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(@as(usize, 1), page.graphemeCount());
|
||||
|
||||
// Move back and overwrite wide
|
||||
@ -3522,7 +3522,7 @@ test "Terminal: overwrite multicodepoint grapheme tail clears grapheme data" {
|
||||
try testing.expectEqual(@as(usize, 2), t.screen.cursor.x);
|
||||
|
||||
// We should have one cell with graphemes
|
||||
const page = &t.screen.cursor.page_pin.page.data;
|
||||
const page = &t.screen.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(@as(usize, 1), page.graphemeCount());
|
||||
|
||||
// Move back and overwrite wide
|
||||
@ -3971,7 +3971,7 @@ test "Terminal: print with hyperlink" {
|
||||
try testing.expect(row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell).?;
|
||||
const id = list_cell.node.data.lookupHyperlink(cell).?;
|
||||
try testing.expectEqual(@as(hyperlink.Id, 1), id);
|
||||
}
|
||||
|
||||
@ -3998,7 +3998,7 @@ test "Terminal: print over cell with same hyperlink" {
|
||||
try testing.expect(row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell).?;
|
||||
const id = list_cell.node.data.lookupHyperlink(cell).?;
|
||||
try testing.expectEqual(@as(hyperlink.Id, 1), id);
|
||||
}
|
||||
|
||||
@ -4025,7 +4025,7 @@ test "Terminal: print and end hyperlink" {
|
||||
try testing.expect(row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell).?;
|
||||
const id = list_cell.node.data.lookupHyperlink(cell).?;
|
||||
try testing.expectEqual(@as(hyperlink.Id, 1), id);
|
||||
}
|
||||
for (3..6) |x| {
|
||||
@ -4060,7 +4060,7 @@ test "Terminal: print and change hyperlink" {
|
||||
} }).?;
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell).?;
|
||||
const id = list_cell.node.data.lookupHyperlink(cell).?;
|
||||
try testing.expectEqual(@as(hyperlink.Id, 1), id);
|
||||
}
|
||||
for (3..6) |x| {
|
||||
@ -4070,7 +4070,7 @@ test "Terminal: print and change hyperlink" {
|
||||
} }).?;
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell).?;
|
||||
const id = list_cell.node.data.lookupHyperlink(cell).?;
|
||||
try testing.expectEqual(@as(hyperlink.Id, 2), id);
|
||||
}
|
||||
|
||||
@ -4094,7 +4094,7 @@ test "Terminal: overwrite hyperlink" {
|
||||
.x = @intCast(x),
|
||||
.y = 0,
|
||||
} }).?;
|
||||
const page = &list_cell.page.data;
|
||||
const page = &list_cell.node.data;
|
||||
const row = list_cell.row;
|
||||
try testing.expect(!row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
@ -4865,7 +4865,7 @@ test "Terminal: insertLines handles style refs" {
|
||||
try t.setAttribute(.{ .unset = {} });
|
||||
|
||||
// verify we have styles in our style map
|
||||
const page = &t.screen.cursor.page_pin.page.data;
|
||||
const page = &t.screen.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(@as(usize, 1), page.styles.count());
|
||||
|
||||
t.setCursorPos(2, 2);
|
||||
@ -5233,9 +5233,9 @@ test "Terminal: scrollUp moves hyperlink" {
|
||||
try testing.expect(row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell).?;
|
||||
const id = list_cell.node.data.lookupHyperlink(cell).?;
|
||||
try testing.expectEqual(@as(hyperlink.Id, 1), id);
|
||||
const page = &list_cell.page.data;
|
||||
const page = &list_cell.node.data;
|
||||
try testing.expectEqual(1, page.hyperlink_set.count());
|
||||
}
|
||||
for (0..3) |x| {
|
||||
@ -5247,7 +5247,7 @@ test "Terminal: scrollUp moves hyperlink" {
|
||||
try testing.expect(!row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(!cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell);
|
||||
const id = list_cell.node.data.lookupHyperlink(cell);
|
||||
try testing.expect(id == null);
|
||||
}
|
||||
}
|
||||
@ -5284,7 +5284,7 @@ test "Terminal: scrollUp clears hyperlink" {
|
||||
try testing.expect(!row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(!cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell);
|
||||
const id = list_cell.node.data.lookupHyperlink(cell);
|
||||
try testing.expect(id == null);
|
||||
}
|
||||
}
|
||||
@ -5386,7 +5386,7 @@ test "Terminal: scrollUp left/right scroll region hyperlink" {
|
||||
} }).?;
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(!cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell);
|
||||
const id = list_cell.node.data.lookupHyperlink(cell);
|
||||
try testing.expect(id == null);
|
||||
}
|
||||
for (1..4) |x| {
|
||||
@ -5398,9 +5398,9 @@ test "Terminal: scrollUp left/right scroll region hyperlink" {
|
||||
try testing.expect(row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell).?;
|
||||
const id = list_cell.node.data.lookupHyperlink(cell).?;
|
||||
try testing.expectEqual(@as(hyperlink.Id, 1), id);
|
||||
const page = &list_cell.page.data;
|
||||
const page = &list_cell.node.data;
|
||||
try testing.expectEqual(1, page.hyperlink_set.count());
|
||||
}
|
||||
for (4..6) |x| {
|
||||
@ -5410,7 +5410,7 @@ test "Terminal: scrollUp left/right scroll region hyperlink" {
|
||||
} }).?;
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(!cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell);
|
||||
const id = list_cell.node.data.lookupHyperlink(cell);
|
||||
try testing.expect(id == null);
|
||||
}
|
||||
}
|
||||
@ -5426,9 +5426,9 @@ test "Terminal: scrollUp left/right scroll region hyperlink" {
|
||||
try testing.expect(row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell).?;
|
||||
const id = list_cell.node.data.lookupHyperlink(cell).?;
|
||||
try testing.expectEqual(@as(hyperlink.Id, 1), id);
|
||||
const page = &list_cell.page.data;
|
||||
const page = &list_cell.node.data;
|
||||
try testing.expectEqual(1, page.hyperlink_set.count());
|
||||
}
|
||||
for (1..4) |x| {
|
||||
@ -5438,7 +5438,7 @@ test "Terminal: scrollUp left/right scroll region hyperlink" {
|
||||
} }).?;
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(!cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell);
|
||||
const id = list_cell.node.data.lookupHyperlink(cell);
|
||||
try testing.expect(id == null);
|
||||
}
|
||||
for (4..6) |x| {
|
||||
@ -5450,9 +5450,9 @@ test "Terminal: scrollUp left/right scroll region hyperlink" {
|
||||
try testing.expect(row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell).?;
|
||||
const id = list_cell.node.data.lookupHyperlink(cell).?;
|
||||
try testing.expectEqual(@as(hyperlink.Id, 1), id);
|
||||
const page = &list_cell.page.data;
|
||||
const page = &list_cell.node.data;
|
||||
try testing.expectEqual(1, page.hyperlink_set.count());
|
||||
}
|
||||
}
|
||||
@ -5596,9 +5596,9 @@ test "Terminal: scrollDown hyperlink moves" {
|
||||
try testing.expect(row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell).?;
|
||||
const id = list_cell.node.data.lookupHyperlink(cell).?;
|
||||
try testing.expectEqual(@as(hyperlink.Id, 1), id);
|
||||
const page = &list_cell.page.data;
|
||||
const page = &list_cell.node.data;
|
||||
try testing.expectEqual(1, page.hyperlink_set.count());
|
||||
}
|
||||
for (0..3) |x| {
|
||||
@ -5610,7 +5610,7 @@ test "Terminal: scrollDown hyperlink moves" {
|
||||
try testing.expect(!row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(!cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell);
|
||||
const id = list_cell.node.data.lookupHyperlink(cell);
|
||||
try testing.expect(id == null);
|
||||
}
|
||||
}
|
||||
@ -5720,9 +5720,9 @@ test "Terminal: scrollDown left/right scroll region hyperlink" {
|
||||
try testing.expect(row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell).?;
|
||||
const id = list_cell.node.data.lookupHyperlink(cell).?;
|
||||
try testing.expectEqual(@as(hyperlink.Id, 1), id);
|
||||
const page = &list_cell.page.data;
|
||||
const page = &list_cell.node.data;
|
||||
try testing.expectEqual(1, page.hyperlink_set.count());
|
||||
}
|
||||
for (1..4) |x| {
|
||||
@ -5732,7 +5732,7 @@ test "Terminal: scrollDown left/right scroll region hyperlink" {
|
||||
} }).?;
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(!cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell);
|
||||
const id = list_cell.node.data.lookupHyperlink(cell);
|
||||
try testing.expect(id == null);
|
||||
}
|
||||
for (4..6) |x| {
|
||||
@ -5744,9 +5744,9 @@ test "Terminal: scrollDown left/right scroll region hyperlink" {
|
||||
try testing.expect(row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell).?;
|
||||
const id = list_cell.node.data.lookupHyperlink(cell).?;
|
||||
try testing.expectEqual(@as(hyperlink.Id, 1), id);
|
||||
const page = &list_cell.page.data;
|
||||
const page = &list_cell.node.data;
|
||||
try testing.expectEqual(1, page.hyperlink_set.count());
|
||||
}
|
||||
}
|
||||
@ -5760,7 +5760,7 @@ test "Terminal: scrollDown left/right scroll region hyperlink" {
|
||||
} }).?;
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(!cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell);
|
||||
const id = list_cell.node.data.lookupHyperlink(cell);
|
||||
try testing.expect(id == null);
|
||||
}
|
||||
for (1..4) |x| {
|
||||
@ -5772,9 +5772,9 @@ test "Terminal: scrollDown left/right scroll region hyperlink" {
|
||||
try testing.expect(row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell).?;
|
||||
const id = list_cell.node.data.lookupHyperlink(cell).?;
|
||||
try testing.expectEqual(@as(hyperlink.Id, 1), id);
|
||||
const page = &list_cell.page.data;
|
||||
const page = &list_cell.node.data;
|
||||
try testing.expectEqual(1, page.hyperlink_set.count());
|
||||
}
|
||||
for (4..6) |x| {
|
||||
@ -5784,7 +5784,7 @@ test "Terminal: scrollDown left/right scroll region hyperlink" {
|
||||
} }).?;
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(!cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell);
|
||||
const id = list_cell.node.data.lookupHyperlink(cell);
|
||||
try testing.expect(id == null);
|
||||
}
|
||||
}
|
||||
@ -6018,7 +6018,7 @@ test "Terminal: eraseChars handles refcounted styles" {
|
||||
try t.print('C');
|
||||
|
||||
// verify we have styles in our style map
|
||||
const page = &t.screen.cursor.page_pin.page.data;
|
||||
const page = &t.screen.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(@as(usize, 1), page.styles.count());
|
||||
|
||||
t.setCursorPos(1, 1);
|
||||
@ -6095,7 +6095,7 @@ test "Terminal: eraseChars wide char boundary conditions" {
|
||||
|
||||
t.setCursorPos(1, 2);
|
||||
t.eraseChars(3);
|
||||
t.screen.cursor.page_pin.page.data.assertIntegrity();
|
||||
t.screen.cursor.page_pin.node.data.assertIntegrity();
|
||||
|
||||
{
|
||||
const str = try t.plainString(alloc);
|
||||
@ -6122,7 +6122,7 @@ test "Terminal: eraseChars wide char wrap boundary conditions" {
|
||||
|
||||
t.setCursorPos(2, 2);
|
||||
t.eraseChars(3);
|
||||
t.screen.cursor.page_pin.page.data.assertIntegrity();
|
||||
t.screen.cursor.page_pin.node.data.assertIntegrity();
|
||||
|
||||
{
|
||||
const str = try t.plainString(alloc);
|
||||
@ -6425,7 +6425,7 @@ test "Terminal: index scrolling with hyperlink" {
|
||||
try testing.expect(row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell).?;
|
||||
const id = list_cell.node.data.lookupHyperlink(cell).?;
|
||||
try testing.expectEqual(@as(hyperlink.Id, 1), id);
|
||||
}
|
||||
{
|
||||
@ -6437,7 +6437,7 @@ test "Terminal: index scrolling with hyperlink" {
|
||||
try testing.expect(!row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(!cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell);
|
||||
const id = list_cell.node.data.lookupHyperlink(cell);
|
||||
try testing.expect(id == null);
|
||||
}
|
||||
}
|
||||
@ -6599,7 +6599,7 @@ test "Terminal: index bottom of scroll region with hyperlinks" {
|
||||
try testing.expect(row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell).?;
|
||||
const id = list_cell.node.data.lookupHyperlink(cell).?;
|
||||
try testing.expectEqual(@as(hyperlink.Id, 1), id);
|
||||
}
|
||||
{
|
||||
@ -6611,7 +6611,7 @@ test "Terminal: index bottom of scroll region with hyperlinks" {
|
||||
try testing.expect(!row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(!cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell);
|
||||
const id = list_cell.node.data.lookupHyperlink(cell);
|
||||
try testing.expect(id == null);
|
||||
}
|
||||
}
|
||||
@ -6648,9 +6648,9 @@ test "Terminal: index bottom of scroll region clear hyperlinks" {
|
||||
try testing.expect(!row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(!cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell);
|
||||
const id = list_cell.node.data.lookupHyperlink(cell);
|
||||
try testing.expect(id == null);
|
||||
const page = &list_cell.page.data;
|
||||
const page = &list_cell.node.data;
|
||||
try testing.expectEqual(0, page.hyperlink_set.count());
|
||||
}
|
||||
}
|
||||
@ -7972,7 +7972,7 @@ test "Terminal: bold style" {
|
||||
const cell = list_cell.cell;
|
||||
try testing.expectEqual(@as(u21, 'A'), cell.content.codepoint);
|
||||
try testing.expect(cell.style_id != 0);
|
||||
const page = &t.screen.cursor.page_pin.page.data;
|
||||
const page = &t.screen.cursor.page_pin.node.data;
|
||||
try testing.expect(page.styles.refCount(page.memory, t.screen.cursor.style_id) > 1);
|
||||
}
|
||||
}
|
||||
@ -7996,7 +7996,7 @@ test "Terminal: garbage collect overwritten" {
|
||||
}
|
||||
|
||||
// verify we have no styles in our style map
|
||||
const page = &t.screen.cursor.page_pin.page.data;
|
||||
const page = &t.screen.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(@as(usize, 0), page.styles.count());
|
||||
}
|
||||
|
||||
@ -8018,7 +8018,7 @@ test "Terminal: do not garbage collect old styles in use" {
|
||||
}
|
||||
|
||||
// verify we have no styles in our style map
|
||||
const page = &t.screen.cursor.page_pin.page.data;
|
||||
const page = &t.screen.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(@as(usize, 1), page.styles.count());
|
||||
}
|
||||
|
||||
@ -8390,7 +8390,7 @@ test "Terminal: insertBlanks deleting graphemes" {
|
||||
try t.print(0x1F467);
|
||||
|
||||
// We should have one cell with graphemes
|
||||
const page = &t.screen.cursor.page_pin.page.data;
|
||||
const page = &t.screen.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(@as(usize, 1), page.graphemeCount());
|
||||
|
||||
t.setCursorPos(1, 1);
|
||||
@ -8426,7 +8426,7 @@ test "Terminal: insertBlanks shift graphemes" {
|
||||
try t.print(0x1F467);
|
||||
|
||||
// We should have one cell with graphemes
|
||||
const page = &t.screen.cursor.page_pin.page.data;
|
||||
const page = &t.screen.cursor.page_pin.node.data;
|
||||
try testing.expectEqual(@as(usize, 1), page.graphemeCount());
|
||||
|
||||
t.setCursorPos(1, 1);
|
||||
@ -8494,7 +8494,7 @@ test "Terminal: insertBlanks shifts hyperlinks" {
|
||||
try testing.expect(row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell).?;
|
||||
const id = list_cell.node.data.lookupHyperlink(cell).?;
|
||||
try testing.expectEqual(@as(hyperlink.Id, 1), id);
|
||||
}
|
||||
for (0..2) |x| {
|
||||
@ -8504,7 +8504,7 @@ test "Terminal: insertBlanks shifts hyperlinks" {
|
||||
} }).?;
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(!cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell);
|
||||
const id = list_cell.node.data.lookupHyperlink(cell);
|
||||
try testing.expect(id == null);
|
||||
}
|
||||
}
|
||||
@ -8534,7 +8534,7 @@ test "Terminal: insertBlanks pushes hyperlink off end completely" {
|
||||
try testing.expect(!row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(!cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell);
|
||||
const id = list_cell.node.data.lookupHyperlink(cell);
|
||||
try testing.expect(id == null);
|
||||
}
|
||||
}
|
||||
@ -9036,7 +9036,7 @@ test "Terminal: deleteChars wide char boundary conditions" {
|
||||
|
||||
t.setCursorPos(1, 2);
|
||||
t.deleteChars(3);
|
||||
t.screen.cursor.page_pin.page.data.assertIntegrity();
|
||||
t.screen.cursor.page_pin.node.data.assertIntegrity();
|
||||
|
||||
{
|
||||
const str = try t.plainString(alloc);
|
||||
@ -9088,7 +9088,7 @@ test "Terminal: deleteChars wide char wrap boundary conditions" {
|
||||
|
||||
t.setCursorPos(2, 2);
|
||||
t.deleteChars(3);
|
||||
t.screen.cursor.page_pin.page.data.assertIntegrity();
|
||||
t.screen.cursor.page_pin.node.data.assertIntegrity();
|
||||
|
||||
{
|
||||
const str = try t.plainString(alloc);
|
||||
@ -9127,7 +9127,7 @@ test "Terminal: deleteChars wide char across right margin" {
|
||||
|
||||
t.setCursorPos(1, 2);
|
||||
t.deleteChars(1);
|
||||
t.screen.cursor.page_pin.page.data.assertIntegrity();
|
||||
t.screen.cursor.page_pin.node.data.assertIntegrity();
|
||||
|
||||
// NOTE: This behavior is slightly inconsistent with xterm. xterm
|
||||
// _visually_ splits the wide character (half the wide character shows
|
||||
|
Reference in New Issue
Block a user