Small refactors (#289)

This commit is contained in:
Denis Isidoro 2020-03-18 12:29:29 -03:00 committed by GitHub
parent 87a5efa059
commit 84e28e7885
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 166 additions and 171 deletions

View file

@ -201,7 +201,7 @@ $ image_id: docker images --- --column 3 --header-lines 1 --delimiter '\s\s+'
The supported parameters are:
- `--prevent-extra` *(experimental)*: limits the user to select one of the suggestions;
- `--column <number>`: extracts a single column from the selected result;
- `--delimiter <regex>`: delimits columns;
- `--delimiter <regex>`: delimits columns + forwarded option to `fzf`;
- `--multi`: forwarded option to `fzf`;
- `--header-lines <number>`: forwarded option to `fzf`;

View file

@ -1,12 +0,0 @@
use crate::cmds;
use crate::cmds::core::Variant;
use crate::option::Config;
use std::error::Error;
pub fn main(query: String, args: Vec<String>, config: Config) -> Result<(), Box<dyn Error>> {
if args.is_empty() {
cmds::core::main(Variant::Filter(query), config, false)
} else {
cmds::aux::abort("passing arguments to 'navi best'", 201)
}
}

View file

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

View file

@ -3,13 +3,13 @@ use regex::Regex;
use std::cmp::max;
use termion::color;
static COMMENT_COLOR: color::LightCyan = color::LightCyan;
static TAG_COLOR: color::Blue = color::Blue;
static SNIPPET_COLOR: color::White = color::White;
const COMMENT_COLOR: color::LightCyan = color::LightCyan;
const TAG_COLOR: color::Blue = color::Blue;
const SNIPPET_COLOR: color::White = color::White;
static NEWLINE_ESCAPE_CHAR: char = '\x15';
pub static LINE_SEPARATOR: &str = " \x15 ";
pub static DELIMITER: &str = r" ";
const NEWLINE_ESCAPE_CHAR: char = '\x15';
pub const LINE_SEPARATOR: &str = " \x15 ";
pub const DELIMITER: &str = r" ";
lazy_static! {
pub static ref WIDTHS: (usize, usize) = get_widths();

View file

@ -1,4 +1,4 @@
use crate::option::Config;
use crate::structures::option::Config;
use std::fs;
use std::fs::File;
use std::io::{self, BufRead, BufReader, Lines};

12
src/flows/best.rs Normal file
View file

@ -0,0 +1,12 @@
use crate::flows;
use crate::flows::core::Variant;
use crate::structures::option::Config;
use std::error::Error;
pub fn main(query: String, args: Vec<String>, config: Config) -> Result<(), Box<dyn Error>> {
if args.is_empty() {
flows::core::main(Variant::Filter(query), config, false)
} else {
flows::aux::abort("passing arguments to 'navi best'", 201)
}
}

View file

@ -1,12 +1,13 @@
use crate::cheat;
use crate::cheat::SuggestionType;
use crate::cmds;
use crate::display;
use crate::filesystem;
use crate::flows;
use crate::fzf;
use crate::handler;
use crate::option;
use crate::option::Config;
use crate::parser;
use crate::structures::cheat::{Suggestion, SuggestionType, VariableMap};
use crate::structures::fzf::Opts as FzfOpts;
use crate::structures::option;
use crate::structures::option::Config;
use regex::Regex;
use std::collections::HashMap;
use std::error::Error;
@ -20,8 +21,8 @@ pub enum Variant {
Query(String),
}
fn gen_core_fzf_opts(variant: Variant, config: &Config) -> fzf::Opts {
let mut opts = fzf::Opts {
fn gen_core_fzf_opts(variant: Variant, config: &Config) -> FzfOpts {
let mut opts = FzfOpts {
preview: if config.no_preview {
None
} else {
@ -65,7 +66,7 @@ fn extract_from_selections(raw_snippet: &str, contains_key: bool) -> (&str, &str
fn prompt_with_suggestions(
varname: &str,
config: &Config,
suggestion: &cheat::Suggestion,
suggestion: &Suggestion,
values: &HashMap<String, String>,
) -> String {
let mut vars_cmd = String::from("");
@ -84,7 +85,7 @@ fn prompt_with_suggestions(
let suggestions = String::from_utf8(child.wait_with_output().unwrap().stdout).unwrap();
let mut opts = fzf::Opts {
let mut opts = FzfOpts {
autoselect: !config.no_autoselect,
overrides: config.fzf_overrides_var.as_ref(),
prompt: Some(display::variable_prompt(varname)),
@ -107,7 +108,7 @@ fn prompt_with_suggestions(
}
fn prompt_without_suggestions(variable_name: &str) -> String {
let opts = fzf::Opts {
let opts = FzfOpts {
autoselect: false,
prompt: Some(display::variable_prompt(variable_name)),
suggestion_type: SuggestionType::Disabled,
@ -122,7 +123,7 @@ fn prompt_without_suggestions(variable_name: &str) -> String {
fn replace_variables_from_snippet(
snippet: &str,
tags: &str,
variables: cheat::VariableMap,
variables: VariableMap,
config: &Config,
) -> String {
let mut interpolated_snippet = String::from(snippet);
@ -162,7 +163,7 @@ pub fn main(variant: Variant, config: Config, contains_key: bool) -> Result<(),
let _ = display::WIDTHS;
let (raw_selection, variables) = fzf::call(gen_core_fzf_opts(variant, &config), |stdin| {
Some(cheat::read_all(&config, stdin))
Some(parser::read_all(&config, stdin))
});
let (key, tags, snippet) = extract_from_selections(&raw_selection[..], contains_key);
@ -176,7 +177,7 @@ pub fn main(variant: Variant, config: Config, contains_key: bool) -> Result<(),
// copy to clipboard
if key == "ctrl-y" {
cmds::aux::abort("copying snippets to the clipboard", 201)?
flows::aux::abort("copying snippets to the clipboard", 201)?
// print to stdout
} else if config.print {
println!("{}", interpolated_snippet);

View file

@ -1,5 +1,5 @@
use crate::handler;
use crate::option;
use crate::structures::option;
use std::error::Error;
use std::process::Command;

8
src/flows/query.rs Normal file
View file

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

View file

@ -1,7 +1,8 @@
use crate::cheat::SuggestionType;
use crate::filesystem;
use crate::fzf;
use crate::git;
use crate::structures::cheat::SuggestionType;
use crate::structures::fzf::Opts as FzfOpts;
use git2::Repository;
use std::error::Error;
use std::fs;
@ -22,7 +23,7 @@ pub fn browse() -> Result<(), Box<dyn Error>> {
let repos = fs::read_to_string(format!("{}/featured_repos.txt", &repo_path_str))
.expect("Unable to fetch featured repos");
let opts = fzf::Opts {
let opts = FzfOpts {
column: Some(1),
..Default::default()
};
@ -66,7 +67,7 @@ pub fn add(uri: String) -> Result<(), Box<dyn Error>> {
.join("\n");
let overrides = "--preview-window right:30%".to_string();
let opts = fzf::Opts {
let opts = FzfOpts {
suggestion_type: SuggestionType::MultipleSelections,
preview: Some(format!("cat '{}/{{}}'", tmp_path_str)),
header: Some(

View file

@ -1,5 +1,5 @@
use super::aux;
use crate::option::Config;
use crate::structures::option::Config;
use std::error::Error;
pub fn main(_query: String, _config: Config) -> Result<(), Box<dyn Error>> {

View file

@ -1,42 +1,9 @@
use crate::cheat;
use crate::cheat::SuggestionType;
use crate::cheat::SuggestionType::SingleSelection;
use crate::display;
use crate::structures::cheat::{SuggestionType, VariableMap};
use crate::structures::fzf::Opts;
use std::process;
use std::process::{Command, Stdio};
pub struct Opts<'a> {
pub query: Option<String>,
pub filter: Option<String>,
pub prompt: Option<String>,
pub preview: Option<String>,
pub autoselect: bool,
pub overrides: Option<&'a String>, // TODO: remove &'a
pub header_lines: u8,
pub header: Option<String>,
pub suggestion_type: SuggestionType,
pub delimiter: Option<&'a str>,
pub column: Option<u8>,
}
impl Default for Opts<'_> {
fn default() -> Self {
Self {
query: None,
filter: None,
autoselect: true,
preview: None,
overrides: None,
header_lines: 0,
header: None,
prompt: None,
suggestion_type: SingleSelection,
column: None,
delimiter: None,
}
}
}
fn get_column(text: String, column: Option<u8>, delimiter: Option<&str>) -> String {
if let Some(c) = column {
let re = regex::Regex::new(delimiter.unwrap_or(r"\s\s+")).unwrap();
@ -50,9 +17,9 @@ fn get_column(text: String, column: Option<u8>, delimiter: Option<&str>) -> Stri
}
}
pub fn call<F>(opts: Opts, stdin_fn: F) -> (String, Option<cheat::VariableMap>)
pub fn call<F>(opts: Opts, stdin_fn: F) -> (String, Option<VariableMap>)
where
F: Fn(&mut process::ChildStdin) -> Option<cheat::VariableMap>,
F: Fn(&mut process::ChildStdin) -> Option<VariableMap>,
{
let mut fzf_command = Command::new("fzf");

View file

@ -1,22 +1,22 @@
use crate::cmds;
use crate::cmds::core::Variant;
use crate::option::Command::{Best, Fn, Preview, Query, Repo, Search, Widget};
use crate::option::{Config, RepoCommand};
use crate::flows;
use crate::flows::core::Variant;
use crate::structures::option::Command::{Best, Fn, Preview, Query, Repo, Search, Widget};
use crate::structures::option::{Config, RepoCommand};
use std::error::Error;
pub fn handle_config(mut config: Config) -> Result<(), Box<dyn Error>> {
match config.cmd.as_mut() {
None => cmds::core::main(Variant::Core, config, true),
None => flows::core::main(Variant::Core, config, true),
Some(c) => match c {
Preview { line } => cmds::preview::main(&line[..]),
Query { query } => cmds::query::main(query.clone(), config),
Best { query, args } => cmds::best::main(query.clone(), args.to_vec(), config),
Search { query } => cmds::search::main(query.clone(), config),
Widget { shell } => cmds::shell::main(&shell[..]),
Fn { func, args } => cmds::func::main(func.clone(), args.to_vec()),
Preview { line } => flows::preview::main(&line[..]),
Query { query } => flows::query::main(query.clone(), config),
Best { query, args } => flows::best::main(query.clone(), args.to_vec(), config),
Search { query } => flows::search::main(query.clone(), config),
Widget { shell } => flows::shell::main(&shell[..]),
Fn { func, args } => flows::func::main(func.clone(), args.to_vec()),
Repo { cmd } => match cmd {
RepoCommand::Add { uri } => cmds::repo::add(uri.clone()),
RepoCommand::Browse => cmds::repo::browse(),
RepoCommand::Add { uri } => flows::repo::add(uri.clone()),
RepoCommand::Browse => flows::repo::browse(),
},
},
}

View file

@ -1,20 +1,19 @@
#[macro_use]
extern crate lazy_static;
mod cheat;
mod cmds;
mod display;
mod filesystem;
mod fnv;
mod flows;
mod fzf;
mod git;
mod handler;
mod option;
mod parser;
mod structures;
mod terminal;
mod welcome;
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
handler::handle_config(option::config_from_env())
handler::handle_config(structures::option::config_from_env())
}

View file

@ -1,53 +1,14 @@
use crate::display;
use crate::filesystem;
use crate::fnv::HashLine;
use crate::option::Config;
use crate::structures::cheat::{SuggestionOpts, SuggestionType, VariableMap};
use crate::structures::fnv::HashLine;
use crate::structures::option::Config;
use crate::welcome;
use regex::Regex;
use std::collections::{HashMap, HashSet};
use std::collections::HashSet;
use std::fs;
use std::io::Write;
#[derive(Debug, PartialEq)]
pub struct SuggestionOpts {
pub header_lines: u8,
pub column: Option<u8>,
pub delimiter: Option<String>,
pub suggestion_type: SuggestionType,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum SuggestionType {
/// fzf will not print any suggestions
Disabled,
/// fzf will only select one of the suggestions
SingleSelection,
/// fzf will select multiple suggestions
MultipleSelections,
/// fzf will select one of the suggestions or use the query
SingleRecommendation,
/// initial snippet selection
SnippetSelection,
}
pub type Suggestion = (String, Option<SuggestionOpts>);
pub struct VariableMap(HashMap<u64, Suggestion>);
impl VariableMap {
pub fn new() -> Self {
Self(HashMap::new())
}
pub fn insert(&mut self, tags: &str, variable: &str, value: Suggestion) -> Option<Suggestion> {
self.0.insert(gen_key(tags, variable), value)
}
pub fn get(&self, tags: &str, variable: &str) -> Option<&Suggestion> {
self.0.get(&gen_key(tags, variable))
}
}
fn remove_quotes(txt: &str) -> String {
txt.replace('"', "").replace('\'', "")
}
@ -118,15 +79,11 @@ fn write_cmd(
}
}
fn gen_key(tags: &str, variable: &str) -> u64 {
format!("{};{}", tags, variable).hash_line()
}
fn read_file(
path: &str,
variables: &mut VariableMap,
visited_lines: &mut HashSet<u64>,
stdin: &mut std::process::ChildStdin,
set: &mut HashSet<u64>,
) -> bool {
let mut tags = String::from("");
let mut comment = String::from("");
@ -143,10 +100,10 @@ fn read_file(
let line = l.unwrap();
let hash = line.hash_line();
if set.contains(&hash) {
if visited_lines.contains(&hash) {
continue;
}
set.insert(hash);
visited_lines.insert(hash);
// blank
if line.is_empty() {
@ -203,9 +160,9 @@ fn read_file(
pub fn read_all(config: &Config, stdin: &mut std::process::ChildStdin) -> VariableMap {
let mut variables = VariableMap::new();
let mut found_something = false;
let mut visited_lines = HashSet::new();
let paths = filesystem::cheat_paths(config);
let folders = paths.split(':');
let mut set = HashSet::new();
for folder in folders {
if let Ok(paths) = fs::read_dir(folder) {
@ -213,7 +170,7 @@ pub fn read_all(config: &Config, stdin: &mut std::process::ChildStdin) -> Variab
let path = path.unwrap().path();
let path_str = path.to_str().unwrap();
if path_str.ends_with(".cheat")
&& read_file(path_str, &mut variables, stdin, &mut set)
&& read_file(path_str, &mut variables, &mut visited_lines, stdin)
&& !found_something
{
found_something = true;
@ -257,10 +214,9 @@ mod tests {
let mut variables = VariableMap::new();
let mut child = Command::new("cat").stdin(Stdio::piped()).spawn().unwrap();
let child_stdin = child.stdin.as_mut().unwrap();
let mut set: HashSet<u64> = HashSet::new();
read_file(path, &mut variables, child_stdin, &mut set);
let mut result = VariableMap::new();
let suggestion = (
let mut visited_lines: HashSet<u64> = HashSet::new();
read_file(path, &mut variables, &mut visited_lines, child_stdin);
let expected_suggestion = (
r#" echo -e "$(whoami)\nroot" "#.to_string(),
Some(SuggestionOpts {
header_lines: 0,
@ -269,19 +225,7 @@ mod tests {
suggestion_type: SuggestionType::SingleRecommendation,
}),
);
result.insert("ssh", "user", suggestion);
let actual_suggestion = result.get("ssh", "user");
assert_eq!(
Some(&(
r#" echo -e "$(whoami)\nroot" "#.to_string(),
Some(SuggestionOpts {
header_lines: 0,
column: None,
delimiter: None,
suggestion_type: SuggestionType::SingleRecommendation,
}),
)),
actual_suggestion
);
let actual_suggestion = variables.get("ssh", "user");
assert_eq!(Some(&expected_suggestion), actual_suggestion);
}
}

46
src/structures/cheat.rs Normal file
View file

@ -0,0 +1,46 @@
use crate::structures::fnv::HashLine;
use std::collections::HashMap;
#[derive(Debug, PartialEq)]
pub struct SuggestionOpts {
pub header_lines: u8,
pub column: Option<u8>,
pub delimiter: Option<String>,
pub suggestion_type: SuggestionType,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum SuggestionType {
/// fzf will not print any suggestions
Disabled,
/// fzf will only select one of the suggestions
SingleSelection,
/// fzf will select multiple suggestions
MultipleSelections,
/// fzf will select one of the suggestions or use the query
SingleRecommendation,
/// initial snippet selection
SnippetSelection,
}
pub type Suggestion = (String, Option<SuggestionOpts>);
fn gen_key(tags: &str, variable: &str) -> u64 {
format!("{};{}", tags, variable).hash_line()
}
pub struct VariableMap(HashMap<u64, Suggestion>);
impl VariableMap {
pub fn new() -> Self {
Self(HashMap::new())
}
pub fn insert(&mut self, tags: &str, variable: &str, value: Suggestion) -> Option<Suggestion> {
self.0.insert(gen_key(tags, variable), value)
}
pub fn get(&self, tags: &str, variable: &str) -> Option<&Suggestion> {
self.0.get(&gen_key(tags, variable))
}
}

33
src/structures/fzf.rs Normal file
View file

@ -0,0 +1,33 @@
use crate::structures::cheat::SuggestionType;
pub struct Opts<'a> {
pub query: Option<String>,
pub filter: Option<String>,
pub prompt: Option<String>,
pub preview: Option<String>,
pub autoselect: bool,
pub overrides: Option<&'a String>, // TODO: remove &'a
pub header_lines: u8,
pub header: Option<String>,
pub suggestion_type: SuggestionType,
pub delimiter: Option<&'a str>,
pub column: Option<u8>,
}
impl Default for Opts<'_> {
fn default() -> Self {
Self {
query: None,
filter: None,
autoselect: true,
preview: None,
overrides: None,
header_lines: 0,
header: None,
prompt: None,
suggestion_type: SuggestionType::SingleSelection,
column: None,
delimiter: None,
}
}
}

4
src/structures/mod.rs Normal file
View file

@ -0,0 +1,4 @@
pub mod cheat;
pub mod fnv;
pub mod fzf;
pub mod option;