terminal: fix possible crash when increasing columns in resize

If a cell has graphemes attached to it, we'd share the grapheme map.
This copies it.
This commit is contained in:
Mitchell Hashimoto
2022-11-26 17:43:58 -08:00
parent d64b0e371e
commit 3fbeca914b

View File

@ -1760,6 +1760,11 @@ pub fn resize(self: *Screen, rows: usize, cols: usize) !void {
errdefer self.storage.deinit(self.alloc); errdefer self.storage.deinit(self.alloc);
defer old.storage.deinit(self.alloc); defer old.storage.deinit(self.alloc);
// Copy grapheme map
self.graphemes = .{};
errdefer self.deinitGraphemes();
defer old.deinitGraphemes();
// Convert our cursor coordinates to screen coordinates because // Convert our cursor coordinates to screen coordinates because
// we may have to reflow the cursor if the line it is on is unwrapped. // we may have to reflow the cursor if the line it is on is unwrapped.
const cursor_pos = (point.Viewport{ const cursor_pos = (point.Viewport{
@ -1914,6 +1919,11 @@ pub fn resize(self: *Screen, rows: usize, cols: usize) !void {
errdefer self.storage.deinit(self.alloc); errdefer self.storage.deinit(self.alloc);
defer old.storage.deinit(self.alloc); defer old.storage.deinit(self.alloc);
// Copy grapheme map
self.graphemes = .{};
errdefer self.deinitGraphemes();
defer old.deinitGraphemes();
// Convert our cursor coordinates to screen coordinates because // Convert our cursor coordinates to screen coordinates because
// we may have to reflow the cursor if the line it is on is moved. // we may have to reflow the cursor if the line it is on is moved.
var cursor_pos = (point.Viewport{ var cursor_pos = (point.Viewport{
@ -3728,6 +3738,44 @@ test "Screen: resize more cols no reflow" {
} }
} }
test "Screen: resize more cols grapheme map" {
const testing = std.testing;
const alloc = testing.allocator;
var s = try init(alloc, 3, 5, 0);
defer s.deinit();
const str = "1ABCD\n2EFGH\n3IJKL";
try s.testWriteString(str);
// Attach graphemes to all the columns
{
var iter = s.rowIterator(.viewport);
while (iter.next()) |row| {
var col: usize = 0;
while (col < s.cols) : (col += 1) {
try row.attachGrapheme(col, 0xFE0F);
}
}
}
const cursor = s.cursor;
try s.resize(3, 10);
// Cursor should not move
try testing.expectEqual(cursor, s.cursor);
{
var contents = try s.testString(alloc, .viewport);
defer alloc.free(contents);
try testing.expectEqualStrings(str, contents);
}
{
var contents = try s.testString(alloc, .screen);
defer alloc.free(contents);
try testing.expectEqualStrings(str, contents);
}
}
test "Screen: resize more cols with reflow that fits full width" { test "Screen: resize more cols with reflow that fits full width" {
const testing = std.testing; const testing = std.testing;
const alloc = testing.allocator; const alloc = testing.allocator;
@ -4051,6 +4099,46 @@ test "Screen: resize less cols no reflow" {
} }
} }
test "Screen: resize less cols with graphemes" {
const testing = std.testing;
const alloc = testing.allocator;
var s = try init(alloc, 3, 5, 0);
defer s.deinit();
const str = "1AB\n2EF\n3IJ";
try s.testWriteString(str);
// Attach graphemes to all the columns
{
var iter = s.rowIterator(.viewport);
while (iter.next()) |row| {
var col: usize = 0;
while (col < 3) : (col += 1) {
try row.attachGrapheme(col, 0xFE0F);
}
}
}
s.cursor.x = 0;
s.cursor.y = 0;
const cursor = s.cursor;
try s.resize(3, 3);
// Cursor should not move
try testing.expectEqual(cursor, s.cursor);
{
var contents = try s.testString(alloc, .viewport);
defer alloc.free(contents);
try testing.expectEqualStrings(str, contents);
}
{
var contents = try s.testString(alloc, .screen);
defer alloc.free(contents);
try testing.expectEqualStrings(str, contents);
}
}
test "Screen: resize less cols with reflow but row space" { test "Screen: resize less cols with reflow but row space" {
const testing = std.testing; const testing = std.testing;
const alloc = testing.allocator; const alloc = testing.allocator;