mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 00:36:07 +03:00
terminal: index hyperlink tests
This commit is contained in:
@ -5809,6 +5809,51 @@ test "Terminal: index from the bottom" {
|
||||
}
|
||||
}
|
||||
|
||||
test "Terminal: index scrolling with hyperlink" {
|
||||
const alloc = testing.allocator;
|
||||
var t = try init(alloc, .{ .cols = 2, .rows = 5 });
|
||||
defer t.deinit(alloc);
|
||||
|
||||
t.setCursorPos(5, 1);
|
||||
try t.screen.startHyperlink("http://example.com", null);
|
||||
try t.print('A');
|
||||
t.screen.endHyperlink();
|
||||
t.cursorLeft(1); // undo moving right from 'A'
|
||||
try t.index();
|
||||
try t.print('B');
|
||||
|
||||
{
|
||||
const str = try t.plainString(testing.allocator);
|
||||
defer testing.allocator.free(str);
|
||||
try testing.expectEqualStrings("\n\n\nA\nB", str);
|
||||
}
|
||||
|
||||
{
|
||||
const list_cell = t.screen.pages.getCell(.{ .viewport = .{
|
||||
.x = 0,
|
||||
.y = 3,
|
||||
} }).?;
|
||||
const row = list_cell.row;
|
||||
try testing.expect(row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell).?;
|
||||
try testing.expectEqual(@as(hyperlink.Id, 1), id);
|
||||
}
|
||||
{
|
||||
const list_cell = t.screen.pages.getCell(.{ .viewport = .{
|
||||
.x = 0,
|
||||
.y = 4,
|
||||
} }).?;
|
||||
const row = list_cell.row;
|
||||
try testing.expect(!row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(!cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell);
|
||||
try testing.expect(id == null);
|
||||
}
|
||||
}
|
||||
|
||||
test "Terminal: index outside of scrolling region" {
|
||||
const alloc = testing.allocator;
|
||||
var t = try init(alloc, .{ .cols = 2, .rows = 5 });
|
||||
@ -5935,6 +5980,92 @@ test "Terminal: index inside scroll region" {
|
||||
}
|
||||
}
|
||||
|
||||
test "Terminal: index bottom of scroll region with hyperlinks" {
|
||||
const alloc = testing.allocator;
|
||||
var t = try init(alloc, .{ .rows = 5, .cols = 5 });
|
||||
defer t.deinit(alloc);
|
||||
|
||||
t.setTopAndBottomMargin(1, 2);
|
||||
try t.print('A');
|
||||
try t.index();
|
||||
t.carriageReturn();
|
||||
try t.screen.startHyperlink("http://example.com", null);
|
||||
try t.print('B');
|
||||
t.screen.endHyperlink();
|
||||
try t.index();
|
||||
t.carriageReturn();
|
||||
try t.print('C');
|
||||
|
||||
{
|
||||
const str = try t.plainString(testing.allocator);
|
||||
defer testing.allocator.free(str);
|
||||
try testing.expectEqualStrings("B\nC", str);
|
||||
}
|
||||
|
||||
{
|
||||
const list_cell = t.screen.pages.getCell(.{ .viewport = .{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
} }).?;
|
||||
const row = list_cell.row;
|
||||
try testing.expect(row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell).?;
|
||||
try testing.expectEqual(@as(hyperlink.Id, 1), id);
|
||||
}
|
||||
{
|
||||
const list_cell = t.screen.pages.getCell(.{ .viewport = .{
|
||||
.x = 0,
|
||||
.y = 1,
|
||||
} }).?;
|
||||
const row = list_cell.row;
|
||||
try testing.expect(!row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(!cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell);
|
||||
try testing.expect(id == null);
|
||||
}
|
||||
}
|
||||
|
||||
test "Terminal: index bottom of scroll region clear hyperlinks" {
|
||||
const alloc = testing.allocator;
|
||||
var t = try init(alloc, .{ .rows = 5, .cols = 5 });
|
||||
defer t.deinit(alloc);
|
||||
|
||||
t.setTopAndBottomMargin(1, 2);
|
||||
try t.screen.startHyperlink("http://example.com", null);
|
||||
try t.print('A');
|
||||
t.screen.endHyperlink();
|
||||
try t.index();
|
||||
t.carriageReturn();
|
||||
try t.print('B');
|
||||
try t.index();
|
||||
t.carriageReturn();
|
||||
try t.print('C');
|
||||
|
||||
{
|
||||
const str = try t.plainString(testing.allocator);
|
||||
defer testing.allocator.free(str);
|
||||
try testing.expectEqualStrings("B\nC", str);
|
||||
}
|
||||
|
||||
for (0..2) |y| {
|
||||
const list_cell = t.screen.pages.getCell(.{ .viewport = .{
|
||||
.x = 0,
|
||||
.y = @intCast(y),
|
||||
} }).?;
|
||||
const row = list_cell.row;
|
||||
try testing.expect(!row.hyperlink);
|
||||
const cell = list_cell.cell;
|
||||
try testing.expect(!cell.hyperlink);
|
||||
const id = list_cell.page.data.lookupHyperlink(cell);
|
||||
try testing.expect(id == null);
|
||||
const page = &list_cell.page.data;
|
||||
try testing.expectEqual(0, page.hyperlink_set.count());
|
||||
}
|
||||
}
|
||||
|
||||
test "Terminal: index bottom of scroll region with background SGR" {
|
||||
const alloc = testing.allocator;
|
||||
var t = try init(alloc, .{ .rows = 5, .cols = 5 });
|
||||
|
@ -615,9 +615,7 @@ pub const Page = struct {
|
||||
|
||||
// If our destination has styles or graphemes then we need to
|
||||
// clear some state.
|
||||
if (dst_row.grapheme or dst_row.styled) {
|
||||
self.clearCells(dst_row, x_start, x_end);
|
||||
}
|
||||
if (dst_row.managedMemory()) self.clearCells(dst_row, x_start, x_end);
|
||||
|
||||
// Copy all the row metadata but keep our cells offset
|
||||
dst_row.* = copy: {
|
||||
@ -640,7 +638,7 @@ pub const Page = struct {
|
||||
|
||||
// If we have no managed memory in the source, then we can just
|
||||
// copy it directly.
|
||||
if (!src_row.grapheme and !src_row.styled) {
|
||||
if (!src_row.managedMemory()) {
|
||||
fastmem.copy(Cell, cells, other_cells);
|
||||
} else {
|
||||
// We have managed memory, so we have to do a slower copy to
|
||||
@ -655,6 +653,26 @@ pub const Page = struct {
|
||||
const cps = other.lookupGrapheme(src_cell).?;
|
||||
for (cps) |cp| try self.appendGrapheme(dst_row, dst_cell, cp);
|
||||
}
|
||||
if (src_cell.hyperlink) hyperlink: {
|
||||
dst_row.hyperlink = true;
|
||||
|
||||
// Fast-path: same page we can move it directly
|
||||
if (other == self) {
|
||||
self.moveHyperlink(src_cell, dst_cell);
|
||||
break :hyperlink;
|
||||
}
|
||||
|
||||
// Slow-path: get the hyperlink from the other page,
|
||||
// add it, and migrate.
|
||||
const id = other.lookupHyperlink(src_cell).?;
|
||||
const other_link = other.hyperlink_set.get(other.memory, id);
|
||||
const dst_id = try self.hyperlink_set.addContext(
|
||||
self.memory,
|
||||
other_link.*,
|
||||
.{ .page = self },
|
||||
);
|
||||
try self.setHyperlink(dst_row, dst_cell, dst_id);
|
||||
}
|
||||
if (src_cell.style_id != style.default_id) {
|
||||
dst_row.styled = true;
|
||||
|
||||
@ -668,8 +686,12 @@ pub const Page = struct {
|
||||
|
||||
// Slow path: Get the style from the other
|
||||
// page and add it to this page's style set.
|
||||
const other_style = other.styles.get(other.memory, src_cell.style_id).*;
|
||||
if (try self.styles.addWithId(self.memory, other_style, src_cell.style_id)) |id| {
|
||||
const other_style = other.styles.get(other.memory, src_cell.style_id);
|
||||
if (try self.styles.addWithId(
|
||||
self.memory,
|
||||
other_style.*,
|
||||
src_cell.style_id,
|
||||
)) |id| {
|
||||
dst_cell.style_id = id;
|
||||
}
|
||||
}
|
||||
@ -1365,6 +1387,12 @@ pub const Row = packed struct(u64) {
|
||||
return self == .prompt or self == .prompt_continuation or self == .input;
|
||||
}
|
||||
};
|
||||
|
||||
/// Returns true if this row has any managed memory outside of the
|
||||
/// row structure (graphemes, styles, etc.)
|
||||
fn managedMemory(self: Row) bool {
|
||||
return self.grapheme or self.styled or self.hyperlink;
|
||||
}
|
||||
};
|
||||
|
||||
/// A cell represents a single terminal grid cell.
|
||||
|
Reference in New Issue
Block a user