mirror of
https://mzte.de/git/LordMZTE/dotfiles.git
synced 2024-12-13 11:32:58 +01:00
mzteinit: make entries configurable
This commit is contained in:
parent
9975a02051
commit
a8e140461a
6 changed files with 128 additions and 79 deletions
3
.config/mzteinit/entries.cfg.cgt
Normal file
3
.config/mzteinit/entries.cfg.cgt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<! for _, v in ipairs(opt.mzteinit_entries) do !>
|
||||||
|
<% v.key %> <% v.label %>: <% table.concat(v.cmd, ",") %><! if v.quit then !> :Q<! end !>
|
||||||
|
<! end !>
|
|
@ -1,5 +1,13 @@
|
||||||
local opts = {}
|
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
|
-- Enable if you have good internet, used for stuff like making
|
||||||
-- streamlink use low-latency mode.
|
-- streamlink use low-latency mode.
|
||||||
opts.good_internet = true
|
opts.good_internet = true
|
||||||
|
|
|
@ -11,9 +11,13 @@ cg.addFile ".vieterrc.cgt"
|
||||||
|
|
||||||
-- Recursively merge 2 tables
|
-- Recursively merge 2 tables
|
||||||
local function merge(a, b)
|
local function merge(a, b)
|
||||||
|
if b[1] then -- b is a list
|
||||||
|
return b
|
||||||
|
end
|
||||||
|
|
||||||
for k, v in pairs(b) do
|
for k, v in pairs(b) do
|
||||||
if type(v) == "table" and type(a[k]) == "table" then
|
if type(v) == "table" and type(a[k]) == "table" then
|
||||||
merge(a[k], v)
|
a[k] = merge(a[k], v)
|
||||||
else
|
else
|
||||||
a[k] = v
|
a[k] = v
|
||||||
end
|
end
|
||||||
|
|
77
scripts/mzteinit/src/command.zig
Normal file
77
scripts/mzteinit/src/command.zig
Normal file
|
@ -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();
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const at = @import("ansi-term");
|
const at = @import("ansi-term");
|
||||||
const env = @import("env.zig");
|
const env = @import("env.zig");
|
||||||
const run = @import("run.zig");
|
const command = @import("command.zig");
|
||||||
const util = @import("util.zig");
|
const util = @import("util.zig");
|
||||||
|
|
||||||
const msg = @import("message.zig").msg;
|
const msg = @import("message.zig").msg;
|
||||||
|
@ -68,7 +68,7 @@ fn tryMain() !void {
|
||||||
arg.* = std.mem.span(arg_in);
|
arg.* = std.mem.span(arg_in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var env_map = try std.process.getEnvMap(alloc);
|
var env_map = try std.process.getEnvMap(alloc);
|
||||||
defer env_map.deinit();
|
defer env_map.deinit();
|
||||||
|
|
||||||
|
@ -94,10 +94,30 @@ fn tryMain() !void {
|
||||||
return;
|
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) {
|
while (true) {
|
||||||
try stdout.writer().writeAll(util.ansi_clear);
|
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});
|
std.debug.print("Error rendering the UI: {}\n", .{e});
|
||||||
break;
|
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();
|
const w = buf_writer.writer();
|
||||||
var style: ?at.style.Style = null;
|
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 updateStyle(w, .{ .font_style = .{ .bold = true } }, &style);
|
||||||
try w.writeAll(" What do you want to do?\n\n");
|
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 updateStyle(w, .{ .foreground = .Cyan }, &style);
|
||||||
try w.print("[{c}] ", .{tag.char()});
|
try w.print("[{c}] ", .{entry.key});
|
||||||
try updateStyle(w, .{ .foreground = .Green }, &style);
|
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);
|
try at.format.resetStyle(w);
|
||||||
style = .{};
|
style = .{};
|
||||||
|
@ -160,12 +180,17 @@ fn ui(buf_writer: anytype) !run.Command {
|
||||||
new_termios.lflag &= ~std.os.linux.ECHO; // No echoing stuff
|
new_termios.lflag &= ~std.os.linux.ECHO; // No echoing stuff
|
||||||
try std.os.tcsetattr(std.os.STDIN_FILENO, .NOW, new_termios);
|
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;
|
var c: [1]u8 = undefined;
|
||||||
while (cmd == null) {
|
while (cmd == null) {
|
||||||
std.debug.assert(try std.io.getStdIn().read(&c) == 1);
|
std.debug.assert(try std.io.getStdIn().read(&c) == 1);
|
||||||
cmd = run.Command.fromChar(c[0]);
|
const key_upper = std.ascii.toUpper(c[0]);
|
||||||
if (cmd == null) {
|
for (entries) |entry| {
|
||||||
|
if (entry.key == key_upper) {
|
||||||
|
cmd = entry;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
try w.print("Unknown command '{s}'\n", .{c});
|
try w.print("Unknown command '{s}'\n", .{c});
|
||||||
try buf_writer.flush();
|
try buf_writer.flush();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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" },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
Loading…
Reference in a new issue