mod: replace Layout.content with Layout.render
Some checks failed
Zig Project Action / Lint, Spell-check and test zig project (push) Failing after 30s
Some checks failed
Zig Project Action / Lint, Spell-check and test zig project (push) Failing after 30s
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.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
.zig-cache/
|
||||
zig-out/
|
||||
log
|
||||
TODO.md
|
||||
|
||||
@@ -45,9 +45,9 @@ pub fn App(comptime E: type, comptime R: fn (comptime bool) type, comptime fulls
|
||||
}
|
||||
return struct {
|
||||
pub const Event = mergeTaggedUnions(event.SystemEvent, E);
|
||||
pub const Layout = @import("layout.zig").Layout(Event);
|
||||
pub const Widget = @import("widget.zig").Widget(Event);
|
||||
pub const Renderer = R(fullscreen);
|
||||
pub const Layout = @import("layout.zig").Layout(Event, Renderer);
|
||||
pub const Widget = @import("widget.zig").Widget(Event);
|
||||
|
||||
queue: Queue(Event, 256) = .{},
|
||||
thread: ?std.Thread = null,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Dynamic dispatch for layout implementations.
|
||||
//! Each layout should at last implement these functions:
|
||||
//! - handle(this: *@This(), event: Event) anyerror!*std.ArrayList(Event) {}
|
||||
//! - content(this: *@This()) anyerror!*std.ArrayList(u8) {}
|
||||
//! - render(this: *@This(), renderer: Renderer) anyerror!void {}
|
||||
//! - deinit(this: *@This()) void {}
|
||||
//!
|
||||
//! Create a `Layout` using `createFrom(object: anytype)` and use them through
|
||||
@@ -11,10 +11,13 @@
|
||||
//! Each `Layout` is responsible for clearing the allocated memory of the used
|
||||
//! widgets when deallocated. This means that `deinit()` will also deallocate
|
||||
//! every used widget too.
|
||||
//!
|
||||
//! When `Layout.render` is called the provided `Renderer` type is expected
|
||||
//! which handles how contents are rendered for a given layout.
|
||||
const std = @import("std");
|
||||
const isTaggedUnion = @import("event.zig").isTaggedUnion;
|
||||
|
||||
pub fn Layout(comptime Event: type) type {
|
||||
pub fn Layout(comptime Event: type, comptime Renderer: type) type {
|
||||
if (!isTaggedUnion(Event)) {
|
||||
@compileError("Provided user event `Event` for `Layout(comptime Event: type)` is not of type `union(enum)`.");
|
||||
}
|
||||
@@ -25,7 +28,7 @@ pub fn Layout(comptime Event: type) type {
|
||||
|
||||
const VTable = struct {
|
||||
handle: *const fn (this: *LayoutType, event: Event) anyerror!*Events,
|
||||
content: *const fn (this: *LayoutType) anyerror!*std.ArrayList(u8),
|
||||
render: *const fn (this: *LayoutType, renderer: Renderer) anyerror!void,
|
||||
deinit: *const fn (this: *LayoutType) void,
|
||||
};
|
||||
|
||||
@@ -37,9 +40,9 @@ pub fn Layout(comptime Event: type) type {
|
||||
return try this.vtable.handle(this, event);
|
||||
}
|
||||
|
||||
// Return the entire content of this `Layout`.
|
||||
pub fn content(this: *LayoutType) !*std.ArrayList(u8) {
|
||||
return try this.vtable.content(this);
|
||||
// Render this `Layout` completely. This will render contained sub-elements too.
|
||||
pub fn render(this: *LayoutType, renderer: Renderer) !void {
|
||||
return try this.vtable.render(this, renderer);
|
||||
}
|
||||
|
||||
pub fn deinit(this: *LayoutType) void {
|
||||
@@ -58,13 +61,13 @@ pub fn Layout(comptime Event: type) type {
|
||||
return try layout.handle(event);
|
||||
}
|
||||
}.handle,
|
||||
.content = struct {
|
||||
// Return the entire content of this `Layout`.
|
||||
fn content(this: *LayoutType) !*std.ArrayList(u8) {
|
||||
.render = struct {
|
||||
// Render the contents of this `Layout`.
|
||||
fn render(this: *LayoutType, renderer: Renderer) !void {
|
||||
const layout: @TypeOf(object) = @ptrFromInt(this.object);
|
||||
return try layout.content();
|
||||
try layout.render(renderer);
|
||||
}
|
||||
}.content,
|
||||
}.render,
|
||||
.deinit = struct {
|
||||
fn deinit(this: *LayoutType) void {
|
||||
const layout: @TypeOf(object) = @ptrFromInt(this.object);
|
||||
@@ -76,9 +79,9 @@ pub fn Layout(comptime Event: type) type {
|
||||
}
|
||||
|
||||
// import and export of `Layout` implementations
|
||||
pub const HStack = @import("layout/HStack.zig").Layout(Event);
|
||||
pub const VStack = @import("layout/VStack.zig").Layout(Event);
|
||||
pub const Padding = @import("layout/Padding.zig").Layout(Event);
|
||||
pub const Framing = @import("layout/Framing.zig").Layout(Event);
|
||||
pub const HStack = @import("layout/HStack.zig").Layout(Event, Renderer);
|
||||
pub const VStack = @import("layout/VStack.zig").Layout(Event, Renderer);
|
||||
pub const Padding = @import("layout/Padding.zig").Layout(Event, Renderer);
|
||||
pub const Framing = @import("layout/Framing.zig").Layout(Event, Renderer);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,32 +11,28 @@ const Key = terminal.Key;
|
||||
|
||||
const log = std.log.scoped(.layout_framing);
|
||||
|
||||
pub fn Layout(comptime Event: type) type {
|
||||
pub fn Layout(comptime Event: type, comptime Renderer: type) type {
|
||||
if (!isTaggedUnion(Event)) {
|
||||
@compileError("Provided user event `Event` for `Layout(comptime Event: type)` is not of type `union(enum)`.");
|
||||
}
|
||||
const Element = union(enum) {
|
||||
layout: @import("../layout.zig").Layout(Event),
|
||||
layout: @import("../layout.zig").Layout(Event, Renderer),
|
||||
widget: @import("../widget.zig").Widget(Event),
|
||||
};
|
||||
const Events = std.ArrayList(Event);
|
||||
const Contents = std.ArrayList(u8);
|
||||
return struct {
|
||||
size: terminal.Size = undefined,
|
||||
contents: Contents = undefined,
|
||||
element: Element = undefined,
|
||||
events: Events = undefined,
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator, element: Element) @This() {
|
||||
return .{
|
||||
.contents = Contents.init(allocator),
|
||||
.element = element,
|
||||
.events = Events.init(allocator),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(this: *@This()) void {
|
||||
this.contents.deinit();
|
||||
this.events.deinit();
|
||||
switch ((&this.element).*) {
|
||||
.layout => |*layout| {
|
||||
@@ -85,19 +81,18 @@ pub fn Layout(comptime Event: type) type {
|
||||
return &this.events;
|
||||
}
|
||||
|
||||
pub fn content(this: *@This()) !*Contents {
|
||||
this.contents.clearRetainingCapacity();
|
||||
pub fn render(this: *@This(), renderer: Renderer) !void {
|
||||
// TODO: padding contents accordingly
|
||||
switch ((&this.element).*) {
|
||||
.layout => |*layout| {
|
||||
const layout_content = try layout.content();
|
||||
try this.contents.appendSlice(layout_content.items);
|
||||
try layout.render(renderer);
|
||||
},
|
||||
.widget => |*widget| {
|
||||
try this.contents.appendSlice(try widget.content());
|
||||
const content = try widget.content();
|
||||
// TODO: use renderer
|
||||
_ = try terminal.write(content);
|
||||
},
|
||||
}
|
||||
return &this.contents;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,23 +11,21 @@ const Key = terminal.Key;
|
||||
|
||||
const log = std.log.scoped(.layout_hstack);
|
||||
|
||||
pub fn Layout(comptime Event: type) type {
|
||||
pub fn Layout(comptime Event: type, comptime Renderer: type) type {
|
||||
if (!isTaggedUnion(Event)) {
|
||||
@compileError("Provided user event `Event` for `Layout(comptime Event: type)` is not of type `union(enum)`.");
|
||||
}
|
||||
const Widget = @import("../widget.zig").Widget(Event);
|
||||
const Lay = @import("../layout.zig").Layout(Event);
|
||||
const Lay = @import("../layout.zig").Layout(Event, Renderer);
|
||||
const Element = union(enum) {
|
||||
layout: Lay,
|
||||
widget: Widget,
|
||||
};
|
||||
const Elements = std.ArrayList(Element);
|
||||
const Events = std.ArrayList(Event);
|
||||
const Contents = std.ArrayList(u8);
|
||||
return struct {
|
||||
// TODO: current focused `Element`?
|
||||
size: terminal.Size = undefined,
|
||||
contents: Contents = undefined,
|
||||
elements: Elements = undefined,
|
||||
events: Events = undefined,
|
||||
|
||||
@@ -53,7 +51,6 @@ pub fn Layout(comptime Event: type) type {
|
||||
@compileError("child: " ++ field.name ++ " is not of type " ++ @typeName(Lay) ++ " or " ++ @typeName(Widget) ++ " but " ++ @typeName(ChildType));
|
||||
}
|
||||
return .{
|
||||
.contents = Contents.init(allocator),
|
||||
.elements = elements,
|
||||
.events = Events.init(allocator),
|
||||
};
|
||||
@@ -61,7 +58,6 @@ pub fn Layout(comptime Event: type) type {
|
||||
|
||||
pub fn deinit(this: *@This()) void {
|
||||
this.events.deinit();
|
||||
this.contents.deinit();
|
||||
for (this.elements.items) |*element| {
|
||||
switch (element.*) {
|
||||
.layout => |*layout| {
|
||||
@@ -116,21 +112,21 @@ pub fn Layout(comptime Event: type) type {
|
||||
return &this.events;
|
||||
}
|
||||
|
||||
pub fn content(this: *@This()) !*Contents {
|
||||
this.contents.clearRetainingCapacity();
|
||||
// TODO: concat contents accordingly to create a vertical stack
|
||||
pub fn render(this: *@This(), renderer: Renderer) !void {
|
||||
// TODO: concat contents accordingly to create a horizontal stack
|
||||
for (this.elements.items) |*element| {
|
||||
switch (element.*) {
|
||||
.layout => |*layout| {
|
||||
const layout_content = try layout.content();
|
||||
try this.contents.appendSlice(layout_content.items);
|
||||
try layout.render(renderer);
|
||||
},
|
||||
.widget => |*widget| {
|
||||
try this.contents.appendSlice(try widget.content());
|
||||
// TODO: clear per widget if necessary (i.e. can I query that?)
|
||||
// TODO: render using `renderer`
|
||||
const content = try widget.content();
|
||||
_ = try terminal.write(content);
|
||||
},
|
||||
}
|
||||
}
|
||||
return &this.contents;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,32 +11,28 @@ const Key = terminal.Key;
|
||||
|
||||
const log = std.log.scoped(.layout_padding);
|
||||
|
||||
pub fn Layout(comptime Event: type) type {
|
||||
pub fn Layout(comptime Event: type, comptime Renderer: type) type {
|
||||
if (!isTaggedUnion(Event)) {
|
||||
@compileError("Provided user event `Event` for `Layout(comptime Event: type)` is not of type `union(enum)`.");
|
||||
}
|
||||
const Element = union(enum) {
|
||||
layout: @import("../layout.zig").Layout(Event),
|
||||
layout: @import("../layout.zig").Layout(Event, Renderer),
|
||||
widget: @import("../widget.zig").Widget(Event),
|
||||
};
|
||||
const Events = std.ArrayList(Event);
|
||||
const Contents = std.ArrayList(u8);
|
||||
return struct {
|
||||
size: terminal.Size = undefined,
|
||||
contents: Contents = undefined,
|
||||
element: Element = undefined,
|
||||
events: Events = undefined,
|
||||
|
||||
pub fn init(allocator: std.mem.Allocator, element: Element) @This() {
|
||||
return .{
|
||||
.contents = Contents.init(allocator),
|
||||
.element = element,
|
||||
.events = Events.init(allocator),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(this: *@This()) void {
|
||||
this.contents.deinit();
|
||||
this.events.deinit();
|
||||
switch ((&this.element).*) {
|
||||
.layout => |*layout| {
|
||||
@@ -85,19 +81,18 @@ pub fn Layout(comptime Event: type) type {
|
||||
return &this.events;
|
||||
}
|
||||
|
||||
pub fn content(this: *@This()) !*Contents {
|
||||
this.contents.clearRetainingCapacity();
|
||||
pub fn render(this: *@This(), renderer: Renderer) !void {
|
||||
// TODO: padding contents accordingly
|
||||
switch ((&this.element).*) {
|
||||
.layout => |*layout| {
|
||||
const layout_content = try layout.content();
|
||||
try this.contents.appendSlice(layout_content.items);
|
||||
try layout.render(renderer);
|
||||
},
|
||||
.widget => |*widget| {
|
||||
try this.contents.appendSlice(try widget.content());
|
||||
const content = try widget.content();
|
||||
// TODO: use renderer
|
||||
_ = try terminal.write(content);
|
||||
},
|
||||
}
|
||||
return &this.contents;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,23 +11,24 @@ const Key = terminal.Key;
|
||||
|
||||
const log = std.log.scoped(.layout_vstack);
|
||||
|
||||
pub fn Layout(comptime Event: type) type {
|
||||
pub fn Layout(comptime Event: type, comptime Renderer: type) type {
|
||||
if (!isTaggedUnion(Event)) {
|
||||
@compileError("Provided user event `Event` for `Layout(comptime Event: type)` is not of type `union(enum)`.");
|
||||
}
|
||||
const Widget = @import("../widget.zig").Widget(Event);
|
||||
const Lay = @import("../layout.zig").Layout(Event);
|
||||
const Lay = @import("../layout.zig").Layout(Event, Renderer);
|
||||
const Element = union(enum) {
|
||||
layout: Lay,
|
||||
widget: Widget,
|
||||
};
|
||||
const Elements = std.ArrayList(Element);
|
||||
const Events = std.ArrayList(Event);
|
||||
const Contents = std.ArrayList(u8);
|
||||
return struct {
|
||||
// TODO: current focused `Element`?
|
||||
// FIX: this should not be 'hardcoded' but dynamically be calculated and updated (i.e. through the event system)
|
||||
anchor: terminal.Position = .{ .col = 1, .row = 1 },
|
||||
size: terminal.Size = undefined,
|
||||
contents: Contents = undefined,
|
||||
element_rows: u16 = undefined,
|
||||
elements: Elements = undefined,
|
||||
events: Events = undefined,
|
||||
|
||||
@@ -53,7 +54,6 @@ pub fn Layout(comptime Event: type) type {
|
||||
@compileError("child: " ++ field.name ++ " is not of type " ++ @typeName(Lay) ++ " or " ++ @typeName(Widget) ++ " but " ++ @typeName(ChildType));
|
||||
}
|
||||
return .{
|
||||
.contents = Contents.init(allocator),
|
||||
.elements = elements,
|
||||
.events = Events.init(allocator),
|
||||
};
|
||||
@@ -61,7 +61,6 @@ pub fn Layout(comptime Event: type) type {
|
||||
|
||||
pub fn deinit(this: *@This()) void {
|
||||
this.events.deinit();
|
||||
this.contents.deinit();
|
||||
for (this.elements.items) |*element| {
|
||||
switch (element.*) {
|
||||
.layout => |*layout| {
|
||||
@@ -83,9 +82,15 @@ pub fn Layout(comptime Event: type) type {
|
||||
this.size = size;
|
||||
log.debug("Using size: {{ .cols = {d}, .rows = {d} }}", .{ size.cols, size.rows });
|
||||
const len: u16 = @truncate(this.elements.items.len);
|
||||
const rows = size.rows / len;
|
||||
this.element_rows = @divTrunc(size.rows, len);
|
||||
var overflow = this.size.rows % len;
|
||||
// adjust size according to the containing elements
|
||||
for (this.elements.items) |*element| {
|
||||
var rows = this.element_rows;
|
||||
if (overflow > 0) {
|
||||
overflow -|= 1;
|
||||
rows += 1;
|
||||
}
|
||||
const sub_event: Event = .{
|
||||
.resize = .{
|
||||
.cols = size.cols,
|
||||
@@ -124,26 +129,32 @@ pub fn Layout(comptime Event: type) type {
|
||||
return &this.events;
|
||||
}
|
||||
|
||||
pub fn content(this: *@This()) !*Contents {
|
||||
this.contents.clearRetainingCapacity();
|
||||
// TODO: concat contents accordingly to create a horizontal stack
|
||||
for (this.elements.items, 1..) |*element, i| {
|
||||
pub fn render(this: *@This(), renderer: Renderer) !void {
|
||||
// FIX: renderer should clear only what is going to change! (i.e. the 'active' widget / layout)
|
||||
try renderer.clear(this.anchor, this.size);
|
||||
var overflow = this.size.rows % this.elements.items.len;
|
||||
for (this.elements.items, 0..) |*element, i| {
|
||||
const row_mul: u16 = @truncate(i);
|
||||
var row = row_mul * this.element_rows + 1;
|
||||
if (i > 0 and overflow > 0) {
|
||||
overflow -|= 1;
|
||||
row += 1;
|
||||
}
|
||||
const pos: terminal.Position = .{ .col = 1, .row = row };
|
||||
log.debug("using position: .{{ .cols = {d}, .rows = {d} }}", .{ pos.col, pos.row });
|
||||
// TODO: do this using the renderer
|
||||
try terminal.setCursorPosition(pos);
|
||||
switch (element.*) {
|
||||
.layout => |*layout| {
|
||||
const layout_content = try layout.content();
|
||||
try this.contents.appendSlice(layout_content.items);
|
||||
try layout.render(renderer);
|
||||
},
|
||||
.widget => |*widget| {
|
||||
const widget_content = try widget.content();
|
||||
try this.contents.appendSlice(widget_content);
|
||||
// TODO: clear per widget if necesary (i.e. can I query that?)
|
||||
const content = try widget.content();
|
||||
_ = try terminal.write(content);
|
||||
},
|
||||
}
|
||||
// TODO: support clear positioning of content on the tui screen
|
||||
if (i != this.elements.items.len) {
|
||||
try this.contents.appendSlice("\n"); // NOTE: this assumes that the previous content fills all the provided size.rows accordingly with content, such that a newline introduces the start of the next content
|
||||
}
|
||||
}
|
||||
return &this.contents;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
14
src/main.zig
14
src/main.zig
@@ -24,7 +24,9 @@ pub fn main() !void {
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
var app: App = .{};
|
||||
var renderer: App.Renderer = .{};
|
||||
const renderer: App.Renderer = .{};
|
||||
// FIX: when not running fullscreen, the application needs to screen down accordingly to display the contents
|
||||
// -> size hint how much should it use?
|
||||
|
||||
const mainFile = try std.fs.cwd().openFile("./src/main.zig", .{});
|
||||
var mainFileText = App.Widget.RawText.init(allocator, mainFile);
|
||||
@@ -35,17 +37,11 @@ pub fn main() !void {
|
||||
appFile.close();
|
||||
|
||||
var spacer = App.Widget.Spacer.init();
|
||||
var framing = App.Layout.Framing.init(allocator, .{
|
||||
.widget = App.Widget.createFrom(&mainFileText),
|
||||
});
|
||||
var hstack = App.Layout.HStack.init(allocator, .{
|
||||
App.Layout.createFrom(&framing),
|
||||
});
|
||||
// TODO: corresponding contents need to be filled out by the layout accordingly!
|
||||
var vstack = App.Layout.VStack.init(allocator, .{
|
||||
App.Widget.createFrom(&appFileText),
|
||||
App.Layout.createFrom(&hstack),
|
||||
App.Widget.createFrom(&spacer),
|
||||
App.Widget.createFrom(&mainFileText),
|
||||
});
|
||||
var layout = App.Layout.createFrom(&vstack);
|
||||
defer layout.deinit();
|
||||
@@ -88,6 +84,6 @@ pub fn main() !void {
|
||||
for (events.items) |e| {
|
||||
app.postEvent(e);
|
||||
}
|
||||
try renderer.render(try layout.content());
|
||||
try layout.render(renderer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ const std = @import("std");
|
||||
const terminal = @import("terminal.zig");
|
||||
|
||||
const Contents = std.ArrayList(u8);
|
||||
const Position = terminal.Position;
|
||||
const Size = terminal.Size;
|
||||
|
||||
pub fn Buffered(comptime fullscreen: bool) type {
|
||||
@@ -40,16 +41,23 @@ pub fn Buffered(comptime fullscreen: bool) type {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn Plain(comptime fullscreen: bool) type {
|
||||
pub fn Plain(comptime _: bool) type {
|
||||
return struct {
|
||||
pub fn render(this: *@This(), content: *Contents) !void {
|
||||
pub fn clear(this: @This(), anchor: Position, size: Size) !void {
|
||||
_ = this;
|
||||
if (fullscreen) {
|
||||
_ = size;
|
||||
// NOTE: clear entire screen for the first content (derived from the anchor being at the very left-top)
|
||||
if (anchor.col == 1 and anchor.row == 1) {
|
||||
try terminal.clearScreen();
|
||||
try terminal.setCursorPositionHome();
|
||||
}
|
||||
// TODO: how would I clear the screen in case of a non fullscreen application (i.e. to clear to the start of the command)
|
||||
_ = try terminal.write(content.items);
|
||||
}
|
||||
|
||||
pub fn render(this: @This(), anchor: Position, size: Size, contents: *Contents) !void {
|
||||
_ = this;
|
||||
_ = size;
|
||||
// FIXME: this should respect the given `size`
|
||||
try terminal.setCursorPosition(anchor);
|
||||
_ = try terminal.write(contents.items);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -62,6 +62,12 @@ pub fn write(buf: []const u8) !usize {
|
||||
return try std.posix.write(std.posix.STDIN_FILENO, buf);
|
||||
}
|
||||
|
||||
pub fn setCursorPosition(pos: Position) !void {
|
||||
var buf: [64]u8 = undefined;
|
||||
const value = try std.fmt.bufPrint(&buf, "\x1b[{d};{d}H", .{ pos.row, pos.col });
|
||||
_ = try std.posix.write(std.posix.STDIN_FILENO, value);
|
||||
}
|
||||
|
||||
pub fn getCursorPosition() !Position {
|
||||
// Needs Raw mode (no wait for \n) to work properly cause
|
||||
// control sequence will not be written without it.
|
||||
|
||||
@@ -10,8 +10,11 @@
|
||||
//!
|
||||
//! Each `Widget` may cache its content and should if the contents will not
|
||||
//! change for a long time.
|
||||
const std = @import("std");
|
||||
const isTaggedUnion = @import("event.zig").isTaggedUnion;
|
||||
|
||||
const log = std.log.scoped(.widget);
|
||||
|
||||
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)`.");
|
||||
@@ -31,6 +34,12 @@ pub fn Widget(comptime Event: type) type {
|
||||
|
||||
// Handle the provided `Event` for this `Widget`.
|
||||
pub fn handle(this: *WidgetType, event: Event) ?Event {
|
||||
switch (event) {
|
||||
.resize => |size| {
|
||||
log.debug("received size: .{{ .cols = {d}, .rows = {d} }}", .{ size.cols, size.rows });
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
return this.vtable.handle(this, event);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,6 @@ pub fn Widget(comptime Event: type) type {
|
||||
// store the received size
|
||||
.resize => |size| {
|
||||
this.size = size;
|
||||
log.debug("Using size: {{ .cols = {d}, .rows = {d} }}", .{ size.cols, size.rows });
|
||||
if (this.line > this.line_index.items.len -| 1 -| size.rows) {
|
||||
this.line = this.line_index.items.len -| 1 -| size.rows;
|
||||
}
|
||||
@@ -82,11 +81,12 @@ pub fn Widget(comptime Event: type) type {
|
||||
} else {
|
||||
// more rows than we can display
|
||||
const i = this.line_index.items[this.line];
|
||||
log.debug("i := {d} this.line := {d}", .{ i, this.line });
|
||||
const e = this.size.rows + 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];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user