this repo has no description
13
fork

Configure Feed

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

Skip render output when nothing changes

authored by

john xu and committed by
Tim Culverhouse
dda10d2e 11f53c70

+68 -25
+68 -25
src/Vaxis.zig
··· 360 360 assert(self.screen.buf.len == @as(usize, @intCast(self.screen.width)) * self.screen.height); // correct size 361 361 assert(self.screen.buf.len == self.screen_last.buf.len); // same size 362 362 363 - // Set up sync before we write anything 364 - // TODO: optimize sync so we only sync _when we have changes_. This 365 - // requires a smarter buffered writer, we'll probably have to write 366 - // our own 367 - try tty.writeAll(ctlseqs.sync_set); 368 - errdefer tty.writeAll(ctlseqs.sync_reset) catch {}; 363 + var started: bool = false; 364 + var sync_active: bool = false; 365 + errdefer if (sync_active) tty.writeAll(ctlseqs.sync_reset) catch {}; 369 366 370 - // Send the cursor to 0,0 371 - // TODO: this needs to move after we optimize writes. We only do 372 - // this if we have an update to make. We also need to hide cursor 373 - // and then reshow it if needed 374 - try tty.writeAll(ctlseqs.hide_cursor); 375 - if (self.state.alt_screen) 376 - try tty.writeAll(ctlseqs.home) 377 - else { 378 - try tty.writeByte('\r'); 379 - for (0..self.state.cursor.row) |_| { 380 - try tty.writeAll(ctlseqs.ri); 381 - } 382 - } 383 - try tty.writeAll(ctlseqs.sgr_reset); 367 + const cursor_vis_changed = self.screen.cursor_vis != self.screen_last.cursor_vis; 368 + const cursor_shape_changed = self.screen.cursor_shape != self.screen_last.cursor_shape; 369 + const mouse_shape_changed = self.screen.mouse_shape != self.screen_last.mouse_shape; 370 + 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; 384 374 385 375 // initialize some variables 386 376 var reposition: bool = false; ··· 388 378 var col: u16 = 0; 389 379 var cursor: Style = .{}; 390 380 var link: Hyperlink = .{}; 391 - var cursor_pos: struct { 381 + const CursorPos = struct { 392 382 row: u16 = 0, 393 383 col: u16 = 0, 394 - } = .{}; 384 + }; 385 + var cursor_pos: CursorPos = .{}; 395 386 396 - // Clear all images 397 - if (self.caps.kitty_graphics) 398 - try tty.writeAll(ctlseqs.kitty_graphics_clear); 387 + const startRender = struct { 388 + fn run( 389 + vx: *Vaxis, 390 + io: *IoWriter, 391 + cursor_pos_ptr: *CursorPos, 392 + reposition_ptr: *bool, 393 + started_ptr: *bool, 394 + sync_active_ptr: *bool, 395 + ) !void { 396 + if (started_ptr.*) return; 397 + started_ptr.* = true; 398 + sync_active_ptr.* = true; 399 + // Set up sync before we write anything 400 + try io.writeAll(ctlseqs.sync_set); 401 + // Send the cursor to 0,0 402 + try io.writeAll(ctlseqs.hide_cursor); 403 + if (vx.state.alt_screen) 404 + try io.writeAll(ctlseqs.home) 405 + else { 406 + try io.writeByte('\r'); 407 + for (0..vx.state.cursor.row) |_| { 408 + try io.writeAll(ctlseqs.ri); 409 + } 410 + } 411 + try io.writeAll(ctlseqs.sgr_reset); 412 + cursor_pos_ptr.* = .{}; 413 + reposition_ptr.* = true; 414 + // Clear all images 415 + if (vx.caps.kitty_graphics) 416 + try io.writeAll(ctlseqs.kitty_graphics_clear); 417 + } 418 + }; 399 419 400 420 // Reset skip flag on all last_screen cells 401 421 for (self.screen_last.buf) |*last_cell| { 402 422 last_cell.skip = false; 423 + } 424 + 425 + if (needs_render) { 426 + try startRender.run(self, tty, &cursor_pos, &reposition, &started, &sync_active); 403 427 } 404 428 405 429 var i: usize = 0; ··· 446 470 try tty.writeAll(ctlseqs.osc8_clear); 447 471 } 448 472 continue; 473 + } 474 + if (!started) { 475 + try startRender.run(self, tty, &cursor_pos, &reposition, &started, &sync_active); 449 476 } 450 477 self.screen_last.buf[i].skipped = false; 451 478 defer { ··· 730 757 cursor_pos.col = col + w; 731 758 cursor_pos.row = row; 732 759 } 760 + if (!started) return; 733 761 if (self.screen.cursor_vis) { 734 762 if (self.state.alt_screen) { 735 763 try tty.print( ··· 761 789 self.state.cursor.row = cursor_pos.row; 762 790 self.state.cursor.col = cursor_pos.col; 763 791 } 792 + self.screen_last.cursor_vis = self.screen.cursor_vis; 764 793 if (self.screen.mouse_shape != self.screen_last.mouse_shape) { 765 794 try tty.print( 766 795 ctlseqs.osc22_mouse_shape, ··· 1409 1438 try tty.print(ctlseqs.osc7, .{uri.fmt(.{ .scheme = true, .authority = true, .path = true })}); 1410 1439 try tty.flush(); 1411 1440 } 1441 + 1442 + test "render: no output when no changes" { 1443 + var vx = try Vaxis.init(std.testing.allocator, .{}); 1444 + var deinit_writer = std.io.Writer.Allocating.init(std.testing.allocator); 1445 + defer deinit_writer.deinit(); 1446 + defer vx.deinit(std.testing.allocator, &deinit_writer.writer); 1447 + 1448 + var render_writer = std.io.Writer.Allocating.init(std.testing.allocator); 1449 + defer render_writer.deinit(); 1450 + try vx.render(&render_writer.writer); 1451 + const output = try render_writer.toOwnedSlice(); 1452 + defer std.testing.allocator.free(output); 1453 + try std.testing.expectEqual(@as(usize, 0), output.len); 1454 + }