diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..08b86cfb6cdecd96d548b4426ab9191f89037f6d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/zig-cache +/deps.zig diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f44e65a961d93698aececce57833e887df7dac21 --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# zig-ansi +![loc](https://sloc.xyz/github/nektro/zig-ansi) +[![license](https://img.shields.io/github/license/nektro/zig-ansi.svg)](https://github.com/nektro/zig-ansi/blob/master/LICENSE) +[![discord](https://img.shields.io/discord/551971034593755159.svg?logo=discord)](https://discord.gg/P6Y4zQC) + +ANSI utilities for CLI usage in Zig. + +## Zig +- https://ziglang.org/ +- https://github.com/ziglang/zig +- https://github.com/ziglang/zig/wiki/Community + +## Getting Started +Using https://github.com/nektro/zigmod, add a `git` type with a path of `https://github.com/nektro/zig-ansi`. + +## Usage +See `src/main.zig` or do `zig build run` to see examples. + +See `src/lib.zig` for source code. + +## Built With +- Zig 0.7.0 + +## Contact +- hello@nektro.net +- https://twitter.com/nektro + +## License +MIT diff --git a/build.zig b/build.zig new file mode 100644 index 0000000000000000000000000000000000000000..242d4f20bdafdb8b697122564dfc239bbaa5bf34 --- /dev/null +++ b/build.zig @@ -0,0 +1,27 @@ +const Builder = @import("std").build.Builder; + +pub fn build(b: *Builder) void { + // Standard target options allows the person running `zig build` to choose + // what target to build for. Here we do not override the defaults, which + // means any target is allowed, and the default is native. Other options + // for restricting supported target set are available. + const target = b.standardTargetOptions(.{}); + + // Standard release options allow the person running `zig build` to select + // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. + const mode = b.standardReleaseOptions(); + + const exe = b.addExecutable("zig-ansi", "src/main.zig"); + exe.setTarget(target); + exe.setBuildMode(mode); + exe.install(); + + const run_cmd = exe.run(); + run_cmd.step.dependOn(b.getInstallStep()); + if (b.args) |args| { + run_cmd.addArgs(args); + } + + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); +} diff --git a/src/lib.zig b/src/lib.zig new file mode 100644 index 0000000000000000000000000000000000000000..85cf6f058328494fc0c816baf1fc1c8b12636800 --- /dev/null +++ b/src/lib.zig @@ -0,0 +1,174 @@ +const std = @import("std"); + +pub const ascii = enum(u8) { + NUL, + SOH, + STX, + ETX, + EOT, + ENQ, + ACK, + BEL, + BS, + TAB, + LF, + VT, + FF, + CR, + SO, + SI, + DLE, + DC1, + DC2, + DC3, + DC4, + NAK, + SYN, + ETB, + CAN, + EM, + SUB, + ESC, + FS, + GS, + RS, + US, + + pub fn s(self: ascii) []const u8 { + return &[_]u8{@enumToInt(self)}; + } +}; + +pub const escape = struct { + pub const SS2 = ascii.ESC.s() ++ "N"; + pub const SS3 = ascii.ESC.s() ++ "O"; + pub const DCS = ascii.ESC.s() ++ "P"; + pub const CSI = ascii.ESC.s() ++ "["; + pub const ST = ascii.ESC.s() ++ "\\"; + pub const OSC = ascii.ESC.s() ++ "]"; + pub const SOS = ascii.ESC.s() ++ "X"; + pub const PM = ascii.ESC.s() ++ "^"; + pub const APC = ascii.ESC.s() ++ "_"; + pub const RIS = ascii.ESC.s() ++ "c"; +}; + +fn make_csi_sequence(comptime c: []const u8, x: anytype) []const u8 { + return escape.CSI ++ _join(";", arr_i_to_s(x)) ++ c; +} + +fn arr_i_to_s(x: anytype) [][]const u8 { + var res: [x.len][]const u8 = undefined; + for (x) |item, i| { + res[i] = std.fmt.comptimePrint("{}", .{item}); + } + return &res; +} + +pub const csi = struct { + fn CursorUp(n: i32) []const u8 { return make_csi_sequence("A", .{n}); } + fn CursorDown(n: i32) []const u8 { return make_csi_sequence("B", .{n}); } + fn CursorForward(n: i32) []const u8 { return make_csi_sequence("C", .{n}); } + fn CursorBack(n: i32) []const u8 { return make_csi_sequence("D", .{n}); } + fn CursorNextLine(n: i32) []const u8 { return make_csi_sequence("E", .{n}); } + fn CursorPrevLine(n: i32) []const u8 { return make_csi_sequence("F", .{n}); } + fn CursorHorzAbs(n: i32) []const u8 { return make_csi_sequence("G", .{n}); } + fn CursorPos(n: i32, m: i32) []const u8 { return make_csi_sequence("H", .{n, m}); } + fn EraseInDisplay(n: i32) []const u8 { return make_csi_sequence("J", .{n}); } + fn EraseInLine(n: i32) []const u8 { return make_csi_sequence("K", .{n}); } + fn ScrollUp(n: i32) []const u8 { return make_csi_sequence("S", .{n}); } + fn ScrollDown(n: i32) []const u8 { return make_csi_sequence("T", .{n}); } + fn HorzVertPos(n: i32, m: i32) []const u8 { return make_csi_sequence("f", .{n, m}); } + fn SGR(ns: anytype) []const u8 { return make_csi_sequence("m", ns); } +}; + +pub const style = struct { + pub const ResetAll = csi.SGR(.{0}); + + pub const Bold = csi.SGR(.{1}); + pub const Faint = csi.SGR(.{2}); + pub const Italic = csi.SGR(.{3}); + pub const Underline = csi.SGR(.{4}); + pub const BlinkSlow = csi.SGR(.{5}); + pub const BlinkFast = csi.SGR(.{6}); + + pub const ResetFont = csi.SGR(.{10}); + pub const Font1 = csi.SGR(.{11}); + pub const Font2 = csi.SGR(.{12}); + pub const Font3 = csi.SGR(.{13}); + pub const Font4 = csi.SGR(.{14}); + pub const Font5 = csi.SGR(.{15}); + pub const Font6 = csi.SGR(.{16}); + pub const Font7 = csi.SGR(.{17}); + pub const Font8 = csi.SGR(.{18}); + pub const Font9 = csi.SGR(.{19}); + + pub const UnderlineDouble = csi.SGR(.{21}); + pub const ResetIntensity = csi.SGR(.{22}); + pub const ResetItalic = csi.SGR(.{23}); + pub const ResetUnderline = csi.SGR(.{24}); + pub const ResetBlink = csi.SGR(.{25}); + + pub const FgBlack = csi.SGR(.{30}); + pub const FgRed = csi.SGR(.{31}); + pub const FgGreen = csi.SGR(.{32}); + pub const FgYellow = csi.SGR(.{33}); + pub const FgBlue = csi.SGR(.{34}); + pub const FgMagenta = csi.SGR(.{35}); + pub const FgCyan = csi.SGR(.{36}); + pub const FgWhite = csi.SGR(.{37}); + // Fg8bit = func(n int) string { return csi.SGR(38, 5, n) } + // Fg24bit = func(r, g, b int) string { return csi.SGR(38, 2, r, g, b) } + pub const ResetFgColor = csi.SGR(.{39}); + + pub const BgBlack = csi.SGR(.{40}); + pub const BgRed = csi.SGR(.{41}); + pub const BgGreen = csi.SGR(.{42}); + pub const BgYellow = csi.SGR(.{43}); + pub const BgBlue = csi.SGR(.{44}); + pub const BgMagenta = csi.SGR(.{45}); + pub const BgCyan = csi.SGR(.{46}); + pub const BgWhite = csi.SGR(.{47}); + // Bg8bit = func(n int) string { return csi.SGR(48, 5, n) } + // Bg24bit = func(r, g, b int) string { return csi.SGR(48, 2, r, g, b) } + pub const ResetBgColor = csi.SGR(.{49}); + + pub const Framed = csi.SGR(.{51}); + pub const Encircled = csi.SGR(.{52}); + pub const Overlined = csi.SGR(.{53}); + pub const ResetFrameEnci = csi.SGR(.{54}); + pub const ResetOverlined = csi.SGR(.{55}); +}; + +pub const color = struct { + pub const Color = enum(u8) { + Black, + Red, + Green, + Yellow, + Blue, + Magenta, + Cyan, + White, + }; + + pub fn Fg(s: Color, comptime m: []const u8) []const u8 { + return csi.SGR(.{30+@enumToInt(s)}) ++ m ++ style.ResetFgColor; + } + + pub fn Bg(s: Color, comptime m: []const u8) []const u8 { + return csi.SGR(.{40+@enumToInt(s)}) ++ m ++ style.ResetBgColor; + } +}; + +// +// private +// + +fn _join(comptime delim: []const u8, comptime xs: [][]const u8) []const u8 { + var buf: []const u8 = ""; + for (xs) |x,i| { + buf = buf ++ x; + if (i < xs.len-1) buf = buf ++ delim; + } + return buf; +} diff --git a/src/main.zig b/src/main.zig new file mode 100644 index 0000000000000000000000000000000000000000..e17c55cd37a7bf9aa1527052d843c34b2377686d --- /dev/null +++ b/src/main.zig @@ -0,0 +1,21 @@ +const std = @import("std"); + +const ansi = @import("./lib.zig"); + +pub fn main() anyerror!void { + std.debug.warn(comptime ansi.color.Fg(.Red, "All your codebase are belong to us.\n"), .{}); + std.debug.warn(comptime ansi.color.Fg(.Green, "All your codebase are belong to us.\n"), .{}); + std.debug.warn(comptime ansi.color.Fg(.Yellow, "All your codebase are belong to us.\n"), .{}); + std.debug.warn(comptime ansi.color.Fg(.Blue, "All your codebase are belong to us.\n"), .{}); + std.debug.warn(comptime ansi.color.Fg(.Magenta, "All your codebase are belong to us.\n"), .{}); + std.debug.warn(comptime ansi.color.Fg(.Cyan, "All your codebase are belong to us.\n"), .{}); + + std.debug.warn("\n", .{}); + + std.debug.warn(comptime ansi.color.Bg(.Red, "All your codebase are belong to us.\n"), .{}); + std.debug.warn(comptime ansi.color.Bg(.Green, "All your codebase are belong to us.\n"), .{}); + std.debug.warn(comptime ansi.color.Bg(.Yellow, "All your codebase are belong to us.\n"), .{}); + std.debug.warn(comptime ansi.color.Bg(.Blue, "All your codebase are belong to us.\n"), .{}); + std.debug.warn(comptime ansi.color.Bg(.Magenta, "All your codebase are belong to us.\n"), .{}); + std.debug.warn(comptime ansi.color.Bg(.Cyan, "All your codebase are belong to us.\n"), .{}); +} diff --git a/zig.mod b/zig.mod new file mode 100644 index 0000000000000000000000000000000000000000..2002e4392f93b9afdc69a6182624fb946d694641 --- /dev/null +++ b/zig.mod @@ -0,0 +1,3 @@ +id: s84v9o48ucb0xq0cmzq0cn433hgw0iaqztugja16h8bzxu3h +name: ansi +main: src/lib.zig