summaryrefslogtreecommitdiff
path: root/src/web.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-15 14:46:38 -0300
committerGabriel Schneider <[email protected]>2026-09-15 17:24:42 -0300
commit40c19fd4f52d20df94c2dfa2d68102b89bd9d3f1 (patch)
tree642150be8703f1d9a0766ff18516f06bfdc8801a /src/web.zig
parent379f4fe55c7c9c7c8cc7b97dc921c83e2c24698b (diff)
downloadpardes-40c19fd4f52d20df94c2dfa2d68102b89bd9d3f1.tar.gz
pardes-40c19fd4f52d20df94c2dfa2d68102b89bd9d3f1.zip
Add optional compact tagline styling for source context
Diffstat (limited to 'src/web.zig')
-rw-r--r--src/web.zig77
1 files changed, 66 insertions, 11 deletions
diff --git a/src/web.zig b/src/web.zig
index a1f3bad8..a944a4a5 100644
--- a/src/web.zig
+++ b/src/web.zig
@@ -99,6 +99,7 @@ comptime {
const State = struct {
core: *pardes.Pardes,
+ layer_cells: [pardes.MAX_PANES][]WebCell = @splat(&.{}),
cells: []WebCell = &.{},
frame_len: usize = 0,
frame_cols: u16 = 0,
@@ -127,6 +128,7 @@ const State = struct {
fn deinit(s: *State) void {
if (s.cells.len > 0) gpa.free(s.cells);
+ for (s.layer_cells) |cells| gpa.free(cells);
s.core.deinit();
pardes.image.stop();
if (comptime pardes.pdf_enabled) pardes.pdf.stop();
@@ -207,6 +209,22 @@ export fn pardes_paste(len_arg: u32) void {
/// Buttons and kinds are their boundary enum ordinals. Invalid values are
/// ignored rather than reaching an unchecked enum cast inside wasm.
export fn pardes_mouse(button_arg: u32, kind_arg: u32, col_arg: u32, row_arg: u32, mods: u32) void {
+ mouseWithHit(button_arg, kind_arg, col_arg, row_arg, mods, null);
+}
+
+export fn pardes_mouse_pixel(button_arg: u32, kind_arg: u32, col_arg: u32, row_arg: u32, mods: u32, x: f32, y: f32, bw: f32, bh: f32, tw: f32, th: f32) void {
+ const s = &(state orelse return);
+ const source = s.core.presentation.pointerFractional(s.core.screen_w, s.core.screen_h, x / @max(1, bw), y / @max(1, bh));
+ var hit: ?pardes.Mouse.BodyHit = null;
+ for (&s.core.surface.body_layers) |*layer| {
+ const point = source orelse break;
+ hit = layer.hitAt(point.x * bw, point.y * bh, bw, bh, tw, th);
+ if (hit != null) break;
+ }
+ mouseWithHit(button_arg, kind_arg, col_arg, row_arg, mods, hit);
+}
+
+fn mouseWithHit(button_arg: u32, kind_arg: u32, col_arg: u32, row_arg: u32, mods: u32, hit: ?pardes.Mouse.BodyHit) void {
const s = &(state orelse return);
const button: pardes.Mouse.Button = switch (button_arg) {
0 => .left,
@@ -229,6 +247,7 @@ export fn pardes_mouse(button_arg: u32, kind_arg: u32, col_arg: u32, row_arg: u3
else => return,
};
s.core.update(.{ .mouse = .{
+ .body_hit = hit,
.button = button,
.kind = kind,
.col = @intCast(@min(col_arg, std.math.maxInt(u16))),
@@ -304,6 +323,46 @@ export fn pardes_cursor_x() i32 {
return if (s.core.surface.cursor) |cursor| cursor.x else -1;
}
+export fn pardes_body_layer_value(index: u32, field: u32) u32 {
+ const s = &(state orelse return 0);
+ if (index >= pardes.MAX_PANES) return 0;
+ const layer = &s.core.surface.body_layers[index];
+ return switch (field) {
+ 0 => layer.rows,
+ 1 => layer.cols,
+ 2 => layer.context_rows,
+ 3 => layer.viewport.x,
+ 4 => layer.viewport.y,
+ 5 => layer.viewport.w,
+ 6 => layer.viewport.h,
+ 7 => layer.serial,
+ 8 => if (layer.cursor) |c| c.x else 65535,
+ 9 => if (layer.cursor) |c| c.y else 65535,
+ 10 => if (layer.cursor) |c| @intFromBool(c.bar) else 0,
+ else => 0,
+ };
+}
+
+export fn pardes_body_layer_cells(index: u32) ?[*]const WebCell {
+ const s = &(state orelse return null);
+ if (index >= pardes.MAX_PANES) return null;
+ const layer = &s.core.surface.body_layers[index];
+ if (layer.rows == 0) return null;
+ const cells = &s.layer_cells[index];
+ if (cells.len != layer.cells.len) cells.* = gpa.realloc(cells.*, layer.cells.len) catch return null;
+ for (layer.cells, cells.*) |cell, *out| out.* = encodeWebCell(cell);
+ return cells.ptr;
+}
+
+export fn pardes_body_layer_limit() u32 {
+ return pardes.MAX_PANES;
+}
+
+export fn pardes_row_metrics(body_w: u16, body_h: u16, tagline_w: u16, tagline_h: u16) void {
+ const s = &(state orelse return);
+ s.core.update(.{ .resize = .{ .cols = s.core.screen_w, .rows = s.core.screen_h, .cell_pixels = s.core.cell_pixels, .row_metrics = .{ .body_w = @max(1, body_w), .body_h = @max(1, body_h), .tagline_w = @max(1, tagline_w), .tagline_h = @max(1, tagline_h) } } });
+}
+
export fn pardes_pointer_shape() u32 {
const s = &(state orelse return 0);
return @intFromEnum(s.core.surface.pointer_shape);
@@ -384,17 +443,13 @@ fn present(ctx: ?*anyopaque, surface: *const pardes.Surface) void {
s.frame_len = count;
s.frame_cols = surface.cols;
s.frame_rows = surface.rows;
- for (surface.cells, s.cells[0..count]) |cell, *out| {
- out.* = .{
- .text = @splat(0),
- .fg = encodeColor(cell.style.fg),
- .bg = encodeColor(cell.style.bg),
- .attrs = encodeAttrs(cell.style),
- .len = if (cell.default) 1 else cell.len,
- .flags = @intFromBool(cell.default),
- };
- if (cell.default) out.text[0] = ' ' else @memcpy(out.text[0..cell.len], cell.grapheme());
- }
+ for (surface.cells, s.cells[0..count]) |cell, *out| out.* = encodeWebCell(cell);
+}
+
+fn encodeWebCell(cell: pardes.Cell) WebCell {
+ var out: WebCell = .{ .text = @splat(0), .fg = encodeColor(cell.style.fg), .bg = encodeColor(cell.style.bg), .attrs = encodeAttrs(cell.style), .len = if (cell.default) 1 else cell.len, .flags = @intFromBool(cell.default) };
+ if (cell.default) out.text[0] = ' ' else @memcpy(out.text[0..cell.len], cell.grapheme());
+ return out;
}
fn writeFile(_: ?*anyopaque, _: u8, path: []const u8, bytes: []const u8) void {