Skip to content

Commit

Permalink
Define trait and constants for importance
Browse files Browse the repository at this point in the history
  • Loading branch information
dhruvkb committed Jul 14, 2023
1 parent ea02c0d commit 9d75392
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 0 deletions.
95 changes: 95 additions & 0 deletions src/models/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ pub struct Constants {
pub symlink: HashMap<SymState, SymlinkInfo>,
/// configuration for the table view
pub table: TableInfo,
/// pairings of importance levels with styling directives
pub imp: Vec<(i8, String)>,

/// mapping of importance levels to styling directives, derived from `imp`
#[serde(skip)]
pub imp_map: HashMap<i8, String>,
}

impl Default for Constants {
Expand Down Expand Up @@ -156,10 +162,48 @@ impl Default for Constants {
.map(|(k, v)| (k, v.to_string()))
.collect(),
},
imp: [(-1, "dimmed"), (1, "italic"), (2, "underline")]
.into_iter()
.map(|(k, v)| (k, v.to_string()))
.collect(),

imp_map: HashMap::new(), // set in Constants::set_imp_map
}
}
}

impl Constants {
/// Set `imp_map` from `imp` and then use it to clean the latter.
///
/// If a level has been defined multiple times, only the last definition
/// will be retained in `imp_map`. The levels will be sorted by importance
/// in `imp`.
pub fn massage_imps(&mut self) {
self.imp_map = self.imp.iter().map(|(k, v)| (*k, v.to_string())).collect();

self.imp = self.imp_map.clone().into_iter().collect();
self.imp.sort_by_cached_key(|entry| entry.0);
}

/// Get the lowest configured importance level, i.e. zeroth index in `imp`.
pub fn min_imp(&self) -> i8 {
self.get_imp(0)
}

/// Get the highest configured importance level, i.e. last index in `imp`.
pub fn max_imp(&self) -> i8 {
self.get_imp(self.imp.len() - 1)
}

/// Get the importance level at the given index.
///
/// This returns 0 (default for `i8`) if the `imp` vector does not have the
/// given index.
fn get_imp(&self, idx: usize) -> i8 {
self.imp.get(idx).map(|row| row.0).unwrap_or_default()
}
}

#[derive(Serialize, Deserialize)]
pub struct NlinkStyles {
/// style to use when file has one hard link
Expand Down Expand Up @@ -217,3 +261,54 @@ pub struct TableInfo {
/// the styles to apply to the text in the header row
pub header_style: String,
}

#[cfg(test)]
mod tests {
use super::Constants;
use std::collections::HashMap;

macro_rules! make_massage_imps_test {
( $($name:ident: $imp:expr => $exp_imp:expr,)* ) => {
$(
#[test]
fn $name() {
let imp: Vec<(i8, String)> = $imp
.into_iter()
.map(|(k, v): (i8, &str)| (k, v.to_string()))
.collect();
let exp_imp: Vec<(i8, String)> = $exp_imp
.into_iter()
.map(|(k, v): (i8, &str)| (k, v.to_string()))
.collect();
let exp_imp_map: HashMap<i8, String> = $exp_imp
.into_iter()
.map(|(k, v): (i8, &str)| (k, v.to_string()))
.collect();

let mut constants = Constants {
imp,
..Constants::default()
};
constants.massage_imps();
assert_eq!(constants.imp, exp_imp);
assert_eq!(constants.imp_map, exp_imp_map);
}
)*
}
}

make_massage_imps_test!(
test_empty: vec![] => vec![],
test_sorting: vec![
(2, "underline"),
(1, "italic"),
] => vec![(1, "italic"), (2, "underline")],
test_deduplication: vec![
(2, "bold"),
(2, "dimmed"),
(1, "reversed"),
(2, "underline"),
(1, "italic"),
] => vec![(1, "italic"), (2, "underline")],
);
}
2 changes: 2 additions & 0 deletions src/traits.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
mod detail;
mod imp;
mod name;
mod sym;

pub use detail::Detail;
pub use imp::Imp;
pub use name::Name;
pub use sym::Sym;
79 changes: 79 additions & 0 deletions src/traits/imp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use crate::config::{Args, Conf};
use crate::models::Node;
use log::debug;

pub trait Imp {
fn default_imp(&self) -> i8;
fn imp_val(&self, args: &Args) -> i8;

fn is_visible(&self, conf: &Conf, args: &Args) -> bool;

fn directives(&self, conf: &Conf, args: &Args) -> Option<String>;
}

impl Imp for Node<'_> {
/// Get the implicit relative importance of the node.
///
/// This is the importance associated with a node if it has not been set by
/// any matching spec. By default we assume nodes with a leading dot to be
/// less important, as they are normally hidden by the `ls(1)` command.
fn default_imp(&self) -> i8 {
if self.name.starts_with('.') {
-1
} else {
0
}
}

/// Get the relative importance of the node.
///
/// This iterates through the specs in reverse, finding the first available
/// importance or falling back the the [default](Imp::default_imp). Then it
/// subtracts the baseline level from the CLI args.
fn imp_val(&self, args: &Args) -> i8 {
self.specs
.iter()
.rev()
.find_map(|spec| spec.importance)
.unwrap_or(self.default_imp())
- args.imp
}

/// Determine whether the node should be displayed in the list.
///
/// Elements below the lowest-defined relative-importance are hidden.
fn is_visible(&self, conf: &Conf, args: &Args) -> bool {
debug!("Checking visibility of \"{self}\" based on importance.");
let rel_imp = self.imp_val(args);
let min_val = conf.constants.min_imp();

let is_visible = rel_imp >= min_val;
if !is_visible {
debug!("\"{self}\" with relative importance {rel_imp} (min: {min_val}) is hidden.")
}
is_visible
}

/* Directives */
/* ========== */

/// Get the directives associated with the node's relative importance.
///
/// The directives are read from the configuration with any missing values
/// having no directives set for them.
///
/// If the node's importance is above the maximum defined, it will be set to
/// the maximum. If it is below the minimum defined, it will already be
/// hidden by [`is_visible`](Imp::is_visible).
fn directives(&self, conf: &Conf, args: &Args) -> Option<String> {
let mut rel_imp = self.imp_val(args);
let max_val = conf.constants.max_imp();
let min_val = conf.constants.min_imp();
debug!("\"{self}\" has relative importance {rel_imp} (min: {min_val}, max: {max_val})");

if rel_imp > max_val {
rel_imp = max_val;
}
conf.constants.imp_map.get(&rel_imp).cloned()
}
}

0 comments on commit 9d75392

Please sign in to comment.