Add error info to core flow.

This commit is contained in:
Csonka Mihaly 2020-03-21 15:56:03 +01:00
parent 807c3a35a5
commit ff264735b9
6 changed files with 59 additions and 34 deletions

View file

@ -1,7 +1,7 @@
use std::error::Error;
use anyhow::Error;
use std::process;
pub fn abort(operation: &str, issue_number: u32) -> Result<(), Box<dyn Error>> {
pub fn abort(operation: &str, issue_number: u32) -> Result<(), Error> {
eprintln!("This version of navi doesn't support {}.", operation);
eprintln!(
"Please check https://github.com/denisidoro/navi/issues/{} for more info.",

View file

@ -1,9 +1,9 @@
use crate::flows;
use crate::flows::core::Variant;
use crate::structures::option::Config;
use std::error::Error;
use anyhow::Error;
pub fn main(query: String, args: Vec<String>, config: Config) -> Result<(), Box<dyn Error>> {
pub fn main(query: String, args: Vec<String>, config: Config) -> Result<(), Error> {
if args.is_empty() {
flows::core::main(Variant::Filter(query), config, false)
} else {

View file

@ -8,9 +8,10 @@ use crate::structures::cheat::{Suggestion, VariableMap};
use crate::structures::fzf::{Opts as FzfOpts, SuggestionType};
use crate::structures::option;
use crate::structures::option::Config;
use anyhow::Context;
use anyhow::Error;
use regex::Regex;
use std::collections::HashMap;
use std::error::Error;
use std::fs;
use std::io::Write;
use std::process::{Command, Stdio};
@ -50,15 +51,18 @@ fn gen_core_fzf_opts(variant: Variant, config: &Config) -> FzfOpts {
fn extract_from_selections(raw_snippet: &str, contains_key: bool) -> (&str, &str, &str) {
let mut lines = raw_snippet.split('\n');
let key = if contains_key {
lines.next().unwrap()
lines
.next()
.expect("Key was promised but not present in `selections`")
} else {
"enter"
};
let mut parts = lines.next().unwrap().split(display::DELIMITER);
parts.next();
parts.next();
parts.next();
let mut parts = lines
.next()
.expect("No more parts in `selections`")
.split(display::DELIMITER)
.skip(3);
let tags = parts.next().unwrap_or("");
parts.next();
@ -72,7 +76,7 @@ fn prompt_with_suggestions(
config: &Config,
suggestion: &Suggestion,
values: &HashMap<String, String>,
) -> String {
) -> Result<String, Error> {
let mut vars_cmd = String::from("");
for (key, value) in values.iter() {
vars_cmd.push_str(format!("{}=\"{}\"; ", key, value).as_str());
@ -85,9 +89,15 @@ fn prompt_with_suggestions(
.arg("-c")
.arg(command)
.spawn()
.unwrap();
.context("Failed to execute bash")?;
let suggestions = String::from_utf8(child.wait_with_output().unwrap().stdout).unwrap();
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 opts = suggestion_opts.clone().unwrap_or_default();
let opts = FzfOpts {
@ -98,11 +108,13 @@ fn prompt_with_suggestions(
};
let (output, _) = fzf::call(opts, |stdin| {
stdin.write_all(suggestions.as_bytes()).unwrap();
stdin
.write_all(suggestions.as_bytes())
.expect("Could not write to fzf's stdin");
None
});
output
Ok(output)
}
fn prompt_without_suggestions(variable_name: &str) -> String {
@ -137,10 +149,11 @@ fn replace_variables_from_snippet(
.unwrap_or_else(|| {
variables
.get(&tags, &variable_name)
.map(|suggestion| {
.ok_or_else(|| anyhow!("No suggestions"))
.and_then(|suggestion| {
prompt_with_suggestions(variable_name, &config, suggestion, &values)
})
.unwrap_or_else(|| prompt_without_suggestions(variable_name))
.unwrap_or_else(|_| prompt_without_suggestions(variable_name))
});
values.insert(variable_name.to_string(), value.clone());
@ -156,7 +169,7 @@ fn with_new_lines(txt: String) -> String {
txt.replace(display::LINE_SEPARATOR, "\n")
}
pub fn main(variant: Variant, config: Config, contains_key: bool) -> Result<(), Box<dyn Error>> {
pub fn main(variant: Variant, config: Config, contains_key: bool) -> Result<(), Error> {
let _ = display::WIDTHS;
let opts = gen_core_fzf_opts(variant, &config);
@ -168,7 +181,7 @@ pub fn main(variant: Variant, config: Config, contains_key: bool) -> Result<(),
let interpolated_snippet = with_new_lines(replace_variables_from_snippet(
snippet,
tags,
variables.unwrap(),
variables.expect("No variables received from fzf"),
&config,
));
@ -180,7 +193,7 @@ pub fn main(variant: Variant, config: Config, contains_key: bool) -> Result<(),
println!("{}", interpolated_snippet);
// save to file
} else if let Some(s) = config.save {
fs::write(s, interpolated_snippet)?;
fs::write(s, interpolated_snippet).context("Unable to save config")?;
// call navi (this prevents "failed to read /dev/tty" from fzf)
} else if interpolated_snippet.starts_with("navi") {
let new_config = option::config_from_iter(interpolated_snippet.split(' ').collect());
@ -190,8 +203,10 @@ pub fn main(variant: Variant, config: Config, contains_key: bool) -> Result<(),
Command::new("bash")
.arg("-c")
.arg(&interpolated_snippet[..])
.spawn()?
.wait()?;
.spawn()
.context("Failed to execute bash")?
.wait()
.context("bash was not running")?;
}
Ok(())

View file

@ -1,8 +1,8 @@
use crate::flows;
use crate::flows::core::Variant;
use crate::structures::option::Config;
use std::error::Error;
use anyhow::Error;
pub fn main(query: String, config: Config) -> Result<(), Box<dyn Error>> {
pub fn main(query: String, config: Config) -> Result<(), Error> {
flows::core::main(Variant::Query(query), config, true)
}

View file

@ -1,7 +1,7 @@
use super::aux;
use crate::structures::option::Config;
use std::error::Error;
use anyhow::Error;
pub fn main(_query: String, _config: Config) -> Result<(), Box<dyn Error>> {
pub fn main(_query: String, _config: Config) -> Result<(), Error> {
aux::abort("searching for cheats online", 201)
}

View file

@ -7,21 +7,31 @@ use anyhow::Error;
pub fn handle_config(mut config: Config) -> Result<(), Error> {
match config.cmd.as_mut() {
None => Ok(flows::core::main(Variant::Core, config, true)
.expect("TODO: convert this flow fn to anyhow error")),
None => flows::core::main(Variant::Core, config, true),
Some(c) => {
match c {
Preview { line } => flows::preview::main(&line[..]),
Query { query } => Ok(flows::query::main(query.clone(), config)
.expect("TODO: convert this flow fn to anyhow error")),
Best { query, args } => Ok(flows::best::main(query.clone(), args.to_vec(), config)
.expect("TODO: convert this flow fn to anyhow error")),
Search { query } => Ok(flows::search::main(query.clone(), config)
.expect("TODO: convert this flow fn to anyhow error")),
Query { query } => {
let error_string = format!("Failed to filter cheatsheets for {}", &query);
flows::query::main(query.clone(), config).context(error_string)
}
Best { query, args } => {
let error_string = format!("Failed to execute snippet similar to {}", &query);
flows::best::main(query.clone(), args.to_vec(), config).context(error_string)
}
Search { query } => flows::search::main(query.clone(), config)
.context("Failed to search for online cheatsheets"),
Widget { shell } => Ok(flows::shell::main(&shell[..])
.expect("TODO: convert this flow fn to anyhow error")),
Fn { func, args } => flows::func::main(func.clone(), args.to_vec())
.with_context(|| format!("Failed to execute function {}", func)),
Repo { cmd } => match cmd {
RepoCommand::Add { uri } => flows::repo::add(uri.clone())
.with_context(|| format!("Failed to import cheatsheets from {}", uri)),