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
Reference in a new issue