mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +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" {
|
test "Terminal: index outside of scrolling region" {
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var t = try init(alloc, .{ .cols = 2, .rows = 5 });
|
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" {
|
test "Terminal: index bottom of scroll region with background SGR" {
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
var t = try init(alloc, .{ .rows = 5, .cols = 5 });
|
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
|
// If our destination has styles or graphemes then we need to
|
||||||
// clear some state.
|
// clear some state.
|
||||||
if (dst_row.grapheme or dst_row.styled) {
|
if (dst_row.managedMemory()) self.clearCells(dst_row, x_start, x_end);
|
||||||
self.clearCells(dst_row, x_start, x_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy all the row metadata but keep our cells offset
|
// Copy all the row metadata but keep our cells offset
|
||||||
dst_row.* = copy: {
|
dst_row.* = copy: {
|
||||||
@ -640,7 +638,7 @@ pub const Page = struct {
|
|||||||
|
|
||||||
// If we have no managed memory in the source, then we can just
|
// If we have no managed memory in the source, then we can just
|
||||||
// copy it directly.
|
// copy it directly.
|
||||||
if (!src_row.grapheme and !src_row.styled) {
|
if (!src_row.managedMemory()) {
|
||||||
fastmem.copy(Cell, cells, other_cells);
|
fastmem.copy(Cell, cells, other_cells);
|
||||||
} else {
|
} else {
|
||||||
// We have managed memory, so we have to do a slower copy to
|
// 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).?;
|
const cps = other.lookupGrapheme(src_cell).?;
|
||||||
for (cps) |cp| try self.appendGrapheme(dst_row, dst_cell, cp);
|
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) {
|
if (src_cell.style_id != style.default_id) {
|
||||||
dst_row.styled = true;
|
dst_row.styled = true;
|
||||||
|
|
||||||
@ -668,8 +686,12 @@ pub const Page = struct {
|
|||||||
|
|
||||||
// Slow path: Get the style from the other
|
// Slow path: Get the style from the other
|
||||||
// page and add it to this page's style set.
|
// page and add it to this page's style set.
|
||||||
const other_style = other.styles.get(other.memory, src_cell.style_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| {
|
if (try self.styles.addWithId(
|
||||||
|
self.memory,
|
||||||
|
other_style.*,
|
||||||
|
src_cell.style_id,
|
||||||
|
)) |id| {
|
||||||
dst_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;
|
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.
|
/// A cell represents a single terminal grid cell.
|
||||||
|
Reference in New Issue
Block a user