widgets: add CodeView widget
CodeView widget allows viewing code in a more visually pleasing manner. It combines LineNumbers widget to provide line numbers on the side. The CodeView widget allows you to optionally highlight a specific line and show indentation guidelines. It is not intended to be a fully fledged editor, but rather for showing code snippets to a user. While it is not a fully fledged editor, this widget's code can give you a good starting point.
This commit is contained in:
parent
84b4821d43
commit
ee113c4269
2 changed files with 113 additions and 0 deletions
|
@ -9,3 +9,4 @@ pub const nvim = @import("widgets/nvim.zig");
|
||||||
pub const ScrollView = @import("widgets/ScrollView.zig");
|
pub const ScrollView = @import("widgets/ScrollView.zig");
|
||||||
pub const LineNumbers = @import("widgets/LineNumbers.zig");
|
pub const LineNumbers = @import("widgets/LineNumbers.zig");
|
||||||
pub const TextView = @import("widgets/TextView.zig");
|
pub const TextView = @import("widgets/TextView.zig");
|
||||||
|
pub const CodeView = @import("widgets/CodeView.zig");
|
||||||
|
|
112
src/widgets/CodeView.zig
Normal file
112
src/widgets/CodeView.zig
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const vaxis = @import("../main.zig");
|
||||||
|
const ScrollView = vaxis.widgets.ScrollView;
|
||||||
|
const LineNumbers = vaxis.widgets.LineNumbers;
|
||||||
|
|
||||||
|
pub const DrawOptions = struct {
|
||||||
|
highlighted_line: usize = 0,
|
||||||
|
draw_line_numbers: bool = true,
|
||||||
|
indentation: usize = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Buffer = vaxis.widgets.TextView.Buffer;
|
||||||
|
|
||||||
|
scroll_view: ScrollView = .{ .vertical_scrollbar = null },
|
||||||
|
highlighted_style: vaxis.Style = .{ .bg = .{ .index = 0 } },
|
||||||
|
indentation_cell: vaxis.Cell = .{
|
||||||
|
.char = .{
|
||||||
|
.grapheme = "┆",
|
||||||
|
.width = 1,
|
||||||
|
},
|
||||||
|
.style = .{ .dim = true },
|
||||||
|
},
|
||||||
|
|
||||||
|
pub fn input(self: *@This(), key: vaxis.Key) void {
|
||||||
|
self.scroll_view.input(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(self: *@This(), win: vaxis.Window, buffer: Buffer, opts: DrawOptions) void {
|
||||||
|
const pad_left: usize = if (opts.draw_line_numbers) LineNumbers.numDigits(buffer.rows) +| 1 else 0;
|
||||||
|
self.scroll_view.draw(win, .{
|
||||||
|
.cols = buffer.cols + pad_left,
|
||||||
|
.rows = buffer.rows,
|
||||||
|
});
|
||||||
|
if (opts.draw_line_numbers) {
|
||||||
|
var nl: LineNumbers = .{
|
||||||
|
.highlighted_line = opts.highlighted_line,
|
||||||
|
.num_lines = buffer.rows +| 1,
|
||||||
|
};
|
||||||
|
nl.draw(win.child(.{
|
||||||
|
.x_off = 0,
|
||||||
|
.y_off = 0,
|
||||||
|
.width = .{ .limit = pad_left },
|
||||||
|
.height = .{ .limit = win.height },
|
||||||
|
}), self.scroll_view.scroll.y);
|
||||||
|
}
|
||||||
|
self.drawCode(win.child(.{ .x_off = pad_left }), buffer, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn drawCode(self: *@This(), win: vaxis.Window, buffer: Buffer, opts: DrawOptions) void {
|
||||||
|
const Pos = struct { x: usize = 0, y: usize = 0 };
|
||||||
|
var pos: Pos = .{};
|
||||||
|
var byte_index: usize = 0;
|
||||||
|
var is_indentation = true;
|
||||||
|
const bounds = self.scroll_view.bounds(win);
|
||||||
|
for (buffer.grapheme.items(.len), buffer.grapheme.items(.offset), 0..) |g_len, g_offset, index| {
|
||||||
|
if (bounds.above(pos.y)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cluster = buffer.content.items[g_offset..][0..g_len];
|
||||||
|
defer byte_index += cluster.len;
|
||||||
|
|
||||||
|
if (std.mem.eql(u8, cluster, "\n")) {
|
||||||
|
if (index == buffer.grapheme.len - 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos.y += 1;
|
||||||
|
pos.x = 0;
|
||||||
|
is_indentation = true;
|
||||||
|
continue;
|
||||||
|
} else if (bounds.below(pos.y)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const highlighted_line = pos.y +| 1 == opts.highlighted_line;
|
||||||
|
var style: vaxis.Style = if (highlighted_line) self.highlighted_style else .{};
|
||||||
|
|
||||||
|
if (buffer.style_map.get(byte_index)) |meta| {
|
||||||
|
const tmp = style.bg;
|
||||||
|
style = buffer.style_list.items[meta];
|
||||||
|
style.bg = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const width = win.gwidth(cluster);
|
||||||
|
defer pos.x +|= width;
|
||||||
|
|
||||||
|
if (!bounds.colInside(pos.x)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts.indentation > 0 and !std.mem.eql(u8, cluster, " ")) {
|
||||||
|
is_indentation = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_indentation and opts.indentation > 0 and pos.x % opts.indentation == 0) {
|
||||||
|
var cell = self.indentation_cell;
|
||||||
|
cell.style.bg = style.bg;
|
||||||
|
self.scroll_view.writeCell(win, pos.x, pos.y, cell);
|
||||||
|
} else {
|
||||||
|
self.scroll_view.writeCell(win, pos.x, pos.y, .{
|
||||||
|
.char = .{ .grapheme = cluster, .width = width },
|
||||||
|
.style = style,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (highlighted_line) {
|
||||||
|
for (pos.x +| width..bounds.x2) |x| {
|
||||||
|
self.scroll_view.writeCell(win, x, pos.y, .{ .style = style });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue