fill in some gaps and add an example

This commit is contained in:
Jeffrey C. Ollie 2024-02-10 19:11:36 -06:00
parent 0e9d395a55
commit bd361e40ee
Signed by: jeff
GPG key ID: 6F86035A6D97044E
4 changed files with 314 additions and 17 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
/result*
/zig-cache
/zig-out
/perf.data*

View file

@ -4,17 +4,17 @@ pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
_ = b.addModule(
const anzi = b.addModule(
"anzi",
.{
.root_source_file = .{
.path = "src/main.zig",
.path = "src/root.zig",
},
},
);
const unit_tests = b.addTest(.{
.root_source_file = .{ .path = "src/main.zig" },
.root_source_file = .{ .path = "src/root.zig" },
.target = target,
.optimize = optimize,
});
@ -22,4 +22,15 @@ pub fn build(b: *std.Build) void {
const run_unit_tests = b.addRunArtifact(unit_tests);
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_unit_tests.step);
const random_sgr = b.addExecutable(.{
.name = "random_sgr",
.root_source_file = .{ .path = "examples/random_sgr.zig" },
.target = target,
.optimize = optimize,
});
random_sgr.root_module.addImport("anzi", anzi);
b.installArtifact(random_sgr);
}

192
examples/random_sgr.zig Normal file
View file

@ -0,0 +1,192 @@
const std = @import("std");
const anzi = @import("anzi");
var done: bool = false;
fn signal(_: c_int) callconv(.C) void {
done = true;
}
var column: u8 = 0;
var line: u8 = 0;
fn nextColumn() u8 {
const c = column;
column = (column + 7) % 80;
return c + 1;
}
fn nextLine() u8 {
const l = line;
line = (line + 27) % 24;
return l + 1;
}
var red: u8 = 0;
var green: u8 = 0;
var blue: u8 = 0;
inline fn nextRed() u8 {
const r = red;
red +%= 31;
return r;
}
inline fn nextGreen() u8 {
const g = green;
green +%= 43;
return g;
}
inline fn nextBlue() u8 {
const b = blue;
blue +%= 67;
return b;
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const alloc = gpa.allocator();
const action = std.os.Sigaction{
.handler = .{
.handler = signal,
},
.flags = 0,
.mask = std.os.empty_sigset,
};
try std.os.sigaction(std.os.SIG.INT, &action, null);
var generator = std.rand.DefaultPrng.init(@intCast(std.time.timestamp()));
const random = generator.random();
const a = anzi.ANSI(.{});
std.debug.print("preparing buffer...\n", .{});
const buffer = try alloc.alloc(u8, 1024 * 1024 * 1024);
defer alloc.free(buffer);
var fbs = std.io.fixedBufferStream(buffer);
{
const writer = fbs.writer();
try writer.print("{}{}", .{
a.ScreenMode{ .mode = .alternate_screen_save_cursor_clear_enter, .action = .set },
a.ScreenMode{ .mode = .cursor_visible, .action = .reset },
});
errdefer {
writer.print("{}{}", .{
a.ScreenMode{ .mode = .cursor_visible, .action = .set },
a.ScreenMode{ .mode = .alternate_screen_save_cursor_clear_enter, .action = .reset },
}) catch unreachable;
}
try a.Erase.entireScreen.write(writer);
var index: usize = 0;
while (!done and index < 10000) : (index += 1) {
// try (a.ScreenMode{ .mode = .synchronized_output, .action = .set }).write(writer);
for (1..80) |_| {
for (1..24) |_| {
try (a.CursorMove{
.to = .{
.column = random.intRangeAtMost(u8, 1, 80),
.line = random.intRangeAtMost(u8, 1, 24),
},
}).write(writer);
try (a.GraphicsRenditions{
.graphics = &[_]a.GraphicsRenditions.GraphicsRendition{
.{
.color = .{
.layer = .foreground,
.color = .{
.colorRGB = .{
.red = random.int(u8),
.green = random.int(u8),
.blue = random.int(u8),
},
},
},
},
.{
.color = .{
.layer = .background,
.color = .{
.colorRGB = .{
.red = random.int(u8),
.green = random.int(u8),
.blue = random.int(u8),
},
},
},
},
},
}).write(writer);
try writer.writeByte('J');
}
}
// try (a.ScreenMode{ .mode = .synchronized_output, .action = .reset }).write(writer);
}
try a.reset.write(writer);
try writer.print("{}{}", .{
a.ScreenMode{ .mode = .cursor_visible, .action = .set },
a.ScreenMode{ .mode = .alternate_screen_save_cursor_clear_enter, .action = .reset },
});
}
var elapsed: u64 = undefined;
const written = fbs.getWritten();
{
const stdout = std.io.getStdOut();
const writer = stdout.writer();
var iter = std.mem.window(u8, written, 4 * 1024 * 1024, 4 * 1024 * 1024);
std.debug.print("starting to send data...\n", .{});
var timer = try std.time.Timer.start();
while (iter.next()) |buf| {
try writer.writeAll(buf);
}
elapsed = timer.read();
std.debug.print("finished sending data...\n", .{});
}
const units = [_]struct {
name: []const u8,
factor: u64,
}{
.{ .name = "y", .factor = 365 * std.time.ns_per_day },
.{ .name = "w", .factor = std.time.ns_per_week },
.{ .name = "d", .factor = std.time.ns_per_day },
.{ .name = "h", .factor = std.time.ns_per_hour },
.{ .name = "m", .factor = std.time.ns_per_min },
.{ .name = "s", .factor = std.time.ns_per_s },
.{ .name = "ms", .factor = std.time.ns_per_ms },
.{ .name = "µs", .factor = std.time.ns_per_us },
.{ .name = "ns", .factor = 1 },
};
var i: usize = 0;
for (units) |unit| {
if (elapsed > unit.factor) {
if (i > 0) std.debug.print(" ", .{});
const r = elapsed % unit.factor;
const x = (elapsed - r) / unit.factor;
std.debug.print("{d}{s}", .{ x, unit.name });
elapsed = r;
i += 1;
}
}
std.debug.print("\n", .{});
std.debug.print("{d}\n", .{written.len});
}

