diff --git a/README.md b/README.md
index d7063c0..8478775 100644
--- a/README.md
+++ b/README.md
@@ -33,6 +33,19 @@ These are the list of matched patterns that will be highlighted by default. If
you want to highlight a pattern that is not in this list you can add one or
more with `--regexp` parameter.
+
+## Key shortcuts
+
+While in **[thumbs]** mode, you can use the following shortcuts:
+
+* a-z: copies selected match to the clipboard
+* CTRL + a-z: copies selected match to the clipboard and triggers [@thumbs-ctrl-action](#thumbs-ctrl-action).
+* SHIFT + a-z: copies selected match to the clipboard and triggers [@thumbs-shift-action](#thumbs-shift-action).
+* ALT + a-z: copies selected match to the clipboard and triggers [@thumbs-alt-action](#thumbs-alt-action).
+* CTRL + c: exit **[thumbs]** mode
+* ESC: exit help or **[thumbs]** mode
+* ?: show help.
+
## Demo
[![demo](https://asciinema.org/a/232775.png?ts=1)](https://asciinema.org/a/232775?autoplay=1)
@@ -93,9 +106,13 @@ NOTE: for changes to take effect, you'll need to source again your `.tmux.conf`
* [@thumbs-unique](#thumbs-unique)
* [@thumbs-position](#thumbs-position)
* [@thumbs-regexp-N](#thumbs-regexp-N)
-* [@thumbs-command](#thumbs-command)
-* [@thumbs-upcase-command](#thumbs-upcase-command)
-* [@thumbs-multi-command](#thumbs-multi-command)
+
+* [@thumbs-main-action](#thumbs-main-action)
+* [@thumbs-shift-action](#thumbs-shift-action)
+* [@thumbs-ctrl-action](#thumbs-ctrl-action)
+* [@thumbs-alt-action](#thumbs-alt-action)
+* [@thumbs-multi-action](#thumbs-multi-action)
+
* [@thumbs-bg-color](#thumbs-bg-color)
* [@thumbs-fg-color](#thumbs-fg-color)
* [@thumbs-hint-bg-color](#thumbs-hint-bg-color)
@@ -106,6 +123,9 @@ NOTE: for changes to take effect, you'll need to source again your `.tmux.conf`
* [@thumbs-multi-bg-color](#thumbs-multi-bg-color)
* [@thumbs-contrast](#thumbs-contrast)
* [@thumbs-osc52](#thumbs-osc52)
+* deprecated: [@thumbs-command](#thumbs-command)
+* deprecated: [@thumbs-upcase-command](#thumbs-upcase-command)
+* deprecated: [@thumbs-multi-command](#thumbs-multi-command)
### @thumbs-key
diff --git a/src/main.rs b/src/main.rs
index 49ded04..6261376 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -37,7 +37,7 @@ fn app_args<'a>() -> clap::ArgMatches<'a> {
)
.arg(
Arg::with_name("format")
- .help("Specifies the out format for the picked hint. (%U: Upcase, %H: Hint)")
+ .help("Specifies the out format for the picked hint. (%K: Key, %H: Hint)")
.long("format")
.short("f")
.default_value("%H"),
@@ -198,12 +198,10 @@ fn main() {
if !selected.is_empty() {
let output = selected
.iter()
- .map(|(text, upcase)| {
- let upcase_value = if *upcase { "true" } else { "false" };
-
+ .map(|(text, modkey)| {
let mut output = format.to_string();
- output = str::replace(&output, "%U", upcase_value);
+ output = str::replace(&output, "%K", modkey);
output = str::replace(&output, "%H", text.as_str());
output
})
diff --git a/src/swapper.rs b/src/swapper.rs
index 6cf1e89..7162754 100644
--- a/src/swapper.rs
+++ b/src/swapper.rs
@@ -58,9 +58,11 @@ fn dbg(msg: &str) {
pub struct Swapper<'a> {
executor: Box<&'a mut dyn Executor>,
dir: String,
- command: String,
- upcase_command: String,
- multi_command: String,
+ main_action: String,
+ shift_action: String,
+ ctrl_action: String,
+ alt_action: String,
+ multi_action: String,
osc52: bool,
active_pane_id: Option,
active_pane_height: Option,
@@ -75,9 +77,11 @@ impl<'a> Swapper<'a> {
fn new(
executor: Box<&'a mut dyn Executor>,
dir: String,
- command: String,
- upcase_command: String,
- multi_command: String,
+ main_action: String,
+ shift_action: String,
+ ctrl_action: String,
+ alt_action: String,
+ multi_action: String,
osc52: bool,
) -> Swapper {
let since_the_epoch = SystemTime::now()
@@ -88,9 +92,11 @@ impl<'a> Swapper<'a> {
Swapper {
executor,
dir,
- command,
- upcase_command,
- multi_command,
+ main_action,
+ shift_action,
+ ctrl_action,
+ alt_action,
+ multi_action,
osc52,
active_pane_id: None,
active_pane_height: None,
@@ -215,7 +221,7 @@ impl<'a> Swapper<'a> {
};
let pane_command = format!(
- "tmux capture-pane -t {active_pane_id} -p{scroll_params} | tail -n {height} | {dir}/target/release/thumbs -f '%U:%H' -t {tmp} {args}; tmux swap-pane -t {active_pane_id}; {zoom_command} tmux wait-for -S {signal}",
+ "tmux capture-pane -t {active_pane_id} -p{scroll_params} | tail -n {height} | {dir}/target/release/thumbs -f '%K:%H' -t {tmp} {args}; tmux swap-pane -t {active_pane_id}; {zoom_command} tmux wait-for -S {signal}",
active_pane_id = active_pane_id,
scroll_params = scroll_params,
height = self.active_pane_height.unwrap_or(i32::MAX),
@@ -320,7 +326,7 @@ impl<'a> Swapper<'a> {
.collect::>()
.join(" ");
- self.execute_final_command(&text, &self.multi_command.clone());
+ self.execute_final_command(&text, "MAIN", &self.multi_action.clone());
return;
}
@@ -330,7 +336,7 @@ impl<'a> Swapper<'a> {
let mut splitter = item.splitn(2, ':');
- if let Some(upcase) = splitter.next() {
+ if let Some(modkey) = splitter.next() {
if let Some(text) = splitter.next() {
if self.osc52 {
let base64_text = base64::encode(text.as_bytes());
@@ -360,10 +366,13 @@ impl<'a> Swapper<'a> {
std::io::stdout().flush().unwrap();
}
- let execute_command = if upcase.trim_end() == "true" {
- self.upcase_command.clone()
- } else {
- self.command.clone()
+ let modkey = modkey.trim_end();
+
+ let execute_command = match modkey {
+ "SHIFT" => self.shift_action.clone(),
+ "CTRL" => self.ctrl_action.clone(),
+ "ALT" => self.alt_action.clone(),
+ _ => self.main_action.clone(),
};
// The command we run has two arguments:
@@ -389,19 +398,20 @@ impl<'a> Swapper<'a> {
// Ideally user commands would just use "${THUMB}" to begin with rather than having any
// sort of ad-hoc string splicing here at all, and then they could specify the quoting they
// want, but that would break backwards compatibility.
- self.execute_final_command(text.trim_end(), &execute_command);
+ self.execute_final_command(text.trim_end(), modkey, &execute_command);
}
}
}
- pub fn execute_final_command(&mut self, text: &str, execute_command: &str) {
+ pub fn execute_final_command(&mut self, text: &str, modkey: &str, execute_command: &str) {
let final_command = str::replace(execute_command, "{}", "${THUMB}");
let retrieve_command = vec![
"bash",
"-c",
- "THUMB=\"$1\"; eval \"$2\"",
+ "THUMB=\"$1\"; MODIFIER=\"$2\"; eval \"$3\"",
"--",
text,
+ modkey,
final_command.as_str(),
];
@@ -450,6 +460,8 @@ mod tests {
"".to_string(),
"".to_string(),
"".to_string(),
+ "".to_string(),
+ "".to_string(),
false,
);
@@ -473,6 +485,8 @@ mod tests {
"".to_string(),
"".to_string(),
"".to_string(),
+ "".to_string(),
+ "".to_string(),
false,
);
@@ -490,15 +504,19 @@ mod tests {
let last_command_outputs = vec!["Blah blah blah, the ignored user script output".to_string()];
let mut executor = TestShell::new(last_command_outputs);
- let user_command = "echo \"{}\"".to_string();
- let upcase_command = "open \"{}\"".to_string();
- let multi_command = "open \"{}\"".to_string();
+ let main_action = "echo \"{}\"".to_string();
+ let shift_action = "open \"{}\"".to_string();
+ let ctrl_action = "echo \"{}\"".to_string();
+ let alt_action = "echo \"{}\"".to_string();
+ let multi_action = "open \"{}\"".to_string();
let mut swapper = Swapper::new(
Box::new(&mut executor),
"".to_string(),
- user_command,
- upcase_command,
- multi_command,
+ main_action,
+ shift_action,
+ ctrl_action,
+ alt_action,
+ multi_action,
false,
);
@@ -539,21 +557,33 @@ fn app_args<'a>() -> clap::ArgMatches<'a> {
.default_value(""),
)
.arg(
- Arg::with_name("command")
+ Arg::with_name("main-action")
.help("Command to execute after choose a hint")
- .long("command")
+ .long("main-action")
.default_value("tmux set-buffer -- \"{}\" && tmux display-message \"Copied {}\""),
)
.arg(
- Arg::with_name("upcase_command")
- .help("Command to execute after choose a hint, in upcase")
- .long("upcase-command")
+ Arg::with_name("shift-action")
+ .help("Command to execute after choose a hint with SHIFT key pressed (Upcase)")
+ .long("shift-action")
.default_value("tmux set-buffer -- \"{}\" && tmux paste-buffer && tmux display-message \"Copied {}\""),
)
.arg(
- Arg::with_name("multi_command")
+ Arg::with_name("ctrl-action")
+ .help("Command to execute after choose a hint with CTRL key pressed")
+ .long("ctrl-action")
+ .default_value("tmux display-message \"No CTRL action configured! Hint: {}\""),
+ )
+ .arg(
+ Arg::with_name("alt-action")
+ .help("Command to execute after choose a hint with ALT key pressed")
+ .long("alt-action")
+ .default_value("tmux display-message \"No ALT action configured! Hint: {}\" && echo \"FOO $MODIFIER ~ $HINT BAR\" > /tmp/tx.txt"),
+ )
+ .arg(
+ Arg::with_name("multi-action")
.help("Command to execute after choose multiple hints")
- .long("multi-command")
+ .long("multi-action")
.default_value("tmux set-buffer -- \"{}\" && tmux paste-buffer && tmux display-message \"Multi copied {}\""),
)
.arg(
@@ -568,9 +598,11 @@ fn app_args<'a>() -> clap::ArgMatches<'a> {
fn main() -> std::io::Result<()> {
let args = app_args();
let dir = args.value_of("dir").unwrap();
- let command = args.value_of("command").unwrap();
- let upcase_command = args.value_of("upcase_command").unwrap();
- let multi_command = args.value_of("multi_command").unwrap();
+ let main_action = args.value_of("main-action").unwrap();
+ let shift_action = args.value_of("shift-action").unwrap();
+ let ctrl_action = args.value_of("ctrl-action").unwrap();
+ let alt_action = args.value_of("alt-action").unwrap();
+ let multi_action = args.value_of("multi-action").unwrap();
let osc52 = args.is_present("osc52");
if dir.is_empty() {
@@ -581,9 +613,11 @@ fn main() -> std::io::Result<()> {
let mut swapper = Swapper::new(
Box::new(&mut executor),
dir.to_string(),
- command.to_string(),
- upcase_command.to_string(),
- multi_command.to_string(),
+ main_action.to_string(),
+ shift_action.to_string(),
+ ctrl_action.to_string(),
+ alt_action.to_string(),
+ multi_action.to_string(),
osc52,
);
diff --git a/src/view.rs b/src/view.rs
index e92cf95..65870cf 100644
--- a/src/view.rs
+++ b/src/view.rs
@@ -1,6 +1,6 @@
use super::*;
-use std::char;
use std::io::{stdout, Read, Write};
+use std::{char, vec};
use termion::async_stdin;
use termion::event::Key;
use termion::input::TermRead;
@@ -25,7 +25,7 @@ pub struct View<'a> {
background_color: Box,
hint_background_color: Box,
hint_foreground_color: Box,
- chosen: Vec<(String, bool)>,
+ chosen: Vec<(String, String)>,
}
enum CaptureEvent {
@@ -196,10 +196,10 @@ impl<'a> View<'a> {
loop {
match stdin.keys().next() {
- Some(key) => {
- match key {
- Ok(key) => {
- match key {
+ Some(original_key) => {
+ match original_key {
+ Ok(original_key) => {
+ match original_key {
Key::Esc => {
if self.multi && !typed_hint.is_empty() {
typed_hint.clear();
@@ -222,11 +222,11 @@ impl<'a> View<'a> {
Key::Backspace => {
typed_hint.pop();
}
- Key::Char(ch) => {
+ Key::Char(ch) | Key::Alt(ch) | Key::Ctrl(ch) => {
match ch {
'\n' => match self.matches.iter().enumerate().find(|&h| h.0 == self.skip) {
Some(hm) => {
- self.chosen.push((hm.1.text.to_string(), false));
+ self.chosen.push((hm.1.text.to_string(), "MAIN".to_string()));
if !self.multi {
return CaptureEvent::Hint;
@@ -251,9 +251,19 @@ impl<'a> View<'a> {
let selection = self.matches.iter().find(|mat| mat.hint == Some(typed_hint.clone()));
+ let modkey = if original_key == Key::Alt(ch) {
+ "ALT".to_string()
+ } else if original_key == Key::Ctrl(ch) {
+ "CTRL".to_string()
+ } else if key != lower_key {
+ "SHIFT".to_string()
+ } else {
+ "MAIN".to_string()
+ };
+
match selection {
Some(mat) => {
- self.chosen.push((mat.text.to_string(), key != lower_key));
+ self.chosen.push((mat.text.to_string(), modkey));
if self.multi {
typed_hint.clear();
@@ -293,7 +303,7 @@ impl<'a> View<'a> {
CaptureEvent::Exit
}
- pub fn present(&mut self) -> Vec<(String, bool)> {
+ pub fn present(&mut self) -> Vec<(String, String)> {
let mut stdin = async_stdin();
let mut stdout = AlternateScreen::from(stdout().into_raw_mode().unwrap());
diff --git a/tmux-thumbs.sh b/tmux-thumbs.sh
index 7e060e8..4978331 100755
--- a/tmux-thumbs.sh
+++ b/tmux-thumbs.sh
@@ -45,9 +45,10 @@ function add-param() {
fi
}
-add-param command string
-add-param upcase-command string
-add-param multi-command string
-add-param osc52 boolean
+add-param main-action string
+add-param shift-action string
+add-param ctrl-action string
+add-param alt-action string
+add-param osc52 boolean
"${TMUX_THUMBS_BINARY}" "${PARAMS[@]}" || true