diff options
author | Jeff Zhao <jeff.no.zhao@gmail.com> | 2022-11-17 19:42:39 -0500 |
---|---|---|
committer | Jeff Zhao <jeff.no.zhao@gmail.com> | 2022-11-20 14:16:59 -0500 |
commit | 5d4cc2dd61b91db28aa127347450a05cb0f2d45d (patch) | |
tree | f4f899c8417070b718a035b3eb914fca0461aee8 /src | |
parent | 75081aae369feb8e71977701ec9cb467e2b166ba (diff) |
add bookmark support
Diffstat (limited to 'src')
-rw-r--r-- | src/commands/bookmark.rs | 135 | ||||
-rw-r--r-- | src/commands/mod.rs | 1 | ||||
-rw-r--r-- | src/commands/show_tasks.rs | 3 | ||||
-rw-r--r-- | src/config/bookmarks/bookmarks.rs | 37 | ||||
-rw-r--r-- | src/config/bookmarks/bookmarks_raw.rs | 13 | ||||
-rw-r--r-- | src/config/bookmarks/mod.rs | 5 | ||||
-rw-r--r-- | src/config/general/display_raw.rs | 7 | ||||
-rw-r--r-- | src/config/general/preview_raw.rs | 38 | ||||
-rw-r--r-- | src/config/general/sort_raw.rs | 8 | ||||
-rw-r--r-- | src/config/general/tab_raw.rs | 8 | ||||
-rw-r--r-- | src/config/mod.rs | 4 | ||||
-rw-r--r-- | src/config/option/display_option.rs | 11 | ||||
-rw-r--r-- | src/config/option/sort_type.rs | 2 | ||||
-rw-r--r-- | src/event/process_event.rs | 2 | ||||
-rw-r--r-- | src/key_command/command.rs | 3 | ||||
-rw-r--r-- | src/key_command/constants.rs | 2 | ||||
-rw-r--r-- | src/key_command/impl_appcommand.rs | 3 | ||||
-rw-r--r-- | src/key_command/impl_appexecute.rs | 3 | ||||
-rw-r--r-- | src/key_command/impl_comment.rs | 3 | ||||
-rw-r--r-- | src/key_command/impl_from_str.rs | 19 | ||||
-rw-r--r-- | src/key_command/impl_interactive.rs | 1 | ||||
-rw-r--r-- | src/main.rs | 9 | ||||
-rw-r--r-- | src/run.rs | 3 | ||||
-rw-r--r-- | src/tab/homepage.rs | 11 | ||||
-rw-r--r-- | src/util/unix.rs | 8 |
25 files changed, 284 insertions, 55 deletions
diff --git a/src/commands/bookmark.rs b/src/commands/bookmark.rs new file mode 100644 index 0000000..6c13752 --- /dev/null +++ b/src/commands/bookmark.rs @@ -0,0 +1,135 @@ +use std::fs::File; +use std::io::Write; + +use termion::event::Event; +use tui::layout::Rect; +use tui::widgets::Clear; + +use crate::config::{search_directories, BookmarkRaw, BookmarksRaw}; +use crate::context::AppContext; +use crate::error::JoshutoResult; +use crate::event::{process_event, AppEvent}; +use crate::traits::ToString; +use crate::ui::views::TuiView; +use crate::ui::widgets::TuiMenu; +use crate::ui::AppBackend; +use crate::util::unix; + +use crate::{BOOKMARKS_FILE, BOOKMARKS_T, CONFIG_HIERARCHY}; + +use super::change_directory::change_directory; + +pub fn add_bookmark(context: &mut AppContext, backend: &mut AppBackend) -> JoshutoResult { + let cwd = std::env::current_dir()?; + + let bookmark_path = match search_directories(BOOKMARKS_FILE, &CONFIG_HIERARCHY) { + Some(file_path) => Some(file_path), + None => { + for p in CONFIG_HIERARCHY.iter() { + if p.exists() { + Some(p.clone()); + } + } + None + } + }; + + if let Some(bookmark_path) = bookmark_path { + let key = poll_for_bookmark_key(context, backend); + if let Some(key) = key { + if let Ok(mut bookmark) = BOOKMARKS_T.lock() { + bookmark.insert(key, cwd.to_string_lossy().to_string()); + } + let new_bookmarks_vec: Vec<BookmarkRaw> = BOOKMARKS_T + .lock() + .unwrap() + .clone() + .drain() + .map(|(k, v)| BookmarkRaw { + key: k.to_string(), + path: v, + }) + .collect(); + let bookmarks_raw = BookmarksRaw { + bookmark: new_bookmarks_vec, + }; + + if let Ok(content) = toml::to_string(&bookmarks_raw) { + let mut file = File::create(bookmark_path)?; + file.write_all(content.as_bytes())?; + } + } + } + + Ok(()) +} + +pub fn change_directory_bookmark( + context: &mut AppContext, + backend: &mut AppBackend, +) -> JoshutoResult { + let key = poll_for_bookmark_key(context, backend); + + if let Some(key) = key { + if let Ok(bookmarks) = BOOKMARKS_T.lock() { + if let Some(p) = bookmarks.get(&key) { + let path = unix::expand_shell_string(p); + change_directory(context, &path)?; + } + } + } + Ok(()) +} + +fn poll_for_bookmark_key<'a>(context: &mut AppContext, backend: &mut AppBackend) -> Option<Event> { + context.flush_event(); + + let mut bookmarks: Vec<String> = BOOKMARKS_T + .lock() + .unwrap() + .iter() + .map(|(k, v)| format!(" {} {:?}", k.to_string(), v)) + .collect(); + bookmarks.sort(); + let bookmarks_str: Vec<&str> = bookmarks.iter().map(|s| s.as_str()).collect(); + + let terminal = backend.terminal_mut(); + loop { + let _ = terminal.draw(|frame| { + let area = frame.size(); + if area.height < 5 { + return; + } + // redraw view + { + let mut view = TuiView::new(context); + view.show_bottom_status = false; + frame.render_widget(view, area); + } + + let menu_widget = TuiMenu::new(bookmarks_str.as_slice()); + let menu_len = menu_widget.len(); + let menu_y = if menu_len + 1 > area.height as usize { + 0 + } else { + (area.height as usize - menu_len - 1) as u16 + }; + + let menu_rect = Rect { + x: 0, + y: menu_y - 1, + width: area.width, + height: menu_len as u16 + 1, + }; + frame.render_widget(Clear, menu_rect); + frame.render_widget(menu_widget, menu_rect); + }); + + if let Ok(event) = context.poll_event() { + match event { + AppEvent::Termion(key) => return Some(key), + event => process_event::process_noninteractive(event, context), + }; + } + } +} diff --git a/src/commands/mod.rs b/src/commands/mod.rs index cf7ef53..5489a1c 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,3 +1,4 @@ +pub mod bookmark; pub mod bulk_rename; pub mod change_directory; pub mod command_line; diff --git a/src/commands/show_tasks.rs b/src/commands/show_tasks.rs index 9dd8ddf..ea5f310 100644 --- a/src/commands/show_tasks.rs +++ b/src/commands/show_tasks.rs @@ -34,7 +34,8 @@ pub fn show_tasks( } } Some(CommandKeybind::CompositeKeybind(m)) => { - let cmd = process_event::get_input_while_composite(backend, context, m); + let cmd = + process_event::poll_event_until_simple_keybind(backend, context, m); if let Some(Command::ShowTasks) = cmd { break; diff --git a/src/config/bookmarks/bookmarks.rs b/src/config/bookmarks/bookmarks.rs new file mode 100644 index 0000000..a1d03a8 --- /dev/null +++ b/src/config/bookmarks/bookmarks.rs @@ -0,0 +1,37 @@ +use std::collections::HashMap; + +use termion::event::Event; + +use crate::config::{parse_to_config_file, TomlConfigFile}; +use crate::util::keyparse; + +use super::bookmarks_raw::BookmarksRaw; + +pub type Bookmarks = HashMap<Event, String>; + +impl From<BookmarksRaw> for Bookmarks { + fn from(raw: BookmarksRaw) -> Self { + let mut raw = raw; + let map: Bookmarks = raw + .bookmark + .drain(..) + .filter_map(|bookmark| match keyparse::str_to_event(&bookmark.key) { + Some(event) => Some((event, bookmark.path)), + None => None, + }) + .collect(); + map + } +} + +impl TomlConfigFile for Bookmarks { + fn get_config(file_name: &str) -> Self { + match parse_to_config_file::<BookmarksRaw, Bookmarks>(file_name) { + Ok(s) => s, + Err(e) => { + eprintln!("Failed to parse app config: {}", e); + Self::default() + } + } + } +} diff --git a/src/config/bookmarks/bookmarks_raw.rs b/src/config/bookmarks/bookmarks_raw.rs new file mode 100644 index 0000000..ba08430 --- /dev/null +++ b/src/config/bookmarks/bookmarks_raw.rs @@ -0,0 +1,13 @@ +use serde_derive::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct BookmarkRaw { + pub key: String, + pub path: String, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct BookmarksRaw { + #[serde(default)] + pub bookmark: Vec<BookmarkRaw>, +} diff --git a/src/config/bookmarks/mod.rs b/src/config/bookmarks/mod.rs new file mode 100644 index 0000000..050ac70 --- /dev/null +++ b/src/config/bookmarks/mod.rs @@ -0,0 +1,5 @@ +pub mod bookmarks; +pub mod bookmarks_raw; + +pub use self::bookmarks::*; +pub use self::bookmarks_raw::*; diff --git a/src/config/general/display_raw.rs b/src/config/general/display_raw.rs index a4edf1c..b6b8a89 100644 --- a/src/config/general/display_raw.rs +++ b/src/config/general/display_raw.rs @@ -105,11 +105,8 @@ impl From<DisplayOptionRaw> for DisplayOption { Constraint::Ratio(0, total), ]; - let _line_nums = match raw.line_number_style.as_ref() { - "absolute" => LineNumberStyle::Absolute, - "relative" => LineNumberStyle::Relative, - _ => LineNumberStyle::None, - }; + let _line_nums = LineNumberStyle::from_str(raw.line_number_style.as_str()) + .unwrap_or_else(|| LineNumberStyle::None); Self { _mode: mode, diff --git a/src/config/general/preview_raw.rs b/src/config/general/preview_raw.rs index 6fb4e05..9204b5d 100644 --- a/src/config/general/preview_raw.rs +++ b/src/config/general/preview_raw.rs @@ -1,10 +1,10 @@ use std::convert::From; -use std::path; use serde_derive::Deserialize; use crate::config::option::PreviewOption; use crate::config::search_directories; +use crate::util::unix; use crate::CONFIG_HIERARCHY; pub const fn default_max_preview_size() -> u64 { @@ -36,30 +36,18 @@ impl std::default::Default for PreviewOptionRaw { impl From<PreviewOptionRaw> for PreviewOption { fn from(raw: PreviewOptionRaw) -> Self { - let preview_script = match raw.preview_script { - Some(s) => { - let tilde_cow = shellexpand::tilde_with_context(s.as_str(), dirs_next::home_dir); - let tilde_path = path::PathBuf::from(tilde_cow.as_ref()); - Some(tilde_path) - } - None => search_directories("preview.sh", &CONFIG_HIERARCHY), - }; - let preview_shown_hook_script = match raw.preview_shown_hook_script { - Some(s) => { - let tilde_cow = shellexpand::tilde_with_context(s.as_str(), dirs_next::home_dir); - let tilde_path = path::PathBuf::from(tilde_cow.as_ref()); - Some(tilde_path) - } - None => None, - }; - let preview_removed_hook_script = match raw.preview_removed_hook_script { - Some(s) => { - let tilde_cow = shellexpand::tilde_with_context(s.as_str(), dirs_next::home_dir); - let tilde_path = path::PathBuf::from(tilde_cow.as_ref()); - Some(tilde_path) - } - None => None, - }; + let preview_script = raw + .preview_script + .map(|s| unix::expand_shell_string(&s)) + .or_else(|| search_directories("preview.sh", &CONFIG_HIERARCHY)); + + let preview_shown_hook_script = raw + .preview_shown_hook_script + .map(|s| unix::expand_shell_string(&s)); + + let preview_removed_hook_script = raw + .preview_removed_hook_script + .map(|s| unix::expand_shell_string(&s)); Self { max_preview_size: raw.max_preview_size, diff --git a/src/config/general/sort_raw.rs b/src/config/general/sort_raw.rs index a75a9a5..2331534 100644 --- a/src/config/general/sort_raw.rs +++ b/src/config/general/sort_raw.rs @@ -33,10 +33,10 @@ impl std::default::Default for SortOptionRaw { impl From<SortOptionRaw> for SortOption { fn from(raw: SortOptionRaw) -> Self { - let sort_method = match raw.sort_method.as_ref() { - Some(s) => SortType::parse(s).unwrap_or(SortType::Natural), - None => SortType::Natural, - }; + let sort_method = raw + .sort_method + .and_then(|s| SortType::from_str(&s)) + .unwrap_or(SortType::Natural); let mut sort_methods = SortTypes::default(); sort_methods.reorganize(sort_method); diff --git a/src/config/general/tab_raw.rs b/src/config/general/tab_raw.rs index 193c30d..9053a7c 100644 --- a/src/config/general/tab_raw.rs +++ b/src/config/general/tab_raw.rs @@ -25,12 +25,8 @@ impl std::default::Default for TabOptionRaw { impl From<TabOptionRaw> for TabOption { fn from(raw: TabOptionRaw) -> Self { - let home_page = match raw.home_page.as_str() { - "inherit" => TabHomePage::Inherit, - "home" => TabHomePage::Home, - "root" => TabHomePage::Root, - _ => TabHomePage::Home, - }; + let home_page = + TabHomePage::from_str(raw.home_page.as_str()).unwrap_or_else(|| TabHomePage::Home); Self::new(home_page) } diff --git a/src/config/mod.rs b/src/config/mod.rs index fde1759..48f7ef0 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,3 +1,4 @@ +pub mod bookmarks; pub mod general; pub mod keymap; pub mod mimetype; @@ -5,7 +6,8 @@ pub mod option; pub mod preview; pub mod theme; -pub use self::general::AppConfig; +pub use self::bookmarks::*; +pub use self::general::*; pub use self::keymap::*; pub use self::mimetype::*; pub use self::preview::*; diff --git a/src/config/option/display_option.rs b/src/config/option/display_option.rs index a339d23..eaeb971 100644 --- a/src/config/option/display_option.rs +++ b/src/config/option/display_option.rs @@ -55,6 +55,17 @@ pub enum LineNumberStyle { Absolute, } +impl LineNumberStyle { + pub fn from_str(s: &str) -> Option<Self> { + match s { + "absolute" => Some(Self::Absolute), + "relative" => Some(Self::Relative), + "none" => Some(Self::None), + _ => None, + } + } +} + impl DirListDisplayOptions { pub fn set_filter_string(&mut self, pattern: &str) { self.filter_string = pattern.to_owned(); diff --git a/src/config/option/sort_type.rs b/src/config/option/sort_type.rs index a00ad29..e8f5d29 100644 --- a/src/config/option/sort_type.rs +++ b/src/config/option/sort_type.rs @@ -18,7 +18,7 @@ pub enum SortType { } impl SortType { - pub fn parse(s: &str) -> Option<Self> { + pub fn from_str(s: &str) -> Option<Self> { match s { "lexical" => Some(SortType::Lexical), "mtime" => Some(SortType::Mtime), diff --git a/src/event/process_event.rs b/src/event/process_event.rs index 4f566ea..c207740 100644 --- a/src/event/process_event.rs +++ b/src/event/process_event.rs @@ -21,7 +21,7 @@ use crate::ui; use crate::ui::views::TuiCommandMenu; use crate::util::format; -pub fn get_input_while_composite<'a>( +pub fn poll_event_until_simple_keybind<'a>( backend: &mut ui::AppBackend, context: &mut AppContext, keymap: &'a KeyMapping, diff --git a/src/key_command/command.rs b/src/key_command/command.rs index 6b2c389..d31aea6 100644 --- a/src/key_command/command.rs +++ b/src/key_command/command.rs @@ -145,4 +145,7 @@ pub enum Command { SubdirFzf, Zoxide(String), ZoxideInteractive, + + BookmarkAdd, + BookmarkChangeDirectory, } diff --git a/src/key_command/constants.rs b/src/key_command/constants.rs index 5ec08d3..28b11ea 100644 --- a/src/key_command/constants.rs +++ b/src/key_command/constants.rs @@ -83,6 +83,8 @@ cmd_constants![ (CMD_FLAT, "flat"), (CMD_ESCAPE, "escape"), (CMD_FILTER, "filter"), + (CMD_BOOKMARK_ADD, "add_bookmark"), + (CMD_BOOKMARK_CHANGE_DIRECTORY, "cd_bookmark"), ]; pub fn complete_command(partial_command: &str) -> Vec<Pair> { diff --git a/src/key_command/impl_appcommand.rs b/src/key_command/impl_appcommand.rs index f267fea..cf4ce6d 100644 --- a/src/key_command/impl_appcommand.rs +++ b/src/key_command/impl_appcommand.rs @@ -91,6 +91,9 @@ impl AppCommand for Command { Self::SubdirFzf => CMD_SUBDIR_FZF, Self::Zoxide(_) => CMD_ZOXIDE, Self::ZoxideInteractive => CMD_ZOXIDE_INTERACTIVE, + + Self::BookmarkAdd => CMD_BOOKMARK_ADD, + Self::BookmarkChangeDirectory => CMD_BOOKMARK_CHANGE_DIRECTORY, } } } diff --git a/src/key_command/impl_appexecute.rs b/src/key_command/impl_appexecute.rs index 52a3ae3..f9b34df 100644 --- a/src/key_command/impl_appexecute.rs +++ b/src/key_command/impl_appexecute.rs @@ -141,6 +141,9 @@ impl AppExecute for Command { Self::SubdirFzf => subdir_fzf::subdir_fzf(context, backend), Self::Zoxide(arg) => zoxide::zoxide_query(context, arg), Self::ZoxideInteractive => zoxide::zoxide_query_interactive(context, backend), + + Self::BookmarkAdd => bookmark::add_bookmark(context, backend), + Self::BookmarkChangeDirectory => bookmark::change_directory_bookmark(context, backend), } } } diff --git a/src/key_command/impl_comment.rs b/src/key_command/impl_comment.rs index e1d004a..8d8eeb7 100644 --- a/src/key_command/impl_comment.rs +++ b/src/key_command/impl_comment.rs @@ -122,6 +122,9 @@ impl CommandComment for Command { Self::SubdirFzf => "Switch to a child directory via fzf", Self::Zoxide(_) => "Zoxide", Self::ZoxideInteractive => "Zoxide interactive", + + Self::BookmarkAdd => "Add a bookmark", + Self::BookmarkChangeDirectory => "Navigate to a bookmark", } } } diff --git a/src/key_command/impl_from_str.rs b/src/key_command/impl_from_str.rs index 5cb6f29..563581a 100644 --- a/src/key_command/impl_from_str.rs +++ b/src/key_command/impl_from_str.rs @@ -1,12 +1,10 @@ use std::path; -use dirs_next::home_dir; -use shellexpand::tilde_with_context; - use crate::commands::quit::QuitAction; use crate::config::option::{LineMode, LineNumberStyle, SelectOption, SortType}; use crate::error::{JoshutoError, JoshutoErrorKind}; use crate::io::FileOperationOptions; +use crate::util::unix; use crate::HOME_DIR; @@ -46,9 +44,15 @@ impl std::str::FromStr for Command { simple_command_conversion_case!(command, CMD_HELP, Self::Help); + simple_command_conversion_case!(command, CMD_BOOKMARK_ADD, Self::BookmarkAdd); + simple_command_conversion_case!( + command, + CMD_BOOKMARK_CHANGE_DIRECTORY, + Self::BookmarkChangeDirectory + ); + simple_command_conversion_case!(command, CMD_CURSOR_MOVE_HOME, Self::CursorMoveHome); simple_command_conversion_case!(command, CMD_CURSOR_MOVE_END, Self::CursorMoveEnd); - simple_command_conversion_case!( command, CMD_CURSOR_MOVE_PAGEHOME, @@ -109,9 +113,8 @@ impl std::str::FromStr for Command { ".." => Ok(Self::ParentDirectory), "-" => Ok(Self::PreviousDirectory), arg => { - let path_accepts_tilde = tilde_with_context(arg, home_dir); - let path = path::PathBuf::from(path_accepts_tilde.as_ref()); - Ok(Self::ChangeDirectory { path }) + let new_path = unix::expand_shell_string(arg); + Ok(Self::ChangeDirectory { path: new_path }) } } } else if command == CMD_CURSOR_MOVE_DOWN { @@ -327,7 +330,7 @@ impl std::str::FromStr for Command { } else if command == CMD_SORT { match arg { "reverse" => Ok(Self::SortReverse), - arg => match SortType::parse(arg) { + arg => match SortType::from_str(arg) { Some(s) => Ok(Self::Sort(s)), None => Err(JoshutoError::new( JoshutoErrorKind::InvalidParameters, diff --git a/src/key_command/impl_interactive.rs b/src/key_command/impl_interactive.rs index 8171ecb..de9664d 100644 --- a/src/key_command/impl_interactive.rs +++ b/src/key_command/impl_interactive.rs @@ -4,7 +4,6 @@ use crate::context::AppContext; use super::{Command, InteractiveExecute}; impl InteractiveExecute for Command { - #[allow(clippy::single_match)] fn interactive_execute(&self, context: &mut AppContext) { match self { Self::SearchIncremental { pattern } => { diff --git a/src/main.rs b/src/main.rs index 1446474..8b73081 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,22 +19,26 @@ use std::fs::File; use std::io::prelude::*; use std::path::PathBuf; use std::process; +use std::sync::Mutex; use structopt::StructOpt; use crate::commands::quit::QuitAction; use crate::config::{ - AppConfig, AppKeyMapping, AppProgramRegistry, AppTheme, JoshutoPreview, TomlConfigFile, + AppConfig, AppKeyMapping, AppProgramRegistry, AppTheme, Bookmarks, JoshutoPreview, + TomlConfigFile, }; use crate::context::AppContext; use crate::error::JoshutoError; const PROGRAM_NAME: &str = "joshuto"; const CONFIG_HOME: &str = "JOSHUTO_CONFIG_HOME"; + const CONFIG_FILE: &str = "joshuto.toml"; const MIMETYPE_FILE: &str = "mimetype.toml"; const KEYMAP_FILE: &str = "keymap.toml"; const THEME_FILE: &str = "theme.toml"; const PREVIEW_FILE: &str = "preview.toml"; +const BOOKMARKS_FILE: &str = "bookmarks.toml"; lazy_static! { // dynamically builds the config hierarchy @@ -69,6 +73,7 @@ lazy_static! { static ref THEME_T: AppTheme = AppTheme::get_config(THEME_FILE); static ref MIMETYPE_T: AppProgramRegistry = AppProgramRegistry::get_config(MIMETYPE_FILE); static ref PREVIEW_T: JoshutoPreview = JoshutoPreview::get_config(PREVIEW_FILE); + static ref BOOKMARKS_T: Mutex<Bookmarks> = Mutex::new(Bookmarks::get_config(BOOKMARKS_FILE)); static ref HOME_DIR: Option<PathBuf> = dirs_next::home_dir(); static ref USERNAME: String = whoami::username(); @@ -107,6 +112,8 @@ fn run_main(args: Args) -> Result<i32, JoshutoError> { lazy_static::initialize(&THEME_T); lazy_static::initialize(&MIMETYPE_T); lazy_static::initialize(&PREVIEW_T); + lazy_static::initialize(&BOOKMARKS_T); + lazy_static::initialize(&HOME_DIR); lazy_static::initialize(&USERNAME); lazy_static::initialize(&HOSTNAME); @@ -89,7 +89,8 @@ pub fn run_loop( } } Some(CommandKeybind::CompositeKeybind(m)) => { - let cmd = process_event::get_input_while_composite(backend, context, m); + let cmd = + process_event::poll_event_until_simple_keybind(backend, context, m); if let Some(command) = cmd { if let Err(e) = command.execute(context, backend, &keymap_t) { diff --git a/src/tab/homepage.rs b/src/tab/homepage.rs index b762c3b..8970a0b 100644 --- a/src/tab/homepage.rs +++ b/src/tab/homepage.rs @@ -4,3 +4,14 @@ pub enum TabHomePage { Home, Root, } + +impl TabHomePage { + pub fn from_str(s: &str) -> Option<Self> { + match s { + "inherit" => Some(Self::Inherit), + "home" => Some(Self::Home), + "root" => Some(Self::Root), + _ => None, + } + } +} diff --git a/src/util/unix.rs b/src/util/unix.rs index 8553e6a..21ff0aa 100644 --- a/src/util/unix.rs +++ b/src/util/unix.rs @@ -1,3 +1,5 @@ +use std::path; + pub fn is_executable(mode: u32) -> bool { const LIBC_PERMISSION_VALS: [u32; 3] = [ libc::S_IXUSR as u32, @@ -50,3 +52,9 @@ pub fn mode_to_string(mode: u32) -> String { } mode_str } + +pub fn expand_shell_string(s: &str) -> path::PathBuf { + let tilde_cow = shellexpand::tilde_with_context(s, dirs_next::home_dir); + let tilde_path = path::PathBuf::from(tilde_cow.as_ref()); + tilde_path +} |