View file

@ -174,7 +174,7 @@ pub fn ANSI(comptime options: Options) type {
/// moves cursor to column #
toColumn: u8,
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
pub fn write(self: @This(), writer: anytype) !void {
try writer.writeAll(Self.RL_PROMPT_START_IGNORE ++ Self.CSI);
switch (self) {
.home => try writer.writeAll("H"),
@ -194,12 +194,17 @@ pub fn ANSI(comptime options: Options) type {
.downBOL => "E",
.upBOL => "F",
.toColumn => "G",
else => unreachable,
};
try writer.writeAll(v);
},
}
try writer.writeAll(Self.RL_PROMPT_END_IGNORE);
}
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
try self.write(writer);
}
};
/// request cursor position (reports as ESC[#;#R)
@ -248,8 +253,8 @@ pub fn ANSI(comptime options: Options) type {
fromStartOfLineToCursor,
entireLine,
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
try writer.writeAll(Self.RL_PROMPT_START_IGNORE ++
pub fn write(self: @This(), writer: anytype) !void {
try writer.writeAll(Self.RL_PROMPT_START_IGNORE ++ Self.CSI ++
switch (self) {
.fromCursorToEndOfScreen => "0J",
.fromStartOfScreenToCursor => "1J",
@ -260,21 +265,26 @@ pub fn ANSI(comptime options: Options) type {
.entireLine => "2K",
} ++ Self.RL_PROMPT_END_IGNORE);
}
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
try self.write(writer);
}
};
const ColorType = union(enum) {
pub const ColorType = union(enum) {
color8: Color8,
color256: Color256,
colorRGB: ColorRGB,
};
const GraphicsRenditions = struct {
const GraphicsRendition = union(enum) {
pub const GraphicsRenditions = struct {
pub const GraphicsRendition = union(enum) {
reset: void,
style: struct {
mode: enum { enable, disable },
style: Style,
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
pub fn write(self: @This(), writer: anytype) !void {
switch (self.mode) {
.enable => try std.fmt.formatInt(@intFromEnum(self.style), 10, .lower, .{}, writer),
.disable => switch (self.style) {
@ -283,11 +293,16 @@ pub fn ANSI(comptime options: Options) type {
},
}
}
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
try self.write(writer);
}
},
color: struct {
layer: Layer,
color: ColorType,
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
pub fn write(self: @This(), writer: anytype) !void {
switch (self.color) {
.color8 => |v| {
var offset: u8 = 30;
@ -315,29 +330,37 @@ pub fn ANSI(comptime options: Options) type {
},
}
}
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
try self.write(writer);
}
},
};
graphics: []const GraphicsRendition,
pub fn format(self: @This(), comptime fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void {
pub fn write(self: @This(), writer: anytype) !void {
try writer.writeAll(Self.RL_PROMPT_START_IGNORE ++ Self.CSI);
for (self.graphics, 0..) |graphic, index| {
if (index > 0) try writer.writeAll(";");
switch (graphic) {
.reset => try writer.writeAll("0"),
.style => |s| try s.format(fmt, opt, writer),
.color => |c| try c.format(fmt, opt, writer),
.style => |s| try s.write(writer),
.color => |c| try c.write(writer),
}
}
try writer.writeAll("m" ++ Self.RL_PROMPT_END_IGNORE);
}
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
try self.write(writer);
}
};
/// Reset all styles and colors to the default
const reset = GraphicsRenditions{
pub const reset = GraphicsRenditions{
.graphics = &.{
.{
.reset = {},
@ -536,13 +559,83 @@ pub fn ANSI(comptime options: Options) type {
HOST_WRITABLE = 2,
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
try writer.writeAll(Self.RL_PROMPT_END_IGNORE_START_IGNORE ++ Self.CSI);
try writer.writeAll(Self.RL_PROMPT_START_IGNORE ++ Self.CSI);
try std.fmt.formatInt(@intFromEnum(self), 10, .lower, .{}, writer);
try writer.writeAll("$~" ++ Self.RL_PROMPT_END_IGNORE);
}
};
pub const ScreenMode = struct {};
pub const ScreenMode = struct {
mode: enum(u16) {
cursor_visible = 25,
alternate_screen = 1047,
alternate_screen_save_cursor_clear_enter = 1049,
bracketed_paste = 2004,
synchronized_output = 2026,
grapheme_cluster = 2027,
report_color_scheme = 2031,
},
action: enum {
set,
reset,
},
pub fn write(self: @This(), writer: anytype) !void {
try writer.writeAll(Self.RL_PROMPT_START_IGNORE ++ Self.CSI ++ "?");
try std.fmt.formatInt(@intFromEnum(self.mode), 10, .lower, .{}, writer);
try writer.writeAll(switch (self.action) {
.set => "h",
.reset => "l",
});
try writer.writeAll(Self.RL_PROMPT_END_IGNORE);
}
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
try self.write(writer);
}
};
pub const KittyGraphicsFormat = enum(u8) {
rgb = 24,
rgba = 32,
png = 100,
};
pub const KittyGraphicsMedium =
enum {
direct,
simple_file,
temporary_file,
shared_memory_object,
};
pub const KittyGraphicsData = struct {
format: KittyGraphicsFormat = .rgba,
medium: KittyGraphicsMedium = .direct,
width: ?u32,
height: ?u32,
compression: enum {
none,
zstd,
},
size: ?u32,
offset: ?u32,
data: []const u8,
// pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
// var first = false;
// const encoded_size = std.base64.standard.Encoder.calcSize(self.data);
// }
};
pub const TransmitKittyGraphicsData = struct {
image_id: ?u32,
image_number: ?u32,
placement_id: ?u32,
action: union {
transmit: KittyGraphicsData,
},
};
};
}