fill in some gaps and add an example
This commit is contained in:
parent
0e9d395a55
commit
bd361e40ee
4 changed files with 314 additions and 17 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
/result*
|
||||
/zig-cache
|
||||
/zig-out
|
||||
/perf.data*
|
||||
|
|
17
build.zig
17
build.zig
|
@ -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
192
examples/random_sgr.zig
Normal 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});
|
||||
}
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in a new issue