mirror of
https://github.com/denisidoro/navi
synced 2024-11-10 14:04:17 +00:00
parent
1f5db34902
commit
6678cda032
7 changed files with 104 additions and 87 deletions
|
@ -191,12 +191,17 @@ For lines starting with `$` you can use `---` to customize the behavior of `fzf`
|
||||||
# This will pick the 3rd column and use the first line as header
|
# This will pick the 3rd column and use the first line as header
|
||||||
docker rmi <image_id>
|
docker rmi <image_id>
|
||||||
|
|
||||||
|
# Even though "false/true" is displayed, this will print "0/1"
|
||||||
|
echo <mapped>
|
||||||
|
|
||||||
$ image_id: docker images --- --column 3 --header-lines 1 --delimiter '\s\s+'
|
$ image_id: docker images --- --column 3 --header-lines 1 --delimiter '\s\s+'
|
||||||
|
$ mapped: echo 'false true' | tr ' ' '\n' --- --map "[[ $0 == t* ]] && echo 1 || echo 0"
|
||||||
```
|
```
|
||||||
|
|
||||||
The supported parameters are:
|
The supported parameters are:
|
||||||
- `--prevent-extra` *(experimental)*: limits the user to select one of the suggestions;
|
- `--prevent-extra` *(experimental)*: limits the user to select one of the suggestions;
|
||||||
- `--column <number>`: extracts a single column from the selected result;
|
- `--column <number>`: extracts a single column from the selected result;
|
||||||
|
- `--map <bash_code>` *(experimental)*: applies a map function to the selected variable value;
|
||||||
|
|
||||||
In addition, it's possible to forward the following parameters to `fzf`:
|
In addition, it's possible to forward the following parameters to `fzf`:
|
||||||
- `--multi`;
|
- `--multi`;
|
||||||
|
@ -205,7 +210,7 @@ In addition, it's possible to forward the following parameters to `fzf`:
|
||||||
- `--query <text>`;
|
- `--query <text>`;
|
||||||
- `--filter <text>`;
|
- `--filter <text>`;
|
||||||
- `--header <text>`;
|
- `--header <text>`;
|
||||||
- `--preview <code>`;
|
- `--preview <bash_code>`;
|
||||||
- `--preview-window <text>`.
|
- `--preview-window <text>`.
|
||||||
|
|
||||||
### Variable dependency
|
### Variable dependency
|
||||||
|
|
|
@ -1,23 +1,27 @@
|
||||||
use super::{get_column, parse_output_single, Finder};
|
use super::{parse, Finder};
|
||||||
use crate::display;
|
use crate::display;
|
||||||
use crate::structures::cheat::VariableMap;
|
use crate::structures::cheat::VariableMap;
|
||||||
use crate::structures::finder::{Opts, SuggestionType};
|
use crate::structures::finder::{Opts, SuggestionType};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
use std::process;
|
use std::process::{self, Command, Stdio};
|
||||||
use std::process::{Command, Stdio};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FzfFinder;
|
pub struct FzfFinder;
|
||||||
|
|
||||||
impl Finder for FzfFinder {
|
impl Finder for FzfFinder {
|
||||||
fn call<F>(&self, opts: Opts, stdin_fn: F) -> Result<(String, Option<VariableMap>), Error>
|
fn call<F>(
|
||||||
|
&self,
|
||||||
|
finder_opts: Opts,
|
||||||
|
stdin_fn: F,
|
||||||
|
) -> Result<(String, Option<VariableMap>), Error>
|
||||||
where
|
where
|
||||||
F: Fn(&mut process::ChildStdin) -> Result<Option<VariableMap>, Error>,
|
F: Fn(&mut process::ChildStdin) -> Result<Option<VariableMap>, Error>,
|
||||||
{
|
{
|
||||||
let mut fzf_command = Command::new("fzf");
|
let mut command = Command::new("fzf");
|
||||||
|
let opts = finder_opts.clone();
|
||||||
|
|
||||||
fzf_command.args(&[
|
command.args(&[
|
||||||
"--preview-window",
|
"--preview-window",
|
||||||
"up:2",
|
"up:2",
|
||||||
"--with-nth",
|
"--with-nth",
|
||||||
|
@ -31,51 +35,51 @@ impl Finder for FzfFinder {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if opts.autoselect {
|
if opts.autoselect {
|
||||||
fzf_command.arg("--select-1");
|
command.arg("--select-1");
|
||||||
}
|
}
|
||||||
|
|
||||||
match opts.suggestion_type {
|
match opts.suggestion_type {
|
||||||
SuggestionType::MultipleSelections => {
|
SuggestionType::MultipleSelections => {
|
||||||
fzf_command.arg("--multi");
|
command.arg("--multi");
|
||||||
}
|
}
|
||||||
SuggestionType::Disabled => {
|
SuggestionType::Disabled => {
|
||||||
fzf_command.args(&["--print-query", "--no-select-1", "--height", "1"]);
|
command.args(&["--print-query", "--no-select-1", "--height", "1"]);
|
||||||
}
|
}
|
||||||
SuggestionType::SnippetSelection => {
|
SuggestionType::SnippetSelection => {
|
||||||
fzf_command.args(&["--expect", "ctrl-y,enter"]);
|
command.args(&["--expect", "ctrl-y,enter"]);
|
||||||
}
|
}
|
||||||
SuggestionType::SingleRecommendation => {
|
SuggestionType::SingleRecommendation => {
|
||||||
fzf_command.args(&["--print-query", "--expect", "tab,enter"]);
|
command.args(&["--print-query", "--expect", "tab,enter"]);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(p) = opts.preview {
|
if let Some(p) = opts.preview {
|
||||||
fzf_command.args(&["--preview", &p]);
|
command.args(&["--preview", &p]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(q) = opts.query {
|
if let Some(q) = opts.query {
|
||||||
fzf_command.args(&["--query", &q]);
|
command.args(&["--query", &q]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(f) = opts.filter {
|
if let Some(f) = opts.filter {
|
||||||
fzf_command.args(&["--filter", &f]);
|
command.args(&["--filter", &f]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(h) = opts.header {
|
if let Some(h) = opts.header {
|
||||||
fzf_command.args(&["--header", &h]);
|
command.args(&["--header", &h]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(p) = opts.prompt {
|
if let Some(p) = opts.prompt {
|
||||||
fzf_command.args(&["--prompt", &p]);
|
command.args(&["--prompt", &p]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(pw) = opts.preview_window {
|
if let Some(pw) = opts.preview_window {
|
||||||
fzf_command.args(&["--preview-window", &pw]);
|
command.args(&["--preview-window", &pw]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.header_lines > 0 {
|
if opts.header_lines > 0 {
|
||||||
fzf_command.args(&["--header-lines", format!("{}", opts.header_lines).as_str()]);
|
command.args(&["--header-lines", format!("{}", opts.header_lines).as_str()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(o) = opts.overrides {
|
if let Some(o) = opts.overrides {
|
||||||
|
@ -84,14 +88,11 @@ impl Finder for FzfFinder {
|
||||||
.map(|s| s.to_string())
|
.map(|s| s.to_string())
|
||||||
.filter(|s| !s.is_empty())
|
.filter(|s| !s.is_empty())
|
||||||
.for_each(|s| {
|
.for_each(|s| {
|
||||||
fzf_command.arg(s);
|
command.arg(s);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let child = fzf_command
|
let child = command.stdin(Stdio::piped()).stdout(Stdio::piped()).spawn();
|
||||||
.stdin(Stdio::piped())
|
|
||||||
.stdout(Stdio::piped())
|
|
||||||
.spawn();
|
|
||||||
|
|
||||||
let mut child = match child {
|
let mut child = match child {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
|
@ -109,24 +110,7 @@ impl Finder for FzfFinder {
|
||||||
|
|
||||||
let out = child.wait_with_output().context("Failed to wait for fzf")?;
|
let out = child.wait_with_output().context("Failed to wait for fzf")?;
|
||||||
|
|
||||||
let text = match out.status.code() {
|
let output = parse(out, finder_opts).context("Unable to get output")?;
|
||||||
Some(0) | Some(1) | Some(2) => {
|
Ok((output, result_map))
|
||||||
String::from_utf8(out.stdout).context("Invalid utf8 received from fzf")?
|
|
||||||
}
|
|
||||||
Some(130) => process::exit(130),
|
|
||||||
_ => {
|
|
||||||
let err = String::from_utf8(out.stderr)
|
|
||||||
.unwrap_or_else(|_| "<stderr contains invalid UTF-8>".to_owned());
|
|
||||||
panic!("External command failed:\n {}", err)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let out = get_column(
|
|
||||||
parse_output_single(text, opts.suggestion_type)?,
|
|
||||||
opts.column,
|
|
||||||
opts.delimiter.as_deref(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok((out, result_map))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,8 @@ use crate::structures::finder::Opts;
|
||||||
use crate::structures::finder::SuggestionType;
|
use crate::structures::finder::SuggestionType;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
use std::process;
|
use std::process::{self, Output};
|
||||||
|
use std::process::{Command, Stdio};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum FinderChoice {
|
pub enum FinderChoice {
|
||||||
|
@ -35,6 +36,22 @@ pub trait Finder {
|
||||||
F: Fn(&mut process::ChildStdin) -> Result<Option<VariableMap>, Error>;
|
F: Fn(&mut process::ChildStdin) -> Result<Option<VariableMap>, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn apply_map(text: String, map_fn: Option<String>) -> String {
|
||||||
|
if let Some(m) = map_fn {
|
||||||
|
let output = Command::new("bash")
|
||||||
|
.arg("-c")
|
||||||
|
.arg(m.as_str())
|
||||||
|
.arg(text.as_str())
|
||||||
|
.stderr(Stdio::inherit())
|
||||||
|
.output()
|
||||||
|
.expect("Failed to execute map function");
|
||||||
|
|
||||||
|
String::from_utf8(output.stdout).expect("Invalid utf8 output for map function")
|
||||||
|
} else {
|
||||||
|
text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_column(text: String, column: Option<u8>, delimiter: Option<&str>) -> String {
|
fn get_column(text: String, column: Option<u8>, delimiter: Option<&str>) -> String {
|
||||||
if let Some(c) = column {
|
if let Some(c) = column {
|
||||||
let mut result = String::from("");
|
let mut result = String::from("");
|
||||||
|
@ -96,6 +113,25 @@ fn parse_output_single(mut text: String, suggestion_type: SuggestionType) -> Res
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse(out: Output, opts: Opts) -> Result<String, Error> {
|
||||||
|
let text = match out.status.code() {
|
||||||
|
Some(0) | Some(1) | Some(2) => {
|
||||||
|
String::from_utf8(out.stdout).context("Invalid utf8 received from finder")?
|
||||||
|
}
|
||||||
|
Some(130) => process::exit(130),
|
||||||
|
_ => {
|
||||||
|
let err = String::from_utf8(out.stderr)
|
||||||
|
.unwrap_or_else(|_| "<stderr contains invalid UTF-8>".to_owned());
|
||||||
|
panic!("External command failed:\n {}", err)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let output = parse_output_single(text, opts.suggestion_type)?;
|
||||||
|
let output = get_column(output, opts.column, opts.delimiter.as_deref());
|
||||||
|
let output = apply_map(output, opts.map);
|
||||||
|
Ok(output)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -1,23 +1,27 @@
|
||||||
use super::{get_column, parse_output_single, Finder};
|
use super::{parse, Finder};
|
||||||
use crate::display;
|
use crate::display;
|
||||||
use crate::structures::cheat::VariableMap;
|
use crate::structures::cheat::VariableMap;
|
||||||
use crate::structures::finder::{Opts, SuggestionType};
|
use crate::structures::finder::{Opts, SuggestionType};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
use std::process;
|
use std::process::{self, Command, Stdio};
|
||||||
use std::process::{Command, Stdio};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SkimFinder;
|
pub struct SkimFinder;
|
||||||
|
|
||||||
impl Finder for SkimFinder {
|
impl Finder for SkimFinder {
|
||||||
fn call<F>(&self, opts: Opts, stdin_fn: F) -> Result<(String, Option<VariableMap>), Error>
|
fn call<F>(
|
||||||
|
&self,
|
||||||
|
finder_opts: Opts,
|
||||||
|
stdin_fn: F,
|
||||||
|
) -> Result<(String, Option<VariableMap>), Error>
|
||||||
where
|
where
|
||||||
F: Fn(&mut process::ChildStdin) -> Result<Option<VariableMap>, Error>,
|
F: Fn(&mut process::ChildStdin) -> Result<Option<VariableMap>, Error>,
|
||||||
{
|
{
|
||||||
let mut skim_command = Command::new("sk");
|
let mut command = Command::new("sk");
|
||||||
|
let opts = finder_opts.clone();
|
||||||
|
|
||||||
skim_command.args(&[
|
command.args(&[
|
||||||
"--preview-window",
|
"--preview-window",
|
||||||
"up:3",
|
"up:3",
|
||||||
"--with-nth",
|
"--with-nth",
|
||||||
|
@ -33,51 +37,51 @@ impl Finder for SkimFinder {
|
||||||
if opts.autoselect {
|
if opts.autoselect {
|
||||||
// TODO skim doesn't support this yet
|
// TODO skim doesn't support this yet
|
||||||
// this option does nothing
|
// this option does nothing
|
||||||
skim_command.arg("--select-1");
|
command.arg("--select-1");
|
||||||
}
|
}
|
||||||
|
|
||||||
match opts.suggestion_type {
|
match opts.suggestion_type {
|
||||||
SuggestionType::MultipleSelections => {
|
SuggestionType::MultipleSelections => {
|
||||||
skim_command.arg("--multi");
|
command.arg("--multi");
|
||||||
}
|
}
|
||||||
SuggestionType::Disabled => {
|
SuggestionType::Disabled => {
|
||||||
skim_command.args(&["--print-query", /*"--no-select-1",*/ "--height", "1"]);
|
command.args(&["--print-query", /*"--no-select-1",*/ "--height", "1"]);
|
||||||
}
|
}
|
||||||
SuggestionType::SnippetSelection => {
|
SuggestionType::SnippetSelection => {
|
||||||
skim_command.args(&["--expect", "ctrl-y,enter"]);
|
command.args(&["--expect", "ctrl-y,enter"]);
|
||||||
}
|
}
|
||||||
SuggestionType::SingleRecommendation => {
|
SuggestionType::SingleRecommendation => {
|
||||||
skim_command.args(&["--print-query", "--expect", "tab,enter"]);
|
command.args(&["--print-query", "--expect", "tab,enter"]);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(p) = opts.preview {
|
if let Some(p) = opts.preview {
|
||||||
skim_command.args(&["--preview", &p]);
|
command.args(&["--preview", &p]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(q) = opts.query {
|
if let Some(q) = opts.query {
|
||||||
skim_command.args(&["--query", &q]);
|
command.args(&["--query", &q]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(f) = opts.filter {
|
if let Some(f) = opts.filter {
|
||||||
skim_command.args(&["--filter", &f]);
|
command.args(&["--filter", &f]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(h) = opts.header {
|
if let Some(h) = opts.header {
|
||||||
skim_command.args(&["--header", &h]);
|
command.args(&["--header", &h]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(p) = opts.prompt {
|
if let Some(p) = opts.prompt {
|
||||||
skim_command.args(&["--prompt", &p]);
|
command.args(&["--prompt", &p]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(pw) = opts.preview_window {
|
if let Some(pw) = opts.preview_window {
|
||||||
skim_command.args(&["--preview-window", &pw]);
|
command.args(&["--preview-window", &pw]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.header_lines > 0 {
|
if opts.header_lines > 0 {
|
||||||
skim_command.args(&["--header-lines", format!("{}", opts.header_lines).as_str()]);
|
command.args(&["--header-lines", format!("{}", opts.header_lines).as_str()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(o) = opts.overrides {
|
if let Some(o) = opts.overrides {
|
||||||
|
@ -86,14 +90,11 @@ impl Finder for SkimFinder {
|
||||||
.map(|s| s.to_string())
|
.map(|s| s.to_string())
|
||||||
.filter(|s| !s.is_empty())
|
.filter(|s| !s.is_empty())
|
||||||
.for_each(|s| {
|
.for_each(|s| {
|
||||||
skim_command.arg(s);
|
command.arg(s);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let child = skim_command
|
let child = command.stdin(Stdio::piped()).stdout(Stdio::piped()).spawn();
|
||||||
.stdin(Stdio::piped())
|
|
||||||
.stdout(Stdio::piped())
|
|
||||||
.spawn();
|
|
||||||
|
|
||||||
let mut child = match child {
|
let mut child = match child {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
|
@ -113,24 +114,7 @@ impl Finder for SkimFinder {
|
||||||
.wait_with_output()
|
.wait_with_output()
|
||||||
.context("Failed to wait for skim")?;
|
.context("Failed to wait for skim")?;
|
||||||
|
|
||||||
let text = match out.status.code() {
|
let output = parse(out, finder_opts).context("Unable to get output")?;
|
||||||
Some(0) | Some(1) | Some(2) => {
|
Ok((output, result_map))
|
||||||
String::from_utf8(out.stdout).context("Invalid utf8 received from skim")?
|
|
||||||
}
|
|
||||||
Some(130) => process::exit(130),
|
|
||||||
_ => {
|
|
||||||
let err = String::from_utf8(out.stderr)
|
|
||||||
.unwrap_or_else(|_| "<stderr contains invalid UTF-8>".to_owned());
|
|
||||||
panic!("External command failed:\n {}", err)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let out = get_column(
|
|
||||||
parse_output_single(text, opts.suggestion_type)?,
|
|
||||||
opts.column,
|
|
||||||
opts.delimiter.as_deref(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok((out, result_map))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ fn parse_opts(text: &str) -> Result<FinderOpts, Error> {
|
||||||
let mut multi = false;
|
let mut multi = false;
|
||||||
let mut prevent_extra = false;
|
let mut prevent_extra = false;
|
||||||
let mut opts = FinderOpts::default();
|
let mut opts = FinderOpts::default();
|
||||||
|
|
||||||
let parts = shellwords::split(text)
|
let parts = shellwords::split(text)
|
||||||
.map_err(|_| anyhow!("Given options are missing a closing quote"))?;
|
.map_err(|_| anyhow!("Given options are missing a closing quote"))?;
|
||||||
|
|
||||||
|
@ -56,6 +57,7 @@ fn parse_opts(text: &str) -> Result<FinderOpts, Error> {
|
||||||
.context("Value for `--column` is invalid u8")?,
|
.context("Value for `--column` is invalid u8")?,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
"--map" => opts.map = Some(value.to_string()),
|
||||||
"--delimiter" => opts.delimiter = Some(value.to_string()),
|
"--delimiter" => opts.delimiter = Some(value.to_string()),
|
||||||
"--query" => opts.query = Some(value.to_string()),
|
"--query" => opts.query = Some(value.to_string()),
|
||||||
"--filter" => opts.filter = Some(value.to_string()),
|
"--filter" => opts.filter = Some(value.to_string()),
|
||||||
|
|
|
@ -12,6 +12,7 @@ pub struct Opts {
|
||||||
pub suggestion_type: SuggestionType,
|
pub suggestion_type: SuggestionType,
|
||||||
pub delimiter: Option<String>,
|
pub delimiter: Option<String>,
|
||||||
pub column: Option<u8>,
|
pub column: Option<u8>,
|
||||||
|
pub map: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Opts {
|
impl Default for Opts {
|
||||||
|
@ -29,6 +30,7 @@ impl Default for Opts {
|
||||||
suggestion_type: SuggestionType::SingleRecommendation,
|
suggestion_type: SuggestionType::SingleRecommendation,
|
||||||
column: None,
|
column: None,
|
||||||
delimiter: None,
|
delimiter: None,
|
||||||
|
map: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,9 @@ echo "<x> <y> <x> <z>"
|
||||||
# with preview
|
# with preview
|
||||||
cat "<file>"
|
cat "<file>"
|
||||||
|
|
||||||
|
# with map
|
||||||
|
echo "<mapped>"
|
||||||
|
|
||||||
# fzf
|
# fzf
|
||||||
ls / | fzf
|
ls / | fzf
|
||||||
|
|
||||||
|
@ -45,7 +48,8 @@ $ 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 ';'
|
$ 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
|
$ multi_col: ls -la | awk '{print $1, $9}' --- --column 2 --delimiter '\s' --multi
|
||||||
$ langs: echo 'clojure rust javascript' | tr ' ' '\n' --- --multi
|
$ langs: echo 'clojure rust javascript' | tr ' ' '\n' --- --multi
|
||||||
$ examples: echo -e 'foo bar\nlorem ipsum\ndolor sit' --- --mult
|
$ mapped: echo 'true false' | tr ' ' '\n' --- --map "[[ $0 == t* ]] && echo 1 || echo 0"
|
||||||
|
$ examples: echo -e 'foo bar\nlorem ipsum\ndolor sit' --- --multi
|
||||||
$ multiword: echo -e 'foo bar\nlorem ipsum\ndolor sit\nbaz'i
|
$ multiword: echo -e 'foo bar\nlorem ipsum\ndolor sit\nbaz'i
|
||||||
$ file: ls . --- --preview 'cat {}' --preview-window '50%'
|
$ file: ls . --- --preview 'cat {}' --preview-window '50%'
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue