diff --git a/src/finder/mod.rs b/src/finder.rs similarity index 63% rename from src/finder/mod.rs rename to src/finder.rs index 4ae6994..b1f7d6b 100644 --- a/src/finder/mod.rs +++ b/src/finder.rs @@ -1,13 +1,9 @@ -mod fzf; -mod skim; - +use crate::display; use crate::structures::cheat::VariableMap; use crate::structures::finder::Opts; use crate::structures::finder::SuggestionType; use anyhow::Context; use anyhow::Error; -pub use fzf::FzfFinder; -pub use skim::SkimFinder; use std::process::{self, Output}; use std::process::{Command, Stdio}; @@ -23,18 +19,6 @@ pub trait Finder { F: Fn(&mut process::ChildStdin) -> Result, Error>; } -impl Finder for FinderChoice { - fn call(&self, opts: Opts, stdin_fn: F) -> Result<(String, Option), Error> - where - F: Fn(&mut process::ChildStdin) -> Result, Error>, - { - match self { - Self::Fzf => FzfFinder.call(opts, stdin_fn), - Self::Skim => SkimFinder.call(opts, stdin_fn), - } - } -} - fn apply_map(text: String, map_fn: Option) -> String { if let Some(m) = map_fn { let output = Command::new("bash") @@ -116,6 +100,116 @@ fn parse(out: Output, opts: Opts) -> Result { Ok(output) } +impl Finder for FinderChoice { + fn call(&self, finder_opts: Opts, stdin_fn: F) -> Result<(String, Option), Error> + where + F: Fn(&mut process::ChildStdin) -> Result, Error>, + { + let finder_str = match self { + Self::Fzf => "fzf", + Self::Skim => "sk", + }; + + let mut command = Command::new(&finder_str); + let opts = finder_opts.clone(); + + command.args(&[ + "--preview-window", + "up:2", + "--with-nth", + "1,2,3", + "--delimiter", + display::DELIMITER.to_string().as_str(), + "--ansi", + "--bind", + "ctrl-j:down,ctrl-k:up", + "--exact", + ]); + + if opts.autoselect { + command.arg("--select-1"); + } + + match opts.suggestion_type { + SuggestionType::MultipleSelections => { + command.arg("--multi"); + } + SuggestionType::Disabled => { + command.args(&["--print-query", "--no-select-1", "--height", "1"]); + } + SuggestionType::SnippetSelection => { + command.args(&["--expect", "ctrl-y,enter"]); + } + SuggestionType::SingleRecommendation => { + command.args(&["--print-query", "--expect", "tab,enter"]); + } + _ => {} + } + + if let Some(p) = opts.preview { + command.args(&["--preview", &p]); + } + + if let Some(q) = opts.query { + command.args(&["--query", &q]); + } + + if let Some(f) = opts.filter { + command.args(&["--filter", &f]); + } + + if let Some(h) = opts.header { + command.args(&["--header", &h]); + } + + if let Some(p) = opts.prompt { + command.args(&["--prompt", &p]); + } + + if let Some(pw) = opts.preview_window { + command.args(&["--preview-window", &pw]); + } + + if opts.header_lines > 0 { + command.args(&["--header-lines", format!("{}", opts.header_lines).as_str()]); + } + + 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); + }); + } + + let child = command.stdin(Stdio::piped()).stdout(Stdio::piped()).spawn(); + + let mut child = match child { + Ok(x) => x, + Err(_) => { + let repo = match self { + Self::Fzf => "https://github.com/junegunn/fzf", + Self::Skim => "https://github.com/lotabout/skim", + }; + eprintln!( + "navi was unable to call {cmd}. + Please make sure it's correctly installed. + Refer to {repo} for more info.", + cmd = &finder_str, + repo = repo + ); + process::exit(33) + } + }; + + let stdin = child.stdin.as_mut().ok_or_else(|| anyhow!("Unable to acquire stdin of finder"))?; + let result_map = stdin_fn(stdin).context("Failed to pass data to finder")?; + + let out = child.wait_with_output().context("Failed to wait for finder")?; + + let output = parse(out, finder_opts).context("Unable to get output")?; + Ok((output, result_map)) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/finder/fzf.rs b/src/finder/fzf.rs deleted file mode 100644 index b4f7cc4..0000000 --- a/src/finder/fzf.rs +++ /dev/null @@ -1,109 +0,0 @@ -use super::{parse, Finder}; -use crate::display; -use crate::structures::cheat::VariableMap; -use crate::structures::finder::{Opts, SuggestionType}; -use anyhow::Context; -use anyhow::Error; -use std::process::{self, Command, Stdio}; - -#[derive(Debug)] -pub struct FzfFinder; - -impl Finder for FzfFinder { - fn call(&self, finder_opts: Opts, stdin_fn: F) -> Result<(String, Option), Error> - where - F: Fn(&mut process::ChildStdin) -> Result, Error>, - { - let mut command = Command::new("fzf"); - let opts = finder_opts.clone(); - - command.args(&[ - "--preview-window", - "up:2", - "--with-nth", - "1,2,3", - "--delimiter", - display::DELIMITER.to_string().as_str(), - "--ansi", - "--bind", - "ctrl-j:down,ctrl-k:up", - "--exact", - ]); - - if opts.autoselect { - command.arg("--select-1"); - } - - match opts.suggestion_type { - SuggestionType::MultipleSelections => { - command.arg("--multi"); - } - SuggestionType::Disabled => { - command.args(&["--print-query", "--no-select-1", "--height", "1"]); - } - SuggestionType::SnippetSelection => { - command.args(&["--expect", "ctrl-y,enter"]); - } - SuggestionType::SingleRecommendation => { - command.args(&["--print-query", "--expect", "tab,enter"]); - } - _ => {} - } - - if let Some(p) = opts.preview { - command.args(&["--preview", &p]); - } - - if let Some(q) = opts.query { - command.args(&["--query", &q]); - } - - if let Some(f) = opts.filter { - command.args(&["--filter", &f]); - } - - if let Some(h) = opts.header { - command.args(&["--header", &h]); - } - - if let Some(p) = opts.prompt { - command.args(&["--prompt", &p]); - } - - if let Some(pw) = opts.preview_window { - command.args(&["--preview-window", &pw]); - } - - if opts.header_lines > 0 { - command.args(&["--header-lines", format!("{}", opts.header_lines).as_str()]); - } - - 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); - }); - } - - let child = command.stdin(Stdio::piped()).stdout(Stdio::piped()).spawn(); - - let mut child = match child { - Ok(x) => x, - Err(_) => { - eprintln!( - "navi was unable to call fzf. -Please make sure it's correctly installed. -Refer to https://github.com/junegunn/fzf for more info." - ); - process::exit(33) - } - }; - - let stdin = child.stdin.as_mut().ok_or_else(|| anyhow!("Unable to acquire stdin of fzf"))?; - let result_map = stdin_fn(stdin).context("Failed to pass data to fzf")?; - - let out = child.wait_with_output().context("Failed to wait for fzf")?; - - let output = parse(out, finder_opts).context("Unable to get output")?; - Ok((output, result_map)) - } -} diff --git a/src/finder/skim.rs b/src/finder/skim.rs deleted file mode 100644 index 046a552..0000000 --- a/src/finder/skim.rs +++ /dev/null @@ -1,121 +0,0 @@ -use super::{parse, Finder}; -use crate::display; -use crate::structures::cheat::VariableMap; -use crate::structures::finder::{Opts, SuggestionType}; -use anyhow::Context; -use anyhow::Error; -use std::process::{self, Command, Stdio}; - -#[derive(Debug)] -pub struct SkimFinder; - -impl Finder for SkimFinder { - fn call(&self, finder_opts: Opts, stdin_fn: F) -> Result<(String, Option), Error> - where - F: Fn(&mut process::ChildStdin) -> Result, Error>, - { - let mut command = Command::new("sk"); - let opts = finder_opts.clone(); - - command.args(&[ - "--preview-window", - "up:3", - "--with-nth", - "1,2,3", - "--delimiter", - display::DELIMITER.to_string().as_str(), - "--ansi", - "--bind", - "ctrl-j:down,ctrl-k:up", - ]); - - if opts.autoselect { - // TODO skim doesn't support this yet - // this option does nothing - command.arg("--select-1"); - } - - match opts.suggestion_type { - SuggestionType::MultipleSelections => { - command.arg("--multi"); - } - SuggestionType::Disabled => { - command.args(&["--print-query", /*"--no-select-1",*/ "--height", "1"]); - } - SuggestionType::SnippetSelection => { - command.args(&["--expect", "ctrl-y,enter"]); - } - SuggestionType::SingleRecommendation => { - command.args(&["--print-query", "--expect", "tab,enter"]); - } - _ => {} - } - - if let Some(p) = opts.preview { - command.args(&["--preview", &p]); - } - - if let Some(q) = opts.query { - command.args(&["--query", &q]); - } - - if let Some(f) = opts.filter { - command.args(&["--filter", &f]); - } - - if let Some(h) = opts.header { - command.args(&["--header", &h]); - } - - if let Some(p) = opts.prompt { - command.args(&["--prompt", &p]); - } - - if let Some(pw) = opts.preview_window { - command.args(&["--preview-window", &pw]); - } - - if opts.header_lines > 0 { - command.args(&["--header-lines", format!("{}", opts.header_lines).as_str()]); - } - - let mut exact = true; - - if let Some(o) = opts.overrides { - if o.contains("--no-exact") { - exact = false - } - - o.as_str() - .split(' ') - .map(|s| s.to_string()) - .filter(|s| !s.is_empty()) - .filter(|s| s != "--no-exact") - .for_each(|s| { - command.arg(s); - }); - } - - if exact { - command.arg("--exact"); - } - - let child = command.stdin(Stdio::piped()).stdout(Stdio::piped()).spawn(); - - let mut child = match child { - Ok(x) => x, - Err(_) => { - eprintln!("navi was unable to call skim.\nPlease make sure it's correctly installed\nRefer to https://github.com/junegunn/skim for more info."); - process::exit(33) - } - }; - - let stdin = child.stdin.as_mut().ok_or_else(|| anyhow!("Unable to acquire stdin of skim"))?; - let result_map = stdin_fn(stdin).context("Failed to pass data to skim")?; - - let out = child.wait_with_output().context("Failed to wait for skim")?; - - let output = parse(out, finder_opts).context("Unable to get output")?; - Ok((output, result_map)) - } -}