summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenis Isidoro <denisidoro@users.noreply.github.com>2020-03-19 22:01:50 -0300
committerGitHub <noreply@github.com>2020-03-19 22:01:50 -0300
commit10f02197921f6ec7c9a5fb324c6421573eef5e95 (patch)
tree0e1797304fe8225d71e6d49ceb7c60b00c2fa637
parent64045e32caff76844f9b78c8433769b470c0e836 (diff)
Forward many more parameters to fzf after `---` (#294)v2.3.0
-rw-r--r--Cargo.lock13
-rw-r--r--Cargo.toml3
-rw-r--r--README.md12
-rw-r--r--src/flows/core.rs24
-rw-r--r--src/flows/repo.rs6
-rw-r--r--src/fzf.rs27
-rw-r--r--src/parser.rs63
-rw-r--r--src/structures/cheat.rs25
-rw-r--r--src/structures/fzf.rs19
-rw-r--r--tests/cheats/more_cases.cheat8
10 files changed, 105 insertions, 95 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 0e1be91..8ce8afa 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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)",
@@ -444,6 +445,15 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -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"
diff --git a/Cargo.toml b/Cargo.toml
index d59fc2d..45595ae 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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"
diff --git a/README.md b/README.md
index 75cd1d1..946d8df 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/src/flows/core.rs b/src/flows/core.rs
index 7bb6eb3..c2814ed 100644
--- a/src/flows/core.rs
+++ b/src/flows/core.rs
@@ -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);
diff --git a/src/flows/repo.rs b/src/flows/repo.rs
index e1aa13f..71eca4f 100644
--- a/src/flows/repo.rs
+++ b/src/flows/repo.rs
@@ -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()
};
diff --git a/src/fzf.rs b/src/fzf.rs
index 70bf2cb..eca0537 100644
--- a/src/fzf.rs
+++ b/src/fzf.rs
@@ -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 {
diff --git a/src/parser.rs b/src/parser.rs
index 30470db..9fdceb9 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -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()
- }
- "--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();
@@ -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");
diff --git a/src/structures/cheat.rs b/src/structures/cheat.rs
index a79f1d6..ef9230a 100644
--- a/src/structures/cheat.rs
+++ b/src/structures/cheat.rs
@@ -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()
diff --git a/src/structures/fzf.rs b/src/structures/fzf.rs
index c24e143..8549233 100644
--- a/src/structures/fzf.rs
+++ b/src/structures/fzf.rs
@@ -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,
+}
diff --git a/tests/cheats/more_cases.cheat b/tests/cheats/more_cases.cheat
index dc3003c..651001a 100644
--- a/tests/cheats/more_cases.cheat
+++ b/tests/cheats/more_cases.cheat
@@ -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 \ No newline at end of file