refactor: remove notcurses renderer
This commit is contained in:
		
							parent
							
								
									32528333b5
								
							
						
					
					
						commit
						3bd10e106d
					
				
					 6 changed files with 0 additions and 909 deletions
				
			
		| 
						 | 
					@ -1,38 +0,0 @@
 | 
				
			||||||
const nc = @import("notcurses");
 | 
					 | 
				
			||||||
const Style = @import("theme").Style;
 | 
					 | 
				
			||||||
const channels = @import("channels.zig");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub const Cell = struct {
 | 
					 | 
				
			||||||
    cell: nc.Cell,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub inline fn set_style(cell: *Cell, style_: Style) void {
 | 
					 | 
				
			||||||
        channels.from_style(&cell.cell.channels, style_);
 | 
					 | 
				
			||||||
        if (style_.fs) |fs| switch (fs) {
 | 
					 | 
				
			||||||
            .normal => nc.cell_set_styles(&cell.cell, nc.style.none),
 | 
					 | 
				
			||||||
            .bold => nc.cell_set_styles(&cell.cell, nc.style.bold),
 | 
					 | 
				
			||||||
            .italic => nc.cell_set_styles(&cell.cell, nc.style.italic),
 | 
					 | 
				
			||||||
            .underline => nc.cell_set_styles(&cell.cell, nc.style.underline),
 | 
					 | 
				
			||||||
            .undercurl => nc.cell_set_styles(&cell.cell, nc.style.undercurl),
 | 
					 | 
				
			||||||
            .strikethrough => nc.cell_set_styles(&cell.cell, nc.style.struck),
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub inline fn set_style_fg(cell: *Cell, style_: Style) void {
 | 
					 | 
				
			||||||
        channels.fg_from_style(&cell.cell.channels, style_);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub inline fn set_style_bg(cell: *Cell, style_: Style) void {
 | 
					 | 
				
			||||||
        channels.bg_from_style(&cell.cell.channels, style_);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub inline fn set_fg_rgb(cell: *Cell, arg_rgb: c_uint) !void {
 | 
					 | 
				
			||||||
        return channels.set_fg_rgb(&cell.cell.channels, arg_rgb);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pub inline fn set_bg_rgb(cell: *Cell, arg_rgb: c_uint) !void {
 | 
					 | 
				
			||||||
        return channels.set_bg_rgb(&cell.cell.channels, arg_rgb);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn columns(cell: *const Cell) usize {
 | 
					 | 
				
			||||||
        return nc.cell_cols(&cell.cell);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,277 +0,0 @@
 | 
				
			||||||
const nc = @import("notcurses");
 | 
					 | 
				
			||||||
const Style = @import("theme").Style;
 | 
					 | 
				
			||||||
const channels = @import("channels.zig");
 | 
					 | 
				
			||||||
const StyleBits = @import("style.zig").StyleBits;
 | 
					 | 
				
			||||||
const Cell = @import("Cell.zig").Cell;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub const Plane = struct {
 | 
					 | 
				
			||||||
    plane: nc.Plane,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub const Options = struct {
 | 
					 | 
				
			||||||
        y: usize = 0,
 | 
					 | 
				
			||||||
        x: usize = 0,
 | 
					 | 
				
			||||||
        rows: usize = 0,
 | 
					 | 
				
			||||||
        cols: usize = 0,
 | 
					 | 
				
			||||||
        name: [*:0]const u8,
 | 
					 | 
				
			||||||
        flags: option = .none,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub const option = enum {
 | 
					 | 
				
			||||||
        none,
 | 
					 | 
				
			||||||
        VSCROLL,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn init(nopts: *const Options, parent_: Plane) !Plane {
 | 
					 | 
				
			||||||
        var nopts_: nc.Plane.Options = .{
 | 
					 | 
				
			||||||
            .y = @intCast(nopts.y),
 | 
					 | 
				
			||||||
            .x = @intCast(nopts.x),
 | 
					 | 
				
			||||||
            .rows = @intCast(nopts.rows),
 | 
					 | 
				
			||||||
            .cols = @intCast(nopts.cols),
 | 
					 | 
				
			||||||
            .name = nopts.name,
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        switch (nopts.flags) {
 | 
					 | 
				
			||||||
            .none => {},
 | 
					 | 
				
			||||||
            .VSCROLL => nopts_.flags = nc.Plane.option.VSCROLL,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return .{ .plane = nc.Plane.init(&nopts_, parent_.plane) catch |e| return e };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn deinit(self: *Plane) void {
 | 
					 | 
				
			||||||
        self.plane.deinit();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn name(self: Plane, buf: []u8) []u8 {
 | 
					 | 
				
			||||||
        return self.plane.name(buf);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn parent(self: Plane) Plane {
 | 
					 | 
				
			||||||
        return .{ .plane = self.plane.parent() };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn above(self: Plane) ?Plane {
 | 
					 | 
				
			||||||
        return .{ .plane = self.plane.above() orelse return null };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn below(self: Plane) ?Plane {
 | 
					 | 
				
			||||||
        return .{ .plane = self.plane.below() orelse return null };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn erase(self: Plane) void {
 | 
					 | 
				
			||||||
        return self.plane.erase();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn abs_y(self: Plane) c_int {
 | 
					 | 
				
			||||||
        return self.plane.abs_y();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn abs_x(self: Plane) c_int {
 | 
					 | 
				
			||||||
        return self.plane.abs_x();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn dim_y(self: Plane) c_uint {
 | 
					 | 
				
			||||||
        return self.plane.dim_y();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn dim_x(self: Plane) c_uint {
 | 
					 | 
				
			||||||
        return self.plane.dim_x();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn abs_yx_to_rel(self: Plane, y: c_int, x: c_int) struct { c_int, c_int } {
 | 
					 | 
				
			||||||
        var y_, var x_ = .{ y, x };
 | 
					 | 
				
			||||||
        self.plane.abs_yx_to_rel(&y_, &x_);
 | 
					 | 
				
			||||||
        return .{ y_, x_ };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn rel_yx_to_abs(self: Plane, y: c_int, x: c_int) struct { c_int, c_int } {
 | 
					 | 
				
			||||||
        var y_, var x_ = .{ y, x };
 | 
					 | 
				
			||||||
        self.plane.rel_yx_to_abs(&y_, &x_);
 | 
					 | 
				
			||||||
        return .{ y_, x_ };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn hide(self: Plane) void {
 | 
					 | 
				
			||||||
        self.plane.move_bottom();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn move_yx(self: Plane, y: c_int, x: c_int) !void {
 | 
					 | 
				
			||||||
        return self.plane.move_yx(y, x);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn resize_simple(self: Plane, ylen: c_uint, xlen: c_uint) !void {
 | 
					 | 
				
			||||||
        return self.plane.resize_simple(ylen, xlen);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn home(self: Plane) void {
 | 
					 | 
				
			||||||
        return self.plane.home();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn print(self: Plane, comptime fmt: anytype, args: anytype) !usize {
 | 
					 | 
				
			||||||
        return self.plane.print(fmt, args);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn print_aligned_right(self: Plane, y: c_int, comptime fmt: anytype, args: anytype) !usize {
 | 
					 | 
				
			||||||
        return self.plane.print_aligned(y, .right, fmt, args);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn print_aligned_center(self: Plane, y: c_int, comptime fmt: anytype, args: anytype) !usize {
 | 
					 | 
				
			||||||
        return self.plane.print_aligned(y, .center, fmt, args);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn putstr(self: Plane, gclustarr: [*:0]const u8) !usize {
 | 
					 | 
				
			||||||
        return self.plane.putstr(gclustarr);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn putc(self: Plane, cell: *const Cell) !usize {
 | 
					 | 
				
			||||||
        return self.plane.putc(&cell.cell);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn putc_yx(self: Plane, y: c_int, x: c_int, cell: *const Cell) !usize {
 | 
					 | 
				
			||||||
        return self.plane.put_yx(y, x, &cell.cell);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn cursor_yx(self: Plane, y: *c_uint, x: *c_uint) void {
 | 
					 | 
				
			||||||
        self.plane.cursor_yx(y, x);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn cursor_y(self: Plane) c_uint {
 | 
					 | 
				
			||||||
        return self.plane.cursor_y();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn cursor_x(self: Plane) c_uint {
 | 
					 | 
				
			||||||
        return self.plane.cursor_x();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn cursor_move_yx(self: Plane, y: c_int, x: c_int) !void {
 | 
					 | 
				
			||||||
        return self.plane.cursor_move_yx(y, x);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn cursor_move_rel(self: Plane, y: c_int, x: c_int) !void {
 | 
					 | 
				
			||||||
        return self.plane.cursor_move_rel(y, x);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn cell_init(self: Plane) Cell {
 | 
					 | 
				
			||||||
        return .{ .cell = self.plane.cell_init() };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn cell_load(self: Plane, cell: *Cell, gcluster: [:0]const u8) !usize {
 | 
					 | 
				
			||||||
        return self.plane.cell_load(&cell.cell, gcluster);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn at_cursor_cell(self: Plane, cell: *Cell) !usize {
 | 
					 | 
				
			||||||
        return self.plane.at_cursor_cell(&cell.cell);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn set_styles(self: Plane, stylebits: StyleBits) void {
 | 
					 | 
				
			||||||
        return self.plane.set_styles(@intCast(@as(u5, @bitCast(stylebits))));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn on_styles(self: Plane, stylebits: StyleBits) void {
 | 
					 | 
				
			||||||
        return self.plane.on_styles(@intCast(@as(u5, @bitCast(stylebits))));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn off_styles(self: Plane, stylebits: StyleBits) void {
 | 
					 | 
				
			||||||
        return self.plane.off_styles(@intCast(@as(u5, @bitCast(stylebits))));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn set_fg_rgb(self: Plane, channel: u32) !void {
 | 
					 | 
				
			||||||
        return self.plane.set_fg_rgb(channel);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn set_bg_rgb(self: Plane, channel: u32) !void {
 | 
					 | 
				
			||||||
        return self.plane.set_bg_rgb(channel);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn set_fg_palindex(self: Plane, idx: c_uint) !void {
 | 
					 | 
				
			||||||
        return self.plane.set_fg_palindex(idx);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn set_bg_palindex(self: Plane, idx: c_uint) !void {
 | 
					 | 
				
			||||||
        return self.plane.set_bg_palindex(idx);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn set_channels(self: Plane, channels_: u64) void {
 | 
					 | 
				
			||||||
        return self.plane.set_channels(channels_);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub inline fn set_base_style(plane: *const Plane, egc_: [*c]const u8, style_: Style) void {
 | 
					 | 
				
			||||||
        var channels_: u64 = 0;
 | 
					 | 
				
			||||||
        channels.from_style(&channels_, style_);
 | 
					 | 
				
			||||||
        if (style_.fg) |fg| plane.plane.set_fg_rgb(fg) catch {};
 | 
					 | 
				
			||||||
        if (style_.bg) |bg| plane.plane.set_bg_rgb(bg) catch {};
 | 
					 | 
				
			||||||
        _ = plane.plane.set_base(egc_, 0, channels_) catch {};
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn set_base_style_transparent(plane: Plane, egc_: [*:0]const u8, style_: Style) void {
 | 
					 | 
				
			||||||
        var channels_: u64 = 0;
 | 
					 | 
				
			||||||
        channels.from_style(&channels_, style_);
 | 
					 | 
				
			||||||
        if (style_.fg) |fg| plane.plane.set_fg_rgb(fg) catch {};
 | 
					 | 
				
			||||||
        if (style_.bg) |bg| plane.plane.set_bg_rgb(bg) catch {};
 | 
					 | 
				
			||||||
        channels.set_fg_transparent(&channels_);
 | 
					 | 
				
			||||||
        channels.set_bg_transparent(&channels_);
 | 
					 | 
				
			||||||
        _ = plane.plane.set_base(egc_, 0, channels_) catch {};
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn set_base_style_bg_transparent(plane: Plane, egc_: [*:0]const u8, style_: Style) void {
 | 
					 | 
				
			||||||
        var channels_: u64 = 0;
 | 
					 | 
				
			||||||
        channels.from_style(&channels_, style_);
 | 
					 | 
				
			||||||
        if (style_.fg) |fg| plane.plane.set_fg_rgb(fg) catch {};
 | 
					 | 
				
			||||||
        if (style_.bg) |bg| plane.plane.set_bg_rgb(bg) catch {};
 | 
					 | 
				
			||||||
        channels.set_bg_transparent(&channels_);
 | 
					 | 
				
			||||||
        _ = plane.plane.set_base(egc_, 0, channels_) catch {};
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub inline fn set_style(plane: *const Plane, style_: Style) void {
 | 
					 | 
				
			||||||
        var channels_: u64 = 0;
 | 
					 | 
				
			||||||
        channels.from_style(&channels_, style_);
 | 
					 | 
				
			||||||
        plane.plane.set_channels(channels_);
 | 
					 | 
				
			||||||
        if (style_.fs) |fs| switch (fs) {
 | 
					 | 
				
			||||||
            .normal => plane.plane.set_styles(nc.style.none),
 | 
					 | 
				
			||||||
            .bold => plane.plane.set_styles(nc.style.bold),
 | 
					 | 
				
			||||||
            .italic => plane.plane.set_styles(nc.style.italic),
 | 
					 | 
				
			||||||
            .underline => plane.plane.set_styles(nc.style.underline),
 | 
					 | 
				
			||||||
            .undercurl => plane.plane.set_styles(nc.style.undercurl),
 | 
					 | 
				
			||||||
            .strikethrough => plane.plane.set_styles(nc.style.struck),
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub inline fn set_style_bg_transparent(plane: *const Plane, style_: Style) void {
 | 
					 | 
				
			||||||
        var channels_: u64 = 0;
 | 
					 | 
				
			||||||
        channels.from_style(&channels_, style_);
 | 
					 | 
				
			||||||
        channels.set_bg_transparent(&channels_);
 | 
					 | 
				
			||||||
        plane.plane.set_channels(channels_);
 | 
					 | 
				
			||||||
        if (style_.fs) |fs| switch (fs) {
 | 
					 | 
				
			||||||
            .normal => plane.plane.set_styles(nc.style.none),
 | 
					 | 
				
			||||||
            .bold => plane.plane.set_styles(nc.style.bold),
 | 
					 | 
				
			||||||
            .italic => plane.plane.set_styles(nc.style.italic),
 | 
					 | 
				
			||||||
            .underline => plane.plane.set_styles(nc.style.underline),
 | 
					 | 
				
			||||||
            .undercurl => plane.plane.set_styles(nc.style.undercurl),
 | 
					 | 
				
			||||||
            .strikethrough => plane.plane.set_styles(nc.style.struck),
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn egc_length(_: Plane, egcs: []const u8, colcount: *c_int, abs_col: usize) usize {
 | 
					 | 
				
			||||||
        if (egcs[0] == '\t') {
 | 
					 | 
				
			||||||
            colcount.* = @intCast(8 - abs_col % 8);
 | 
					 | 
				
			||||||
            return 1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return nc.ncegc_len(egcs, colcount) catch ret: {
 | 
					 | 
				
			||||||
            colcount.* = 1;
 | 
					 | 
				
			||||||
            break :ret 1;
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn egc_chunk_width(plane: Plane, chunk_: []const u8, abs_col_: usize) usize {
 | 
					 | 
				
			||||||
        var abs_col = abs_col_;
 | 
					 | 
				
			||||||
        var chunk = chunk_;
 | 
					 | 
				
			||||||
        var colcount: usize = 0;
 | 
					 | 
				
			||||||
        var cols: c_int = 0;
 | 
					 | 
				
			||||||
        while (chunk.len > 0) {
 | 
					 | 
				
			||||||
            const bytes = plane.egc_length(chunk, &cols, abs_col);
 | 
					 | 
				
			||||||
            colcount += @intCast(cols);
 | 
					 | 
				
			||||||
            abs_col += @intCast(cols);
 | 
					 | 
				
			||||||
            if (chunk.len < bytes) break;
 | 
					 | 
				
			||||||
            chunk = chunk[bytes..];
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return colcount;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,40 +0,0 @@
 | 
				
			||||||
const Style = @import("theme").Style;
 | 
					 | 
				
			||||||
const nc = @import("notcurses");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub const set_fg_rgb = nc.channels_set_fg_rgb;
 | 
					 | 
				
			||||||
pub const set_bg_rgb = nc.channels_set_bg_rgb;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn set_fg_opaque(channels_: *u64) void {
 | 
					 | 
				
			||||||
    nc.channels_set_fg_alpha(channels_, nc.ALPHA_OPAQUE) catch {};
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn set_bg_opaque(channels_: *u64) void {
 | 
					 | 
				
			||||||
    nc.channels_set_bg_alpha(channels_, nc.ALPHA_OPAQUE) catch {};
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn set_fg_transparent(channels_: *u64) void {
 | 
					 | 
				
			||||||
    nc.channels_set_fg_alpha(channels_, nc.ALPHA_TRANSPARENT) catch {};
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn set_bg_transparent(channels_: *u64) void {
 | 
					 | 
				
			||||||
    nc.channels_set_bg_alpha(channels_, nc.ALPHA_TRANSPARENT) catch {};
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub inline fn fg_from_style(channels_: *u64, style_: Style) void {
 | 
					 | 
				
			||||||
    if (style_.fg) |fg| {
 | 
					 | 
				
			||||||
        set_fg_rgb(channels_, fg) catch {};
 | 
					 | 
				
			||||||
        set_fg_opaque(channels_);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub inline fn bg_from_style(channels_: *u64, style_: Style) void {
 | 
					 | 
				
			||||||
    if (style_.bg) |bg| {
 | 
					 | 
				
			||||||
        set_bg_rgb(channels_, bg) catch {};
 | 
					 | 
				
			||||||
        set_bg_opaque(channels_);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub inline fn from_style(channels_: *u64, style_: Style) void {
 | 
					 | 
				
			||||||
    fg_from_style(channels_, style_);
 | 
					 | 
				
			||||||
    bg_from_style(channels_, style_);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,15 +0,0 @@
 | 
				
			||||||
const nc = @import("notcurses");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub const key = nc.key;
 | 
					 | 
				
			||||||
pub const key_type = u32;
 | 
					 | 
				
			||||||
pub const modifier = nc.mod;
 | 
					 | 
				
			||||||
pub const event_type = nc.event_type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub const utils = struct {
 | 
					 | 
				
			||||||
    pub const isSuper = nc.isSuper;
 | 
					 | 
				
			||||||
    pub const isCtrl = nc.isCtrl;
 | 
					 | 
				
			||||||
    pub const isShift = nc.isShift;
 | 
					 | 
				
			||||||
    pub const isAlt = nc.isAlt;
 | 
					 | 
				
			||||||
    pub const key_id_string = nc.key_id_string;
 | 
					 | 
				
			||||||
    pub const key_string = nc.key_string;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,525 +0,0 @@
 | 
				
			||||||
const std = @import("std");
 | 
					 | 
				
			||||||
const cbor = @import("cbor");
 | 
					 | 
				
			||||||
const log = @import("log");
 | 
					 | 
				
			||||||
const nc = @import("notcurses");
 | 
					 | 
				
			||||||
const Style = @import("theme").Style;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub const input = @import("input.zig");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub const Plane = @import("Plane.zig").Plane;
 | 
					 | 
				
			||||||
pub const Cell = @import("Cell.zig").Cell;
 | 
					 | 
				
			||||||
pub const channels = @import("channels.zig");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub const style = @import("style.zig").StyleBits;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const mod = input.modifier;
 | 
					 | 
				
			||||||
const key = input.key;
 | 
					 | 
				
			||||||
const event_type = input.event_type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const Self = @This();
 | 
					 | 
				
			||||||
pub const log_name = "notcurses";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
a: std.mem.Allocator,
 | 
					 | 
				
			||||||
ctx: nc.Context,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
escape_state: EscapeState = .none,
 | 
					 | 
				
			||||||
escape_initial: ?nc.Input = null,
 | 
					 | 
				
			||||||
escape_code: std.ArrayList(u8),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
event_buffer: std.ArrayList(u8),
 | 
					 | 
				
			||||||
mods: ModState = .{},
 | 
					 | 
				
			||||||
drag: bool = false,
 | 
					 | 
				
			||||||
drag_event: nc.Input = nc.input(),
 | 
					 | 
				
			||||||
bracketed_paste: bool = false,
 | 
					 | 
				
			||||||
bracketed_paste_buffer: std.ArrayList(u8),
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
handler_ctx: *anyopaque,
 | 
					 | 
				
			||||||
dispatch_input: ?*const fn (ctx: *anyopaque, cbor_msg: []const u8) void = null,
 | 
					 | 
				
			||||||
dispatch_mouse: ?*const fn (ctx: *anyopaque, y: c_int, x: c_int, cbor_msg: []const u8) void = null,
 | 
					 | 
				
			||||||
dispatch_mouse_drag: ?*const fn (ctx: *anyopaque, y: c_int, x: c_int, dragging: bool, cbor_msg: []const u8) void = null,
 | 
					 | 
				
			||||||
dispatch_event: ?*const fn (ctx: *anyopaque, cbor_msg: []const u8) void = null,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
logger: log.Logger,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const EscapeState = enum { none, init, OSC, st, CSI };
 | 
					 | 
				
			||||||
const ModState = struct { ctrl: bool = false, shift: bool = false, alt: bool = false };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn init(a: std.mem.Allocator, handler_ctx: *anyopaque, no_alternate: bool) !Self {
 | 
					 | 
				
			||||||
    var opts = nc.Context.Options{
 | 
					 | 
				
			||||||
        .termtype = null,
 | 
					 | 
				
			||||||
        .loglevel = @intFromEnum(nc.LogLevel.silent),
 | 
					 | 
				
			||||||
        .margin_t = 0,
 | 
					 | 
				
			||||||
        .margin_r = 0,
 | 
					 | 
				
			||||||
        .margin_b = 0,
 | 
					 | 
				
			||||||
        .margin_l = 0,
 | 
					 | 
				
			||||||
        .flags = nc.Context.option.SUPPRESS_BANNERS | nc.Context.option.INHIBIT_SETLOCALE | nc.Context.option.NO_WINCH_SIGHANDLER,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    if (no_alternate)
 | 
					 | 
				
			||||||
        opts.flags |= nc.Context.option.NO_ALTERNATE_SCREEN;
 | 
					 | 
				
			||||||
    const nc_ = try nc.Context.core_init(&opts, null);
 | 
					 | 
				
			||||||
    nc_.mice_enable(nc.mice.ALL_EVENTS) catch {};
 | 
					 | 
				
			||||||
    try nc_.linesigs_disable();
 | 
					 | 
				
			||||||
    bracketed_paste_enable();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return .{
 | 
					 | 
				
			||||||
        .a = a,
 | 
					 | 
				
			||||||
        .ctx = nc_,
 | 
					 | 
				
			||||||
        .escape_code = std.ArrayList(u8).init(a),
 | 
					 | 
				
			||||||
        .event_buffer = std.ArrayList(u8).init(a),
 | 
					 | 
				
			||||||
        .bracketed_paste_buffer = std.ArrayList(u8).init(a),
 | 
					 | 
				
			||||||
        .handler_ctx = handler_ctx,
 | 
					 | 
				
			||||||
        .logger = log.logger(log_name),
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn deinit(self: *Self) void {
 | 
					 | 
				
			||||||
    self.escape_code.deinit();
 | 
					 | 
				
			||||||
    self.event_buffer.deinit();
 | 
					 | 
				
			||||||
    self.bracketed_paste_buffer.deinit();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn run(_: *Self) !void {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn render(self: Self) !void {
 | 
					 | 
				
			||||||
    return self.ctx.render();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn refresh(self: Self) !void {
 | 
					 | 
				
			||||||
    return self.ctx.refresh();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn stop(self: Self) void {
 | 
					 | 
				
			||||||
    return self.ctx.stop();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn stdplane(self: Self) Plane {
 | 
					 | 
				
			||||||
    return .{ .plane = self.ctx.stdplane() };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn input_fd(self: Self) i32 {
 | 
					 | 
				
			||||||
    return self.ctx.inputready_fd();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn leave_alternate_screen(self: Self) void {
 | 
					 | 
				
			||||||
    return self.ctx.leave_alternate_screen();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const InputError = error{
 | 
					 | 
				
			||||||
    OutOfMemory,
 | 
					 | 
				
			||||||
    InvalidCharacter,
 | 
					 | 
				
			||||||
    NoSpaceLeft,
 | 
					 | 
				
			||||||
    CborIntegerTooLarge,
 | 
					 | 
				
			||||||
    CborIntegerTooSmall,
 | 
					 | 
				
			||||||
    CborInvalidType,
 | 
					 | 
				
			||||||
    CborTooShort,
 | 
					 | 
				
			||||||
    Ucs32toUtf8Error,
 | 
					 | 
				
			||||||
    InvalidPadding,
 | 
					 | 
				
			||||||
    ReadInputError,
 | 
					 | 
				
			||||||
    WouldBlock,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn process_input(self: *Self) InputError!void {
 | 
					 | 
				
			||||||
    var input_buffer: [256]nc.Input = undefined;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    while (true) {
 | 
					 | 
				
			||||||
        const nivec = self.ctx.getvec_nblock(&input_buffer) catch return error.ReadInputError;
 | 
					 | 
				
			||||||
        if (nivec.len == 0)
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        for (nivec) |*ni| {
 | 
					 | 
				
			||||||
            if (ni.id == 27 or self.escape_state != .none) {
 | 
					 | 
				
			||||||
                try self.handle_escape(ni);
 | 
					 | 
				
			||||||
                continue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            self.dispatch_input_event(ni) catch |e|
 | 
					 | 
				
			||||||
                self.logger.err("input dispatch", e);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (self.escape_state == .init)
 | 
					 | 
				
			||||||
        try self.handle_escape_short();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn fmtmsg(self: *Self, value: anytype) ![]const u8 {
 | 
					 | 
				
			||||||
    self.event_buffer.clearRetainingCapacity();
 | 
					 | 
				
			||||||
    try cbor.writeValue(self.event_buffer.writer(), value);
 | 
					 | 
				
			||||||
    return self.event_buffer.items;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn dispatch_input_event(self: *Self, ni: *nc.Input) !void {
 | 
					 | 
				
			||||||
    const keypress: u32 = ni.id;
 | 
					 | 
				
			||||||
    ni.modifiers &= mod.CTRL | mod.SHIFT | mod.ALT | mod.SUPER | mod.META | mod.HYPER;
 | 
					 | 
				
			||||||
    if (keypress == key.RESIZE) return;
 | 
					 | 
				
			||||||
    try self.sync_mod_state(keypress, ni.modifiers);
 | 
					 | 
				
			||||||
    if (keypress == key.MOTION) {
 | 
					 | 
				
			||||||
        if (ni.y == 0 and ni.x == 0 and ni.ypx == -1 and ni.xpx == -1) return;
 | 
					 | 
				
			||||||
        if (self.dispatch_mouse) |f| f(
 | 
					 | 
				
			||||||
            self.handler_ctx,
 | 
					 | 
				
			||||||
            ni.y,
 | 
					 | 
				
			||||||
            ni.x,
 | 
					 | 
				
			||||||
            try self.fmtmsg(.{
 | 
					 | 
				
			||||||
                "M",
 | 
					 | 
				
			||||||
                ni.x,
 | 
					 | 
				
			||||||
                ni.y,
 | 
					 | 
				
			||||||
                ni.xpx,
 | 
					 | 
				
			||||||
                ni.ypx,
 | 
					 | 
				
			||||||
            }),
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    } else if (keypress > key.MOTION and keypress <= key.BUTTON11) {
 | 
					 | 
				
			||||||
        if (ni.y == 0 and ni.x == 0 and ni.ypx == -1 and ni.xpx == -1) return;
 | 
					 | 
				
			||||||
        if (try self.detect_drag(ni)) return;
 | 
					 | 
				
			||||||
        if (self.dispatch_mouse) |f| f(
 | 
					 | 
				
			||||||
            self.handler_ctx,
 | 
					 | 
				
			||||||
            ni.y,
 | 
					 | 
				
			||||||
            ni.x,
 | 
					 | 
				
			||||||
            try self.fmtmsg(.{
 | 
					 | 
				
			||||||
                "B",
 | 
					 | 
				
			||||||
                ni.evtype,
 | 
					 | 
				
			||||||
                keypress,
 | 
					 | 
				
			||||||
                input.utils.key_string(ni),
 | 
					 | 
				
			||||||
                ni.x,
 | 
					 | 
				
			||||||
                ni.y,
 | 
					 | 
				
			||||||
                ni.xpx,
 | 
					 | 
				
			||||||
                ni.ypx,
 | 
					 | 
				
			||||||
            }),
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        const cbor_msg = try self.fmtmsg(.{
 | 
					 | 
				
			||||||
            "I",
 | 
					 | 
				
			||||||
            normalized_evtype(ni.evtype),
 | 
					 | 
				
			||||||
            keypress,
 | 
					 | 
				
			||||||
            if (@hasField(nc.Input, "eff_text")) ni.eff_text[0] else keypress,
 | 
					 | 
				
			||||||
            input.utils.key_string(ni),
 | 
					 | 
				
			||||||
            ni.modifiers,
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        if (self.bracketed_paste and self.handle_bracketed_paste_input(cbor_msg) catch |e| {
 | 
					 | 
				
			||||||
            self.bracketed_paste_buffer.clearAndFree();
 | 
					 | 
				
			||||||
            self.bracketed_paste = false;
 | 
					 | 
				
			||||||
            return e;
 | 
					 | 
				
			||||||
        }) {} else if (self.dispatch_input) |f| f(self.handler_ctx, cbor_msg);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn handle_bracketed_paste_input(self: *Self, cbor_msg: []const u8) !bool {
 | 
					 | 
				
			||||||
    var keypress: u32 = undefined;
 | 
					 | 
				
			||||||
    var egc_: u32 = undefined;
 | 
					 | 
				
			||||||
    if (try cbor.match(cbor_msg, .{ "I", cbor.number, cbor.extract(&keypress), cbor.extract(&egc_), cbor.string, 0 })) {
 | 
					 | 
				
			||||||
        switch (keypress) {
 | 
					 | 
				
			||||||
            key.ENTER => try self.bracketed_paste_buffer.appendSlice("\n"),
 | 
					 | 
				
			||||||
            else => if (!key.synthesized_p(keypress)) {
 | 
					 | 
				
			||||||
                var buf: [6]u8 = undefined;
 | 
					 | 
				
			||||||
                const bytes = try ucs32_to_utf8(&[_]u32{egc_}, &buf);
 | 
					 | 
				
			||||||
                try self.bracketed_paste_buffer.appendSlice(buf[0..bytes]);
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                try self.handle_bracketed_paste_end();
 | 
					 | 
				
			||||||
                return false;
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn normalized_evtype(evtype: c_uint) c_uint {
 | 
					 | 
				
			||||||
    return if (evtype == event_type.UNKNOWN) @as(c_uint, @intCast(event_type.PRESS)) else evtype;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn sync_mod_state(self: *Self, keypress: u32, modifiers: u32) !void {
 | 
					 | 
				
			||||||
    if (input.utils.isCtrl(modifiers) and !self.mods.ctrl and !(keypress == key.LCTRL or keypress == key.RCTRL))
 | 
					 | 
				
			||||||
        try self.send_sync_key(event_type.PRESS, key.LCTRL, "lctrl", modifiers);
 | 
					 | 
				
			||||||
    if (!input.utils.isCtrl(modifiers) and self.mods.ctrl and !(keypress == key.LCTRL or keypress == key.RCTRL))
 | 
					 | 
				
			||||||
        try self.send_sync_key(event_type.RELEASE, key.LCTRL, "lctrl", modifiers);
 | 
					 | 
				
			||||||
    if (input.utils.isAlt(modifiers) and !self.mods.alt and !(keypress == key.LALT or keypress == key.RALT))
 | 
					 | 
				
			||||||
        try self.send_sync_key(event_type.PRESS, key.LALT, "lalt", modifiers);
 | 
					 | 
				
			||||||
    if (!input.utils.isAlt(modifiers) and self.mods.alt and !(keypress == key.LALT or keypress == key.RALT))
 | 
					 | 
				
			||||||
        try self.send_sync_key(event_type.RELEASE, key.LALT, "lalt", modifiers);
 | 
					 | 
				
			||||||
    if (input.utils.isShift(modifiers) and !self.mods.shift and !(keypress == key.LSHIFT or keypress == key.RSHIFT))
 | 
					 | 
				
			||||||
        try self.send_sync_key(event_type.PRESS, key.LSHIFT, "lshift", modifiers);
 | 
					 | 
				
			||||||
    if (!input.utils.isShift(modifiers) and self.mods.shift and !(keypress == key.LSHIFT or keypress == key.RSHIFT))
 | 
					 | 
				
			||||||
        try self.send_sync_key(event_type.RELEASE, key.LSHIFT, "lshift", modifiers);
 | 
					 | 
				
			||||||
    self.mods = .{
 | 
					 | 
				
			||||||
        .ctrl = input.utils.isCtrl(modifiers),
 | 
					 | 
				
			||||||
        .alt = input.utils.isAlt(modifiers),
 | 
					 | 
				
			||||||
        .shift = input.utils.isShift(modifiers),
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn send_sync_key(self: *Self, event_type_: c_int, keypress: u32, key_string: []const u8, modifiers: u32) !void {
 | 
					 | 
				
			||||||
    if (self.dispatch_input) |f| f(
 | 
					 | 
				
			||||||
        self.handler_ctx,
 | 
					 | 
				
			||||||
        try self.fmtmsg(.{
 | 
					 | 
				
			||||||
            "I",
 | 
					 | 
				
			||||||
            event_type_,
 | 
					 | 
				
			||||||
            keypress,
 | 
					 | 
				
			||||||
            keypress,
 | 
					 | 
				
			||||||
            key_string,
 | 
					 | 
				
			||||||
            modifiers,
 | 
					 | 
				
			||||||
        }),
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn detect_drag(self: *Self, ni: *nc.Input) !bool {
 | 
					 | 
				
			||||||
    return switch (ni.id) {
 | 
					 | 
				
			||||||
        key.BUTTON1...key.BUTTON3, key.BUTTON6...key.BUTTON9 => if (self.drag) self.detect_drag_end(ni) else self.detect_drag_begin(ni),
 | 
					 | 
				
			||||||
        else => false,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn detect_drag_begin(self: *Self, ni: *nc.Input) !bool {
 | 
					 | 
				
			||||||
    if (ni.evtype == event_type.PRESS and self.drag_event.id == ni.id) {
 | 
					 | 
				
			||||||
        self.drag_event = ni.*;
 | 
					 | 
				
			||||||
        self.drag = true;
 | 
					 | 
				
			||||||
        if (self.dispatch_mouse_drag) |f| f(
 | 
					 | 
				
			||||||
            self.handler_ctx,
 | 
					 | 
				
			||||||
            ni.y,
 | 
					 | 
				
			||||||
            ni.x,
 | 
					 | 
				
			||||||
            true,
 | 
					 | 
				
			||||||
            try self.fmtmsg(.{
 | 
					 | 
				
			||||||
                "D",
 | 
					 | 
				
			||||||
                event_type.PRESS,
 | 
					 | 
				
			||||||
                ni.id,
 | 
					 | 
				
			||||||
                input.utils.key_string(ni),
 | 
					 | 
				
			||||||
                ni.x,
 | 
					 | 
				
			||||||
                ni.y,
 | 
					 | 
				
			||||||
                ni.xpx,
 | 
					 | 
				
			||||||
                ni.ypx,
 | 
					 | 
				
			||||||
            }),
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (ni.evtype == event_type.PRESS)
 | 
					 | 
				
			||||||
        self.drag_event = ni.*
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        self.drag_event = nc.input();
 | 
					 | 
				
			||||||
    return false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn detect_drag_end(self: *Self, ni: *nc.Input) !bool {
 | 
					 | 
				
			||||||
    if (ni.id == self.drag_event.id and ni.evtype != event_type.PRESS) {
 | 
					 | 
				
			||||||
        if (self.dispatch_mouse_drag) |f| f(
 | 
					 | 
				
			||||||
            self.handler_ctx,
 | 
					 | 
				
			||||||
            ni.y,
 | 
					 | 
				
			||||||
            ni.x,
 | 
					 | 
				
			||||||
            false,
 | 
					 | 
				
			||||||
            try self.fmtmsg(.{
 | 
					 | 
				
			||||||
                "D",
 | 
					 | 
				
			||||||
                event_type.RELEASE,
 | 
					 | 
				
			||||||
                ni.id,
 | 
					 | 
				
			||||||
                input.utils.key_string(ni),
 | 
					 | 
				
			||||||
                ni.x,
 | 
					 | 
				
			||||||
                ni.y,
 | 
					 | 
				
			||||||
                ni.xpx,
 | 
					 | 
				
			||||||
                ni.ypx,
 | 
					 | 
				
			||||||
            }),
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        self.drag = false;
 | 
					 | 
				
			||||||
        self.drag_event = nc.input();
 | 
					 | 
				
			||||||
    } else if (self.dispatch_mouse_drag) |f| f(
 | 
					 | 
				
			||||||
        self.handler_ctx,
 | 
					 | 
				
			||||||
        ni.y,
 | 
					 | 
				
			||||||
        ni.x,
 | 
					 | 
				
			||||||
        true,
 | 
					 | 
				
			||||||
        try self.fmtmsg(.{
 | 
					 | 
				
			||||||
            "D",
 | 
					 | 
				
			||||||
            ni.evtype,
 | 
					 | 
				
			||||||
            ni.id,
 | 
					 | 
				
			||||||
            input.utils.key_string(ni),
 | 
					 | 
				
			||||||
            ni.x,
 | 
					 | 
				
			||||||
            ni.y,
 | 
					 | 
				
			||||||
            ni.xpx,
 | 
					 | 
				
			||||||
            ni.ypx,
 | 
					 | 
				
			||||||
        }),
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn handle_escape(self: *Self, ni: *nc.Input) !void {
 | 
					 | 
				
			||||||
    switch (self.escape_state) {
 | 
					 | 
				
			||||||
        .none => switch (ni.id) {
 | 
					 | 
				
			||||||
            '\x1B' => {
 | 
					 | 
				
			||||||
                self.escape_state = .init;
 | 
					 | 
				
			||||||
                self.escape_initial = ni.*;
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            else => unreachable,
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        .init => switch (ni.id) {
 | 
					 | 
				
			||||||
            ']' => self.escape_state = .OSC,
 | 
					 | 
				
			||||||
            '[' => self.escape_state = .CSI,
 | 
					 | 
				
			||||||
            else => {
 | 
					 | 
				
			||||||
                try self.handle_escape_short();
 | 
					 | 
				
			||||||
                _ = try self.dispatch_input_event(ni);
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        .OSC => switch (ni.id) {
 | 
					 | 
				
			||||||
            '\x1B' => self.escape_state = .st,
 | 
					 | 
				
			||||||
            '\\' => try self.handle_OSC_escape_code(),
 | 
					 | 
				
			||||||
            ' '...'\\' - 1, '\\' + 1...127 => {
 | 
					 | 
				
			||||||
                const p = try self.escape_code.addOne();
 | 
					 | 
				
			||||||
                p.* = @intCast(ni.id);
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            else => try self.handle_OSC_escape_code(),
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        .st => switch (ni.id) {
 | 
					 | 
				
			||||||
            '\\' => try self.handle_OSC_escape_code(),
 | 
					 | 
				
			||||||
            else => try self.handle_OSC_escape_code(),
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        .CSI => switch (ni.id) {
 | 
					 | 
				
			||||||
            '0'...'9', ';', ' ', '-', '?' => {
 | 
					 | 
				
			||||||
                const p = try self.escape_code.addOne();
 | 
					 | 
				
			||||||
                p.* = @intCast(ni.id);
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            else => {
 | 
					 | 
				
			||||||
                const p = try self.escape_code.addOne();
 | 
					 | 
				
			||||||
                p.* = @intCast(ni.id);
 | 
					 | 
				
			||||||
                try self.handle_CSI_escape_code();
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn handle_escape_short(self: *Self) !void {
 | 
					 | 
				
			||||||
    self.escape_code.clearAndFree();
 | 
					 | 
				
			||||||
    self.escape_state = .none;
 | 
					 | 
				
			||||||
    defer self.escape_initial = null;
 | 
					 | 
				
			||||||
    if (self.escape_initial) |*ni|
 | 
					 | 
				
			||||||
        _ = try self.dispatch_input_event(ni);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn match_code(self: Self, match: []const u8, skip: usize) bool {
 | 
					 | 
				
			||||||
    const code = self.escape_code.items;
 | 
					 | 
				
			||||||
    if (!(code.len >= match.len - skip)) return false;
 | 
					 | 
				
			||||||
    const code_prefix = code[0 .. match.len - skip];
 | 
					 | 
				
			||||||
    return std.mem.eql(u8, match[skip..], code_prefix);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const OSC = "\x1B]"; // Operating System Command
 | 
					 | 
				
			||||||
const ST = "\x1B\\"; // String Terminator
 | 
					 | 
				
			||||||
const BEL = "\x07";
 | 
					 | 
				
			||||||
const OSC0_title = OSC ++ "0;";
 | 
					 | 
				
			||||||
const OSC52_clipboard = OSC ++ "52;c;";
 | 
					 | 
				
			||||||
const OSC52_clipboard_paste = OSC ++ "52;p;";
 | 
					 | 
				
			||||||
const OSC22_cursor = OSC ++ "22;";
 | 
					 | 
				
			||||||
const OSC22_cursor_reply = OSC ++ "22:";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn handle_OSC_escape_code(self: *Self) !void {
 | 
					 | 
				
			||||||
    self.escape_state = .none;
 | 
					 | 
				
			||||||
    self.escape_initial = null;
 | 
					 | 
				
			||||||
    defer self.escape_code.clearAndFree();
 | 
					 | 
				
			||||||
    const code = self.escape_code.items;
 | 
					 | 
				
			||||||
    if (self.match_code(OSC52_clipboard, OSC.len))
 | 
					 | 
				
			||||||
        return self.handle_system_clipboard(code[OSC52_clipboard.len - OSC.len ..]);
 | 
					 | 
				
			||||||
    if (self.match_code(OSC52_clipboard_paste, OSC.len))
 | 
					 | 
				
			||||||
        return self.handle_system_clipboard(code[OSC52_clipboard_paste.len - OSC.len ..]);
 | 
					 | 
				
			||||||
    if (self.match_code(OSC22_cursor_reply, OSC.len))
 | 
					 | 
				
			||||||
        return self.handle_mouse_cursor(code[OSC22_cursor_reply.len - OSC.len ..]);
 | 
					 | 
				
			||||||
    self.logger.print("ignored escape code: OSC {s}", .{std.fmt.fmtSliceEscapeLower(code)});
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn handle_system_clipboard(self: *Self, base64: []const u8) !void {
 | 
					 | 
				
			||||||
    const decoder = std.base64.standard.Decoder;
 | 
					 | 
				
			||||||
    const text = try self.a.alloc(u8, try decoder.calcSizeForSlice(base64));
 | 
					 | 
				
			||||||
    defer self.a.free(text);
 | 
					 | 
				
			||||||
    try decoder.decode(text, base64);
 | 
					 | 
				
			||||||
    if (self.dispatch_event) |f| f(self.handler_ctx, try self.fmtmsg(.{ "system_clipboard", text }));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn handle_mouse_cursor(self: Self, text: []const u8) !void {
 | 
					 | 
				
			||||||
    self.logger.print("mouse cursor report: {s}", .{text});
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const CSI = "\x1B["; // Control Sequence Introducer
 | 
					 | 
				
			||||||
const CSI_bracketed_paste_enable = CSI ++ "?2004h";
 | 
					 | 
				
			||||||
const CSI_bracketed_paste_disable = CSI ++ "?2004h";
 | 
					 | 
				
			||||||
const CIS_bracketed_paste_begin = CSI ++ "200~";
 | 
					 | 
				
			||||||
const CIS_bracketed_paste_end = CSI ++ "201~";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn bracketed_paste_enable() void {
 | 
					 | 
				
			||||||
    write_stdout(CSI_bracketed_paste_enable);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn bracketed_paste_disable() void {
 | 
					 | 
				
			||||||
    write_stdout(CSI_bracketed_paste_disable);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn handle_CSI_escape_code(self: *Self) !void {
 | 
					 | 
				
			||||||
    self.escape_state = .none;
 | 
					 | 
				
			||||||
    self.escape_initial = null;
 | 
					 | 
				
			||||||
    defer self.escape_code.clearAndFree();
 | 
					 | 
				
			||||||
    const code = self.escape_code.items;
 | 
					 | 
				
			||||||
    if (self.match_code(CIS_bracketed_paste_begin, CSI.len))
 | 
					 | 
				
			||||||
        return self.handle_bracketed_paste_begin();
 | 
					 | 
				
			||||||
    if (self.match_code(CIS_bracketed_paste_end, CSI.len))
 | 
					 | 
				
			||||||
        return self.handle_bracketed_paste_end();
 | 
					 | 
				
			||||||
    self.logger.print("ignored escape code: CSI {s}", .{std.fmt.fmtSliceEscapeLower(code)});
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn handle_bracketed_paste_begin(self: *Self) !void {
 | 
					 | 
				
			||||||
    self.bracketed_paste_buffer.clearAndFree();
 | 
					 | 
				
			||||||
    self.bracketed_paste = true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn handle_bracketed_paste_end(self: *Self) !void {
 | 
					 | 
				
			||||||
    defer self.bracketed_paste_buffer.clearAndFree();
 | 
					 | 
				
			||||||
    if (!self.bracketed_paste) return;
 | 
					 | 
				
			||||||
    self.bracketed_paste = false;
 | 
					 | 
				
			||||||
    if (self.dispatch_event) |f| f(self.handler_ctx, try self.fmtmsg(.{ "system_clipboard", self.bracketed_paste_buffer.items }));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn set_terminal_title(_: *Self, text: []const u8) void {
 | 
					 | 
				
			||||||
    var writer = std.io.getStdOut().writer();
 | 
					 | 
				
			||||||
    var buf: [std.posix.PATH_MAX]u8 = undefined;
 | 
					 | 
				
			||||||
    const term_cmd = std.fmt.bufPrint(&buf, OSC0_title ++ "{s}" ++ BEL, .{text}) catch return;
 | 
					 | 
				
			||||||
    _ = writer.write(term_cmd) catch return;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn copy_to_system_clipboard(self: *Self, text: []const u8) void {
 | 
					 | 
				
			||||||
    self.copy_to_system_clipboard_with_errors(text) catch |e| log.logger(log_name).err("copy_to_system_clipboard", e);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn copy_to_system_clipboard_with_errors(self: *Self, text: []const u8) !void {
 | 
					 | 
				
			||||||
    var writer = std.io.getStdOut().writer();
 | 
					 | 
				
			||||||
    const encoder = std.base64.standard.Encoder;
 | 
					 | 
				
			||||||
    const size = OSC52_clipboard.len + encoder.calcSize(text.len) + ST.len;
 | 
					 | 
				
			||||||
    const buf = try self.a.alloc(u8, size);
 | 
					 | 
				
			||||||
    defer self.a.free(buf);
 | 
					 | 
				
			||||||
    @memcpy(buf[0..OSC52_clipboard.len], OSC52_clipboard);
 | 
					 | 
				
			||||||
    const b64 = encoder.encode(buf[OSC52_clipboard.len..], text);
 | 
					 | 
				
			||||||
    @memcpy(buf[OSC52_clipboard.len + b64.len ..], ST);
 | 
					 | 
				
			||||||
    _ = try writer.write(buf);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn request_system_clipboard(_: *Self) void {
 | 
					 | 
				
			||||||
    write_stdout(OSC52_clipboard ++ "?" ++ ST);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn request_mouse_cursor_text(_: *Self, push_or_pop: bool) void {
 | 
					 | 
				
			||||||
    if (push_or_pop) mouse_cursor_push("text") else mouse_cursor_pop();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn request_mouse_cursor_pointer(_: *Self, push_or_pop: bool) void {
 | 
					 | 
				
			||||||
    if (push_or_pop) mouse_cursor_push("pointer") else mouse_cursor_pop();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn request_mouse_cursor_default(_: *Self, push_or_pop: bool) void {
 | 
					 | 
				
			||||||
    if (push_or_pop) mouse_cursor_push("default") else mouse_cursor_pop();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn mouse_cursor_push(comptime name: []const u8) void {
 | 
					 | 
				
			||||||
    write_stdout(OSC22_cursor ++ name ++ ST);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn mouse_cursor_pop() void {
 | 
					 | 
				
			||||||
    write_stdout(OSC22_cursor ++ "default" ++ ST);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
fn write_stdout(bytes: []const u8) void {
 | 
					 | 
				
			||||||
    _ = std.io.getStdOut().writer().write(bytes) catch |e| log.logger(log_name).err("stdout", e);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn cursor_enable(self: Self, y: c_int, x: c_int) !void {
 | 
					 | 
				
			||||||
    return self.ctx.cursor_enable(y, x);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn cursor_disable(self: Self) void {
 | 
					 | 
				
			||||||
    self.ctx.cursor_disable() catch {};
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub const ucs32_to_utf8 = nc.ucs32_to_utf8;
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,14 +0,0 @@
 | 
				
			||||||
pub const StyleBits = packed struct(u5) {
 | 
					 | 
				
			||||||
    struck: bool = false,
 | 
					 | 
				
			||||||
    bold: bool = false,
 | 
					 | 
				
			||||||
    undercurl: bool = false,
 | 
					 | 
				
			||||||
    underline: bool = false,
 | 
					 | 
				
			||||||
    italic: bool = false,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub const struck: StyleBits = .{ .struck = true };
 | 
					 | 
				
			||||||
    pub const bold: StyleBits = .{ .bold = true };
 | 
					 | 
				
			||||||
    pub const undercurl: StyleBits = .{ .undercurl = true };
 | 
					 | 
				
			||||||
    pub const underline: StyleBits = .{ .underline = true };
 | 
					 | 
				
			||||||
    pub const italic: StyleBits = .{ .italic = true };
 | 
					 | 
				
			||||||
    pub const normal: StyleBits = .{};
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue