feat(element/scrollable): scrollbar rendering

Configuration to enable scrollbar rendering for scrollable `Element`s.
Currently only the fg `Color` of the scrollbar can be configured while
the background uses the same fg `Color` but adds the emphasis `.dim` to
make it obvious what the is the actual scrollbar. In the future it might
be necessary to provide the user with more options to configure the
representation of the scrollbar.

Tests have been added to test the scrollbar rendering and placement
accordingly.
This commit is contained in:
yves-biener committed 2025-05-21 18:20:52 +02:00
1 parent aa4adf20f9
commit ba25e6056c
9 files changed
+247 -16

No files matched your search

+237 -10
View File
@@ -70,9 +70,29 @@ pub fn Scrollable(Event: type) type {
anchor: Point = .{},
/// The actual `Container`, that is scrollable.
container: Container(Event),
/// Whether the scrollable contents should show a scroll bar or not.
/// The scroll bar will only be shown if required and enabled. With the
/// corresponding provided color if to be shown.
configuration: Configuration,
pub fn init(container: Container(Event)) @This() {
return .{ .container = container };
pub const Configuration = packed struct {
scrollbar: bool,
color: Color = .default,
x_axis: bool = false,
y_axis: bool = false,
pub const disabled: @This() = .{ .scrollbar = false };
pub fn enabled(color: Color) @This() {
return .{ .scrollbar = true, .color = color };
}
};
pub fn init(container: Container(Event), configuration: Configuration) @This() {
return .{
.container = container,
.configuration = configuration,
};
}
pub fn element(this: *@This()) Element(Event) {
@@ -91,8 +111,18 @@ pub fn Scrollable(Event: type) type {
const this: *@This() = @ptrCast(@alignCast(ctx));
this.size = size;
// TODO scrollbar space - depending on configuration and only if necessary?
this.container.resize(this.size);
this.container.resize(size);
if (this.configuration.scrollbar) {
if (this.container.properties.size.dim.x > this.size.x or this.container.size.x > this.size.x) this.configuration.y_axis = true;
if (this.container.properties.size.dim.y > this.size.y or this.container.size.y > this.size.y) this.configuration.x_axis = true;
if (this.configuration.x_axis or this.configuration.y_axis)
this.container.resize(.{
.x = this.size.x - if (this.configuration.x_axis) @as(u16, 1) else @as(u16, 0),
.y = this.size.y - if (this.configuration.y_axis) @as(u16, 1) else @as(u16, 0),
});
}
this.container_size = this.container.size;
}
@@ -157,34 +187,75 @@ pub fn Scrollable(Event: type) type {
fn content(ctx: *anyopaque, cells: []Cell, size: Point) !void {
const this: *@This() = @ptrCast(@alignCast(ctx));
std.debug.assert(cells.len == @as(usize, this.size.x) * @as(usize, this.size.y));
const offset_x: usize = if (this.configuration.x_axis) 1 else 0;
const offset_y: usize = if (this.configuration.y_axis) 1 else 0;
const container_size = this.container.size;
const container_cells = try this.container.allocator.alloc(Cell, @as(usize, container_size.x) * @as(usize, container_size.y));
{
const container_cells_const = try this.container.content();
defer this.container.allocator.free(container_cells_const);
std.debug.assert(container_cells_const.len == @as(usize, container_size.x) * @as(usize, container_size.y));
assert(container_cells_const.len == @as(usize, container_size.x) * @as(usize, container_size.y));
@memcpy(container_cells, container_cells_const);
}
for (this.container.elements.items) |child| try render_container(child, container_cells, container_size);
const anchor = (@as(usize, this.anchor.y) * @as(usize, container_size.x)) + @as(usize, this.anchor.x);
// TODO render scrollbar according to configuration!
for (0..size.y) |row| {
for (0..size.x) |col| {
for (0..size.y - offset_y) |row| {
for (0..size.x - offset_x) |col| {
cells[(row * size.x) + col] = container_cells[anchor + (row * container_size.x) + col];
}
}
if (this.configuration.scrollbar) {
if (this.configuration.x_axis) {
const ratio: f32 = @as(f32, @floatFromInt(this.size.y)) / @as(f32, @floatFromInt(this.container.size.y));
const scrollbar_size: usize = @intFromFloat(@as(f32, @floatFromInt(this.size.y)) * ratio);
const pos_ratio: f32 = @as(f32, @floatFromInt(this.anchor.y)) / @as(f32, @floatFromInt(this.container.size.y));
const scrollbar_starting_pos: usize = @intFromFloat(@as(f32, @floatFromInt(this.size.y)) * pos_ratio);
for (0..size.y) |row| {
cells[(row * size.x) + size.x - 1] = .{
.style = .{
.fg = this.configuration.color,
.emphasis = if (row >= scrollbar_starting_pos and row <= scrollbar_starting_pos + scrollbar_size)
&.{} // scrollbar itself
else
&.{.dim}, // background (around scrollbar)
},
.cp = '🮋', // 7/8 block right
};
}
}
if (this.configuration.y_axis) {
const ratio: f32 = @as(f32, @floatFromInt(this.size.x)) / @as(f32, @floatFromInt(this.container.size.x));
const scrollbar_size: usize = @intFromFloat(@as(f32, @floatFromInt(this.size.x)) * ratio);
const pos_ratio: f32 = @as(f32, @floatFromInt(this.anchor.x)) / @as(f32, @floatFromInt(this.container.size.x));
const scrollbar_starting_pos: usize = @intFromFloat(@as(f32, @floatFromInt(this.size.x)) * pos_ratio);
for (0..size.x) |col| {
cells[((size.y - 1) * size.x) + col] = .{
.style = .{
.fg = this.configuration.color,
.emphasis = if (col >= scrollbar_starting_pos and col <= scrollbar_starting_pos + scrollbar_size)
&.{} // scrollbar itself
else
&.{.dim}, // background (around scrollbar)
},
.cp = '🮄', // 5/8 block top (to make it look more equivalent to the vertical scrollbar)
};
}
}
}
this.container.allocator.free(container_cells);
}
};
}
const std = @import("std");
const assert = std.debug.assert;
const input = @import("input.zig");
const Container = @import("container.zig").Container;
const Cell = @import("cell.zig");
const Color = @import("color.zig").Color;
const Mouse = input.Mouse;
const Point = @import("point.zig").Point;
@@ -225,7 +296,7 @@ test "scrollable vertical" {
}, .{}));
defer box.deinit();
var scrollable: Scrollable(event.SystemEvent) = .init(box);
var scrollable: Scrollable(event.SystemEvent) = .init(box, .disabled);
var container: Container(event.SystemEvent) = try .init(allocator, .{
.border = .{
@@ -268,6 +339,84 @@ test "scrollable vertical" {
try testing.expectEqualCells(.{}, renderer.size, @import("test/element/scrollable.vertical.bottom.zon"), renderer.screen);
}
test "scrollable vertical with scrollbar" {
const event = @import("event.zig");
const testing = @import("testing.zig");
const allocator = std.testing.allocator;
const size: Point = .{
.x = 30,
.y = 20,
};
var box: Container(event.SystemEvent) = try .init(allocator, .{
.border = .{
.sides = .all,
.color = .red,
},
.layout = .{
.separator = .{
.enabled = true,
.color = .red,
},
.direction = .vertical,
.padding = .all(1),
},
.size = .{
.dim = .{ .y = size.y + 15 },
},
}, .{});
try box.append(try .init(allocator, .{
.rectangle = .{ .fill = .grey },
}, .{}));
try box.append(try .init(allocator, .{
.rectangle = .{ .fill = .grey },
}, .{}));
defer box.deinit();
var scrollable: Scrollable(event.SystemEvent) = .init(box, .enabled(.white));
var container: Container(event.SystemEvent) = try .init(allocator, .{
.border = .{
.color = .green,
.sides = .vertical,
},
}, scrollable.element());
defer container.deinit();
var renderer: testing.Renderer = .init(allocator, size);
defer renderer.deinit();
container.resize(size);
container.reposition(.{});
try renderer.render(Container(event.SystemEvent), &container);
try testing.expectEqualCells(.{}, renderer.size, @import("test/element/scrollable.vertical.scrollbar.top.zon"), renderer.screen);
// scroll down 15 times (exactly to the end)
for (0..15) |_| try container.handle(.{
.mouse = .{
.button = .wheel_down,
.kind = .press,
.x = 5,
.y = 5,
},
});
try renderer.render(Container(event.SystemEvent), &container);
try testing.expectEqualCells(.{}, renderer.size, @import("test/element/scrollable.vertical.scrollbar.bottom.zon"), renderer.screen);
// further scrolling down will not change anything
try container.handle(.{
.mouse = .{
.button = .wheel_down,
.kind = .press,
.x = 5,
.y = 5,
},
});
try renderer.render(Container(event.SystemEvent), &container);
try testing.expectEqualCells(.{}, renderer.size, @import("test/element/scrollable.vertical.scrollbar.bottom.zon"), renderer.screen);
}
test "scrollable horizontal" {
const event = @import("event.zig");
const testing = @import("testing.zig");
@@ -303,7 +452,7 @@ test "scrollable horizontal" {
}, .{}));
defer box.deinit();
var scrollable: Scrollable(event.SystemEvent) = .init(box);
var scrollable: Scrollable(event.SystemEvent) = .init(box, .disabled);
var container: Container(event.SystemEvent) = try .init(allocator, .{
.border = .{
@@ -345,3 +494,81 @@ test "scrollable horizontal" {
try renderer.render(Container(event.SystemEvent), &container);
try testing.expectEqualCells(.{}, renderer.size, @import("test/element/scrollable.horizontal.right.zon"), renderer.screen);
}
test "scrollable horizontal with scrollbar" {
const event = @import("event.zig");
const testing = @import("testing.zig");
const allocator = std.testing.allocator;
const size: Point = .{
.x = 30,
.y = 20,
};
var box: Container(event.SystemEvent) = try .init(allocator, .{
.border = .{
.sides = .all,
.color = .red,
},
.layout = .{
.separator = .{
.enabled = true,
.color = .red,
},
.direction = .horizontal,
.padding = .all(1),
},
.size = .{
.dim = .{ .x = size.x + 15 },
},
}, .{});
try box.append(try .init(allocator, .{
.rectangle = .{ .fill = .grey },
}, .{}));
try box.append(try .init(allocator, .{
.rectangle = .{ .fill = .grey },
}, .{}));
defer box.deinit();
var scrollable: Scrollable(event.SystemEvent) = .init(box, .enabled(.white));
var container: Container(event.SystemEvent) = try .init(allocator, .{
.border = .{
.color = .green,
.sides = .horizontal,
},
}, scrollable.element());
defer container.deinit();
var renderer: testing.Renderer = .init(allocator, size);
defer renderer.deinit();
container.resize(size);
container.reposition(.{});
try renderer.render(Container(event.SystemEvent), &container);
try testing.expectEqualCells(.{}, renderer.size, @import("test/element/scrollable.horizontal.scrollbar.left.zon"), renderer.screen);
// scroll right 15 times (exactly to the end)
for (0..15) |_| try container.handle(.{
.mouse = .{
.button = .wheel_right,
.kind = .press,
.x = 5,
.y = 5,
},
});
try renderer.render(Container(event.SystemEvent), &container);
try testing.expectEqualCells(.{}, renderer.size, @import("test/element/scrollable.horizontal.scrollbar.right.zon"), renderer.screen);
// further scrolling right will not change anything
try container.handle(.{
.mouse = .{
.button = .wheel_right,
.kind = .press,
.x = 5,
.y = 5,
},
});
try renderer.render(Container(event.SystemEvent), &container);
try testing.expectEqualCells(.{}, renderer.size, @import("test/element/scrollable.horizontal.scrollbar.right.zon"), renderer.screen);
}
@@ -0,0 +1 @@
.{.{.cp=9484,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9474,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.curLine truncated
@@ -0,0 +1 @@
.{.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9488,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cLine truncated
@@ -0,0 +1 @@
.{.{.cp=9474,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9474,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=129931,.style=.{.fg=.white,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{.dim}}},.{.cp=9474,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.grey,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.defLine truncated
@@ -0,0 +1 @@
.{.{.cp=9484,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9472,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9488,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=129931,.style=.{.fg=.white,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=9474,.style=.{.fg=.red,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,.cursor=false,.ul_style=.off,.emphasis=.{}}},.{.cp=32,.style=.{.fg=.default,.bg=.default,.ul=.default,Line truncated