fancy_tree/config/icons/
mod.rs

1//! Module for the icon config.
2use super::ConfigFile;
3use crate::lua::interop;
4use crate::tree::{
5    Entry,
6    entry::{Attributes, attributes::FileAttributes},
7};
8use mlua::{FromLua, Lua};
9use std::path::Path;
10
11/// The configuration for icons.
12#[derive(Debug, Default)]
13pub struct Icons {
14    /// Function to get the icon for an entry.
15    get_icon: Option<mlua::Function>,
16}
17
18impl Icons {
19    /// The default icon to display for files.
20    const DEFAULT_FILE_ICON: &'static str = "\u{f0214}"; // 󰈔
21    /// The default icon to display when a file is an executable.
22    const DEFAULT_EXECUTABLE_ICON: &'static str = "\u{f070e}"; // 󰜎
23    /// The default icon to display for directories/folders.
24    const DEFAULT_DIRECTORY_ICON: &'static str = "\u{f024b}"; // 󰉋
25    /// The default icon to display for symlinks.
26    const DEFAULT_SYMLINK_ICON: &'static str = "\u{cf481}"; // 
27
28    /// The icon (padding) to use if there is no icon.
29    const EMPTY_ICON: &'static str = " ";
30
31    /// Get the icon for the entry. If the configuration returns `nil`, a string with
32    /// invisible characters will be returned.
33    ///
34    /// On a Lua error, this falls back to the default icon choice.
35    pub fn get_icon<P>(&self, entry: &Entry<P>) -> String
36    where
37        P: AsRef<Path>,
38    {
39        // TODO Use Cow
40        let default_icon = Self::default_icon(entry);
41        self.get_icon
42            .as_ref()
43            .and_then(|f| {
44                let path = entry.path();
45                let attributes = interop::FileAttributes::from(entry);
46                // TODO Report the error when this function fails
47                f.call::<Option<String>>((path, attributes, default_icon))
48                    .ok()
49            })
50            .unwrap_or_else(|| Some(String::from(default_icon)))
51            .unwrap_or_else(|| String::from(Self::EMPTY_ICON))
52    }
53
54    /// Gets the default icon choice for an entry.
55    fn default_icon<P>(entry: &Entry<P>) -> &str
56    where
57        P: AsRef<Path>,
58    {
59        match entry.attributes() {
60            Attributes::Directory(_) => Self::DEFAULT_DIRECTORY_ICON,
61            Attributes::File(attributes) => Self::get_file_icon(attributes),
62            Attributes::Symlink(_) => Self::DEFAULT_SYMLINK_ICON,
63        }
64    }
65
66    /// Gets the default icon for a file entry.
67    fn get_file_icon(attributes: &FileAttributes) -> &'static str {
68        if attributes.is_executable() {
69            return Self::DEFAULT_EXECUTABLE_ICON;
70        }
71        attributes
72            .language()
73            .and_then(|language| language.nerd_font_glyph())
74            .unwrap_or(Self::DEFAULT_FILE_ICON)
75    }
76}
77
78impl ConfigFile for Icons {
79    const FILENAME: &'static str = "icons.lua";
80    const DEFAULT_MODULE: &'static str = include_str!("./icons.lua");
81}
82
83impl FromLua for Icons {
84    fn from_lua(value: mlua::Value, lua: &Lua) -> mlua::Result<Self> {
85        Option::<mlua::Function>::from_lua(value, lua).map(|get_icon| Self { get_icon })
86    }
87}