732 lines
25 KiB
Zig
732 lines
25 KiB
Zig
const std = @import("std");
|
|
|
|
pub const Mode = enum {
|
|
C0,
|
|
C1,
|
|
Bash,
|
|
};
|
|
|
|
pub const Options = struct {
|
|
mode: Mode = .C0,
|
|
wrap: bool = false,
|
|
};
|
|
|
|
pub const ColorName = enum(u8) {
|
|
BLACK = 0,
|
|
RED = 1,
|
|
GREEN = 2,
|
|
YELLOW = 3,
|
|
BLUE = 4,
|
|
MAGENTA = 5,
|
|
CYAN = 6,
|
|
WHITE = 7,
|
|
DEFAULT = 9,
|
|
};
|
|
|
|
pub const Layer = enum {
|
|
foreground,
|
|
background,
|
|
};
|
|
|
|
pub const Color8 = struct {
|
|
color: ColorName,
|
|
bright: bool = false,
|
|
};
|
|
|
|
pub const Color256 = u8;
|
|
|
|
pub const ColorRGB = struct {
|
|
red: u8,
|
|
green: u8,
|
|
blue: u8,
|
|
};
|
|
|
|
pub const Style = enum(u8) {
|
|
/// enable bold mode
|
|
BOLD = 1,
|
|
|
|
/// enable faint mode
|
|
FAINT = 2,
|
|
|
|
/// enable italic mode
|
|
ITALIC = 3,
|
|
|
|
/// enable underline mode
|
|
UNDERLINE = 4,
|
|
|
|
/// enable blinking mode
|
|
BLINKING = 5,
|
|
|
|
/// enable inverse mode
|
|
INVERSE = 7,
|
|
|
|
/// enable hidden mode
|
|
HIDDEN = 8,
|
|
|
|
/// enable strikethrough mode
|
|
STRIKETHROUGH = 9,
|
|
|
|
/// double underline mode, not supported by many terminals
|
|
DOUBLE_UNDERLINE = 21,
|
|
|
|
/// set dim mode
|
|
pub const DIM = Style.FAINT;
|
|
|
|
/// set reverse mode
|
|
pub const REVERSE = Style.INVERSE;
|
|
|
|
/// set invisible mode
|
|
pub const INVISIBLE = Style.HIDDEN;
|
|
};
|
|
|
|
pub fn ANSI(comptime options: Options) type {
|
|
return struct {
|
|
const mode = options.mode;
|
|
const wrap = options.wrap;
|
|
|
|
const Self = @This();
|
|
|
|
pub const SOH: []const u8 = switch (options.mode) {
|
|
.C0, .C1 => &.{std.ascii.control_code.soh},
|
|
.Bash => "\\[",
|
|
};
|
|
|
|
pub const STX: []const u8 = switch (options.mode) {
|
|
.C0, .C1 => &.{std.ascii.control_code.stx},
|
|
.Bash => "\\]",
|
|
};
|
|
|
|
pub const RL_PROMPT_START_IGNORE: []const u8 = if (options.wrap) Self.SOH else "";
|
|
pub const RL_PROMPT_END_IGNORE: []const u8 = if (options.wrap) Self.STX else "";
|
|
|
|
pub fn readlinePromptStartIgnore(writer: anytype) !void {
|
|
if (comptime options.wrap) try writer.writeAll(Self.SOH);
|
|
}
|
|
|
|
pub fn readlinePromptEndIgnore(writer: anytype) !void {
|
|
if (comptime options.wrap) try writer.writeAll(Self.STX);
|
|
}
|
|
|
|
pub const BEL: []const u8 = switch (options.mode) {
|
|
.C0, .C1 => &.{std.ascii.control_code.bel},
|
|
.Bash => "\\a",
|
|
};
|
|
|
|
pub const BS: []const u8 = &.{std.ascii.control_code.bs};
|
|
pub const HT: []const u8 = &.{std.ascii.control_code.ht};
|
|
pub const LF: []const u8 = &.{std.ascii.control_code.lf};
|
|
pub const VT: []const u8 = &.{std.ascii.control_code.vt};
|
|
pub const FF: []const u8 = &.{std.ascii.control_code.ff};
|
|
pub const CR: []const u8 = &.{std.ascii.control_code.cr};
|
|
|
|
pub const ESC: []const u8 = switch (options.mode) {
|
|
.C0, .C1 => &.{std.ascii.control_code.esc},
|
|
.Bash => "\\e",
|
|
};
|
|
|
|
pub const DEL: []const u8 = "\x7f";
|
|
|
|
/// Device Control String
|
|
pub const DCS: []const u8 = switch (options.mode) {
|
|
.C0, .Bash => Self.ESC ++ "P",
|
|
.C1 => "\x8d",
|
|
};
|
|
|
|
/// Control Sequence Introducer
|
|
pub const CSI: []const u8 = switch (options.mode) {
|
|
.C0, .Bash => Self.ESC ++ "[",
|
|
.C1 => "\x9b",
|
|
};
|
|
|
|
/// String Terminator
|
|
pub const ST: []const u8 = switch (options.mode) {
|
|
.C0 => Self.ESC ++ "\\",
|
|
.C1 => "\x9c",
|
|
.Bash => Self.BEL,
|
|
};
|
|
|
|
/// Operating System Command
|
|
pub const OSC: []const u8 = switch (options.mode) {
|
|
.C0, .Bash => Self.ESC ++ "]",
|
|
.C1 => "\x9d",
|
|
};
|
|
|
|
pub const CursorMove = union(enum) {
|
|
/// moves cursor to home position (0, 0)
|
|
home: void,
|
|
/// moves cursor to line #, column #
|
|
to: struct {
|
|
line: u8,
|
|
column: u8,
|
|
},
|
|
/// moves cursor up # lines
|
|
up: u8,
|
|
/// moves cursor down # lines
|
|
down: u8,
|
|
/// moves cursor right # columns
|
|
right: u8,
|
|
/// moves cursor left # columns
|
|
left: u8,
|
|
/// moves cursor to beginning of next line, # lines down
|
|
downBOL: u8,
|
|
/// moves cursor to beginning of previous line, # lines up
|
|
upBOL: u8,
|
|
/// moves cursor to column #
|
|
toColumn: u8,
|
|
|
|
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"),
|
|
.to => |value| {
|
|
try std.fmt.formatInt(value.line, 10, .lower, .{}, writer);
|
|
try writer.writeAll(";");
|
|
try std.fmt.formatInt(value.column, 10, .lower, .{}, writer);
|
|
try writer.writeAll("H"); // also could use "f" instead of "H"
|
|
},
|
|
.up, .down, .left, .right, .downBOL, .upBOL, .toColumn => |value| {
|
|
try std.fmt.formatInt(value, 10, .lower, .{}, writer);
|
|
const v = switch (self) {
|
|
.up => "A",
|
|
.down => "B",
|
|
.right => "C",
|
|
.left => "D",
|
|
.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)
|
|
pub fn requestCursorPosition(writer: anytype) !void {
|
|
try writer.writeAll(Self.RL_PROMPT_START_IGNORE ++ Self.CSI ++ "6n" ++ Self.RL_PROMPT_END_IGNORE);
|
|
}
|
|
|
|
/// moves cursor one line up, scrolling if needed
|
|
pub fn moveCursorUpOne(writer: anytype) !void {
|
|
try writer.writeAll(Self.RL_PROMPT_START_IGNORE ++ Self.CSI ++ "7" ++ Self.RL_PROMPT_END_IGNORE);
|
|
}
|
|
|
|
/// save cursor position
|
|
pub const SaveCursorPosition = enum {
|
|
DEC,
|
|
SCO,
|
|
|
|
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
|
try writer.writeAll(Self.RL_PROMPT_START_IGNORE ++
|
|
switch (self) {
|
|
.DEC => Self.ESC ++ "7",
|
|
.SCO => Self.CSI ++ "s",
|
|
} ++ Self.RL_PROMPT_END_IGNORE);
|
|
}
|
|
};
|
|
|
|
pub const RestoreCursorPosition = enum {
|
|
DEC,
|
|
SCO,
|
|
|
|
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
|
try writer.writeAll(Self.RL_PROMPT_START_IGNORE ++
|
|
switch (self) {
|
|
.DEC => Self.ESC ++ "8",
|
|
.SCO => Self.CSI ++ "u",
|
|
} ++ Self.RL_PROMPT_END_IGNORE);
|
|
}
|
|
};
|
|
|
|
pub const Erase = enum {
|
|
fromCursorToEndOfScreen,
|
|
fromStartOfScreenToCursor,
|
|
entireScreen,
|
|
savedLines,
|
|
fromCursorToEndOfLine,
|
|
fromStartOfLineToCursor,
|
|
entireLine,
|
|
|
|
pub fn write(self: @This(), writer: anytype) !void {
|
|
try writer.writeAll(Self.RL_PROMPT_START_IGNORE ++ Self.CSI ++
|
|
switch (self) {
|
|
.fromCursorToEndOfScreen => "0J",
|
|
.fromStartOfScreenToCursor => "1J",
|
|
.entireScreen => "2J",
|
|
.savedLines => "3J",
|
|
.fromCursorToEndOfLine => "0K",
|
|
.fromStartOfLineToCursor => "1K",
|
|
.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);
|
|
}
|
|
};
|
|
|
|
pub const ColorType = union(enum) {
|
|
color8: Color8,
|
|
color256: Color256,
|
|
colorRGB: ColorRGB,
|
|
};
|
|
|
|
pub const GraphicsRenditions = struct {
|
|
pub const GraphicsRendition = union(enum) {
|
|
reset: void,
|
|
style: struct {
|
|
mode: enum { enable, disable },
|
|
style: Style,
|
|
|
|
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) {
|
|
.BOLD, .FAINT => try writer.writeAll("22"),
|
|
else => try std.fmt.formatInt(@intFromEnum(self.style) + 20, 10, .lower, .{}, writer),
|
|
},
|
|
}
|
|
}
|
|
|
|
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 write(self: @This(), writer: anytype) !void {
|
|
switch (self.color) {
|
|
.color8 => |v| {
|
|
var offset: u8 = 30;
|
|
if (v.bright) offset = 100;
|
|
if (self.layer == .background) offset += 10;
|
|
try std.fmt.formatInt(@intFromEnum(v.color) + offset, 10, .lower, .{}, writer);
|
|
},
|
|
.color256 => |v| {
|
|
switch (self.layer) {
|
|
.foreground => try writer.writeAll("38;5;"),
|
|
.background => try writer.writeAll("48;5;"),
|
|
}
|
|
try std.fmt.formatInt(v, 10, .lower, .{}, writer);
|
|
},
|
|
.colorRGB => |v| {
|
|
switch (self.layer) {
|
|
.foreground => try writer.writeAll("38;2;"),
|
|
.background => try writer.writeAll("48;2;"),
|
|
}
|
|
try std.fmt.formatInt(v.red, 10, .lower, .{}, writer);
|
|
try writer.writeAll(";");
|
|
try std.fmt.formatInt(v.green, 10, .lower, .{}, writer);
|
|
try writer.writeAll(";");
|
|
try std.fmt.formatInt(v.blue, 10, .lower, .{}, writer);
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
|
try self.write(writer);
|
|
}
|
|
},
|
|
};
|
|
|
|
graphics: []const GraphicsRendition,
|
|
|
|
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.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
|
|
pub const reset = GraphicsRenditions{
|
|
.graphics = &.{
|
|
.{
|
|
.reset = {},
|
|
},
|
|
},
|
|
};
|
|
|
|
/// Set the color using the 8 standard colors.
|
|
pub fn color8(layer: Layer, color: ColorName, bright: bool) GraphicsRenditions {
|
|
return GraphicsRenditions{
|
|
.graphics = &.{
|
|
.{
|
|
.color = .{
|
|
.layer = layer,
|
|
.color = .{
|
|
.color8 = .{
|
|
.color = color,
|
|
.bright = bright,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
/// Set the color using the 256 color palette.
|
|
pub fn color256(layer: Layer, color: Color256) GraphicsRenditions {
|
|
return GraphicsRenditions{
|
|
.graphics = &.{
|
|
.{
|
|
.color = .{
|
|
.layer = layer,
|
|
.color = .{
|
|
.color256 = color,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
/// Set the color using a 24 bit RGB color.
|
|
pub fn colorRGB(layer: Layer, red: u8, green: u8, blue: u8) GraphicsRenditions {
|
|
return GraphicsRenditions{
|
|
.graphics = &.{
|
|
.{
|
|
.color = .{
|
|
.layer = layer,
|
|
.color = .{
|
|
.colorRGB = .{
|
|
.red = red,
|
|
.green = green,
|
|
.blue = blue,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
pub const IconNameAndWindowTitle = struct {
|
|
icon_name: ?[]const u8 = null,
|
|
window_title: ?[]const u8 = null,
|
|
|
|
fn write(comptime control: []const u8, parameter: []const u8, writer: anytype) !void {
|
|
try writer.writeAll(Self.OSC ++ control ++ ";");
|
|
try writer.writeAll(parameter);
|
|
try writer.writeAll(Self.ST);
|
|
}
|
|
|
|
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
|
try writer.writeAll(Self.RL_PROMPT_START_IGNORE);
|
|
if (self.icon_name) |icon_name| {
|
|
if (self.window_title) |window_title| {
|
|
if (std.mem.eql(u8, icon_name, window_title)) {
|
|
try write("0", icon_name, writer);
|
|
} else {
|
|
try write("1", icon_name, writer);
|
|
try write("2", window_title, writer);
|
|
}
|
|
} else {
|
|
try write("1", icon_name, writer);
|
|
}
|
|
} else {
|
|
if (self.window_title) |window_title| {
|
|
try write("2", window_title, writer);
|
|
}
|
|
}
|
|
try writer.writeAll(Self.RL_PROMPT_END_IGNORE);
|
|
}
|
|
};
|
|
|
|
pub const SetProperty = struct {
|
|
property: []const u8,
|
|
value: ?[]const u8,
|
|
|
|
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
|
try writer.writeAll(Self.RL_PROMPT_START_IGNORE ++ "3;");
|
|
try writer.writeAll(self.property);
|
|
if (self.value) |v| {
|
|
try writer.writeAll("=");
|
|
try writer.writeAll(v);
|
|
}
|
|
try writer.writeAll(Self.ST ++ Self.RL_PROMPT_END_IGNORE);
|
|
}
|
|
};
|
|
|
|
pub const Hyperlink = struct {
|
|
link: []const u8,
|
|
text: []const u8,
|
|
|
|
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
|
try writer.writeAll(Self.RL_PROMPT_START_IGNORE ++ Self.OSC ++ "8;;");
|
|
try writer.writeAll(self.link);
|
|
try writer.writeAll(Self.ST ++ Self.RL_PROMPT_END_IGNORE);
|
|
try writer.writeAll(self.text);
|
|
try writer.writeAll(Self.RL_PROMPT_START_IGNORE ++ Self.OSC ++ "8;;" ++ Self.ST ++ Self.RL_PROMPT_END_IGNORE);
|
|
}
|
|
};
|
|
|
|
pub const Notification = struct {
|
|
text: []const u8,
|
|
|
|
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
|
try writer.writeAll(Self.RL_PROMPT_START_IGNORE ++ Self.OSC ++ "9;");
|
|
try writer.writeAll(self.text);
|
|
try writer.writeAll(Self.ST ++ Self.RL_PROMPT_END_IGNORE);
|
|
}
|
|
};
|
|
|
|
pub const DesktopNotification = struct {
|
|
identifier: []const u8,
|
|
encoded: bool = false,
|
|
title: []const u8,
|
|
body: []const u8,
|
|
report: bool = false,
|
|
focus: bool = false,
|
|
|
|
fn formatMetadata(self: @This(), part: enum { title, body }, done: bool, text: []const u8, writer: anytype) !void {
|
|
try writer.writeAll(Self.RL_PROMPT_START_IGNORE ++ Self.OSC ++ "99;");
|
|
try writer.writeAll("i=");
|
|
try writer.writeAll(self.identifier);
|
|
if (self.encoded) try writer.writeAll(";e=1") else try writer.writeAll(";e=0");
|
|
try writer.writeAll(";a=");
|
|
if (self.report) try writer.writeAll("report") else try writer.writeAll("-report");
|
|
try writer.writeAll(",");
|
|
if (self.focus) try writer.writeAll("focus") else try writer.writeAll("-focus");
|
|
switch (part) {
|
|
.title => try writer.writeAll(";p=title"),
|
|
.body => try writer.writeAll(";p=body"),
|
|
}
|
|
if (done) try writer.writeAll(";d=1;") else try writer.writeAll(";d=0;");
|
|
try writer.writeAll(text);
|
|
try writer.writeAll(Self.ST ++ Self.RL_PROMPT_END_IGNORE);
|
|
}
|
|
|
|
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
|
_ = writer;
|
|
_ = self;
|
|
}
|
|
};
|
|
|
|
pub const CurrentDirectory = struct {
|
|
text: []const u8,
|
|
style: enum {
|
|
OSC1337,
|
|
} = .OSC1337,
|
|
|
|
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
|
switch (self.style) {
|
|
.OSC1337 => {
|
|
try writer.writeAll(Self.RL_PROMPT_START_IGNORE ++ Self.OSC ++ "1337;CurrentDir=");
|
|
try writer.writeAll(self.text);
|
|
try writer.writeAll(Self.ST ++ Self.RL_PROMPT_END_IGNORE);
|
|
},
|
|
}
|
|
}
|
|
};
|
|
|
|
pub const ActiveStatusDisplay = enum(u8) {
|
|
MAIN_DISPLAY = 0,
|
|
STATUS_LINE = 1,
|
|
|
|
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
|
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 StatusLineType = enum(u8) {
|
|
NONE = 0,
|
|
INDICATOR = 1,
|
|
HOST_WRITABLE = 2,
|
|
|
|
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
|
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 {
|
|
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,
|
|
},
|
|
};
|
|
};
|
|
}
|
|
|
|
test "osc-c0" {
|
|
const a = ANSI(.{ .mode = .C0 });
|
|
try std.testing.expect(std.mem.eql(u8, a.OSC, @as([]const u8, "\x1b]")));
|
|
}
|
|
|
|
test "osc-c1" {
|
|
const a = ANSI(.{ .mode = .C1 });
|
|
try std.testing.expect(std.mem.eql(u8, a.OSC, @as([]const u8, "\x9d")));
|
|
}
|
|
|
|
test "osc-bash" {
|
|
const a = ANSI(.{ .mode = .Bash });
|
|
try std.testing.expect(std.mem.eql(u8, a.OSC, @as([]const u8, "\\e]")));
|
|
}
|
|
|
|
test "colorRGB-bash" {
|
|
const a = ANSI(.{ .mode = .Bash });
|
|
const g = a.GraphicsRenditions{
|
|
.graphics = &.{
|
|
.{
|
|
.color = .{
|
|
.layer = .foreground,
|
|
.color = .{
|
|
.colorRGB = .{
|
|
.red = 1,
|
|
.green = 2,
|
|
.blue = 3,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
const result = try std.fmt.allocPrint(std.testing.allocator, "{}", .{g});
|
|
try std.testing.expectEqualSlices(u8, result, "\\e[38;2;1;2;3m");
|
|
std.testing.allocator.free(result);
|
|
}
|
|
|
|
test "colorRGB-c0" {
|
|
const a = ANSI(.{ .mode = .C0 });
|
|
const g = a.GraphicsRenditions{
|
|
.graphics = &.{
|
|
.{
|
|
.reset = {},
|
|
},
|
|
.{
|
|
.color = .{
|
|
.layer = .foreground,
|
|
.color = .{
|
|
.color8 = .{
|
|
.color = .RED,
|
|
.bright = false,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
const result = try std.fmt.allocPrint(std.testing.allocator, "{}", .{g});
|
|
try std.testing.expectEqualSlices(u8, result, "\x1b[0;31m");
|
|
std.testing.allocator.free(result);
|
|
}
|
|
|
|
test "reset" {
|
|
const a = ANSI(.{ .mode = .C0 });
|
|
const g = a.reset;
|
|
const result = try std.fmt.allocPrint(std.testing.allocator, "{}", .{g});
|
|
try std.testing.expectEqualSlices(u8, result, "\x1b[0m");
|
|
std.testing.allocator.free(result);
|
|
}
|
|
|
|
test "color8" {
|
|
const a = ANSI(.{ .mode = .C0 });
|
|
const g = a.color8(.foreground, .BLUE, false);
|
|
const result = try std.fmt.allocPrint(std.testing.allocator, "{}", .{g});
|
|
try std.testing.expectEqualSlices(u8, result, "\x1b[34m");
|
|
std.testing.allocator.free(result);
|
|
}
|
|
|
|
test "hyperlink-c0" {
|
|
const a = ANSI(.{ .mode = .C0, .wrap = false });
|
|
var buffer: [128]u8 = undefined;
|
|
const written = try std.fmt.bufPrint(&buffer, "{}", .{
|
|
a.Hyperlink{
|
|
.link = "https://www.example.com",
|
|
.text = "Example",
|
|
},
|
|
});
|
|
try std.testing.expectEqualSlices(u8, "\x1b]8;;https://www.example.com\x1b\\Example\x1b]8;;\x1b\\", written);
|
|
}
|