terminal: Zig 0.15, lib-vt and test-lib-vt work
parent
913d2dfb23
commit
3770f97608
|
|
@ -33,8 +33,13 @@ pub fn HashMap(
|
|||
) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
const Map = std.HashMapUnmanaged(K, *Queue.Node, Context, max_load_percentage);
|
||||
const Queue = std.DoublyLinkedList(KV);
|
||||
const Queue = std.DoublyLinkedList;
|
||||
const Map = std.HashMapUnmanaged(
|
||||
K,
|
||||
*Entry,
|
||||
Context,
|
||||
max_load_percentage,
|
||||
);
|
||||
|
||||
/// Map to maintain our entries.
|
||||
map: Map,
|
||||
|
|
@ -46,6 +51,15 @@ pub fn HashMap(
|
|||
/// misses will begin evicting entries.
|
||||
capacity: Map.Size,
|
||||
|
||||
const Entry = struct {
|
||||
data: KV,
|
||||
node: Queue.Node,
|
||||
|
||||
fn fromNode(node: *Queue.Node) *Entry {
|
||||
return @fieldParentPtr("node", node);
|
||||
}
|
||||
};
|
||||
|
||||
pub const KV = struct {
|
||||
key: K,
|
||||
value: V,
|
||||
|
|
@ -82,7 +96,7 @@ pub fn HashMap(
|
|||
var it = self.queue.first;
|
||||
while (it) |node| {
|
||||
it = node.next;
|
||||
alloc.destroy(node);
|
||||
alloc.destroy(Entry.fromNode(node));
|
||||
}
|
||||
|
||||
self.map.deinit(alloc);
|
||||
|
|
@ -108,8 +122,8 @@ pub fn HashMap(
|
|||
const map_gop = try self.map.getOrPutContext(alloc, key, ctx);
|
||||
if (map_gop.found_existing) {
|
||||
// Move to end to mark as most recently used
|
||||
self.queue.remove(map_gop.value_ptr.*);
|
||||
self.queue.append(map_gop.value_ptr.*);
|
||||
self.queue.remove(&map_gop.value_ptr.*.node);
|
||||
self.queue.append(&map_gop.value_ptr.*.node);
|
||||
|
||||
return GetOrPutResult{
|
||||
.found_existing = true,
|
||||
|
|
@ -122,37 +136,34 @@ pub fn HashMap(
|
|||
// We're evicting if our map insertion increased our capacity.
|
||||
const evict = self.map.count() > self.capacity;
|
||||
|
||||
// Get our node. If we're not evicting then we allocate a new
|
||||
// node. If we are evicting then we avoid allocation by just
|
||||
// reusing the node we would've evicted.
|
||||
var node = if (!evict) try alloc.create(Queue.Node) else node: {
|
||||
// Get our entry. If we're not evicting then we allocate a new
|
||||
// entry. If we are evicting then we avoid allocation by just
|
||||
// reusing the entry we would've evicted.
|
||||
const entry: *Entry = if (!evict) try alloc.create(Entry) else entry: {
|
||||
// Our first node is the least recently used.
|
||||
const least_used = self.queue.first.?;
|
||||
|
||||
// Move our least recently used to the end to make
|
||||
// it the most recently used.
|
||||
self.queue.remove(least_used);
|
||||
const least_used_node = self.queue.popFirst().?;
|
||||
const least_used_entry: *Entry = .fromNode(least_used_node);
|
||||
|
||||
// Remove the least used from the map
|
||||
_ = self.map.remove(least_used.data.key);
|
||||
_ = self.map.remove(least_used_entry.data.key);
|
||||
|
||||
break :node least_used;
|
||||
break :entry least_used_entry;
|
||||
};
|
||||
errdefer if (!evict) alloc.destroy(node);
|
||||
errdefer if (!evict) alloc.destroy(entry);
|
||||
|
||||
// Store our node in the map.
|
||||
map_gop.value_ptr.* = node;
|
||||
// Store our entry in the map.
|
||||
map_gop.value_ptr.* = entry;
|
||||
|
||||
// Mark the node as most recently used
|
||||
self.queue.append(node);
|
||||
// Mark the entry as most recently used
|
||||
self.queue.append(&entry.node);
|
||||
|
||||
// Set our key
|
||||
node.data.key = key;
|
||||
entry.data.key = key;
|
||||
|
||||
return GetOrPutResult{
|
||||
return .{
|
||||
.found_existing = map_gop.found_existing,
|
||||
.value_ptr = &node.data.value,
|
||||
.evicted = if (!evict) null else node.data,
|
||||
.value_ptr = &entry.data.value,
|
||||
.evicted = if (!evict) null else entry.data,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -193,11 +204,12 @@ pub fn HashMap(
|
|||
|
||||
var i: Map.Size = 0;
|
||||
while (i < delta) : (i += 1) {
|
||||
const node = self.queue.first.?;
|
||||
evicted[i] = node.data.value;
|
||||
const node = self.queue.popFirst().?;
|
||||
const entry: *Entry = .fromNode(node);
|
||||
evicted[i] = entry.data.value;
|
||||
self.queue.remove(node);
|
||||
_ = self.map.remove(node.data.key);
|
||||
alloc.destroy(node);
|
||||
_ = self.map.remove(entry.data.key);
|
||||
alloc.destroy(entry);
|
||||
}
|
||||
|
||||
self.capacity = capacity;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ pub const CacheTable = cache_table.CacheTable;
|
|||
pub const CircBuf = circ_buf.CircBuf;
|
||||
pub const IntrusiveDoublyLinkedList = intrusive_linked_list.DoublyLinkedList;
|
||||
pub const SegmentedPool = segmented_pool.SegmentedPool;
|
||||
pub const SplitTree = split_tree.SplitTree;
|
||||
//pub const SplitTree = split_tree.SplitTree;
|
||||
|
||||
test {
|
||||
@import("std").testing.refAllDecls(@This());
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ const std_size = Page.layout(std_capacity).total_size;
|
|||
/// allocator because we need memory that is zero-initialized and page-aligned.
|
||||
const PagePool = std.heap.MemoryPoolAligned(
|
||||
[std_size]u8,
|
||||
std.heap.page_size_min,
|
||||
.fromByteUnits(std.heap.page_size_min),
|
||||
);
|
||||
|
||||
/// List of pins, known as "tracked" pins. These are pins that are kept
|
||||
|
|
@ -388,11 +388,18 @@ pub fn reset(self: *PageList) void {
|
|||
const page_arena = &self.pool.pages.arena;
|
||||
var it = page_arena.state.buffer_list.first;
|
||||
while (it) |node| : (it = node.next) {
|
||||
// The fully allocated buffer
|
||||
const alloc_buf = @as([*]u8, @ptrCast(node))[0..node.data];
|
||||
// WARN: Since HeapAllocator's BufNode is not public API,
|
||||
// we have to hardcode its layout here. We do a comptime assert
|
||||
// on Zig version to verify we check it on every bump.
|
||||
const BufNode = struct {
|
||||
data: usize,
|
||||
node: std.SinglyLinkedList.Node,
|
||||
};
|
||||
const buf_node: *BufNode = @fieldParentPtr("node", node);
|
||||
|
||||
// The fully allocated buffer
|
||||
const alloc_buf = @as([*]u8, @ptrCast(buf_node))[0..buf_node.data];
|
||||
// The buffer minus our header
|
||||
const BufNode = @TypeOf(page_arena.state.buffer_list).Node;
|
||||
const data_buf = alloc_buf[@sizeOf(BufNode)..];
|
||||
@memset(data_buf, 0);
|
||||
}
|
||||
|
|
@ -2075,7 +2082,7 @@ inline fn createPageExt(
|
|||
else
|
||||
try page_alloc.alignedAlloc(
|
||||
u8,
|
||||
std.heap.page_size_min,
|
||||
.fromByteUnits(std.heap.page_size_min),
|
||||
layout.total_size,
|
||||
);
|
||||
errdefer if (pooled)
|
||||
|
|
@ -2676,7 +2683,7 @@ pub const EncodeUtf8Options = struct {
|
|||
/// predates this and is a thin wrapper around it so the tests all live there.
|
||||
pub fn encodeUtf8(
|
||||
self: *const PageList,
|
||||
writer: anytype,
|
||||
writer: *std.Io.Writer,
|
||||
opts: EncodeUtf8Options,
|
||||
) anyerror!void {
|
||||
// We don't currently use self at all. There is an argument that this
|
||||
|
|
|
|||
|
|
@ -97,13 +97,9 @@ pub const Action = union(enum) {
|
|||
// Implement formatter for logging
|
||||
pub fn format(
|
||||
self: CSI,
|
||||
comptime layout: []const u8,
|
||||
opts: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
writer: *std.Io.Writer,
|
||||
) !void {
|
||||
_ = layout;
|
||||
_ = opts;
|
||||
try std.fmt.format(writer, "ESC [ {s} {any} {c}", .{
|
||||
try writer.print("ESC [ {s} {any} {c}", .{
|
||||
self.intermediates,
|
||||
self.params,
|
||||
self.final,
|
||||
|
|
@ -118,13 +114,9 @@ pub const Action = union(enum) {
|
|||
// Implement formatter for logging
|
||||
pub fn format(
|
||||
self: ESC,
|
||||
comptime layout: []const u8,
|
||||
opts: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
writer: *std.Io.Writer,
|
||||
) !void {
|
||||
_ = layout;
|
||||
_ = opts;
|
||||
try std.fmt.format(writer, "ESC {s} {c}", .{
|
||||
try writer.print("ESC {s} {c}", .{
|
||||
self.intermediates,
|
||||
self.final,
|
||||
});
|
||||
|
|
@ -142,11 +134,8 @@ pub const Action = union(enum) {
|
|||
// print out custom formats for some of our primitives.
|
||||
pub fn format(
|
||||
self: Action,
|
||||
comptime layout: []const u8,
|
||||
opts: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
writer: *std.Io.Writer,
|
||||
) !void {
|
||||
_ = layout;
|
||||
const T = Action;
|
||||
const info = @typeInfo(T).@"union";
|
||||
|
||||
|
|
@ -162,21 +151,20 @@ pub const Action = union(enum) {
|
|||
const value = @field(self, u_field.name);
|
||||
switch (@TypeOf(value)) {
|
||||
// Unicode
|
||||
u21 => try std.fmt.format(writer, "'{u}' (U+{X})", .{ value, value }),
|
||||
u21 => try writer.print("'{u}' (U+{X})", .{ value, value }),
|
||||
|
||||
// Byte
|
||||
u8 => try std.fmt.format(writer, "0x{x}", .{value}),
|
||||
u8 => try writer.print("0x{x}", .{value}),
|
||||
|
||||
// Note: we don't do ASCII (u8) because there are a lot
|
||||
// of invisible characters we don't want to handle right
|
||||
// now.
|
||||
|
||||
// All others do the default behavior
|
||||
else => try std.fmt.formatType(
|
||||
@field(self, u_field.name),
|
||||
else => try writer.printValue(
|
||||
"any",
|
||||
opts,
|
||||
writer,
|
||||
.{},
|
||||
@field(self, u_field.name),
|
||||
3,
|
||||
),
|
||||
}
|
||||
|
|
@ -391,7 +379,7 @@ inline fn doAction(self: *Parser, action: TransitionAction, c: u8) ?Action {
|
|||
// We only allow colon or mixed separators for the 'm' command.
|
||||
if (c != 'm' and self.params_sep.count() > 0) {
|
||||
log.warn(
|
||||
"CSI colon or mixed separators only allowed for 'm' command, got: {}",
|
||||
"CSI colon or mixed separators only allowed for 'm' command, got: {f}",
|
||||
.{result},
|
||||
);
|
||||
break :csi_dispatch null;
|
||||
|
|
|
|||
|
|
@ -2168,17 +2168,21 @@ pub const SelectionString = struct {
|
|||
/// Returns the raw text associated with a selection. This will unwrap
|
||||
/// soft-wrapped edges. The returned slice is owned by the caller and allocated
|
||||
/// using alloc, not the allocator associated with the screen (unless they match).
|
||||
pub fn selectionString(self: *Screen, alloc: Allocator, opts: SelectionString) ![:0]const u8 {
|
||||
pub fn selectionString(
|
||||
self: *Screen,
|
||||
alloc: Allocator,
|
||||
opts: SelectionString,
|
||||
) ![:0]const u8 {
|
||||
// Use an ArrayList so that we can grow the array as we go. We
|
||||
// build an initial capacity of just our rows in our selection times
|
||||
// columns. It can be more or less based on graphemes, newlines, etc.
|
||||
var strbuilder = std.ArrayList(u8).init(alloc);
|
||||
defer strbuilder.deinit();
|
||||
var strbuilder: std.ArrayList(u8) = .empty;
|
||||
defer strbuilder.deinit(alloc);
|
||||
|
||||
// If we're building a stringmap, create our builder for the pins.
|
||||
const MapBuilder = std.ArrayList(Pin);
|
||||
var mapbuilder: ?MapBuilder = if (opts.map != null) MapBuilder.init(alloc) else null;
|
||||
defer if (mapbuilder) |*b| b.deinit();
|
||||
var mapbuilder: ?MapBuilder = if (opts.map != null) .empty else null;
|
||||
defer if (mapbuilder) |*b| b.deinit(alloc);
|
||||
|
||||
const sel_ordered = opts.sel.ordered(self, .forward);
|
||||
const sel_start: Pin = start: {
|
||||
|
|
@ -2235,9 +2239,9 @@ pub fn selectionString(self: *Screen, alloc: Allocator, opts: SelectionString) !
|
|||
const raw: u21 = if (cell.hasText()) cell.content.codepoint else 0;
|
||||
const char = if (raw > 0) raw else ' ';
|
||||
const encode_len = try std.unicode.utf8Encode(char, &buf);
|
||||
try strbuilder.appendSlice(buf[0..encode_len]);
|
||||
try strbuilder.appendSlice(alloc, buf[0..encode_len]);
|
||||
if (mapbuilder) |*b| {
|
||||
for (0..encode_len) |_| try b.append(.{
|
||||
for (0..encode_len) |_| try b.append(alloc, .{
|
||||
.node = chunk.node,
|
||||
.y = @intCast(y),
|
||||
.x = @intCast(x),
|
||||
|
|
@ -2248,9 +2252,9 @@ pub fn selectionString(self: *Screen, alloc: Allocator, opts: SelectionString) !
|
|||
const cps = chunk.node.data.lookupGrapheme(cell).?;
|
||||
for (cps) |cp| {
|
||||
const encode_len = try std.unicode.utf8Encode(cp, &buf);
|
||||
try strbuilder.appendSlice(buf[0..encode_len]);
|
||||
try strbuilder.appendSlice(alloc, buf[0..encode_len]);
|
||||
if (mapbuilder) |*b| {
|
||||
for (0..encode_len) |_| try b.append(.{
|
||||
for (0..encode_len) |_| try b.append(alloc, .{
|
||||
.node = chunk.node,
|
||||
.y = @intCast(y),
|
||||
.x = @intCast(x),
|
||||
|
|
@ -2265,8 +2269,8 @@ pub fn selectionString(self: *Screen, alloc: Allocator, opts: SelectionString) !
|
|||
if (!is_final_row and
|
||||
(!row.wrap or sel_ordered.rectangle))
|
||||
{
|
||||
try strbuilder.append('\n');
|
||||
if (mapbuilder) |*b| try b.append(.{
|
||||
try strbuilder.append(alloc, '\n');
|
||||
if (mapbuilder) |*b| try b.append(alloc, .{
|
||||
.node = chunk.node,
|
||||
.y = @intCast(y),
|
||||
.x = chunk.node.data.size.cols - 1,
|
||||
|
|
@ -2281,11 +2285,11 @@ pub fn selectionString(self: *Screen, alloc: Allocator, opts: SelectionString) !
|
|||
|
||||
// If we have a mapbuilder, we need to setup our string map.
|
||||
if (mapbuilder) |*b| {
|
||||
var strclone = try strbuilder.clone();
|
||||
defer strclone.deinit();
|
||||
const str = try strclone.toOwnedSliceSentinel(0);
|
||||
var strclone = try strbuilder.clone(alloc);
|
||||
defer strclone.deinit(alloc);
|
||||
const str = try strclone.toOwnedSliceSentinel(alloc, 0);
|
||||
errdefer alloc.free(str);
|
||||
const map = try b.toOwnedSlice();
|
||||
const map = try b.toOwnedSlice(alloc);
|
||||
errdefer alloc.free(map);
|
||||
opts.map.?.* = .{ .string = str, .map = map };
|
||||
}
|
||||
|
|
@ -2306,7 +2310,7 @@ pub fn selectionString(self: *Screen, alloc: Allocator, opts: SelectionString) !
|
|||
const i = strbuilder.items.len;
|
||||
strbuilder.items.len += trimmed.len;
|
||||
std.mem.copyForwards(u8, strbuilder.items[i..], trimmed);
|
||||
try strbuilder.append('\n');
|
||||
try strbuilder.append(alloc, '\n');
|
||||
}
|
||||
|
||||
// Remove all trailing newlines
|
||||
|
|
@ -2317,7 +2321,7 @@ pub fn selectionString(self: *Screen, alloc: Allocator, opts: SelectionString) !
|
|||
}
|
||||
|
||||
// Get our final string
|
||||
const string = try strbuilder.toOwnedSliceSentinel(0);
|
||||
const string = try strbuilder.toOwnedSliceSentinel(alloc, 0);
|
||||
errdefer alloc.free(string);
|
||||
|
||||
return string;
|
||||
|
|
@ -2902,7 +2906,7 @@ pub fn promptPath(
|
|||
/// one byte at a time.
|
||||
pub fn dumpString(
|
||||
self: *const Screen,
|
||||
writer: anytype,
|
||||
writer: *std.Io.Writer,
|
||||
opts: PageList.EncodeUtf8Options,
|
||||
) anyerror!void {
|
||||
try self.pages.encodeUtf8(writer, opts);
|
||||
|
|
@ -2915,10 +2919,10 @@ pub fn dumpStringAlloc(
|
|||
alloc: Allocator,
|
||||
tl: point.Point,
|
||||
) ![]const u8 {
|
||||
var builder = std.ArrayList(u8).init(alloc);
|
||||
var builder: std.Io.Writer.Allocating = .init(alloc);
|
||||
defer builder.deinit();
|
||||
|
||||
try self.dumpString(builder.writer(), .{
|
||||
try self.dumpString(&builder.writer, .{
|
||||
.tl = self.pages.getTopLeft(tl),
|
||||
.br = self.pages.getBottomRight(tl) orelse return error.UnknownPoint,
|
||||
.unwrap = false,
|
||||
|
|
@ -2934,10 +2938,10 @@ pub fn dumpStringAllocUnwrapped(
|
|||
alloc: Allocator,
|
||||
tl: point.Point,
|
||||
) ![]const u8 {
|
||||
var builder = std.ArrayList(u8).init(alloc);
|
||||
var builder: std.Io.Writer.Allocating = .init(alloc);
|
||||
defer builder.deinit();
|
||||
|
||||
try self.dumpString(builder.writer(), .{
|
||||
try self.dumpString(&builder.writer, .{
|
||||
.tl = self.pages.getTopLeft(tl),
|
||||
.br = self.pages.getBottomRight(tl) orelse return error.UnknownPoint,
|
||||
.unwrap = true,
|
||||
|
|
@ -9030,33 +9034,33 @@ test "Screen UTF8 cell map with newlines" {
|
|||
|
||||
var cell_map = Page.CellMap.init(alloc);
|
||||
defer cell_map.deinit();
|
||||
var builder = std.ArrayList(u8).init(alloc);
|
||||
var builder: std.Io.Writer.Allocating = .init(alloc);
|
||||
defer builder.deinit();
|
||||
try s.dumpString(builder.writer(), .{
|
||||
try s.dumpString(&builder.writer, .{
|
||||
.tl = s.pages.getTopLeft(.screen),
|
||||
.br = s.pages.getBottomRight(.screen),
|
||||
.cell_map = &cell_map,
|
||||
});
|
||||
|
||||
try testing.expectEqual(7, builder.items.len);
|
||||
try testing.expectEqualStrings("A\n\nB\n\nC", builder.items);
|
||||
try testing.expectEqual(builder.items.len, cell_map.items.len);
|
||||
try testing.expectEqual(7, builder.written().len);
|
||||
try testing.expectEqualStrings("A\n\nB\n\nC", builder.written());
|
||||
try testing.expectEqual(builder.written().len, cell_map.map.items.len);
|
||||
try testing.expectEqual(Page.CellMapEntry{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
}, cell_map.items[0]);
|
||||
}, cell_map.map.items[0]);
|
||||
try testing.expectEqual(Page.CellMapEntry{
|
||||
.x = 1,
|
||||
.y = 0,
|
||||
}, cell_map.items[1]);
|
||||
}, cell_map.map.items[1]);
|
||||
try testing.expectEqual(Page.CellMapEntry{
|
||||
.x = 0,
|
||||
.y = 1,
|
||||
}, cell_map.items[2]);
|
||||
}, cell_map.map.items[2]);
|
||||
try testing.expectEqual(Page.CellMapEntry{
|
||||
.x = 0,
|
||||
.y = 2,
|
||||
}, cell_map.items[3]);
|
||||
}, cell_map.map.items[3]);
|
||||
}
|
||||
|
||||
test "Screen UTF8 cell map with blank prefix" {
|
||||
|
|
@ -9068,32 +9072,32 @@ test "Screen UTF8 cell map with blank prefix" {
|
|||
s.cursorAbsolute(2, 1);
|
||||
try s.testWriteString("B");
|
||||
|
||||
var cell_map = Page.CellMap.init(alloc);
|
||||
var cell_map: Page.CellMap = .init(alloc);
|
||||
defer cell_map.deinit();
|
||||
var builder = std.ArrayList(u8).init(alloc);
|
||||
var builder: std.Io.Writer.Allocating = .init(alloc);
|
||||
defer builder.deinit();
|
||||
try s.dumpString(builder.writer(), .{
|
||||
try s.dumpString(&builder.writer, .{
|
||||
.tl = s.pages.getTopLeft(.screen),
|
||||
.br = s.pages.getBottomRight(.screen),
|
||||
.cell_map = &cell_map,
|
||||
});
|
||||
|
||||
try testing.expectEqualStrings("\n B", builder.items);
|
||||
try testing.expectEqual(builder.items.len, cell_map.items.len);
|
||||
try testing.expectEqualStrings("\n B", builder.written());
|
||||
try testing.expectEqual(builder.written().len, cell_map.map.items.len);
|
||||
try testing.expectEqual(Page.CellMapEntry{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
}, cell_map.items[0]);
|
||||
}, cell_map.map.items[0]);
|
||||
try testing.expectEqual(Page.CellMapEntry{
|
||||
.x = 0,
|
||||
.y = 1,
|
||||
}, cell_map.items[1]);
|
||||
}, cell_map.map.items[1]);
|
||||
try testing.expectEqual(Page.CellMapEntry{
|
||||
.x = 1,
|
||||
.y = 1,
|
||||
}, cell_map.items[2]);
|
||||
}, cell_map.map.items[2]);
|
||||
try testing.expectEqual(Page.CellMapEntry{
|
||||
.x = 2,
|
||||
.y = 1,
|
||||
}, cell_map.items[3]);
|
||||
}, cell_map.map.items[3]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ pub fn init(
|
|||
.left = 0,
|
||||
.right = cols - 1,
|
||||
},
|
||||
.pwd = std.ArrayList(u8).init(alloc),
|
||||
.pwd = .empty,
|
||||
.modes = .{
|
||||
.values = opts.default_modes,
|
||||
.default = opts.default_modes,
|
||||
|
|
@ -235,7 +235,7 @@ pub fn deinit(self: *Terminal, alloc: Allocator) void {
|
|||
self.tabstops.deinit(alloc);
|
||||
self.screen.deinit();
|
||||
self.secondary_screen.deinit();
|
||||
self.pwd.deinit();
|
||||
self.pwd.deinit(alloc);
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ pub fn BitmapAllocator(comptime chunk_size: comptime_int) type {
|
|||
assert(std.math.isPowerOfTwo(chunk_size));
|
||||
}
|
||||
|
||||
pub const base_align = @alignOf(u64);
|
||||
pub const base_align: std.mem.Alignment = .fromByteUnits(@alignOf(u64));
|
||||
pub const bitmap_bit_size = @bitSizeOf(u64);
|
||||
|
||||
/// The bitmap of available chunks. Each bit represents a chunk. A
|
||||
|
|
@ -49,7 +49,7 @@ pub fn BitmapAllocator(comptime chunk_size: comptime_int) type {
|
|||
|
||||
/// Initialize the allocator map with a given buf and memory layout.
|
||||
pub fn init(buf: OffsetBuf, l: Layout) Self {
|
||||
assert(@intFromPtr(buf.start()) % base_align == 0);
|
||||
assert(base_align.check(@intFromPtr(buf.start())));
|
||||
|
||||
// Initialize our bitmaps to all 1s to note that all chunks are free.
|
||||
const bitmap = buf.member(u64, l.bitmap_start);
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ pub const Handler = struct {
|
|||
// https://github.com/mitchellh/ghostty/issues/517
|
||||
'q' => .{
|
||||
.state = .{
|
||||
.xtgettcap = try std.ArrayList(u8).initCapacity(
|
||||
.xtgettcap = try .initCapacity(
|
||||
alloc,
|
||||
128, // Arbitrary choice
|
||||
),
|
||||
|
|
@ -134,11 +134,11 @@ pub const Handler = struct {
|
|||
} else unreachable,
|
||||
|
||||
.xtgettcap => |*list| {
|
||||
if (list.items.len >= self.max_bytes) {
|
||||
if (list.written().len >= self.max_bytes) {
|
||||
return error.OutOfMemory;
|
||||
}
|
||||
|
||||
try list.append(byte);
|
||||
try list.writer.writeByte(byte);
|
||||
},
|
||||
|
||||
.decrqss => |*buffer| {
|
||||
|
|
@ -170,11 +170,12 @@ pub const Handler = struct {
|
|||
break :tmux .{ .tmux = .{ .exit = {} } };
|
||||
} else unreachable,
|
||||
|
||||
.xtgettcap => |list| xtgettcap: {
|
||||
for (list.items, 0..) |b, i| {
|
||||
list.items[i] = std.ascii.toUpper(b);
|
||||
}
|
||||
break :xtgettcap .{ .xtgettcap = .{ .data = list } };
|
||||
.xtgettcap => |*list| xtgettcap: {
|
||||
// Note: purposely do not deinit our state here because
|
||||
// we copy it into the resulting command.
|
||||
const items = list.written();
|
||||
for (items, 0..) |b, i| items[i] = std.ascii.toUpper(b);
|
||||
break :xtgettcap .{ .xtgettcap = .{ .data = list.* } };
|
||||
},
|
||||
|
||||
.decrqss => |buffer| .{ .decrqss = switch (buffer.len) {
|
||||
|
|
@ -216,8 +217,8 @@ pub const Command = union(enum) {
|
|||
else
|
||||
void,
|
||||
|
||||
pub fn deinit(self: Command) void {
|
||||
switch (self) {
|
||||
pub fn deinit(self: *Command) void {
|
||||
switch (self.*) {
|
||||
.xtgettcap => |*v| v.data.deinit(),
|
||||
.decrqss => {},
|
||||
.tmux => {},
|
||||
|
|
@ -225,16 +226,16 @@ pub const Command = union(enum) {
|
|||
}
|
||||
|
||||
pub const XTGETTCAP = struct {
|
||||
data: std.ArrayList(u8),
|
||||
data: std.Io.Writer.Allocating,
|
||||
i: usize = 0,
|
||||
|
||||
/// Returns the next terminfo key being requested and null
|
||||
/// when there are no more keys. The returned value is NOT hex-decoded
|
||||
/// because we expect to use a comptime lookup table.
|
||||
pub fn next(self: *XTGETTCAP) ?[]const u8 {
|
||||
if (self.i >= self.data.items.len) return null;
|
||||
|
||||
var rem = self.data.items[self.i..];
|
||||
const items = self.data.written();
|
||||
if (self.i >= items.len) return null;
|
||||
var rem = items[self.i..];
|
||||
const idx = std.mem.indexOf(u8, rem, ";") orelse rem.len;
|
||||
|
||||
// Note that if we're at the end, idx + 1 is len + 1 so we're over
|
||||
|
|
@ -271,7 +272,7 @@ const State = union(enum) {
|
|||
ignore: void,
|
||||
|
||||
/// XTGETTCAP
|
||||
xtgettcap: std.ArrayList(u8),
|
||||
xtgettcap: std.Io.Writer.Allocating,
|
||||
|
||||
/// DECRQSS
|
||||
decrqss: struct {
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ pub fn OffsetHashMap(
|
|||
/// Initialize a new HashMap with the given capacity and backing
|
||||
/// memory. The backing memory must be aligned to base_align.
|
||||
pub fn init(buf: OffsetBuf, l: Layout) Self {
|
||||
assert(@intFromPtr(buf.start()) % base_align == 0);
|
||||
assert(base_align.check(@intFromPtr(buf.start())));
|
||||
|
||||
const m = Unmanaged.init(buf, l);
|
||||
return .{ .metadata = getOffset(
|
||||
|
|
@ -124,7 +124,11 @@ fn HashMapUnmanaged(
|
|||
const header_align = @alignOf(Header);
|
||||
const key_align = if (@sizeOf(K) == 0) 1 else @alignOf(K);
|
||||
const val_align = if (@sizeOf(V) == 0) 1 else @alignOf(V);
|
||||
const base_align = @max(header_align, key_align, val_align);
|
||||
const base_align: mem.Alignment = .fromByteUnits(@max(
|
||||
header_align,
|
||||
key_align,
|
||||
val_align,
|
||||
));
|
||||
|
||||
// This is actually a midway pointer to the single buffer containing
|
||||
// a `Header` field, the `Metadata`s and `Entry`s.
|
||||
|
|
@ -287,7 +291,7 @@ fn HashMapUnmanaged(
|
|||
/// Initialize a hash map with a given capacity and a buffer. The
|
||||
/// buffer must fit within the size defined by `layoutForCapacity`.
|
||||
pub fn init(buf: OffsetBuf, layout: Layout) Self {
|
||||
assert(@intFromPtr(buf.start()) % base_align == 0);
|
||||
assert(base_align.check(@intFromPtr(buf.start())));
|
||||
|
||||
// Get all our main pointers
|
||||
const metadata_buf = buf.rebase(@sizeOf(Header));
|
||||
|
|
@ -862,7 +866,11 @@ fn HashMapUnmanaged(
|
|||
|
||||
// Our total memory size required is the end of our values
|
||||
// aligned to the base required alignment.
|
||||
const total_size = std.mem.alignForward(usize, vals_end, base_align);
|
||||
const total_size = std.mem.alignForward(
|
||||
usize,
|
||||
vals_end,
|
||||
base_align.toByteUnits(),
|
||||
);
|
||||
|
||||
// The offsets we actually store in the map are from the
|
||||
// metadata pointer so that we can use self.metadata as
|
||||
|
|
@ -1126,15 +1134,15 @@ test "HashMap put and remove loop in random order" {
|
|||
defer alloc.free(buf);
|
||||
var map = Map.init(.init(buf), layout);
|
||||
|
||||
var keys = std.ArrayList(u32).init(alloc);
|
||||
defer keys.deinit();
|
||||
var keys: std.ArrayList(u32) = .empty;
|
||||
defer keys.deinit(alloc);
|
||||
|
||||
const size = 32;
|
||||
const iterations = 100;
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < size) : (i += 1) {
|
||||
try keys.append(i);
|
||||
try keys.append(alloc, i);
|
||||
}
|
||||
var prng = std.Random.DefaultPrng.init(0);
|
||||
const random = prng.random();
|
||||
|
|
|
|||
|
|
@ -42,13 +42,8 @@ pub const Kind = union(enum) {
|
|||
|
||||
pub fn format(
|
||||
self: Kind,
|
||||
comptime layout: []const u8,
|
||||
opts: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
writer: *std.Io.Writer,
|
||||
) !void {
|
||||
_ = layout;
|
||||
_ = opts;
|
||||
|
||||
switch (self) {
|
||||
.palette => |p| try writer.print("{d}", .{p}),
|
||||
.special => |s| try writer.print("{s}", .{@tagName(s)}),
|
||||
|
|
@ -61,11 +56,11 @@ test "OSC: kitty color protocol kind string" {
|
|||
|
||||
var buf: [256]u8 = undefined;
|
||||
{
|
||||
const actual = try std.fmt.bufPrint(&buf, "{}", .{Kind{ .special = .foreground }});
|
||||
const actual = try std.fmt.bufPrint(&buf, "{f}", .{Kind{ .special = .foreground }});
|
||||
try testing.expectEqualStrings("foreground", actual);
|
||||
}
|
||||
{
|
||||
const actual = try std.fmt.bufPrint(&buf, "{}", .{Kind{ .palette = 42 }});
|
||||
const actual = try std.fmt.bufPrint(&buf, "{f}", .{Kind{ .palette = 42 }});
|
||||
try testing.expectEqualStrings("42", actual);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -475,7 +475,7 @@ pub const Parser = struct {
|
|||
|
||||
// Some commands have their own memory management we need to clear.
|
||||
switch (self.command) {
|
||||
.kitty_color_protocol => |*v| v.list.deinit(),
|
||||
.kitty_color_protocol => |*v| v.list.deinit(self.alloc.?),
|
||||
.color_operation => |*v| v.requests.deinit(self.alloc.?),
|
||||
else => {},
|
||||
}
|
||||
|
|
@ -821,15 +821,15 @@ pub const Parser = struct {
|
|||
|
||||
.@"21" => switch (c) {
|
||||
';' => kitty: {
|
||||
const alloc = self.alloc orelse {
|
||||
if (self.alloc == null) {
|
||||
log.info("OSC 21 requires an allocator, but none was provided", .{});
|
||||
self.state = .invalid;
|
||||
break :kitty;
|
||||
};
|
||||
}
|
||||
|
||||
self.command = .{
|
||||
.kitty_color_protocol = .{
|
||||
.list = std.ArrayList(kitty_color.OSC.Request).init(alloc),
|
||||
.list = .empty,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -1553,18 +1553,22 @@ pub const Parser = struct {
|
|||
return;
|
||||
}
|
||||
|
||||
// Asserted when the command is set to kitty_color_protocol
|
||||
// that we have an allocator.
|
||||
const alloc = self.alloc.?;
|
||||
|
||||
if (kind == .key_only or value.len == 0) {
|
||||
v.list.append(.{ .reset = key }) catch |err| {
|
||||
v.list.append(alloc, .{ .reset = key }) catch |err| {
|
||||
log.warn("unable to append kitty color protocol option: {}", .{err});
|
||||
return;
|
||||
};
|
||||
} else if (mem.eql(u8, "?", value)) {
|
||||
v.list.append(.{ .query = key }) catch |err| {
|
||||
v.list.append(alloc, .{ .query = key }) catch |err| {
|
||||
log.warn("unable to append kitty color protocol option: {}", .{err});
|
||||
return;
|
||||
};
|
||||
} else {
|
||||
v.list.append(.{
|
||||
v.list.append(alloc, .{
|
||||
.set = .{
|
||||
.key = key,
|
||||
.color = RGB.parse(value) catch |err| switch (err) {
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ pub const Page = struct {
|
|||
assert(std.heap.page_size_min % @max(
|
||||
@alignOf(Row),
|
||||
@alignOf(Cell),
|
||||
style.Set.base_align,
|
||||
style.Set.base_align.toByteUnits(),
|
||||
) == 0);
|
||||
}
|
||||
|
||||
|
|
@ -1528,7 +1528,21 @@ pub const Page = struct {
|
|||
};
|
||||
|
||||
/// See cell_map
|
||||
pub const CellMap = std.ArrayList(CellMapEntry);
|
||||
pub const CellMap = struct {
|
||||
alloc: Allocator,
|
||||
map: std.ArrayList(CellMapEntry),
|
||||
|
||||
pub fn init(alloc: Allocator) CellMap {
|
||||
return .{
|
||||
.alloc = alloc,
|
||||
.map = .empty,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *CellMap) void {
|
||||
self.map.deinit(self.alloc);
|
||||
}
|
||||
};
|
||||
|
||||
/// The x/y coordinate of a single cell in the cell map.
|
||||
pub const CellMapEntry = struct {
|
||||
|
|
@ -1547,7 +1561,7 @@ pub const Page = struct {
|
|||
/// it makes it easier to test input contents.
|
||||
pub fn encodeUtf8(
|
||||
self: *const Page,
|
||||
writer: anytype,
|
||||
writer: *std.Io.Writer,
|
||||
opts: EncodeUtf8Options,
|
||||
) anyerror!EncodeUtf8Options.TrailingUtf8State {
|
||||
var blank_rows: usize = opts.preceding.rows;
|
||||
|
|
@ -1583,7 +1597,7 @@ pub const Page = struct {
|
|||
// This is tested in Screen.zig, i.e. one test is
|
||||
// "cell map with newlines"
|
||||
if (opts.cell_map) |cell_map| {
|
||||
try cell_map.append(.{
|
||||
try cell_map.map.append(cell_map.alloc, .{
|
||||
.x = last_x,
|
||||
.y = @intCast(y - blank_rows + i - 1),
|
||||
});
|
||||
|
|
@ -1618,9 +1632,9 @@ pub const Page = struct {
|
|||
continue;
|
||||
}
|
||||
if (blank_cells > 0) {
|
||||
try writer.writeByteNTimes(' ', blank_cells);
|
||||
try writer.splatByteAll(' ', blank_cells);
|
||||
if (opts.cell_map) |cell_map| {
|
||||
for (0..blank_cells) |i| try cell_map.append(.{
|
||||
for (0..blank_cells) |i| try cell_map.map.append(cell_map.alloc, .{
|
||||
.x = @intCast(x - blank_cells + i),
|
||||
.y = y,
|
||||
});
|
||||
|
|
@ -1634,7 +1648,7 @@ pub const Page = struct {
|
|||
try writer.print("{u}", .{cell.content.codepoint});
|
||||
if (opts.cell_map) |cell_map| {
|
||||
last_x = x + 1;
|
||||
try cell_map.append(.{
|
||||
try cell_map.map.append(cell_map.alloc, .{
|
||||
.x = x,
|
||||
.y = y,
|
||||
});
|
||||
|
|
@ -1645,7 +1659,7 @@ pub const Page = struct {
|
|||
try writer.print("{u}", .{cell.content.codepoint});
|
||||
if (opts.cell_map) |cell_map| {
|
||||
last_x = x + 1;
|
||||
try cell_map.append(.{
|
||||
try cell_map.map.append(cell_map.alloc, .{
|
||||
.x = x,
|
||||
.y = y,
|
||||
});
|
||||
|
|
@ -1653,7 +1667,7 @@ pub const Page = struct {
|
|||
|
||||
for (self.lookupGrapheme(cell).?) |cp| {
|
||||
try writer.print("{u}", .{cp});
|
||||
if (opts.cell_map) |cell_map| try cell_map.append(.{
|
||||
if (opts.cell_map) |cell_map| try cell_map.map.append(cell_map.alloc, .{
|
||||
.x = x,
|
||||
.y = y,
|
||||
});
|
||||
|
|
@ -1743,25 +1757,25 @@ pub const Page = struct {
|
|||
const dirty_end: usize = dirty_start + (dirty_usize_length * @sizeOf(usize));
|
||||
|
||||
const styles_layout: style.Set.Layout = .init(cap.styles);
|
||||
const styles_start = alignForward(usize, dirty_end, style.Set.base_align);
|
||||
const styles_start = alignForward(usize, dirty_end, style.Set.base_align.toByteUnits());
|
||||
const styles_end = styles_start + styles_layout.total_size;
|
||||
|
||||
const grapheme_alloc_layout = GraphemeAlloc.layout(cap.grapheme_bytes);
|
||||
const grapheme_alloc_start = alignForward(usize, styles_end, GraphemeAlloc.base_align);
|
||||
const grapheme_alloc_start = alignForward(usize, styles_end, GraphemeAlloc.base_align.toByteUnits());
|
||||
const grapheme_alloc_end = grapheme_alloc_start + grapheme_alloc_layout.total_size;
|
||||
|
||||
const grapheme_count = @divFloor(cap.grapheme_bytes, grapheme_chunk);
|
||||
const grapheme_map_layout = GraphemeMap.layout(@intCast(grapheme_count));
|
||||
const grapheme_map_start = alignForward(usize, grapheme_alloc_end, GraphemeMap.base_align);
|
||||
const grapheme_map_start = alignForward(usize, grapheme_alloc_end, GraphemeMap.base_align.toByteUnits());
|
||||
const grapheme_map_end = grapheme_map_start + grapheme_map_layout.total_size;
|
||||
|
||||
const string_layout = StringAlloc.layout(cap.string_bytes);
|
||||
const string_start = alignForward(usize, grapheme_map_end, StringAlloc.base_align);
|
||||
const string_start = alignForward(usize, grapheme_map_end, StringAlloc.base_align.toByteUnits());
|
||||
const string_end = string_start + string_layout.total_size;
|
||||
|
||||
const hyperlink_count = @divFloor(cap.hyperlink_bytes, @sizeOf(hyperlink.Set.Item));
|
||||
const hyperlink_set_layout: hyperlink.Set.Layout = .init(@intCast(hyperlink_count));
|
||||
const hyperlink_set_start = alignForward(usize, string_end, hyperlink.Set.base_align);
|
||||
const hyperlink_set_start = alignForward(usize, string_end, hyperlink.Set.base_align.toByteUnits());
|
||||
const hyperlink_set_end = hyperlink_set_start + hyperlink_set_layout.total_size;
|
||||
|
||||
const hyperlink_map_count: u32 = count: {
|
||||
|
|
@ -1773,7 +1787,7 @@ pub const Page = struct {
|
|||
break :count std.math.ceilPowerOfTwoAssert(u32, mult);
|
||||
};
|
||||
const hyperlink_map_layout = hyperlink.Map.layout(hyperlink_map_count);
|
||||
const hyperlink_map_start = alignForward(usize, hyperlink_set_end, hyperlink.Map.base_align);
|
||||
const hyperlink_map_start = alignForward(usize, hyperlink_set_end, hyperlink.Map.base_align.toByteUnits());
|
||||
const hyperlink_map_end = hyperlink_map_start + hyperlink_map_layout.total_size;
|
||||
|
||||
const total_size = alignForward(usize, hyperlink_map_end, std.heap.page_size_min);
|
||||
|
|
@ -1867,12 +1881,12 @@ pub const Capacity = struct {
|
|||
// for rows & cells (which will allow us to calculate the number of
|
||||
// rows we can fit at a certain column width) we need to layout the
|
||||
// "meta" members of the page (i.e. everything else) from the end.
|
||||
const hyperlink_map_start = alignBackward(usize, layout.total_size - layout.hyperlink_map_layout.total_size, hyperlink.Map.base_align);
|
||||
const hyperlink_set_start = alignBackward(usize, hyperlink_map_start - layout.hyperlink_set_layout.total_size, hyperlink.Set.base_align);
|
||||
const string_alloc_start = alignBackward(usize, hyperlink_set_start - layout.string_alloc_layout.total_size, StringAlloc.base_align);
|
||||
const grapheme_map_start = alignBackward(usize, string_alloc_start - layout.grapheme_map_layout.total_size, GraphemeMap.base_align);
|
||||
const grapheme_alloc_start = alignBackward(usize, grapheme_map_start - layout.grapheme_alloc_layout.total_size, GraphemeAlloc.base_align);
|
||||
const styles_start = alignBackward(usize, grapheme_alloc_start - layout.styles_layout.total_size, style.Set.base_align);
|
||||
const hyperlink_map_start = alignBackward(usize, layout.total_size - layout.hyperlink_map_layout.total_size, hyperlink.Map.base_align.toByteUnits());
|
||||
const hyperlink_set_start = alignBackward(usize, hyperlink_map_start - layout.hyperlink_set_layout.total_size, hyperlink.Set.base_align.toByteUnits());
|
||||
const string_alloc_start = alignBackward(usize, hyperlink_set_start - layout.string_alloc_layout.total_size, StringAlloc.base_align.toByteUnits());
|
||||
const grapheme_map_start = alignBackward(usize, string_alloc_start - layout.grapheme_map_layout.total_size, GraphemeMap.base_align.toByteUnits());
|
||||
const grapheme_alloc_start = alignBackward(usize, grapheme_map_start - layout.grapheme_alloc_layout.total_size, GraphemeAlloc.base_align.toByteUnits());
|
||||
const styles_start = alignBackward(usize, grapheme_alloc_start - layout.styles_layout.total_size, style.Set.base_align.toByteUnits());
|
||||
|
||||
// The size per row is:
|
||||
// - The row metadata itself
|
||||
|
|
|
|||
|
|
@ -59,12 +59,12 @@ pub fn RefCountedSet(
|
|||
return struct {
|
||||
const Self = @This();
|
||||
|
||||
pub const base_align = @max(
|
||||
pub const base_align: std.mem.Alignment = .fromByteUnits(@max(
|
||||
@alignOf(Context),
|
||||
@alignOf(Layout),
|
||||
@alignOf(Item),
|
||||
@alignOf(Id),
|
||||
);
|
||||
));
|
||||
|
||||
/// Set item
|
||||
pub const Item = struct {
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ pub const PageListSearch = struct {
|
|||
needle: []const u8,
|
||||
) Allocator.Error!PageListSearch {
|
||||
var window = try SlidingWindow.init(alloc, needle);
|
||||
errdefer window.deinit(alloc);
|
||||
errdefer window.deinit();
|
||||
|
||||
return .{
|
||||
.list = list,
|
||||
|
|
@ -63,16 +63,13 @@ pub const PageListSearch = struct {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *PageListSearch, alloc: Allocator) void {
|
||||
self.window.deinit(alloc);
|
||||
pub fn deinit(self: *PageListSearch) void {
|
||||
self.window.deinit();
|
||||
}
|
||||
|
||||
/// Find the next match for the needle in the pagelist. This returns
|
||||
/// null when there are no more matches.
|
||||
pub fn next(
|
||||
self: *PageListSearch,
|
||||
alloc: Allocator,
|
||||
) Allocator.Error!?Selection {
|
||||
pub fn next(self: *PageListSearch) Allocator.Error!?Selection {
|
||||
// Try to search for the needle in the window. If we find a match
|
||||
// then we can return that and we're done.
|
||||
if (self.window.next()) |sel| return sel;
|
||||
|
|
@ -89,7 +86,7 @@ pub const PageListSearch = struct {
|
|||
// until we find a match or we reach the end of the pagelist.
|
||||
// This append then next pattern limits memory usage of the window.
|
||||
while (node_) |node| : (node_ = node.next) {
|
||||
try self.window.append(alloc, node);
|
||||
try self.window.append(node);
|
||||
if (self.window.next()) |sel| return sel;
|
||||
}
|
||||
|
||||
|
|
@ -115,6 +112,14 @@ pub const PageListSearch = struct {
|
|||
/// and repeat the process. This will always maintain the minimum
|
||||
/// required memory to search for the needle.
|
||||
const SlidingWindow = struct {
|
||||
/// The allocator to use for all the data within this window. We
|
||||
/// store this rather than passing it around because its already
|
||||
/// part of multiple elements (eg. Meta's CellMap) and we want to
|
||||
/// ensure we always use a consistent allocator. Additionally, only
|
||||
/// a small amount of sliding windows are expected to be in use
|
||||
/// at any one time so the memory overhead isn't that large.
|
||||
alloc: Allocator,
|
||||
|
||||
/// The data buffer is a circular buffer of u8 that contains the
|
||||
/// encoded page text that we can use to search for the needle.
|
||||
data: DataBuf,
|
||||
|
|
@ -163,6 +168,7 @@ const SlidingWindow = struct {
|
|||
errdefer alloc.free(overlap_buf);
|
||||
|
||||
return .{
|
||||
.alloc = alloc,
|
||||
.data = data,
|
||||
.meta = meta,
|
||||
.needle = needle,
|
||||
|
|
@ -170,13 +176,13 @@ const SlidingWindow = struct {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *SlidingWindow, alloc: Allocator) void {
|
||||
alloc.free(self.overlap_buf);
|
||||
self.data.deinit(alloc);
|
||||
pub fn deinit(self: *SlidingWindow) void {
|
||||
self.alloc.free(self.overlap_buf);
|
||||
self.data.deinit(self.alloc);
|
||||
|
||||
var meta_it = self.meta.iterator(.forward);
|
||||
while (meta_it.next()) |meta| meta.deinit();
|
||||
self.meta.deinit(alloc);
|
||||
self.meta.deinit(self.alloc);
|
||||
}
|
||||
|
||||
/// Clear all data but retain allocated capacity.
|
||||
|
|
@ -206,7 +212,10 @@ const SlidingWindow = struct {
|
|||
|
||||
// Search the first slice for the needle.
|
||||
if (std.mem.indexOf(u8, slices[0], self.needle)) |idx| {
|
||||
return self.selection(idx, self.needle.len);
|
||||
return self.selection(
|
||||
idx,
|
||||
self.needle.len,
|
||||
);
|
||||
}
|
||||
|
||||
// Search the overlap buffer for the needle.
|
||||
|
|
@ -244,7 +253,10 @@ const SlidingWindow = struct {
|
|||
|
||||
// Search the last slice for the needle.
|
||||
if (std.mem.indexOf(u8, slices[1], self.needle)) |idx| {
|
||||
return self.selection(slices[0].len + idx, self.needle.len);
|
||||
return self.selection(
|
||||
slices[0].len + idx,
|
||||
self.needle.len,
|
||||
);
|
||||
}
|
||||
|
||||
// No match. We keep `needle.len - 1` bytes available to
|
||||
|
|
@ -254,15 +266,15 @@ const SlidingWindow = struct {
|
|||
var saved: usize = 0;
|
||||
while (meta_it.next()) |meta| {
|
||||
const needed = self.needle.len - 1 - saved;
|
||||
if (meta.cell_map.items.len >= needed) {
|
||||
if (meta.cell_map.map.items.len >= needed) {
|
||||
// We save up to this meta. We set our data offset
|
||||
// to exactly where it needs to be to continue
|
||||
// searching.
|
||||
self.data_offset = meta.cell_map.items.len - needed;
|
||||
self.data_offset = meta.cell_map.map.items.len - needed;
|
||||
break;
|
||||
}
|
||||
|
||||
saved += meta.cell_map.items.len;
|
||||
saved += meta.cell_map.map.items.len;
|
||||
} else {
|
||||
// If we exited the while loop naturally then we
|
||||
// never got the amount we needed and so there is
|
||||
|
|
@ -284,7 +296,7 @@ const SlidingWindow = struct {
|
|||
var prune_data_len: usize = 0;
|
||||
for (0..prune_count) |_| {
|
||||
const meta = meta_it.next().?;
|
||||
prune_data_len += meta.cell_map.items.len;
|
||||
prune_data_len += meta.cell_map.map.items.len;
|
||||
meta.deinit();
|
||||
}
|
||||
self.meta.deleteOldest(prune_count);
|
||||
|
|
@ -384,16 +396,16 @@ const SlidingWindow = struct {
|
|||
// meta_i is the index we expect to find the match in the
|
||||
// cell map within this meta if it contains it.
|
||||
const meta_i = idx - offset.*;
|
||||
if (meta_i >= meta.cell_map.items.len) {
|
||||
if (meta_i >= meta.cell_map.map.items.len) {
|
||||
// This meta doesn't contain the match. This means we
|
||||
// can also prune this set of data because we only look
|
||||
// forward.
|
||||
offset.* += meta.cell_map.items.len;
|
||||
offset.* += meta.cell_map.map.items.len;
|
||||
continue;
|
||||
}
|
||||
|
||||
// We found the meta that contains the start of the match.
|
||||
const map = meta.cell_map.items[meta_i];
|
||||
const map = meta.cell_map.map.items[meta_i];
|
||||
return .{
|
||||
.node = meta.node,
|
||||
.y = map.y,
|
||||
|
|
@ -411,13 +423,15 @@ const SlidingWindow = struct {
|
|||
/// via a search (via next()).
|
||||
pub fn append(
|
||||
self: *SlidingWindow,
|
||||
alloc: Allocator,
|
||||
node: *PageList.List.Node,
|
||||
) Allocator.Error!void {
|
||||
// Initialize our metadata for the node.
|
||||
var meta: Meta = .{
|
||||
.node = node,
|
||||
.cell_map = .init(alloc),
|
||||
.cell_map = .{
|
||||
.alloc = self.alloc,
|
||||
.map = .empty,
|
||||
},
|
||||
};
|
||||
errdefer meta.deinit();
|
||||
|
||||
|
|
@ -425,27 +439,27 @@ const SlidingWindow = struct {
|
|||
// temporary memory, and then copy it into our circular buffer.
|
||||
// In the future, we should benchmark and see if we can encode
|
||||
// directly into the circular buffer.
|
||||
var encoded: std.ArrayListUnmanaged(u8) = .{};
|
||||
defer encoded.deinit(alloc);
|
||||
var encoded: std.Io.Writer.Allocating = .init(self.alloc);
|
||||
defer encoded.deinit();
|
||||
|
||||
// Encode the page into the buffer.
|
||||
const page: *const Page = &meta.node.data;
|
||||
_ = page.encodeUtf8(
|
||||
encoded.writer(alloc),
|
||||
&encoded.writer,
|
||||
.{ .cell_map = &meta.cell_map },
|
||||
) catch {
|
||||
// writer uses anyerror but the only realistic error on
|
||||
// an ArrayList is out of memory.
|
||||
return error.OutOfMemory;
|
||||
};
|
||||
assert(meta.cell_map.items.len == encoded.items.len);
|
||||
assert(meta.cell_map.map.items.len == encoded.written().len);
|
||||
|
||||
// Ensure our buffers are big enough to store what we need.
|
||||
try self.data.ensureUnusedCapacity(alloc, encoded.items.len);
|
||||
try self.meta.ensureUnusedCapacity(alloc, 1);
|
||||
try self.data.ensureUnusedCapacity(self.alloc, encoded.written().len);
|
||||
try self.meta.ensureUnusedCapacity(self.alloc, 1);
|
||||
|
||||
// Append our new node to the circular buffer.
|
||||
try self.data.appendSlice(encoded.items);
|
||||
try self.data.appendSlice(encoded.written());
|
||||
try self.meta.append(meta);
|
||||
|
||||
self.assertIntegrity();
|
||||
|
|
@ -462,7 +476,7 @@ const SlidingWindow = struct {
|
|||
// Integrity check: verify our data matches our metadata exactly.
|
||||
var meta_it = self.meta.iterator(.forward);
|
||||
var data_len: usize = 0;
|
||||
while (meta_it.next()) |m| data_len += m.cell_map.items.len;
|
||||
while (meta_it.next()) |m| data_len += m.cell_map.map.items.len;
|
||||
assert(data_len == self.data.len());
|
||||
|
||||
// Integrity check: verify our data offset is within bounds.
|
||||
|
|
@ -480,11 +494,11 @@ test "PageListSearch single page" {
|
|||
try testing.expect(s.pages.pages.first == s.pages.pages.last);
|
||||
|
||||
var search = try PageListSearch.init(alloc, &s.pages, "boo!");
|
||||
defer search.deinit(alloc);
|
||||
defer search.deinit();
|
||||
|
||||
// We should be able to find two matches.
|
||||
{
|
||||
const sel = (try search.next(alloc)).?;
|
||||
const sel = (try search.next()).?;
|
||||
try testing.expectEqual(point.Point{ .active = .{
|
||||
.x = 7,
|
||||
.y = 0,
|
||||
|
|
@ -495,7 +509,7 @@ test "PageListSearch single page" {
|
|||
} }, s.pages.pointFromPin(.active, sel.end()).?);
|
||||
}
|
||||
{
|
||||
const sel = (try search.next(alloc)).?;
|
||||
const sel = (try search.next()).?;
|
||||
try testing.expectEqual(point.Point{ .active = .{
|
||||
.x = 19,
|
||||
.y = 0,
|
||||
|
|
@ -505,8 +519,8 @@ test "PageListSearch single page" {
|
|||
.y = 0,
|
||||
} }, s.pages.pointFromPin(.active, sel.end()).?);
|
||||
}
|
||||
try testing.expect((try search.next(alloc)) == null);
|
||||
try testing.expect((try search.next(alloc)) == null);
|
||||
try testing.expect((try search.next()) == null);
|
||||
try testing.expect((try search.next()) == null);
|
||||
}
|
||||
|
||||
test "SlidingWindow empty on init" {
|
||||
|
|
@ -514,7 +528,7 @@ test "SlidingWindow empty on init" {
|
|||
const alloc = testing.allocator;
|
||||
|
||||
var w = try SlidingWindow.init(alloc, "boo!");
|
||||
defer w.deinit(alloc);
|
||||
defer w.deinit();
|
||||
try testing.expectEqual(0, w.data.len());
|
||||
try testing.expectEqual(0, w.meta.len());
|
||||
}
|
||||
|
|
@ -524,7 +538,7 @@ test "SlidingWindow single append" {
|
|||
const alloc = testing.allocator;
|
||||
|
||||
var w = try SlidingWindow.init(alloc, "boo!");
|
||||
defer w.deinit(alloc);
|
||||
defer w.deinit();
|
||||
|
||||
var s = try Screen.init(alloc, 80, 24, 0);
|
||||
defer s.deinit();
|
||||
|
|
@ -533,7 +547,7 @@ test "SlidingWindow single append" {
|
|||
// We want to test single-page cases.
|
||||
try testing.expect(s.pages.pages.first == s.pages.pages.last);
|
||||
const node: *PageList.List.Node = s.pages.pages.first.?;
|
||||
try w.append(alloc, node);
|
||||
try w.append(node);
|
||||
|
||||
// We should be able to find two matches.
|
||||
{
|
||||
|
|
@ -567,7 +581,7 @@ test "SlidingWindow single append no match" {
|
|||
const alloc = testing.allocator;
|
||||
|
||||
var w = try SlidingWindow.init(alloc, "nope!");
|
||||
defer w.deinit(alloc);
|
||||
defer w.deinit();
|
||||
|
||||
var s = try Screen.init(alloc, 80, 24, 0);
|
||||
defer s.deinit();
|
||||
|
|
@ -576,7 +590,7 @@ test "SlidingWindow single append no match" {
|
|||
// We want to test single-page cases.
|
||||
try testing.expect(s.pages.pages.first == s.pages.pages.last);
|
||||
const node: *PageList.List.Node = s.pages.pages.first.?;
|
||||
try w.append(alloc, node);
|
||||
try w.append(node);
|
||||
|
||||
// No matches
|
||||
try testing.expect(w.next() == null);
|
||||
|
|
@ -591,7 +605,7 @@ test "SlidingWindow two pages" {
|
|||
const alloc = testing.allocator;
|
||||
|
||||
var w = try SlidingWindow.init(alloc, "boo!");
|
||||
defer w.deinit(alloc);
|
||||
defer w.deinit();
|
||||
|
||||
var s = try Screen.init(alloc, 80, 24, 1000);
|
||||
defer s.deinit();
|
||||
|
|
@ -609,8 +623,8 @@ test "SlidingWindow two pages" {
|
|||
|
||||
// Add both pages
|
||||
const node: *PageList.List.Node = s.pages.pages.first.?;
|
||||
try w.append(alloc, node);
|
||||
try w.append(alloc, node.next.?);
|
||||
try w.append(node);
|
||||
try w.append(node.next.?);
|
||||
|
||||
// Search should find two matches
|
||||
{
|
||||
|
|
@ -644,7 +658,7 @@ test "SlidingWindow two pages match across boundary" {
|
|||
const alloc = testing.allocator;
|
||||
|
||||
var w = try SlidingWindow.init(alloc, "hello, world");
|
||||
defer w.deinit(alloc);
|
||||
defer w.deinit();
|
||||
|
||||
var s = try Screen.init(alloc, 80, 24, 1000);
|
||||
defer s.deinit();
|
||||
|
|
@ -661,8 +675,8 @@ test "SlidingWindow two pages match across boundary" {
|
|||
|
||||
// Add both pages
|
||||
const node: *PageList.List.Node = s.pages.pages.first.?;
|
||||
try w.append(alloc, node);
|
||||
try w.append(alloc, node.next.?);
|
||||
try w.append(node);
|
||||
try w.append(node.next.?);
|
||||
|
||||
// Search should find a match
|
||||
{
|
||||
|
|
@ -688,7 +702,7 @@ test "SlidingWindow two pages no match prunes first page" {
|
|||
const alloc = testing.allocator;
|
||||
|
||||
var w = try SlidingWindow.init(alloc, "nope!");
|
||||
defer w.deinit(alloc);
|
||||
defer w.deinit();
|
||||
|
||||
var s = try Screen.init(alloc, 80, 24, 1000);
|
||||
defer s.deinit();
|
||||
|
|
@ -706,8 +720,8 @@ test "SlidingWindow two pages no match prunes first page" {
|
|||
|
||||
// Add both pages
|
||||
const node: *PageList.List.Node = s.pages.pages.first.?;
|
||||
try w.append(alloc, node);
|
||||
try w.append(alloc, node.next.?);
|
||||
try w.append(node);
|
||||
try w.append(node.next.?);
|
||||
|
||||
// Search should find nothing
|
||||
try testing.expect(w.next() == null);
|
||||
|
|
@ -737,18 +751,18 @@ test "SlidingWindow two pages no match keeps both pages" {
|
|||
try s.testWriteString("hello. boo!");
|
||||
|
||||
// Imaginary needle for search. Doesn't match!
|
||||
var needle_list = std.ArrayList(u8).init(alloc);
|
||||
defer needle_list.deinit();
|
||||
try needle_list.appendNTimes('x', first_page_rows * s.pages.cols);
|
||||
var needle_list: std.ArrayList(u8) = .empty;
|
||||
defer needle_list.deinit(alloc);
|
||||
try needle_list.appendNTimes(alloc, 'x', first_page_rows * s.pages.cols);
|
||||
const needle: []const u8 = needle_list.items;
|
||||
|
||||
var w = try SlidingWindow.init(alloc, needle);
|
||||
defer w.deinit(alloc);
|
||||
defer w.deinit();
|
||||
|
||||
// Add both pages
|
||||
const node: *PageList.List.Node = s.pages.pages.first.?;
|
||||
try w.append(alloc, node);
|
||||
try w.append(alloc, node.next.?);
|
||||
try w.append(node);
|
||||
try w.append(node.next.?);
|
||||
|
||||
// Search should find nothing
|
||||
try testing.expect(w.next() == null);
|
||||
|
|
@ -763,7 +777,7 @@ test "SlidingWindow single append across circular buffer boundary" {
|
|||
const alloc = testing.allocator;
|
||||
|
||||
var w = try SlidingWindow.init(alloc, "abc");
|
||||
defer w.deinit(alloc);
|
||||
defer w.deinit();
|
||||
|
||||
var s = try Screen.init(alloc, 80, 24, 0);
|
||||
defer s.deinit();
|
||||
|
|
@ -776,8 +790,8 @@ test "SlidingWindow single append across circular buffer boundary" {
|
|||
// our implementation changes our test will fail.
|
||||
try testing.expect(s.pages.pages.first == s.pages.pages.last);
|
||||
const node: *PageList.List.Node = s.pages.pages.first.?;
|
||||
try w.append(alloc, node);
|
||||
try w.append(alloc, node);
|
||||
try w.append(node);
|
||||
try w.append(node);
|
||||
{
|
||||
// No wrap around yet
|
||||
const slices = w.data.getPtrSlice(0, w.data.len());
|
||||
|
|
@ -793,7 +807,7 @@ test "SlidingWindow single append across circular buffer boundary" {
|
|||
w.needle = "boo";
|
||||
|
||||
// Add new page, now wraps
|
||||
try w.append(alloc, node);
|
||||
try w.append(node);
|
||||
{
|
||||
const slices = w.data.getPtrSlice(0, w.data.len());
|
||||
try testing.expect(slices[0].len > 0);
|
||||
|
|
@ -818,7 +832,7 @@ test "SlidingWindow single append match on boundary" {
|
|||
const alloc = testing.allocator;
|
||||
|
||||
var w = try SlidingWindow.init(alloc, "abcd");
|
||||
defer w.deinit(alloc);
|
||||
defer w.deinit();
|
||||
|
||||
var s = try Screen.init(alloc, 80, 24, 0);
|
||||
defer s.deinit();
|
||||
|
|
@ -831,8 +845,8 @@ test "SlidingWindow single append match on boundary" {
|
|||
// our implementation changes our test will fail.
|
||||
try testing.expect(s.pages.pages.first == s.pages.pages.last);
|
||||
const node: *PageList.List.Node = s.pages.pages.first.?;
|
||||
try w.append(alloc, node);
|
||||
try w.append(alloc, node);
|
||||
try w.append(node);
|
||||
try w.append(node);
|
||||
{
|
||||
// No wrap around yet
|
||||
const slices = w.data.getPtrSlice(0, w.data.len());
|
||||
|
|
@ -848,7 +862,7 @@ test "SlidingWindow single append match on boundary" {
|
|||
w.needle = "boo!";
|
||||
|
||||
// Add new page, now wraps
|
||||
try w.append(alloc, node);
|
||||
try w.append(node);
|
||||
{
|
||||
const slices = w.data.getPtrSlice(0, w.data.len());
|
||||
try testing.expect(slices[0].len > 0);
|
||||
|
|
|
|||
|
|
@ -288,13 +288,13 @@ pub fn Stream(comptime Handler: type) type {
|
|||
|
||||
for (actions) |action_opt| {
|
||||
const action = action_opt orelse continue;
|
||||
if (comptime debug) log.info("action: {}", .{action});
|
||||
if (comptime debug) log.info("action: {f}", .{action});
|
||||
|
||||
// If this handler handles everything manually then we do nothing
|
||||
// if it can be processed.
|
||||
if (@hasDecl(T, "handleManually")) {
|
||||
const processed = self.handler.handleManually(action) catch |err| err: {
|
||||
log.warn("error handling action manually err={} action={}", .{
|
||||
log.warn("error handling action manually err={} action={f}", .{
|
||||
err,
|
||||
action,
|
||||
});
|
||||
|
|
@ -341,7 +341,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||
|
||||
pub inline fn execute(self: *Self, c: u8) !void {
|
||||
const c0: ansi.C0 = @enumFromInt(c);
|
||||
if (comptime debug) log.info("execute: {}", .{c0});
|
||||
if (comptime debug) log.info("execute: {f}", .{c0});
|
||||
switch (c0) {
|
||||
// We ignore SOH/STX: https://github.com/microsoft/terminal/issues/10786
|
||||
.NUL, .SOH, .STX => {},
|
||||
|
|
@ -399,12 +399,12 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => 1,
|
||||
1 => input.params[0],
|
||||
else => {
|
||||
log.warn("invalid cursor up command: {}", .{input});
|
||||
log.warn("invalid cursor up command: {f}", .{input});
|
||||
return;
|
||||
},
|
||||
},
|
||||
false,
|
||||
) else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
) else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI A with intermediates: {s}",
|
||||
|
|
@ -419,12 +419,12 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => 1,
|
||||
1 => input.params[0],
|
||||
else => {
|
||||
log.warn("invalid cursor down command: {}", .{input});
|
||||
log.warn("invalid cursor down command: {f}", .{input});
|
||||
return;
|
||||
},
|
||||
},
|
||||
false,
|
||||
) else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
) else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI B with intermediates: {s}",
|
||||
|
|
@ -439,11 +439,11 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => 1,
|
||||
1 => input.params[0],
|
||||
else => {
|
||||
log.warn("invalid cursor right command: {}", .{input});
|
||||
log.warn("invalid cursor right command: {f}", .{input});
|
||||
return;
|
||||
},
|
||||
},
|
||||
) else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
) else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI C with intermediates: {s}",
|
||||
|
|
@ -458,11 +458,11 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => 1,
|
||||
1 => input.params[0],
|
||||
else => {
|
||||
log.warn("invalid cursor left command: {}", .{input});
|
||||
log.warn("invalid cursor left command: {f}", .{input});
|
||||
return;
|
||||
},
|
||||
},
|
||||
) else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
) else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI D with intermediates: {s}",
|
||||
|
|
@ -477,12 +477,12 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => 1,
|
||||
1 => input.params[0],
|
||||
else => {
|
||||
log.warn("invalid cursor up command: {}", .{input});
|
||||
log.warn("invalid cursor up command: {f}", .{input});
|
||||
return;
|
||||
},
|
||||
},
|
||||
true,
|
||||
) else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
) else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI E with intermediates: {s}",
|
||||
|
|
@ -497,12 +497,12 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => 1,
|
||||
1 => input.params[0],
|
||||
else => {
|
||||
log.warn("invalid cursor down command: {}", .{input});
|
||||
log.warn("invalid cursor down command: {f}", .{input});
|
||||
return;
|
||||
},
|
||||
},
|
||||
true,
|
||||
) else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
) else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI F with intermediates: {s}",
|
||||
|
|
@ -516,8 +516,8 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => if (@hasDecl(T, "setCursorCol")) switch (input.params.len) {
|
||||
0 => try self.handler.setCursorCol(1),
|
||||
1 => try self.handler.setCursorCol(input.params[0]),
|
||||
else => log.warn("invalid HPA command: {}", .{input}),
|
||||
} else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
else => log.warn("invalid HPA command: {f}", .{input}),
|
||||
} else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI G with intermediates: {s}",
|
||||
|
|
@ -532,8 +532,8 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => try self.handler.setCursorPos(1, 1),
|
||||
1 => try self.handler.setCursorPos(input.params[0], 1),
|
||||
2 => try self.handler.setCursorPos(input.params[0], input.params[1]),
|
||||
else => log.warn("invalid CUP command: {}", .{input}),
|
||||
} else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
else => log.warn("invalid CUP command: {f}", .{input}),
|
||||
} else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI H with intermediates: {s}",
|
||||
|
|
@ -548,11 +548,11 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => 1,
|
||||
1 => input.params[0],
|
||||
else => {
|
||||
log.warn("invalid horizontal tab command: {}", .{input});
|
||||
log.warn("invalid horizontal tab command: {f}", .{input});
|
||||
return;
|
||||
},
|
||||
},
|
||||
) else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
) else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI I with intermediates: {s}",
|
||||
|
|
@ -569,7 +569,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||
};
|
||||
|
||||
const protected = protected_ orelse {
|
||||
log.warn("invalid erase display command: {}", .{input});
|
||||
log.warn("invalid erase display command: {f}", .{input});
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
@ -580,12 +580,12 @@ pub fn Stream(comptime Handler: type) type {
|
|||
};
|
||||
|
||||
const mode = mode_ orelse {
|
||||
log.warn("invalid erase display command: {}", .{input});
|
||||
log.warn("invalid erase display command: {f}", .{input});
|
||||
return;
|
||||
};
|
||||
|
||||
try self.handler.eraseDisplay(mode, protected);
|
||||
} else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
} else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
// Erase Line
|
||||
'K' => if (@hasDecl(T, "eraseLine")) {
|
||||
|
|
@ -596,7 +596,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||
};
|
||||
|
||||
const protected = protected_ orelse {
|
||||
log.warn("invalid erase line command: {}", .{input});
|
||||
log.warn("invalid erase line command: {f}", .{input});
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
@ -607,12 +607,12 @@ pub fn Stream(comptime Handler: type) type {
|
|||
};
|
||||
|
||||
const mode = mode_ orelse {
|
||||
log.warn("invalid erase line command: {}", .{input});
|
||||
log.warn("invalid erase line command: {f}", .{input});
|
||||
return;
|
||||
};
|
||||
|
||||
try self.handler.eraseLine(mode, protected);
|
||||
} else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
} else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
// IL - Insert Lines
|
||||
// TODO: test
|
||||
|
|
@ -620,8 +620,8 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => if (@hasDecl(T, "insertLines")) switch (input.params.len) {
|
||||
0 => try self.handler.insertLines(1),
|
||||
1 => try self.handler.insertLines(input.params[0]),
|
||||
else => log.warn("invalid IL command: {}", .{input}),
|
||||
} else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
else => log.warn("invalid IL command: {f}", .{input}),
|
||||
} else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI L with intermediates: {s}",
|
||||
|
|
@ -635,8 +635,8 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => if (@hasDecl(T, "deleteLines")) switch (input.params.len) {
|
||||
0 => try self.handler.deleteLines(1),
|
||||
1 => try self.handler.deleteLines(input.params[0]),
|
||||
else => log.warn("invalid DL command: {}", .{input}),
|
||||
} else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
else => log.warn("invalid DL command: {f}", .{input}),
|
||||
} else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI M with intermediates: {s}",
|
||||
|
|
@ -651,11 +651,11 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => 1,
|
||||
1 => input.params[0],
|
||||
else => {
|
||||
log.warn("invalid delete characters command: {}", .{input});
|
||||
log.warn("invalid delete characters command: {f}", .{input});
|
||||
return;
|
||||
},
|
||||
},
|
||||
) else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
) else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI P with intermediates: {s}",
|
||||
|
|
@ -671,11 +671,11 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => 1,
|
||||
1 => input.params[0],
|
||||
else => {
|
||||
log.warn("invalid scroll up command: {}", .{input});
|
||||
log.warn("invalid scroll up command: {f}", .{input});
|
||||
return;
|
||||
},
|
||||
},
|
||||
) else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
) else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI S with intermediates: {s}",
|
||||
|
|
@ -690,11 +690,11 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => 1,
|
||||
1 => input.params[0],
|
||||
else => {
|
||||
log.warn("invalid scroll down command: {}", .{input});
|
||||
log.warn("invalid scroll down command: {f}", .{input});
|
||||
return;
|
||||
},
|
||||
},
|
||||
) else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
) else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI T with intermediates: {s}",
|
||||
|
|
@ -711,7 +711,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||
if (@hasDecl(T, "tabSet"))
|
||||
try self.handler.tabSet()
|
||||
else
|
||||
log.warn("unimplemented tab set callback: {}", .{input});
|
||||
log.warn("unimplemented tab set callback: {f}", .{input});
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -725,12 +725,12 @@ pub fn Stream(comptime Handler: type) type {
|
|||
2 => if (@hasDecl(T, "tabClear"))
|
||||
try self.handler.tabClear(.current)
|
||||
else
|
||||
log.warn("unimplemented tab clear callback: {}", .{input}),
|
||||
log.warn("unimplemented tab clear callback: {f}", .{input}),
|
||||
|
||||
5 => if (@hasDecl(T, "tabClear"))
|
||||
try self.handler.tabClear(.all)
|
||||
else
|
||||
log.warn("unimplemented tab clear callback: {}", .{input}),
|
||||
log.warn("unimplemented tab clear callback: {f}", .{input}),
|
||||
|
||||
else => {},
|
||||
},
|
||||
|
|
@ -738,7 +738,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||
else => {},
|
||||
}
|
||||
|
||||
log.warn("invalid cursor tabulation control: {}", .{input});
|
||||
log.warn("invalid cursor tabulation control: {f}", .{input});
|
||||
return;
|
||||
},
|
||||
|
||||
|
|
@ -746,8 +746,8 @@ pub fn Stream(comptime Handler: type) type {
|
|||
if (@hasDecl(T, "tabReset"))
|
||||
try self.handler.tabReset()
|
||||
else
|
||||
log.warn("unimplemented tab reset callback: {}", .{input});
|
||||
} else log.warn("invalid cursor tabulation control: {}", .{input}),
|
||||
log.warn("unimplemented tab reset callback: {f}", .{input});
|
||||
} else log.warn("invalid cursor tabulation control: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI W with intermediates: {s}",
|
||||
|
|
@ -762,11 +762,11 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => 1,
|
||||
1 => input.params[0],
|
||||
else => {
|
||||
log.warn("invalid erase characters command: {}", .{input});
|
||||
log.warn("invalid erase characters command: {f}", .{input});
|
||||
return;
|
||||
},
|
||||
},
|
||||
) else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
) else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI X with intermediates: {s}",
|
||||
|
|
@ -781,11 +781,11 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => 1,
|
||||
1 => input.params[0],
|
||||
else => {
|
||||
log.warn("invalid horizontal tab back command: {}", .{input});
|
||||
log.warn("invalid horizontal tab back command: {f}", .{input});
|
||||
return;
|
||||
},
|
||||
},
|
||||
) else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
) else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI Z with intermediates: {s}",
|
||||
|
|
@ -800,11 +800,11 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => 1,
|
||||
1 => input.params[0],
|
||||
else => {
|
||||
log.warn("invalid HPR command: {}", .{input});
|
||||
log.warn("invalid HPR command: {f}", .{input});
|
||||
return;
|
||||
},
|
||||
},
|
||||
) else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
) else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI a with intermediates: {s}",
|
||||
|
|
@ -819,11 +819,11 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => 1,
|
||||
1 => input.params[0],
|
||||
else => {
|
||||
log.warn("invalid print repeat command: {}", .{input});
|
||||
log.warn("invalid print repeat command: {f}", .{input});
|
||||
return;
|
||||
},
|
||||
},
|
||||
) else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
) else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI b with intermediates: {s}",
|
||||
|
|
@ -842,12 +842,12 @@ pub fn Stream(comptime Handler: type) type {
|
|||
},
|
||||
else => @as(?ansi.DeviceAttributeReq, null),
|
||||
} orelse {
|
||||
log.warn("invalid device attributes command: {}", .{input});
|
||||
log.warn("invalid device attributes command: {f}", .{input});
|
||||
return;
|
||||
};
|
||||
|
||||
try self.handler.deviceAttributes(req, input.params);
|
||||
} else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
} else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
// VPA - Cursor Vertical Position Absolute
|
||||
'd' => switch (input.intermediates.len) {
|
||||
|
|
@ -856,11 +856,11 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => 1,
|
||||
1 => input.params[0],
|
||||
else => {
|
||||
log.warn("invalid VPA command: {}", .{input});
|
||||
log.warn("invalid VPA command: {f}", .{input});
|
||||
return;
|
||||
},
|
||||
},
|
||||
) else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
) else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI d with intermediates: {s}",
|
||||
|
|
@ -875,11 +875,11 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => 1,
|
||||
1 => input.params[0],
|
||||
else => {
|
||||
log.warn("invalid VPR command: {}", .{input});
|
||||
log.warn("invalid VPR command: {f}", .{input});
|
||||
return;
|
||||
},
|
||||
},
|
||||
) else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
) else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI e with intermediates: {s}",
|
||||
|
|
@ -894,11 +894,11 @@ pub fn Stream(comptime Handler: type) type {
|
|||
switch (input.params.len) {
|
||||
1 => @enumFromInt(input.params[0]),
|
||||
else => {
|
||||
log.warn("invalid tab clear command: {}", .{input});
|
||||
log.warn("invalid tab clear command: {f}", .{input});
|
||||
return;
|
||||
},
|
||||
},
|
||||
) else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
) else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI g with intermediates: {s}",
|
||||
|
|
@ -913,7 +913,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||
if (input.intermediates.len == 1 and
|
||||
input.intermediates[0] == '?') break :ansi false;
|
||||
|
||||
log.warn("invalid set mode command: {}", .{input});
|
||||
log.warn("invalid set mode command: {f}", .{input});
|
||||
break :mode;
|
||||
};
|
||||
|
||||
|
|
@ -924,7 +924,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||
log.warn("unimplemented mode: {}", .{mode_int});
|
||||
}
|
||||
}
|
||||
} else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
} else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
// RM - Reset Mode
|
||||
'l' => if (@hasDecl(T, "setMode")) mode: {
|
||||
|
|
@ -933,7 +933,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||
if (input.intermediates.len == 1 and
|
||||
input.intermediates[0] == '?') break :ansi false;
|
||||
|
||||
log.warn("invalid set mode command: {}", .{input});
|
||||
log.warn("invalid set mode command: {f}", .{input});
|
||||
break :mode;
|
||||
};
|
||||
|
||||
|
|
@ -944,7 +944,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||
log.warn("unimplemented mode: {}", .{mode_int});
|
||||
}
|
||||
}
|
||||
} else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
} else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
// SGR - Select Graphic Rendition
|
||||
'm' => switch (input.intermediates.len) {
|
||||
|
|
@ -958,7 +958,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||
// log.info("SGR attribute: {}", .{attr});
|
||||
try self.handler.setAttribute(attr);
|
||||
}
|
||||
} else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
} else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
1 => switch (input.intermediates[0]) {
|
||||
'>' => if (@hasDecl(T, "setModifyKeyFormat")) blk: {
|
||||
|
|
@ -974,13 +974,13 @@ pub fn Stream(comptime Handler: type) type {
|
|||
2 => .{ .function_keys = {} },
|
||||
4 => .{ .other_keys = .none },
|
||||
else => {
|
||||
log.warn("invalid setModifyKeyFormat: {}", .{input});
|
||||
log.warn("invalid setModifyKeyFormat: {f}", .{input});
|
||||
break :blk;
|
||||
},
|
||||
};
|
||||
|
||||
if (input.params.len > 2) {
|
||||
log.warn("invalid setModifyKeyFormat: {}", .{input});
|
||||
log.warn("invalid setModifyKeyFormat: {f}", .{input});
|
||||
break :blk;
|
||||
}
|
||||
|
||||
|
|
@ -1000,7 +1000,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||
}
|
||||
|
||||
try self.handler.setModifyKeyFormat(format);
|
||||
} else log.warn("unimplemented setModifyKeyFormat: {}", .{input}),
|
||||
} else log.warn("unimplemented setModifyKeyFormat: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"unknown CSI m with intermediate: {}",
|
||||
|
|
@ -1029,12 +1029,12 @@ pub fn Stream(comptime Handler: type) type {
|
|||
input.intermediates[0] == '?')
|
||||
{
|
||||
if (!@hasDecl(T, "deviceStatusReport")) {
|
||||
log.warn("unimplemented CSI callback: {}", .{input});
|
||||
log.warn("unimplemented CSI callback: {f}", .{input});
|
||||
return;
|
||||
}
|
||||
|
||||
if (input.params.len != 1) {
|
||||
log.warn("invalid device status report command: {}", .{input});
|
||||
log.warn("invalid device status report command: {f}", .{input});
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1043,12 +1043,12 @@ pub fn Stream(comptime Handler: type) type {
|
|||
if (input.intermediates.len == 1 and
|
||||
input.intermediates[0] == '?') break :question true;
|
||||
|
||||
log.warn("invalid set mode command: {}", .{input});
|
||||
log.warn("invalid set mode command: {f}", .{input});
|
||||
return;
|
||||
};
|
||||
|
||||
const req = device_status.reqFromInt(input.params[0], question) orelse {
|
||||
log.warn("invalid device status report command: {}", .{input});
|
||||
log.warn("invalid device status report command: {f}", .{input});
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
@ -1067,7 +1067,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||
// only support reverting back to modify other keys in
|
||||
// numeric except format.
|
||||
try self.handler.setModifyKeyFormat(.{ .other_keys = .numeric_except });
|
||||
} else log.warn("unimplemented setModifyKeyFormat: {}", .{input}),
|
||||
} else log.warn("unimplemented setModifyKeyFormat: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"unknown CSI n with intermediate: {}",
|
||||
|
|
@ -1101,13 +1101,13 @@ pub fn Stream(comptime Handler: type) type {
|
|||
};
|
||||
|
||||
if (input.params.len != 1) {
|
||||
log.warn("invalid DECRQM command: {}", .{input});
|
||||
log.warn("invalid DECRQM command: {f}", .{input});
|
||||
break :decrqm;
|
||||
}
|
||||
|
||||
if (@hasDecl(T, "requestMode")) {
|
||||
try self.handler.requestMode(input.params[0], ansi_mode);
|
||||
} else log.warn("unimplemented DECRQM callback: {}", .{input});
|
||||
} else log.warn("unimplemented DECRQM callback: {f}", .{input});
|
||||
},
|
||||
|
||||
else => log.warn(
|
||||
|
|
@ -1126,11 +1126,11 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => ansi.CursorStyle.default,
|
||||
1 => @enumFromInt(input.params[0]),
|
||||
else => {
|
||||
log.warn("invalid set curor style command: {}", .{input});
|
||||
log.warn("invalid set curor style command: {f}", .{input});
|
||||
return;
|
||||
},
|
||||
},
|
||||
) else log.warn("unimplemented CSI callback: {}", .{input});
|
||||
) else log.warn("unimplemented CSI callback: {f}", .{input});
|
||||
},
|
||||
|
||||
// DECSCA
|
||||
|
|
@ -1147,12 +1147,12 @@ pub fn Stream(comptime Handler: type) type {
|
|||
};
|
||||
|
||||
const mode = mode_ orelse {
|
||||
log.warn("invalid set protected mode command: {}", .{input});
|
||||
log.warn("invalid set protected mode command: {f}", .{input});
|
||||
return;
|
||||
};
|
||||
|
||||
try self.handler.setProtectedMode(mode);
|
||||
} else log.warn("unimplemented CSI callback: {}", .{input});
|
||||
} else log.warn("unimplemented CSI callback: {f}", .{input});
|
||||
},
|
||||
|
||||
// XTVERSION
|
||||
|
|
@ -1180,10 +1180,10 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => try self.handler.setTopAndBottomMargin(0, 0),
|
||||
1 => try self.handler.setTopAndBottomMargin(input.params[0], 0),
|
||||
2 => try self.handler.setTopAndBottomMargin(input.params[0], input.params[1]),
|
||||
else => log.warn("invalid DECSTBM command: {}", .{input}),
|
||||
else => log.warn("invalid DECSTBM command: {f}", .{input}),
|
||||
}
|
||||
} else log.warn(
|
||||
"unimplemented CSI callback: {}",
|
||||
"unimplemented CSI callback: {f}",
|
||||
.{input},
|
||||
),
|
||||
|
||||
|
|
@ -1203,13 +1203,13 @@ pub fn Stream(comptime Handler: type) type {
|
|||
},
|
||||
|
||||
else => log.warn(
|
||||
"unknown CSI s with intermediate: {}",
|
||||
"unknown CSI s with intermediate: {f}",
|
||||
.{input},
|
||||
),
|
||||
},
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI s with intermediates: {s}",
|
||||
"ignoring unimplemented CSI s with intermediates: {f}",
|
||||
.{input},
|
||||
),
|
||||
},
|
||||
|
|
@ -1225,10 +1225,10 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => try self.handler.setLeftAndRightMarginAmbiguous(),
|
||||
1 => try self.handler.setLeftAndRightMargin(input.params[0], 0),
|
||||
2 => try self.handler.setLeftAndRightMargin(input.params[0], input.params[1]),
|
||||
else => log.warn("invalid DECSLRM command: {}", .{input}),
|
||||
else => log.warn("invalid DECSLRM command: {f}", .{input}),
|
||||
}
|
||||
} else log.warn(
|
||||
"unimplemented CSI callback: {}",
|
||||
"unimplemented CSI callback: {f}",
|
||||
.{input},
|
||||
),
|
||||
|
||||
|
|
@ -1254,30 +1254,30 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => false,
|
||||
1 => true,
|
||||
else => {
|
||||
log.warn("invalid XTSHIFTESCAPE command: {}", .{input});
|
||||
log.warn("invalid XTSHIFTESCAPE command: {f}", .{input});
|
||||
break :capture;
|
||||
},
|
||||
},
|
||||
else => {
|
||||
log.warn("invalid XTSHIFTESCAPE command: {}", .{input});
|
||||
log.warn("invalid XTSHIFTESCAPE command: {f}", .{input});
|
||||
break :capture;
|
||||
},
|
||||
};
|
||||
|
||||
try self.handler.setMouseShiftCapture(capture);
|
||||
} else log.warn(
|
||||
"unimplemented CSI callback: {}",
|
||||
"unimplemented CSI callback: {f}",
|
||||
.{input},
|
||||
),
|
||||
|
||||
else => log.warn(
|
||||
"unknown CSI s with intermediate: {}",
|
||||
"unknown CSI s with intermediate: {f}",
|
||||
.{input},
|
||||
),
|
||||
},
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI s with intermediates: {s}",
|
||||
"ignoring unimplemented CSI s with intermediates: {f}",
|
||||
.{input},
|
||||
),
|
||||
},
|
||||
|
|
@ -1296,7 +1296,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||
.{},
|
||||
);
|
||||
} else log.warn(
|
||||
"ignoring CSI 14 t with extra parameters: {}",
|
||||
"ignoring CSI 14 t with extra parameters: {f}",
|
||||
.{input},
|
||||
),
|
||||
16 => if (input.params.len == 1) {
|
||||
|
|
@ -1308,7 +1308,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||
.{},
|
||||
);
|
||||
} else log.warn(
|
||||
"ignoring CSI 16 t with extra parameters: {s}",
|
||||
"ignoring CSI 16 t with extra parameters: {f}",
|
||||
.{input},
|
||||
),
|
||||
18 => if (input.params.len == 1) {
|
||||
|
|
@ -1320,7 +1320,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||
.{},
|
||||
);
|
||||
} else log.warn(
|
||||
"ignoring CSI 18 t with extra parameters: {s}",
|
||||
"ignoring CSI 18 t with extra parameters: {f}",
|
||||
.{input},
|
||||
),
|
||||
21 => if (input.params.len == 1) {
|
||||
|
|
@ -1332,7 +1332,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||
.{},
|
||||
);
|
||||
} else log.warn(
|
||||
"ignoring CSI 21 t with extra parameters: {s}",
|
||||
"ignoring CSI 21 t with extra parameters: {f}",
|
||||
.{input},
|
||||
),
|
||||
inline 22, 23 => |number| if ((input.params.len == 2 or
|
||||
|
|
@ -1359,21 +1359,21 @@ pub fn Stream(comptime Handler: type) type {
|
|||
.{},
|
||||
);
|
||||
} else log.warn(
|
||||
"ignoring CSI 22/23 t with extra parameters: {s}",
|
||||
"ignoring CSI 22/23 t with extra parameters: {f}",
|
||||
.{input},
|
||||
),
|
||||
else => log.warn(
|
||||
"ignoring CSI t with unimplemented parameter: {s}",
|
||||
"ignoring CSI t with unimplemented parameter: {f}",
|
||||
.{input},
|
||||
),
|
||||
}
|
||||
} else log.err(
|
||||
"ignoring CSI t with no parameters: {s}",
|
||||
"ignoring CSI t with no parameters: {f}",
|
||||
.{input},
|
||||
);
|
||||
},
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI t with intermediates: {s}",
|
||||
"ignoring unimplemented CSI t with intermediates: {f}",
|
||||
.{input},
|
||||
),
|
||||
},
|
||||
|
|
@ -1382,7 +1382,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => if (@hasDecl(T, "restoreCursor"))
|
||||
try self.handler.restoreCursor()
|
||||
else
|
||||
log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
// Kitty keyboard protocol
|
||||
1 => switch (input.intermediates[0]) {
|
||||
|
|
@ -1393,7 +1393,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||
'>' => if (@hasDecl(T, "pushKittyKeyboard")) push: {
|
||||
const flags: u5 = if (input.params.len == 1)
|
||||
std.math.cast(u5, input.params[0]) orelse {
|
||||
log.warn("invalid pushKittyKeyboard command: {}", .{input});
|
||||
log.warn("invalid pushKittyKeyboard command: {f}", .{input});
|
||||
break :push;
|
||||
}
|
||||
else
|
||||
|
|
@ -1414,7 +1414,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||
'=' => if (@hasDecl(T, "setKittyKeyboard")) set: {
|
||||
const flags: u5 = if (input.params.len >= 1)
|
||||
std.math.cast(u5, input.params[0]) orelse {
|
||||
log.warn("invalid setKittyKeyboard command: {}", .{input});
|
||||
log.warn("invalid setKittyKeyboard command: {f}", .{input});
|
||||
break :set;
|
||||
}
|
||||
else
|
||||
|
|
@ -1430,7 +1430,7 @@ pub fn Stream(comptime Handler: type) type {
|
|||
2 => .@"or",
|
||||
3 => .not,
|
||||
else => {
|
||||
log.warn("invalid setKittyKeyboard command: {}", .{input});
|
||||
log.warn("invalid setKittyKeyboard command: {f}", .{input});
|
||||
break :set;
|
||||
},
|
||||
};
|
||||
|
|
@ -1442,13 +1442,13 @@ pub fn Stream(comptime Handler: type) type {
|
|||
},
|
||||
|
||||
else => log.warn(
|
||||
"unknown CSI s with intermediate: {}",
|
||||
"unknown CSI s with intermediate: {f}",
|
||||
.{input},
|
||||
),
|
||||
},
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI u: {}",
|
||||
"ignoring unimplemented CSI u: {f}",
|
||||
.{input},
|
||||
),
|
||||
},
|
||||
|
|
@ -1458,11 +1458,11 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => if (@hasDecl(T, "insertBlanks")) switch (input.params.len) {
|
||||
0 => try self.handler.insertBlanks(1),
|
||||
1 => try self.handler.insertBlanks(input.params[0]),
|
||||
else => log.warn("invalid ICH command: {}", .{input}),
|
||||
} else log.warn("unimplemented CSI callback: {}", .{input}),
|
||||
else => log.warn("invalid ICH command: {f}", .{input}),
|
||||
} else log.warn("unimplemented CSI callback: {f}", .{input}),
|
||||
|
||||
else => log.warn(
|
||||
"ignoring unimplemented CSI @: {}",
|
||||
"ignoring unimplemented CSI @: {f}",
|
||||
.{input},
|
||||
),
|
||||
},
|
||||
|
|
@ -1487,13 +1487,13 @@ pub fn Stream(comptime Handler: type) type {
|
|||
break :decsasd true;
|
||||
};
|
||||
|
||||
if (!success) log.warn("unimplemented CSI callback: {}", .{input});
|
||||
if (!success) log.warn("unimplemented CSI callback: {f}", .{input});
|
||||
},
|
||||
|
||||
else => if (@hasDecl(T, "csiUnimplemented"))
|
||||
try self.handler.csiUnimplemented(input)
|
||||
else
|
||||
log.warn("unimplemented CSI action: {}", .{input}),
|
||||
log.warn("unimplemented CSI action: {f}", .{input}),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1690,10 +1690,10 @@ pub fn Stream(comptime Handler: type) type {
|
|||
'7' => if (@hasDecl(T, "saveCursor")) switch (action.intermediates.len) {
|
||||
0 => try self.handler.saveCursor(),
|
||||
else => {
|
||||
log.warn("invalid command: {}", .{action});
|
||||
log.warn("invalid command: {f}", .{action});
|
||||
return;
|
||||
},
|
||||
} else log.warn("unimplemented ESC callback: {}", .{action}),
|
||||
} else log.warn("unimplemented ESC callback: {f}", .{action}),
|
||||
|
||||
'8' => blk: {
|
||||
switch (action.intermediates.len) {
|
||||
|
|
@ -1701,14 +1701,14 @@ pub fn Stream(comptime Handler: type) type {
|
|||
0 => if (@hasDecl(T, "restoreCursor")) {
|
||||
try self.handler.restoreCursor();
|
||||
break :blk {};
|
||||
} else log.warn("unimplemented restore cursor callback: {}", .{action}),
|
||||
} else log.warn("unimplemented restore cursor callback: {f}", .{action}),
|
||||
|
||||
1 => switch (action.intermediates[0]) {
|
||||
// DECALN - Fill Screen with E
|
||||
'#' => if (@hasDecl(T, "decaln")) {
|
||||
try self.handler.decaln();
|
||||
break :blk {};
|
||||
} else log.warn("unimplemented ESC callback: {}", .{action}),
|
||||
} else log.warn("unimplemented ESC callback: {f}", .{action}),
|
||||
|
||||
else => {},
|
||||
},
|
||||
|
|
@ -1716,146 +1716,146 @@ pub fn Stream(comptime Handler: type) type {
|
|||
else => {}, // fall through
|
||||
}
|
||||
|
||||
log.warn("unimplemented ESC action: {}", .{action});
|
||||
log.warn("unimplemented ESC action: {f}", .{action});
|
||||
},
|
||||
|
||||
// IND - Index
|
||||
'D' => if (@hasDecl(T, "index")) switch (action.intermediates.len) {
|
||||
0 => try self.handler.index(),
|
||||
else => {
|
||||
log.warn("invalid index command: {}", .{action});
|
||||
log.warn("invalid index command: {f}", .{action});
|
||||
return;
|
||||
},
|
||||
} else log.warn("unimplemented ESC callback: {}", .{action}),
|
||||
} else log.warn("unimplemented ESC callback: {f}", .{action}),
|
||||
|
||||
// NEL - Next Line
|
||||
'E' => if (@hasDecl(T, "nextLine")) switch (action.intermediates.len) {
|
||||
0 => try self.handler.nextLine(),
|
||||
else => {
|
||||
log.warn("invalid next line command: {}", .{action});
|
||||
log.warn("invalid next line command: {f}", .{action});
|
||||
return;
|
||||
},
|
||||
} else log.warn("unimplemented ESC callback: {}", .{action}),
|
||||
} else log.warn("unimplemented ESC callback: {f}", .{action}),
|
||||
|
||||
// HTS - Horizontal Tab Set
|
||||
'H' => if (@hasDecl(T, "tabSet")) switch (action.intermediates.len) {
|
||||
0 => try self.handler.tabSet(),
|
||||
else => {
|
||||
log.warn("invalid tab set command: {}", .{action});
|
||||
log.warn("invalid tab set command: {f}", .{action});
|
||||
return;
|
||||
},
|
||||
} else log.warn("unimplemented tab set callback: {}", .{action}),
|
||||
} else log.warn("unimplemented tab set callback: {f}", .{action}),
|
||||
|
||||
// RI - Reverse Index
|
||||
'M' => if (@hasDecl(T, "reverseIndex")) switch (action.intermediates.len) {
|
||||
0 => try self.handler.reverseIndex(),
|
||||
else => {
|
||||
log.warn("invalid reverse index command: {}", .{action});
|
||||
log.warn("invalid reverse index command: {f}", .{action});
|
||||
return;
|
||||
},
|
||||
} else log.warn("unimplemented ESC callback: {}", .{action}),
|
||||
} else log.warn("unimplemented ESC callback: {f}", .{action}),
|
||||
|
||||
// SS2 - Single Shift 2
|
||||
'N' => if (@hasDecl(T, "invokeCharset")) switch (action.intermediates.len) {
|
||||
0 => try self.handler.invokeCharset(.GL, .G2, true),
|
||||
else => {
|
||||
log.warn("invalid single shift 2 command: {}", .{action});
|
||||
log.warn("invalid single shift 2 command: {f}", .{action});
|
||||
return;
|
||||
},
|
||||
} else log.warn("unimplemented invokeCharset: {}", .{action}),
|
||||
} else log.warn("unimplemented invokeCharset: {f}", .{action}),
|
||||
|
||||
// SS3 - Single Shift 3
|
||||
'O' => if (@hasDecl(T, "invokeCharset")) switch (action.intermediates.len) {
|
||||
0 => try self.handler.invokeCharset(.GL, .G3, true),
|
||||
else => {
|
||||
log.warn("invalid single shift 3 command: {}", .{action});
|
||||
log.warn("invalid single shift 3 command: {f}", .{action});
|
||||
return;
|
||||
},
|
||||
} else log.warn("unimplemented invokeCharset: {}", .{action}),
|
||||
} else log.warn("unimplemented invokeCharset: {f}", .{action}),
|
||||
|
||||
// SPA - Start of Guarded Area
|
||||
'V' => if (@hasDecl(T, "setProtectedMode") and action.intermediates.len == 0) {
|
||||
try self.handler.setProtectedMode(ansi.ProtectedMode.iso);
|
||||
} else log.warn("unimplemented ESC callback: {}", .{action}),
|
||||
} else log.warn("unimplemented ESC callback: {f}", .{action}),
|
||||
|
||||
// EPA - End of Guarded Area
|
||||
'W' => if (@hasDecl(T, "setProtectedMode") and action.intermediates.len == 0) {
|
||||
try self.handler.setProtectedMode(ansi.ProtectedMode.off);
|
||||
} else log.warn("unimplemented ESC callback: {}", .{action}),
|
||||
} else log.warn("unimplemented ESC callback: {f}", .{action}),
|
||||
|
||||
// DECID
|
||||
'Z' => if (@hasDecl(T, "deviceAttributes") and action.intermediates.len == 0) {
|
||||
try self.handler.deviceAttributes(.primary, &.{});
|
||||
} else log.warn("unimplemented ESC callback: {}", .{action}),
|
||||
} else log.warn("unimplemented ESC callback: {f}", .{action}),
|
||||
|
||||
// RIS - Full Reset
|
||||
'c' => if (@hasDecl(T, "fullReset")) switch (action.intermediates.len) {
|
||||
0 => try self.handler.fullReset(),
|
||||
else => {
|
||||
log.warn("invalid full reset command: {}", .{action});
|
||||
log.warn("invalid full reset command: {f}", .{action});
|
||||
return;
|
||||
},
|
||||
} else log.warn("unimplemented ESC callback: {}", .{action}),
|
||||
} else log.warn("unimplemented ESC callback: {f}", .{action}),
|
||||
|
||||
// LS2 - Locking Shift 2
|
||||
'n' => if (@hasDecl(T, "invokeCharset")) switch (action.intermediates.len) {
|
||||
0 => try self.handler.invokeCharset(.GL, .G2, false),
|
||||
else => {
|
||||
log.warn("invalid single shift 2 command: {}", .{action});
|
||||
log.warn("invalid single shift 2 command: {f}", .{action});
|
||||
return;
|
||||
},
|
||||
} else log.warn("unimplemented invokeCharset: {}", .{action}),
|
||||
} else log.warn("unimplemented invokeCharset: {f}", .{action}),
|
||||
|
||||
// LS3 - Locking Shift 3
|
||||
'o' => if (@hasDecl(T, "invokeCharset")) switch (action.intermediates.len) {
|
||||
0 => try self.handler.invokeCharset(.GL, .G3, false),
|
||||
else => {
|
||||
log.warn("invalid single shift 3 command: {}", .{action});
|
||||
log.warn("invalid single shift 3 command: {f}", .{action});
|
||||
return;
|
||||
},
|
||||
} else log.warn("unimplemented invokeCharset: {}", .{action}),
|
||||
} else log.warn("unimplemented invokeCharset: {f}", .{action}),
|
||||
|
||||
// LS1R - Locking Shift 1 Right
|
||||
'~' => if (@hasDecl(T, "invokeCharset")) switch (action.intermediates.len) {
|
||||
0 => try self.handler.invokeCharset(.GR, .G1, false),
|
||||
else => {
|
||||
log.warn("invalid locking shift 1 right command: {}", .{action});
|
||||
log.warn("invalid locking shift 1 right command: {f}", .{action});
|
||||
return;
|
||||
},
|
||||
} else log.warn("unimplemented invokeCharset: {}", .{action}),
|
||||
} else log.warn("unimplemented invokeCharset: {f}", .{action}),
|
||||
|
||||
// LS2R - Locking Shift 2 Right
|
||||
'}' => if (@hasDecl(T, "invokeCharset")) switch (action.intermediates.len) {
|
||||
0 => try self.handler.invokeCharset(.GR, .G2, false),
|
||||
else => {
|
||||
log.warn("invalid locking shift 2 right command: {}", .{action});
|
||||
log.warn("invalid locking shift 2 right command: {f}", .{action});
|
||||
return;
|
||||
},
|
||||
} else log.warn("unimplemented invokeCharset: {}", .{action}),
|
||||
} else log.warn("unimplemented invokeCharset: {f}", .{action}),
|
||||
|
||||
// LS3R - Locking Shift 3 Right
|
||||
'|' => if (@hasDecl(T, "invokeCharset")) switch (action.intermediates.len) {
|
||||
0 => try self.handler.invokeCharset(.GR, .G3, false),
|
||||
else => {
|
||||
log.warn("invalid locking shift 3 right command: {}", .{action});
|
||||
log.warn("invalid locking shift 3 right command: {f}", .{action});
|
||||
return;
|
||||
},
|
||||
} else log.warn("unimplemented invokeCharset: {}", .{action}),
|
||||
} else log.warn("unimplemented invokeCharset: {f}", .{action}),
|
||||
|
||||
// Set application keypad mode
|
||||
'=' => if (@hasDecl(T, "setMode") and action.intermediates.len == 0) {
|
||||
try self.handler.setMode(.keypad_keys, true);
|
||||
} else log.warn("unimplemented setMode: {}", .{action}),
|
||||
} else log.warn("unimplemented setMode: {f}", .{action}),
|
||||
|
||||
// Reset application keypad mode
|
||||
'>' => if (@hasDecl(T, "setMode") and action.intermediates.len == 0) {
|
||||
try self.handler.setMode(.keypad_keys, false);
|
||||
} else log.warn("unimplemented setMode: {}", .{action}),
|
||||
} else log.warn("unimplemented setMode: {f}", .{action}),
|
||||
|
||||
else => if (@hasDecl(T, "escUnimplemented"))
|
||||
try self.handler.escUnimplemented(action)
|
||||
else
|
||||
log.warn("unimplemented ESC action: {}", .{action}),
|
||||
log.warn("unimplemented ESC action: {f}", .{action}),
|
||||
|
||||
// Sets ST (string terminator). We don't have to do anything
|
||||
// because our parser always accepts ST.
|
||||
|
|
|
|||
Loading…
Reference in New Issue