keymaps 1.2.0

A rust crate which provides a standardized encoding for key codes
Documentation
// keymaps - A rust crate which provides a standardized encoding for key codes
//
// Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// This file is part of the keymaps crate.
//
// You should have received a copy of the License along with this program.
// If not, see <https://www.gnu.org/licenses/lgpl-3.0.txt>.

use std::fmt::Display;

use crate::map_tree::{Node, NodeValue};

use super::Trie;

impl<K, V> Display for Node<K, V>
where
    K: Clone + Eq + Ord + std::hash::Hash + std::fmt::Debug + Display,
    V: Clone + PartialEq + std::fmt::Debug + Display,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        fn write_node<K, V>(
            f: &mut std::fmt::Formatter<'_>,
            node: &Node<K, V>,
            indention: &str,
            location: &[K],
            is_last: bool,
            is_root: bool,
        ) -> std::fmt::Result
        where
            K: Clone + Eq + Ord + std::hash::Hash + std::fmt::Debug + Display,
            V: Clone + PartialEq + std::fmt::Debug + Display,
        {
            let node_value = match &node.value {
                NodeValue::Parent { children: _ } => "<Parent>".to_owned(),
                NodeValue::Child { value } => value.to_string(),
            };

            let new_idention = indention.to_string()
                + if is_root {
                    ""
                } else if is_last {
                    "    "
                } else {
                    ""
                };

            let bullet = if is_last {
                String::from("└── ")
            } else {
                String::from("├── ")
            };

            if is_root {
                writeln!(f, ": {node_value}")?;
            } else {
                writeln!(
                    f,
                    "{}{}\x1b[1;33m{}\x1b[0m: {}",
                    indention,
                    bullet,
                    location.iter().map(ToString::to_string).collect::<String>(),
                    node_value,
                )?;
            };

            match &node.value {
                NodeValue::Parent { children } => {
                    let mut children_vec: Vec<(&K, &Node<K, V>)> = children.iter().collect();
                    children_vec.sort_by(|(a, _), (b, _)| a.cmp(b));

                    let mut counter = 1;
                    for (key, child) in &children_vec {
                        let mut new_location = location.to_vec();
                        new_location.push((*key).to_owned());

                        write_node(
                            f,
                            child,
                            &new_idention,
                            &new_location,
                            counter == children_vec.len(),
                            false,
                        )?;
                        counter += 1;
                    }
                }
                NodeValue::Child { value: _ } => {
                    // Do nothing and stop the recursion
                }
            }

            Ok(())
        }

        write_node(f, self, "", &[], false, true)?;

        Ok(())
    }
}

impl<K, V> Display for Trie<K, V>
where
    K: Clone + Eq + Ord + std::hash::Hash + std::fmt::Debug + Display,
    V: Clone + PartialEq + std::fmt::Debug + Display,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.root.fmt(f)
    }
}