From b32495bd359fa25b9cd4d52e72da1e24630a0663 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 12 Dec 2021 12:12:23 +0100 Subject: bin: allow specifying the console on the command line As in: $ vtcol --console /dev/tty6 colors get solarized $ vtcol --console /dev/tty6 colors set phosphor $ vtcol --console /dev/tty6 colors get phosphor That simplifies testing so much I wonder why the heck I needed this long to finally implement it. --- src/vtcol.rs | 180 ++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 117 insertions(+), 63 deletions(-) (limited to 'src/vtcol.rs') diff --git a/src/vtcol.rs b/src/vtcol.rs index dcc7820..89cc162 100644 --- a/src/vtcol.rs +++ b/src/vtcol.rs @@ -18,9 +18,18 @@ macro_rules! vrb { )} } +/** Helper for choosing the console. Defaults to the current one if +none is explicitly supplied. */ +#[inline] +fn open_console(path: Option<&str>) -> io::Result +{ + path.map(Console::from_path).unwrap_or_else(|| Console::current()) +} + +/** Trait for subcommands to implement. */ trait Run { - fn run(self) -> Result<()>; + fn run(self, console: Option) -> Result<()>; } #[derive(Debug)] @@ -38,13 +47,14 @@ enum LedJob impl Run for LedJob { - fn run(self) -> Result<()> + fn run(self, console: Option) -> Result<()> { match self { - Self::Get(raw) => Self::get(raw), - Self::Revert => Self::revert(), - Self::Set(st) => Self::set(st), - Self::SetIndividual(c, n, s) => Self::set_individual(c, n, s), + Self::Get(raw) => Self::get(console, raw), + Self::Revert => Self::revert(console), + Self::Set(st) => Self::set(console, st), + Self::SetIndividual(c, n, s) => + Self::set_individual(console, c, n, s), } } } /* [impl Run for LedJob] */ @@ -52,9 +62,9 @@ impl Run for LedJob impl LedJob { /** Get the keyboard LED state. */ - fn get(raw: bool) -> Result<()> + fn get(con: Option, raw: bool) -> Result<()> { - let fd = Console::current()?; + let fd = open_console(con.as_deref())?; vrb!("console fd: {}", fd); let leds = KbLedState::get(&fd)?; @@ -69,9 +79,9 @@ impl LedJob } /** Set the keyboard LED state. */ - fn set(st: KbLedState) -> Result<()> + fn set(con: Option, st: KbLedState) -> Result<()> { - let fd = Console::current()?; + let fd = open_console(con.as_deref())?; vrb!("console fd: {}", fd); st.set(&fd)?; @@ -82,12 +92,13 @@ impl LedJob /** Set the state of the given LEDs using the current state as base. */ fn set_individual( + con: Option, cap: Option, num: Option, scr: Option, ) -> Result<()> { - let fd = Console::current()?; + let fd = open_console(con.as_deref())?; vrb!("console fd: {}", fd); let mut st = KbLedState::get(&fd)?; @@ -103,9 +114,9 @@ impl LedJob } /** Revert the keyboard LED state. */ - fn revert() -> Result<()> + fn revert(con: Option) -> Result<()> { - let fd = Console::current()?; + let fd = open_console(con.as_deref())?; vrb!("console fd: {}", fd); KbLedState::revert(&fd)?; @@ -134,16 +145,16 @@ enum ColorJob impl Run for ColorJob { - fn run(self) -> Result<()> + fn run(self, console: Option) -> Result<()> { match self { Self::Dump(scm) => Self::dump(scm), Self::List => Self::list(), - Self::Set(scm) => Self::set(scm), - Self::Get(b64) => Self::get(b64), - Self::Toggle(one, two) => Self::toggle(one, two), + Self::Set(scm) => Self::set(console, scm), + Self::Get(b64) => Self::get(console, b64), + Self::Toggle(one, two) => Self::toggle(console, one, two), Self::Fade(from, to, ms, hz, clear) => - Self::fade(from, to, ms, hz, clear), + Self::fade(console, from, to, ms, hz, clear), } } } /* [impl Run for ColorJob] */ @@ -192,22 +203,22 @@ impl ColorJob } } - fn set(scheme: Scheme) -> Result<()> + fn set(con: Option, scheme: Scheme) -> Result<()> { - let con = Console::current()?; - vrb!("console fd: {}", con); + let fd = open_console(con.as_deref())?; + vrb!("console fd: {}", fd); - con.apply_scheme(&scheme)?; - con.clear()?; + fd.apply_scheme(&scheme)?; + fd.clear()?; vrb!("successfully enabled scheme {:?}", scheme); /* It’s fine to leak the fd, the kernel will clean up anyways. */ Ok(()) } - fn get(b64: bool) -> Result<()> + fn get(con: Option, b64: bool) -> Result<()> { - let fd = Console::current()?; + let fd = open_console(con.as_deref())?; vrb!("console fd: {}", fd); let scm = fd.current_scheme()?; @@ -224,15 +235,18 @@ impl ColorJob /** Toggle between two schemes. Defaults to ``one`` in case neither scheme is active. */ - fn toggle(one: Scheme, two: Scheme) -> Result<()> + fn toggle(con: Option, one: Scheme, two: Scheme) -> Result<()> { - let fd = Console::current()?; - vrb!("console fd: {}", fd); + let pal = { + let fd = open_console(con.as_deref())?; + vrb!("console fd: {}", fd); + fd.current_palette()? + }; - if fd.current_palette()? == Palette::try_from(&one)? { - Self::set(two) + if pal == Palette::try_from(&one)? { + Self::set(con, two) } else { - Self::set(one) + Self::set(con, one) } } @@ -240,6 +254,7 @@ impl ColorJob If ``from`` is ``None``, the current palette is used as starting point. */ fn fade( + con: Option, from: Option, to: Scheme, dur: Duration, @@ -247,7 +262,7 @@ impl ColorJob clear: bool, ) -> Result<()> { - let fd = Console::current()?; + let fd = open_console(con.as_deref())?; vrb!("console fd: {}", fd); let from = if let Some(from) = from { @@ -266,7 +281,7 @@ impl ColorJob /** Subcommand and runtime parameters. */ #[derive(Debug)] -enum Job +enum Subcmd { /** Console palette ops. */ Colors(ColorJob), @@ -274,6 +289,9 @@ enum Job Leds(LedJob), } +#[derive(Debug)] +struct Job(Option, Subcmd); + impl<'a> Job { pub fn from_argv() -> Result @@ -292,6 +310,17 @@ impl<'a> Job .help("enable extra diagnostics") .takes_value(false), ) + .arg( + Arg::with_name("console") + .set(ArgSettings::Global) + .short("C") + .long("console") + .help( + "path to the console device to operate on [default: \ + current console]", + ) + .takes_value(true), + ) .subcommand( SubCommand::with_name("colors") .about("operations on the console palette") @@ -508,25 +537,37 @@ impl<'a> Job VERBOSITY.store(true, Ordering::SeqCst); } + let con = matches.value_of("console").map(String::from); + match matches.subcommand() { ("colors", Some(subm)) => match subm.subcommand() { ("dump", Some(subm)) => { if let Some(b64) = subm.value_of("base64") { let scheme = Scheme::from_base64(b64)?; - return Ok(Self::Colors(ColorJob::Dump(scheme))); + return Ok(Self( + con, + Subcmd::Colors(ColorJob::Dump(scheme)), + )); } if let Some(name) = subm.value_of("scheme") { let scm = Scheme::from(name); - return Ok(Self::Colors(ColorJob::Dump(scm))); + return Ok(Self( + con, + Subcmd::Colors(ColorJob::Dump(scm)), + )); } Err(anyhow!("dump requires an argument")) }, - ("list", _) => Ok(Self::Colors(ColorJob::List)), + ("list", _) => + Ok(Self(con, Subcmd::Colors(ColorJob::List))), ("set", Some(subm)) => { if let Some(b64) = subm.value_of("base64") { let scheme = Scheme::from_base64(&b64)?; - return Ok(Self::Colors(ColorJob::Set(scheme))); + return Ok(Self( + con, + Subcmd::Colors(ColorJob::Set(scheme)), + )); } let scheme = match subm.value_of("scheme") { Some("-") => Self::read_scheme_from_stdin(), @@ -547,20 +588,26 @@ impl<'a> Job }, }, }; - Ok(Self::Colors(ColorJob::Set(scheme))) + Ok(Self(con, Subcmd::Colors(ColorJob::Set(scheme)))) }, ("get", Some(subm)) => - Ok(Self::Colors(ColorJob::Get( - subm.is_present("base64"), - ))), + Ok(Self( + con, + Subcmd::Colors(ColorJob::Get( + subm.is_present("base64"), + )), + )), ("toggle", Some(subm)) => { match (subm.value_of("one"), subm.value_of("two")) { (Some(one), Some(two)) => { vrb!("toggle schemes [{}] and [{}]", one, two); - Ok(Self::Colors(ColorJob::Toggle( - Scheme::from(one), - Scheme::from(two), - ))) + Ok(Self( + con, + Subcmd::Colors(ColorJob::Toggle( + Scheme::from(one), + Scheme::from(two), + )), + )) }, _ => Err(anyhow!( @@ -590,13 +637,16 @@ impl<'a> Job "please supply color scheme to fade to" )), (from, Some(to)) => - Ok(Self::Colors(ColorJob::Fade( - from.map(Scheme::from), - Scheme::from(to), - dur, - hz, - clear, - ))), + Ok(Self( + con, + Subcmd::Colors(ColorJob::Fade( + from.map(Scheme::from), + Scheme::from(to), + dur, + hz, + clear, + )), + )), } }, (junk, _) => @@ -612,21 +662,27 @@ impl<'a> Job match subm.subcommand() { ("get", Some(subm)) => { let raw = subm.is_present("u8"); - Ok(Self::Leds(LedJob::Get(raw))) + Ok(Self(con, Subcmd::Leds(LedJob::Get(raw)))) }, ("set", Some(subm)) => { if subm.is_present("revert") { - return Ok(Self::Leds(LedJob::Revert)); + return Ok(Self(con, Subcmd::Leds(LedJob::Revert))); } if let Some(st) = subm.value_of("u8") { let st: u8 = st.parse()?; let st = KbLedState::try_from(st)?; - return Ok(Self::Leds(LedJob::Set(st))); + return Ok(Self( + con, + Subcmd::Leds(LedJob::Set(st)), + )); } let cap = subm.value_of("caps").map(|a| a == "on"); let num = subm.value_of("num").map(|a| a == "on"); let scr = subm.value_of("scroll").map(|a| a == "on"); - Ok(Self::Leds(LedJob::SetIndividual(cap, num, scr))) + Ok(Self( + con, + Subcmd::Leds(LedJob::SetIndividual(cap, num, scr)), + )) }, (junk, _) => Err(anyhow!( @@ -652,20 +708,18 @@ impl<'a> Job vrb!("vtcol>"); Scheme::from_stdin() } -} /* [impl Job] */ -impl Run for Job -{ fn run(self) -> Result<()> { - match self { - Self::Colors(cols) => cols.run()?, - Self::Leds(leds) => leds.run()?, + let Job(con, cmd) = self; + match cmd { + Subcmd::Colors(cols) => cols.run(con)?, + Subcmd::Leds(leds) => leds.run(con)?, } Ok(()) } -} /* [impl Run for Job] */ +} /* [impl Job] */ fn main() -> Result<()> { -- cgit v1.2.3