this repo has no description
13
fork

Configure Feed

Select the types of activity you want to include in your feed.

vaxis: implement hyperlinks (osc8)

This requires additional allocations anytime there is a hyperlink

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>

+41 -16
+1 -1
README.md
··· 18 18 | Feature | Vaxis | libvaxis | notcurses | 19 19 | ------------------------------ | :---: | :------: | :-------: | 20 20 | RGB | ✅ | ✅ | ✅ | 21 - | Hyperlinks | ✅ | planned | ❌ | 21 + | Hyperlinks | ✅ | ✅ | ❌ | 22 22 | Bracketed Paste | ✅ | ✅ | ❌ | 23 23 | Kitty Keyboard | ✅ | ✅ | ✅ | 24 24 | Styled Underlines | ✅ | ✅ | ✅ |
+21 -5
src/InternalScreen.zig
··· 11 11 pub const InternalCell = struct { 12 12 char: std.ArrayList(u8) = undefined, 13 13 style: Style = .{}, 14 + uri: std.ArrayList(u8) = undefined, 15 + uri_id: std.ArrayList(u8) = undefined, 14 16 // if we got skipped because of a wide character 15 17 skipped: bool = false, 16 18 17 19 pub fn eql(self: InternalCell, cell: Cell) bool { 18 - return std.mem.eql(u8, self.char.items, cell.char.grapheme) and std.meta.eql(self.style, cell.style); 20 + return std.mem.eql(u8, self.char.items, cell.char.grapheme) and 21 + std.meta.eql(self.style, cell.style) and 22 + std.mem.eql(u8, self.uri.items, cell.link.uri) and 23 + std.mem.eql(u8, self.uri_id.items, cell.link.params); 19 24 } 20 25 }; 21 26 ··· 37 42 for (screen.buf, 0..) |_, i| { 38 43 screen.buf[i] = .{ 39 44 .char = try std.ArrayList(u8).initCapacity(alloc, 1), 45 + .uri = std.ArrayList(u8).init(alloc), 46 + .uri_id = std.ArrayList(u8).init(alloc), 40 47 }; 41 48 } 42 49 screen.width = w; ··· 47 54 pub fn deinit(self: *InternalScreen, alloc: std.mem.Allocator) void { 48 55 for (self.buf, 0..) |_, i| { 49 56 self.buf[i].char.deinit(); 57 + self.buf[i].uri.deinit(); 58 + self.buf[i].uri_id.deinit(); 50 59 } 51 60 52 61 alloc.free(self.buf); ··· 57 66 self: *InternalScreen, 58 67 col: usize, 59 68 row: usize, 60 - char: []const u8, 61 - style: Style, 69 + cell: Cell, 62 70 ) void { 63 71 if (self.width < col) { 64 72 // column out of bounds ··· 71 79 const i = (row * self.width) + col; 72 80 assert(i < self.buf.len); 73 81 self.buf[i].char.clearRetainingCapacity(); 74 - self.buf[i].char.appendSlice(char) catch { 82 + self.buf[i].char.appendSlice(cell.char.grapheme) catch { 75 83 log.warn("couldn't write grapheme", .{}); 76 84 }; 77 - self.buf[i].style = style; 85 + self.buf[i].uri.clearRetainingCapacity(); 86 + self.buf[i].uri.appendSlice(cell.link.uri) catch { 87 + log.warn("couldn't write uri", .{}); 88 + }; 89 + self.buf[i].uri.clearRetainingCapacity(); 90 + self.buf[i].uri_id.appendSlice(cell.link.params) catch { 91 + log.warn("couldn't write uri_id", .{}); 92 + }; 93 + self.buf[i].style = cell.style; 78 94 }
+7 -2
src/cell.zig
··· 1 1 pub const Cell = struct { 2 2 char: Character = .{}, 3 3 style: Style = .{}, 4 + link: Hyperlink = .{}, 4 5 }; 5 6 6 7 pub const Character = struct { 7 8 grapheme: []const u8 = " ", 8 9 width: usize = 1, 10 + }; 11 + 12 + pub const Hyperlink = struct { 13 + uri: []const u8 = "", 14 + /// ie "id=app-1234" 15 + params: []const u8 = "", 9 16 }; 10 17 11 18 pub const Style = struct { ··· 24 31 ul_style: Underline = .off, 25 32 // TODO: url should maybe go outside of style. We'll need to allocate these 26 33 // in the internal screen 27 - url: ?[]const u8 = null, 28 - url_params: ?[]const u8 = null, 29 34 30 35 bold: bool = false, 31 36 dim: bool = false,
+12 -8
src/vaxis.zig
··· 11 11 const Window = @import("Window.zig"); 12 12 const Options = @import("Options.zig"); 13 13 const Style = @import("cell.zig").Style; 14 + const Hyperlink = @import("cell.zig").Hyperlink; 14 15 const gwidth = @import("gwidth.zig"); 15 16 const Shape = @import("Mouse.zig").Shape; 16 17 ··· 275 276 var row: usize = 0; 276 277 var col: usize = 0; 277 278 var cursor: Style = .{}; 279 + var link: Hyperlink = .{}; 278 280 279 281 var i: usize = 0; 280 282 while (i < self.screen.buf.len) { ··· 301 303 reposition = true; 302 304 // Close any osc8 sequence we might be in before 303 305 // repositioning 304 - if (cursor.url) |_| { 306 + if (link.uri.len > 0) { 305 307 _ = try tty.write(ctlseqs.osc8_clear); 306 308 } 307 309 continue; 308 310 } 309 311 self.screen_last.buf[i].skipped = false; 310 - defer cursor = cell.style; 312 + defer { 313 + cursor = cell.style; 314 + link = cell.link; 315 + } 311 316 // Set this cell in the last frame 312 - self.screen_last.writeCell(col, row, cell.char.grapheme, cell.style); 317 + self.screen_last.writeCell(col, row, cell); 313 318 314 319 // reposition the cursor, if needed 315 320 if (reposition) { ··· 442 447 } 443 448 444 449 // url 445 - if (!std.meta.eql(cursor.url, cell.style.url)) { 446 - const url = cell.style.url orelse ""; 447 - var ps = cell.style.url_params orelse ""; 448 - if (url.len == 0) { 450 + if (!std.meta.eql(link.uri, cell.link.uri)) { 451 + var ps = cell.link.params; 452 + if (cell.link.uri.len == 0) { 449 453 // Empty out the params no matter what if we don't have 450 454 // a url 451 455 ps = ""; 452 456 } 453 457 const writer = tty.buffered_writer.writer(); 454 - try std.fmt.format(writer, ctlseqs.osc8, .{ ps, url }); 458 + try std.fmt.format(writer, ctlseqs.osc8, .{ ps, cell.link.uri }); 455 459 } 456 460 _ = try tty.write(cell.char.grapheme); 457 461 }