├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── build.zig ├── licenses.txt ├── src ├── lib.zig ├── main.zig └── test.zig └── zig.mod /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .zig-cache 2 | zig-out 3 | .zigmod 4 | deps.zig 5 | files.zig 6 | zigmod.lock 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Meghan Denny 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zig-ansi 2 | 3 | ![loc](https://sloc.xyz/github/nektro/zig-ansi) 4 | [![license](https://img.shields.io/github/license/nektro/zig-ansi.svg)](https://github.com/nektro/zig-ansi/blob/master/LICENSE) 5 | [![discord](https://img.shields.io/discord/551971034593755159.svg?logo=discord)](https://discord.gg/P6Y4zQC) 6 | [![nektro @ github sponsors](https://img.shields.io/badge/sponsors-nektro-purple?logo=github)](https://github.com/sponsors/nektro) 7 | [![Zig](https://img.shields.io/badge/Zig-0.14-f7a41d)](https://ziglang.org/) 8 | [![Zigmod](https://img.shields.io/badge/Zigmod-latest-f7a41d)](https://github.com/nektro/zigmod) 9 | 10 | ANSI utilities for CLI usage in Zig. 11 | 12 | ## Zig 13 | 14 | - https://ziglang.org/ 15 | - https://github.com/ziglang/zig 16 | - https://github.com/ziglang/zig/wiki/Community 17 | 18 | ## Getting Started 19 | 20 | Using https://github.com/nektro/zigmod, add a `git` type with a path of `https://github.com/nektro/zig-ansi`. 21 | 22 | ## Usage 23 | 24 | See `src/main.zig` or do `zig build run` to see examples. 25 | 26 | See `src/lib.zig` for source code. 27 | -------------------------------------------------------------------------------- /build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | pub fn build(b: *std.Build) void { 4 | const target = b.standardTargetOptions(.{}); 5 | const mode = b.option(std.builtin.Mode, "mode", "") orelse .Debug; 6 | const disable_llvm = b.option(bool, "disable_llvm", "use the non-llvm zig codegen") orelse false; 7 | 8 | const exe = b.addExecutable(.{ 9 | .name = "zig-ansi", 10 | .root_source_file = b.path("src/main.zig"), 11 | .target = target, 12 | .optimize = mode, 13 | }); 14 | exe.use_llvm = !disable_llvm; 15 | exe.use_lld = !disable_llvm; 16 | b.installArtifact(exe); 17 | 18 | const run_cmd = b.addRunArtifact(exe); 19 | run_cmd.step.dependOn(b.getInstallStep()); 20 | if (b.args) |args| { 21 | run_cmd.addArgs(args); 22 | } 23 | 24 | const run_step = b.step("run", "Run the app"); 25 | run_step.dependOn(&run_cmd.step); 26 | 27 | const tests = b.addTest(.{ 28 | .root_source_file = b.path("src/test.zig"), 29 | .target = target, 30 | .optimize = mode, 31 | }); 32 | tests.use_llvm = !disable_llvm; 33 | tests.use_lld = !disable_llvm; 34 | 35 | const run_test = b.addRunArtifact(tests); 36 | run_test.has_side_effects = true; 37 | 38 | const test_step = b.step("test", "Run all library tests"); 39 | test_step.dependOn(&run_test.step); 40 | } 41 | -------------------------------------------------------------------------------- /licenses.txt: -------------------------------------------------------------------------------- 1 | MIT: 2 | = https://spdx.org/licenses/MIT 3 | - This 4 | -------------------------------------------------------------------------------- /src/lib.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | pub const ascii = enum(u7) { 4 | NUL, 5 | SOH, 6 | STX, 7 | ETX, 8 | EOT, 9 | ENQ, 10 | ACK, 11 | BEL, 12 | BS, 13 | TAB, 14 | LF, 15 | VT, 16 | FF, 17 | CR, 18 | SO, 19 | SI, 20 | DLE, 21 | DC1, 22 | DC2, 23 | DC3, 24 | DC4, 25 | NAK, 26 | SYN, 27 | ETB, 28 | CAN, 29 | EM, 30 | SUB, 31 | ESC, 32 | FS, 33 | GS, 34 | RS, 35 | US, 36 | _, 37 | 38 | pub fn s(self: ascii) [1]u8 { 39 | return .{@intFromEnum(self)}; 40 | } 41 | }; 42 | 43 | pub const escape = struct { 44 | pub const SS2 = ascii.ESC.s() ++ "N"; 45 | pub const SS3 = ascii.ESC.s() ++ "O"; 46 | pub const DCS = ascii.ESC.s() ++ "P"; 47 | pub const CSI = ascii.ESC.s() ++ "["; 48 | pub const ST = ascii.ESC.s() ++ "\\"; 49 | pub const OSC = ascii.ESC.s() ++ "]"; 50 | pub const SOS = ascii.ESC.s() ++ "X"; 51 | pub const PM = ascii.ESC.s() ++ "^"; 52 | pub const APC = ascii.ESC.s() ++ "_"; 53 | pub const RIS = ascii.ESC.s() ++ "c"; 54 | }; 55 | 56 | fn make_csi_sequence(comptime c: []const u8, comptime x: anytype) []const u8 { 57 | return comptime escape.CSI ++ _join(";", arr_i_to_s(x)) ++ c; 58 | } 59 | 60 | fn arr_i_to_s(x: anytype) [][]const u8 { 61 | var res: [x.len][]const u8 = undefined; 62 | for (x, 0..) |item, i| { 63 | res[i] = std.fmt.comptimePrint("{}", .{item}); 64 | } 65 | return &res; 66 | } 67 | 68 | pub const csi = struct { 69 | pub fn CursorUp(comptime n: i32) []const u8 { 70 | return make_csi_sequence("A", .{n}); 71 | } 72 | pub fn CursorDown(comptime n: i32) []const u8 { 73 | return make_csi_sequence("B", .{n}); 74 | } 75 | pub fn CursorForward(comptime n: i32) []const u8 { 76 | return make_csi_sequence("C", .{n}); 77 | } 78 | pub fn CursorBack(comptime n: i32) []const u8 { 79 | return make_csi_sequence("D", .{n}); 80 | } 81 | pub fn CursorNextLine(comptime n: i32) []const u8 { 82 | return make_csi_sequence("E", .{n}); 83 | } 84 | pub fn CursorPrevLine(comptime n: i32) []const u8 { 85 | return make_csi_sequence("F", .{n}); 86 | } 87 | pub fn CursorHorzAbs(comptime n: i32) []const u8 { 88 | return make_csi_sequence("G", .{n}); 89 | } 90 | pub fn CursorPos(comptime n: i32, m: i32) []const u8 { 91 | return make_csi_sequence("H", .{ n, m }); 92 | } 93 | pub fn EraseInDisplay(comptime n: i32) []const u8 { 94 | return make_csi_sequence("J", .{n}); 95 | } 96 | pub fn EraseInLine(comptime n: i32) []const u8 { 97 | return make_csi_sequence("K", .{n}); 98 | } 99 | pub fn ScrollUp(comptime n: i32) []const u8 { 100 | return make_csi_sequence("S", .{n}); 101 | } 102 | pub fn ScrollDown(comptime n: i32) []const u8 { 103 | return make_csi_sequence("T", .{n}); 104 | } 105 | pub fn HorzVertPos(comptime n: i32, m: i32) []const u8 { 106 | return make_csi_sequence("f", .{ n, m }); 107 | } 108 | pub fn SGR(comptime ns: anytype) []const u8 { 109 | return make_csi_sequence("m", ns); 110 | } 111 | }; 112 | 113 | pub const style = struct { 114 | pub const ResetAll = csi.SGR(.{0}); 115 | 116 | pub const Bold = csi.SGR(.{1}); 117 | pub const Faint = csi.SGR(.{2}); 118 | pub const Italic = csi.SGR(.{3}); 119 | pub const Underline = csi.SGR(.{4}); 120 | pub const BlinkSlow = csi.SGR(.{5}); 121 | pub const BlinkFast = csi.SGR(.{6}); 122 | 123 | pub const ResetFont = csi.SGR(.{10}); 124 | pub const Font1 = csi.SGR(.{11}); 125 | pub const Font2 = csi.SGR(.{12}); 126 | pub const Font3 = csi.SGR(.{13}); 127 | pub const Font4 = csi.SGR(.{14}); 128 | pub const Font5 = csi.SGR(.{15}); 129 | pub const Font6 = csi.SGR(.{16}); 130 | pub const Font7 = csi.SGR(.{17}); 131 | pub const Font8 = csi.SGR(.{18}); 132 | pub const Font9 = csi.SGR(.{19}); 133 | 134 | pub const UnderlineDouble = csi.SGR(.{21}); 135 | pub const ResetIntensity = csi.SGR(.{22}); 136 | pub const ResetItalic = csi.SGR(.{23}); 137 | pub const ResetUnderline = csi.SGR(.{24}); 138 | pub const ResetBlink = csi.SGR(.{25}); 139 | 140 | pub const FgBlack = csi.SGR(.{30}); 141 | pub const FgRed = csi.SGR(.{31}); 142 | pub const FgGreen = csi.SGR(.{32}); 143 | pub const FgYellow = csi.SGR(.{33}); 144 | pub const FgBlue = csi.SGR(.{34}); 145 | pub const FgMagenta = csi.SGR(.{35}); 146 | pub const FgCyan = csi.SGR(.{36}); 147 | pub const FgWhite = csi.SGR(.{37}); 148 | // Fg8bit = func(n int) string { return csi.SGR(38, 5, n) } 149 | // Fg24bit = func(r, g, b int) string { return csi.SGR(38, 2, r, g, b) } 150 | pub const ResetFgColor = csi.SGR(.{39}); 151 | 152 | pub const BgBlack = csi.SGR(.{40}); 153 | pub const BgRed = csi.SGR(.{41}); 154 | pub const BgGreen = csi.SGR(.{42}); 155 | pub const BgYellow = csi.SGR(.{43}); 156 | pub const BgBlue = csi.SGR(.{44}); 157 | pub const BgMagenta = csi.SGR(.{45}); 158 | pub const BgCyan = csi.SGR(.{46}); 159 | pub const BgWhite = csi.SGR(.{47}); 160 | // Bg8bit = func(n int) string { return csi.SGR(48, 5, n) } 161 | // Bg24bit = func(r, g, b int) string { return csi.SGR(48, 2, r, g, b) } 162 | pub const ResetBgColor = csi.SGR(.{49}); 163 | 164 | pub const Framed = csi.SGR(.{51}); 165 | pub const Encircled = csi.SGR(.{52}); 166 | pub const Overlined = csi.SGR(.{53}); 167 | pub const ResetFrameEnci = csi.SGR(.{54}); 168 | pub const ResetOverlined = csi.SGR(.{55}); 169 | }; 170 | 171 | pub const color = struct { 172 | pub const Color = enum(u8) { 173 | Black, 174 | Red, 175 | Green, 176 | Yellow, 177 | Blue, 178 | Magenta, 179 | Cyan, 180 | White, 181 | }; 182 | 183 | pub fn Fg(s: Color, comptime m: []const u8) []const u8 { 184 | return csi.SGR(.{30 + @intFromEnum(s)}) ++ m ++ style.ResetFgColor; 185 | } 186 | 187 | pub fn Bg(s: Color, comptime m: []const u8) []const u8 { 188 | return csi.SGR(.{40 + @intFromEnum(s)}) ++ m ++ style.ResetBgColor; 189 | } 190 | 191 | pub fn Bold(comptime m: []const u8) []const u8 { 192 | return style.Bold ++ m ++ style.ResetIntensity; 193 | } 194 | 195 | pub fn Faint(comptime m: []const u8) []const u8 { 196 | return style.Faint ++ m ++ style.ResetIntensity; 197 | } 198 | 199 | pub fn Italic(comptime m: []const u8) []const u8 { 200 | return style.Italic ++ m ++ style.ResetItalic; 201 | } 202 | 203 | pub fn Underline(comptime m: []const u8) []const u8 { 204 | return style.Underline ++ m ++ style.ResetUnderline; 205 | } 206 | }; 207 | 208 | // 209 | // private 210 | // 211 | 212 | fn _join(comptime delim: []const u8, comptime xs: [][]const u8) []const u8 { 213 | var buf: []const u8 = ""; 214 | for (xs, 0..) |x, i| { 215 | buf = buf ++ x; 216 | if (i < xs.len - 1) buf = buf ++ delim; 217 | } 218 | return buf; 219 | } 220 | -------------------------------------------------------------------------------- /src/main.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const ansi = @import("./lib.zig"); 3 | 4 | pub fn main() anyerror!void { 5 | std.debug.print(ansi.color.Fg(.Red, "All your codebase are belong to us.\n"), .{}); 6 | std.debug.print(ansi.color.Fg(.Green, "All your codebase are belong to us.\n"), .{}); 7 | std.debug.print(ansi.color.Fg(.Yellow, "All your codebase are belong to us.\n"), .{}); 8 | std.debug.print(ansi.color.Fg(.Blue, "All your codebase are belong to us.\n"), .{}); 9 | std.debug.print(ansi.color.Fg(.Magenta, "All your codebase are belong to us.\n"), .{}); 10 | std.debug.print(ansi.color.Fg(.Cyan, "All your codebase are belong to us.\n"), .{}); 11 | 12 | std.debug.print("\n", .{}); 13 | 14 | std.debug.print(ansi.color.Bg(.Red, "All your codebase are belong to us.\n"), .{}); 15 | std.debug.print(ansi.color.Bg(.Green, "All your codebase are belong to us.\n"), .{}); 16 | std.debug.print(ansi.color.Bg(.Yellow, "All your codebase are belong to us.\n"), .{}); 17 | std.debug.print(ansi.color.Bg(.Blue, "All your codebase are belong to us.\n"), .{}); 18 | std.debug.print(ansi.color.Bg(.Magenta, "All your codebase are belong to us.\n"), .{}); 19 | std.debug.print(ansi.color.Bg(.Cyan, "All your codebase are belong to us.\n"), .{}); 20 | } 21 | -------------------------------------------------------------------------------- /src/test.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const ansi = @import("./lib.zig"); 3 | 4 | fn expectFmt(comptime actual: []const u8, expected: []const u8) !void { 5 | return std.testing.expectEqualSlices(u8, expected, actual); 6 | } 7 | 8 | test { 9 | try expectFmt( 10 | ansi.color.Fg(.Blue, "All your codebase"), 11 | &(.{ 27, '[', '3', '4', 'm' } ++ "All your codebase".* ++ .{ 27, '[', '3', '9', 'm' }), 12 | ); 13 | } 14 | test { 15 | try expectFmt( 16 | ansi.color.Bg(.Cyan, "All your codebase"), 17 | &(.{ 27, '[', '4', '6', 'm' } ++ "All your codebase".* ++ .{ 27, '[', '4', '9', 'm' }), 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /zig.mod: -------------------------------------------------------------------------------- 1 | id: s84v9o48ucb0xq0cmzq0cn433hgw0iaqztugja16h8bzxu3h 2 | name: ansi 3 | main: src/lib.zig 4 | license: MIT 5 | dependencies: 6 | --------------------------------------------------------------------------------