From ec6596fe76e02f58028a72a397638fd7fdd1ae4b Mon Sep 17 00:00:00 2001 From: Denis Isidoro Date: Fri, 27 Nov 2020 09:35:15 -0300 Subject: [PATCH] Fix Ctrl-O behavior when snippet has variables (#437) --- rustfmt.toml | 2 +- src/cheatsh.rs | 30 +++++++++++-- src/cmds/alfred.rs | 14 ++++-- src/cmds/core.rs | 93 ++++++++++++++++++++++++++++++--------- src/cmds/func.rs | 4 +- src/cmds/repo.rs | 21 ++++++--- src/common/file_issue.rs | 4 +- src/common/filesystem.rs | 18 ++++++-- src/common/shell.rs | 4 +- src/common/url.rs | 5 ++- src/display/alfred.rs | 4 +- src/display/mod.rs | 4 +- src/display/terminal.rs | 19 +++++--- src/fetcher/filesystem.rs | 36 +++++++++++++-- src/fetcher/mod.rs | 7 ++- src/filesystem.rs | 11 ++++- src/finder.rs | 50 ++++++++++++++++----- src/handler.rs | 31 +++++++++---- src/parser.rs | 29 +++++++++--- src/tldr.rs | 14 +++++- src/welcome.rs | 20 +++++++-- 21 files changed, 332 insertions(+), 88 deletions(-) diff --git a/rustfmt.toml b/rustfmt.toml index bc30bf4..284d219 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1 +1 @@ -max_width = 150 +max_width = 110 diff --git a/src/cheatsh.rs b/src/cheatsh.rs index 224e9fc..7600c1f 100644 --- a/src/cheatsh.rs +++ b/src/cheatsh.rs @@ -24,17 +24,34 @@ fn lines(query: &str, markdown: &str) -> impl Iterator Result, Error> { +fn read_all( + query: &str, + cheat: &str, + stdin: &mut std::process::ChildStdin, + writer: &mut dyn Writer, +) -> Result, Error> { let mut variables = VariableMap::new(); let mut visited_lines = HashSet::new(); - parser::read_lines(lines(query, cheat), "cheat.sh", 0, &mut variables, &mut visited_lines, writer, stdin)?; + parser::read_lines( + lines(query, cheat), + "cheat.sh", + 0, + &mut variables, + &mut visited_lines, + writer, + stdin, + )?; Ok(Some(variables)) } pub fn fetch(query: &str) -> Result { let args = ["-qO-", &format!("cheat.sh/{}", query)]; - let child = Command::new("wget").args(&args).stdin(Stdio::piped()).stdout(Stdio::piped()).spawn(); + let child = Command::new("wget") + .args(&args) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn(); let child = match child { Ok(x) => x, @@ -85,7 +102,12 @@ impl Fetcher { } impl fetcher::Fetcher for Fetcher { - fn fetch(&self, stdin: &mut std::process::ChildStdin, writer: &mut dyn Writer, _files: &mut Vec) -> Result, Error> { + fn fetch( + &self, + stdin: &mut std::process::ChildStdin, + writer: &mut dyn Writer, + _files: &mut Vec, + ) -> Result, Error> { let cheat = fetch(&self.query)?; read_all(&self.query, &cheat, stdin, writer) } diff --git a/src/cmds/alfred.rs b/src/cmds/alfred.rs index 4898ba5..a3db0c5 100644 --- a/src/cmds/alfred.rs +++ b/src/cmds/alfred.rs @@ -10,7 +10,10 @@ use std::env; use std::process::{Command, Stdio}; pub fn main(config: Config) -> Result<(), Error> { - let mut child = Command::new("cat").stdin(Stdio::piped()).spawn().context("Unable to create child")?; + let mut child = Command::new("cat") + .stdin(Stdio::piped()) + .spawn() + .context("Unable to create child")?; let stdin = child.stdin.as_mut().context("Unable to get stdin")?; let mut writer = display::alfred::Writer::new(); @@ -38,8 +41,13 @@ fn prompt_finder(suggestion: &Suggestion) -> Result { .spawn() .map_err(|e| BashSpawnError::new(suggestion_command, e))?; - let suggestions = String::from_utf8(child.wait_with_output().context("Failed to wait and collect output from bash")?.stdout) - .context("Suggestions are invalid utf8")?; + let suggestions = String::from_utf8( + child + .wait_with_output() + .context("Failed to wait and collect output from bash")? + .stdout, + ) + .context("Suggestions are invalid utf8")?; Ok(suggestions) } diff --git a/src/cmds/core.rs b/src/cmds/core.rs index 58e5177..5a28e96 100644 --- a/src/cmds/core.rs +++ b/src/cmds/core.rs @@ -15,7 +15,7 @@ use crate::tldr; use crate::welcome; use anyhow::Context; use anyhow::Error; -use edit; + use std::env; use std::fs; use std::io::Write; @@ -32,23 +32,40 @@ fn gen_core_finder_opts(config: &Config) -> Result { autoselect: config.autoselect(), overrides: config.fzf_overrides.clone(), suggestion_type: SuggestionType::SnippetSelection, - query: if config.get_best_match() { None } else { config.get_query() }, - filter: if config.get_best_match() { config.get_query() } else { None }, + query: if config.get_best_match() { + None + } else { + config.get_query() + }, + filter: if config.get_best_match() { + config.get_query() + } else { + None + }, ..Default::default() }; Ok(opts) } -fn extract_from_selections(raw_snippet: &str, is_single: bool) -> Result<(&str, &str, &str, &str, Option), Error> { +fn extract_from_selections( + raw_snippet: &str, + is_single: bool, +) -> Result<(&str, &str, &str, &str, Option), Error> { let mut lines = raw_snippet.split('\n'); let key = if is_single { "enter" } else { - lines.next().context("Key was promised but not present in `selections`")? + lines + .next() + .context("Key was promised but not present in `selections`")? }; - let mut parts = lines.next().context("No more parts in `selections`")?.split(display::DELIMITER).skip(3); + let mut parts = lines + .next() + .context("No more parts in `selections`")? + .split(display::DELIMITER) + .skip(3); let tags = parts.next().unwrap_or(""); let comment = parts.next().unwrap_or(""); @@ -57,7 +74,12 @@ fn extract_from_selections(raw_snippet: &str, is_single: bool) -> Result<(&str, Ok((key, tags, comment, snippet, file_index)) } -fn prompt_finder(variable_name: &str, config: &Config, suggestion: Option<&Suggestion>, variable_count: usize) -> Result { +fn prompt_finder( + variable_name: &str, + config: &Config, + suggestion: Option<&Suggestion>, + variable_count: usize, +) -> Result { env::remove_var(env_vars::PREVIEW_COLUMN); env::remove_var(env_vars::PREVIEW_DELIMITER); env::remove_var(env_vars::PREVIEW_MAP); @@ -89,8 +111,13 @@ fn prompt_finder(variable_name: &str, config: &Config, suggestion: Option<&Sugge .spawn() .map_err(|e| BashSpawnError::new(suggestion_command, e))?; - let text = String::from_utf8(child.wait_with_output().context("Failed to wait and collect output from bash")?.stdout) - .context("Suggestions are invalid utf8")?; + let text = String::from_utf8( + child + .wait_with_output() + .context("Failed to wait and collect output from bash")? + .stdout, + ) + .context("Suggestions are invalid utf8")?; (text, suggestion_opts) } else { @@ -138,7 +165,9 @@ NAVIEOF let (output, _) = config .finder .call(opts, &mut Vec::new(), |stdin, _| { - stdin.write_all(suggestions.as_bytes()).context("Could not write to finder's stdin")?; + stdin + .write_all(suggestions.as_bytes()) + .context("Could not write to finder's stdin")?; Ok(None) }) .context("finder was unable to prompt with suggestions")?; @@ -153,9 +182,17 @@ fn unique_result_count(results: &[&str]) -> usize { vars.len() } -fn replace_variables_from_snippet(snippet: &str, tags: &str, variables: VariableMap, config: &Config) -> Result { +fn replace_variables_from_snippet( + snippet: &str, + tags: &str, + variables: VariableMap, + config: &Config, +) -> Result { let mut interpolated_snippet = String::from(snippet); - let variables_found: Vec<&str> = display::VAR_REGEX.find_iter(snippet).map(|m| m.as_str()).collect(); + let variables_found: Vec<&str> = display::VAR_REGEX + .find_iter(snippet) + .map(|m| m.as_str()) + .collect(); let variable_count = unique_result_count(&variables_found); for bracketed_variable_name in variables_found { @@ -167,7 +204,8 @@ fn replace_variables_from_snippet(snippet: &str, tags: &str, variables: Variable e } else if let Some(suggestion) = variables.get_suggestion(&tags, &variable_name) { let mut new_suggestion = suggestion.clone(); - new_suggestion.0 = replace_variables_from_snippet(&new_suggestion.0, tags, variables.clone(), config)?; + new_suggestion.0 = + replace_variables_from_snippet(&new_suggestion.0, tags, variables.clone(), config)?; prompt_finder(variable_name, &config, Some(&new_suggestion), variable_count)? } else { prompt_finder(variable_name, &config, None, variable_count)? @@ -214,15 +252,27 @@ pub fn main(config: Config) -> Result<(), Error> { }) .context("Failed getting selection and variables from finder")?; - let (key, tags, comment, snippet, file_index) = extract_from_selections(&raw_selection, config.get_best_match())?; + let (key, tags, comment, snippet, file_index) = + extract_from_selections(&raw_selection, config.get_best_match())?; + + if key == "ctrl-o" { + edit::edit_file(Path::new(&files[file_index.expect("No files found")])) + .expect("Cound not open file in external editor"); + return Ok(()); + } env::set_var(env_vars::PREVIEW_INITIAL_SNIPPET, &snippet); env::set_var(env_vars::PREVIEW_TAGS, &tags); env::set_var(env_vars::PREVIEW_COMMENT, &comment); let interpolated_snippet = display::with_new_lines( - replace_variables_from_snippet(snippet, tags, variables.expect("No variables received from finder"), &config) - .context("Failed to replace variables from snippet")?, + replace_variables_from_snippet( + snippet, + tags, + variables.expect("No variables received from finder"), + &config, + ) + .context("Failed to replace variables from snippet")?, ); match config.action() { @@ -232,12 +282,11 @@ pub fn main(config: Config) -> Result<(), Error> { Action::SAVE(filepath) => { fs::write(filepath, interpolated_snippet).context("Unable to save output")?; } - Action::EXECUTE => { - if key == "ctrl-y" { + Action::EXECUTE => match key { + "ctrl-y" => { clipboard::copy(interpolated_snippet)?; - } else if key == "ctrl-o" { - edit::edit_file(Path::new(&files[file_index.expect("No files found")])).expect("Cound not open file in external editor"); - } else { + } + _ => { Command::new("bash") .arg("-c") .arg(&interpolated_snippet[..]) @@ -246,7 +295,7 @@ pub fn main(config: Config) -> Result<(), Error> { .wait() .context("bash was not running")?; } - } + }, }; Ok(()) diff --git a/src/cmds/func.rs b/src/cmds/func.rs index a35b28e..666908e 100644 --- a/src/cmds/func.rs +++ b/src/cmds/func.rs @@ -12,6 +12,8 @@ pub enum Func { pub fn main(func: &Func, args: Vec) -> Result<(), Error> { match func { Func::UrlOpen => url::open(args), - Func::Welcome => handler::handle_config(config::config_from_iter("navi --path /tmp/navi/irrelevant".split(' ').collect())), + Func::Welcome => handler::handle_config(config::config_from_iter( + "navi --path /tmp/navi/irrelevant".split(' ').collect(), + )), } } diff --git a/src/cmds/repo.rs b/src/cmds/repo.rs index 8e5ea5f..6dbc50d 100644 --- a/src/cmds/repo.rs +++ b/src/cmds/repo.rs @@ -14,9 +14,11 @@ pub fn browse(finder: &FinderChoice) -> Result<(), Error> { filesystem::create_dir(&repo_path_str)?; let (repo_url, _, _) = git::meta("denisidoro/cheats"); - git::shallow_clone(repo_url.as_str(), &repo_path_str).with_context(|| format!("Failed to clone `{}`", repo_url))?; + git::shallow_clone(repo_url.as_str(), &repo_path_str) + .with_context(|| format!("Failed to clone `{}`", repo_url))?; - let repos = fs::read_to_string(format!("{}/featured_repos.txt", &repo_path_str)).context("Unable to fetch featured repositories")?; + let repos = fs::read_to_string(format!("{}/featured_repos.txt", &repo_path_str)) + .context("Unable to fetch featured repositories")?; let opts = FinderOpts { column: Some(1), @@ -26,7 +28,9 @@ pub fn browse(finder: &FinderChoice) -> Result<(), Error> { let (repo, _) = finder .call(opts, &mut Vec::new(), |stdin, _| { - stdin.write_all(repos.as_bytes()).context("Unable to prompt featured repositories")?; + stdin + .write_all(repos.as_bytes()) + .context("Unable to prompt featured repositories")?; Ok(None) }) .context("Failed to get repo URL from finder")?; @@ -45,7 +49,9 @@ pub fn ask_if_should_import_all(finder: &FinderChoice) -> Result { let (response, _) = finder .call(opts, &mut Vec::new(), |stdin, _| { - stdin.write_all(b"Yes\nNo").context("Unable to writer alternatives")?; + stdin + .write_all(b"Yes\nNo") + .context("Unable to writer alternatives")?; Ok(None) }) .context("Unable to get response")?; @@ -69,7 +75,8 @@ pub fn add(uri: String, finder: &FinderChoice) -> Result<(), Error> { eprintln!("Cloning {} into {}...\n", &actual_uri, &tmp_path_str); - git::shallow_clone(actual_uri.as_str(), &tmp_path_str).with_context(|| format!("Failed to clone `{}`", actual_uri))?; + git::shallow_clone(actual_uri.as_str(), &tmp_path_str) + .with_context(|| format!("Failed to clone `{}`", actual_uri))?; let all_files = filesystem::all_cheat_files(&tmp_path_str).join("\n"); @@ -86,7 +93,9 @@ pub fn add(uri: String, finder: &FinderChoice) -> Result<(), Error> { } else { let (files, _) = finder .call(opts, &mut Vec::new(), |stdin, _| { - stdin.write_all(all_files.as_bytes()).context("Unable to prompt cheats to import")?; + stdin + .write_all(all_files.as_bytes()) + .context("Unable to prompt cheats to import")?; Ok(None) }) .context("Failed to get cheatsheet files from finder")?; diff --git a/src/common/file_issue.rs b/src/common/file_issue.rs index c1deeee..40d468f 100644 --- a/src/common/file_issue.rs +++ b/src/common/file_issue.rs @@ -16,6 +16,8 @@ impl FileAnIssue { where SourceError: Into, { - FileAnIssue { source: source.into() } + FileAnIssue { + source: source.into(), + } } } diff --git a/src/common/filesystem.rs b/src/common/filesystem.rs index 5b116ee..429a61f 100644 --- a/src/common/filesystem.rs +++ b/src/common/filesystem.rs @@ -23,7 +23,9 @@ where P: AsRef + Display + Copy, { let file = File::open(filename).with_context(|| format!("Failed to open file {}", filename))?; - Ok(io::BufReader::new(file).lines().map(|line| line.map_err(Error::from))) + Ok(io::BufReader::new(file) + .lines() + .map(|line| line.map_err(Error::from))) } pub fn pathbuf_to_string(pathbuf: PathBuf) -> Result { @@ -37,10 +39,18 @@ pub fn pathbuf_to_string(pathbuf: PathBuf) -> Result { fn follow_symlink(pathbuf: PathBuf) -> Result { fs::read_link(pathbuf.clone()) .map(|o| { - let o_str = o.as_os_str().to_str().ok_or_else(|| InvalidPath(o.to_path_buf()))?; + let o_str = o + .as_os_str() + .to_str() + .ok_or_else(|| InvalidPath(o.to_path_buf()))?; if o_str.starts_with('.') { - let parent = pathbuf.parent().ok_or_else(|| anyhow!("`{}` has no parent", pathbuf.display()))?; - let parent_str = parent.as_os_str().to_str().ok_or_else(|| InvalidPath(parent.to_path_buf()))?; + let parent = pathbuf + .parent() + .ok_or_else(|| anyhow!("`{}` has no parent", pathbuf.display()))?; + let parent_str = parent + .as_os_str() + .to_str() + .ok_or_else(|| InvalidPath(parent.to_path_buf()))?; let path_str = format!("{}/{}", parent_str, o_str); let p = PathBuf::from(path_str); follow_symlink(p) diff --git a/src/common/shell.rs b/src/common/shell.rs index 84d34f1..b85d97f 100644 --- a/src/common/shell.rs +++ b/src/common/shell.rs @@ -3,7 +3,9 @@ use std::fmt::Debug; use thiserror::Error; lazy_static! { - pub static ref IS_FISH: bool = env::var("SHELL").unwrap_or_else(|_| "".to_string()).contains(&"fish"); + pub static ref IS_FISH: bool = env::var("SHELL") + .unwrap_or_else(|_| "".to_string()) + .contains(&"fish"); } #[derive(Debug)] diff --git a/src/common/url.rs b/src/common/url.rs index 0856eb3..23b61ca 100644 --- a/src/common/url.rs +++ b/src/common/url.rs @@ -3,7 +3,10 @@ use anyhow::Error; use std::process::Command; pub fn open(args: Vec) -> Result<(), Error> { - let url = args.into_iter().next().ok_or_else(|| anyhow!("No URL specified"))?; + let url = args + .into_iter() + .next() + .ok_or_else(|| anyhow!("No URL specified"))?; let code = r#" exst() { type "$1" &>/dev/null diff --git a/src/display/alfred.rs b/src/display/alfred.rs index 28cf23a..a1c90b5 100644 --- a/src/display/alfred.rs +++ b/src/display/alfred.rs @@ -6,7 +6,9 @@ pub struct Writer { } fn escape_for_json(txt: &str) -> String { - txt.replace('\\', "\\\\").replace('"', "“").replace(display::NEWLINE_ESCAPE_CHAR, " ") + txt.replace('\\', "\\\\") + .replace('"', "“") + .replace(display::NEWLINE_ESCAPE_CHAR, " ") } pub fn print_items_start(varname: Option<&str>) { diff --git a/src/display/mod.rs b/src/display/mod.rs index 0f57dc1..9f70b97 100644 --- a/src/display/mod.rs +++ b/src/display/mod.rs @@ -19,7 +19,9 @@ pub fn with_new_lines(txt: String) -> String { pub fn fix_newlines(txt: &str) -> String { if txt.contains(NEWLINE_ESCAPE_CHAR) { - (*NEWLINE_REGEX).replace_all(txt.replace(LINE_SEPARATOR, " ").as_str(), "").to_string() + (*NEWLINE_REGEX) + .replace_all(txt.replace(LINE_SEPARATOR, " ").as_str(), "") + .to_string() } else { txt.to_string() } diff --git a/src/display/terminal.rs b/src/display/terminal.rs index ed864fd..7e3514b 100644 --- a/src/display/terminal.rs +++ b/src/display/terminal.rs @@ -19,9 +19,12 @@ pub fn parse_env_var(varname: &str) -> Option { } lazy_static! { - pub static ref TAG_COLOR: color::AnsiValue = color::AnsiValue(parse_env_var(env_vars::TAG_COLOR).unwrap_or(14)); - pub static ref COMMENT_COLOR: color::AnsiValue = color::AnsiValue(parse_env_var(env_vars::COMMENT_COLOR).unwrap_or(4)); - pub static ref SNIPPET_COLOR: color::AnsiValue = color::AnsiValue(parse_env_var(env_vars::SNIPPET_COLOR).unwrap_or(7)); + pub static ref TAG_COLOR: color::AnsiValue = + color::AnsiValue(parse_env_var(env_vars::TAG_COLOR).unwrap_or(14)); + pub static ref COMMENT_COLOR: color::AnsiValue = + color::AnsiValue(parse_env_var(env_vars::COMMENT_COLOR).unwrap_or(4)); + pub static ref SNIPPET_COLOR: color::AnsiValue = + color::AnsiValue(parse_env_var(env_vars::SNIPPET_COLOR).unwrap_or(7)); pub static ref TAG_WIDTH_PERCENTAGE: u16 = parse_env_var(env_vars::TAG_WIDTH).unwrap_or(20); pub static ref COMMENT_WIDTH_PERCENTAGE: u16 = parse_env_var(env_vars::COMMENT_WIDTH).unwrap_or(40); } @@ -106,7 +109,10 @@ pub fn preview_var(selection: &str, query: &str, variable: &str) { color = variable_color, variable = variable_name, reset = reset, - value = wrapped_by_map(&finder::get_column(value, column, delimiter.as_deref()), map.as_deref()) + value = wrapped_by_map( + &finder::get_column(value, column, delimiter.as_deref()), + map.as_deref() + ) ); } @@ -145,7 +151,10 @@ pub struct Writer { impl Writer { pub fn new() -> Writer { let (tag_width, comment_width) = get_widths(); - display::terminal::Writer { tag_width, comment_width } + display::terminal::Writer { + tag_width, + comment_width, + } } } diff --git a/src/fetcher/filesystem.rs b/src/fetcher/filesystem.rs index 37fcd25..7b1c3dd 100644 --- a/src/fetcher/filesystem.rs +++ b/src/fetcher/filesystem.rs @@ -58,7 +58,12 @@ pub fn cheat_paths(path: Option) -> Result { } } -pub fn read_all(path: Option, files: &mut Vec, stdin: &mut std::process::ChildStdin, writer: &mut dyn Writer) -> Result, Error> { +pub fn read_all( + path: Option, + files: &mut Vec, + stdin: &mut std::process::ChildStdin, + writer: &mut dyn Writer, +) -> Result, Error> { let mut variables = VariableMap::new(); let mut found_something = false; let mut visited_lines = HashSet::new(); @@ -75,7 +80,18 @@ pub fn read_all(path: Option, files: &mut Vec, stdin: &mut std:: for file in all_cheat_files(folder) { let full_filename = format!("{}/{}", &folder, &file); files.push(full_filename.clone()); - if read_file(&full_filename, files.len()-1, &mut variables, &mut visited_lines, writer, stdin).is_ok() && !found_something { + let index = files.len() - 1; + if read_file( + &full_filename, + index, + &mut variables, + &mut visited_lines, + writer, + stdin, + ) + .is_ok() + && !found_something + { found_something = true } } @@ -99,11 +115,23 @@ mod tests { fn test_read_file() { let path = "tests/cheats/ssh.cheat"; let mut variables = VariableMap::new(); - let mut child = Command::new("cat").stdin(Stdio::piped()).stdout(Stdio::null()).spawn().unwrap(); + let mut child = Command::new("cat") + .stdin(Stdio::piped()) + .stdout(Stdio::null()) + .spawn() + .unwrap(); let child_stdin = child.stdin.as_mut().unwrap(); let mut visited_lines: HashSet = HashSet::new(); let mut writer: Box = Box::new(display::terminal::Writer::new()); - read_file(path, 0, &mut variables, &mut visited_lines, &mut *writer, child_stdin).unwrap(); + read_file( + path, + 0, + &mut variables, + &mut visited_lines, + &mut *writer, + child_stdin, + ) + .unwrap(); let expected_suggestion = ( r#" echo -e "$(whoami)\nroot" "#.to_string(), Some(FinderOpts { diff --git a/src/fetcher/mod.rs b/src/fetcher/mod.rs index 3f91657..3225df6 100644 --- a/src/fetcher/mod.rs +++ b/src/fetcher/mod.rs @@ -5,5 +5,10 @@ use crate::structures::cheat::VariableMap; use anyhow::Error; pub trait Fetcher { - fn fetch(&self, stdin: &mut std::process::ChildStdin, writer: &mut dyn Writer, files: &mut Vec) -> Result, Error>; + fn fetch( + &self, + stdin: &mut std::process::ChildStdin, + writer: &mut dyn Writer, + files: &mut Vec, + ) -> Result, Error>; } diff --git a/src/filesystem.rs b/src/filesystem.rs index f93f6a7..4977938 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -1,4 +1,6 @@ -pub use crate::common::filesystem::{create_dir, exe_string, pathbuf_to_string, remove_dir, InvalidPath, UnreadableDir}; +pub use crate::common::filesystem::{ + create_dir, exe_string, pathbuf_to_string, remove_dir, InvalidPath, UnreadableDir, +}; use crate::display::Writer; use crate::fetcher; pub use crate::fetcher::filesystem::{all_cheat_files, default_cheat_pathbuf, read_all}; @@ -21,7 +23,12 @@ impl Fetcher { } impl fetcher::Fetcher for Fetcher { - fn fetch(&self, stdin: &mut std::process::ChildStdin, writer: &mut dyn Writer, files: &mut Vec) -> Result, Error> { + fn fetch( + &self, + stdin: &mut std::process::ChildStdin, + writer: &mut dyn Writer, + files: &mut Vec, + ) -> Result, Error> { read_all(self.path.clone(), files, stdin, writer) } } diff --git a/src/finder.rs b/src/finder.rs index d41bf7f..2486dc8 100644 --- a/src/finder.rs +++ b/src/finder.rs @@ -14,7 +14,12 @@ pub enum FinderChoice { } pub trait Finder { - fn call(&self, opts: Opts, files: &mut Vec, stdin_fn: F) -> Result<(String, Option), Error> + fn call( + &self, + opts: Opts, + files: &mut Vec, + stdin_fn: F, + ) -> Result<(String, Option), Error> where F: Fn(&mut process::ChildStdin, &mut Vec) -> Result, Error>; } @@ -58,7 +63,11 @@ pub fn get_column(text: String, column: Option, delimiter: Option<&str>) -> fn parse_output_single(mut text: String, suggestion_type: SuggestionType) -> Result { Ok(match suggestion_type { - SuggestionType::SingleSelection => text.lines().next().context("Not sufficient data for single selection")?.to_string(), + SuggestionType::SingleSelection => text + .lines() + .next() + .context("Not sufficient data for single selection")? + .to_string(), SuggestionType::MultipleSelections | SuggestionType::Disabled | SuggestionType::SnippetSelection => { let len = text.len(); if len > 1 { @@ -70,14 +79,18 @@ fn parse_output_single(mut text: String, suggestion_type: SuggestionType) -> Res let lines: Vec<&str> = text.lines().collect(); match (lines.get(0), lines.get(1), lines.get(2)) { - (Some(one), Some(termination), Some(two)) if *termination == "enter" || termination.is_empty() => { + (Some(one), Some(termination), Some(two)) + if *termination == "enter" || termination.is_empty() => + { if two.is_empty() { (*one).to_string() } else { (*two).to_string() } } - (Some(one), Some(termination), None) if *termination == "enter" || termination.is_empty() => (*one).to_string(), + (Some(one), Some(termination), None) if *termination == "enter" || termination.is_empty() => { + (*one).to_string() + } (Some(one), Some(termination), _) if *termination == "tab" => (*one).to_string(), _ => "".to_string(), } @@ -87,10 +100,13 @@ fn parse_output_single(mut text: String, suggestion_type: SuggestionType) -> Res fn parse(out: Output, opts: Opts) -> Result { let text = match out.status.code() { - Some(0) | Some(1) | Some(2) => String::from_utf8(out.stdout).context("Invalid utf8 received from finder")?, + Some(0) | Some(1) | Some(2) => { + String::from_utf8(out.stdout).context("Invalid utf8 received from finder")? + } Some(130) => process::exit(130), _ => { - let err = String::from_utf8(out.stderr).unwrap_or_else(|_| "".to_owned()); + let err = String::from_utf8(out.stderr) + .unwrap_or_else(|_| "".to_owned()); panic!("External command failed:\n {}", err) } }; @@ -102,7 +118,12 @@ fn parse(out: Output, opts: Opts) -> Result { } impl Finder for FinderChoice { - fn call(&self, finder_opts: Opts, files: &mut Vec, stdin_fn: F) -> Result<(String, Option), Error> + fn call( + &self, + finder_opts: Opts, + files: &mut Vec, + stdin_fn: F, + ) -> Result<(String, Option), Error> where F: Fn(&mut process::ChildStdin, &mut Vec) -> Result, Error>, { @@ -189,9 +210,13 @@ impl Finder for FinderChoice { } if let Some(o) = opts.overrides { - o.as_str().split(' ').map(|s| s.to_string()).filter(|s| !s.is_empty()).for_each(|s| { - command.arg(s); - }); + o.as_str() + .split(' ') + .map(|s| s.to_string()) + .filter(|s| !s.is_empty()) + .for_each(|s| { + command.arg(s); + }); } let child = command.stdin(Stdio::piped()).stdout(Stdio::piped()).spawn(); @@ -214,7 +239,10 @@ impl Finder for FinderChoice { } }; - let stdin = child.stdin.as_mut().ok_or_else(|| anyhow!("Unable to acquire stdin of finder"))?; + let stdin = child + .stdin + .as_mut() + .ok_or_else(|| anyhow!("Unable to acquire stdin of finder"))?; let result_map = stdin_fn(stdin, files).context("Failed to pass data to finder")?; let out = child.wait_with_output().context("Failed to wait for finder")?; diff --git a/src/handler.rs b/src/handler.rs index bb7ea2a..241ad64 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -11,17 +11,25 @@ pub fn handle_config(config: Config) -> Result<(), Error> { Some(c) => match c { Preview { line } => cmds::preview::main(&line), - PreviewVar { selection, query, variable } => cmds::preview::main_var(&selection, &query, &variable), + PreviewVar { + selection, + query, + variable, + } => cmds::preview::main_var(&selection, &query, &variable), Widget { shell } => cmds::shell::main(shell).context("Failed to print shell widget code"), - Fn { func, args } => cmds::func::main(func, args.to_vec()).with_context(|| format!("Failed to execute function `{:#?}`", func)), + Fn { func, args } => cmds::func::main(func, args.to_vec()) + .with_context(|| format!("Failed to execute function `{:#?}`", func)), - Info { info } => cmds::info::main(info).with_context(|| format!("Failed to fetch info `{:#?}`", info)), + Info { info } => { + cmds::info::main(info).with_context(|| format!("Failed to fetch info `{:#?}`", info)) + } Repo { cmd } => match cmd { RepoCommand::Add { uri } => { - cmds::repo::add(uri.clone(), &config.finder).with_context(|| format!("Failed to import cheatsheets from `{}`", uri))?; + cmds::repo::add(uri.clone(), &config.finder) + .with_context(|| format!("Failed to import cheatsheets from `{}`", uri))?; cmds::core::main(config) } RepoCommand::Browse => { @@ -31,10 +39,17 @@ pub fn handle_config(config: Config) -> Result<(), Error> { }, Alfred { cmd } => match cmd { - AlfredCommand::Start => cmds::alfred::main(config).context("Failed to call Alfred starting function"), - AlfredCommand::Suggestions => cmds::alfred::suggestions(config, false).context("Failed to call Alfred suggestion function"), - AlfredCommand::Check => cmds::alfred::suggestions(config, true).context("Failed to call Alfred check function"), - AlfredCommand::Transform => cmds::alfred::transform().context("Failed to call Alfred transform function"), + AlfredCommand::Start => { + cmds::alfred::main(config).context("Failed to call Alfred starting function") + } + AlfredCommand::Suggestions => cmds::alfred::suggestions(config, false) + .context("Failed to call Alfred suggestion function"), + AlfredCommand::Check => { + cmds::alfred::suggestions(config, true).context("Failed to call Alfred check function") + } + AlfredCommand::Transform => { + cmds::alfred::transform().context("Failed to call Alfred transform function") + } }, _ => cmds::core::main(config), diff --git a/src/parser.rs b/src/parser.rs index 4501c5b..3b41dc8 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -45,8 +45,18 @@ fn parse_opts(text: &str) -> Result { .map(|flag_and_value| { if let [flag, value] = flag_and_value { match flag.as_str() { - "--headers" | "--header-lines" => opts.header_lines = value.parse::().context("Value for `--headers` is invalid u8")?, - "--column" => opts.column = Some(value.parse::().context("Value for `--column` is invalid u8")?), + "--headers" | "--header-lines" => { + opts.header_lines = value + .parse::() + .context("Value for `--headers` is invalid u8")? + } + "--column" => { + opts.column = Some( + value + .parse::() + .context("Value for `--column` is invalid u8")?, + ) + } "--map" => opts.map = Some(value.to_string()), "--delimiter" => opts.delimiter = Some(value.to_string()), "--query" => opts.query = Some(value.to_string()), @@ -145,7 +155,8 @@ pub fn read_lines( let mut should_break = false; for (line_nr, line_result) in lines.enumerate() { - let line = line_result.with_context(|| format!("Failed to read line number {} in cheatsheet `{}`", line_nr, id))?; + let line = line_result + .with_context(|| format!("Failed to read line number {} in cheatsheet `{}`", line_nr, id))?; if should_break { break; @@ -180,8 +191,13 @@ pub fn read_lines( else if line.starts_with('$') { should_break = write_cmd(&tags, &comment, &snippet, &file_index, writer, stdin).is_err(); snippet = String::from(""); - let (variable, command, opts) = parse_variable_line(&line) - .with_context(|| format!("Failed to parse variable line. See line number {} in cheatsheet `{}`", line_nr + 1, id))?; + let (variable, command, opts) = parse_variable_line(&line).with_context(|| { + format!( + "Failed to parse variable line. See line number {} in cheatsheet `{}`", + line_nr + 1, + id + ) + })?; variables.insert_suggestion(&tags, &variable, (String::from(command), opts)); } // snippet @@ -212,7 +228,8 @@ mod tests { #[test] fn test_parse_variable_line() { - let (variable, command, command_options) = parse_variable_line("$ user : echo -e \"$(whoami)\\nroot\" --- --prevent-extra").unwrap(); + let (variable, command, command_options) = + parse_variable_line("$ user : echo -e \"$(whoami)\\nroot\" --- --prevent-extra").unwrap(); assert_eq!(command, " echo -e \"$(whoami)\\nroot\" "); assert_eq!(variable, "user"); assert_eq!( diff --git a/src/tldr.rs b/src/tldr.rs index d7d985a..ae10f80 100644 --- a/src/tldr.rs +++ b/src/tldr.rs @@ -60,7 +60,12 @@ fn markdown_lines(query: &str, markdown: &str) -> impl Iterator Result, Error> { +fn read_all( + query: &str, + markdown: &str, + stdin: &mut std::process::ChildStdin, + writer: &mut dyn Writer, +) -> Result, Error> { let mut variables = VariableMap::new(); let mut visited_lines = HashSet::new(); parser::read_lines( @@ -145,7 +150,12 @@ impl Fetcher { } impl fetcher::Fetcher for Fetcher { - fn fetch(&self, stdin: &mut std::process::ChildStdin, writer: &mut dyn Writer, _files: &mut Vec) -> Result, Error> { + fn fetch( + &self, + stdin: &mut std::process::ChildStdin, + writer: &mut dyn Writer, + _files: &mut Vec, + ) -> Result, Error> { let markdown = fetch(&self.query)?; read_all(&self.query, &markdown, stdin, writer) } diff --git a/src/welcome.rs b/src/welcome.rs index 5be067f..21864e9 100644 --- a/src/welcome.rs +++ b/src/welcome.rs @@ -2,14 +2,22 @@ use crate::display::Writer; use crate::structures::item::Item; use std::io::Write; -fn add_msg(tags: &str, comment: &str, snippet: &str, writer: &mut dyn Writer, stdin: &mut std::process::ChildStdin) { +fn add_msg( + tags: &str, + comment: &str, + snippet: &str, + writer: &mut dyn Writer, + stdin: &mut std::process::ChildStdin, +) { let item = Item { tags: &tags, comment: &comment, snippet: &snippet, file_index: &0, }; - stdin.write_all(writer.write(item).as_bytes()).expect("Could not write to fzf's stdin"); + stdin + .write_all(writer.write(item).as_bytes()) + .expect("Could not write to fzf's stdin"); } pub fn populate_cheatsheet(writer: &mut dyn Writer, stdin: &mut std::process::ChildStdin) { @@ -20,6 +28,12 @@ pub fn populate_cheatsheet(writer: &mut dyn Writer, stdin: &mut std::process::Ch writer, stdin, ); - add_msg("cheatsheets", "Browse for cheatsheet repos", "navi repo browse", writer, stdin); + add_msg( + "cheatsheets", + "Browse for cheatsheet repos", + "navi repo browse", + writer, + stdin, + ); add_msg("more info", "Read --help message", "navi --help", writer, stdin); }