5 Commits

Author SHA1 Message Date
b4836b8d2b mod: bump to version 0.0.4
All checks were successful
Zig Project Action / Lint, Spell-check and test zig project (push) Successful in 55s
Release Zig Application / Release zig project (release) Successful in 1m36s
2025-11-08 12:54:20 +01:00
5ee2c6662e feat: invalid page for unavailable resources
All checks were successful
Zig Project Action / Lint, Spell-check and test zig project (push) Successful in 1m46s
Accessing resources which are not available, the invalid page will be
rendered instead. The original attempt for access will be logged.
2025-11-08 12:50:25 +01:00
28afdc0ff9 mod: bump to version 0.0.3
All checks were successful
Zig Project Action / Lint, Spell-check and test zig project (push) Successful in 55s
Release Zig Application / Release zig project (release) Successful in 1m35s
2025-11-05 22:12:27 +01:00
b228c69ae5 mod: bump zterm dependency
All checks were successful
Zig Project Action / Lint, Spell-check and test zig project (push) Successful in 1m7s
2025-11-05 22:10:48 +01:00
489d958ac5 mod: bump zterm dependency; respect scrollbar in calculated size requirement for content
All checks were successful
Zig Project Action / Lint, Spell-check and test zig project (push) Successful in 1m19s
2025-11-05 18:47:59 +01:00
4 changed files with 36 additions and 12 deletions

View File

