aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-05-05 14:02:09 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-05-05 14:02:09 +0200
commit47e3b82d0f8c9c4abcaf8588764fa934446dbdc8 (patch)
tree807f4874f1b945b82c00ec5cd666b4173bd09aab
parentfeat(pkgs/lf-make-map): Init (diff)
downloadnixos-config-47e3b82d0f8c9c4abcaf8588764fa934446dbdc8.zip
feat(pkgs/lf-make-map): Change the key to custom type and add visuals
-rw-r--r--sys/nixpkgs/pkgs/lf-make-map/src/generator/mod.rs16
-rw-r--r--sys/nixpkgs/pkgs/lf-make-map/src/generator/mod.rs.old165
-rw-r--r--sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree.rs107
-rw-r--r--sys/nixpkgs/pkgs/lf-make-map/src/mapping/mod.rs145
4 files changed, 181 insertions, 252 deletions
diff --git a/sys/nixpkgs/pkgs/lf-make-map/src/generator/mod.rs b/sys/nixpkgs/pkgs/lf-make-map/src/generator/mod.rs
index 48df027f..c03b33dc 100644
--- a/sys/nixpkgs/pkgs/lf-make-map/src/generator/mod.rs
+++ b/sys/nixpkgs/pkgs/lf-make-map/src/generator/mod.rs
@@ -1,10 +1,10 @@
use std::path::PathBuf;
use anyhow::{Context, Result};
-use log::{debug, info, trace};
+use log::trace;
use walkdir::{DirEntry, WalkDir};
-use crate::mapping::{map_tree::MappingTree, Mapping};
+use crate::mapping::{map_tree::MappingTree, MapKey, Mapping};
pub struct MappingsGenerator {
mappings: MappingTree,
@@ -35,9 +35,15 @@ impl MappingsGenerator {
trace!("Processed '{}'..", directory.path().display());
let mapping = Mapping::new(&home_path, directory.path().to_path_buf());
- mappings
- .insert(&mapping.key.clone(), mapping)
- .context("Failed to insert a key")?;
+ let mapping_key = mapping.key.clone();
+ mappings.insert(&mapping_key, mapping).with_context(|| {
+ format!(
+ "Failed to insert '{}' for path: '{}'\nMapTree is now: \n{}",
+ MapKey::display(&mapping_key),
+ directory.path().display(),
+ mappings,
+ )
+ })?;
}
}
todo!()
diff --git a/sys/nixpkgs/pkgs/lf-make-map/src/generator/mod.rs.old b/sys/nixpkgs/pkgs/lf-make-map/src/generator/mod.rs.old
deleted file mode 100644
index 406b1996..00000000
--- a/sys/nixpkgs/pkgs/lf-make-map/src/generator/mod.rs.old
+++ /dev/null
@@ -1,165 +0,0 @@
-use std::{
- collections::HashMap,
- path::{Path, PathBuf},
-};
-
-use anyhow::{bail, Context, Result};
-use futures::{Stream, StreamExt, TryStreamExt};
-use log::info;
-use tokio::{
- fs::{self, DirEntry},
- io,
- sync::mpsc::{self, Receiver, Sender},
- task::JoinHandle,
-};
-use tokio_stream::wrappers::{ReadDirStream, ReceiverStream};
-
-pub struct MappingGenerator {
- current_mappings: HashMap<String, PathBuf>,
- paths_to_process: Vec<PathBuf>,
-}
-
-pub struct MappingGeneratorHelper {
- tx: Sender<(PathBuf, oneshotSender<PathBuf>)>,
- handle: JoinHandle<()>,
- done: Vec<PathBuf>,
-}
-
-impl MappingGeneratorHelper {
- pub fn new() -> Self {
- let (rx, tx) = mpsc::channel(100);
-
- let handle = tokio::spawn(async move {
- while let Some(dir) = rx.recv().await {
- info!("processing '{}'..", dir.display());
- get_dir(dir);
- }
- });
-
- Self { tx, handle }
- }
-
- pub async fn process(&self, dir: PathBuf) -> Result<()> {
- let (tx, rx) =
- self.tx.send(dir).await?;
- Ok(())
- }
-}
-
-impl MappingGenerator {
- pub async fn new(directories_to_scan: Vec<PathBuf>, depth: usize) -> Result<Self> {
- let cleaned_directories: Vec<PathBuf> = directories_to_scan
- .into_iter()
- .map(check_dir)
- .collect::<Result<_>>()?;
-
- let helper = MappingGeneratorHelper::new();
-
- cleaned_directories
- .into_iter()
- .for_each(|dir| helper.process(dir));
-
- info!(
- "Will process:\n {}",
- all_directories
- .iter()
- .map(|pat| pat.display().to_string())
- .collect::<Vec<_>>()
- .join("\n ")
- );
- Ok(Self {
- current_mappings: HashMap::new(),
- paths_to_process: all_directories,
- })
- }
-}
-
-fn check_dir(dir: PathBuf) -> Result<PathBuf> {
- match dir.metadata() {
- Ok(_) => Ok(dir),
- Err(e) => bail!(
- "'{}' is not a valid path; Error was: '{}'",
- dir.display(),
- e
- ),
- }
-}
-
-pub async fn get_dir(dir: PathBuf, current_depth: usize, max_depth: usize) -> Result<Vec<PathBuf>> {
- let (tx, rx) = mpsc::channel(100);
-
- let handle = tokio::spawn(async move { get_dir_recursive(dir, current_depth, max_depth, tx) });
-
- let out = ReceiverStream::new(rx).collect::<Vec<PathBuf>>().await;
- handle.await?;
- Ok(out)
-}
-
-async fn get_dir_recursive(
- dir: PathBuf,
- current_depth: usize,
- max_depth: usize,
- tx: Sender<PathBuf>,
-) -> Result<()> {
- if dir.is_dir() && current_depth != max_depth {
- tx.send(dir).await?;
-
- match fs::read_dir(&dir).await {
- Ok(directories) => {
- let mut handles: Vec<JoinHandle<Result<(), anyhow::Error>>> = vec![];
- while let Some(entry) = directories
- .next_entry()
- .await
- .with_context(|| format!("Failed to read directory: '{}'", dir.display()))?
- {
- let tx_new = tx.clone();
- handles.push(tokio::spawn(async move {
- get_dir_recursive(entry.path(), current_depth + 1, max_depth, tx_new)
- .await
- .with_context(|| {
- format!("Failed to get child directories to '{}'", dir.display())
- })?;
-
- Ok(())
- }));
- }
-
- let out: Vec<_> = tokio_stream::iter(handles)
- .then(|handle| async move { handle.await })
- .collect()
- .await;
-
- // I have no idea what happened here to the type system
- for i in out {
- i??
- }
-
- Ok(())
- }
-
- Err(e) => {
- bail!(
- "Unable to read directory {}, skipping; error: {}",
- dir.display(),
- e
- );
- }
- }
- } else {
- return Ok(());
- }
-}
-
-#[cfg(test)]
-mod test {
- use std::path::PathBuf;
-
- use super::get_dir;
-
- #[test]
- fn test_get_dir() {
- let dirs = get_dir(PathBuf::from("~/repos"));
- let expected_dirs = vec![PathBuf::from("~/repos/rust")];
- assert_eq!(dirs, expected_dirs);
- }
-}
diff --git a/sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree.rs b/sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree.rs
index 44165ed1..90296044 100644
--- a/sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree.rs
+++ b/sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree.rs
@@ -1,6 +1,6 @@
-use std::collections::HashMap;
+use std::{collections::HashMap, fmt::Display, path::PathBuf};
-use super::{error, Mapping};
+use super::{error, MapKey, Mapping};
/// A prefix tree
pub struct MappingTree {
@@ -9,33 +9,33 @@ pub struct MappingTree {
#[derive(Clone)]
pub struct Node {
- children: HashMap<char, Node>,
+ children: HashMap<MapKey, Node>,
value: Option<Mapping>,
/// The key needed to get to this node
- location: String,
+ location: Vec<MapKey>,
}
impl MappingTree {
pub fn new() -> Self {
Self {
- root: Node::new(String::new(), None),
+ root: Node::new(vec![], None),
}
}
/// Returns the node at the key, otherwise None
- pub fn get(&self, key: &str) -> Option<&Node> {
+ pub fn get(&self, key: &[MapKey]) -> Option<&Node> {
let mut current_node = &self.root;
- for ch in key.chars() {
+ for ch in key.iter() {
current_node = current_node.children.get(&ch)?
}
Some(current_node)
}
/// Returns the node at the key, otherwise None. The node can be changed
- pub fn get_mut(&mut self, key: &str) -> Option<&mut Node> {
+ pub fn get_mut(&mut self, key: &[MapKey]) -> Option<&mut Node> {
let mut current_node = &mut self.root;
- for ch in key.chars() {
+ for ch in key.iter() {
current_node = current_node.children.get_mut(&ch)?
}
@@ -43,9 +43,9 @@ impl MappingTree {
}
/// Returns the node at the key, otherwise the last node that matched.
- pub fn try_get(&self, key: &str) -> &Node {
+ pub fn try_get(&self, key: &[MapKey]) -> &Node {
let mut current_node = &self.root;
- for ch in key.chars() {
+ for ch in key.iter() {
if let Some(node) = current_node.children.get(&ch) {
current_node = node;
} else {
@@ -56,20 +56,22 @@ impl MappingTree {
current_node
}
- pub fn insert(&mut self, key: &str, mapping: Mapping) -> Result<(), error::Error> {
+ pub fn insert(&mut self, key: &[MapKey], mapping: Mapping) -> Result<(), error::Error> {
let node = self.try_get(key).clone();
- if node.location.as_str() != key {
- let needed_nodes_key = key.trim_start_matches(node.location.as_str());
- let needed_nodes_length = needed_nodes_key.chars().count();
+ if node.location.as_slice() != key {
+ let needed_nodes_key = key
+ .strip_prefix(node.location.as_slice())
+ .expect("The node's location is a prefix");
+ let needed_nodes_length = needed_nodes_key.iter().count();
let mut current_node = self
.get_mut(&node.location)
.expect("This should always exists");
let mut current_location = node.location.clone();
- let mut counter = 0;
+ let mut counter = 1;
- for ch in needed_nodes_key.chars() {
- current_location.push(ch);
+ for ch in needed_nodes_key.iter() {
+ current_location.push(ch.to_owned());
let next_node = if counter == needed_nodes_length {
Node::new(current_location.clone(), Some(mapping.clone()))
@@ -77,7 +79,7 @@ impl MappingTree {
Node::new(current_location.clone(), None)
};
- current_node.children.insert(ch, next_node);
+ current_node.children.insert(ch.to_owned(), next_node);
current_node = current_node
.children
.get_mut(&ch)
@@ -85,7 +87,7 @@ impl MappingTree {
counter += 1;
}
} else {
- return Err(error::Error::NodeExits(key.to_owned()));
+ return Err(error::Error::NodeExits(MapKey::display(key)));
}
Ok(())
@@ -93,7 +95,7 @@ impl MappingTree {
}
impl Node {
- pub fn new(location: String, mapping: Option<Mapping>) -> Self {
+ pub fn new(location: Vec<MapKey>, mapping: Option<Mapping>) -> Self {
Self {
children: HashMap::new(),
location,
@@ -101,3 +103,66 @@ impl Node {
}
}
}
+
+impl Display for MappingTree {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ fn write_node(
+ node: &Node,
+ indention: String,
+ has_parent: bool,
+ is_last: bool,
+ f: &mut std::fmt::Formatter<'_>,
+ ) -> std::fmt::Result {
+ let bullet = if has_parent {
+ if is_last {
+ String::from("└── ")
+ } else {
+ String::from("├── ")
+ }
+ } else {
+ String::new()
+ };
+
+ let node_value = if let Some(value) = &node.value {
+ value.to_string()
+ } else {
+ "[No Value]".to_owned()
+ };
+
+ let new_idention = if !has_parent {
+ String::new()
+ } else if is_last {
+ indention.replace('│', " ") + " "
+ } else {
+ indention.clone() + "│ "
+ };
+
+ write!(
+ f,
+ "{}{}\x1b[1;33m{}\x1b[0m: {}\n",
+ indention,
+ bullet,
+ MapKey::display(&node.location),
+ node_value,
+ )?;
+
+ let value_length = node.children.len();
+ let mut counter = 1;
+
+ for child in node.children.values() {
+ if counter == value_length {
+ write_node(child, new_idention.clone(), true, true, f)?;
+ } else {
+ write_node(child, new_idention.clone(), true, false, f)?;
+ };
+ counter += 1;
+ }
+
+ Ok(())
+ }
+
+ write_node(&self.root, String::new(), false, false, f)?;
+
+ Ok(())
+ }
+}
diff --git a/sys/nixpkgs/pkgs/lf-make-map/src/mapping/mod.rs b/sys/nixpkgs/pkgs/lf-make-map/src/mapping/mod.rs
index 7de1ca5d..d05d3417 100644
--- a/sys/nixpkgs/pkgs/lf-make-map/src/mapping/mod.rs
+++ b/sys/nixpkgs/pkgs/lf-make-map/src/mapping/mod.rs
@@ -1,4 +1,7 @@
-use std::path::{Path, PathBuf};
+use std::{
+ fmt::Display,
+ path::{Path, PathBuf},
+};
use log::debug;
@@ -11,15 +14,42 @@ pub struct Mapping {
pub keys: usize,
- pub key: String,
+ pub key: Vec<MapKey>,
}
+
+#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Hash, Eq)]
+pub struct MapKey {
+ value: String,
+}
+
+impl MapKey {
+ pub fn new(value: String) -> Self {
+ Self { value }
+ }
+ pub fn display(values: &[Self]) -> String {
+ values.iter().map(|value| value.value.clone()).collect()
+ }
+}
+
+impl Display for MapKey {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_str(&self.value)
+ }
+}
+
+impl Display for Mapping {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", self.raw_path.display())
+ }
+}
+
impl Mapping {
pub fn new(home_path: &Path, initial_path: PathBuf) -> Mapping {
let raw_path = initial_path
.strip_prefix(home_path)
.expect("Must always be under the `home_path`");
- let key = Self::path_to_key(raw_path.to_str().expect("Should be a valid &str"));
+ let key = Self::path_to_keys(raw_path.to_str().expect("Should be a valid &str"));
Self {
raw_path: raw_path.to_owned(),
@@ -28,71 +58,64 @@ impl Mapping {
}
}
- fn path_to_key(path: &str) -> String {
- let key: String = path
- .split('/')
- .map(|part| part.chars().nth(0).expect("Must have a first element"))
- .collect();
- debug!("'{}' -> '{}'", path, key);
+ fn path_to_keys(path: &str) -> Vec<MapKey> {
+ let key: Vec<MapKey> = path.split('/').map(Self::part_path_to_key).collect();
+ debug!("Will insert: '{}' -> '{}'", path, MapKey::display(&key));
key
}
-}
-pub fn gen_hot_key(path: &Path, base_path: &Path, amount_of_chars: usize) -> String {
- let path_filename_as_str = path
- .file_name()
- .expect("All paths here should have a file name")
- .to_str()
- .expect("The OSstr should be convertible");
-
- let mut return_val = String::from("g");
- if path != base_path {
- return_val.push(
- base_path
- .file_name()
- .expect("All paths here should have a file name")
- .to_str()
- .expect("The OSstr should be convertible")
- .chars()
- .nth(0)
- .expect("All names should have a first char"),
- );
- }
- if path_filename_as_str.contains("_") {
- path_filename_as_str.split("_").for_each(|a| {
- return_val.push(
- a.chars()
- .nth(0)
- .expect("All names should have a first char"),
- )
- });
- } else {
- if path == base_path {
- return_val.push(
- path_filename_as_str
- .chars()
- .nth(0)
- .expect("All names should have a first char"),
- );
+ fn part_path_to_key(part: &str) -> MapKey {
+ let value = if part.contains('_') {
+ part.split('_').filter_map(|ch| ch.chars().nth(0)).collect()
+ } else if part.contains('-') {
+ part.split('-').filter_map(|ch| ch.chars().nth(0)).collect()
} else {
- for a in 0..amount_of_chars {
- return_val.push(if let Some(b) = path_filename_as_str.chars().nth(a) {
- b
- } else {
- path_filename_as_str
- .chars()
- .nth(0)
- .expect("All names should have a first char")
- });
- }
- }
- }
- if path == base_path {
- return_val.push('.');
+ part.chars()
+ .nth(0)
+ .expect("Must have a first element")
+ .to_string()
+ };
+ MapKey::new(value)
}
- return_val
}
+// pub fn gen_hot_key(path: &Path, base_path: &Path, amount_of_chars: usize) -> String {
+// let mut return_val = String::from("g");
+// if path_filename_as_str.contains("_") {
+// path_filename_as_str.split("_").for_each(|a| {
+// return_val.push(
+// a.chars()
+// .nth(0)
+// .expect("All names should have a first char"),
+// )
+// });
+// } else {
+// if path == base_path {
+// return_val.push(
+// path_filename_as_str
+// .chars()
+// .nth(0)
+// .expect("All names should have a first char"),
+// );
+// } else {
+// for a in 0..amount_of_chars {
+// return_val.push(if let Some(b) = path_filename_as_str.chars().nth(a) {
+// b
+// } else {
+// path_filename_as_str
+// .chars()
+// .nth(0)
+// .expect("All names should have a first char")
+// });
+// }
+// }
+// }
+// if path == base_path {
+// return_val.push('.');
+// }
+// return_val
+// }
+
#[cfg(test)]
mod tests {
use super::*;