Refactor to lookup filenames in Vector

This commit is contained in:
Benjamin Siderius-Manning 2020-11-26 21:36:20 +01:00
parent d78bcf1f60
commit 0686583a57
No known key found for this signature in database
GPG key ID: 365F67BB26C7CCB1
13 changed files with 44 additions and 38 deletions

View file

@ -27,7 +27,7 @@ fn lines(query: &str, markdown: &str) -> impl Iterator<Item = Result<String, Err
fn read_all(query: &str, cheat: &str, stdin: &mut std::process::ChildStdin, writer: &mut dyn Writer) -> Result<Option<VariableMap>, Error> { fn read_all(query: &str, cheat: &str, stdin: &mut std::process::ChildStdin, writer: &mut dyn Writer) -> Result<Option<VariableMap>, Error> {
let mut variables = VariableMap::new(); let mut variables = VariableMap::new();
let mut visited_lines = HashSet::new(); let mut visited_lines = HashSet::new();
parser::read_lines(lines(query, cheat), "cheat.sh", &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)) Ok(Some(variables))
} }
@ -85,7 +85,7 @@ impl Fetcher {
} }
impl fetcher::Fetcher for Fetcher { impl fetcher::Fetcher for Fetcher {
fn fetch(&self, stdin: &mut std::process::ChildStdin, writer: &mut dyn Writer) -> Result<Option<VariableMap>, Error> { fn fetch(&self, stdin: &mut std::process::ChildStdin, writer: &mut dyn Writer, _files: &mut Vec<String>) -> Result<Option<VariableMap>, Error> {
let cheat = fetch(&self.query)?; let cheat = fetch(&self.query)?;
read_all(&self.query, &cheat, stdin, writer) read_all(&self.query, &cheat, stdin, writer)
} }

View file

@ -18,7 +18,7 @@ pub fn main(config: Config) -> Result<(), Error> {
let fetcher = filesystem::Fetcher::new(config.path); let fetcher = filesystem::Fetcher::new(config.path);
fetcher fetcher
.fetch(stdin, &mut writer) .fetch(stdin, &mut writer, &mut Vec::new())
.context("Failed to parse variables intended for finder")?; .context("Failed to parse variables intended for finder")?;
// make sure everything was printed to stdout before attempting to close the items vector // make sure everything was printed to stdout before attempting to close the items vector
@ -55,7 +55,7 @@ pub fn suggestions(config: Config, dry_run: bool) -> Result<(), Error> {
let fetcher = filesystem::Fetcher::new(config.path); let fetcher = filesystem::Fetcher::new(config.path);
let variables = fetcher let variables = fetcher
.fetch(stdin, &mut writer) .fetch(stdin, &mut writer, &mut Vec::new())
.context("Failed to parse variables intended for finder")? .context("Failed to parse variables intended for finder")?
.expect("Empty variable map"); .expect("Empty variable map");

View file

@ -40,7 +40,7 @@ fn gen_core_finder_opts(config: &Config) -> Result<FinderOpts, Error> {
Ok(opts) Ok(opts)
} }
fn extract_from_selections(raw_snippet: &str, is_single: bool) -> Result<(&str, &str, &str, &str, &str), Error> { fn extract_from_selections(raw_snippet: &str, is_single: bool) -> Result<(&str, &str, &str, &str, Option<usize>), Error> {
let mut lines = raw_snippet.split('\n'); let mut lines = raw_snippet.split('\n');
let key = if is_single { let key = if is_single {
"enter" "enter"
@ -53,8 +53,8 @@ fn extract_from_selections(raw_snippet: &str, is_single: bool) -> Result<(&str,
let tags = parts.next().unwrap_or(""); let tags = parts.next().unwrap_or("");
let comment = parts.next().unwrap_or(""); let comment = parts.next().unwrap_or("");
let snippet = parts.next().unwrap_or(""); let snippet = parts.next().unwrap_or("");
let suggestion_file = parts.next().unwrap_or(""); let file_index = parts.next().unwrap_or("").parse().ok();
Ok((key, tags, comment, snippet, suggestion_file)) Ok((key, tags, comment, snippet, file_index))
} }
fn prompt_finder(variable_name: &str, config: &Config, suggestion: Option<&Suggestion>, variable_count: usize) -> Result<String, Error> { fn prompt_finder(variable_name: &str, config: &Config, suggestion: Option<&Suggestion>, variable_count: usize) -> Result<String, Error> {
@ -137,7 +137,7 @@ NAVIEOF
let (output, _) = config let (output, _) = config
.finder .finder
.call(opts, |stdin| { .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) Ok(None)
}) })
@ -188,9 +188,11 @@ fn replace_variables_from_snippet(snippet: &str, tags: &str, variables: Variable
pub fn main(config: Config) -> Result<(), Error> { pub fn main(config: Config) -> Result<(), Error> {
let opts = gen_core_finder_opts(&config).context("Failed to generate finder options")?; let opts = gen_core_finder_opts(&config).context("Failed to generate finder options")?;
let mut files = Vec::new();
let (raw_selection, variables) = config let (raw_selection, variables) = config
.finder .finder
.call(opts, |stdin| { .call(opts, &mut files, |stdin, files| {
let mut writer = display::terminal::Writer::new(); let mut writer = display::terminal::Writer::new();
let fetcher: Box<dyn Fetcher> = match config.source() { let fetcher: Box<dyn Fetcher> = match config.source() {
@ -200,7 +202,7 @@ pub fn main(config: Config) -> Result<(), Error> {
}; };
let res = fetcher let res = fetcher
.fetch(stdin, &mut writer) .fetch(stdin, &mut writer, files)
.context("Failed to parse variables intended for finder")?; .context("Failed to parse variables intended for finder")?;
if let Some(variables) = res { if let Some(variables) = res {
@ -212,7 +214,7 @@ pub fn main(config: Config) -> Result<(), Error> {
}) })
.context("Failed getting selection and variables from finder")?; .context("Failed getting selection and variables from finder")?;
let (key, tags, comment, snippet, suggestion_file) = 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())?;
env::set_var(env_vars::PREVIEW_INITIAL_SNIPPET, &snippet); env::set_var(env_vars::PREVIEW_INITIAL_SNIPPET, &snippet);
env::set_var(env_vars::PREVIEW_TAGS, &tags); env::set_var(env_vars::PREVIEW_TAGS, &tags);
@ -234,7 +236,7 @@ pub fn main(config: Config) -> Result<(), Error> {
if key == "ctrl-y" { if key == "ctrl-y" {
clipboard::copy(interpolated_snippet)?; clipboard::copy(interpolated_snippet)?;
} else if key == "ctrl-o" { } else if key == "ctrl-o" {
edit::edit_file(Path::new(suggestion_file)).expect("Cound not open file in external editor"); edit::edit_file(Path::new(&files[file_index.expect("No files found")])).expect("Cound not open file in external editor");
} else { } else {
Command::new("bash") Command::new("bash")
.arg("-c") .arg("-c")

View file

@ -25,7 +25,7 @@ pub fn browse(finder: &FinderChoice) -> Result<(), Error> {
}; };
let (repo, _) = finder let (repo, _) = finder
.call(opts, |stdin| { .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) Ok(None)
}) })
@ -44,7 +44,7 @@ pub fn ask_if_should_import_all(finder: &FinderChoice) -> Result<bool, Error> {
}; };
let (response, _) = finder let (response, _) = finder
.call(opts, |stdin| { .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) Ok(None)
}) })
@ -85,7 +85,7 @@ pub fn add(uri: String, finder: &FinderChoice) -> Result<(), Error> {
all_files all_files
} else { } else {
let (files, _) = finder let (files, _) = finder
.call(opts, |stdin| { .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) Ok(None)
}) })

View file

@ -152,7 +152,7 @@ impl Writer {
impl display::Writer for Writer { impl display::Writer for Writer {
fn write(&mut self, item: Item) -> String { fn write(&mut self, item: Item) -> String {
format!( format!(
"{tag_color}{tags_short}{delimiter}{comment_color}{comment_short}{delimiter}{snippet_color}{snippet_short}{delimiter}{tags}{delimiter}{comment}{delimiter}{snippet}{delimiter}{file}{delimiter}\n", "{tag_color}{tags_short}{delimiter}{comment_color}{comment_short}{delimiter}{snippet_color}{snippet_short}{delimiter}{tags}{delimiter}{comment}{delimiter}{snippet}{delimiter}{file_index}{delimiter}\n",
tags_short = limit_str(item.tags, self.tag_width), tags_short = limit_str(item.tags, self.tag_width),
comment_short = limit_str(item.comment, self.comment_width), comment_short = limit_str(item.comment, self.comment_width),
snippet_short = display::fix_newlines(item.snippet), snippet_short = display::fix_newlines(item.snippet),
@ -163,7 +163,7 @@ impl display::Writer for Writer {
comment = item.comment, comment = item.comment,
delimiter = display::DELIMITER, delimiter = display::DELIMITER,
snippet = &item.snippet, snippet = &item.snippet,
file = item.file, file_index = item.file_index,
) )
} }
} }

View file

@ -31,13 +31,14 @@ fn paths_from_path_param<'a>(env_var: &'a str) -> impl Iterator<Item = &'a str>
// TODO: move // TODO: move
fn read_file( fn read_file(
path: &str, path: &str,
file_index: usize,
variables: &mut VariableMap, variables: &mut VariableMap,
visited_lines: &mut HashSet<u64>, visited_lines: &mut HashSet<u64>,
writer: &mut dyn Writer, writer: &mut dyn Writer,
stdin: &mut std::process::ChildStdin, stdin: &mut std::process::ChildStdin,
) -> Result<(), Error> { ) -> Result<(), Error> {
let lines = read_lines(path)?; let lines = read_lines(path)?;
parser::read_lines(lines, path, variables, visited_lines, writer, stdin) parser::read_lines(lines, path, file_index, variables, visited_lines, writer, stdin)
} }
pub fn default_cheat_pathbuf() -> Result<PathBuf, Error> { pub fn default_cheat_pathbuf() -> Result<PathBuf, Error> {
@ -57,7 +58,7 @@ pub fn cheat_paths(path: Option<String>) -> Result<String, Error> {
} }
} }
pub fn read_all(path: Option<String>, stdin: &mut std::process::ChildStdin, writer: &mut dyn Writer) -> Result<Option<VariableMap>, Error> { pub fn read_all(path: Option<String>, files: &mut Vec<String>, stdin: &mut std::process::ChildStdin, writer: &mut dyn Writer) -> Result<Option<VariableMap>, Error> {
let mut variables = VariableMap::new(); let mut variables = VariableMap::new();
let mut found_something = false; let mut found_something = false;
let mut visited_lines = HashSet::new(); let mut visited_lines = HashSet::new();
@ -73,7 +74,8 @@ pub fn read_all(path: Option<String>, stdin: &mut std::process::ChildStdin, writ
for folder in folders { for folder in folders {
for file in all_cheat_files(folder) { for file in all_cheat_files(folder) {
let full_filename = format!("{}/{}", &folder, &file); let full_filename = format!("{}/{}", &folder, &file);
if read_file(&full_filename, &mut variables, &mut visited_lines, writer, stdin).is_ok() && !found_something { files.push(full_filename.clone());
if read_file(&full_filename, files.len()-1, &mut variables, &mut visited_lines, writer, stdin).is_ok() && !found_something {
found_something = true found_something = true
} }
} }
@ -101,7 +103,7 @@ mod tests {
let child_stdin = child.stdin.as_mut().unwrap(); let child_stdin = child.stdin.as_mut().unwrap();
let mut visited_lines: HashSet<u64> = HashSet::new(); let mut visited_lines: HashSet<u64> = HashSet::new();
let mut writer: Box<dyn Writer> = Box::new(display::terminal::Writer::new()); let mut writer: Box<dyn Writer> = Box::new(display::terminal::Writer::new());
read_file(path, &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 = ( let expected_suggestion = (
r#" echo -e "$(whoami)\nroot" "#.to_string(), r#" echo -e "$(whoami)\nroot" "#.to_string(),
Some(FinderOpts { Some(FinderOpts {

View file

@ -5,5 +5,5 @@ use crate::structures::cheat::VariableMap;
use anyhow::Error; use anyhow::Error;
pub trait Fetcher { pub trait Fetcher {
fn fetch(&self, stdin: &mut std::process::ChildStdin, writer: &mut dyn Writer) -> Result<Option<VariableMap>, Error>; fn fetch(&self, stdin: &mut std::process::ChildStdin, writer: &mut dyn Writer, files: &mut Vec<String>) -> Result<Option<VariableMap>, Error>;
} }

View file

@ -21,7 +21,7 @@ impl Fetcher {
} }
impl fetcher::Fetcher for Fetcher { impl fetcher::Fetcher for Fetcher {
fn fetch(&self, stdin: &mut std::process::ChildStdin, writer: &mut dyn Writer) -> Result<Option<VariableMap>, Error> { fn fetch(&self, stdin: &mut std::process::ChildStdin, writer: &mut dyn Writer, files: &mut Vec<String>) -> Result<Option<VariableMap>, Error> {
read_all(self.path.clone(), stdin, writer) read_all(self.path.clone(), files, stdin, writer)
} }
} }

View file

@ -14,9 +14,9 @@ pub enum FinderChoice {
} }
pub trait Finder { pub trait Finder {
fn call<F>(&self, opts: Opts, stdin_fn: F) -> Result<(String, Option<VariableMap>), Error> fn call<F>(&self, opts: Opts, files: &mut Vec<String>, stdin_fn: F) -> Result<(String, Option<VariableMap>), Error>
where where
F: Fn(&mut process::ChildStdin) -> Result<Option<VariableMap>, Error>; F: Fn(&mut process::ChildStdin, &mut Vec<String>) -> Result<Option<VariableMap>, Error>;
} }
fn apply_map(text: String, map_fn: Option<String>) -> String { fn apply_map(text: String, map_fn: Option<String>) -> String {
@ -102,9 +102,9 @@ fn parse(out: Output, opts: Opts) -> Result<String, Error> {
} }
impl Finder for FinderChoice { impl Finder for FinderChoice {
fn call<F>(&self, finder_opts: Opts, stdin_fn: F) -> Result<(String, Option<VariableMap>), Error> fn call<F>(&self, finder_opts: Opts, files: &mut Vec<String>, stdin_fn: F) -> Result<(String, Option<VariableMap>), Error>
where where
F: Fn(&mut process::ChildStdin) -> Result<Option<VariableMap>, Error>, F: Fn(&mut process::ChildStdin, &mut Vec<String>) -> Result<Option<VariableMap>, Error>,
{ {
let finder_str = match self { let finder_str = match self {
Self::Fzf => "fzf", Self::Fzf => "fzf",
@ -215,7 +215,7 @@ 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).context("Failed to pass data to 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")?; let out = child.wait_with_output().context("Failed to wait for finder")?;

View file

@ -103,7 +103,7 @@ fn write_cmd(
tags: &str, tags: &str,
comment: &str, comment: &str,
snippet: &str, snippet: &str,
file: &str, file_index: &usize,
writer: &mut dyn Writer, writer: &mut dyn Writer,
stdin: &mut std::process::ChildStdin, stdin: &mut std::process::ChildStdin,
) -> Result<(), Error> { ) -> Result<(), Error> {
@ -114,7 +114,7 @@ fn write_cmd(
tags: &tags, tags: &tags,
comment: &comment, comment: &comment,
snippet: &snippet, snippet: &snippet,
file: &file, file_index: &file_index,
}; };
stdin stdin
.write_all(writer.write(item).as_bytes()) .write_all(writer.write(item).as_bytes())
@ -133,6 +133,7 @@ fn without_prefix(line: &str) -> String {
pub fn read_lines( pub fn read_lines(
lines: impl Iterator<Item = Result<String, Error>>, lines: impl Iterator<Item = Result<String, Error>>,
id: &str, id: &str,
file_index: usize,
variables: &mut VariableMap, variables: &mut VariableMap,
visited_lines: &mut HashSet<u64>, visited_lines: &mut HashSet<u64>,
writer: &mut dyn Writer, writer: &mut dyn Writer,
@ -157,7 +158,7 @@ pub fn read_lines(
} }
// tag // tag
else if line.starts_with('%') { else if line.starts_with('%') {
should_break = write_cmd(&tags, &comment, &snippet, &id, writer, stdin).is_err(); should_break = write_cmd(&tags, &comment, &snippet, &file_index, writer, stdin).is_err();
snippet = String::from(""); snippet = String::from("");
tags = without_prefix(&line); tags = without_prefix(&line);
} }
@ -171,13 +172,13 @@ pub fn read_lines(
} }
// comment // comment
else if line.starts_with('#') { else if line.starts_with('#') {
should_break = write_cmd(&tags, &comment, &snippet, &id, writer, stdin).is_err(); should_break = write_cmd(&tags, &comment, &snippet, &file_index, writer, stdin).is_err();
snippet = String::from(""); snippet = String::from("");
comment = without_prefix(&line); comment = without_prefix(&line);
} }
// variable // variable
else if line.starts_with('$') { else if line.starts_with('$') {
should_break = write_cmd(&tags, &comment, &snippet, &id, writer, stdin).is_err(); should_break = write_cmd(&tags, &comment, &snippet, &file_index, writer, stdin).is_err();
snippet = String::from(""); snippet = String::from("");
let (variable, command, opts) = parse_variable_line(&line) 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))?; .with_context(|| format!("Failed to parse variable line. See line number {} in cheatsheet `{}`", line_nr + 1, id))?;
@ -199,7 +200,7 @@ pub fn read_lines(
} }
if !should_break { if !should_break {
let _ = write_cmd(&tags, &comment, &snippet, &id, writer, stdin); let _ = write_cmd(&tags, &comment, &snippet, &file_index, writer, stdin);
} }
Ok(()) Ok(())

View file

@ -2,5 +2,5 @@ pub struct Item<'a> {
pub tags: &'a str, pub tags: &'a str,
pub comment: &'a str, pub comment: &'a str,
pub snippet: &'a str, pub snippet: &'a str,
pub file: &'a str, pub file_index: &'a usize,
} }

View file

@ -66,6 +66,7 @@ fn read_all(query: &str, markdown: &str, stdin: &mut std::process::ChildStdin, w
parser::read_lines( parser::read_lines(
markdown_lines(query, markdown), markdown_lines(query, markdown),
"markdown", "markdown",
0,
&mut variables, &mut variables,
&mut visited_lines, &mut visited_lines,
writer, writer,
@ -144,7 +145,7 @@ impl Fetcher {
} }
impl fetcher::Fetcher for Fetcher { impl fetcher::Fetcher for Fetcher {
fn fetch(&self, stdin: &mut std::process::ChildStdin, writer: &mut dyn Writer) -> Result<Option<VariableMap>, Error> { fn fetch(&self, stdin: &mut std::process::ChildStdin, writer: &mut dyn Writer, _files: &mut Vec<String>) -> Result<Option<VariableMap>, Error> {
let markdown = fetch(&self.query)?; let markdown = fetch(&self.query)?;
read_all(&self.query, &markdown, stdin, writer) read_all(&self.query, &markdown, stdin, writer)
} }

View file

@ -7,7 +7,7 @@ fn add_msg(tags: &str, comment: &str, snippet: &str, writer: &mut dyn Writer, st
tags: &tags, tags: &tags,
comment: &comment, comment: &comment,
snippet: &snippet, snippet: &snippet,
file: "", 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");
} }