init :)
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
ui.json
|
||||||
|
.zig-cache/
|
||||||
|
zig-out/
|
||||||
52
build.zig
Normal file
52
build.zig
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
const target = b.standardTargetOptions(.{});
|
||||||
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
|
const mod = b.addModule("zig_server_documention", .{
|
||||||
|
.root_source_file = b.path("src/root.zig"),
|
||||||
|
.target = target,
|
||||||
|
});
|
||||||
|
|
||||||
|
const exe = b.addExecutable(.{
|
||||||
|
.name = "zig_server_documention",
|
||||||
|
.root_module = b.createModule(.{
|
||||||
|
.root_source_file = b.path("src/main.zig"),
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.imports = &.{
|
||||||
|
.{ .name = "zig_server_documention", .module = mod },
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
b.installArtifact(exe);
|
||||||
|
|
||||||
|
const run_step = b.step("run", "Run the app");
|
||||||
|
|
||||||
|
const run_cmd = b.addRunArtifact(exe);
|
||||||
|
run_step.dependOn(&run_cmd.step);
|
||||||
|
|
||||||
|
run_cmd.step.dependOn(b.getInstallStep());
|
||||||
|
|
||||||
|
if (b.args) |args| {
|
||||||
|
run_cmd.addArgs(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mod_tests = b.addTest(.{
|
||||||
|
.root_module = mod,
|
||||||
|
});
|
||||||
|
|
||||||
|
const run_mod_tests = b.addRunArtifact(mod_tests);
|
||||||
|
|
||||||
|
const exe_tests = b.addTest(.{
|
||||||
|
.root_module = exe.root_module,
|
||||||
|
});
|
||||||
|
|
||||||
|
const run_exe_tests = b.addRunArtifact(exe_tests);
|
||||||
|
|
||||||
|
const test_step = b.step("test", "Run tests");
|
||||||
|
test_step.dependOn(&run_mod_tests.step);
|
||||||
|
test_step.dependOn(&run_exe_tests.step);
|
||||||
|
}
|
||||||
12
build.zig.zon
Normal file
12
build.zig.zon
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
.{
|
||||||
|
.name = .zig_server_documention,
|
||||||
|
.version = "0.0.0",
|
||||||
|
.fingerprint = 0xa4a5c99d1a862ab7, // Changing this has security and trust implications.
|
||||||
|
.minimum_zig_version = "0.16.0",
|
||||||
|
.dependencies = .{},
|
||||||
|
.paths = .{
|
||||||
|
"build.zig",
|
||||||
|
"build.zig.zon",
|
||||||
|
"src",
|
||||||
|
},
|
||||||
|
}
|
||||||
37
example.json
Normal file
37
example.json
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"ascii_art": " ╔═══════╗\n ║ ╸╸╸╸ @║\n ║│╳╳╳╳│*║\n ║│╳╳╳╳│.║\n ╟┤╳╳╳╳├╌╢\n ║│╳╳╳╳│ ║\n ║│╳╳╳╳│ ║\n ╚╧════╧═╝",
|
||||||
|
"ip": "10.0.0.9",
|
||||||
|
"name": "truenas",
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"name": "git",
|
||||||
|
"ports": [
|
||||||
|
3069
|
||||||
|
],
|
||||||
|
"description": "services for running my forge"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lang tools",
|
||||||
|
"ports": [
|
||||||
|
8081
|
||||||
|
],
|
||||||
|
"description": "spell checker so i dont have to download the 300GB of the english language"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ascii_art": " ╔══════╤══════╤══════╤══════╤══════╗\n ║╳╳╳╳╳@╏╳╳╳╳╳@╏╳╳╳╳╳@╏╳╳╳╳╳@╏╸=[]@*║\n ╚══════╧══════╧══════╧══════╧══════╝",
|
||||||
|
"ip": "10.0.0.10",
|
||||||
|
"name": "the big boy",
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"name": "minecraft",
|
||||||
|
"ports": [
|
||||||
|
25565
|
||||||
|
],
|
||||||
|
"description": "26.2 minecraft server"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
59
readme.md
Normal file
59
readme.md
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
# Server documentation tool, ill work out a fun name later
|
||||||
|
|
||||||
|
This is fun small tool used to document your homelab its very simplistic and should be used more as a fun show case and not as real documentation.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### how to use it
|
||||||
|
|
||||||
|
first compile the project with zig 0.16.0,
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ zig build
|
||||||
|
```
|
||||||
|
|
||||||
|
then its time to create your UI, create a json file called what ever you want and follow the schema provided ([`ui.schema.json`](ui.schema.json))
|
||||||
|
|
||||||
|
|
||||||
|
you file should look something like this ([`example.json`](example.json))
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"ascii_art": " ╔═══════╗\n ║ ╸╸╸╸ @║\n ║│╳╳╳╳│*║\n ║│╳╳╳╳│.║\n ╟┤╳╳╳╳├╌╢\n ║│╳╳╳╳│ ║\n ║│╳╳╳╳│ ║\n ╚╧════╧═╝",
|
||||||
|
"ip": "10.0.0.9",
|
||||||
|
"name": "truenas",
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"name": "git",
|
||||||
|
"ports": [
|
||||||
|
3069
|
||||||
|
],
|
||||||
|
"description": "services for running my forge"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lang tools",
|
||||||
|
"ports": [
|
||||||
|
8081
|
||||||
|
],
|
||||||
|
"description": "spell checker so i dont have to download the 300GB of the english language"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ascii_art": " ╔══════╤══════╤══════╤══════╤══════╗\n ║╳╳╳╳╳@╏╳╳╳╳╳@╏╳╳╳╳╳@╏╳╳╳╳╳@╏╸=[]@*║\n ╚══════╧══════╧══════╧══════╧══════╝",
|
||||||
|
"ip": "10.0.0.10",
|
||||||
|
"name": "the big boy",
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"name": "minecraft",
|
||||||
|
"ports": [
|
||||||
|
25565
|
||||||
|
],
|
||||||
|
"description": "26.2 minecraft server"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally to run pass the *relative* path of the json to the executable located in [`zig-out/bin/`](zig-out/bin/).
|
||||||
BIN
res/example_image.png
Normal file
BIN
res/example_image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
169
src/ansi.zig
Normal file
169
src/ansi.zig
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Colour = @import("colour.zig").Colour;
|
||||||
|
|
||||||
|
pub const colour_set_string_fg_fmt = "\x1B[38;2;{d};{d};{d}m";
|
||||||
|
pub const colour_set_string_bg_fmt = "\x1B[48;2;{d};{d};{d}m";
|
||||||
|
|
||||||
|
/// Enable terminal raw mode, return previous configuration.
|
||||||
|
pub fn enableRawMode() !std.os.linux.termios {
|
||||||
|
const orig_termios = try std.posix.tcgetattr(std.posix.STDIN_FILENO);
|
||||||
|
var termios = orig_termios;
|
||||||
|
termios.lflag.ECHO = false; // don't echo input characters
|
||||||
|
termios.lflag.ICANON = false; // read input byte-by-byte instead of line-by-line
|
||||||
|
termios.lflag.ISIG = false; // disable Ctrl-C and Ctrl-Z signals
|
||||||
|
termios.iflag.IXON = false; // disable Ctrl-S and Ctrl-Q signals
|
||||||
|
termios.lflag.IEXTEN = false; // disable Ctrl-V
|
||||||
|
termios.iflag.ICRNL = false; // CTRL-M being read as CTRL-J
|
||||||
|
termios.iflag.BRKINT = false; // break conditions cause SIGINT signal
|
||||||
|
termios.iflag.INPCK = false; // disable parity checking (obsolete?)
|
||||||
|
termios.iflag.ISTRIP = false; // disable stripping of 8th bit
|
||||||
|
termios.cflag.CSIZE = .CS8; // set character size to 8 bits
|
||||||
|
termios.cc[@intFromEnum(std.os.linux.V.MIN)] = 0; // Return immediately when any bytes are available
|
||||||
|
termios.cc[@intFromEnum(std.os.linux.V.TIME)] = 1; // Wait up to 0.1 seconds for input
|
||||||
|
// termios.oflag.OPOST = false; // disable output processing
|
||||||
|
|
||||||
|
try std.posix.tcsetattr(std.posix.STDIN_FILENO, .FLUSH, termios);
|
||||||
|
|
||||||
|
return orig_termios;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Disable terminal raw mode by restoring the saved configuration.
|
||||||
|
pub fn disableRawMode(termios: std.os.linux.termios) void {
|
||||||
|
// force termios back in to a useable state
|
||||||
|
var cpy = termios;
|
||||||
|
cpy.lflag.ICANON = true;
|
||||||
|
cpy.lflag.ECHO = true;
|
||||||
|
cpy.lflag.ISIG = true;
|
||||||
|
cpy.iflag.IXON = true;
|
||||||
|
cpy.lflag.IEXTEN = true;
|
||||||
|
cpy.iflag.ICRNL = true;
|
||||||
|
cpy.iflag.BRKINT = false;
|
||||||
|
cpy.iflag.INPCK = false;
|
||||||
|
cpy.iflag.ISTRIP = false;
|
||||||
|
cpy.cflag.CSIZE = .CS8;
|
||||||
|
cpy.oflag.OPOST = true; // disable output processing
|
||||||
|
cpy.cc[@intFromEnum(std.os.linux.V.MIN)] = 1;
|
||||||
|
cpy.cc[@intFromEnum(std.os.linux.V.TIME)] = 0;
|
||||||
|
std.posix.tcsetattr(std.posix.STDIN_FILENO, .FLUSH, cpy) catch @panic("Disabling raw mode failed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eraseInLine(writer: *std.Io.Writer) !void {
|
||||||
|
_ = try writer.write("\x1b[K");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clearScreen(writer: *std.Io.Writer) !void {
|
||||||
|
_ = try writer.write("\x1b[2J");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn showCursor(writer: *std.Io.Writer) !void {
|
||||||
|
_ = try writer.write("\x1b[?25h");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hideCursor(writer: *std.Io.Writer) !void {
|
||||||
|
_ = try writer.write("\x1b[?25l");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn startBold(writer: *std.Io.Writer) !void {
|
||||||
|
_ = try writer.write("\x1b[1m");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn endBold(writer: *std.Io.Writer) !void {
|
||||||
|
_ = try writer.write("\x1b[22m");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn startDim(writer: *std.Io.Writer) !void {
|
||||||
|
_ = try writer.write("\x1b[2m");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn endDim(writer: *std.Io.Writer) !void {
|
||||||
|
_ = try writer.write("\x1b[22m");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn startItalic(writer: *std.Io.Writer) !void {
|
||||||
|
_ = try writer.write("\x1b[3m");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn endItalic(writer: *std.Io.Writer) !void {
|
||||||
|
_ = try writer.write("\x1b[23m");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn startUnderline(writer: *std.Io.Writer) !void {
|
||||||
|
_ = try writer.write("\x1b[4m");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn endUnderline(writer: *std.Io.Writer) !void {
|
||||||
|
_ = try writer.write("\x1b[24m");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn startBlinking(writer: *std.Io.Writer) !void {
|
||||||
|
_ = try writer.write("\x1b[5m");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn endBlinking(writer: *std.Io.Writer) !void {
|
||||||
|
_ = try writer.write("\x1b[25m");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn startInverse(writer: *std.Io.Writer) !void {
|
||||||
|
_ = try writer.write("\x1b[7m");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn endInverse(writer: *std.Io.Writer) !void {
|
||||||
|
_ = try writer.write("\x1b[27m");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn startHidden(writer: *std.Io.Writer) !void {
|
||||||
|
_ = try writer.write("\x1b[8m");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn endHidden(writer: *std.Io.Writer) !void {
|
||||||
|
_ = try writer.write("\x1b[28m");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn startStrikethrough(writer: *std.Io.Writer) !void {
|
||||||
|
_ = try writer.write("\x1b[9m");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn endStrikethrough(writer: *std.Io.Writer) !void {
|
||||||
|
_ = try writer.write("\x1b[29m");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn endMode(writer: *std.Io.Writer) !void {
|
||||||
|
_ = try writer.write("\x1b[m");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn returnToHome(writer: *std.Io.Writer) !void {
|
||||||
|
// try self.appendStr("\x1bOH");
|
||||||
|
try placeCursorAt(writer, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn placeCursorAt(writer: *std.Io.Writer, x: usize, y: usize) !void {
|
||||||
|
try writer.print("\x1b[{};{}H", .{ y, x });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn startColour(writer: *std.Io.Writer, foreground: Colour, background: Colour) !void {
|
||||||
|
try writer.print(
|
||||||
|
colour_set_string_fg_fmt ++ colour_set_string_bg_fmt,
|
||||||
|
.{
|
||||||
|
foreground.r, foreground.b, foreground.g,
|
||||||
|
background.r, background.b, background.g,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn startFgColour(writer: *std.Io.Writer, colour: Colour) !void {
|
||||||
|
try writer.print(
|
||||||
|
colour_set_string_fg_fmt,
|
||||||
|
.{
|
||||||
|
colour.r, colour.b, colour.g,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn startBgColour(writer: *std.Io.Writer, colour: Colour) !void {
|
||||||
|
try writer.print(
|
||||||
|
colour_set_string_bg_fmt,
|
||||||
|
.{
|
||||||
|
colour.r, colour.b, colour.g,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
199
src/colour.zig
Normal file
199
src/colour.zig
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
/// colour type
|
||||||
|
pub const Colour = struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
r: u8,
|
||||||
|
g: u8,
|
||||||
|
b: u8,
|
||||||
|
|
||||||
|
/// inits the struct with a custom colour
|
||||||
|
pub fn custom(r: u8, g: u8, b: u8) Self {
|
||||||
|
return Self{ .r = r, .g = g, .b = b };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// inits the struct with a red colour
|
||||||
|
pub fn red() Self {
|
||||||
|
return Self{ .r = 255, .g = 0, .b = 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// inits the struct with a orange colour
|
||||||
|
pub fn orange() Self {
|
||||||
|
return Self{ .r = 255, .g = 128, .b = 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// inits the struct with a yellow colour
|
||||||
|
pub fn yellow() Self {
|
||||||
|
return Self{ .r = 255, .g = 255, .b = 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// inits the struct with a gold colour
|
||||||
|
pub fn gold() Self {
|
||||||
|
return Self{ .r = 255, .g = 200, .b = 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// inits the struct with a lightGreen colour
|
||||||
|
pub fn lightGreen() Self {
|
||||||
|
return Self{ .r = 128, .g = 255, .b = 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// inits the struct with a green colour
|
||||||
|
pub fn green() Self {
|
||||||
|
return Self{ .r = 0, .g = 255, .b = 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// inits the struct with a cyan colour
|
||||||
|
pub fn cyan() Self {
|
||||||
|
return Self{ .r = 0, .g = 255, .b = 128 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// inits the struct with a turquoise colour
|
||||||
|
pub fn turquoise() Self {
|
||||||
|
return Self{ .r = 0, .g = 255, .b = 190 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// inits the struct with a lightBlue colour
|
||||||
|
pub fn lightBlue() Self {
|
||||||
|
return Self{ .r = 0, .g = 128, .b = 255 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// inits the struct with a blue colour
|
||||||
|
pub fn blue() Self {
|
||||||
|
return Self{ .r = 0, .g = 0, .b = 255 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// inits the struct with a darkPurple colour
|
||||||
|
pub fn darkPurple() Self {
|
||||||
|
return Self{ .r = 128, .g = 0, .b = 255 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// inits the struct with a purple colour
|
||||||
|
pub fn purple() Self {
|
||||||
|
return Self{ .r = 170, .g = 0, .b = 255 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// inits the struct with a lightPurple colour
|
||||||
|
pub fn lightPurple() Self {
|
||||||
|
return Self{ .r = 196, .g = 78, .b = 255 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// inits the struct with a magenta colour
|
||||||
|
pub fn magenta() Self {
|
||||||
|
return Self{ .r = 255, .g = 0, .b = 255 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// inits the struct with a pink colour
|
||||||
|
pub fn pink() Self {
|
||||||
|
return Self{ .r = 255, .g = 0, .b = 128 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// inits the struct with a peach colour
|
||||||
|
pub fn peach() Self {
|
||||||
|
return Self{ .r = 255, .g = 158, .b = 158 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// inits the struct with a black colour
|
||||||
|
pub fn black() Self {
|
||||||
|
return Self{ .r = 0, .g = 0, .b = 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// inits the struct with a white colour
|
||||||
|
pub fn white() Self {
|
||||||
|
return Self{ .r = 255, .g = 255, .b = 255 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// inits the struct with a grey colour
|
||||||
|
pub fn grey() Self {
|
||||||
|
return Self{ .r = 128, .g = 128, .b = 128 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// inits the struct with a greyScale colour
|
||||||
|
pub fn greyScale(scale: u8) Self {
|
||||||
|
// 255 max
|
||||||
|
return Self{ .r = scale, .g = scale, .b = scale };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// this is the background colour of the defualt windows terminal
|
||||||
|
pub fn windowsTerminalBackground() Self {
|
||||||
|
return greyScale(12);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// this is the colour of the defualt windows terminal front
|
||||||
|
pub fn windowsTerminalFont() Self {
|
||||||
|
return greyScale(204);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// point must be an unsigned number type
|
||||||
|
pub fn pointToColour(point: anytype) Colour {
|
||||||
|
const normed_point_hue: u16 = @as(u16, @intFromFloat((@as(f32, @floatFromInt(point)) / @as(f32, @floatFromInt(std.math.maxInt(@TypeOf(point))))) * 255 * 5)) + 255;
|
||||||
|
const normed_point_rgb: u8 = @intCast((normed_point_hue + 1) % 256);
|
||||||
|
|
||||||
|
if (normed_point_hue <= 255 * 2) { //count up
|
||||||
|
return custom(255, normed_point_rgb, 0);
|
||||||
|
}
|
||||||
|
// 0, 255, 0, 255*3
|
||||||
|
if (normed_point_hue <= 255 * 3) { // count down
|
||||||
|
return custom(255 - normed_point_rgb, 255, 0);
|
||||||
|
}
|
||||||
|
// 0, 255, 255, 255*4
|
||||||
|
if (normed_point_hue <= 255 * 4) { // count up
|
||||||
|
return custom(0, 255, normed_point_rgb);
|
||||||
|
}
|
||||||
|
// 0, 0, 255, 255*5
|
||||||
|
if (normed_point_hue <= 255 * 5) { // count down
|
||||||
|
return custom(0, 255 - normed_point_rgb, 255);
|
||||||
|
}
|
||||||
|
// 255, 0, 255, 255*6
|
||||||
|
if (normed_point_hue <= 255 * 6) { // count up
|
||||||
|
return custom(normed_point_rgb, 0, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Colour.white();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rangeToColour(start: usize, end: usize, point: usize) Colour {
|
||||||
|
const delta = end - start;
|
||||||
|
const shifted_point: usize = point - start;
|
||||||
|
// wrapping mul to insure that this will never overflow
|
||||||
|
const normed_point_pos: usize = (std.math.maxInt(usize) / delta) *% shifted_point;
|
||||||
|
return pointToColour(normed_point_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// this will return a set colour based on the usize number
|
||||||
|
/// how ever at at point it will start to be random
|
||||||
|
pub fn usizeToColour(number: usize) Self {
|
||||||
|
return switch (number) {
|
||||||
|
0 => red(),
|
||||||
|
1 => orange(),
|
||||||
|
2 => yellow(),
|
||||||
|
3 => gold(),
|
||||||
|
4 => lightGreen(),
|
||||||
|
5 => green(),
|
||||||
|
6 => cyan(),
|
||||||
|
7 => turquoise(),
|
||||||
|
8 => lightBlue(),
|
||||||
|
9 => blue(),
|
||||||
|
10 => darkPurple(),
|
||||||
|
11 => purple(),
|
||||||
|
12 => lightPurple(),
|
||||||
|
13 => magenta(),
|
||||||
|
14 => pink(),
|
||||||
|
15 => peach(),
|
||||||
|
else => random(), // just make a random colour
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns a random colour
|
||||||
|
pub fn random() Self {
|
||||||
|
const static = struct {
|
||||||
|
var prng = std.rand.DefaultPrng.init(69420);
|
||||||
|
};
|
||||||
|
const rand = static.prng.random();
|
||||||
|
return custom(
|
||||||
|
rand.int(u8),
|
||||||
|
rand.int(u8),
|
||||||
|
rand.int(u8),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
439
src/main.zig
Normal file
439
src/main.zig
Normal file
@@ -0,0 +1,439 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const Io = std.Io;
|
||||||
|
const ansi = @import("ansi.zig");
|
||||||
|
const keys = @import("scan_codes.zig");
|
||||||
|
const zig_server_documention = @import("zig_server_documention");
|
||||||
|
|
||||||
|
const Service = struct {
|
||||||
|
name: []const u8,
|
||||||
|
ports: []const u16,
|
||||||
|
description: []const u8,
|
||||||
|
|
||||||
|
const none = Service{
|
||||||
|
.name = "None",
|
||||||
|
.ports = &.{0},
|
||||||
|
.description = "",
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const Server = struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
ascii_art: []const u8,
|
||||||
|
ip: []const u8,
|
||||||
|
services: []const Service,
|
||||||
|
name: []const u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
const UI = struct {
|
||||||
|
const Self = @This();
|
||||||
|
const Lists = enum {
|
||||||
|
servers,
|
||||||
|
services,
|
||||||
|
};
|
||||||
|
|
||||||
|
writer: *std.Io.Writer,
|
||||||
|
reader: *std.Io.Reader,
|
||||||
|
|
||||||
|
servers: []const Server,
|
||||||
|
current_server_index: usize = 0,
|
||||||
|
current_service_index: usize = 0,
|
||||||
|
|
||||||
|
active_list: Lists = .servers,
|
||||||
|
|
||||||
|
const text_box_width = 54;
|
||||||
|
const text_box_heading = " ┌─{s:-<41}─port:{d:-<5}─┐ ";
|
||||||
|
const text_box_footer = " └──────────────────────────────────────────────────────┘ ";
|
||||||
|
|
||||||
|
const ui =
|
||||||
|
\\
|
||||||
|
\\ ╔══════════════════════════════════════╦═══════════════════════════════════════════════════════════╗
|
||||||
|
\\ ║ ║ name : {s: <51}║
|
||||||
|
\\ ║ ║ ip : {s: <53}║
|
||||||
|
\\ ║ ╟───────────────────────────────────────────────────────────╢
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ║ ║ ║
|
||||||
|
\\ ╚══════════════════════════════════════╩═══════════════════════════════════════════════════════════╝
|
||||||
|
\\
|
||||||
|
;
|
||||||
|
|
||||||
|
// returns how many lines were written
|
||||||
|
pub fn drawTextAt(self: Self, offset_x: u16, offset_y: u16, wrap_length: u16, text: []const u8) !usize {
|
||||||
|
var itter = std.mem.splitScalar(u8, text, '\n');
|
||||||
|
|
||||||
|
var line_index: usize = 0;
|
||||||
|
while (itter.next()) |line| {
|
||||||
|
var utf8_view = try std.unicode.Utf8View.init(line);
|
||||||
|
var line_itter = utf8_view.iterator();
|
||||||
|
|
||||||
|
var i: usize = 0;
|
||||||
|
try ansi.placeCursorAt(self.writer, offset_x, offset_y + line_index);
|
||||||
|
while (line_itter.nextCodepointSlice()) |code_point| {
|
||||||
|
_ = try self.writer.write(code_point);
|
||||||
|
if (i >= wrap_length) {
|
||||||
|
try ansi.placeCursorAt(self.writer, offset_x, offset_y + line_index);
|
||||||
|
line_index += 1;
|
||||||
|
i = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
line_index += 1;
|
||||||
|
}
|
||||||
|
try self.writer.flush();
|
||||||
|
|
||||||
|
return line_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// might need to fix utf8 wrapping in this
|
||||||
|
fn drawServiceBox(
|
||||||
|
self: Self,
|
||||||
|
offset_x: u16,
|
||||||
|
offset_y: u16,
|
||||||
|
service: Service,
|
||||||
|
min_height: u16,
|
||||||
|
) !usize {
|
||||||
|
var itter = std.mem.splitScalar(u8, service.description, '\n');
|
||||||
|
|
||||||
|
try ansi.placeCursorAt(self.writer, offset_x, offset_y);
|
||||||
|
try self.writer.print(text_box_heading, .{ service.name, service.ports[0] });
|
||||||
|
|
||||||
|
var line_index: usize = 1;
|
||||||
|
while (itter.next()) |line| {
|
||||||
|
const loops = @divFloor(line.len, text_box_width);
|
||||||
|
|
||||||
|
for (0..loops) |i| {
|
||||||
|
try ansi.placeCursorAt(self.writer, offset_x, offset_y + line_index);
|
||||||
|
try self.writer.print(" │{s}│ ", .{line[i * text_box_width .. (i + 1) * text_box_width]});
|
||||||
|
line_index += 1;
|
||||||
|
}
|
||||||
|
try ansi.placeCursorAt(self.writer, offset_x, offset_y + line_index);
|
||||||
|
try self.writer.print(" │{s: <54}│ ", .{line[loops * text_box_width ..]});
|
||||||
|
line_index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (0..min_height -| line_index) |_| {
|
||||||
|
try ansi.placeCursorAt(self.writer, offset_x, offset_y + line_index);
|
||||||
|
try self.writer.print(" │{s: <54}│ ", .{" "});
|
||||||
|
line_index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
try ansi.placeCursorAt(self.writer, offset_x, offset_y + line_index);
|
||||||
|
_ = try self.writer.write(text_box_footer);
|
||||||
|
try self.writer.flush();
|
||||||
|
|
||||||
|
return line_index + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getCurrentServer(self: Self) Server {
|
||||||
|
return self.servers[self.current_server_index];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(self: Self) !void {
|
||||||
|
try self.writer.print(ui, .{ self.getCurrentServer().name, self.getCurrentServer().ip });
|
||||||
|
|
||||||
|
var y_offset: u16 = 3;
|
||||||
|
for (self.servers, 0..) |server, i| {
|
||||||
|
if (i == self.current_server_index) try ansi.startInverse(self.writer);
|
||||||
|
const lines_drawn = try self.drawTextAt(3, y_offset, 38, server.ascii_art);
|
||||||
|
y_offset += @intCast(lines_drawn);
|
||||||
|
try ansi.endMode(self.writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// render services
|
||||||
|
y_offset = 6;
|
||||||
|
const x_offset = 42;
|
||||||
|
for (self.getCurrentServer().services, 0..) |service, i| {
|
||||||
|
if (i == self.current_service_index and self.active_list == .services) try ansi.startInverse(self.writer);
|
||||||
|
const lines_drawn = try self.drawServiceBox(x_offset, y_offset, service, 4);
|
||||||
|
y_offset += @intCast(lines_drawn);
|
||||||
|
try ansi.endMode(self.writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn addWrapping(value_to_wrap: *usize, wrap: usize, value_to_add: isize) void {
|
||||||
|
if (@as(isize, @intCast(value_to_wrap.*)) + value_to_add < 0) {
|
||||||
|
value_to_wrap.* = wrap - 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (@as(isize, @intCast(value_to_wrap.*)) + value_to_add >= @as(isize, @intCast(wrap))) {
|
||||||
|
value_to_wrap.* = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_to_wrap.* = @intCast(@as(isize, @intCast(value_to_wrap.*)) + value_to_add);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn increamentActiveList(self: *Self, by: isize) void {
|
||||||
|
switch (self.active_list) {
|
||||||
|
.servers => addWrapping(&self.current_server_index, self.servers.len, by),
|
||||||
|
.services => addWrapping(&self.current_service_index, self.getCurrentServer().services.len, by),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handleInput(self: *Self, input: enum {
|
||||||
|
up,
|
||||||
|
down,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
}) void {
|
||||||
|
switch (input) {
|
||||||
|
.up => self.increamentActiveList(-1),
|
||||||
|
.down => self.increamentActiveList(1),
|
||||||
|
.left => {
|
||||||
|
switch (self.active_list) {
|
||||||
|
.servers => {},
|
||||||
|
.services => self.active_list = .servers,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.right => {
|
||||||
|
switch (self.active_list) {
|
||||||
|
.servers => self.active_list = .services,
|
||||||
|
.services => {},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn main(init: std.process.Init) !void {
|
||||||
|
|
||||||
|
// In order to do I/O operations need an `Io` instance.
|
||||||
|
const io = init.io;
|
||||||
|
|
||||||
|
// Stdout is for the actual output of your application, for example if you
|
||||||
|
// are implementing gzip, then only the compressed bytes should be sent to
|
||||||
|
// stdout, not any debugging messages.
|
||||||
|
var stdout_buffer: [1024]u8 = undefined;
|
||||||
|
var stdin_buffer: [1024]u8 = undefined;
|
||||||
|
// var stderr_buffer: [1024]u8 = undefined;
|
||||||
|
|
||||||
|
var stdin_file_reader: Io.File.Reader = .init(.stdin(), io, &stdin_buffer);
|
||||||
|
var stdout_file_writer: Io.File.Writer = .init(.stdout(), io, &stdout_buffer);
|
||||||
|
// var stderr_file_writer: Io.File.Writer = .init(.stderr(), io, &stderr_buffer);
|
||||||
|
const stdout_writer = &stdout_file_writer.interface;
|
||||||
|
const stdin_reader = &stdin_file_reader.interface;
|
||||||
|
|
||||||
|
// var file_buffer: [1024]u8 = undefined;
|
||||||
|
// const cwd = std.Io.Dir.cwd();
|
||||||
|
// const file = try cwd.createFile(io, "ui.json", .{});
|
||||||
|
// var file_writer = file.writer(io, &file_buffer);
|
||||||
|
// var json = std.json.Stringify{ .writer = &file_writer.interface };
|
||||||
|
// try json.write(ui.servers);
|
||||||
|
// try file_writer.flush();
|
||||||
|
// file.close(io);
|
||||||
|
|
||||||
|
var args = init.minimal.args.iterate();
|
||||||
|
const cwd_path = args.next() orelse {
|
||||||
|
std.debug.print("please enter path to the json\n", .{});
|
||||||
|
return error.no_file;
|
||||||
|
};
|
||||||
|
_ = cwd_path;
|
||||||
|
const file_path = args.next() orelse {
|
||||||
|
std.debug.print("please enter path to the json\n", .{});
|
||||||
|
return error.no_file;
|
||||||
|
};
|
||||||
|
std.debug.print("path : {s}\n", .{file_path});
|
||||||
|
|
||||||
|
const cwd = std.Io.Dir.cwd();
|
||||||
|
const file = try cwd.readFileAlloc(io, file_path, init.gpa, .unlimited);
|
||||||
|
|
||||||
|
_ = try stdout_writer.write(file_path);
|
||||||
|
|
||||||
|
const servers = try std.json.parseFromSlice([]Server, init.gpa, file, .{ .allocate = .alloc_always });
|
||||||
|
defer init.gpa.free(file);
|
||||||
|
defer servers.deinit();
|
||||||
|
|
||||||
|
var ui = UI{
|
||||||
|
.reader = stdin_reader,
|
||||||
|
.writer = stdout_writer,
|
||||||
|
// .servers = &.{
|
||||||
|
// Server{
|
||||||
|
// .ascii_art =
|
||||||
|
// \\ ╔═══════╗
|
||||||
|
// \\ ║ ╸╸╸╸ @║
|
||||||
|
// \\ ║│╳╳╳╳│*║
|
||||||
|
// \\ ║│╳╳╳╳│.║
|
||||||
|
// \\ ╟┤╳╳╳╳├╌╢
|
||||||
|
// \\ ║│╳╳╳╳│ ║
|
||||||
|
// \\ ║│╳╳╳╳│ ║
|
||||||
|
// \\ ╚╧════╧═╝
|
||||||
|
// ,
|
||||||
|
// .ip = "10.0.0.9",
|
||||||
|
// .name = "the docs",
|
||||||
|
// .services = &.{
|
||||||
|
// Service{
|
||||||
|
// .name = "gitea",
|
||||||
|
// .ports = &.{
|
||||||
|
// 3069,
|
||||||
|
// },
|
||||||
|
// .description = "services for running my forge",
|
||||||
|
// },
|
||||||
|
// Service{
|
||||||
|
// .name = "lang tools",
|
||||||
|
// .ports = &.{
|
||||||
|
// 8081,
|
||||||
|
// },
|
||||||
|
// .description = "spell checker so i dont have to download the 300GB of the english language",
|
||||||
|
// },
|
||||||
|
// Service{
|
||||||
|
// .name = "miniflux",
|
||||||
|
// .ports = &.{
|
||||||
|
// 3067,
|
||||||
|
// },
|
||||||
|
// .description = "rss feed reader, \n-ratfactor\n-jordanhay\n- N-O-D-E\nlowtechmagazine",
|
||||||
|
// },
|
||||||
|
// Service{
|
||||||
|
// .name = "netalert",
|
||||||
|
// .ports = &.{
|
||||||
|
// 1254,
|
||||||
|
// },
|
||||||
|
// .description = "fing alternative",
|
||||||
|
// },
|
||||||
|
// Service{
|
||||||
|
// .name = "nginx reverse proxy manager",
|
||||||
|
// .ports = &.{
|
||||||
|
// 81,
|
||||||
|
// 80,
|
||||||
|
// 443,
|
||||||
|
// },
|
||||||
|
// .description = "handling ssl certs for the network",
|
||||||
|
// },
|
||||||
|
// Service{
|
||||||
|
// .name = "silver bullet",
|
||||||
|
// .ports = &.{
|
||||||
|
// 3056,
|
||||||
|
// },
|
||||||
|
// .description = "for multi device note taking",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// Server{
|
||||||
|
// .ascii_art =
|
||||||
|
// \\ ╔══════╤══════╤══════╤══════╤══════╗
|
||||||
|
// \\ ║╳╳╳╳╳@╏╳╳╳╳╳@╏╳╳╳╳╳@╏╳╳╳╳╳@╏╸=[]@*║
|
||||||
|
// \\ ╚══════╧══════╧══════╧══════╧══════╝
|
||||||
|
// ,
|
||||||
|
// .ip = "10.0.0.29",
|
||||||
|
// .name = "the edmund fitzgerald",
|
||||||
|
// .services = &.{
|
||||||
|
// Service{
|
||||||
|
// .name = "minecraft survival",
|
||||||
|
// .ports = &.{
|
||||||
|
// 25565,
|
||||||
|
// },
|
||||||
|
// .description = "minecraft server 26.2, french village one",
|
||||||
|
// },
|
||||||
|
// Service{
|
||||||
|
// .name = "minecraft creative",
|
||||||
|
// .ports = &.{
|
||||||
|
// 25566,
|
||||||
|
// },
|
||||||
|
// .description = "minecraft server 26.2, for creative building",
|
||||||
|
// },
|
||||||
|
// Service{
|
||||||
|
// .name = "vintage story",
|
||||||
|
// .ports = &.{
|
||||||
|
// 42420,
|
||||||
|
// },
|
||||||
|
// .description = "vintage story server",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// Server{
|
||||||
|
// .ascii_art =
|
||||||
|
// \\ ╔══════╤══════╤══════╤══════╤══════╗
|
||||||
|
// \\ ║[###]▢╏[###]▢╏[###]▢╏[###]▢╏[###]▢║
|
||||||
|
// \\ ║[###]▢╏[###]▢╏[###]▢╏[###]▢╏[###]▢║
|
||||||
|
// \\ ║[###]▢╏[###]▢╏[###]▢╏[###]▢╏[###]▢║
|
||||||
|
// \\ ╚══════╧══════╧══════╧══════╧══════╝
|
||||||
|
// ,
|
||||||
|
// .ip = "offline",
|
||||||
|
// .name = "Anemos",
|
||||||
|
// .services = &.{
|
||||||
|
// .none,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// Server{
|
||||||
|
// .ascii_art =
|
||||||
|
// \\ ╔══════╤══════╤══════╤══════╤══════╗
|
||||||
|
// \\ ║[###]▢╏[###]▢╏[###]▢╏[###]▢╏[###]▢║
|
||||||
|
// \\ ║[###]▢╏[###]▢╏[###]▢╏[###]▢╏[###]▢║
|
||||||
|
// \\ ║[###]▢╏[###]▢╏[###]▢╏[###]▢╏[###]▢║
|
||||||
|
// \\ ╚══════╧══════╧══════╧══════╧══════╝
|
||||||
|
// ,
|
||||||
|
// .ip = "offline",
|
||||||
|
// .name = "Artemis",
|
||||||
|
// .services = &.{
|
||||||
|
// .none,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
.servers = servers.value,
|
||||||
|
};
|
||||||
|
|
||||||
|
const term = try ansi.enableRawMode();
|
||||||
|
try stdout_writer.flush();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const key = keys.parseKeycode(stdin_reader) catch continue orelse continue;
|
||||||
|
const exit_key_0 = comptime (keys.Key{ .escape = keys.ctrl('q') }).keyToU64();
|
||||||
|
const exit_key_1 = comptime (keys.Key{ .escape = keys.ctrl('c') }).keyToU64();
|
||||||
|
|
||||||
|
const up_key = comptime (keys.Up.keyToU64());
|
||||||
|
const down_key = comptime (keys.Down.keyToU64());
|
||||||
|
const left_key = comptime (keys.Left.keyToU64());
|
||||||
|
const right_key = comptime (keys.Right.keyToU64());
|
||||||
|
|
||||||
|
switch (key.keyToU64()) {
|
||||||
|
exit_key_0, exit_key_1 => break,
|
||||||
|
|
||||||
|
up_key => ui.handleInput(.up),
|
||||||
|
down_key => ui.handleInput(.down),
|
||||||
|
left_key => ui.handleInput(.left),
|
||||||
|
right_key => ui.handleInput(.right),
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
try ansi.returnToHome(stdout_writer);
|
||||||
|
try ui.render();
|
||||||
|
try stdout_writer.flush();
|
||||||
|
}
|
||||||
|
try ansi.clearScreen(stdout_writer);
|
||||||
|
try ansi.placeCursorAt(stdout_writer, 0, 99);
|
||||||
|
try stdout_writer.flush();
|
||||||
|
ansi.disableRawMode(term);
|
||||||
|
}
|
||||||
18
src/root.zig
Normal file
18
src/root.zig
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
//! By convention, root.zig is the root source file when making a package.
|
||||||
|
const std = @import("std");
|
||||||
|
const Io = std.Io;
|
||||||
|
|
||||||
|
/// This is a documentation comment to explain the `printAnotherMessage` function below.
|
||||||
|
///
|
||||||
|
/// Accepting an `Io.Writer` instance is a handy way to write reusable code.
|
||||||
|
pub fn printAnotherMessage(writer: *Io.Writer) Io.Writer.Error!void {
|
||||||
|
try writer.print("Run `zig build test` to run the tests.\n", .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add(a: i32, b: i32) i32 {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "basic add functionality" {
|
||||||
|
try std.testing.expect(add(3, 7) == 10);
|
||||||
|
}
|
||||||
574
src/scan_codes.zig
Normal file
574
src/scan_codes.zig
Normal file
@@ -0,0 +1,574 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const escape_char = 27;
|
||||||
|
|
||||||
|
pub fn ctrl(comptime char: u8) u8 {
|
||||||
|
return switch (char) {
|
||||||
|
'@' => 0,
|
||||||
|
'A', 'a' => 1,
|
||||||
|
'B', 'b' => 2,
|
||||||
|
'C', 'c' => 3,
|
||||||
|
'D', 'd' => 4,
|
||||||
|
'E', 'e' => 5,
|
||||||
|
'F', 'f' => 6,
|
||||||
|
'G', 'g' => 7,
|
||||||
|
'H', 'h' => 8,
|
||||||
|
'I', 'i' => 9,
|
||||||
|
'J', 'j' => 10,
|
||||||
|
'K', 'k' => 11,
|
||||||
|
'L', 'l' => 12,
|
||||||
|
'M', 'm' => 13,
|
||||||
|
'N', 'n' => 14,
|
||||||
|
'O', 'o' => 15,
|
||||||
|
'P', 'p' => 16,
|
||||||
|
'Q', 'q' => 17,
|
||||||
|
'R', 'r' => 18,
|
||||||
|
'S', 's' => 19,
|
||||||
|
'T', 't' => 20,
|
||||||
|
'U', 'u' => 21,
|
||||||
|
'V', 'v' => 22,
|
||||||
|
'W', 'w' => 23,
|
||||||
|
'X', 'x' => 24,
|
||||||
|
'Y', 'y' => 25,
|
||||||
|
'Z', 'z' => 26,
|
||||||
|
'[' => 27,
|
||||||
|
'\\' => 28,
|
||||||
|
']' => 29,
|
||||||
|
'^' => 30,
|
||||||
|
'_' => 31,
|
||||||
|
else => @compileError("that key does not have a ctrl value"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isControlChar(char: u8) bool {
|
||||||
|
//yoniked https://github.com/torvalds/linux/blob/9ecfb2f7287a967b418ba69f10d45ead0d360593/tools/include/nolibc/ctype.h#L33
|
||||||
|
return char < 0x20 or char == 0x7f;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parseKeycode(reader: *std.Io.Reader) !?Key {
|
||||||
|
// if (self.poller.pollTimeout(100) catch false) {
|
||||||
|
// https://en.wikipedia.org/wiki/ANSI_escape_code#Terminal%20input%20sequences
|
||||||
|
// <char> -> char
|
||||||
|
// <esc> <nochar> -> esc
|
||||||
|
// <esc> <esc> -> esc
|
||||||
|
// <esc> <char> -> Alt-keypress or keycode sequence
|
||||||
|
// <esc> '[' <nochar> -> Alt-[
|
||||||
|
// <esc> '[' (<modifier>) <char> -> keycode sequence, <modifier> is a decimal
|
||||||
|
// number and defaults to 1 (xterm)
|
||||||
|
// <esc> '[' 1 ; <modifier> <char> -> xterm
|
||||||
|
// <esc> '[' (<keycode>) (';'<modifier>) '~' -> keycode sequence, <keycode> and <modifier>
|
||||||
|
// are decimal numbers and default to 1 (vt)
|
||||||
|
|
||||||
|
const char = try reader.takeByte();
|
||||||
|
var k: Key = Key{};
|
||||||
|
|
||||||
|
if (isControlChar(char)) {
|
||||||
|
k.escape = char;
|
||||||
|
} else {
|
||||||
|
k.keycode = char;
|
||||||
|
}
|
||||||
|
|
||||||
|
// not part of an espace sequence
|
||||||
|
if (char != '\x1b') {
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
k.escape = char;
|
||||||
|
|
||||||
|
const char_2 = try reader.takeByte();
|
||||||
|
|
||||||
|
// not part of an Alt-[ sequence
|
||||||
|
if (char_2 != '[' and char_2 != 'O') {
|
||||||
|
k.keycode = char_2;
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char_3 = try reader.takeByte();
|
||||||
|
k.keycode = char_3;
|
||||||
|
|
||||||
|
// bt function keys the strange one
|
||||||
|
if (char_2 == 'O' and char_3 >= 'P' and char_3 <= 'S') {
|
||||||
|
k.keycode = char_2;
|
||||||
|
k.keycode_2 = char_3;
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
// strange vt function keys we do the only convertion here
|
||||||
|
|
||||||
|
// xterm check
|
||||||
|
if (char_3 >= 'A' and char_3 <= 'O' or char_3 >= 'T' and char_3 <= 'Z') {
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char_4 = try reader.takeByte();
|
||||||
|
|
||||||
|
// modified xterm check
|
||||||
|
if (char_3 == '1' and char_4 == ';') {
|
||||||
|
const char_5 = try reader.takeByte();
|
||||||
|
const char_6 = try reader.takeByte();
|
||||||
|
k.modifier = char_5;
|
||||||
|
k.keycode = char_6;
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
// xterm sequence
|
||||||
|
if (char_3 == 1 and char_4 >= 'P' and char_4 <= 'S') {
|
||||||
|
k.keycode_2 = char_4;
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (char_4 == 0x1A) {
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
// vt sequence with single keycode
|
||||||
|
if (char_4 == '~') {
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
// vt sequence with multi keycode
|
||||||
|
if (char_3 >= '1' and char_3 <= '3' and char_4 != ';') {
|
||||||
|
k.keycode_2 = char_4;
|
||||||
|
const tilde = try reader.takeByte();
|
||||||
|
if (tilde != '~') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (char_4 != ';') {
|
||||||
|
k.modifier = char_3;
|
||||||
|
k.keycode = char_4;
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (char_4 == ';') {
|
||||||
|
const char_5 = try reader.takeByte();
|
||||||
|
_ = try reader.takeByte();
|
||||||
|
k.modifier = char_5;
|
||||||
|
k.keycode = char_3;
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const Key = struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
escape: u8 = 0,
|
||||||
|
keycode: u8 = 0,
|
||||||
|
// this fucker is only needed for 2 chars sequences
|
||||||
|
keycode_2: u8 = 0,
|
||||||
|
// Shift 1
|
||||||
|
// (Left) Alt 2
|
||||||
|
// ctrl 4
|
||||||
|
// meta 8
|
||||||
|
modifier: u8 = 0,
|
||||||
|
|
||||||
|
pub fn eq(a: Self, b: Self) bool {
|
||||||
|
return (a.escape == b.escape and
|
||||||
|
a.keycode == b.keycode and
|
||||||
|
a.modifier == b.modifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
// make it 64 to make things nice
|
||||||
|
// this allows for switch cases to be used
|
||||||
|
pub fn keyToU64(self: Self) u64 {
|
||||||
|
return (@as(u64, self.escape) << 24) +
|
||||||
|
(@as(u64, self.modifier) << 16) +
|
||||||
|
(@as(u64, self.keycode_2) << 8) +
|
||||||
|
@as(u64, self.keycode);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn isRenderable(self: Self) bool {
|
||||||
|
return switch (self.escape) {
|
||||||
|
0 => true,
|
||||||
|
9 => true,
|
||||||
|
else => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toChar(self: Self) u8 {
|
||||||
|
return switch (self.escape) {
|
||||||
|
0 => self.keycode,
|
||||||
|
9 => '\t',
|
||||||
|
else => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format(
|
||||||
|
self: Self,
|
||||||
|
writer: *std.Io.Writer,
|
||||||
|
) !void {
|
||||||
|
if (self.keycode_2 == 0) {
|
||||||
|
try writer.print(
|
||||||
|
"key(esc={}, keycode=\"{c}\", mod={})",
|
||||||
|
.{
|
||||||
|
self.escape,
|
||||||
|
self.keycode,
|
||||||
|
self.modifier,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
try writer.print(
|
||||||
|
"key(esc={}, keycode=|{c}|{}|, mod={}, id={})",
|
||||||
|
.{
|
||||||
|
self.escape,
|
||||||
|
self.keycode,
|
||||||
|
self.keycode_2,
|
||||||
|
self.modifier,
|
||||||
|
self.keyToU64(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// normal seqs
|
||||||
|
|
||||||
|
pub const Enter: Key = Key{
|
||||||
|
.escape = 13,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Backspace: Key = Key{
|
||||||
|
.escape = 127,
|
||||||
|
};
|
||||||
|
|
||||||
|
// vt sequences:
|
||||||
|
pub const Home_0: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '1',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Insert: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '2',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Delete: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '3',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const End_0: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '4',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const PgUp: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '5',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const PgDn: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '6',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Home_1: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '7',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const End_1: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '8',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const F0: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '1',
|
||||||
|
.keycode_2 = '0',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const F1: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '1',
|
||||||
|
.keycode_2 = '1',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const F2: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '1',
|
||||||
|
.keycode_2 = '2',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const F3: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '1',
|
||||||
|
.keycode_2 = '3',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const F4: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '1',
|
||||||
|
.keycode_2 = '4',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const F5: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '1',
|
||||||
|
.keycode_2 = '5',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const F6: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '1',
|
||||||
|
.keycode_2 = '7',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const F7: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '1',
|
||||||
|
.keycode_2 = '8',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const F8: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '1',
|
||||||
|
.keycode_2 = '9',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const F9: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '2',
|
||||||
|
.keycode_2 = '0',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const F10: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '2',
|
||||||
|
.keycode_2 = '1',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const F11: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '2',
|
||||||
|
.keycode_2 = '3',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const F12: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '2',
|
||||||
|
.keycode_2 = '4',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const F13: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '2',
|
||||||
|
.keycode_2 = '5',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const F14: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '2',
|
||||||
|
.keycode_2 = '6',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const F15: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '2',
|
||||||
|
.keycode_2 = '8',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const F16: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '2',
|
||||||
|
.keycode_2 = '9',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const F17: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '3',
|
||||||
|
.keycode_2 = '1',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const F18: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '3',
|
||||||
|
.keycode_2 = '2',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const F19: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '3',
|
||||||
|
.keycode_2 = '3',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const F20: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '3',
|
||||||
|
.keycode_2 = '4',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const vt_9: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '9',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const vt_16: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '1',
|
||||||
|
.keycode_2 = '6',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const vt_22: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '2',
|
||||||
|
.keycode_2 = '2',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const vt_27: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '2',
|
||||||
|
.keycode_2 = '7',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const vt_30: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '3',
|
||||||
|
.keycode_2 = '0',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const vt_35: Key = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = '3',
|
||||||
|
.keycode_2 = '5',
|
||||||
|
};
|
||||||
|
|
||||||
|
// xterm sequences:
|
||||||
|
|
||||||
|
pub const Up = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'A',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Down = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'B',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Right = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'C',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Left = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'D',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const xterm_End = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'F',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Keypad_5 = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'G',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const xterm_Home = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'H',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const xterm_F1 = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.modifier = 1,
|
||||||
|
.keycode = 'P',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const xterm_F2 = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.modifier = 1,
|
||||||
|
.keycode = 'Q',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const xterm_F3 = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.modifier = 1,
|
||||||
|
.keycode = 'R',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const xterm_F4 = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.modifier = 1,
|
||||||
|
.keycode = 'S',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const xterm_E = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'E',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const xterm_I = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'I',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const xterm_J = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'J',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const xterm_K = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'K',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const xterm_L = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'L',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const xterm_M = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'M',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const xterm_N = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'N',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const xterm_O = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'O',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const xterm_T = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'T',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const xterm_U = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'U',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const xterm_V = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'V',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const xterm_W = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'W',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const xterm_X = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'X',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const xterm_Y = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'Y',
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const xterm_Z = Key{
|
||||||
|
.escape = escape_char,
|
||||||
|
.keycode = 'Z',
|
||||||
|
};
|
||||||
25
ui.schema.json
Normal file
25
ui.schema.json
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type" :"object",
|
||||||
|
"properties": {
|
||||||
|
"ascii_art" : {"type" : "string"},
|
||||||
|
"ip" : {"type" : "string"},
|
||||||
|
"name": {"type" : "string"},
|
||||||
|
"services" : {
|
||||||
|
"type" : "array",
|
||||||
|
"items": {
|
||||||
|
"type" : "object",
|
||||||
|
"properties": {
|
||||||
|
"name" : {"type" : "string"},
|
||||||
|
"ports" : {
|
||||||
|
"type" : "array",
|
||||||
|
"items": {"type" : "number"}
|
||||||
|
},
|
||||||
|
"description" : {"type" : "string"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user