aboutsummaryrefslogtreecommitdiffstats
path: root/pkgs/by-name/lf/lf-make-map/src/mapping
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/by-name/lf/lf-make-map/src/mapping')
-rw-r--r--pkgs/by-name/lf/lf-make-map/src/mapping/map_tree/display.rs91
-rw-r--r--pkgs/by-name/lf/lf-make-map/src/mapping/map_tree/iterator.rs53
-rw-r--r--pkgs/by-name/lf/lf-make-map/src/mapping/map_tree/lf_mapping.rs19
-rw-r--r--pkgs/by-name/lf/lf-make-map/src/mapping/map_tree/mod.rs402
-rw-r--r--pkgs/by-name/lf/lf-make-map/src/mapping/mod.rs156
5 files changed, 721 insertions, 0 deletions
diff --git a/pkgs/by-name/lf/lf-make-map/src/mapping/map_tree/display.rs b/pkgs/by-name/lf/lf-make-map/src/mapping/map_tree/display.rs
new file mode 100644
index 00000000..65302e1e
--- /dev/null
+++ b/pkgs/by-name/lf/lf-make-map/src/mapping/map_tree/display.rs
@@ -0,0 +1,91 @@
+use std::fmt::Display;
+
+use crate::mapping::{
+ map_tree::{Node, NodeValue},
+ MapKey,
+};
+
+use super::MappingTree;
+
+impl Display for MappingTree {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ fn write_node(
+ f: &mut std::fmt::Formatter<'_>,
+ node: &Node,
+ indention: String,
+ location: Vec<MapKey>,
+ is_last: bool,
+ is_root: bool,
+ ) -> std::fmt::Result {
+ let node_value = match &node.value {
+ NodeValue::Parent { children: _ } => "<Parent>".to_owned(),
+ NodeValue::Child { path, extandable } => {
+ path.to_owned() + if *extandable { " [exten.]" } else { " [stop]" }
+ }
+ };
+
+ let new_idention = indention.clone()
+ + if is_root {
+ ""
+ } else {
+ match is_last {
+ true => " ",
+ false => "│ ",
+ }
+ };
+
+ let bullet = match is_last {
+ true => String::from("└── "),
+ false => String::from("├── "),
+ };
+
+ if is_root {
+ write!(f, ": {}\n", node_value)?;
+ } else {
+ write!(
+ f,
+ "{}{}\x1b[1;33m{}\x1b[0m: {}\n",
+ indention,
+ bullet,
+ MapKey::display(&location),
+ node_value,
+ )?;
+ };
+
+ match &node.value {
+ NodeValue::Parent { children } => {
+ let mut children_vec: Vec<(&MapKey, &Node)> = children.iter().collect();
+ children_vec.sort_by(|(a, _), (b, _)| a.key.cmp(&b.key));
+
+ let mut counter = 1;
+ for (key, child) in &children_vec {
+ let mut new_location = location.clone();
+ new_location.push((*key).to_owned());
+
+ write_node(
+ f,
+ child,
+ new_idention.clone(),
+ new_location.clone(),
+ counter == children_vec.len(),
+ false,
+ )?;
+ counter += 1;
+ }
+ }
+ NodeValue::Child {
+ path: _,
+ extandable: _,
+ } => {
+ // Do nothing and stop the recursion
+ }
+ }
+
+ Ok(())
+ }
+
+ write_node(f, &self.root, String::new(), vec![], false, true)?;
+
+ Ok(())
+ }
+}
diff --git a/pkgs/by-name/lf/lf-make-map/src/mapping/map_tree/iterator.rs b/pkgs/by-name/lf/lf-make-map/src/mapping/map_tree/iterator.rs
new file mode 100644
index 00000000..4364bb2b
--- /dev/null
+++ b/pkgs/by-name/lf/lf-make-map/src/mapping/map_tree/iterator.rs
@@ -0,0 +1,53 @@
+use crate::mapping::MapKey;
+
+use super::{MappingTree, Node, NodeValue};
+
+pub struct MappingTreeIterator {
+ children: Vec<(Vec<MapKey>, String)>,
+}
+
+impl MappingTreeIterator {
+ pub fn new(tree: &MappingTree, ignore_extendable: bool) -> Self {
+ let children = extract_child(vec![], &tree.root, ignore_extendable);
+
+ Self { children }
+ }
+}
+
+fn extract_child(
+ current_key: Vec<MapKey>,
+ node: &Node,
+ ignore_extendable: bool,
+) -> Vec<(Vec<MapKey>, String)> {
+ match &node.value {
+ NodeValue::Parent { children } => children
+ .iter()
+ .map(|(key, value)| {
+ let mut new_key = current_key.clone();
+ new_key.push(key.to_owned());
+
+ extract_child(new_key, value, ignore_extendable)
+ })
+ .flatten()
+ .collect(),
+ NodeValue::Child { path, extandable } => {
+ if ignore_extendable {
+ vec![(current_key, path.to_string())]
+ } else {
+ if *extandable {
+ vec![(current_key, path.to_string())]
+ } else {
+ vec![]
+ }
+ }
+ }
+ }
+}
+
+impl Iterator for MappingTreeIterator {
+ type Item = (Vec<MapKey>, String);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.children.pop()
+ }
+}
diff --git a/pkgs/by-name/lf/lf-make-map/src/mapping/map_tree/lf_mapping.rs b/pkgs/by-name/lf/lf-make-map/src/mapping/map_tree/lf_mapping.rs
new file mode 100644
index 00000000..6d9c7a0d
--- /dev/null
+++ b/pkgs/by-name/lf/lf-make-map/src/mapping/map_tree/lf_mapping.rs
@@ -0,0 +1,19 @@
+use std::path::PathBuf;
+
+use crate::mapping::MapKey;
+
+use super::MappingTree;
+
+impl MappingTree {
+ pub fn to_lf_mappings(self, home_path: PathBuf) -> String {
+ self.iter(true)
+ .map(|(key, value)| {
+ format!(
+ "map g{} cd \"{}\"\n",
+ MapKey::display(&key),
+ home_path.join(&value).display()
+ )
+ })
+ .collect()
+ }
+}
diff --git a/pkgs/by-name/lf/lf-make-map/src/mapping/map_tree/mod.rs b/pkgs/by-name/lf/lf-make-map/src/mapping/map_tree/mod.rs
new file mode 100644
index 00000000..35e6d91d
--- /dev/null
+++ b/pkgs/by-name/lf/lf-make-map/src/mapping/map_tree/mod.rs
@@ -0,0 +1,402 @@
+use std::{collections::HashMap, mem};
+
+use anyhow::{bail, Result};
+use log::debug;
+
+use self::iterator::MappingTreeIterator;
+
+use super::MapKey;
+
+pub mod display;
+pub mod iterator;
+pub mod lf_mapping;
+
+/// A prefix tree
+#[derive(Debug)]
+pub struct MappingTree {
+ root: Node,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum NodeValue {
+ Parent { children: HashMap<MapKey, Node> },
+ Child { path: String, extandable: bool },
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct Node {
+ value: NodeValue,
+}
+
+impl MappingTree {
+ pub fn new() -> Self {
+ Self {
+ root: Node::new_parent(),
+ }
+ }
+
+ pub fn root_node(&self) -> &Node {
+ &self.root
+ }
+
+ pub fn iter(&self, ignore_extendable: bool) -> MappingTreeIterator {
+ MappingTreeIterator::new(&self, ignore_extendable)
+ }
+
+ /// Returns the node at the key, otherwise None. The node can be changed
+ pub fn get_mut(&mut self, key: &[MapKey]) -> Option<&mut Node> {
+ let mut current_node = &mut self.root;
+ for ch in key.iter() {
+ if let NodeValue::Parent { children } = &mut current_node.value {
+ current_node = children.get_mut(&ch)?
+ } else {
+ return None;
+ }
+ }
+
+ Some(current_node)
+ }
+
+ /// Returns the node at the key, otherwise the last node that matched.
+ pub fn try_get(&self, key: &[MapKey]) -> (&Node, Vec<MapKey>) {
+ let mut current_node = &self.root;
+ let mut current_key = vec![];
+
+ for ch in key.iter() {
+ if let NodeValue::Parent { children } = &current_node.value {
+ current_node = if let Some(node) = children.get(&ch) {
+ let (key, _value) = children
+ .get_key_value(&ch)
+ .expect("This exists, we checked");
+ current_key.push(key.clone());
+
+ node
+ } else {
+ return (current_node, current_key);
+ };
+ } else {
+ return (current_node, current_key);
+ }
+ }
+
+ (current_node, current_key)
+ }
+
+ pub fn include(&mut self, path: &str) -> Result<()> {
+ let associated_key = MapKey::new_ones_from_path(path, 1);
+ self.insert(&associated_key, path)
+ }
+
+ pub fn insert(&mut self, key: &[MapKey], path: &str) -> Result<()> {
+ self.insert_node(key, Node::new_child(path.to_owned()))
+ }
+
+ pub fn interleave(&mut self, key: &[MapKey], node: Node) -> Result<()> {
+ let want_to_be_parent = self.get_mut(&key).expect("This value exists");
+ let (parent_value, _parent_children) = if let NodeValue::Parent { children } = node.value {
+ (
+ NodeValue::Parent {
+ children: children.clone(),
+ },
+ children,
+ )
+ } else {
+ unreachable!("This value will be a parent")
+ };
+
+ let child_value = mem::replace(&mut want_to_be_parent.value, parent_value);
+ assert!(matches!(
+ child_value,
+ NodeValue::Child {
+ path: _,
+ extandable: _
+ }
+ ));
+
+ let child_value = if let NodeValue::Child {
+ path,
+ extandable: _,
+ } = child_value
+ {
+ NodeValue::Child {
+ path,
+ extandable: false,
+ }
+ } else {
+ unreachable!("This is only a child value")
+ };
+
+ let child = Node { value: child_value };
+
+ let mut new_key = key.to_vec();
+ new_key.push(MapKey {
+ key: '.',
+ part_path: ".".to_owned(),
+ resolution: 1,
+ });
+ self.insert_node(&new_key, child)?;
+ Ok(())
+ }
+
+ pub fn insert_node(&mut self, key: &[MapKey], node: Node) -> Result<()> {
+ let (_node, found_key) = self.try_get(key).clone();
+
+ if found_key != key {
+ let needed_nodes_key = key
+ .strip_prefix(&found_key[..])
+ .expect("The node's location is a prefix");
+
+ let needed_nodes_length = needed_nodes_key.iter().count();
+
+ let mut current_node = self
+ .get_mut(&found_key[..])
+ .expect("This should always exists");
+ let mut current_location = found_key.clone();
+ let mut counter = 1;
+
+ for ch in needed_nodes_key.iter() {
+ current_location.push(ch.to_owned());
+
+ let next_node = if counter == needed_nodes_length {
+ node.clone()
+ } else {
+ Node::new_parent()
+ };
+
+ current_node = match &current_node.value {
+ NodeValue::Parent { children } => {
+ assert_eq!(children.get(&ch), None);
+
+ let children =
+ if let NodeValue::Parent { children } = &mut current_node.value {
+ children
+ } else {
+ unreachable!("This is a parent, we cheched")
+ };
+
+ children.insert(ch.to_owned(), next_node);
+ children.get_mut(&ch).expect("Was just inserted")
+ }
+ NodeValue::Child {
+ path,
+ extandable: _,
+ } => {
+ // A node that should be a parent was classified
+ // as child before:
+ //
+ // 1. Remove the child node and replace it with a parent one.
+ // 2. Add the child node to the parent node as child, but with a '.' as MapKey.
+ // 3. Add the original node also as child to the parent node.
+
+ let mut children = HashMap::new();
+ let move_child_node = Node::new_child(path.to_owned());
+
+ children.insert(
+ MapKey {
+ key: '.',
+ part_path: ".".to_owned(),
+ resolution: 1,
+ },
+ move_child_node,
+ );
+ children.insert(ch.to_owned(), next_node);
+
+ current_node.value = NodeValue::Parent { children };
+
+ let children =
+ if let NodeValue::Parent { children } = &mut current_node.value {
+ children
+ } else {
+ unreachable!("We just inserted the parent value.")
+ };
+
+ children.get_mut(&ch).expect("Was just inserted")
+ }
+ };
+
+ counter += 1;
+ }
+ } else {
+ fn reduce_string(a: &str) -> Option<char> {
+ let first_char = a.chars().take(1).last().expect("Should contain one char");
+
+ if a.chars().all(|ch| ch == first_char) {
+ return Some(first_char);
+ } else {
+ return None;
+ }
+ }
+ fn check_subset(a: &str, b: &str) -> bool {
+ if a.len() > b.len() {
+ let a_prefix: String = a.chars().take(b.len()).collect();
+ let a_suffix: String = a.chars().skip(b.len()).collect();
+
+ if a_prefix == b {
+ let clean_suffix = reduce_string(&a_suffix);
+ if let Some(ch) = clean_suffix {
+ ch == b.chars().last().expect("Will match")
+ } else {
+ false
+ }
+ } else {
+ false
+ }
+ } else if b.len() > a.len() {
+ let b_prefix: String = b.chars().take(a.len()).collect();
+ let b_suffix: String = b.chars().skip(a.len()).collect();
+
+ if b_prefix == a {
+ let clean_suffix = reduce_string(&b_suffix);
+ if let Some(ch) = clean_suffix {
+ ch == a.chars().last().expect("Will match")
+ } else {
+ false
+ }
+ } else {
+ false
+ }
+ } else {
+ a == b
+ }
+ }
+
+ // Another node was already inserted with the same key!
+ // So we simple increase the resolution of the other node and this node, until their
+ // keys are not the same anymore.
+ // This only includes the last segment of the `MapKey`
+ //
+ // 1. Change both keys, until they are not equal any more
+ // 2. Move the wrongly placed node to the new place.
+ // 3. Insert our node.
+ let mut foreign_key = vec![found_key.last().expect("This will exist").clone()];
+ let mut our_key = vec![key.last().expect("This will exist").clone()];
+
+ debug!(
+ "'{}' ('{}') and '{}' ('{}') are the same, try to find a better combination!",
+ MapKey::display(&our_key),
+ our_key[0].part_path,
+ MapKey::display(&foreign_key),
+ foreign_key[0].part_path,
+ );
+
+ // The 'a' and 'b' stuff is here, to ensure that both returning None will not match
+ // this condition.
+ if reduce_string(&foreign_key[0].part_path).unwrap_or('a')
+ == reduce_string(&our_key[0].part_path).unwrap_or('b')
+ {
+ bail!(
+ "\
+The foreign_key ('{}', path_part: '{}' -> '{}') and our_key ('{}', path_part: '{}' -> '{}') \
+have an identical path_part (when duplicated chars are removed)!
+I cannot extended them via incrementation.
+Please rename the paths to fix this.
+ ",
+ MapKey::display(&foreign_key),
+ &foreign_key[0].part_path,
+ reduce_string(&foreign_key[0].part_path).expect("Is some here"),
+ MapKey::display(&our_key),
+ &our_key[0].part_path,
+ reduce_string(&our_key[0].part_path).expect("Is some here"),
+ );
+ }
+
+ if check_subset(&foreign_key[0].part_path, &our_key[0].part_path) {
+ bail!(
+ "\
+The foreign_key ('{}', path_part: '{}') and our_key ('{}', path_part: '{}') \
+are subsets of one another!
+A discrimination through incrementation will not work!
+Please rename the paths to fix this.
+ ",
+ MapKey::display(&foreign_key),
+ &foreign_key[0].part_path,
+ MapKey::display(&our_key),
+ &our_key[0].part_path,
+ );
+ }
+
+ while our_key == foreign_key {
+ our_key = our_key[0].increment(our_key[our_key.len() - 1].resolution + 1);
+ foreign_key =
+ foreign_key[0].increment(foreign_key[foreign_key.len() - 1].resolution + 1);
+ debug!(
+ "Now its: '{}' ('{}') and '{}' ('{}')",
+ MapKey::display(&our_key),
+ our_key[0].part_path,
+ MapKey::display(&foreign_key),
+ foreign_key[0].part_path,
+ );
+ }
+
+ debug!(
+ "Found a better one: '{}' ('{}') and '{}' ('{}')",
+ MapKey::display(&our_key),
+ our_key[0].part_path,
+ MapKey::display(&foreign_key),
+ foreign_key[0].part_path,
+ );
+
+ let parent = self
+ .get_mut(&found_key[..&found_key.len() - 1])
+ .expect("This will exist");
+
+ if let NodeValue::Parent { children } = &mut parent.value {
+ if let NodeValue::Child {
+ path: _,
+ extandable: _,
+ } = children
+ .get(found_key.last().expect("Exists"))
+ .expect("This node also exists")
+ .value
+ {
+ let old = children
+ .remove(found_key.last().expect("This will exist"))
+ .expect("This will be there");
+
+ let full_foreign_key: Vec<_> = found_key
+ .clone()
+ .into_iter()
+ .rev()
+ .skip(1)
+ .rev()
+ .chain(foreign_key.clone().into_iter())
+ .collect();
+ self.insert_node(&full_foreign_key, old.clone())?;
+ }
+
+ let full_our_key: Vec<_> = key
+ .to_vec()
+ .into_iter()
+ .rev()
+ .skip(1)
+ .rev()
+ .chain(our_key.clone().into_iter())
+ .collect();
+
+ self.insert_node(&full_our_key, node.clone())?;
+ } else {
+ unreachable!("This node will be a parent");
+ }
+ }
+
+ Ok(())
+ }
+}
+
+impl Node {
+ pub fn new_child(path: String) -> Self {
+ Self {
+ value: NodeValue::Child {
+ path,
+ extandable: true,
+ },
+ }
+ }
+ pub fn new_parent() -> Self {
+ Self {
+ value: NodeValue::Parent {
+ children: HashMap::new(),
+ },
+ }
+ }
+}
diff --git a/pkgs/by-name/lf/lf-make-map/src/mapping/mod.rs b/pkgs/by-name/lf/lf-make-map/src/mapping/mod.rs
new file mode 100644
index 00000000..114fdca0
--- /dev/null
+++ b/pkgs/by-name/lf/lf-make-map/src/mapping/mod.rs
@@ -0,0 +1,156 @@
+use std::{
+ fmt::{Display, Write},
+ hash::Hash,
+};
+
+use log::debug;
+
+pub mod map_tree;
+
+#[derive(Clone, Debug, Eq)]
+pub struct MapKey {
+ pub key: char,
+
+ resolution: usize,
+
+ /// Part of the path, used to derive the key
+ part_path: String,
+}
+
+impl Hash for MapKey {
+ fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+ self.key.hash(state)
+ }
+}
+
+impl PartialEq for MapKey {
+ fn eq(&self, other: &Self) -> bool {
+ self.key == other.key
+ }
+}
+
+impl MapKey {
+ pub fn new_from_part_path(part_path: &str, resolution: usize) -> Vec<Self> {
+ let key = Self::part_path_to_key(&part_path, resolution);
+
+ key.chars()
+ .map(|ch| Self {
+ key: ch,
+ resolution,
+ part_path: part_path.to_owned(),
+ })
+ .collect()
+ }
+
+ pub fn new_ones_from_path(path: &str, number_of_chars: usize) -> Vec<Self> {
+ let key: Vec<MapKey> = path
+ .split('/')
+ .map(|part| Self::new_from_part_path(part, number_of_chars))
+ .flatten()
+ .collect();
+
+ debug!(
+ "Generated full MapKeys: '{}' -> '{}'",
+ path,
+ MapKey::display(&key)
+ );
+ key
+ }
+
+ pub fn increment(&self, target_resolution: usize) -> Vec<Self> {
+ let new_resolution = target_resolution;
+
+ // debug!("Incrementing: '{}' ('{}')", &self, &self.part_path);
+
+ let added_chars = if new_resolution < self.part_path.len() {
+ MapKey::part_path_to_key(&self.part_path, new_resolution)
+ } else {
+ let mut generated_chars =
+ MapKey::part_path_to_key(&self.part_path, self.part_path.len());
+
+ generated_chars.extend(
+ (0..(new_resolution - self.part_path.len()))
+ .into_iter()
+ .map(|_| self.part_path.chars().last().expect("This will exists")),
+ );
+
+ generated_chars
+ };
+
+ let part_path = self.part_path.clone();
+ let output: Vec<Self> = added_chars
+ .chars()
+ .enumerate()
+ .map(|(res, ch)| MapKey {
+ key: ch,
+ resolution: res + 1,
+ part_path: part_path.clone(),
+ })
+ .collect();
+
+ // debug!("Finished increment: '{}' ('{}')", MapKey::display(&output), output[0].part_path);
+ output
+ }
+
+ pub fn display(values: &[Self]) -> String {
+ values.iter().map(|value| value.key.clone()).collect()
+ }
+ fn part_path_to_key(part: &str, number_of_chars: usize) -> String {
+ fn make(pat: char, part: &str, number_of_chars: usize) -> String {
+ let mut acc = String::new();
+
+ if !part.split(pat).all(|part| part.len() > 0) {
+ panic!(
+ "\
+Can't turn this path '{}' to a mapping.
+This should not happen, please report the bug!",
+ part
+ )
+ }
+
+ let mut last_working = None;
+ for i in 0..number_of_chars {
+ for str in part.split(pat) {
+ if acc.len() != number_of_chars {
+ acc.push(match str.chars().nth(i) {
+ Some(ch) => ch,
+ None => {
+ if let Some(last) = last_working {
+ str.chars().nth(last).expect("This should always exist")
+ } else {
+ last_working = Some(i - 1);
+ str.chars().nth(i - 1).expect("This should always exist")
+ }
+ }
+ })
+ }
+ }
+ }
+
+ acc
+ }
+
+ let value = if part.contains('_') && !part.starts_with('_') && !part.ends_with('_') {
+ make('_', part, number_of_chars)
+ } else if part.contains('-') && !part.starts_with('-') && !part.ends_with('-') {
+ make('-', part, number_of_chars)
+ } else {
+ part.chars().take(number_of_chars).collect::<String>()
+ };
+
+ assert_eq!(
+ value.len(),
+ number_of_chars,
+ "'{}' does not have expected length of: {}",
+ value,
+ number_of_chars
+ );
+ value
+ }
+}
+
+impl Display for MapKey {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_char(self.key)
+ }
+}