From a8e140461a3809e02cb1fc66fcf39fdad71b1ff4 Mon Sep 17 00:00:00 2001 From: LordMZTE Date: Sun, 27 Aug 2023 21:05:25 +0200 Subject: [PATCH] mzteinit: make entries configurable --- .config/mzteinit/entries.cfg.cgt | 3 ++ cg_opts.lua | 8 ++++ confgen.lua | 6 ++- scripts/mzteinit/src/command.zig | 77 ++++++++++++++++++++++++++++++++ scripts/mzteinit/src/main.zig | 45 ++++++++++++++----- scripts/mzteinit/src/run.zig | 68 ---------------------------- 6 files changed, 128 insertions(+), 79 deletions(-) create mode 100644 .config/mzteinit/entries.cfg.cgt create mode 100644 scripts/mzteinit/src/command.zig delete mode 100644 scripts/mzteinit/src/run.zig diff --git a/.config/mzteinit/entries.cfg.cgt b/.config/mzteinit/entries.cfg.cgt new file mode 100644 index 00000000..6689b976 --- /dev/null +++ b/.config/mzteinit/entries.cfg.cgt @@ -0,0 +1,3 @@ + +<% v.key %> <% v.label %>: <% table.concat(v.cmd, ",") %> :Q + diff --git a/cg_opts.lua b/cg_opts.lua index ccccac6f..0e29ebd4 100644 --- a/cg_opts.lua +++ b/cg_opts.lua @@ -1,5 +1,13 @@ local opts = {} +opts.mzteinit_entries = { + { key = "x", label = "startx", cmd = { "starx" } }, + { key = "s", label = "shell", cmd = { "fish" } }, + { key = "l", label = "logout", cmd = { "!quit" } }, + { key = "p", label = "shutdown", cmd = { "systemctl", "poweroff" }, quit = true }, + { key = "r", label = "reboot", cmd = { "systemctl", "reboot" }, quit = true }, +} + -- Enable if you have good internet, used for stuff like making -- streamlink use low-latency mode. opts.good_internet = true diff --git a/confgen.lua b/confgen.lua index 8d78b1c7..e58c567b 100644 --- a/confgen.lua +++ b/confgen.lua @@ -11,9 +11,13 @@ cg.addFile ".vieterrc.cgt" -- Recursively merge 2 tables local function merge(a, b) + if b[1] then -- b is a list + return b + end + for k, v in pairs(b) do if type(v) == "table" and type(a[k]) == "table" then - merge(a[k], v) + a[k] = merge(a[k], v) else a[k] = v end diff --git a/scripts/mzteinit/src/command.zig b/scripts/mzteinit/src/command.zig new file mode 100644 index 00000000..5d6da894 --- /dev/null +++ b/scripts/mzteinit/src/command.zig @@ -0,0 +1,77 @@ +const std = @import("std"); +const log = std.log.scoped(.command); + +pub const Command = struct { + key: u8, + label: []const u8, + command: [][]const u8, + exit: bool, + + pub fn deinit(self: Command, alloc: std.mem.Allocator) void { + alloc.free(self.command); + } + + pub fn run( + self: Command, + alloc: std.mem.Allocator, + exit: *@import("util.zig").ExitMode, + env: *const std.process.EnvMap, + ) !void { + if (std.mem.eql(u8, self.command[0], "!quit")) { + exit.* = .delayed; + log.info("user logged out", .{}); + return; + } + + if (self.exit) exit.* = .immediate; + + log.info("run cmd: {s}", .{self.command}); + var child = std.ChildProcess.init(self.command, alloc); + child.env_map = env; + _ = try child.spawnAndWait(); + } +}; + +pub fn parseEntriesConfig(alloc: std.mem.Allocator, data: []const u8) ![]Command { + var entries = std.ArrayList(Command).init(alloc); + errdefer entries.deinit(); + + var line_splits = std.mem.tokenizeScalar(u8, data, '\n'); + while (line_splits.next()) |line| { + const line_without_comment = std.mem.sliceTo(line, '#'); + if (line_without_comment.len == 0) + continue; + + var seg_splits = std.mem.tokenizeScalar(u8, line_without_comment, ':'); + const labels = std.mem.trim(u8, seg_splits.next() orelse return error.InvalidConfig, &std.ascii.whitespace); + const command = std.mem.trim(u8, seg_splits.next() orelse return error.InvalidConfig, &std.ascii.whitespace); + var exit = false; + if (seg_splits.next()) |extra| { + if (std.mem.eql(u8, extra, "Q")) { + exit = true; + } else return error.InvalidConfig; + } + if (seg_splits.next()) |_| return error.InvalidConfig; + + if (labels.len < 3 or labels[1] != ' ') return error.InvalidConfig; + const key = std.ascii.toUpper(labels[0]); + const label = labels[2..]; + + var argv = std.ArrayList([]const u8).init(alloc); + errdefer argv.deinit(); + var command_splits = std.mem.splitScalar(u8, command, ','); + while (command_splits.next()) |arg| + try argv.append(arg); + + if (argv.items.len == 0) return error.InvalidConfig; + + try entries.append(.{ + .key = key, + .label = label, + .command = try argv.toOwnedSlice(), + .exit = exit, + }); + } + + return try entries.toOwnedSlice(); +} diff --git a/scripts/mzteinit/src/main.zig b/scripts/mzteinit/src/main.zig index 5bf8baf2..f87e2263 100644 --- a/scripts/mzteinit/src/main.zig +++ b/scripts/mzteinit/src/main.zig @@ -1,7 +1,7 @@ const std = @import("std"); const at = @import("ansi-term"); const env = @import("env.zig"); -const run = @import("run.zig"); +const command = @import("command.zig"); const util = @import("util.zig"); const msg = @import("message.zig").msg; @@ -68,7 +68,7 @@ fn tryMain() !void { arg.* = std.mem.span(arg_in); } } - + var env_map = try std.process.getEnvMap(alloc); defer env_map.deinit(); @@ -94,10 +94,30 @@ fn tryMain() !void { return; } + const entries_config_path = try std.fs.path.join(alloc, &.{ + env_map.get("XDG_CONFIG_HOME") orelse @panic("bork"), + "mzteinit", + "entries.cfg", + }); + defer alloc.free(entries_config_path); + + var entries_config_file = try std.fs.cwd().openFile(entries_config_path, .{}); + defer entries_config_file.close(); + + const entries_config_data = try entries_config_file.readToEndAlloc(alloc, std.math.maxInt(usize)); + defer alloc.free(entries_config_data); + + const entries = try command.parseEntriesConfig(alloc, entries_config_data); + defer { + for (entries) |entry| + entry.deinit(alloc); + alloc.free(entries); + } + while (true) { try stdout.writer().writeAll(util.ansi_clear); - const cmd = ui(&stdout) catch |e| { + const cmd = ui(&stdout, entries) catch |e| { std.debug.print("Error rendering the UI: {}\n", .{e}); break; }; @@ -124,7 +144,7 @@ fn tryMain() !void { } } -fn ui(buf_writer: anytype) !run.Command { +fn ui(buf_writer: anytype, entries: []command.Command) !command.Command { const w = buf_writer.writer(); var style: ?at.style.Style = null; @@ -143,11 +163,11 @@ fn ui(buf_writer: anytype) !run.Command { try updateStyle(w, .{ .font_style = .{ .bold = true } }, &style); try w.writeAll(" What do you want to do?\n\n"); - for (std.enums.values(run.Command)) |tag| { + for (entries) |entry| { try updateStyle(w, .{ .foreground = .Cyan }, &style); - try w.print("[{c}] ", .{tag.char()}); + try w.print("[{c}] ", .{entry.key}); try updateStyle(w, .{ .foreground = .Green }, &style); - try w.print("{s}\n", .{@tagName(tag)}); + try w.print("{s}\n", .{entry.label}); } try at.format.resetStyle(w); style = .{}; @@ -160,12 +180,17 @@ fn ui(buf_writer: anytype) !run.Command { new_termios.lflag &= ~std.os.linux.ECHO; // No echoing stuff try std.os.tcsetattr(std.os.STDIN_FILENO, .NOW, new_termios); - var cmd: ?run.Command = null; + var cmd: ?command.Command = null; var c: [1]u8 = undefined; while (cmd == null) { std.debug.assert(try std.io.getStdIn().read(&c) == 1); - cmd = run.Command.fromChar(c[0]); - if (cmd == null) { + const key_upper = std.ascii.toUpper(c[0]); + for (entries) |entry| { + if (entry.key == key_upper) { + cmd = entry; + break; + } + } else { try w.print("Unknown command '{s}'\n", .{c}); try buf_writer.flush(); } diff --git a/scripts/mzteinit/src/run.zig b/scripts/mzteinit/src/run.zig deleted file mode 100644 index 93c48bdd..00000000 --- a/scripts/mzteinit/src/run.zig +++ /dev/null @@ -1,68 +0,0 @@ -const std = @import("std"); -const log = std.log.scoped(.run); - -pub const Command = enum { - startx, - shell, - zellij, - logout, - shutdown, - reboot, - - pub fn fromChar(c: u8) ?Command { - return switch (c) { - 'x', 'X' => .startx, - 's', 'S' => .shell, - 'z', 'Z' => .zellij, - 'l', 'L' => .logout, - 'p', 'P' => .shutdown, - 'r', 'R' => .reboot, - else => null, - }; - } - - pub fn char(self: Command) u8 { - return switch (self) { - .startx => 'X', - .shell => 'S', - .zellij => 'Z', - .logout => 'L', - .shutdown => 'P', - .reboot => 'R', - }; - } - - pub fn run( - self: Command, - alloc: std.mem.Allocator, - exit: *@import("util.zig").ExitMode, - env: *const std.process.EnvMap, - ) !void { - switch (self) { - .logout => { - exit.* = .delayed; - log.info("user logged out", .{}); - return; - }, - .shutdown, .reboot => exit.* = .immediate, - else => {}, - } - - const arg = self.argv(); - log.info("run cmd: {s}", .{arg}); - var child = std.ChildProcess.init(arg, alloc); - child.env_map = env; - _ = try child.spawnAndWait(); - } - - fn argv(self: Command) []const []const u8 { - return switch (self) { - .startx => &.{"startx"}, - .shell => &.{"fish"}, - .zellij => &.{"zellij"}, - .logout => unreachable, - .shutdown => &.{ "systemctl", "poweroff" }, - .reboot => &.{ "systemctl", "reboot" }, - }; - } -};