mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-24 04:36:10 +03:00
renderer: convert link to new state
This commit is contained in:
@ -64,11 +64,13 @@ pub const Set = struct {
|
||||
self: *const Set,
|
||||
alloc: Allocator,
|
||||
screen: *Screen,
|
||||
mouse_vp_pt: point.Viewport,
|
||||
mouse_vp_pt: point.Coordinate,
|
||||
mouse_mods: inputpkg.Mods,
|
||||
) !MatchSet {
|
||||
// Convert the viewport point to a screen point.
|
||||
const mouse_pt = mouse_vp_pt.toScreen(screen);
|
||||
const mouse_pin = screen.pages.pin(.{
|
||||
.viewport = mouse_vp_pt,
|
||||
}) orelse return .{};
|
||||
|
||||
// This contains our list of matches. The matches are stored
|
||||
// as selections which contain the start and end points of
|
||||
@ -78,14 +80,25 @@ pub const Set = struct {
|
||||
defer matches.deinit();
|
||||
|
||||
// Iterate over all the visible lines.
|
||||
var lineIter = screen.lineIterator(.viewport);
|
||||
while (lineIter.next()) |line| {
|
||||
const strmap = line.stringMap(alloc) catch |err| {
|
||||
log.warn(
|
||||
"failed to build string map for link checking err={}",
|
||||
.{err},
|
||||
);
|
||||
continue;
|
||||
var lineIter = screen.lineIterator(screen.pages.pin(.{
|
||||
.viewport = .{},
|
||||
}) orelse return .{});
|
||||
while (lineIter.next()) |line_sel| {
|
||||
const strmap: terminal.StringMap = strmap: {
|
||||
var strmap: terminal.StringMap = undefined;
|
||||
const str = screen.selectionString(alloc, .{
|
||||
.sel = line_sel,
|
||||
.trim = false,
|
||||
.map = &strmap,
|
||||
}) catch |err| {
|
||||
log.warn(
|
||||
"failed to build string map for link checking err={}",
|
||||
.{err},
|
||||
);
|
||||
continue;
|
||||
};
|
||||
alloc.free(str);
|
||||
break :strmap strmap;
|
||||
};
|
||||
defer strmap.deinit(alloc);
|
||||
|
||||
@ -98,7 +111,7 @@ pub const Set = struct {
|
||||
.always => {},
|
||||
.always_mods => |v| if (!mouse_mods.equal(v)) continue,
|
||||
inline .hover, .hover_mods => |v, tag| {
|
||||
if (!line.selection().contains(mouse_pt)) continue;
|
||||
if (!line_sel.contains(screen, mouse_pin)) continue;
|
||||
if (comptime tag == .hover_mods) {
|
||||
if (!mouse_mods.equal(v)) continue;
|
||||
}
|
||||
@ -121,7 +134,7 @@ pub const Set = struct {
|
||||
.always, .always_mods => {},
|
||||
.hover,
|
||||
.hover_mods,
|
||||
=> if (!sel.contains(mouse_pt)) continue,
|
||||
=> if (!sel.contains(screen, mouse_pin)) continue,
|
||||
}
|
||||
|
||||
try matches.append(sel);
|
||||
@ -153,156 +166,228 @@ pub const MatchSet = struct {
|
||||
/// results.
|
||||
pub fn orderedContains(
|
||||
self: *MatchSet,
|
||||
pt: point.ScreenPoint,
|
||||
screen: *const Screen,
|
||||
pin: terminal.Pin,
|
||||
) bool {
|
||||
// If we're beyond the end of our possible matches, we're done.
|
||||
if (self.i >= self.matches.len) return false;
|
||||
|
||||
// If our selection ends before the point, then no point will ever
|
||||
// again match this selection so we move on to the next one.
|
||||
while (self.matches[self.i].end.before(pt)) {
|
||||
while (self.matches[self.i].end().before(pin)) {
|
||||
self.i += 1;
|
||||
if (self.i >= self.matches.len) return false;
|
||||
}
|
||||
|
||||
return self.matches[self.i].contains(pt);
|
||||
return self.matches[self.i].contains(screen, pin);
|
||||
}
|
||||
};
|
||||
|
||||
// TODO(paged-terminal)
|
||||
// test "matchset" {
|
||||
// const testing = std.testing;
|
||||
// const alloc = testing.allocator;
|
||||
//
|
||||
// // Initialize our screen
|
||||
// var s = try Screen.init(alloc, 5, 5, 0);
|
||||
// defer s.deinit();
|
||||
// const str = "1ABCD2EFGH\n3IJKL";
|
||||
// try s.testWriteString(str);
|
||||
//
|
||||
// // Get a set
|
||||
// var set = try Set.fromConfig(alloc, &.{
|
||||
// .{
|
||||
// .regex = "AB",
|
||||
// .action = .{ .open = {} },
|
||||
// .highlight = .{ .always = {} },
|
||||
// },
|
||||
//
|
||||
// .{
|
||||
// .regex = "EF",
|
||||
// .action = .{ .open = {} },
|
||||
// .highlight = .{ .always = {} },
|
||||
// },
|
||||
// });
|
||||
// defer set.deinit(alloc);
|
||||
//
|
||||
// // Get our matches
|
||||
// var match = try set.matchSet(alloc, &s, .{}, .{});
|
||||
// defer match.deinit(alloc);
|
||||
// try testing.expectEqual(@as(usize, 2), match.matches.len);
|
||||
//
|
||||
// // Test our matches
|
||||
// try testing.expect(!match.orderedContains(.{ .x = 0, .y = 0 }));
|
||||
// try testing.expect(match.orderedContains(.{ .x = 1, .y = 0 }));
|
||||
// try testing.expect(match.orderedContains(.{ .x = 2, .y = 0 }));
|
||||
// try testing.expect(!match.orderedContains(.{ .x = 3, .y = 0 }));
|
||||
// try testing.expect(match.orderedContains(.{ .x = 1, .y = 1 }));
|
||||
// try testing.expect(!match.orderedContains(.{ .x = 1, .y = 2 }));
|
||||
// }
|
||||
//
|
||||
// test "matchset hover links" {
|
||||
// const testing = std.testing;
|
||||
// const alloc = testing.allocator;
|
||||
//
|
||||
// // Initialize our screen
|
||||
// var s = try Screen.init(alloc, 5, 5, 0);
|
||||
// defer s.deinit();
|
||||
// const str = "1ABCD2EFGH\n3IJKL";
|
||||
// try s.testWriteString(str);
|
||||
//
|
||||
// // Get a set
|
||||
// var set = try Set.fromConfig(alloc, &.{
|
||||
// .{
|
||||
// .regex = "AB",
|
||||
// .action = .{ .open = {} },
|
||||
// .highlight = .{ .hover = {} },
|
||||
// },
|
||||
//
|
||||
// .{
|
||||
// .regex = "EF",
|
||||
// .action = .{ .open = {} },
|
||||
// .highlight = .{ .always = {} },
|
||||
// },
|
||||
// });
|
||||
// defer set.deinit(alloc);
|
||||
//
|
||||
// // Not hovering over the first link
|
||||
// {
|
||||
// var match = try set.matchSet(alloc, &s, .{}, .{});
|
||||
// defer match.deinit(alloc);
|
||||
// try testing.expectEqual(@as(usize, 1), match.matches.len);
|
||||
//
|
||||
// // Test our matches
|
||||
// try testing.expect(!match.orderedContains(.{ .x = 0, .y = 0 }));
|
||||
// try testing.expect(!match.orderedContains(.{ .x = 1, .y = 0 }));
|
||||
// try testing.expect(!match.orderedContains(.{ .x = 2, .y = 0 }));
|
||||
// try testing.expect(!match.orderedContains(.{ .x = 3, .y = 0 }));
|
||||
// try testing.expect(match.orderedContains(.{ .x = 1, .y = 1 }));
|
||||
// try testing.expect(!match.orderedContains(.{ .x = 1, .y = 2 }));
|
||||
// }
|
||||
//
|
||||
// // Hovering over the first link
|
||||
// {
|
||||
// var match = try set.matchSet(alloc, &s, .{ .x = 1, .y = 0 }, .{});
|
||||
// defer match.deinit(alloc);
|
||||
// try testing.expectEqual(@as(usize, 2), match.matches.len);
|
||||
//
|
||||
// // Test our matches
|
||||
// try testing.expect(!match.orderedContains(.{ .x = 0, .y = 0 }));
|
||||
// try testing.expect(match.orderedContains(.{ .x = 1, .y = 0 }));
|
||||
// try testing.expect(match.orderedContains(.{ .x = 2, .y = 0 }));
|
||||
// try testing.expect(!match.orderedContains(.{ .x = 3, .y = 0 }));
|
||||
// try testing.expect(match.orderedContains(.{ .x = 1, .y = 1 }));
|
||||
// try testing.expect(!match.orderedContains(.{ .x = 1, .y = 2 }));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// test "matchset mods no match" {
|
||||
// const testing = std.testing;
|
||||
// const alloc = testing.allocator;
|
||||
//
|
||||
// // Initialize our screen
|
||||
// var s = try Screen.init(alloc, 5, 5, 0);
|
||||
// defer s.deinit();
|
||||
// const str = "1ABCD2EFGH\n3IJKL";
|
||||
// try s.testWriteString(str);
|
||||
//
|
||||
// // Get a set
|
||||
// var set = try Set.fromConfig(alloc, &.{
|
||||
// .{
|
||||
// .regex = "AB",
|
||||
// .action = .{ .open = {} },
|
||||
// .highlight = .{ .always = {} },
|
||||
// },
|
||||
//
|
||||
// .{
|
||||
// .regex = "EF",
|
||||
// .action = .{ .open = {} },
|
||||
// .highlight = .{ .always_mods = .{ .ctrl = true } },
|
||||
// },
|
||||
// });
|
||||
// defer set.deinit(alloc);
|
||||
//
|
||||
// // Get our matches
|
||||
// var match = try set.matchSet(alloc, &s, .{}, .{});
|
||||
// defer match.deinit(alloc);
|
||||
// try testing.expectEqual(@as(usize, 1), match.matches.len);
|
||||
//
|
||||
// // Test our matches
|
||||
// try testing.expect(!match.orderedContains(.{ .x = 0, .y = 0 }));
|
||||
// try testing.expect(match.orderedContains(.{ .x = 1, .y = 0 }));
|
||||
// try testing.expect(match.orderedContains(.{ .x = 2, .y = 0 }));
|
||||
// try testing.expect(!match.orderedContains(.{ .x = 3, .y = 0 }));
|
||||
// try testing.expect(!match.orderedContains(.{ .x = 1, .y = 1 }));
|
||||
// try testing.expect(!match.orderedContains(.{ .x = 1, .y = 2 }));
|
||||
// }
|
||||
test "matchset" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
// Initialize our screen
|
||||
var s = try Screen.init(alloc, 5, 5, 0);
|
||||
defer s.deinit();
|
||||
const str = "1ABCD2EFGH\n3IJKL";
|
||||
try s.testWriteString(str);
|
||||
|
||||
// Get a set
|
||||
var set = try Set.fromConfig(alloc, &.{
|
||||
.{
|
||||
.regex = "AB",
|
||||
.action = .{ .open = {} },
|
||||
.highlight = .{ .always = {} },
|
||||
},
|
||||
|
||||
.{
|
||||
.regex = "EF",
|
||||
.action = .{ .open = {} },
|
||||
.highlight = .{ .always = {} },
|
||||
},
|
||||
});
|
||||
defer set.deinit(alloc);
|
||||
|
||||
// Get our matches
|
||||
var match = try set.matchSet(alloc, &s, .{}, .{});
|
||||
defer match.deinit(alloc);
|
||||
try testing.expectEqual(@as(usize, 2), match.matches.len);
|
||||
|
||||
// Test our matches
|
||||
try testing.expect(!match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
} }).?));
|
||||
try testing.expect(match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 1,
|
||||
.y = 0,
|
||||
} }).?));
|
||||
try testing.expect(match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 2,
|
||||
.y = 0,
|
||||
} }).?));
|
||||
try testing.expect(!match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 3,
|
||||
.y = 0,
|
||||
} }).?));
|
||||
try testing.expect(match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 1,
|
||||
.y = 1,
|
||||
} }).?));
|
||||
try testing.expect(!match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 1,
|
||||
.y = 2,
|
||||
} }).?));
|
||||
}
|
||||
|
||||
test "matchset hover links" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
// Initialize our screen
|
||||
var s = try Screen.init(alloc, 5, 5, 0);
|
||||
defer s.deinit();
|
||||
const str = "1ABCD2EFGH\n3IJKL";
|
||||
try s.testWriteString(str);
|
||||
|
||||
// Get a set
|
||||
var set = try Set.fromConfig(alloc, &.{
|
||||
.{
|
||||
.regex = "AB",
|
||||
.action = .{ .open = {} },
|
||||
.highlight = .{ .hover = {} },
|
||||
},
|
||||
|
||||
.{
|
||||
.regex = "EF",
|
||||
.action = .{ .open = {} },
|
||||
.highlight = .{ .always = {} },
|
||||
},
|
||||
});
|
||||
defer set.deinit(alloc);
|
||||
|
||||
// Not hovering over the first link
|
||||
{
|
||||
var match = try set.matchSet(alloc, &s, .{}, .{});
|
||||
defer match.deinit(alloc);
|
||||
try testing.expectEqual(@as(usize, 1), match.matches.len);
|
||||
|
||||
// Test our matches
|
||||
try testing.expect(!match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
} }).?));
|
||||
try testing.expect(!match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 1,
|
||||
.y = 0,
|
||||
} }).?));
|
||||
try testing.expect(!match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 2,
|
||||
.y = 0,
|
||||
} }).?));
|
||||
try testing.expect(!match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 3,
|
||||
.y = 0,
|
||||
} }).?));
|
||||
try testing.expect(match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 1,
|
||||
.y = 1,
|
||||
} }).?));
|
||||
try testing.expect(!match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 1,
|
||||
.y = 2,
|
||||
} }).?));
|
||||
}
|
||||
|
||||
// Hovering over the first link
|
||||
{
|
||||
var match = try set.matchSet(alloc, &s, .{ .x = 1, .y = 0 }, .{});
|
||||
defer match.deinit(alloc);
|
||||
try testing.expectEqual(@as(usize, 2), match.matches.len);
|
||||
|
||||
// Test our matches
|
||||
try testing.expect(!match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
} }).?));
|
||||
try testing.expect(match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 1,
|
||||
.y = 0,
|
||||
} }).?));
|
||||
try testing.expect(match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 2,
|
||||
.y = 0,
|
||||
} }).?));
|
||||
try testing.expect(!match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 3,
|
||||
.y = 0,
|
||||
} }).?));
|
||||
try testing.expect(match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 1,
|
||||
.y = 1,
|
||||
} }).?));
|
||||
try testing.expect(!match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 1,
|
||||
.y = 2,
|
||||
} }).?));
|
||||
}
|
||||
}
|
||||
|
||||
test "matchset mods no match" {
|
||||
const testing = std.testing;
|
||||
const alloc = testing.allocator;
|
||||
|
||||
// Initialize our screen
|
||||
var s = try Screen.init(alloc, 5, 5, 0);
|
||||
defer s.deinit();
|
||||
const str = "1ABCD2EFGH\n3IJKL";
|
||||
try s.testWriteString(str);
|
||||
|
||||
// Get a set
|
||||
var set = try Set.fromConfig(alloc, &.{
|
||||
.{
|
||||
.regex = "AB",
|
||||
.action = .{ .open = {} },
|
||||
.highlight = .{ .always = {} },
|
||||
},
|
||||
|
||||
.{
|
||||
.regex = "EF",
|
||||
.action = .{ .open = {} },
|
||||
.highlight = .{ .always_mods = .{ .ctrl = true } },
|
||||
},
|
||||
});
|
||||
defer set.deinit(alloc);
|
||||
|
||||
// Get our matches
|
||||
var match = try set.matchSet(alloc, &s, .{}, .{});
|
||||
defer match.deinit(alloc);
|
||||
try testing.expectEqual(@as(usize, 1), match.matches.len);
|
||||
|
||||
// Test our matches
|
||||
try testing.expect(!match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
} }).?));
|
||||
try testing.expect(match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 1,
|
||||
.y = 0,
|
||||
} }).?));
|
||||
try testing.expect(match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 2,
|
||||
.y = 0,
|
||||
} }).?));
|
||||
try testing.expect(!match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 3,
|
||||
.y = 0,
|
||||
} }).?));
|
||||
try testing.expect(!match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 1,
|
||||
.y = 1,
|
||||
} }).?));
|
||||
try testing.expect(!match.orderedContains(&s, s.pages.pin(.{ .screen = .{
|
||||
.x = 1,
|
||||
.y = 2,
|
||||
} }).?));
|
||||
}
|
||||
|
Reference in New Issue
Block a user