mirror of
https://github.com/denisidoro/navi
synced 2024-11-10 14:04:17 +00:00
add --allow-extra option
This commit is contained in:
parent
8669ba9829
commit
0a22398a47
4 changed files with 110 additions and 27 deletions
72
src/cheat.rs
72
src/cheat.rs
|
@ -7,6 +7,7 @@ use std::collections::HashMap;
|
|||
use std::fs;
|
||||
use std::io::Write;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct SuggestionOpts {
|
||||
pub header_lines: u8,
|
||||
pub column: Option<u8>,
|
||||
|
@ -14,7 +15,7 @@ pub struct SuggestionOpts {
|
|||
pub suggestion_type : SuggestionType,
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
#[derive(Clone,Copy,Debug,PartialEq)]
|
||||
pub enum SuggestionType {
|
||||
Disabled,
|
||||
SingleSelection,
|
||||
|
@ -41,6 +42,7 @@ fn parse_opts(text: &str) -> SuggestionOpts {
|
|||
let mut header_lines: u8 = 0;
|
||||
let mut column: Option<u8> = None;
|
||||
let mut multi = false;
|
||||
let mut allow_extra = false;
|
||||
let mut delimiter: Option<String> = None;
|
||||
|
||||
let mut parts = text.split(' ');
|
||||
|
@ -48,6 +50,7 @@ fn parse_opts(text: &str) -> SuggestionOpts {
|
|||
while let Some(p) = parts.next() {
|
||||
match p {
|
||||
"--multi" => multi = true,
|
||||
"--allow-extra" => allow_extra = true,
|
||||
"--header" | "--headers" | "--header-lines" => {
|
||||
header_lines = remove_quote(parts.next().unwrap()).parse::<u8>().unwrap()
|
||||
}
|
||||
|
@ -57,12 +60,18 @@ fn parse_opts(text: &str) -> SuggestionOpts {
|
|||
}
|
||||
}
|
||||
|
||||
SuggestionOpts {
|
||||
let result = SuggestionOpts {
|
||||
header_lines,
|
||||
column,
|
||||
delimiter,
|
||||
suggestion_type: if multi { SuggestionType::MultipleSelections } else { SuggestionType::SingleSelection},
|
||||
}
|
||||
suggestion_type: match (multi, allow_extra) {
|
||||
(true,_) => SuggestionType::MultipleSelections , // multi wins over allow-extra
|
||||
(false,true) => SuggestionType::SingleRecommendation,
|
||||
(false,false) => SuggestionType::SingleSelection
|
||||
},
|
||||
};
|
||||
result
|
||||
|
||||
}
|
||||
|
||||
fn parse_variable_line(line: &str) -> (&str, &str, Option<SuggestionOpts>) {
|
||||
|
@ -70,12 +79,10 @@ fn parse_variable_line(line: &str) -> (&str, &str, Option<SuggestionOpts>) {
|
|||
let caps = re.captures(line).unwrap();
|
||||
let variable = caps.get(1).unwrap().as_str().trim();
|
||||
let mut command_plus_opts = caps.get(2).unwrap().as_str().split("---");
|
||||
let command = command_plus_opts.next().unwrap();
|
||||
let opts = match command_plus_opts.next() {
|
||||
Some(o) => Some(parse_opts(o)),
|
||||
None => None,
|
||||
};
|
||||
(variable, command, opts)
|
||||
let command : &str = command_plus_opts.next().unwrap();
|
||||
let command_option_string : Option<&str>= command_plus_opts.next();
|
||||
let command_options = command_option_string.map(parse_opts);
|
||||
(variable, command, command_options)
|
||||
}
|
||||
|
||||
fn read_file(
|
||||
|
@ -106,7 +113,7 @@ fn read_file(
|
|||
}
|
||||
// variable
|
||||
else if line.starts_with('$') {
|
||||
let (variable, command, opts) = parse_variable_line(&line[..]);
|
||||
let (variable, command, opts) = parse_variable_line(&line);
|
||||
variables.insert(
|
||||
format!("{};{}", tags, variable),
|
||||
(String::from(command), opts),
|
||||
|
@ -170,3 +177,46 @@ pub fn read_all(config: &Config, stdin: &mut std::process::ChildStdin) -> HashMa
|
|||
|
||||
variables
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse_variable_line() {
|
||||
let( variable, command, command_options ) = parse_variable_line("$ user : echo -e \"$(whoami)\\nroot\" --- --allow-extra" );
|
||||
assert_eq!(command, " echo -e \"$(whoami)\\nroot\" ");
|
||||
assert_eq!(variable, "user");
|
||||
assert_eq!(command_options, Some(SuggestionOpts{
|
||||
header_lines: 0,
|
||||
column: None,
|
||||
delimiter: None,
|
||||
suggestion_type: SuggestionType::SingleRecommendation
|
||||
}));
|
||||
|
||||
}
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
#[test]
|
||||
fn test_read_file() {
|
||||
|
||||
let path = "tests/cheats/ssh.cheat";
|
||||
let mut variables: HashMap<String, Suggestion> = HashMap::new();
|
||||
let mut child = Command::new("cat")
|
||||
.stdin(Stdio::piped())
|
||||
.spawn().unwrap();
|
||||
let child_stdin = child.stdin.as_mut().unwrap();
|
||||
read_file(
|
||||
path,
|
||||
&mut variables,
|
||||
child_stdin
|
||||
);
|
||||
let mut result : HashMap<String, (String, std::option::Option<_>)> = HashMap::new();
|
||||
result.insert("ssh;user".to_string(),
|
||||
(" echo -e \"$(whoami)\\nroot\" ".to_string(), Some(SuggestionOpts { header_lines: 0, column: None, delimiter: None, suggestion_type: SuggestionType::SingleRecommendation }))
|
||||
);
|
||||
assert_eq!(variables, result);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ fn prompt_with_suggestions(
|
|||
let mut delimiter = r"\s\s+";
|
||||
|
||||
if let Some(o) = &suggestion_options {
|
||||
opts.suggestion_type = if o.suggestion_type == SuggestionType::Disabled { SuggestionType::SingleSelection} else { SuggestionType::SingleSelection};
|
||||
opts.suggestion_type = o.suggestion_type;
|
||||
opts.header_lines = o.header_lines;
|
||||
column = o.column;
|
||||
if let Some(d) = o.delimiter.as_ref() {
|
||||
|
|
57
src/fzf.rs
57
src/fzf.rs
|
@ -16,7 +16,6 @@ pub struct Opts<'a> {
|
|||
pub autoselect: bool,
|
||||
pub overrides: Option<&'a String>, // TODO: remove &'a
|
||||
pub header_lines: u8,
|
||||
pub copyable: bool,
|
||||
pub suggestion_type : SuggestionType,
|
||||
}
|
||||
|
||||
|
@ -31,7 +30,6 @@ impl Default for Opts<'_> {
|
|||
overrides: None,
|
||||
header_lines: 0,
|
||||
prompt: None,
|
||||
copyable: false,
|
||||
suggestion_type: SingleSelection,
|
||||
}
|
||||
}
|
||||
|
@ -68,10 +66,12 @@ where
|
|||
SuggestionType::SnippetSelection =>{
|
||||
fzf_command.args(&["--expect", "ctrl-y,enter"]);
|
||||
}
|
||||
SuggestionType::SingleRecommendation =>{
|
||||
fzf_command.args(&["--print-query", "--expect", "tab,enter"]);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
||||
if opts.preview {
|
||||
fzf_command.args(&[
|
||||
"--preview",
|
||||
|
@ -125,7 +125,7 @@ where
|
|||
|
||||
let out = child.wait_with_output().unwrap();
|
||||
|
||||
let mut text = match out.status.code() {
|
||||
let text = match out.status.code() {
|
||||
Some(0) | Some(1) => String::from_utf8(out.stdout).unwrap(),
|
||||
Some(130) => process::exit(130),
|
||||
_ => {
|
||||
|
@ -153,13 +153,19 @@ fn parse_output_single(mut text: String, suggestion_type: SuggestionType) -> St
|
|||
return text;
|
||||
}
|
||||
SuggestionType::SingleRecommendation => {
|
||||
let lines : Vec<&str>= text.lines().collect();
|
||||
match *(lines.get(1).unwrap()) {
|
||||
input_string if input_string == "enter" =>
|
||||
return lines.get(2).unwrap().to_string(),
|
||||
_ =>
|
||||
return lines.get(0).unwrap().to_string(),
|
||||
}
|
||||
let lines: Vec<&str> = text.lines().collect();
|
||||
|
||||
match (lines.get(0), lines.get(1), lines.get(2)) {
|
||||
(Some(one), Some(termination), Some(two)) if *termination == "enter" =>
|
||||
if two.is_empty() {
|
||||
one.to_string()
|
||||
} else {
|
||||
two.to_string()
|
||||
},
|
||||
(Some(one), Some(termination), None)if *termination == "enter" => one.to_string(),
|
||||
(Some(one), Some(termination), _)if *termination == "tab" => one.to_string(),
|
||||
_ => "".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -170,28 +176,49 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_parse_output1() {
|
||||
let mut text = "palo\n".to_string();
|
||||
let text = "palo\n".to_string();
|
||||
let output = parse_output_single(text, SuggestionType::SingleSelection);
|
||||
assert_eq!(output, "palo");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_output2() {
|
||||
let mut text = "\nenter\npalo".to_string();
|
||||
let text = "\nenter\npalo".to_string();
|
||||
let output = parse_output_single(text, SuggestionType::SingleRecommendation);
|
||||
assert_eq!(output, "palo");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_recommendation_output_1() {
|
||||
let text = "\nenter\npalo".to_string();
|
||||
let output = parse_output_single(text, SuggestionType::SingleRecommendation);
|
||||
assert_eq!(output, "palo");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_recommendation_output_2() {
|
||||
let text = "p\nenter\npalo".to_string();
|
||||
let output = parse_output_single(text, SuggestionType::SingleRecommendation);
|
||||
assert_eq!(output, "palo");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_recommendation_output_3() {
|
||||
let text = "peter\nenter\n".to_string();
|
||||
let output = parse_output_single(text, SuggestionType::SingleRecommendation);
|
||||
assert_eq!(output, "peter");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_output3() {
|
||||
let mut text = "p\ntab\npalo".to_string();
|
||||
let text = "p\ntab\npalo".to_string();
|
||||
let output = parse_output_single(text, SuggestionType::SingleRecommendation);
|
||||
assert_eq!(output, "p");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_snippet_request() {
|
||||
let mut text = "enter\nssh ⠀login to a server and forward to ssh key (d… ⠀ssh -A <user>@<server> ⠀ssh ⠀login to a server and forward to ssh key (dangerous but usefull for bastion hosts) ⠀ssh -A <user>@<server> ⠀\n".to_string();
|
||||
let text = "enter\nssh ⠀login to a server and forward to ssh key (d… ⠀ssh -A <user>@<server> ⠀ssh ⠀login to a server and forward to ssh key (dangerous but usefull for bastion hosts) ⠀ssh -A <user>@<server> ⠀\n".to_string();
|
||||
let output = parse_output_single(text, SuggestionType::SnippetSelection);
|
||||
assert_eq!(output, "enter\nssh ⠀login to a server and forward to ssh key (d… ⠀ssh -A <user>@<server> ⠀ssh ⠀login to a server and forward to ssh key (dangerous but usefull for bastion hosts) ⠀ssh -A <user>@<server> ⠀");
|
||||
}
|
||||
|
|
6
tests/cheats/ssh.cheat
Normal file
6
tests/cheats/ssh.cheat
Normal file
|
@ -0,0 +1,6 @@
|
|||
% ssh
|
||||
|
||||
# login to a server with a key and port
|
||||
ssh -i <sshkey> -p <port> <user>@<server>
|
||||
|
||||
$ user : echo -e "$(whoami)\nroot" --- --allow-extra
|
Loading…
Reference in a new issue