Skip to content

Commit

Permalink
Some code refactoring for flatter module structure
Browse files Browse the repository at this point in the history
  • Loading branch information
rossmacarthur committed Jun 27, 2023
1 parent 5b486a9 commit 4a5ab15
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 163 deletions.
36 changes: 18 additions & 18 deletions src/hid/cmd.rs → src/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,6 @@ use std::process;

use anyhow::{bail, Context, Result};

/// Nicely format an error message for when the subprocess didn't exit
/// successfully.
pub fn format_error_msg(cmd: &process::Command, output: process::Output) -> String {
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
let mut msg = format!(
"subprocess didn't exit successfully `{:?}` ({})",
cmd, output.status
);
if !stdout.trim().is_empty() {
msg.push_str(&format!("\n--- stdout\n{}", stdout));
}
if !stderr.trim().is_empty() {
msg.push_str(&format!("\n--- stderr\n{}", stderr));
}
msg
}

pub trait CommandExt {
/// Run the command return the standard output as a UTF-8 string.
fn output_text(&mut self) -> Result<String>;
Expand All @@ -37,3 +19,21 @@ impl CommandExt for process::Command {
String::from_utf8(output.stdout).context("failed to parse stdout")
}
}

/// Nicely format an error message for when the subprocess didn't exit
/// successfully.
fn format_error_msg(cmd: &process::Command, output: process::Output) -> String {
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
let mut msg = format!(
"subprocess didn't exit successfully `{:?}` ({})",
cmd, output.status
);
if !stdout.trim().is_empty() {
msg.push_str(&format!("\n--- stdout\n{}", stdout));
}
if !stderr.trim().is_empty() {
msg.push_str(&format!("\n--- stderr\n{}", stderr));
}
msg
}
3 changes: 1 addition & 2 deletions src/hex.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::str::FromStr;

use anyhow::anyhow;
use anyhow::{Context, Error, Result};
use anyhow::{anyhow, Context, Error, Result};

#[derive(Debug, Clone, Copy)]
pub struct Hex(pub u64);
Expand Down
14 changes: 5 additions & 9 deletions src/hid/mod.rs → src/hid.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
mod cmd;
mod types;

use std::collections::HashMap;
use std::fmt::Write;
use std::process;

use anyhow::{anyhow, Context, Result};

use crate::cmd::CommandExt;
use crate::hex;
use crate::hid::cmd::CommandExt;
pub use crate::hid::types::{Key, Map, Mappings};
pub use crate::types::{Key, Map, Mappings};

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Device {
Expand Down Expand Up @@ -57,11 +54,10 @@ pub fn list() -> Result<Vec<Device>> {
}

let indices = h_indices.as_deref().unwrap().windows(2);
#[allow(clippy::match_ref_pats)]
let map: HashMap<_, _> = indices
.map(|w| match w {
&[Some(m), Some(n)] => (h[m..n].trim(), line[m..n].trim()),
&[Some(m), None] => (h[m..].trim(), line[m..].trim()),
.map(|w| match *w {
[Some(m), Some(n)] => (h[m..n].trim(), line[m..n].trim()),
[Some(m), None] => (h[m..].trim(), line[m..].trim()),
_ => unreachable!(),
})
.collect();
Expand Down
120 changes: 0 additions & 120 deletions src/hid/types/mod.rs

This file was deleted.

5 changes: 4 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
mod cmd;
mod hex;
mod hid;
mod types;

use std::fmt::Write;

use anyhow::{bail, Result};
use clap::Parser;

use crate::hex::Hex;
use crate::hid::{Device, Map, Mappings};
use crate::hid::Device;
use crate::types::{Map, Mappings};

const HELP_TEMPLATE: &str = "\
{before-help}{bin} {version}
Expand Down
121 changes: 108 additions & 13 deletions src/hid/types/key.rs → src/types.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,85 @@
use std::str::FromStr;

use anyhow::{bail, Error};
use anyhow::{anyhow, bail, Error, Result};

use crate::hex;

/// A key on a keyboard.
/// A keyboard modification consisting of one or more mappings.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Mappings(pub Vec<Map>);

/// A basic remapping of one key to another.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Map(pub Key, pub Key);

impl FromStr for Mappings {
type Err = Error;

fn from_str(s: &str) -> Result<Self> {
if s.is_empty() {
bail!("empty")
}
let (src, dst) = s
.split_once(':')
.ok_or_else(|| anyhow!("colon not found"))?;

enum K {
Double { l: Key, r: Key },
Single(Key),
}

let parse = |s| {
let m: K = match s {
"control" => K::Double {
l: Key::LeftControl,
r: Key::RightControl,
},
"shift" => K::Double {
l: Key::LeftShift,
r: Key::RightShift,
},
"option" => K::Double {
l: Key::LeftOption,
r: Key::RightOption,
},
"command" => K::Double {
l: Key::LeftCommand,
r: Key::RightCommand,
},
src => K::Single(src.parse()?),
};
Ok::<_, Error>(m)
};

fn map(src: K, dst: K) -> Vec<Map> {
match (src, dst) {
(K::Double { l: l0, r: r0 }, K::Double { l: l1, r: r1 }) => {
vec![Map(l0, l1), Map(r0, r1)]
}
(K::Double { l, r }, K::Single(dst)) => {
vec![Map(l, dst), Map(r, dst)]
}
(K::Single(src), K::Double { l, r }) => {
vec![Map(src, l), Map(src, r)]
}
(K::Single(src), K::Single(dst)) => {
vec![Map(src, dst)]
}
}
}

Ok(Self(map(parse(src)?, parse(dst)?)))
}
}

impl Map {
/// Returns a new modification with the source and destination swapped.
pub fn swapped(self) -> Self {
Self(self.1, self.0)
}
}

/// A user representation of a key on a keyboard.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Key {
Expand Down Expand Up @@ -36,17 +111,6 @@ pub enum Key {
Fn,

/// A character on the keyboard.
///
/// # Examples
///
/// ```
/// use kb_remap::Key;
///
/// let a = Key::Char('a');
/// let b = Key::Char('B');
/// let zero = Key::Char('0');
/// let percent = Key::Char('%');
/// ```
Char(char),

/// A function key e.g. F1, F2, F3, etc.
Expand Down Expand Up @@ -213,6 +277,37 @@ impl Key {
mod tests {
use super::*;

#[test]
fn mod_from_str() {
let tests = &[
("return:A", [Map(Key::Return, Key::Char('A'))].as_slice()),
(
"capslock:0x64",
[Map(Key::CapsLock, Key::Raw(0x64))].as_slice(),
),
(
"command:lcontrol",
[
Map(Key::LeftCommand, Key::LeftControl),
Map(Key::RightCommand, Key::LeftControl),
]
.as_slice(),
),
(
"command:control",
[
Map(Key::LeftCommand, Key::LeftControl),
Map(Key::RightCommand, Key::RightControl),
]
.as_slice(),
),
];

for tc in tests {
assert_eq!(Mappings::from_str(tc.0).unwrap().0, tc.1);
}
}

#[test]
fn key_from_str() {
assert_eq!(Key::from_str("return").unwrap(), Key::Return);
Expand Down

0 comments on commit 4a5ab15

Please sign in to comment.