terminal: adjust page capacity for graphemes if necessary
parent
c0ed1fa370
commit
a59d4286c7
5
TODO.md
5
TODO.md
|
|
@ -20,8 +20,3 @@ Major Features:
|
||||||
|
|
||||||
- Bell
|
- Bell
|
||||||
- Sixels: https://saitoha.github.io/libsixel/
|
- Sixels: https://saitoha.github.io/libsixel/
|
||||||
|
|
||||||
paged-terminal branch:
|
|
||||||
|
|
||||||
- tests and logic for overflowing page capacities:
|
|
||||||
- graphemes
|
|
||||||
|
|
|
||||||
|
|
@ -1033,6 +1033,48 @@ pub fn manualStyleUpdate(self: *Screen) !void {
|
||||||
self.cursor.style_ref = &md.ref;
|
self.cursor.style_ref = &md.ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Append a grapheme to the given cell within the current cursor row.
|
||||||
|
pub fn appendGrapheme(self: *Screen, cell: *Cell, cp: u21) !void {
|
||||||
|
self.cursor.page_pin.page.data.appendGrapheme(
|
||||||
|
self.cursor.page_row,
|
||||||
|
cell,
|
||||||
|
cp,
|
||||||
|
) catch |err| switch (err) {
|
||||||
|
error.OutOfMemory => {
|
||||||
|
// We need to determine the actual cell index of the cell so
|
||||||
|
// that after we adjust the capacity we can reload the cell.
|
||||||
|
const cell_idx: usize = cell_idx: {
|
||||||
|
const cells: [*]Cell = @ptrCast(self.cursor.page_cell);
|
||||||
|
const zero: [*]Cell = cells - self.cursor.x;
|
||||||
|
const target: [*]Cell = @ptrCast(cell);
|
||||||
|
const cell_idx = (@intFromPtr(target) - @intFromPtr(zero)) / @sizeOf(Cell);
|
||||||
|
break :cell_idx cell_idx;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Adjust our capacity. This will update our cursor page pin and
|
||||||
|
// force us to reload.
|
||||||
|
const original_node = self.cursor.page_pin.page;
|
||||||
|
const new_bytes = original_node.data.capacity.grapheme_bytes * 2;
|
||||||
|
_ = try self.pages.adjustCapacity(original_node, .{ .grapheme_bytes = new_bytes });
|
||||||
|
self.cursorReload();
|
||||||
|
|
||||||
|
// The cell pointer is now invalid, so we need to get it from
|
||||||
|
// the reloaded cursor pointers.
|
||||||
|
const reloaded_cell: *Cell = switch (std.math.order(cell_idx, self.cursor.x)) {
|
||||||
|
.eq => self.cursor.page_cell,
|
||||||
|
.lt => self.cursorCellLeft(@intCast(self.cursor.x - cell_idx)),
|
||||||
|
.gt => self.cursorCellRight(@intCast(cell_idx - self.cursor.x)),
|
||||||
|
};
|
||||||
|
|
||||||
|
try self.cursor.page_pin.page.data.appendGrapheme(
|
||||||
|
self.cursor.page_row,
|
||||||
|
reloaded_cell,
|
||||||
|
cp,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the selection to the given selection. If this is a tracked selection
|
/// Set the selection to the given selection. If this is a tracked selection
|
||||||
/// then the screen will take overnship of the selection. If this is untracked
|
/// then the screen will take overnship of the selection. If this is untracked
|
||||||
/// then the screen will convert it to tracked internally. This will automatically
|
/// then the screen will convert it to tracked internally. This will automatically
|
||||||
|
|
|
||||||
|
|
@ -351,11 +351,7 @@ pub fn print(self: *Terminal, c: u21) !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("c={x} grapheme attach to left={}", .{ c, prev.left });
|
log.debug("c={x} grapheme attach to left={}", .{ c, prev.left });
|
||||||
try self.screen.cursor.page_pin.page.data.appendGrapheme(
|
try self.screen.appendGrapheme(prev.cell, c);
|
||||||
self.screen.cursor.page_row,
|
|
||||||
prev.cell,
|
|
||||||
c,
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -408,11 +404,7 @@ pub fn print(self: *Terminal, c: u21) !void {
|
||||||
if (!emoji) return;
|
if (!emoji) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try self.screen.cursor.page_pin.page.data.appendGrapheme(
|
try self.screen.appendGrapheme(prev, c);
|
||||||
self.screen.cursor.page_row,
|
|
||||||
prev,
|
|
||||||
c,
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2299,6 +2291,17 @@ test "Terminal: input unique style per cell" {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "Terminal: input glitch text" {
|
||||||
|
const glitch = @embedFile("res/glitch.txt");
|
||||||
|
const alloc = testing.allocator;
|
||||||
|
var t = try init(alloc, .{ .cols = 30, .rows = 30 });
|
||||||
|
defer t.deinit(alloc);
|
||||||
|
|
||||||
|
for (0..100) |_| {
|
||||||
|
try t.printString(glitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
test "Terminal: zero-width character at start" {
|
test "Terminal: zero-width character at start" {
|
||||||
var t = try init(testing.allocator, .{ .cols = 80, .rows = 80 });
|
var t = try init(testing.allocator, .{ .cols = 80, .rows = 80 });
|
||||||
defer t.deinit(testing.allocator);
|
defer t.deinit(testing.allocator);
|
||||||
|
|
|
||||||
|
|
@ -373,7 +373,7 @@ pub const Page = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Append a codepoint to the given cell as a grapheme.
|
/// Append a codepoint to the given cell as a grapheme.
|
||||||
pub fn appendGrapheme(self: *Page, row: *Row, cell: *Cell, cp: u21) !void {
|
pub fn appendGrapheme(self: *Page, row: *Row, cell: *Cell, cp: u21) Allocator.Error!void {
|
||||||
if (comptime std.debug.runtime_safety) assert(cell.hasText());
|
if (comptime std.debug.runtime_safety) assert(cell.hasText());
|
||||||
|
|
||||||
const cell_offset = getOffset(Cell, self.memory, cell);
|
const cell_offset = getOffset(Cell, self.memory, cell);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Ḡ̴͎͍̜͎͔͕̩̗͕͖̟̜͑̊̌̇̑͒͋͑̄̈́͐̈́́̽͌͂̎̀̔͋̓́̅̌̇͘̕͜͝͝h̶̡̞̫͉̳̬̜̱̥͕͑̾͛̒̆̒̉̒̑͂̄͘ͅǫ̷̨̥͔͔͖̭͚͙̯̟̭̘͇̫̰͚̺̳̙̳̟͚̫̱̹̱͒̂̑͒͜͠ͅş̴̖̰̜̱̹͙̅͒̀̏͆̐̋͂̓͋̃̈̔̂̈͛̐̿̔́̔̄͑̇͑̋̈́͌͋̾̃̽̈́̕͘̚͘͘͘͠͠t̵̢̜̱̦͇͉̬̮̼͖̳̗̥̝̬͇͕̥̜͕̳̱̥̮͉̮̩̘̰̪̤͉͎̲͈͍̳̟̠͈̝̫͋̊̀͐̍̅̀̄̃̈́̔̇̈́̄̃̽̂̌̅̄̋͒̃̈́̍̀̍̇̽̐͊̾̆̅̈̿̓͒̄̾͌̚͝͝͝͝͝t̴̥̼̳̗̬̬͔͎̯͉͇̮̰͖͇̝͔̳̳̗̰͇͎͉̬͇̝̺̯͎͖͔̍͆͒̊̒̔̊̈́̿̊̅͂̐͋̿͂̈̒̄͜͠͠ÿ̴̢̗̜̥͇͖̰͎̝̹̗̪̙̞̣̳͎̯̹͚̲̝̗̳̳̗̖͎̗̬͈͙̝̟͍̥̤͖͇̰͈̺͛̒̂͌̌̏̈̾̓̈́̿͐̂̓̔̓̂̈́͑͛͊͋̔̿̊͑͌̊̏͘͘̕͘͠͝
|
||||||
Loading…
Reference in New Issue