Skip to content

Commit

Permalink
name regex pattern icon type
Browse files Browse the repository at this point in the history
  • Loading branch information
tuna-f1sh committed Jun 30, 2024
1 parent 9667cfd commit 1bb7170
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 4 deletions.
39 changes: 39 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ rand = "0.8.5"
terminal_size = "0.2.5"
strum = "0.24.1"
strum_macros = "0.24.3"
regex = "1.10.5"

[dev-dependencies]
diff = "0.1"
Expand Down
1 change: 1 addition & 0 deletions doc/cyme_example_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"user": {
"classifier#02": "",
"classifier-sub-protocol#fe:01:01": "",
"name#.*sd\\scard\\sreader.*": "",
"undefined-classifier": "",
"unknown-vendor": "",
"vid#05ac": "",
Expand Down
72 changes: 68 additions & 4 deletions src/icon.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! Icons and themeing of cyme output
use regex;
use serde::{Deserialize, Serialize};
use serde_with::{DeserializeFromStr, SerializeDisplay};
use std::collections::HashMap;
Expand Down Expand Up @@ -35,6 +36,8 @@ pub enum Icon {
Classifier(ClassCode),
/// Class classifier lookup with SubClass and Protocol
ClassifierSubProtocol((ClassCode, u8, u8)),
/// Pattern match device name icon
Name(String),
/// Icon for unknown vendors
UnknownVendor,
/// Icon for undefined classifier
Expand Down Expand Up @@ -86,6 +89,15 @@ impl FromStr for Icon {
"Invalid Icon enum name or valued enum without value",
)),
}
// name#pattern
} else if matches!(enum_name, "name") {
match regex::Regex::new(value_split[1]) {
Ok(_) => Ok(Icon::Name(value_split[1].to_string())),
Err(_) => Err(Error::new(
ErrorKind::Parsing,
"Invalid regex pattern in Icon enum string",
)),
}
// enum contains value
} else {
let (parse_ints, errors): (Vec<Result<u32, _>>, Vec<_>) = value_split[1]
Expand Down Expand Up @@ -161,6 +173,7 @@ impl fmt::Display for Icon {
c.1,
c.2
),
Icon::Name(s) => write!(f, "name#{}", s),
Icon::Endpoint(Direction::In) => write!(f, "endpoint_in"),
Icon::Endpoint(Direction::Out) => write!(f, "endpoint_out"),
_ => {
Expand Down Expand Up @@ -263,8 +276,7 @@ lazy_static! {
(Icon::Vid(0x1fc9), "\u{f2db}"), // nxp 
(Icon::Vid(0x1050), "\u{f084}"), // yubikey 
(Icon::Vid(0x0781), "\u{f129e}"), // sandisk 󱊞
(Icon::VidPid((0x05ac, 0x8409)), "\u{ef61}"), // Apple sd card reader 
(Icon::VidPid((0x05e3, 0x0749)), "\u{ef61}"), // USB 3.0 SD Card reader 
(Icon::Name(r".*sd\scard\sreader.*".to_string()), "\u{ef61}"), // sd card reader 
(Icon::VidPid((0x18D1, 0x2D05)), "\u{e70e}"), // android dev 
(Icon::VidPid((0x18D1, 0xd00d)), "\u{e70e}"), // android 
(Icon::VidPid((0x1d50, 0x606f)), "\u{f191d}"), // candlelight_fw gs_can 󱤝
Expand Down Expand Up @@ -365,10 +377,15 @@ impl IconTheme {
}
}

/// Get icon for USBDevice `d` by checking `Self` using Vendor ID and Product ID
/// Get icon for USBDevice `d` by checking `Self` using Name, Vendor ID and Product ID
pub fn get_device_icon(&self, d: &USBDevice) -> String {
if let (Some(vid), Some(pid)) = (d.vendor_id, d.product_id) {
self.get_vidpid_icon(vid, pid)
// try name first since vidpid will return UnknownVendor default icon if not found
// does mean regex will be built/checked for every device
match self.get_name_icon(&d.name) {
s if !s.is_empty() => s,
_ => self.get_vidpid_icon(vid, pid),
}
} else {
String::new()
}
Expand Down Expand Up @@ -421,6 +438,41 @@ impl IconTheme {
IconTheme::get_default_classifier_icon(class, sub, protocol)
}
}

/// Get default icon for device based on descriptor name pattern `[Icon::Name]` pattern match
pub fn get_default_name_icon(name: &str) -> String {
DEFAULT_ICONS
.iter()
.find(|(k, _)| {
if let Icon::Name(s) = k {
regex::Regex::new(s).map_or(false, |r| r.is_match(&name.to_lowercase()))
} else {
false
}
})
.map(|(_, v)| v.to_owned())
.unwrap_or("")
.to_string()
}

/// Get icon for device based on descriptor name pattern `[Icon::Name]` pattern match
pub fn get_name_icon(&self, name: &str) -> String {
if let Some(user_icons) = self.user.as_ref() {
user_icons
.iter()
.find(|(k, _)| {
if let Icon::Name(s) = k {
regex::Regex::new(s).map_or(false, |r| r.is_match(&name.to_lowercase()))
} else {
false
}
})
.map(|(_, v)| v.to_owned())
.unwrap_or(String::new())
} else {
IconTheme::get_default_name_icon(name)
}
}
}

/// Gets tree icon from [`DEFAULT_UTF8_TREE`] or [`DEFAULT_ASCII_TREE`] (depanding on [`Encoding`]) as `String` with `unwrap` because should panic if missing from there
Expand Down Expand Up @@ -458,6 +510,10 @@ pub fn example() -> HashMap<Icon, String> {
"\u{e795}".into(),
), // serial 
(Icon::UndefinedClassifier, "\u{2636}".into()), //☶
(
Icon::Name(r".*sd\scard\sreader.*".to_string()),
"\u{ef61}".into(),
), // sd card reader 
])
}

Expand Down Expand Up @@ -561,5 +617,13 @@ mod tests {
let str = "unknown-vendor";
let icon = Icon::from_str(str);
assert_eq!(icon.unwrap(), Icon::UnknownVendor);

let str = "name#test";
let icon = Icon::from_str(str);
assert_eq!(icon.unwrap(), Icon::Name("test".to_string()));

let str = r"name#sd\s+card";
let icon = Icon::from_str(str);
assert_eq!(icon.unwrap(), Icon::Name("sd\\s+card".to_string()));
}
}

0 comments on commit 1bb7170

Please sign in to comment.