diff options
author | Caleb Bassi <calebjbassi@gmail.com> | 2019-02-15 04:43:09 -0800 |
---|---|---|
committer | Caleb Bassi <calebjbassi@gmail.com> | 2019-02-15 05:56:09 -0800 |
commit | 29b3922f9efb9f277641a63f8f1719a15cbb8d16 (patch) | |
tree | d919ba11fa5c754565c64c43cb1614f7ae4d2546 /src/config | |
parent | 3853eef2d052460982903038daac7abd2b71d12e (diff) |
refactor: project layout
Diffstat (limited to 'src/config')
-rw-r--r-- | src/config/config.rs | 125 | ||||
-rw-r--r-- | src/config/keymap.rs | 152 | ||||
-rw-r--r-- | src/config/mimetype.rs | 87 | ||||
-rw-r--r-- | src/config/mod.rs | 61 | ||||
-rw-r--r-- | src/config/preview.rs | 61 | ||||
-rw-r--r-- | src/config/theme.rs | 230 |
6 files changed, 716 insertions, 0 deletions
diff --git a/src/config/config.rs b/src/config/config.rs new file mode 100644 index 0000000..b970c16 --- /dev/null +++ b/src/config/config.rs @@ -0,0 +1,125 @@ +extern crate toml; +extern crate whoami; +extern crate xdg; + +use config::{parse_config_file, Flattenable}; +use sort; + +use CONFIG_FILE; + +#[derive(Clone, Debug, Deserialize)] +pub struct SortRawOption { + pub show_hidden: Option<bool>, + pub directories_first: Option<bool>, + pub case_sensitive: Option<bool>, + pub reverse: Option<bool>, +} + +#[derive(Clone, Debug, Deserialize)] +pub struct JoshutoRawConfig { + scroll_offset: Option<usize>, + tilde_in_titlebar: Option<bool>, + sort_type: Option<String>, + sort_option: Option<SortRawOption>, + column_ratio: Option<[usize; 3]>, +} + +impl JoshutoRawConfig { + #[allow(dead_code)] + pub fn new() -> Self { + JoshutoRawConfig { + scroll_offset: Some(8), + tilde_in_titlebar: Some(true), + sort_type: Some(String::from("natural")), + sort_option: None, + column_ratio: Some([1, 3, 4]), + } + } +} + +impl Flattenable<JoshutoConfig> for JoshutoRawConfig { + fn flatten(self) -> JoshutoConfig { + let column_ratio = match self.column_ratio { + Some(s) => (s[0], s[1], s[2]), + None => (1, 3, 4), + }; + + let scroll_offset: usize = self.scroll_offset.unwrap_or(6); + let tilde_in_titlebar: bool = self.tilde_in_titlebar.unwrap_or(true); + + let show_hidden: bool; + let case_sensitive: bool; + let reverse: bool; + let directories_first: bool; + + match self.sort_option { + Some(s) => { + show_hidden = s.show_hidden.unwrap_or(false); + case_sensitive = s.case_sensitive.unwrap_or(false); + reverse = s.reverse.unwrap_or(false); + directories_first = s.directories_first.unwrap_or(true); + } + None => { + show_hidden = false; + case_sensitive = false; + reverse = false; + directories_first = true; + } + } + + let sort_option = sort::SortOption { + show_hidden, + directories_first, + case_sensitive, + reverse, + }; + + let sort_type: sort::SortType = match self.sort_type { + Some(s) => match s.as_str() { + "natural" => sort::SortType::SortNatural(sort_option), + "mtime" => sort::SortType::SortMtime(sort_option), + _ => sort::SortType::SortNatural(sort_option), + }, + _ => sort::SortType::SortNatural(sort_option), + }; + + JoshutoConfig { + scroll_offset, + tilde_in_titlebar, + sort_type, + column_ratio, + } + } +} + +#[derive(Debug, Clone)] +pub struct JoshutoConfig { + pub scroll_offset: usize, + pub tilde_in_titlebar: bool, + pub sort_type: sort::SortType, + pub column_ratio: (usize, usize, usize), +} + +impl JoshutoConfig { + pub fn new() -> Self { + let sort_option = sort::SortOption { + show_hidden: false, + directories_first: true, + case_sensitive: false, + reverse: false, + }; + let sort_type = sort::SortType::SortNatural(sort_option); + + JoshutoConfig { + scroll_offset: 6, + tilde_in_titlebar: true, + sort_type, + column_ratio: (1, 3, 4), + } + } + + pub fn get_config() -> JoshutoConfig { + parse_config_file::<JoshutoRawConfig, JoshutoConfig>(CONFIG_FILE) + .unwrap_or_else(|| JoshutoConfig::new()) + } +} diff --git a/src/config/keymap.rs b/src/config/keymap.rs new file mode 100644 index 0000000..639c33c --- /dev/null +++ b/src/config/keymap.rs @@ -0,0 +1,152 @@ +extern crate fs_extra; +extern crate toml; +extern crate xdg; + +use std::collections::HashMap; +use std::process::exit; + +use commands; +use config::{parse_config_file, Flattenable}; +use KEYMAP_FILE; + +pub const BACKSPACE: i32 = 0x7F; +pub const TAB: i32 = 0x9; +pub const ENTER: i32 = 0xA; +pub const ESCAPE: i32 = 0x1B; + +/* #define KEY_ALT(x) KEY_F(60) + (x - 'A') */ + +#[derive(Debug, Deserialize)] +struct JoshutoMapCommand { + pub keys: Vec<String>, + pub command: String, + pub args: Option<Vec<String>>, +} + +#[derive(Debug, Deserialize)] +struct JoshutoRawKeymap { + mapcommand: Option<Vec<JoshutoMapCommand>>, +} + +impl Flattenable<JoshutoKeymap> for JoshutoRawKeymap { + fn flatten(self) -> JoshutoKeymap { + let mut keymaps: HashMap<i32, commands::CommandKeybind> = HashMap::new(); + if let Some(maps) = self.mapcommand { + for mapcommand in maps { + match commands::from_args(mapcommand.command.as_str(), mapcommand.args.as_ref()) { + Some(command) => { + insert_keycommand(&mut keymaps, command, &mapcommand.keys[..]); + } + None => { + println!("Unknown command: {}", mapcommand.command); + } + } + } + } + JoshutoKeymap { keymaps } + } +} + +#[derive(Debug)] +pub struct JoshutoKeymap { + pub keymaps: HashMap<i32, commands::CommandKeybind>, +} + +impl JoshutoKeymap { + pub fn new() -> Self { + let keymaps = HashMap::new(); + JoshutoKeymap { keymaps } + } + + pub fn get_config() -> JoshutoKeymap { + parse_config_file::<JoshutoRawKeymap, JoshutoKeymap>(KEYMAP_FILE) + .unwrap_or_else(|| JoshutoKeymap::new()) + } +} + +fn insert_keycommand( + map: &mut HashMap<i32, commands::CommandKeybind>, + keycommand: Box<dyn commands::JoshutoCommand>, + keys: &[String], +) { + if keys.len() == 1 { + match key_to_i32(&keys[0]) { + Some(s) => { + map.insert(s, commands::CommandKeybind::SimpleKeybind(keycommand)); + } + None => {} + } + } else { + match key_to_i32(&keys[0]) { + Some(s) => { + let mut new_map: HashMap<i32, commands::CommandKeybind>; + match map.remove(&s) { + Some(commands::CommandKeybind::CompositeKeybind(mut m)) => { + new_map = m; + } + Some(_) => { + eprintln!("Error: Keybindings ambiguous"); + exit(1); + } + None => { + new_map = HashMap::new(); + } + } + insert_keycommand(&mut new_map, keycommand, &keys[1..]); + let composite_command = commands::CommandKeybind::CompositeKeybind(new_map); + map.insert(s as i32, composite_command); + } + None => {} + } + } +} + +pub fn key_to_i32(keycode: &str) -> Option<i32> { + if keycode.len() == 1 { + for ch in keycode.chars() { + if ch.is_ascii() { + return Some(ch as i32); + } + } + return None; + } else { + match keycode { + "Tab" => Some(TAB), + "Space" => Some(' ' as i32), + "Backspace" => Some(BACKSPACE), + "Delete" => Some(ncurses::KEY_DC), + "Enter" => Some(ENTER), + "Escape" => Some(ESCAPE), + + "F0" => Some(ncurses::KEY_F0), + "F1" => Some(ncurses::KEY_F1), + "F2" => Some(ncurses::KEY_F2), + "F3" => Some(ncurses::KEY_F3), + "F4" => Some(ncurses::KEY_F4), + "F5" => Some(ncurses::KEY_F5), + "F6" => Some(ncurses::KEY_F6), + "F7" => Some(ncurses::KEY_F7), + "F8" => Some(ncurses::KEY_F8), + "F9" => Some(ncurses::KEY_F9), + "F10" => Some(ncurses::KEY_F10), + "F11" => Some(ncurses::KEY_F11), + "F12" => Some(ncurses::KEY_F12), + "F13" => Some(ncurses::KEY_F13), + "F14" => Some(ncurses::KEY_F14), + "F15" => Some(ncurses::KEY_F15), + + "Insert" => Some(ncurses::KEY_IC), /* insert-character key */ + "PageUp" => Some(ncurses::KEY_PPAGE), /* next-page key */ + "PageDown" => Some(ncurses::KEY_NPAGE), /* previous-page key */ + "PrintScreen" => Some(ncurses::KEY_PRINT), /* print key */ + + "Up" => Some(ncurses::KEY_UP), + "Down" => Some(ncurses::KEY_DOWN), + "Left" => Some(ncurses::KEY_LEFT), + "Right" => Some(ncurses::KEY_RIGHT), + "Home" => Some(ncurses::KEY_HOME), + "End" => Some(ncurses::KEY_END), + _ => None, + } + } +} diff --git a/src/config/mimetype.rs b/src/config/mimetype.rs new file mode 100644 index 0000000..1be211f --- /dev/null +++ b/src/config/mimetype.rs @@ -0,0 +1,87 @@ +extern crate toml; +extern crate xdg; + +use std::collections::HashMap; +use std::fmt; + +use config::{parse_config_file, Flattenable}; +use MIMETYPE_FILE; + +#[derive(Debug, Deserialize)] +pub struct JoshutoMimetypeEntry { + pub program: String, + pub args: Option<Vec<String>>, + pub fork: Option<bool>, + pub silent: Option<bool>, +} + +impl std::fmt::Display for JoshutoMimetypeEntry { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self.program.as_str()).unwrap(); + if let Some(s) = self.args.as_ref() { + for arg in s { + write!(f, " {}", arg).unwrap(); + } + } + f.write_str("\t[").unwrap(); + if let Some(s) = self.fork { + if s { + f.write_str("fork,").unwrap(); + } + } + if let Some(s) = self.silent { + if s { + f.write_str("silent").unwrap(); + } + } + f.write_str("]") + } +} + +#[derive(Debug, Deserialize)] +pub struct JoshutoRawMimetype { + mimetype: Option<HashMap<String, Vec<JoshutoMimetypeEntry>>>, + extension: Option<HashMap<String, Vec<JoshutoMimetypeEntry>>>, +} + +impl JoshutoRawMimetype { + #[allow(dead_code)] + pub fn new() -> Self { + JoshutoRawMimetype { + mimetype: None, + extension: None, + } + } +} + +impl Flattenable<JoshutoMimetype> for JoshutoRawMimetype { + fn flatten(self) -> JoshutoMimetype { + let mimetype = self.mimetype.unwrap_or(HashMap::new()); + let extension = self.extension.unwrap_or(HashMap::new()); + + JoshutoMimetype { + mimetype, + extension, + } + } +} + +#[derive(Debug)] +pub struct JoshutoMimetype { + pub mimetype: HashMap<String, Vec<JoshutoMimetypeEntry>>, + pub extension: HashMap<String, Vec<JoshutoMimetypeEntry>>, +} + +impl JoshutoMimetype { + pub fn new() -> Self { + JoshutoMimetype { + mimetype: HashMap::new(), + extension: HashMap::new(), + } + } + + pub fn get_config() -> JoshutoMimetype { + parse_config_file::<JoshutoRawMimetype, JoshutoMimetype>(MIMETYPE_FILE) + .unwrap_or_else(|| JoshutoMimetype::new()) + } +} diff --git a/src/config/mod.rs b/src/config/mod.rs new file mode 100644 index 0000000..273b9ab --- /dev/null +++ b/src/config/mod.rs @@ -0,0 +1,61 @@ +extern crate serde; + +pub mod config; +pub mod keymap; +pub mod mimetype; +pub mod preview; +pub mod theme; + +pub use self::config::JoshutoConfig; +pub use self::keymap::JoshutoKeymap; +pub use self::mimetype::JoshutoMimetype; +pub use self::preview::JoshutoPreview; +pub use self::theme::{JoshutoColorTheme, JoshutoTheme}; + +use self::serde::de::DeserializeOwned; +use std::fs; +use std::path::{Path, PathBuf}; + +use CONFIG_HIERARCHY; + +// implemented by config file implementations to turn a RawConfig into a Config +trait Flattenable<T> { + fn flatten(self) -> T; +} + +// searches a list of folders for a given file in order of preference +pub fn search_directories<P>(filename: &str, directories: &[P]) -> Option<PathBuf> +where + P: AsRef<Path>, +{ + for path in directories.iter() { + let filepath = path.as_ref().join(filename); + if filepath.exists() { + return Some(filepath); + } + } + None +} + +// parses a config file into its appropriate format +fn parse_config_file<T, S>(filename: &str) -> Option<S> +where + T: DeserializeOwned + Flattenable<S>, +{ + let file_path = search_directories(filename, &CONFIG_HIERARCHY)?; + let file_contents = match fs::read_to_string(&file_path) { + Ok(content) => content, + Err(e) => { + eprintln!("Error reading {} file: {}", filename, e); + return None; + } + }; + let config = match toml::from_str::<T>(&file_contents) { + Ok(config) => config, + Err(e) => { + eprintln!("Error parsing {} file: {}", filename, e); + return None; + } + }; + Some(config.flatten()) +} diff --git a/src/config/preview.rs b/src/config/preview.rs new file mode 100644 index 0000000..d8f3072 --- /dev/null +++ b/src/config/preview.rs @@ -0,0 +1,61 @@ +extern crate toml; +extern crate xdg; + +use std::collections::HashMap; + +use config::{parse_config_file, Flattenable}; +use PREVIEW_FILE; + +#[derive(Debug, Deserialize)] +pub struct JoshutoPreviewEntry { + pub program: String, + pub args: Option<Vec<String>>, +} + +#[derive(Debug, Deserialize)] +pub struct JoshutoRawPreview { + pub mimetype: Option<HashMap<String, JoshutoPreviewEntry>>, + pub extension: Option<HashMap<String, JoshutoPreviewEntry>>, +} + +impl JoshutoRawPreview { + #[allow(dead_code)] + pub fn new() -> Self { + JoshutoRawPreview { + mimetype: None, + extension: None, + } + } +} + +impl Flattenable<JoshutoPreview> for JoshutoRawPreview { + fn flatten(self) -> JoshutoPreview { + let mimetype = self.mimetype.unwrap_or(HashMap::new()); + let extension = self.extension.unwrap_or(HashMap::new()); + + JoshutoPreview { + mimetype, + extension, + } + } +} + +#[derive(Debug)] +pub struct JoshutoPreview { + pub mimetype: HashMap<String, JoshutoPreviewEntry>, + pub extension: HashMap<String, JoshutoPreviewEntry>, +} + +impl JoshutoPreview { + pub fn new() -> Self { + JoshutoPreview { + mimetype: HashMap::new(), + extension: HashMap::new(), + } + } + + pub fn get_config() -> JoshutoPreview { + parse_config_file::<JoshutoRawPreview, JoshutoPreview>(PREVIEW_FILE) + .unwrap_or_else(|| JoshutoPreview::new()) + } +} diff --git a/src/config/theme.rs b/src/config/theme.rs new file mode 100644 index 0000000..2e27663 --- /dev/null +++ b/src/config/theme.rs @@ -0,0 +1,230 @@ +extern crate toml; +extern crate xdg; + +use std::collections::HashMap; + +use config::{parse_config_file, Flattenable}; + +#[derive(Debug, Deserialize, Clone)] +pub struct JoshutoColorPair { + pub id: i16, + pub fg: i16, + pub bg: i16, +} + +impl JoshutoColorPair { + pub fn new(id: i16, fg: i16, bg: i16) -> Self { + JoshutoColorPair { id, fg, bg } + } +} + +#[derive(Debug, Deserialize, Clone)] +pub struct JoshutoRawColorTheme { + pub colorpair: i16, + pub bold: Option<bool>, + pub underline: Option<bool>, + pub prefix: Option<String>, + pub prefixsize: Option<usize>, +} + +impl JoshutoRawColorTheme { + pub fn flatten(self) -> JoshutoColorTheme { + JoshutoColorTheme { + colorpair: self.colorpair, + bold: self.bold.unwrap_or(false), + underline: self.underline.unwrap_or(false), + prefix: self.prefix, + prefixsize: self.prefixsize, + } + } +} + +#[derive(Debug, Deserialize)] +pub struct JoshutoRawTheme { + colorpair: Option<Vec<JoshutoColorPair>>, + selection: Option<JoshutoRawColorTheme>, + executable: Option<JoshutoRawColorTheme>, + regular: Option<JoshutoRawColorTheme>, + directory: Option<JoshutoRawColorTheme>, + link: Option<JoshutoRawColorTheme>, + socket: Option<JoshutoRawColorTheme>, + ext: Option<HashMap<String, JoshutoRawColorTheme>>, +} + +impl Flattenable<JoshutoTheme> for JoshutoRawTheme { + fn flatten(self) -> JoshutoTheme { + let colorpair = match self.colorpair { + Some(s) => s, + None => { + let mut colorpair: Vec<JoshutoColorPair> = Vec::with_capacity(10); + colorpair.push(JoshutoColorPair::new(2, 2, -1)); + colorpair.push(JoshutoColorPair::new(3, 3, -1)); + colorpair.push(JoshutoColorPair::new(4, 4, -1)); + colorpair.push(JoshutoColorPair::new(5, 5, -1)); + colorpair.push(JoshutoColorPair::new(6, 6, -1)); + colorpair + } + }; + + let selection = self.selection.unwrap_or(JoshutoRawColorTheme { + colorpair: 3, + bold: Some(true), + underline: None, + prefix: None, + prefixsize: None, + }); + + let executable = self.executable.unwrap_or(JoshutoRawColorTheme { + colorpair: 2, + bold: Some(true), + underline: None, + prefix: None, + prefixsize: None, + }); + + let regular = self.regular.unwrap_or(JoshutoRawColorTheme { + colorpair: 0, + bold: None, + underline: None, + prefix: None, + prefixsize: None, + }); + + let directory = self.directory.unwrap_or(JoshutoRawColorTheme { + colorpair: 4, + bold: Some(true), + underline: None, + prefix: None, + prefixsize: None, + }); + + let link = self.link.unwrap_or(JoshutoRawColorTheme { + colorpair: 6, + bold: Some(true), + underline: None, + prefix: None, + prefixsize: None, + }); + + let socket = self.socket.unwrap_or(JoshutoRawColorTheme { + colorpair: 6, + bold: Some(true), + underline: None, + prefix: None, + prefixsize: None, + }); + + let mut extraw = self.ext.unwrap_or(HashMap::new()); + let mut ext: HashMap<String, JoshutoColorTheme> = HashMap::new(); + for (k, v) in extraw.drain() { + ext.insert(k, v.flatten()); + } + + JoshutoTheme { + colorpair, + regular: regular.flatten(), + directory: directory.flatten(), + selection: selection.flatten(), + executable: executable.flatten(), + link: link.flatten(), + socket: socket.flatten(), + ext, + } + } +} + +#[derive(Debug, Clone)] +pub struct JoshutoColorTheme { + pub colorpair: i16, + pub bold: bool, + pub underline: bool, + pub prefix: Option<String>, + pub prefixsize: Option<usize>, +} + +#[derive(Debug, Clone)] +pub struct JoshutoTheme { + pub colorpair: Vec<JoshutoColorPair>, + pub regular: JoshutoColorTheme, + pub selection: JoshutoColorTheme, + pub directory: JoshutoColorTheme, + pub executable: JoshutoColorTheme, + pub link: JoshutoColorTheme, + pub socket: JoshutoColorTheme, + pub ext: HashMap<String, JoshutoColorTheme>, +} + +impl JoshutoTheme { + pub fn new() -> Self { + let mut colorpair: Vec<JoshutoColorPair> = Vec::with_capacity(10); + colorpair.push(JoshutoColorPair::new(2, 2, -1)); + colorpair.push(JoshutoColorPair::new(3, 3, -1)); + colorpair.push(JoshutoColorPair::new(4, 4, -1)); + colorpair.push(JoshutoColorPair::new(5, 5, -1)); + colorpair.push(JoshutoColorPair::new(6, 6, -1)); + + let selection = JoshutoColorTheme { + colorpair: 3, + bold: true, + underline: false, + prefix: None, + prefixsize: None, + }; + + let executable = JoshutoColorTheme { + colorpair: 2, + bold: true, + underline: false, + prefix: None, + prefixsize: None, + }; + + let regular = JoshutoColorTheme { + colorpair: 0, + bold: false, + underline: false, + prefix: None, + prefixsize: None, + }; + + let directory = JoshutoColorTheme { + colorpair: 4, + bold: true, + underline: false, + prefix: None, + prefixsize: None, + }; + + let link = JoshutoColorTheme { + colorpair: 6, + bold: true, + underline: false, + prefix: None, + prefixsize: None, + }; + + let socket = JoshutoColorTheme { + colorpair: 6, + bold: true, + underline: false, + prefix: None, + prefixsize: None, + }; + + JoshutoTheme { + colorpair, + selection, + executable, + regular, + directory, + link, + socket, + ext: HashMap::new(), + } + } + + pub fn get_config() -> JoshutoTheme { + parse_config_file::<JoshutoRawTheme, JoshutoTheme>(::THEME_FILE) + .unwrap_or_else(|| JoshutoTheme::new()) + } +} |