Files
zterm/src/widget/RawText.zig
Yves Biener b314ff7813
Some checks failed
Zig Project Action / Lint, Spell-check and test zig project (push) Failing after 30s
mod: replace Layout.content with Layout.render
The App.Renderer is used for the new `Layout.render` method. Each layout
renders itself now with corresponding renderers which might only update
parts of the screen, etc.
2024-11-10 14:34:28 +01:00

96 lines
3.5 KiB
Zig

const std = @import("std");
const terminal = @import("../terminal.zig");
const isTaggedUnion = @import("../event.zig").isTaggedUnion;
const Error = @import("../event.zig").Error;
const Key = terminal.Key;
const Style = terminal.Style;
const log = std.log.scoped(.widget_rawtext);
pub fn Widget(comptime Event: type) type {
if (!isTaggedUnion(Event)) {
@compileError("Provided user event `Event` for `Layout(comptime Event: type)` is not of type `union(enum)`.");
}
const Contents = std.ArrayList(u8);
return struct {
contents: Contents = undefined,
line_index: std.ArrayList(usize) = undefined,
line: usize = 0,
size: terminal.Size = undefined,
pub fn init(allocator: std.mem.Allocator, file: std.fs.File) @This() {
var contents = Contents.init(allocator);
var line_index = std.ArrayList(usize).init(allocator);
file.reader().readAllArrayList(&contents, std.math.maxInt(usize)) catch {};
line_index.append(0) catch {};
for (contents.items, 0..) |item, i| {
if (item == '\n') {
line_index.append(i + 1) catch {};
}
}
return .{
.contents = contents,
.line_index = line_index,
};
}
pub fn deinit(this: *@This()) void {
this.contents.deinit();
this.line_index.deinit();
this.* = undefined;
}
pub fn handle(this: *@This(), event: Event) ?Event {
switch (event) {
// store the received size
.resize => |size| {
this.size = size;
if (this.line > this.line_index.items.len -| 1 -| size.rows) {
this.line = this.line_index.items.len -| 1 -| size.rows;
}
},
.key => |key| {
if (key.matches(.{ .cp = 'g' })) {
// top
this.line = 0;
}
if (key.matches(.{ .cp = 'G' })) {
// bottom
this.line = this.line_index.items.len -| 1 -| this.size.rows;
}
if (key.matches(.{ .cp = 'j' })) {
// down
if (this.line < this.line_index.items.len -| 1 -| this.size.rows) {
this.line +|= 1;
}
}
if (key.matches(.{ .cp = 'k' })) {
// up
this.line -|= 1;
}
},
else => {},
}
return null;
}
pub fn content(this: *@This()) ![]u8 {
if (this.size.rows >= this.line_index.items.len) {
return this.contents.items;
} else {
// more rows than we can display
const i = this.line_index.items[this.line];
const e = this.size.rows + this.line + 1;
if (e >= this.line_index.items.len) {
return this.contents.items[i..];
}
// last line should not end with the last character (likely a newline character)
// FIX: what about files which do not end with a newline?
const x = this.line_index.items[e] - 1;
return this.contents.items[i..x];
}
}
};
}