Skip to content

Commit

Permalink
Forward many more parameters to fzf after --- (#294)
Browse files Browse the repository at this point in the history
  • Loading branch information
denisidoro authored Mar 20, 2020
1 parent 64045e3 commit 10f0219
Show file tree
Hide file tree
Showing 10 changed files with 105 additions and 95 deletions.
13 changes: 12 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "navi"
version = "2.2.0"
version = "2.3.0"
authors = ["Denis Isidoro <[email protected]>"]
edition = "2018"
description = "An interactive cheatsheet tool for the command-line"
Expand All @@ -23,6 +23,7 @@ lazy_static = "1.4.0"
dirs = "2.0.0"
terminal_size = "0.1.10"
walkdir = "2"
shellwords = "1.0.0"

[dependencies.git2]
version = "0.10.0"
Expand Down
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,15 @@ $ 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 + forwarded option to `fzf`;
- `--multi`: forwarded option to `fzf`;
- `--header-lines <number>`: forwarded option to `fzf`;

In addition, it's possible to forward the following parameters to `fzf`:
- `--header-lines <number>`;
- `--delimiter <regex>`;
- `--query <text>`;
- `--filter <text>`;
- `--header <text>`;
- `--preview <code>`;
- `--preview-window <text>`.

### Variable dependency

Expand Down
24 changes: 9 additions & 15 deletions src/flows/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use crate::flows;
use crate::fzf;
use crate::handler;
use crate::parser;
use crate::structures::cheat::{Suggestion, SuggestionType, VariableMap};
use crate::structures::fzf::Opts as FzfOpts;
use crate::structures::cheat::{Suggestion, VariableMap};
use crate::structures::fzf::{Opts as FzfOpts, SuggestionType};
use crate::structures::option;
use crate::structures::option::Config;
use regex::Regex;
Expand Down Expand Up @@ -73,7 +73,7 @@ fn prompt_with_suggestions(
for (key, value) in values.iter() {
vars_cmd.push_str(format!("{}=\"{}\"; ", key, value).as_str());
}
let (suggestion_command, suggestion_options) = &suggestion;
let (suggestion_command, suggestion_opts) = suggestion;
let command = format!("{} {}", vars_cmd, suggestion_command);

let child = Command::new("bash")
Expand All @@ -85,18 +85,12 @@ fn prompt_with_suggestions(

let suggestions = String::from_utf8(child.wait_with_output().unwrap().stdout).unwrap();

let mut opts = FzfOpts {
let opts = suggestion_opts.clone().unwrap_or_default();
let opts = FzfOpts {
autoselect: !config.no_autoselect,
overrides: config.fzf_overrides_var.clone(),
prompt: Some(display::variable_prompt(varname)),
..Default::default()
};

if let Some(o) = &suggestion_options {
opts.suggestion_type = o.suggestion_type;
opts.header_lines = o.header_lines;
opts.column = o.column;
opts.delimiter = o.delimiter.clone();
..opts
};

let (output, _) = fzf::call(opts, |stdin| {
Expand Down Expand Up @@ -162,9 +156,9 @@ fn with_new_lines(txt: String) -> String {
pub fn main(variant: Variant, config: Config, contains_key: bool) -> Result<(), Box<dyn Error>> {
let _ = display::WIDTHS;

let (raw_selection, variables) = fzf::call(gen_core_fzf_opts(variant, &config), |stdin| {
Some(parser::read_all(&config, stdin))
});
let opts = gen_core_fzf_opts(variant, &config);
let (raw_selection, variables) =
fzf::call(opts, |stdin| Some(parser::read_all(&config, stdin)));

let (key, tags, snippet) = extract_from_selections(&raw_selection[..], contains_key);

Expand Down
6 changes: 2 additions & 4 deletions src/flows/repo.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use crate::filesystem;
use crate::fzf;
use crate::git;
use crate::structures::cheat::SuggestionType;
use crate::structures::fzf::Opts as FzfOpts;
use crate::structures::fzf::{Opts as FzfOpts, SuggestionType};
use git2::Repository;
use std::error::Error;
use std::fs;
Expand Down Expand Up @@ -66,14 +65,13 @@ pub fn add(uri: String) -> Result<(), Box<dyn Error>> {
.collect::<Vec<String>>()
.join("\n");

let overrides = "--preview-window right:30%".to_string();
let opts = FzfOpts {
suggestion_type: SuggestionType::MultipleSelections,
preview: Some(format!("cat '{}/{{}}'", tmp_path_str)),
header: Some(
"Select the cheatsheets you want to import with <TAB> then hit <Enter>".to_string(),
),
overrides: Some(overrides),
preview_window: Some("--preview-window right:30%".to_string()),
..Default::default()
};

Expand Down
27 changes: 15 additions & 12 deletions src/fzf.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::display;
use crate::structures::cheat::{SuggestionType, VariableMap};
use crate::structures::fzf::Opts;
use crate::structures::cheat::VariableMap;
use crate::structures::fzf::{Opts, SuggestionType};
use std::process;
use std::process::{Command, Stdio};

Expand Down Expand Up @@ -86,6 +86,10 @@ where
fzf_command.args(&["--prompt", &p]);
}

if let Some(pw) = opts.preview_window {
fzf_command.args(&["--preview-window", &pw]);
}

if opts.header_lines > 0 {
fzf_command.args(&["--header-lines", format!("{}", opts.header_lines).as_str()]);
}
Expand Down Expand Up @@ -114,12 +118,12 @@ where
};

let stdin = child.stdin.as_mut().unwrap();
let result = stdin_fn(stdin);
let result_map = stdin_fn(stdin);

let out = child.wait_with_output().unwrap();

let text = match out.status.code() {
Some(0) | Some(1) => String::from_utf8(out.stdout).unwrap(),
Some(0) | Some(1) | Some(2) => String::from_utf8(out.stdout).unwrap(),
Some(130) => process::exit(130),
_ => {
let err = String::from_utf8(out.stderr)
Expand All @@ -128,14 +132,13 @@ where
}
};

(
get_column(
parse_output_single(text, opts.suggestion_type),
opts.column,
opts.delimiter.as_deref(),
),
result,
)
let out = get_column(
parse_output_single(text, opts.suggestion_type),
opts.column,
opts.delimiter.as_deref(),
);

(out, result_map)
}

fn parse_output_single(mut text: String, suggestion_type: SuggestionType) -> String {
Expand Down
63 changes: 31 additions & 32 deletions src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,55 +1,52 @@
use crate::display;
use crate::filesystem;
use crate::structures::cheat::{SuggestionOpts, SuggestionType, VariableMap};
use crate::structures::cheat::VariableMap;
use crate::structures::fnv::HashLine;
use crate::structures::fzf::{Opts as FzfOpts, SuggestionType};
use crate::structures::option::Config;
use crate::welcome;
use regex::Regex;
use std::collections::HashSet;
use std::fs;
use std::io::Write;

fn remove_quotes(txt: &str) -> String {
txt.replace('"', "").replace('\'', "")
}

fn parse_opts(text: &str) -> SuggestionOpts {
let mut header_lines: u8 = 0;
let mut column: Option<u8> = None;
fn parse_opts(text: &str) -> FzfOpts {
let mut multi = false;
let mut prevent_extra = false;
let mut delimiter: Option<String> = None;

let mut parts = text.split(' ');
let mut opts = FzfOpts::default();
let parts_vec = shellwords::split(text).unwrap();
let mut parts = parts_vec.into_iter();

while let Some(p) = parts.next() {
match p {
match p.as_str() {
"--multi" => multi = true,
"--prevent-extra" => prevent_extra = true,
"--header" | "--headers" | "--header-lines" => {
header_lines = remove_quotes(parts.next().unwrap()).parse::<u8>().unwrap()
}
"--column" => {
column = Some(remove_quotes(parts.next().unwrap()).parse::<u8>().unwrap())
"--headers" | "--header-lines" => {
opts.header_lines = parts.next().unwrap().parse::<u8>().unwrap()
}
"--delimiter" => delimiter = Some(remove_quotes(parts.next().unwrap()).to_string()),
"--column" => opts.column = Some(parts.next().unwrap().parse::<u8>().unwrap()),
"--delimiter" => opts.delimiter = Some(parts.next().unwrap().to_string()),
"--query" => opts.query = Some(parts.next().unwrap().to_string()),
"--filter" => opts.filter = Some(parts.next().unwrap().to_string()),
"--preview" => opts.preview = Some(parts.next().unwrap().to_string()),
"--preview-window" => opts.preview_window = Some(parts.next().unwrap().to_string()),
"--header" => opts.header = Some(parts.next().unwrap().to_string()),
"--overrides" => opts.overrides = Some(parts.next().unwrap().to_string()),
_ => (),
}
}

SuggestionOpts {
header_lines,
column,
delimiter,
suggestion_type: match (multi, prevent_extra) {
(true, _) => SuggestionType::MultipleSelections, // multi wins over allow-extra
(false, false) => SuggestionType::SingleRecommendation,
(false, true) => SuggestionType::SingleSelection,
},
}
let suggestion_type = match (multi, prevent_extra) {
(true, _) => SuggestionType::MultipleSelections, // multi wins over allow-extra
(false, false) => SuggestionType::SingleRecommendation,
(false, true) => SuggestionType::SingleSelection,
};
opts.suggestion_type = suggestion_type;

opts
}

fn parse_variable_line(line: &str) -> (&str, &str, Option<SuggestionOpts>) {
fn parse_variable_line(line: &str) -> (&str, &str, Option<FzfOpts>) {
let re = Regex::new(r"^\$\s*([^:]+):(.*)").unwrap();
let caps = re.captures(line).unwrap();
let variable = caps.get(1).unwrap().as_str().trim();
Expand Down Expand Up @@ -200,11 +197,12 @@ mod tests {
assert_eq!(variable, "user");
assert_eq!(
command_options,
Some(SuggestionOpts {
Some(FzfOpts {
header_lines: 0,
column: None,
delimiter: None,
suggestion_type: SuggestionType::SingleRecommendation
suggestion_type: SuggestionType::SingleRecommendation,
..Default::default()
})
);
}
Expand All @@ -220,11 +218,12 @@ mod tests {
read_file(path, &mut variables, &mut visited_lines, child_stdin);
let expected_suggestion = (
r#" echo -e "$(whoami)\nroot" "#.to_string(),
Some(SuggestionOpts {
Some(FzfOpts {
header_lines: 0,
column: None,
delimiter: None,
suggestion_type: SuggestionType::SingleRecommendation,
..Default::default()
}),
);
let actual_suggestion = variables.get("ssh", "user");
Expand Down
25 changes: 2 additions & 23 deletions src/structures/cheat.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,8 @@
use crate::structures::fnv::HashLine;
use crate::structures::fzf::Opts;
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>);
pub type Suggestion = (String, Option<Opts>);

fn gen_key(tags: &str, variable: &str) -> u64 {
format!("{};{}", tags, variable).hash_line()
Expand Down
19 changes: 17 additions & 2 deletions src/structures/fzf.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::structures::cheat::SuggestionType;

#[derive(Debug, PartialEq, Clone)]
pub struct Opts {
pub query: Option<String>,
pub filter: Option<String>,
pub prompt: Option<String>,
pub preview: Option<String>,
pub preview_window: Option<String>,
pub autoselect: bool,
pub overrides: Option<String>,
pub header_lines: u8,
Expand All @@ -21,6 +21,7 @@ impl Default for Opts {
filter: None,
autoselect: true,
preview: None,
preview_window: None,
overrides: None,
header_lines: 0,
header: None,
Expand All @@ -31,3 +32,17 @@ impl Default for Opts {
}
}
}

#[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,
}
Loading

0 comments on commit 10f0219

Please sign in to comment.