this repo has no description
13
fork

Configure Feed

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

widgets: remove neovim widget

The neovim widget was great. But we have a full virtual terminal widget
now, which doesn't bring in extra dependencies.

-860
-8
build.zig
··· 3 3 pub fn build(b: *std.Build) void { 4 4 const include_libxev = b.option(bool, "libxev", "Enable support for libxev library (default: true)") orelse true; 5 5 const include_images = b.option(bool, "images", "Enable support for images (default: true)") orelse true; 6 - const include_nvim = b.option(bool, "nvim", "Enable support for the neovim widget (default: true)") orelse true; 7 6 const include_text_input = b.option(bool, "text_input", "Enable support for the TextInput widget (default: true)") orelse true; 8 7 9 8 const options = b.addOptions(); 10 9 options.addOption(bool, "libxev", include_libxev); 11 10 options.addOption(bool, "images", include_images); 12 - options.addOption(bool, "nvim", include_nvim); 13 11 options.addOption(bool, "text_input", include_text_input); 14 12 15 13 const options_mod = options.createModule(); ··· 31 29 .optimize = optimize, 32 30 .target = target, 33 31 }) else null; 34 - const znvim_dep = if (include_nvim) b.lazyDependency("znvim", .{ 35 - .optimize = optimize, 36 - .target = target, 37 - }) else null; 38 32 const xev_dep = if (include_libxev) b.lazyDependency("libxev", .{ 39 33 .optimize = optimize, 40 34 .target = target, ··· 51 45 vaxis_mod.addImport("DisplayWidth", zg_dep.module("DisplayWidth")); 52 46 if (zigimg_dep) |dep| vaxis_mod.addImport("zigimg", dep.module("zigimg")); 53 47 if (gap_buffer_dep) |dep| vaxis_mod.addImport("gap_buffer", dep.module("gap_buffer")); 54 - if (znvim_dep) |dep| vaxis_mod.addImport("znvim", dep.module("znvim")); 55 48 if (xev_dep) |dep| vaxis_mod.addImport("xev", dep.module("xev")); 56 49 vaxis_mod.addImport("build_options", options_mod); 57 50 ··· 97 90 tests.root_module.addImport("DisplayWidth", zg_dep.module("DisplayWidth")); 98 91 if (zigimg_dep) |dep| tests.root_module.addImport("zigimg", dep.module("zigimg")); 99 92 if (gap_buffer_dep) |dep| tests.root_module.addImport("gap_buffer", dep.module("gap_buffer")); 100 - if (znvim_dep) |dep| tests.root_module.addImport("znvim", dep.module("znvim")); 101 93 tests.root_module.addImport("build_options", options_mod); 102 94 103 95 const tests_run = b.addRunArtifact(tests);
-5
build.zig.zon
··· 13 13 .hash = "1220f525973ae804ec0284556bfc47db7b6a8dc86464a853956ef859d6e0fb5fa93b", 14 14 .lazy = true, 15 15 }, 16 - .znvim = .{ 17 - .url = "git+https://github.com/jinzhongjia/znvim#515fb2784f7b0db2ea7a0021aada8d4aa89a08fe", 18 - .hash = "1220ca0a762fdf3172623e3f15890e396c975657d8ec57d907896f74ef94a37b73f2", 19 - .lazy = true, 20 - }, 21 16 .zg = .{ 22 17 .url = "git+https://codeberg.org/dude_the_builder/zg?ref=master#689ab6b83d08c02724b99d199d650ff731250998", 23 18 .hash = "12200d1ce5f9733a9437415d85665ad5fbc85a4d27689fd337fecad8014acffe3aa5",
-83
examples/nvim.zig
··· 1 - const std = @import("std"); 2 - const vaxis = @import("vaxis"); 3 - const Cell = vaxis.Cell; 4 - 5 - // Our Event. This can contain internal events as well as Vaxis events. 6 - // Internal events can be posted into the same queue as vaxis events to allow 7 - // for a single event loop with exhaustive switching. Booya 8 - const Event = union(enum) { 9 - key_press: vaxis.Key, 10 - winsize: vaxis.Winsize, 11 - focus_in, 12 - nvim: vaxis.widgets.nvim.Event, 13 - }; 14 - 15 - pub fn main() !void { 16 - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; 17 - defer { 18 - const deinit_status = gpa.deinit(); 19 - //fail test; can't try in defer as defer is executed after we return 20 - if (deinit_status == .leak) { 21 - std.log.err("memory leak", .{}); 22 - } 23 - } 24 - const alloc = gpa.allocator(); 25 - 26 - var tty = try vaxis.Tty.init(); 27 - defer tty.deinit(); 28 - 29 - // Initialize Vaxis 30 - var vx = try vaxis.init(alloc, .{}); 31 - defer vx.deinit(alloc, tty.anyWriter()); 32 - 33 - var loop: vaxis.Loop(Event) = .{ .tty = &tty, .vaxis = &vx }; 34 - try loop.init(); 35 - 36 - try loop.start(); 37 - defer loop.stop(); 38 - 39 - // Optionally enter the alternate screen 40 - // try vx.enterAltScreen(tty.anyWriter()); 41 - try vx.queryTerminal(tty.anyWriter(), 1 * std.time.ns_per_s); 42 - 43 - var nvim = try vaxis.widgets.nvim.Nvim(Event).init(alloc, &loop); 44 - try nvim.spawn(); 45 - defer nvim.deinit(); 46 - 47 - // The main event loop. Vaxis provides a thread safe, blocking, buffered 48 - // queue which can serve as the primary event queue for an application 49 - while (true) { 50 - // nextEvent blocks until an event is in the queue 51 - const event = loop.nextEvent(); 52 - std.log.debug("event: {}", .{event}); 53 - // exhaustive switching ftw. Vaxis will send events if your Event 54 - // enum has the fields for those events (ie "key_press", "winsize") 55 - switch (event) { 56 - .key_press => |key| { 57 - try nvim.update(.{ .key_press = key }); 58 - }, 59 - .winsize => |ws| { 60 - try vx.resize(alloc, tty.anyWriter(), ws); 61 - }, 62 - .nvim => |nvim_event| { 63 - switch (nvim_event) { 64 - .redraw => {}, 65 - .quit => return, 66 - } 67 - }, 68 - else => {}, 69 - } 70 - 71 - const win = vx.window(); 72 - win.clear(); 73 - const child = win.child( 74 - .{ 75 - .height = .{ .limit = 40 }, 76 - .width = .{ .limit = 80 }, 77 - .border = .{ .where = .all }, 78 - }, 79 - ); 80 - try nvim.draw(child); 81 - try vx.render(tty.anyWriter()); 82 - } 83 - }
-1
src/widgets.zig
··· 15 15 // Widgets with dependencies 16 16 17 17 pub const TextInput = if (opts.text_input) @import("widgets/TextInput.zig") else undefined; 18 - pub const nvim = if (opts.nvim) @import("widgets/nvim.zig") else undefined;
-763
src/widgets/nvim.zig
··· 1 - const std = @import("std"); 2 - const assert = std.debug.assert; 3 - const vaxis = @import("../main.zig"); 4 - const znvim = @import("znvim"); 5 - 6 - pub const Event = union(enum) { 7 - redraw: *anyopaque, 8 - quit: *anyopaque, 9 - }; 10 - 11 - pub fn Nvim(comptime T: type) type { 12 - if (!@hasField(T, "nvim")) { 13 - @compileError("Nvim widget requires an Event to have an 'nvim' event of type Nvim.Event"); 14 - } 15 - return struct { 16 - const Self = @This(); 17 - const Client = znvim.DefaultClient(.file); 18 - const EventType = T; 19 - 20 - const log = std.log.scoped(.nvim); 21 - 22 - /// vaxis events handled by Nvim 23 - pub const VaxisEvent = union(enum) { 24 - key_press: vaxis.Key, 25 - }; 26 - 27 - alloc: std.mem.Allocator, 28 - 29 - /// true when we have spawned 30 - spawned: bool = false, 31 - /// true when we have ui attached 32 - attached: bool = false, 33 - 34 - client: ?Client = null, 35 - 36 - /// draw mutex. We lock access to the internal model while drawing 37 - mutex: std.Thread.Mutex = .{}, 38 - 39 - /// the child process 40 - process: std.ChildProcess, 41 - 42 - thread: ?std.Thread = null, 43 - 44 - screen: vaxis.AllocatingScreen = undefined, 45 - visible_screen: vaxis.AllocatingScreen = undefined, 46 - 47 - hl_map: HighlightMap, 48 - 49 - loop: *vaxis.Loop(T), 50 - dirty: bool = false, 51 - mode_set: std.ArrayList(Mode), 52 - 53 - /// initialize nvim. Starts the nvim process. UI is not attached until the first 54 - /// call to draw 55 - pub fn init(alloc: std.mem.Allocator, loop: *vaxis.Loop(T)) !Self { 56 - const args = [_][]const u8{ "nvim", "--embed" }; 57 - var nvim = std.ChildProcess.init(&args, alloc); 58 - 59 - // set to use pipe 60 - nvim.stdin_behavior = .Pipe; 61 - // set to use pipe 62 - nvim.stdout_behavior = .Pipe; 63 - // set ignore 64 - nvim.stderr_behavior = .Ignore; 65 - 66 - // try spwan 67 - try nvim.spawn(); 68 - return .{ 69 - .alloc = alloc, 70 - .process = nvim, 71 - .hl_map = HighlightMap.init(alloc), 72 - .loop = loop, 73 - .mode_set = std.ArrayList(Mode).init(alloc), 74 - }; 75 - } 76 - 77 - /// spawns the client thread and registers callbacks 78 - pub fn spawn(self: *Self) !void { 79 - if (self.spawned) return; 80 - defer self.spawned = true; 81 - 82 - // get stdin and stdout pipe 83 - assert(self.process.stdin != null); 84 - assert(self.process.stdout != null); 85 - const nvim_stdin = self.process.stdin.?; 86 - const nvim_stdout = self.process.stdout.?; 87 - 88 - self.client = try Client.init( 89 - nvim_stdin, 90 - nvim_stdout, 91 - self.alloc, 92 - ); 93 - 94 - self.thread = try std.Thread.spawn(.{}, Self.nvimLoop, .{self}); 95 - } 96 - 97 - pub fn deinit(self: *Self) void { 98 - if (self.client) |*client| { 99 - client.deinit(); 100 - } 101 - _ = self.process.kill() catch |err| 102 - log.err("couldn't kill nvim process: {}", .{err}); 103 - if (self.thread) |thread| { 104 - thread.join(); 105 - } 106 - self.screen.deinit(self.alloc); 107 - self.visible_screen.deinit(self.alloc); 108 - self.hl_map.map.deinit(); 109 - self.mode_set.deinit(); 110 - } 111 - 112 - pub fn draw(self: *Self, win: vaxis.Window) !void { 113 - self.mutex.lock(); 114 - defer self.mutex.unlock(); 115 - self.dirty = false; 116 - win.setCursorShape(self.visible_screen.cursor_shape); 117 - if (!self.attached) try self.attach(win.width, win.height); 118 - if (win.width != self.screen.width or 119 - win.height != self.screen.height) try self.resize(win.width, win.height); 120 - var row: usize = 0; 121 - while (row < self.visible_screen.height) : (row += 1) { 122 - var col: usize = 0; 123 - while (col < self.visible_screen.width) : (col += 1) { 124 - win.writeCell(col, row, self.visible_screen.readCell(col, row).?); 125 - } 126 - } 127 - if (self.visible_screen.cursor_vis) 128 - win.showCursor(self.visible_screen.cursor_col, self.visible_screen.cursor_row); 129 - } 130 - 131 - pub fn update(self: *Self, event: VaxisEvent) !void { 132 - var client = self.client orelse return; 133 - switch (event) { 134 - .key_press => |key| { 135 - const key_str = if (key.text) |text| 136 - text 137 - else blk: { 138 - var buf: [64]u8 = undefined; 139 - var alloc = std.heap.FixedBufferAllocator.init(&buf); 140 - var w = std.ArrayList(u8).init(alloc.allocator()); 141 - try w.append('<'); 142 - if (key.mods.shift) 143 - try w.appendSlice("S-"); 144 - if (key.mods.ctrl) 145 - try w.appendSlice("C-"); 146 - if (key.mods.alt) 147 - try w.appendSlice("M-"); 148 - if (key.mods.super) 149 - try w.appendSlice("D-"); 150 - 151 - const key_str = switch (key.codepoint) { 152 - '<' => "lt", 153 - '\\' => "Bslash", 154 - '|' => "Bar", 155 - vaxis.Key.enter => "CR", 156 - vaxis.Key.backspace => "BS", 157 - vaxis.Key.tab => "Tab", 158 - vaxis.Key.escape => "ESC", 159 - vaxis.Key.space => "Space", 160 - vaxis.Key.delete => "Del", 161 - vaxis.Key.up => "Up", 162 - vaxis.Key.down => "Down", 163 - vaxis.Key.left => "Left", 164 - vaxis.Key.right => "Right", 165 - 166 - else => utf8: { 167 - var utf8Buf: [4]u8 = undefined; 168 - const n = try std.unicode.utf8Encode(key.codepoint, &utf8Buf); 169 - break :utf8 utf8Buf[0..n]; 170 - }, 171 - }; 172 - 173 - try w.appendSlice(key_str); 174 - try w.append('>'); 175 - 176 - break :blk w.items; 177 - }; 178 - var payload = try Client.createParams(1, self.alloc); 179 - defer Client.freeParams(payload, self.alloc); 180 - payload.arr[0] = try znvim.Payload.strToPayload(key_str, self.alloc); 181 - try client.notify("nvim_input", payload); 182 - }, 183 - } 184 - } 185 - 186 - fn attach(self: *Self, width: usize, height: usize) !void { 187 - self.attached = true; 188 - try self.client.?.registerNotifyMethod( 189 - "redraw", 190 - .{ 191 - .userdata = self, 192 - .func = &redrawCallback, 193 - }, 194 - ); 195 - self.screen = try vaxis.AllocatingScreen.init(self.alloc, width, height); 196 - self.visible_screen = try vaxis.AllocatingScreen.init(self.alloc, width, height); 197 - const params = try Client.createParams(3, self.alloc); 198 - defer Client.freeParams(params, self.alloc); 199 - 200 - var opts = znvim.Payload.mapPayload(self.alloc); 201 - try opts.mapPut("ext_linegrid", znvim.Payload.boolToPayload(true)); 202 - 203 - params.arr[0] = znvim.Payload.uintToPayload(self.screen.width); 204 - params.arr[1] = znvim.Payload.uintToPayload(self.screen.height); 205 - params.arr[2] = opts; 206 - 207 - const result = try self.client.?.call("nvim_ui_attach", params); 208 - switch (result) { 209 - .err => |err| Client.freeParams(err, self.alloc), 210 - .result => |r| Client.freeParams(r, self.alloc), 211 - } 212 - } 213 - 214 - fn resize(self: *Self, width: usize, height: usize) !void { 215 - self.screen.deinit(self.alloc); 216 - self.visible_screen.deinit(self.alloc); 217 - self.screen = try vaxis.AllocatingScreen.init(self.alloc, width, height); 218 - self.visible_screen = try vaxis.AllocatingScreen.init(self.alloc, width, height); 219 - const params = try Client.createParams(2, self.alloc); 220 - defer Client.freeParams(params, self.alloc); 221 - 222 - params.arr[0] = znvim.Payload.uintToPayload(self.screen.width); 223 - params.arr[1] = znvim.Payload.uintToPayload(self.screen.height); 224 - 225 - try self.client.?.notify("nvim_ui_try_resize", params); 226 - } 227 - 228 - fn redrawCallback( 229 - params: znvim.Payload, 230 - alloc: std.mem.Allocator, 231 - userdata: ?*anyopaque, 232 - ) void { 233 - _ = alloc; // autofix 234 - assert(userdata != null); 235 - var self: *Self = @ptrCast(@alignCast(userdata.?)); 236 - for (params.arr) |event| { 237 - assert(event == znvim.Payload.arr); 238 - const event_name = event.arr[0].str.value(); 239 - log.debug("redraw callback event {s}", .{event_name}); 240 - const event_enum = std.meta.stringToEnum(NvimEvent, event_name) orelse { 241 - log.err("unhandled nvim event: {s}", .{event_name}); 242 - continue; 243 - }; 244 - assert(event.arr[1] == znvim.Payload.arr); 245 - self.handleEvent(event_enum, event.arr[1..]); 246 - } 247 - } 248 - 249 - fn nvimLoop(self: *Self) void { 250 - if (self.client) |*client| { 251 - while (true) { 252 - client.loop() catch |err| { 253 - log.err("rpc loop error: {}", .{err}); 254 - self.loop.postEvent(.{ .nvim = .{ .quit = self } }); 255 - return; 256 - }; 257 - } 258 - } 259 - } 260 - 261 - const NvimEvent = enum { 262 - chdir, 263 - default_colors_set, 264 - flush, 265 - grid_clear, 266 - grid_cursor_goto, 267 - grid_line, 268 - grid_resize, 269 - grid_scroll, 270 - hl_attr_define, 271 - hl_group_set, 272 - mode_change, 273 - mode_info_set, 274 - option_set, 275 - set_icon, 276 - set_title, 277 - }; 278 - 279 - const OptionSet = enum { 280 - ambiwidth, 281 - arabicshape, 282 - emoji, 283 - guifont, 284 - guifontwide, 285 - linespace, 286 - mousefocus, 287 - mousehide, 288 - mousemoveevent, 289 - pumblend, 290 - showtabline, 291 - termguicolors, 292 - termsync, 293 - ttimeout, 294 - ttimeoutlen, 295 - verbose, 296 - 297 - ext_cmdline, 298 - ext_hlstate, 299 - ext_linegrid, 300 - ext_messages, 301 - ext_multigrid, 302 - ext_popupmenu, 303 - ext_tabline, 304 - ext_termcolors, 305 - ext_wildmenu, 306 - }; 307 - 308 - const Mode = struct { 309 - cursor_style_enabled: bool = false, 310 - cursor_shape: vaxis.Cell.CursorShape = .default, 311 - attr_id: usize = 0, 312 - mouse_shape: vaxis.Mouse.Shape = .default, 313 - short_name: []const u8 = "", 314 - name: []const u8 = "", 315 - 316 - fn deinit(self: Mode, alloc: std.mem.Allocator) void { 317 - alloc.free(self.short_name); 318 - alloc.free(self.name); 319 - } 320 - 321 - const Keys = enum { 322 - cursor_shape, 323 - blinkon, 324 - blinkoff, 325 - attr_id, 326 - short_name, 327 - name, 328 - mouse_shape, 329 - }; 330 - }; 331 - 332 - const HighlightMap = struct { 333 - /// the keys used in rgb_dict field in the nvim rpc event 334 - const Keys = enum { 335 - foreground, 336 - background, 337 - special, 338 - italic, 339 - bold, 340 - strikethrough, 341 - reverse, 342 - underline, 343 - undercurl, 344 - underdouble, 345 - underdotted, 346 - 347 - // not used: 348 - altfont, 349 - blend, 350 - url, // TODO: handle urls 351 - 352 - }; 353 - 354 - const Highlight = struct { 355 - id: u64, 356 - attrs: struct { 357 - fg: ?vaxis.Color = null, 358 - bg: ?vaxis.Color = null, 359 - special: ?vaxis.Color = null, 360 - italic: ?bool = null, 361 - bold: ?bool = null, 362 - strikethrough: ?bool = null, 363 - underline: ?bool = null, 364 - undercurl: ?bool = null, 365 - underdouble: ?bool = null, 366 - underdotted: ?bool = null, 367 - reverse: ?bool = null, 368 - // TODO: urls 369 - // url: ?[]const u8 = null, 370 - } = .{}, 371 - }; 372 - 373 - alloc: std.mem.Allocator, 374 - default: vaxis.Style, 375 - map: std.ArrayList(Highlight), 376 - 377 - pub fn init(alloc: std.mem.Allocator) HighlightMap { 378 - return .{ 379 - .alloc = alloc, 380 - .default = .{}, 381 - .map = std.ArrayList(Highlight).init(alloc), 382 - }; 383 - } 384 - 385 - /// returns the requested id, or default if not found 386 - pub fn get(self: *HighlightMap, id: u64) vaxis.Style { 387 - for (self.map.items) |h| { 388 - if (h.id == id) return self.merge(h); 389 - } else return self.default; 390 - } 391 - 392 - pub fn put(self: *HighlightMap, hl: Highlight) !void { 393 - for (self.map.items, 0..) |h, i| { 394 - if (h.id == hl.id) { 395 - self.map.items[i] = hl; 396 - return; 397 - } 398 - } else try self.map.append(hl); 399 - } 400 - 401 - /// merges a Highlight with the default to create a vaxis.Style 402 - fn merge(self: HighlightMap, hl: Highlight) vaxis.Style { 403 - var result = self.default; 404 - const attrs = hl.attrs; 405 - if (attrs.fg) |val| result.fg = val; 406 - if (attrs.bg) |val| result.bg = val; 407 - if (attrs.special) |val| result.ul = val; 408 - if (attrs.italic) |val| result.italic = val; 409 - if (attrs.bold) |val| result.bold = val; 410 - if (attrs.strikethrough) |val| result.strikethrough = val; 411 - if (attrs.underline) |val| result.ul_style = if (val) .single else .off; 412 - if (attrs.undercurl) |val| result.ul_style = if (val) .single else .off; 413 - if (attrs.underdotted) |val| result.ul_style = if (val) .dotted else .off; 414 - if (attrs.reverse) |val| result.reverse = val; 415 - // TODO: hyperlinks 416 - return result; 417 - } 418 - }; 419 - 420 - /// handles an nvim event. params will always be a .arr payload type. Each event 421 - /// is of the form: [ "event_name", [ param_tuple ], [param_tuple], ... ]. Each 422 - /// event can come with multiple params (IE multiple instances of the same event) 423 - fn handleEvent(self: *Self, event: NvimEvent, params: []znvim.Payload) void { 424 - switch (event) { 425 - .chdir => { 426 - // param_tuple: [path] 427 - for (params) |param| { 428 - assert(param == znvim.Payload.arr); 429 - assert(param.arr.len == 1); 430 - assert(param.arr[0] == znvim.Payload.str); 431 - } 432 - }, 433 - .default_colors_set => { 434 - // param_tuple: [rgb_fg, rgb_bg, rgb_sp, cterm_fg, cterm_bg] 435 - for (params) |param| { 436 - assert(param == znvim.Payload.arr); 437 - assert(param.arr.len == 5); 438 - self.hl_map.default.fg = vaxis.Color.rgbFromUint(@truncate(param.arr[0].uint)); 439 - self.hl_map.default.bg = vaxis.Color.rgbFromUint(@truncate(param.arr[1].uint)); 440 - self.hl_map.default.ul = vaxis.Color.rgbFromUint(@truncate(param.arr[2].uint)); 441 - } 442 - }, 443 - .flush => { 444 - self.mutex.lock(); 445 - defer self.mutex.unlock(); 446 - var row: usize = 0; 447 - while (row < self.visible_screen.height) : (row += 1) { 448 - var col: usize = 0; 449 - while (col < self.visible_screen.width) : (col += 1) { 450 - self.visible_screen.writeCell(col, row, self.screen.readCell(col, row).?); 451 - } 452 - } 453 - self.visible_screen.cursor_row = self.screen.cursor_row; 454 - self.visible_screen.cursor_col = self.screen.cursor_col; 455 - self.visible_screen.cursor_vis = self.screen.cursor_vis; 456 - self.visible_screen.cursor_shape = self.screen.cursor_shape; 457 - if (!self.dirty) { 458 - self.dirty = true; 459 - self.loop.postEvent(.{ .nvim = .{ .redraw = self } }); 460 - } 461 - }, 462 - .grid_clear => { 463 - var row: usize = 0; 464 - var col: usize = 0; 465 - while (row < self.screen.height) : (row += 1) { 466 - while (col < self.screen.width) : (col += 1) { 467 - self.screen.writeCell(col, row, .{ .style = self.hl_map.default }); 468 - } 469 - } 470 - }, 471 - .grid_cursor_goto => { 472 - // param_tuple: [grid, row, col] 473 - for (params) |param| { 474 - assert(param == znvim.Payload.arr); 475 - assert(param.arr.len == 3); 476 - self.screen.cursor_row = @truncate(param.arr[1].uint); 477 - self.screen.cursor_col = @truncate(param.arr[2].uint); 478 - self.screen.cursor_vis = true; 479 - } 480 - }, 481 - .grid_line => { 482 - // param_tuple: [grid, row, col_start, cells, wrap] 483 - var style: vaxis.Style = self.hl_map.default; 484 - for (params) |param| { 485 - assert(param == znvim.Payload.arr); 486 - assert(param.arr.len == 5); 487 - assert(param.arr[1] == znvim.Payload.uint); 488 - assert(param.arr[2] == znvim.Payload.uint); 489 - assert(param.arr[3] == znvim.Payload.arr); 490 - const row: usize = param.arr[1].uint; 491 - var col: usize = param.arr[2].uint; 492 - const cells = param.arr[3].arr; 493 - for (cells) |cell| { 494 - assert(cell == znvim.Payload.arr); 495 - switch (cell.arr.len) { 496 - 1 => { 497 - assert(cell.arr[0] == znvim.Payload.str); 498 - self.screen.writeCell(col, row, .{ 499 - .char = .{ 500 - .grapheme = cell.arr[0].str.value(), 501 - }, 502 - .style = style, 503 - }); 504 - col += 1; 505 - }, 506 - 2 => { 507 - assert(cell.arr[0] == znvim.Payload.str); 508 - assert(cell.arr[1] == znvim.Payload.uint); 509 - style = self.hl_map.get(cell.arr[1].uint); 510 - self.screen.writeCell(col, row, .{ 511 - .char = .{ 512 - .grapheme = cell.arr[0].str.value(), 513 - }, 514 - .style = style, 515 - }); 516 - col += 1; 517 - }, 518 - 3 => { 519 - assert(cell.arr[0] == znvim.Payload.str); 520 - assert(cell.arr[1] == znvim.Payload.uint); 521 - assert(cell.arr[2] == znvim.Payload.uint); 522 - style = self.hl_map.get(cell.arr[1].uint); 523 - var i: usize = 0; 524 - while (i < cell.arr[2].uint) : (i += 1) { 525 - self.screen.writeCell(col, row, .{ 526 - .char = .{ 527 - .grapheme = cell.arr[0].str.value(), 528 - }, 529 - .style = style, 530 - }); 531 - col += 1; 532 - } 533 - }, 534 - else => unreachable, 535 - } 536 - } 537 - } 538 - }, 539 - .grid_resize => { 540 - // param_tuple: [grid, width, height] 541 - // We don't need to handle this since we aren't activating 542 - // ui_multigrid. Grid ID 1 will always be our main grid 543 - }, 544 - .grid_scroll => { 545 - // param_tuple: [grid, top, bot, left, right, rows, cols] 546 - for (params) |param| { 547 - assert(param == znvim.Payload.arr); 548 - assert(param.arr.len == 7); 549 - // we don't care about grid 550 - // assert(param.arr[0] == znvim.Payload.uint); 551 - assert(param.arr[1] == znvim.Payload.uint); 552 - assert(param.arr[2] == znvim.Payload.uint); 553 - assert(param.arr[3] == znvim.Payload.uint); 554 - assert(param.arr[4] == znvim.Payload.uint); 555 - assert(param.arr[5] == znvim.Payload.uint or 556 - param.arr[5] == znvim.Payload.int); 557 - // we don't care about cols. This is always zero 558 - // currently 559 - // assert(param.arr[6] == znvim.Payload.uint); 560 - const top: usize = @truncate(param.arr[1].uint); 561 - const bot: usize = @truncate(param.arr[2].uint); 562 - const left: usize = @truncate(param.arr[3].uint); 563 - const right: usize = @truncate(param.arr[4].uint); 564 - if (param.arr[5] == znvim.Payload.uint) { 565 - const rows: usize = @truncate(param.arr[5].uint); 566 - var row: usize = top; 567 - while (row < bot) : (row += 1) { 568 - if (row + rows > bot) break; 569 - var col: usize = left; 570 - while (col < right) : (col += 1) { 571 - const cell = self.screen.readCell(col, row + rows) orelse return; 572 - self.screen.writeCell(col, row, cell); 573 - } 574 - } 575 - } else { 576 - const rows: usize = @intCast(-param.arr[5].int); 577 - var row: usize = bot -| 1; 578 - while (row >= top) : (row -|= 1) { 579 - if (row + 1 -| rows <= top) break; 580 - var col: usize = left; 581 - while (col < right) : (col += 1) { 582 - const cell = self.screen.readCell(col, row -| rows) orelse unreachable; 583 - self.screen.writeCell(col, row, cell); 584 - } 585 - } 586 - } 587 - } 588 - }, 589 - .hl_attr_define => { 590 - // param_tuple: [id, rgb_attr, cterm_attr, info] 591 - for (params) |param| { 592 - assert(param == znvim.Payload.arr); 593 - assert(param.arr.len == 4); 594 - assert(param.arr[0] == znvim.Payload.uint); 595 - assert(param.arr[1] == znvim.Payload.map); 596 - // we don't care about cterm_attr 597 - // assert(param.arr[2] == znvim.Payload.map); 598 - assert(param.arr[3] == znvim.Payload.arr); 599 - const rgb_dict = param.arr[1].map; 600 - 601 - var hl: HighlightMap.Highlight = .{ 602 - .id = param.arr[0].uint, 603 - }; 604 - var rgb_iter = rgb_dict.iterator(); 605 - while (rgb_iter.next()) |kv| { 606 - const key = std.meta.stringToEnum(HighlightMap.Keys, kv.key_ptr.*) orelse { 607 - log.warn("unhandled highlight key: {s}", .{kv.key_ptr.*}); 608 - continue; 609 - }; 610 - switch (key) { 611 - .foreground => { 612 - hl.attrs.fg = vaxis.Color.rgbFromUint(@truncate(kv.value_ptr.*.uint)); 613 - }, 614 - .background => { 615 - hl.attrs.bg = vaxis.Color.rgbFromUint(@truncate(kv.value_ptr.*.uint)); 616 - }, 617 - .special => { 618 - hl.attrs.bg = vaxis.Color.rgbFromUint(@truncate(kv.value_ptr.*.uint)); 619 - }, 620 - .italic => hl.attrs.italic = kv.value_ptr.*.bool, 621 - .bold => hl.attrs.bold = kv.value_ptr.*.bool, 622 - .strikethrough => hl.attrs.strikethrough = kv.value_ptr.*.bool, 623 - .underline => hl.attrs.underline = kv.value_ptr.*.bool, 624 - .undercurl => hl.attrs.undercurl = kv.value_ptr.*.bool, 625 - .underdouble => hl.attrs.underdouble = kv.value_ptr.*.bool, 626 - .underdotted => hl.attrs.underdotted = kv.value_ptr.*.bool, 627 - .reverse => hl.attrs.reverse = kv.value_ptr.*.bool, 628 - else => {}, 629 - } 630 - } 631 - self.hl_map.put(hl) catch |err| { 632 - log.err("couldn't save highlight: {}", .{err}); 633 - }; 634 - } 635 - }, 636 - .hl_group_set => {}, // not used right now 637 - .mode_change => { 638 - // param_tuple: [mode, mode_idx] 639 - for (params) |param| { 640 - assert(param == znvim.Payload.arr); 641 - assert(param.arr.len == 2); 642 - assert(param.arr[1] == znvim.Payload.uint); 643 - const mode = self.mode_set.items[param.arr[1].uint]; 644 - log.debug("MODE CHANGE: {}", .{mode.cursor_shape}); 645 - self.screen.cursor_shape = mode.cursor_shape; 646 - } 647 - }, 648 - .mode_info_set => { 649 - // param_tuple: [cursor_style_enabled, mode_info] 650 - for (params) |param| { 651 - assert(param == znvim.Payload.arr); 652 - assert(param.arr.len == 2); 653 - assert(param.arr[0] == znvim.Payload.bool); 654 - assert(param.arr[1] == znvim.Payload.arr); 655 - for (param.arr[1].arr) |mode_info| { 656 - assert(mode_info == znvim.Payload.map); 657 - var iter = mode_info.map.iterator(); 658 - var mode: Mode = .{}; 659 - var blink: ?bool = null; 660 - var shape: vaxis.Cell.CursorShape = .default; 661 - while (iter.next()) |kv| { 662 - const key = std.meta.stringToEnum(Mode.Keys, kv.key_ptr.*) orelse continue; 663 - switch (key) { 664 - .cursor_shape => { 665 - if (std.mem.eql(u8, "block", kv.value_ptr.*.str.value())) 666 - shape = .block 667 - else if (std.mem.eql(u8, "horizontal", kv.value_ptr.*.str.value())) 668 - shape = .underline 669 - else if (std.mem.eql(u8, "vertical", kv.value_ptr.*.str.value())) 670 - shape = .beam; 671 - }, 672 - .short_name => {}, 673 - .name => {}, 674 - .mouse_shape => {}, 675 - .attr_id => {}, 676 - .blinkon => { 677 - if (blink == null and kv.value_ptr.*.uint != 0) 678 - blink = true 679 - else 680 - blink = false; 681 - }, 682 - .blinkoff => { 683 - if (blink == null and kv.value_ptr.*.uint != 0) 684 - blink = true 685 - else 686 - blink = false; 687 - }, 688 - } 689 - mode.cursor_shape = if (blink == null or !blink.?) 690 - shape 691 - else 692 - @enumFromInt(@intFromEnum(shape) - 1); 693 - log.err("key={s}, value={}", .{ kv.key_ptr.*, kv.value_ptr.* }); 694 - } 695 - self.mode_set.append(mode) catch |err| { 696 - log.err("couldn't add mode_set: {}", .{err}); 697 - }; 698 - } 699 - } 700 - }, 701 - .option_set => { 702 - // param_tuple: [name, value] 703 - for (params) |param| { 704 - assert(param == znvim.Payload.arr); 705 - assert(param.arr.len == 2); 706 - assert(param.arr[0] == znvim.Payload.str); 707 - const opt = std.meta.stringToEnum(OptionSet, param.arr[0].str.value()) orelse { 708 - log.err("unknonwn 'option_set' key: {s}", .{param.arr[0].str.value()}); 709 - continue; 710 - }; 711 - switch (opt) { 712 - .ambiwidth => {}, 713 - .arabicshape => {}, 714 - .emoji => {}, 715 - .guifont => {}, 716 - .guifontwide => {}, 717 - .linespace => {}, 718 - .mousefocus => {}, 719 - .mousehide => {}, 720 - .mousemoveevent => {}, 721 - .pumblend => {}, 722 - .showtabline => {}, 723 - .termguicolors => {}, 724 - .termsync => {}, 725 - .ttimeout => {}, 726 - .ttimeoutlen => {}, 727 - .verbose => {}, 728 - .ext_cmdline => {}, 729 - .ext_hlstate => {}, 730 - .ext_linegrid => {}, 731 - .ext_messages => {}, 732 - .ext_multigrid => {}, 733 - .ext_popupmenu => {}, 734 - .ext_tabline => {}, 735 - .ext_termcolors => {}, 736 - .ext_wildmenu => {}, 737 - } 738 - } 739 - }, 740 - .set_icon => { 741 - // param_tuple: [title] 742 - for (params) |param| { 743 - assert(param == znvim.Payload.arr); 744 - assert(param.arr.len == 1); 745 - assert(param.arr[0] == znvim.Payload.str); 746 - const icon = param.arr[0].str.value(); 747 - log.debug("set_icon: {s}", .{icon}); 748 - } 749 - }, 750 - .set_title => { 751 - // param_tuple: [icon] 752 - for (params) |param| { 753 - assert(param == znvim.Payload.arr); 754 - assert(param.arr.len == 1); 755 - assert(param.arr[0] == znvim.Payload.str); 756 - const title = param.arr[0].str.value(); 757 - log.debug("set_title: {s}", .{title}); 758 - } 759 - }, 760 - } 761 - } 762 - }; 763 - }