this repo has no description
13
fork

Configure Feed

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

feat: add support for creating kitty secondary cursors

authored by

CJ van den Berg and committed by
Tim Culverhouse
86cac58a d4f4ab93

+76 -20
+3 -2
src/Screen.zig
··· 8 8 const Method = @import("gwidth.zig").Method; 9 9 10 10 const Screen = @This(); 11 + pub const Cursor = struct { row: u16 = 0, col: u16 = 0 }; 11 12 12 13 width: u16 = 0, 13 14 height: u16 = 0, ··· 17 18 18 19 buf: []Cell = &.{}, 19 20 20 - cursor_row: u16 = 0, 21 - cursor_col: u16 = 0, 21 + cursor: Cursor = .{}, 22 22 cursor_vis: bool = false, 23 + cursor_secondary: []Cursor = &.{}, 23 24 24 25 width_method: Method = .wcwidth, 25 26
+66 -16
src/Vaxis.zig
··· 11 11 const Key = @import("Key.zig"); 12 12 const Mouse = @import("Mouse.zig"); 13 13 const Screen = @import("Screen.zig"); 14 + const Cursor = Screen.Cursor; 14 15 const unicode = @import("unicode.zig"); 15 16 const Window = @import("Window.zig"); 16 17 ··· 96 97 changed_default_fg: bool = false, 97 98 changed_default_bg: bool = false, 98 99 changed_cursor_color: bool = false, 99 - cursor: struct { 100 - row: u16 = 0, 101 - col: u16 = 0, 102 - } = .{}, 100 + cursor: Cursor = .{}, 101 + cursor_secondary: []Cursor = &.{}, 102 + prev_cursor_secondary: []const Cursor = &.{}, 103 103 } = .{}, 104 104 105 105 /// Initialize Vaxis with runtime options ··· 119 119 self.resetState(tty) catch {}; 120 120 121 121 if (alloc) |a| { 122 + if (self.state.prev_cursor_secondary.ptr != self.screen.cursor_secondary.ptr) 123 + a.free(self.state.prev_cursor_secondary); 124 + a.free(self.screen.cursor_secondary); 122 125 self.screen.deinit(a); 123 126 self.screen_last.deinit(a); 124 127 } ··· 368 371 const cursor_shape_changed = self.screen.cursor_shape != self.screen_last.cursor_shape; 369 372 const mouse_shape_changed = self.screen.mouse_shape != self.screen_last.mouse_shape; 370 373 const cursor_pos_changed = self.screen.cursor_vis and 371 - (self.screen.cursor_row != self.state.cursor.row or 372 - self.screen.cursor_col != self.state.cursor.col); 373 - const needs_render = self.refresh or cursor_vis_changed or cursor_shape_changed or mouse_shape_changed or cursor_pos_changed; 374 + (self.screen.cursor.row != self.state.cursor.row or 375 + self.screen.cursor.col != self.state.cursor.col); 376 + const cursor_secondary_changed = self.screen.cursor_vis and 377 + std.meta.eql(self.screen.cursor_secondary, self.state.cursor_secondary); 378 + const needs_render = self.refresh or 379 + cursor_vis_changed or 380 + cursor_shape_changed or 381 + mouse_shape_changed or 382 + cursor_pos_changed or 383 + cursor_secondary_changed; 374 384 375 385 // initialize some variables 376 386 var reposition: bool = false; ··· 763 773 try tty.print( 764 774 ctlseqs.cup, 765 775 .{ 766 - self.screen.cursor_row + 1, 767 - self.screen.cursor_col + 1, 776 + self.screen.cursor.row + 1, 777 + self.screen.cursor.col + 1, 768 778 }, 769 779 ); 770 780 } else { 771 781 // TODO: position cursor relative to current location 772 782 try tty.writeByte('\r'); 773 - if (self.screen.cursor_row >= cursor_pos.row) { 774 - for (0..(self.screen.cursor_row - cursor_pos.row)) |_| { 783 + if (self.screen.cursor.row >= cursor_pos.row) { 784 + for (0..(self.screen.cursor.row - cursor_pos.row)) |_| { 775 785 try tty.writeByte('\n'); 776 786 } 777 787 } else { 778 - for (0..(cursor_pos.row - self.screen.cursor_row)) |_| { 788 + for (0..(cursor_pos.row - self.screen.cursor.row)) |_| { 779 789 try tty.writeAll(ctlseqs.ri); 780 790 } 781 791 } 782 - if (self.screen.cursor_col > 0) 783 - try tty.print(ctlseqs.cuf, .{self.screen.cursor_col}); 792 + if (self.screen.cursor.col > 0) 793 + try tty.print(ctlseqs.cuf, .{self.screen.cursor.col}); 784 794 } 785 - self.state.cursor.row = self.screen.cursor_row; 786 - self.state.cursor.col = self.screen.cursor_col; 795 + self.state.cursor.row = self.screen.cursor.row; 796 + self.state.cursor.col = self.screen.cursor.col; 787 797 try tty.writeAll(ctlseqs.show_cursor); 788 798 } else { 789 799 self.state.cursor.row = cursor_pos.row; 790 800 self.state.cursor.col = cursor_pos.col; 801 + } 802 + if (self.screen.cursor_vis) { 803 + try tty.print(ctlseqs.reset_secondary_cursors, .{}); 804 + for (self.screen.cursor_secondary) |cur| 805 + try tty.print(ctlseqs.show_secondary_cursor, .{ cur.row + 1, cur.col + 1 }); 806 + if (cursor_secondary_changed) { 807 + self.state.prev_cursor_secondary = self.state.cursor_secondary; 808 + self.state.cursor_secondary = self.screen.cursor_secondary; 809 + } 791 810 } 792 811 self.screen_last.cursor_vis = self.screen.cursor_vis; 793 812 if (self.screen.mouse_shape != self.screen_last.mouse_shape) { ··· 1113 1132 try tty.print(ctlseqs.osc12_set, .{ rgb[0], rgb[0], rgb[1], rgb[1], rgb[2], rgb[2] }); 1114 1133 try tty.flush(); 1115 1134 self.state.changed_cursor_color = true; 1135 + } 1136 + 1137 + /// Set the terminal secondary cursor color 1138 + pub fn setTerminalCursorSecondaryColor(self: *Vaxis, tty: *IoWriter, rgb: [3]u8) error{WriteFailed}!void { 1139 + try tty.print(ctlseqs.secondary_cursors_rgb, .{ rgb[0], rgb[1], rgb[2] }); 1140 + try tty.flush(); 1141 + self.state.changed_cursor_color = true; 1142 + } 1143 + 1144 + pub fn resetAllTerminalSecondaryCursors(self: *Vaxis, alloc: std.mem.Allocator) error{OutOfMemory}!void { 1145 + if (self.state.prev_cursor_secondary.ptr != self.state.cursor_secondary.ptr) { 1146 + alloc.free(self.state.prev_cursor_secondary); 1147 + self.state.prev_cursor_secondary = &.{}; 1148 + } 1149 + if (self.screen.cursor_secondary.ptr != self.state.cursor_secondary.ptr) 1150 + alloc.free(self.screen.cursor_secondary); 1151 + self.screen.cursor_secondary = &.{}; 1152 + } 1153 + 1154 + pub fn addTerminalSecondaryCursor(self: *Vaxis, alloc: std.mem.Allocator, y: u16, x: u16) error{OutOfMemory}!void { 1155 + if (self.state.prev_cursor_secondary.ptr != self.state.cursor_secondary.ptr) { 1156 + alloc.free(self.state.prev_cursor_secondary); 1157 + self.state.prev_cursor_secondary = &.{}; 1158 + } 1159 + var cursors: std.ArrayList(Screen.Cursor) = if (self.screen.cursor_secondary.ptr == self.state.cursor_secondary.ptr) 1160 + .fromOwnedSlice(try alloc.dupe(Cursor, self.screen.cursor_secondary)) 1161 + else 1162 + .fromOwnedSlice(self.screen.cursor_secondary); 1163 + 1164 + (try cursors.addOne(alloc)).* = .{ .row = y, .col = x }; 1165 + self.screen.cursor_secondary = try cursors.toOwnedSlice(alloc); 1116 1166 } 1117 1167 1118 1168 /// Request a color report from the terminal. Note: not all terminals support
+2 -2
src/Window.zig
··· 248 248 col >= self.width) 249 249 return; 250 250 self.screen.cursor_vis = true; 251 - self.screen.cursor_row = @intCast(row + self.y_off); 252 - self.screen.cursor_col = @intCast(col + self.x_off); 251 + self.screen.cursor.row = @intCast(row + self.y_off); 252 + self.screen.cursor.col = @intCast(col + self.x_off); 253 253 } 254 254 255 255 pub fn setCursorShape(self: Window, shape: Cell.CursorShape) void {
+5
src/ctlseqs.zig
··· 65 65 pub const cuf = "\x1b[{d}C"; 66 66 pub const cub = "\x1b[{d}D"; 67 67 68 + // Multi Cursor 69 + pub const secondary_cursors_rgb = "\x1b[>40;2:{d}:{d}:{d} q"; 70 + pub const reset_secondary_cursors = "\x1b[>0;4 q"; 71 + pub const show_secondary_cursor = "\x1b[>29;2:{d}:{d} q"; 72 + 68 73 // Erase 69 74 pub const erase_below_cursor = "\x1b[J"; 70 75