this repo has no description
13
fork

Configure Feed

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

window!: allow negative offsets and windows beyond screen

Allow negative offsets to a window. Allow a window to extend any edge of
the screen. Out-of-bounds cells ultimately don't write to the screen

+54 -65
+4 -14
src/Screen.zig
··· 50 50 51 51 /// writes a cell to a location. 0 indexed 52 52 pub fn writeCell(self: *Screen, col: u16, row: u16, cell: Cell) void { 53 - if (self.width <= col) { 54 - // column out of bounds 53 + if (col >= self.width or 54 + row >= self.height) 55 55 return; 56 - } 57 - if (self.height <= row) { 58 - // height out of bounds 59 - return; 60 - } 61 56 const i = (row * self.width) + col; 62 57 assert(i < self.buf.len); 63 58 self.buf[i] = cell; 64 59 } 65 60 66 61 pub fn readCell(self: *const Screen, col: u16, row: u16) ?Cell { 67 - if (self.width <= col) { 68 - // column out of bounds 62 + if (col >= self.width or 63 + row >= self.height) 69 64 return null; 70 - } 71 - if (self.height <= row) { 72 - // height out of bounds 73 - return null; 74 - } 75 65 const i = (row * self.width) + col; 76 66 assert(i < self.buf.len); 77 67 return self.buf[i];
+48 -39
src/Window.zig
··· 10 10 const Window = @This(); 11 11 12 12 /// horizontal offset from the screen 13 - x_off: u16, 13 + x_off: i17, 14 14 /// vertical offset from the screen 15 - y_off: u16, 15 + y_off: i17, 16 16 /// width of the window. This can't be larger than the terminal screen 17 17 width: u16, 18 18 /// height of the window. This can't be larger than the terminal screen ··· 25 25 /// unaware of resizes. 26 26 fn initChild( 27 27 self: Window, 28 - x_off: u16, 29 - y_off: u16, 28 + x_off: i17, 29 + y_off: i17, 30 30 maybe_width: ?u16, 31 31 maybe_height: ?u16, 32 32 ) Window { 33 - const resolved_width: u16 = if (maybe_width) |width| 34 - @min(width, self.width -| x_off) 35 - else 36 - self.width -| x_off; 33 + const width: u16 = maybe_width orelse @max(self.width - x_off, 0); 34 + const height: u16 = maybe_height orelse @max(self.height - y_off, 0); 37 35 38 - const resolved_height: u16 = if (maybe_height) |height| 39 - @min(height, self.height -| y_off) 40 - else 41 - self.height -| y_off; 42 36 return Window{ 43 37 .x_off = x_off + self.x_off, 44 38 .y_off = y_off + self.y_off, 45 - .width = resolved_width, 46 - .height = resolved_height, 39 + .width = width, 40 + .height = height, 47 41 .screen = self.screen, 48 42 }; 49 43 } 50 44 51 45 pub const ChildOptions = struct { 52 - x_off: u16 = 0, 53 - y_off: u16 = 0, 46 + x_off: i17 = 0, 47 + y_off: i17 = 0, 54 48 /// the width of the resulting child, including any borders 55 49 width: ?u16 = null, 56 50 /// the height of the resulting child, including any borders ··· 171 165 172 166 /// writes a cell to the location in the window 173 167 pub fn writeCell(self: Window, col: u16, row: u16, cell: Cell) void { 174 - if (self.height == 0 or self.width == 0) return; 175 168 if (self.height <= row or self.width <= col) return; 176 - self.screen.writeCell(col + self.x_off, row + self.y_off, cell); 169 + if (self.x_off + col < 0) return; 170 + if (self.y_off + row < 0) return; 171 + self.screen.writeCell(@intCast(col + self.x_off), @intCast(row + self.y_off), cell); 177 172 } 178 173 179 174 /// reads a cell at the location in the window 180 175 pub fn readCell(self: Window, col: u16, row: u16) ?Cell { 181 - if (self.height == 0 or self.width == 0) return null; 182 - if (self.height <= row or self.width <= col) return null; 183 - return self.screen.readCell(col + self.x_off, row + self.y_off); 176 + if (self.height <= row or 177 + self.width <= col or 178 + self.x_off + col < 0 or 179 + self.y_off + row < 0) 180 + return null; 181 + return self.screen.readCell(@intCast(col + self.x_off), @intCast(row + self.y_off)); 184 182 } 185 183 186 184 /// fills the window with the default cell ··· 195 193 196 194 /// fills the window with the provided cell 197 195 pub fn fill(self: Window, cell: Cell) void { 198 - if (self.screen.width < self.x_off) 199 - return; 200 - if (self.screen.height < self.y_off) 196 + if (self.x_off + self.width < 0 or 197 + self.y_off + self.height < 0 or 198 + self.screen.width < self.x_off or 199 + self.screen.height < self.y_off) 201 200 return; 201 + const first_row: u16 = @intCast(@max(self.y_off, 0)); 202 202 if (self.x_off == 0 and self.width == self.screen.width) { 203 203 // we have a full width window, therefore contiguous memory. 204 - const start = @min(self.y_off * self.width, self.screen.buf.len); 204 + const start = @min(first_row * self.width, self.screen.buf.len); 205 205 const end = @min(start + (self.height * self.width), self.screen.buf.len); 206 206 @memset(self.screen.buf[start..end], cell); 207 207 } else { 208 208 // Non-contiguous. Iterate over rows an memset 209 - var row: u16 = self.y_off; 209 + var row: u16 = first_row; 210 + const first_col: u16 = @max(self.x_off, 0); 210 211 const last_row = @min(self.height + self.y_off, self.screen.height); 211 212 while (row < last_row) : (row += 1) { 212 - const start = @min(self.x_off + (row * self.screen.width), self.screen.buf.len); 213 - var end = @min(start + self.width, start + (self.screen.width - self.x_off)); 213 + const start = @min(first_col + (row * self.screen.width), self.screen.buf.len); 214 + var end = @min(start + self.width, start + (self.screen.width - first_col)); 214 215 end = @min(end, self.screen.buf.len); 215 216 @memset(self.screen.buf[start..end], cell); 216 217 } ··· 224 225 225 226 /// show the cursor at the given coordinates, 0 indexed 226 227 pub fn showCursor(self: Window, col: u16, row: u16) void { 227 - if (self.height == 0 or self.width == 0) return; 228 - if (self.height <= row or self.width <= col) return; 228 + if (self.x_off + col < 0 or 229 + self.y_off + row < 0 or 230 + row >= self.height or 231 + col >= self.width) 232 + return; 229 233 self.screen.cursor_vis = true; 230 - self.screen.cursor_row = row + self.y_off; 231 - self.screen.cursor_col = col + self.x_off; 234 + self.screen.cursor_row = @intCast(row + self.y_off); 235 + self.screen.cursor_col = @intCast(col + self.x_off); 232 236 } 233 237 234 238 pub fn setCursorShape(self: Window, shape: Cell.CursorShape) void { ··· 431 435 /// screen and shifts all rows up one) 432 436 pub fn scroll(self: Window, n: u16) void { 433 437 if (n > self.height) return; 434 - var row = self.y_off; 438 + var row: u16 = @max(self.y_off, 0); 439 + const first_col: u16 = @max(self.x_off, 0); 435 440 while (row < self.height - n) : (row += 1) { 436 - const dst_start = (row * self.width) + self.x_off; 441 + const dst_start = (row * self.width) + first_col; 437 442 const dst_end = dst_start + self.width; 438 443 439 - const src_start = ((row + n) * self.width) + self.x_off; 444 + const src_start = ((row + n) * self.width) + first_col; 440 445 const src_end = src_start + self.width; 441 446 @memcpy(self.screen.buf[dst_start..dst_end], self.screen.buf[src_start..src_end]); 442 447 } ··· 480 485 }; 481 486 482 487 const ch = parent.initChild(0, 0, 21, 21); 483 - try std.testing.expectEqual(20, ch.width); 484 - try std.testing.expectEqual(20, ch.height); 488 + try std.testing.expectEqual(21, ch.width); 489 + try std.testing.expectEqual(21, ch.height); 485 490 } 486 491 487 492 test "Window size set too big with offset" { ··· 494 499 }; 495 500 496 501 const ch = parent.initChild(10, 10, 21, 21); 497 - try std.testing.expectEqual(10, ch.width); 498 - try std.testing.expectEqual(10, ch.height); 502 + try std.testing.expectEqual(21, ch.width); 503 + try std.testing.expectEqual(21, ch.height); 499 504 } 500 505 501 506 test "Window size nested offsets" { ··· 837 842 } 838 843 } 839 844 }; 845 + 846 + test "refAllDecls" { 847 + std.testing.refAllDecls(@This()); 848 + }
+2 -12
src/main.zig
··· 73 73 \\ ▀▄▀ █ █ █ █ ▄█▄ ▀▄▄▄▀ 74 74 ; 75 75 76 - test { 77 - _ = @import("gwidth.zig"); 78 - _ = @import("Cell.zig"); 79 - _ = @import("Key.zig"); 80 - _ = @import("Parser.zig"); 81 - _ = @import("Window.zig"); 82 - 83 - _ = @import("gwidth.zig"); 84 - _ = @import("queue.zig"); 85 - _ = @import("widgets/TextInput.zig"); 86 - 87 - _ = @import("Loop.zig"); 76 + test "refAllDecls" { 77 + std.testing.refAllDecls(@This()); 88 78 }