Forward many more parameters to fzf after --- (#294)

This commit is contained in:
Denis Isidoro 2020-03-19 22:01:50 -03:00 committed by GitHub
parent 64045e32ca
commit 10f0219792
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 105 additions and 95 deletions

13
Cargo.lock generated
View file

@ -245,13 +245,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "navi"
version = "2.2.0"
version = "2.3.0"
dependencies = [
"dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"git2 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"raw_tty 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"shellwords 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
"terminal_size 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -443,6 +444,15 @@ name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "shellwords"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "smallvec"
version = "1.2.0"
@ -698,6 +708,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum shellwords 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "685f0e9b0efe23d26e60a780d8dcd3ac95e90975814de9bc6f48e5d609b5d0f5"
"checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum structopt 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe43617218c0805c6eb37160119dc3c548110a67786da7218d1c6555212f073"

View file

@ -1,6 +1,6 @@
[package]
name = "navi"
version = "2.2.0"
version = "2.3.0"
authors = ["Denis Isidoro <denis_isidoro@live.com>"]
edition = "2018"
description = "An interactive cheatsheet tool for the command-line"
@ -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"

View file

@ -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

View file

@ -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;
@ -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")
@ -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| {
@ -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);

View file

@ -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;
@ -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()
};

View file

@ -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};
@ -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()]);
}
@ -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)
@ -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 {

View file

@ -1,7 +1,8 @@
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;
@ -9,47 +10,43 @@ 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()
"--headers" | "--header-lines" => {
opts.header_lines = parts.next().unwrap().parse::<u8>().unwrap()
}
"--column" => {
column = Some(remove_quotes(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();
@ -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()
})
);
}
@ -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");

View file

@ -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()

View file

@ -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,
@ -21,6 +21,7 @@ impl Default for Opts {
filter: None,
autoselect: true,
preview: None,
preview_window: None,
overrides: None,
header_lines: 0,
header: None,
@ -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,
}

View file

@ -32,6 +32,9 @@ echo "I like these examples: "$(printf '%s' "<examples>" | sed 's/^..*$/"&"/' |
# multiple replacements -> "foo"
echo "<x> <y> <x> <z>"
# with preview
cat "<file>"
$ x: echo '1 2 3' | tr ' ' '\n'
$ y: echo 'a b c' | tr ' ' '\n'
$ z: echo 'foo bar' | tr ' ' '\n'
@ -39,8 +42,9 @@ $ table_elem: echo -e '0 rust rust-lang.org\n1 clojure clojure.org' ---
$ table_elem2: echo -e '0;rust;rust-lang.org\n1;clojure;clojure.org' --- --column 2 --delimiter ';'
$ multi_col: ls -la | awk '{print $1, $9}' --- --column 2 --delimiter '\s' --multi
$ langs: echo 'clojure rust javascript' | tr ' ' '\n' --- --multi
$ examples: echo -e 'foo bar\nlorem ipsum\ndolor sit' --- --multi
$ multiword: echo -e 'foo bar\nlorem ipsum\ndolor sit\nbaz'
$ examples: echo -e 'foo bar\nlorem ipsum\ndolor sit' --- --mult
$ multiword: echo -e 'foo bar\nlorem ipsum\ndolor sit\nbaz'i
$ file: ls . --- --preview 'cat {}' --preview-window '50%'
# this should be displayed
echo hi