a modern tui library written in zig
at main 3.5 kB view raw
1const std = @import("std"); 2const vaxis = @import("../main.zig"); 3const ScrollView = vaxis.widgets.ScrollView; 4const LineNumbers = vaxis.widgets.LineNumbers; 5 6pub const DrawOptions = struct { 7 highlighted_line: u16 = 0, 8 draw_line_numbers: bool = true, 9 indentation: u16 = 0, 10}; 11 12pub const Buffer = vaxis.widgets.TextView.Buffer; 13 14scroll_view: ScrollView = .{ .vertical_scrollbar = null }, 15highlighted_style: vaxis.Style = .{ .bg = .{ .index = 0 } }, 16indentation_cell: vaxis.Cell = .{ 17 .char = .{ 18 .grapheme = "", 19 .width = 1, 20 }, 21 .style = .{ .dim = true }, 22}, 23 24pub fn input(self: *@This(), key: vaxis.Key) void { 25 self.scroll_view.input(key); 26} 27 28pub fn draw(self: *@This(), win: vaxis.Window, buffer: Buffer, opts: DrawOptions) void { 29 const pad_left: usize = if (opts.draw_line_numbers) LineNumbers.numDigits(buffer.rows) +| 1 else 0; 30 self.scroll_view.draw(win, .{ 31 .cols = buffer.cols + pad_left, 32 .rows = buffer.rows, 33 }); 34 if (opts.draw_line_numbers) { 35 var nl: LineNumbers = .{ 36 .highlighted_line = opts.highlighted_line, 37 .num_lines = buffer.rows +| 1, 38 }; 39 nl.draw(win.child(.{ 40 .x_off = 0, 41 .y_off = 0, 42 .width = pad_left, 43 .height = win.height, 44 }), self.scroll_view.scroll.y); 45 } 46 self.drawCode(win.child(.{ .x_off = pad_left }), buffer, opts); 47} 48 49fn drawCode(self: *@This(), win: vaxis.Window, buffer: Buffer, opts: DrawOptions) void { 50 const Pos = struct { x: usize = 0, y: usize = 0 }; 51 var pos: Pos = .{}; 52 var byte_index: usize = 0; 53 var is_indentation = true; 54 const bounds = self.scroll_view.bounds(win); 55 for (buffer.grapheme.items(.len), buffer.grapheme.items(.offset), 0..) |g_len, g_offset, index| { 56 if (bounds.above(pos.y)) { 57 break; 58 } 59 60 const cluster = buffer.content.items[g_offset..][0..g_len]; 61 defer byte_index += cluster.len; 62 63 if (std.mem.eql(u8, cluster, "\n")) { 64 if (index == buffer.grapheme.len - 1) { 65 break; 66 } 67 pos.y += 1; 68 pos.x = 0; 69 is_indentation = true; 70 continue; 71 } else if (bounds.below(pos.y)) { 72 continue; 73 } 74 75 const highlighted_line = pos.y +| 1 == opts.highlighted_line; 76 var style: vaxis.Style = if (highlighted_line) self.highlighted_style else .{}; 77 78 if (buffer.style_map.get(byte_index)) |meta| { 79 const tmp = style.bg; 80 style = buffer.style_list.items[meta]; 81 style.bg = tmp; 82 } 83 84 const width = win.gwidth(cluster); 85 defer pos.x +|= width; 86 87 if (!bounds.colInside(pos.x)) { 88 continue; 89 } 90 91 if (opts.indentation > 0 and !std.mem.eql(u8, cluster, " ")) { 92 is_indentation = false; 93 } 94 95 if (is_indentation and opts.indentation > 0 and pos.x % opts.indentation == 0) { 96 var cell = self.indentation_cell; 97 cell.style.bg = style.bg; 98 self.scroll_view.writeCell(win, pos.x, pos.y, cell); 99 } else { 100 self.scroll_view.writeCell(win, pos.x, pos.y, .{ 101 .char = .{ .grapheme = cluster, .width = @intCast(width) }, 102 .style = style, 103 }); 104 } 105 106 if (highlighted_line) { 107 for (pos.x +| width..bounds.x2) |x| { 108 self.scroll_view.writeCell(win, x, pos.y, .{ .style = style }); 109 } 110 } 111 } 112}