@@ -1,13 +1,13 @@
.{ .{
.name = .tui_website, .name = .tui_website,
// This is a [Semantic Version](https://semver.org/). // This is a [Semantic Version](https://semver.org/).
.version = "0.0.2", .version = "0.0.4",
.fingerprint = 0x93d98a4d9d000e9c, // Changing this has security and trust implications. .fingerprint = 0x93d98a4d9d000e9c, // Changing this has security and trust implications.
.minimum_zig_version = "0.16.0-dev.463+f624191f9", .minimum_zig_version = "0.16.0-dev.463+f624191f9",
.dependencies = .{ .dependencies = .{
.zterm = .{ .zterm = .{
.url = "git+https://gitea.yves-biener.de/yves-biener/zterm#a83e86f8d931bc8df5e6d18405d2cab6cc6375e7", .url = "git+https://gitea.yves-biener.de/yves-biener/zterm#ad32e46bc9fd6d1d9b7a3615979a3b80877c9300",
.hash = "zterm-0.3.0-1xmmEFoJHADThbLfms-pORIdMp0vs-Zw8FHSzZIyH1OJ", .hash = "zterm-0.3.0-1xmmEO8PHABP4tE6BnEZllJTh6Hpza_5C9wS8s2vjwou",
}, },
.zlog = .{ .zlog = .{
.url = "git+https://gitea.yves-biener.de/yves-biener/zlog#f43034cea9a0863e618c3d0a43706ce38c8791cf", .url = "git+https://gitea.yves-biener.de/yves-biener/zlog#f43034cea9a0863e618c3d0a43706ce38c8791cf",

View File

@@ -22,16 +22,13 @@ pub fn Content(App: type) type {
} }
fn minSize(ctx: *anyopaque, size: zterm.Point) zterm.Point { fn minSize(ctx: *anyopaque, size: zterm.Point) zterm.Point {
// TODO what about that initial size? seems wrong!
if (size.x == 0 or size.y == 0) return size;
const this: *const @This() = @ptrCast(@alignCast(ctx)); const this: *const @This() = @ptrCast(@alignCast(ctx));
const text = this.document.content; const text = this.document.content;
var index: usize = 0; var index: usize = 0;
var new_size: zterm.Point = .{ .x = size.x }; var new_size: zterm.Point = .{ .x = size.x };
for (0..text.len) |_| rows: { for (0..text.len) |_| rows: {
for (0..size.x) |_| { for (0..size.x - 1) |_| { // assume that there is one cell reserved for the scrollbar
if (index == text.len) break :rows; if (index == text.len) break :rows;
const cp = text[index]; const cp = text[index];
index += 1; index += 1;
@@ -60,10 +57,16 @@ pub fn Content(App: type) type {
}, },
.blog => |path| { .blog => |path| {
model.page.deinit(this.allocator); model.page.deinit(this.allocator);
model.document.deinit(this.allocator);
errdefer {
if (path) |p| this.allocator.free(p);
model.document = .invalidPage;
model.page = .{ .blog = null };
}
model.document = .init(try std.fs.cwd().readFileAlloc(if (path) |p| p else "./doc/blog.md", this.allocator, .unlimited));
model.page = .{ .blog = path }; model.page = .{ .blog = path };
model.document.deinit(this.allocator);
model.document = .init(try std.fs.cwd().readFileAlloc(if (path) |p| p else "./doc/blog.md", this.allocator, .unlimited));
this.document = &model.document; this.document = &model.document;
}, },
else => {}, else => {},

View File

@@ -1,4 +1,11 @@
// usage: tui_website <path> // TODO
// - should the path containing the contents of the tui-website reside in the
// hardcode `./doc` directory or shall this become a compilation argument to
// allow for custom directory locations?
// usage: tui_website <location>
// <location>: partial path to the document without the file extension and the beginning `./doc` path
// ending `/` (as used from the web-world) are trimmed automatically
pub fn main() !void { pub fn main() !void {
errdefer |err| log.err("Application Error: {any}", .{err}); errdefer |err| log.err("Application Error: {any}", .{err});
@@ -106,7 +113,11 @@ pub fn main() !void {
// -> enforce a specific structure? // -> enforce a specific structure?
// -> in case an invalid path is provided the 404 error page shall be shown // -> in case an invalid path is provided the 404 error page shall be shown
// -> reporte an corresponding error! (such that I can see that in the log) // -> reporte an corresponding error! (such that I can see that in the log)
app.postEvent(.{ .blog = try allocator.dupe(u8, path) }); var blog = path[0..path.len];
blog = std.mem.trimStart(u8, blog, "./");
blog = std.mem.trimEnd(u8, blog, ".md");
blog = std.mem.trimEnd(u8, blog, "/");
app.postEvent(.{ .blog = try std.fmt.allocPrint(allocator, "./doc/{s}.md", .{blog}) });
} }
arg_it.deinit(); arg_it.deinit();
@@ -127,10 +138,12 @@ pub fn main() !void {
// pre event handling // pre event handling
switch (event) { switch (event) {
.key => |key| { .key => |key| {
if (key.eql(.{ .cp = 'c', .mod = .{ .ctrl = true } })) app.quit(); if (key.eql(.{ .cp = 'c', .mod = .{ .ctrl = true } }) or key.eql(.{ .cp = 'q' })) app.quit();
// test if the event handling is working correctly // test if the event handling is working correctly
if (key.eql(.{ .cp = zterm.input.Space })) app.postEvent(.{ .blog = allocator.dupe(u8, "./doc/test.md") catch unreachable }); if (key.eql(.{ .cp = zterm.input.Space })) app.postEvent(.{ .blog = allocator.dupe(u8, "./doc/test.md") catch unreachable });
}, },
.about => log.info(ResourceRequestFormat, .{"./doc/about.md"}),
.blog => |path| log.info(ResourceRequestFormat, .{if (path) |p| p else "./doc/blog.md"}),
.err => |err| log.err("Received {s} with message: {s}", .{ @errorName(err.err), err.msg }), .err => |err| log.err("Received {s} with message: {s}", .{ @errorName(err.err), err.msg }),
else => {}, else => {},
} }
@@ -161,6 +174,8 @@ pub const panic = App.panic_handler;
pub const std_options = zlog.std_options; pub const std_options = zlog.std_options;
const log = std.log.scoped(.default); const log = std.log.scoped(.default);
const ResourceRequestFormat = "Requesting resource: `{s}`";
const std = @import("std"); const std = @import("std");
const assert = std.debug.assert; const assert = std.debug.assert;
const zlog = @import("zlog"); const zlog = @import("zlog");

View File

@@ -33,6 +33,12 @@ pub const Document = struct {
date, date,
}; };
pub const invalidPage: @This() = .{
.title = "Page not found",
.content = "Requested page does not exist",
.ptr = undefined,
};
pub fn init(content: []const u8) @This() { pub fn init(content: []const u8) @This() {
if (std.mem.startsWith(u8, content, "---\n")) { if (std.mem.startsWith(u8, content, "---\n")) {
var document: @This() = .{ .ptr = content }; var document: @This() = .{ .ptr = content };