first
This commit is contained in:
commit
0e9d395a55
6 changed files with 817 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
/result*
|
||||||
|
/zig-cache
|
||||||
|
/zig-out
|
25
build.zig
Normal file
25
build.zig
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
const target = b.standardTargetOptions(.{});
|
||||||
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
|
_ = b.addModule(
|
||||||
|
"anzi",
|
||||||
|
.{
|
||||||
|
.root_source_file = .{
|
||||||
|
.path = "src/main.zig",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const unit_tests = b.addTest(.{
|
||||||
|
.root_source_file = .{ .path = "src/main.zig" },
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
|
||||||
|
const run_unit_tests = b.addRunArtifact(unit_tests);
|
||||||
|
const test_step = b.step("test", "Run unit tests");
|
||||||
|
test_step.dependOn(&run_unit_tests.step);
|
||||||
|
}
|
14
build.zig.zon
Normal file
14
build.zig.zon
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
.{
|
||||||
|
.name = "ansi",
|
||||||
|
.version = "0.0.0",
|
||||||
|
|
||||||
|
.paths = .{
|
||||||
|
"",
|
||||||
|
// For example...
|
||||||
|
//"build.zig",
|
||||||
|
//"build.zig.zon",
|
||||||
|
//"src",
|
||||||
|
//"LICENSE",
|
||||||
|
//"README.md",
|
||||||
|
},
|
||||||
|
}
|
76
flake.lock
Normal file
76
flake.lock
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1694529238,
|
||||||
|
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"make-shell": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1634940815,
|
||||||
|
"narHash": "sha256-P69OmveboXzS+es1vQGS4bt+ckwbeIExqxfGLjGuJqA=",
|
||||||
|
"owner": "ursi",
|
||||||
|
"repo": "nix-make-shell",
|
||||||
|
"rev": "8add91681170924e4d0591b22f294aee3f5516f9",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "ursi",
|
||||||
|
"repo": "nix-make-shell",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1697059129,
|
||||||
|
"narHash": "sha256-9NJcFF9CEYPvHJ5ckE8kvINvI84SZZ87PvqMbH6pro0=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "5e4c2ada4fcd54b99d56d7bd62f384511a7e2593",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"id": "nixpkgs",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"type": "indirect"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"make-shell": "make-shell",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
61
flake.nix
Normal file
61
flake.nix
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
{
|
||||||
|
description = "zig-ansi";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs = {
|
||||||
|
url = "nixpkgs/nixos-unstable";
|
||||||
|
};
|
||||||
|
flake-utils = {
|
||||||
|
url = "github:numtide/flake-utils";
|
||||||
|
};
|
||||||
|
make-shell = {
|
||||||
|
url = "github:ursi/nix-make-shell";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = {
|
||||||
|
self,
|
||||||
|
nixpkgs,
|
||||||
|
flake-utils,
|
||||||
|
...
|
||||||
|
} @ inputs:
|
||||||
|
flake-utils.lib.eachDefaultSystem
|
||||||
|
(
|
||||||
|
system: let
|
||||||
|
pkgs = import nixpkgs {
|
||||||
|
inherit system;
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
devShells.default = let
|
||||||
|
project = "zig-ansi";
|
||||||
|
make-shell = import inputs.make-shell {
|
||||||
|
inherit system;
|
||||||
|
pkgs = pkgs;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
make-shell {
|
||||||
|
packages = [
|
||||||
|
pkgs.zon2nix
|
||||||
|
pkgs.zig_0_11
|
||||||
|
pkgs.zls
|
||||||
|
];
|
||||||
|
env = {
|
||||||
|
NIX_PROJECT = project;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
packages = {
|
||||||
|
zig-ansi = pkgs.stdenv.mkDerivation {
|
||||||
|
name = "zig-ansi";
|
||||||
|
src = ./.;
|
||||||
|
nativeBuildInputs = [
|
||||||
|
pkgs.zig_0_11.hook
|
||||||
|
];
|
||||||
|
postPatch = ''
|
||||||
|
ln -s ${pkgs.callPackage ./deps.nix {}} $ZIG_GLOBAL_CACHE_DIR/p
|
||||||
|
'';
|
||||||
|
dontStrip = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
638
src/main.zig
Normal file
638
src/main.zig
Normal file
|
@ -0,0 +1,638 @@
|
||||||
|
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 format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, 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",
|
||||||
|
};
|
||||||
|
try writer.writeAll(v);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
try writer.writeAll(Self.RL_PROMPT_END_IGNORE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// 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 format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
||||||
|
try writer.writeAll(Self.RL_PROMPT_START_IGNORE ++
|
||||||
|
switch (self) {
|
||||||
|
.fromCursorToEndOfScreen => "0J",
|
||||||
|
.fromStartOfScreenToCursor => "1J",
|
||||||
|
.entireScreen => "2J",
|
||||||
|
.savedLines => "3J",
|
||||||
|
.fromCursorToEndOfLine => "0K",
|
||||||
|
.fromStartOfLineToCursor => "1K",
|
||||||
|
.entireLine => "2K",
|
||||||
|
} ++ Self.RL_PROMPT_END_IGNORE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const ColorType = union(enum) {
|
||||||
|
color8: Color8,
|
||||||
|
color256: Color256,
|
||||||
|
colorRGB: ColorRGB,
|
||||||
|
};
|
||||||
|
|
||||||
|
const GraphicsRenditions = struct {
|
||||||
|
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 {
|
||||||
|
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),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
color: struct {
|
||||||
|
layer: Layer,
|
||||||
|
color: ColorType,
|
||||||
|
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, 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);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
graphics: []const GraphicsRendition,
|
||||||
|
|
||||||
|
pub fn format(self: @This(), comptime fmt: []const u8, opt: std.fmt.FormatOptions, 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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try writer.writeAll("m" ++ Self.RL_PROMPT_END_IGNORE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Reset all styles and colors to the default
|
||||||
|
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_END_IGNORE_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 {};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
Loading…
Reference in a new issue