widgets(terminal): simple key encoding, alt screen
This commit is contained in:
parent
78508b76bd
commit
7a7f4892d7
2 changed files with 106 additions and 5 deletions
|
@ -13,10 +13,22 @@ pub const Cell = struct {
|
||||||
style: vaxis.Style = .{},
|
style: vaxis.Style = .{},
|
||||||
uri: std.ArrayList(u8) = undefined,
|
uri: std.ArrayList(u8) = undefined,
|
||||||
uri_id: std.ArrayList(u8) = undefined,
|
uri_id: std.ArrayList(u8) = undefined,
|
||||||
width: u8 = 0,
|
width: u8 = 1,
|
||||||
|
|
||||||
wrapped: bool = false,
|
wrapped: bool = false,
|
||||||
dirty: bool = true,
|
dirty: bool = true,
|
||||||
|
|
||||||
|
pub fn erase(self: *Cell, bg: vaxis.Color) void {
|
||||||
|
self.char.clearRetainingCapacity();
|
||||||
|
self.char.append(' ') catch unreachable; // we never completely free this list
|
||||||
|
self.style = .{};
|
||||||
|
self.style.bg = bg;
|
||||||
|
self.uri.clearRetainingCapacity();
|
||||||
|
self.uri_id.clearRetainingCapacity();
|
||||||
|
self.width = 1;
|
||||||
|
self.wrapped = false;
|
||||||
|
self.dirty = true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Cursor = struct {
|
pub const Cursor = struct {
|
||||||
|
@ -130,6 +142,11 @@ pub fn readCell(self: *Screen, col: usize, row: usize) ?vaxis.Cell {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// returns true if the current cursor position is within the scrolling region
|
||||||
|
pub fn withinScrollingRegion(self: Screen) bool {
|
||||||
|
return self.scrolling_region.contains(self.cursor.col, self.cursor.row);
|
||||||
|
}
|
||||||
|
|
||||||
/// writes a cell to a location. 0 indexed
|
/// writes a cell to a location. 0 indexed
|
||||||
pub fn print(
|
pub fn print(
|
||||||
self: *Screen,
|
self: *Screen,
|
||||||
|
@ -288,3 +305,12 @@ pub fn cursorLeft(self: *Screen, n: usize) void {
|
||||||
self.cursor.pending_wrap = false;
|
self.cursor.pending_wrap = false;
|
||||||
self.cursor.col -= cnt;
|
self.cursor.col -= cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn eraseRight(self: *Screen) void {
|
||||||
|
self.cursor.pending_wrap = false;
|
||||||
|
const end = (self.cursor.row * self.width) + (self.width);
|
||||||
|
var i = (self.cursor.row * self.width) + self.cursor.col;
|
||||||
|
while (i < end) : (i += 1) {
|
||||||
|
self.buf[i].erase(self.cursor.style.bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ const vaxis = @import("../../main.zig");
|
||||||
const Winsize = vaxis.Winsize;
|
const Winsize = vaxis.Winsize;
|
||||||
const Screen = @import("Screen.zig");
|
const Screen = @import("Screen.zig");
|
||||||
const DisplayWidth = @import("DisplayWidth");
|
const DisplayWidth = @import("DisplayWidth");
|
||||||
|
const Key = vaxis.Key;
|
||||||
|
|
||||||
const grapheme = @import("grapheme");
|
const grapheme = @import("grapheme");
|
||||||
|
|
||||||
|
@ -26,6 +27,11 @@ pub const Options = struct {
|
||||||
pub const Mode = struct {
|
pub const Mode = struct {
|
||||||
origin: bool = false,
|
origin: bool = false,
|
||||||
cursor: bool = true,
|
cursor: bool = true,
|
||||||
|
sync: bool = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const InputEvent = union(enum) {
|
||||||
|
key_press: vaxis.Key,
|
||||||
};
|
};
|
||||||
|
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
|
@ -134,7 +140,7 @@ pub fn resize(self: *Terminal, ws: Winsize) !void {
|
||||||
|
|
||||||
pub fn draw(self: *Terminal, win: vaxis.Window) !void {
|
pub fn draw(self: *Terminal, win: vaxis.Window) !void {
|
||||||
// TODO: check sync
|
// TODO: check sync
|
||||||
if (self.back_mutex.tryLock()) {
|
if (self.back_mutex.tryLock() and !self.mode.sync) {
|
||||||
defer self.back_mutex.unlock();
|
defer self.back_mutex.unlock();
|
||||||
try self.back_screen.copyTo(&self.front_screen);
|
try self.back_screen.copyTo(&self.front_screen);
|
||||||
}
|
}
|
||||||
|
@ -153,6 +159,24 @@ pub fn draw(self: *Terminal, win: vaxis.Window) !void {
|
||||||
win.showCursor(self.front_screen.cursor.col, self.front_screen.cursor.row);
|
win.showCursor(self.front_screen.cursor.col, self.front_screen.cursor.row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update(self: *Terminal, event: InputEvent) !void {
|
||||||
|
switch (event) {
|
||||||
|
.key_press => |key| try self.encodeKey(key, true),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opaqueWrite(ptr: *const anyopaque, buf: []const u8) !usize {
|
||||||
|
const self: *const Terminal = @ptrCast(@alignCast(ptr));
|
||||||
|
return posix.write(self.pty.pty, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn anyWriter(self: *const Terminal) std.io.AnyWriter {
|
||||||
|
return .{
|
||||||
|
.context = self,
|
||||||
|
.writeFn = Terminal.opaqueWrite,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn opaqueRead(ptr: *const anyopaque, buf: []u8) !usize {
|
fn opaqueRead(ptr: *const anyopaque, buf: []u8) !usize {
|
||||||
const self: *const Terminal = @ptrCast(@alignCast(ptr));
|
const self: *const Terminal = @ptrCast(@alignCast(ptr));
|
||||||
return posix.read(self.pty.pty, buf);
|
return posix.read(self.pty.pty, buf);
|
||||||
|
@ -199,7 +223,26 @@ fn run(self: *Terminal) !void {
|
||||||
'B' => { // CUD
|
'B' => { // CUD
|
||||||
var iter = seq.iterator(u16);
|
var iter = seq.iterator(u16);
|
||||||
const delta = iter.next() orelse 1;
|
const delta = iter.next() orelse 1;
|
||||||
self.back_screen.cursor.row = @min(self.back_screen.height - 1, self.back_screen.cursor.row + delta);
|
self.back_screen.cursor.row = @min(
|
||||||
|
self.back_screen.height - 1,
|
||||||
|
self.back_screen.cursor.row + delta,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
'C' => {
|
||||||
|
self.back_screen.cursor.pending_wrap = false;
|
||||||
|
var iter = seq.iterator(u16);
|
||||||
|
const delta = iter.next() orelse 1;
|
||||||
|
const within = self.back_screen.withinScrollingRegion();
|
||||||
|
if (within)
|
||||||
|
self.back_screen.cursor.col = @min(
|
||||||
|
self.back_screen.cursor.col + delta,
|
||||||
|
self.back_screen.scrolling_region.right,
|
||||||
|
)
|
||||||
|
else
|
||||||
|
self.back_screen.cursor.col = @min(
|
||||||
|
self.back_screen.cursor.col + delta,
|
||||||
|
self.back_screen.width,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
'H' => { // CUP
|
'H' => { // CUP
|
||||||
var iter = seq.iterator(u16);
|
var iter = seq.iterator(u16);
|
||||||
|
@ -208,6 +251,17 @@ fn run(self: *Terminal) !void {
|
||||||
self.back_screen.cursor.col = col - 1;
|
self.back_screen.cursor.col = col - 1;
|
||||||
self.back_screen.cursor.row = row - 1;
|
self.back_screen.cursor.row = row - 1;
|
||||||
},
|
},
|
||||||
|
'K' => {
|
||||||
|
// TODO selective erase (private_marker == '?')
|
||||||
|
var iter = seq.iterator(u8);
|
||||||
|
const ps = iter.next() orelse 0;
|
||||||
|
switch (ps) {
|
||||||
|
0 => self.back_screen.eraseRight(),
|
||||||
|
1 => {},
|
||||||
|
2 => {},
|
||||||
|
else => continue,
|
||||||
|
}
|
||||||
|
},
|
||||||
'h', 'l' => {
|
'h', 'l' => {
|
||||||
var iter = seq.iterator(u16);
|
var iter = seq.iterator(u16);
|
||||||
const mode = iter.next() orelse continue;
|
const mode = iter.next() orelse continue;
|
||||||
|
@ -256,9 +310,30 @@ inline fn handleC0(self: *Terminal, b: ansi.C0) !void {
|
||||||
|
|
||||||
pub fn setMode(self: *Terminal, mode: u16, val: bool) void {
|
pub fn setMode(self: *Terminal, mode: u16, val: bool) void {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
25 => {
|
25 => self.mode.cursor = val,
|
||||||
self.mode.cursor = val;
|
1049 => {
|
||||||
|
if (val)
|
||||||
|
self.back_screen = &self.back_screen_alt
|
||||||
|
else
|
||||||
|
self.back_screen = &self.back_screen_pri;
|
||||||
},
|
},
|
||||||
|
2026 => self.mode.sync = val,
|
||||||
else => return,
|
else => return,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn encodeKey(self: *Terminal, key: vaxis.Key, press: bool) !void {
|
||||||
|
switch (press) {
|
||||||
|
true => {
|
||||||
|
if (key.text) |text| {
|
||||||
|
try self.anyWriter().writeAll(text);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (key.codepoint) {
|
||||||
|
0x00...0x7F => try self.anyWriter().writeByte(@intCast(key.codepoint)),
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
false => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue