diff options
| author | Julian Hurst <ark@mansus.space> | 2026-02-16 19:50:35 +0100 |
|---|---|---|
| committer | Julian Hurst <ark@mansus.space> | 2026-02-16 19:50:35 +0100 |
| commit | f014d1ce8e95fe93b453a7cd50554b959214e502 (patch) | |
| tree | 0a4c9311c2ae0626e746338309eb3f5d8cbfc7ad /cmd | |
| download | plctl-master.tar.gz | |
Diffstat (limited to 'cmd')
| -rw-r--r-- | cmd/plctl/plctl.ha | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/cmd/plctl/plctl.ha b/cmd/plctl/plctl.ha new file mode 100644 index 0000000..d559b4d --- /dev/null +++ b/cmd/plctl/plctl.ha @@ -0,0 +1,190 @@ +use fmt; +use strings; +use os; +use os::exec; +use io; +use encoding::utf8; + +type listcmd = enum { + PLAYERS, + TITLES, +}; + +def PLAYERSARGS: [2]str = ["playerctl", "-l"]; +def TITLESARGS: [4]str = ["playerctl", "-a", "metadata", "title"]; + +type mapping = struct { + player: str, + title: str, +}; + +type err = !(!exec::exit_status | utf8::invalid | io::error | exec::error | nomem); +type simpleerr = !(exec::error | !exec::exit_status | nomem); +type mismatch = !void; + +export fn main() void = { + const map = getmap()!; + //for (let mapp .. map) { + // fmt::println(mapp.player)!; + // fmt::println(mapp.title)!; + //}; + defer finish(map); + + if (len(map) == 0) { + return; + }; + + if (len(map) == 1) { + toggle(map[0])!; + return; + }; + + const m = match (choice(map)) { + case let m: mapping => + yield m; + case void => + return; + case let e: err => + handleerr(e); + }; + + toggle(m)!; +}; + +fn toggle(m: mapping) (void | simpleerr) = { + let cmd = exec::cmd("playerctl", "-p", m.player, "play-pause")?; + + let proc = exec::start(&cmd)?; + + let status = exec::wait(&proc)?; + const st = match (exec::check(&status)) { + case let e: !exec::exit_status => + return e; + case void => void; + }; +}; + +fn choice(map: []mapping) (mapping | void | err) = { + let cmd = exec::cmd("wmenu")?; + + const (read, write) = exec::pipe(); + const (read1, write1) = exec::pipe(); + exec::addfile(&cmd, os::stdin_file, read1)?; + exec::addfile(&cmd, os::stdout_file, write)?; + let proc = exec::start(&cmd)?; + + io::close(read1)?; + io::close(write)?; + for (let mapp .. map) { + io::writeall(write1, strings::toutf8(mapp.title))?; + io::writeall(write1, strings::toutf8("\n"))?; + }; + io::close(write1)?; + + let data = io::drain(read)?; + defer free(data); + io::close(read)?; + let status = exec::wait(&proc)?; + + const st = match (exec::check(&status)) { + case let e: !exec::exit_status => + return e; + case void => void; + }; + + let s = strings::trim(strings::fromutf8(data)?); + for (let mapp .. map) { + if (mapp.title == s) { + return mapp; + }; + }; + return void; +}; + +fn finish(map: []mapping) void = { + for (let mapp .. map) { + free(mapp.player); + free(mapp.title); + }; + free(map); +}; + +fn handleerr(e: err) never = { + match (e) { + case let e: utf8::invalid => + fmt::fatal(utf8::strerror(e)); + case let e: io::error => + fmt::fatal(io::strerror(e)); + case let e: exec::error => + fmt::fatal(exec::strerror(e)); + case nomem => + fmt::fatal("No memory left"); + case let e: !exec::exit_status => + fmt::fatal(exec::exitstr(e)); + }; +}; + +fn getmap() ([]mapping | err | mismatch) = { + const pls = match (getlist(listcmd::PLAYERS)) { + case let s: []str => + yield s; + case let e: err => + handleerr(e); + }; + defer strings::freeall(pls); + + const titles = match (getlist(listcmd::TITLES)) { + case let s: []str => + yield s; + case let e: err => + handleerr(e); + }; + defer strings::freeall(titles); + + if (len(pls) != len(titles)) { + return mismatch; + }; + + let map: []mapping = []; + for (let i = 0z; i < len(pls); i += 1) { + append(map, mapping { + player = strings::dup(pls[i])?, + title = strings::dup(titles[i])?, + })?; + }; + return map; +}; + +fn argslistcmd(lcmd: listcmd) []str = switch (lcmd) { +case listcmd::PLAYERS => + yield strings::dupall(PLAYERSARGS)!; +case listcmd::TITLES => + yield strings::dupall(TITLESARGS)!; +}; + +fn getlist(lcmd: listcmd) ([]str | err) = { + const args = argslistcmd(lcmd); + defer strings::freeall(args); + let cmd = exec::cmd(args[0], args[1..]...)?; + + const (read, write) = exec::pipe(); + exec::addfile(&cmd, os::stdout_file, write)?; + let proc = exec::start(&cmd)?; + io::close(write)?; + + let data = io::drain(read)?; + defer free(data); + io::close(read)?; + let status = exec::wait(&proc)?; + + const st = match (exec::check(&status)) { + case let e: !exec::exit_status => + return e; + case void => void; + }; + + const s = strings::fromutf8(data)?; + const spl =strings::split(strings::trim(s), "\n")?; + defer free(spl); + return strings::dupall(spl)?; +}; |
