diff options
-rw-r--r-- | README.md | 22 | ||||
-rw-r--r-- | demo/gpg-tui-selection_mode.gif | bin | 0 -> 459273 bytes | |||
-rw-r--r-- | man/gpg-tui.1 | 3 | ||||
-rw-r--r-- | src/app/handler.rs | 4 | ||||
-rw-r--r-- | src/app/launcher.rs | 23 | ||||
-rw-r--r-- | src/app/prompt.rs | 2 | ||||
-rw-r--r-- | src/app/selection.rs | 2 | ||||
-rw-r--r-- | src/app/state.rs | 10 | ||||
-rw-r--r-- | src/args.rs | 9 | ||||
-rw-r--r-- | src/main.rs | 9 |
10 files changed, 75 insertions, 9 deletions
@@ -62,6 +62,7 @@ It aims to ease the key management operations such as listing/exporting/signing - [Scrolling](#scrolling) - [Options Menu](#options-menu) - [Copy / Paste](#copy--paste) + - [Selection Mode](#selection-mode) - [Detailed View](#detailed-view) - [Search](#search) - [Running commands](#running-commands) @@ -289,6 +290,8 @@ OPTIONS: -c, --color <color> Sets the accent color of the terminal [env: COLOR=] [default: gray] -s, --style <style> Sets the style of the terminal [env: STYLE=] [default: plain] [possible values: plain, colored] + --select <option> Enables the selection mode [env: SELECT=] + [possible values: key_id, key_fpr, user_id, row1, row2] ``` ## Key Bindings @@ -504,6 +507,25 @@ Instead of copying values with `copy` mode, you can use the `visual` mode which ![](demo/gpg-tui-visual_mode.gif) +#### Selection Mode + +In the selection mode, key bindings that are responsible for showing the options menu (e.g. `enter`) are used for exiting the user interface and printing out the selection to the standard output. This is useful when you want to use **gpg-tui** in conjunction with shell commands/other tools. + +For switching to the selection mode, use the `--select` argument as follows: + +```sh +gpg-tui --select <option> +``` + +`<option>` might be one of the following: + +- `key_id`: Key ID +- `key_fpr`: Key fingerprint +- `user_id`: User ID +- `row<n>`: Contents of the nth row + +![](demo/gpg-tui-selection_mode.gif) + #### Detailed View Press `Tab` to toggle the [detail level](#detail-levels) for the selected entry in the list. Number keys (e.g. `1`, `2`, `3`) can be also used to set a specific level. diff --git a/demo/gpg-tui-selection_mode.gif b/demo/gpg-tui-selection_mode.gif Binary files differnew file mode 100644 index 0000000..7dd092f --- /dev/null +++ b/demo/gpg-tui-selection_mode.gif diff --git a/man/gpg-tui.1 b/man/gpg-tui.1 index 03759b3..0d9046d 100644 --- a/man/gpg-tui.1 +++ b/man/gpg-tui.1 @@ -52,6 +52,9 @@ Sets the accent color of the terminal [env: COLOR=] [default: gray] .TP \fB\-s\fR, \fB\-\-style\fR <style> Sets the style of the terminal [env: STYLE=] [default: plain] [possible values: plain, colored] +.TP +\fB\-\-select\fR <option> +Enables the selection mode [env: SELECT=] [possible values: key_id, key_fpr, user_id, row1, row2] .SH KEY BINDINGS .SS USER INTERFACE diff --git a/src/app/handler.rs b/src/app/handler.rs index fa1cc18..7ad53c2 100644 --- a/src/app/handler.rs +++ b/src/app/handler.rs @@ -310,7 +310,9 @@ fn handle_key_event(key_event: KeyEvent, app: &mut App) -> Command { } } Key::Char('o') | Key::Char(' ') | Key::Enter => { - if app.state.show_options { + if let Some(select_type) = app.state.select { + Command::Copy(select_type) + } else if app.state.show_options { app.options.selected().cloned().unwrap_or(Command::None) } else if !app.keys_table.items.is_empty() { Command::ShowOptions diff --git a/src/app/launcher.rs b/src/app/launcher.rs index 7212ff9..e3b897d 100644 --- a/src/app/launcher.rs +++ b/src/app/launcher.rs @@ -22,6 +22,7 @@ use std::path::Path; use std::process::Command as OsCommand; use std::str; use std::str::FromStr; +use std::time::Instant; use tui::style::Color; /// Max duration of prompt messages. @@ -71,10 +72,20 @@ impl<'a> App<'a> { .expect("failed to get public keys") .to_vec(), ); + let state = State::from(args); Ok(Self { - state: State::from(args), mode: Mode::Normal, - prompt: Prompt::default(), + prompt: if state.select.is_some() { + Prompt { + output_type: OutputType::Action, + text: String::from("-- select --"), + clock: Some(Instant::now()), + ..Prompt::default() + } + } else { + Prompt::default() + }, + state, tab: Tab::Keys(KeyType::Public), options: StatefulList::with_items(Vec::new()), splash_screen: SplashScreen::new("splash.jpg", 12)?, @@ -825,7 +836,11 @@ impl<'a> App<'a> { }; match content { Ok(content) => { - if let Some(clipboard) = self.clipboard.as_mut() { + if self.state.select.is_some() { + self.state.exit_message = Some(content); + self.run_command(Command::Quit)?; + } else if let Some(clipboard) = self.clipboard.as_mut() + { clipboard .set_contents(content) .expect("failed to set clipboard contents"); @@ -843,7 +858,7 @@ impl<'a> App<'a> { Err(e) => { self.prompt.set_output(( OutputType::Failure, - format!("copy error: {}", e), + format!("selection error: {}", e), )); } } diff --git a/src/app/prompt.rs b/src/app/prompt.rs index d821f6c..45470ee 100644 --- a/src/app/prompt.rs +++ b/src/app/prompt.rs @@ -75,7 +75,7 @@ pub struct Prompt { /// Command history. pub history: Vec<String>, /// Index of the selected command from history. - history_index: usize, + pub history_index: usize, } impl Prompt { diff --git a/src/app/selection.rs b/src/app/selection.rs index bfb2c8b..c35f714 100644 --- a/src/app/selection.rs +++ b/src/app/selection.rs @@ -43,7 +43,7 @@ impl FromStr for Selection { "key_fingerprint" | "key_fpr" | "fingerprint" | "fpr" => { Ok(Self::KeyFingerprint) } - "key_user_id" | "user" => Ok(Self::KeyUserId), + "key_user_id" | "user" | "user_id" => Ok(Self::KeyUserId), _ => Err(String::from("could not parse the type")), } } diff --git a/src/app/state.rs b/src/app/state.rs index 8cb4276..bc0444d 100644 --- a/src/app/state.rs +++ b/src/app/state.rs @@ -1,3 +1,4 @@ +use crate::app::selection::Selection; use crate::args::Args; use crate::widget::style::Color; use tui::style::Color as TuiColor; @@ -15,6 +16,10 @@ pub struct State { pub show_options: bool, /// Is the splash screen showing? pub show_splash: bool, + /// Is the selection mode enabled? + pub select: Option<Selection>, + /// Exit message of the app. + pub exit_message: Option<String>, } impl Default for State { @@ -25,6 +30,8 @@ impl Default for State { color: Color::default().get(), show_options: false, show_splash: false, + select: None, + exit_message: None, } } } @@ -35,6 +42,7 @@ impl<'a> From<&'a Args> for State { colored: args.style == *"colored", color: args.color.get(), show_splash: args.splash, + select: args.select, ..Self::default() } } @@ -62,5 +70,7 @@ mod tests { assert_eq!(TuiColor::Gray, state.color); assert_eq!(false, state.show_options); assert_eq!(false, state.show_splash); + assert_eq!(None, state.select); + assert_eq!(None, state.exit_message); } } diff --git a/src/args.rs b/src/args.rs index a3ae868..0342866 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1,6 +1,7 @@ //! Command-line argument parser. use crate::app::banner::BANNERS; +use crate::app::selection::Selection; use crate::widget::style::Color; use structopt::clap::AppSettings; use structopt::StructOpt; @@ -48,6 +49,14 @@ pub struct Args { default_value = "plain", env )] pub style: String, + /// Enables the selection mode. + #[structopt( + long, + value_name = "option", + possible_values = &["key_id", "key_fpr", "user_id", "row1", "row2"], + env + )] + pub select: Option<Selection>, } impl Args { diff --git a/src/main.rs b/src/main.rs index a6c1f5e..effc241 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,6 +39,11 @@ fn main() -> Result<()> { _ => {} } } - // Exit. - tui.exit() + // Exit the user interface. + tui.exit()?; + // Print the exit message if any. + if let Some(message) = app.state.exit_message { + println!("{}", message); + } + Ok(()) } |