summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHelmut K. C. Tessarek <tessarek@evermeet.cx>2024-04-18 11:16:54 -0400
committerGitHub <noreply@github.com>2024-04-18 16:16:54 +0100
commit176eae02f7f855ef40a4461caca61d530486113f (patch)
tree14cbe3b9e30d00997036816fbdb5aac2b0e1567c
parent2fba4aae933c17f0024110dd9ec4a57d748cf867 (diff)
feat: show preview auto (#1804)
* feat: show preview auto * refactor: preview_auto
-rw-r--r--atuin-client/config.toml5
-rw-r--r--atuin-client/src/settings.rs2
-rw-r--r--atuin/src/command/client/search/interactive.rs200
3 files changed, 190 insertions, 17 deletions
diff --git a/atuin-client/config.toml b/atuin-client/config.toml
index 254586a5..415fd441 100644
--- a/atuin-client/config.toml
+++ b/atuin-client/config.toml
@@ -73,6 +73,11 @@
## useful when the command is longer than the terminal width and is cut off
# show_preview = false
+## enable or disable automatic preview. It shows a preview, if the command is
+## longer than the width of the terminal. It respects max_preview_height.
+## (default: true)
+# show_preview_auto = true
+
## what to do when the escape key is pressed when searching
## possible values: return-original, return-query
# exit_mode = "return-original"
diff --git a/atuin-client/src/settings.rs b/atuin-client/src/settings.rs
index 035af321..daf8fe34 100644
--- a/atuin-client/src/settings.rs
+++ b/atuin-client/src/settings.rs
@@ -358,6 +358,7 @@ pub struct Settings {
pub inline_height: u16,
pub invert: bool,
pub show_preview: bool,
+ pub show_preview_auto: bool,
pub max_preview_height: u16,
pub show_help: bool,
pub show_tabs: bool,
@@ -615,6 +616,7 @@ impl Settings {
.set_default("style", "auto")?
.set_default("inline_height", 0)?
.set_default("show_preview", false)?
+ .set_default("show_preview_auto", true)?
.set_default("max_preview_height", 4)?
.set_default("show_help", true)?
.set_default("show_tabs", true)?
diff --git a/atuin/src/command/client/search/interactive.rs b/atuin/src/command/client/search/interactive.rs
index d2a314ef..7a3a834b 100644
--- a/atuin/src/command/client/search/interactive.rs
+++ b/atuin/src/command/client/search/interactive.rs
@@ -535,23 +535,28 @@ impl State {
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::bool_to_int_with_if)]
- #[allow(clippy::too_many_lines)]
- fn draw(
- &mut self,
- f: &mut Frame,
- results: &[History],
- stats: Option<HistoryStats>,
+ fn calc_preview_height(
settings: &Settings,
- ) {
- let compact = match settings.style {
- atuin_client::settings::Style::Auto => f.size().height < 14,
- atuin_client::settings::Style::Compact => true,
- atuin_client::settings::Style::Full => false,
- };
- let invert = settings.invert;
- let border_size = if compact { 0 } else { 1 };
- let preview_width = f.size().width - 2;
- let preview_height = if settings.show_preview && self.tab_index == 0 {
+ results: &[History],
+ selected: usize,
+ tab_index: usize,
+ compact: bool,
+ border_size: u16,
+ preview_width: u16,
+ ) -> u16 {
+ if settings.show_preview_auto && tab_index == 0 && !results.is_empty() {
+ let length_current_cmd = results[selected].command.len() as u16;
+ // The '- 19' takes the characters before the command (duration and time) into account
+ if length_current_cmd > preview_width - 19 {
+ std::cmp::min(
+ settings.max_preview_height,
+ (length_current_cmd + preview_width - 1 - border_size)
+ / (preview_width - border_size),
+ ) + border_size * 2
+ } else {
+ 1
+ }
+ } else if settings.show_preview && !settings.show_preview_auto && tab_index == 0 {
let longest_command = results
.iter()
.max_by(|h1, h2| h1.command.len().cmp(&h2.command.len()));
@@ -567,11 +572,40 @@ impl State {
.sum(),
)
}) + border_size * 2
- } else if compact || self.tab_index == 1 {
+ } else if compact || tab_index == 1 {
0
} else {
1
+ }
+ }
+
+ #[allow(clippy::cast_possible_truncation)]
+ #[allow(clippy::bool_to_int_with_if)]
+ #[allow(clippy::too_many_lines)]
+ fn draw(
+ &mut self,
+ f: &mut Frame,
+ results: &[History],
+ stats: Option<HistoryStats>,
+ settings: &Settings,
+ ) {
+ let compact = match settings.style {
+ atuin_client::settings::Style::Auto => f.size().height < 14,
+ atuin_client::settings::Style::Compact => true,
+ atuin_client::settings::Style::Full => false,
};
+ let invert = settings.invert;
+ let border_size = if compact { 0 } else { 1 };
+ let preview_width = f.size().width - 2;
+ let preview_height = Self::calc_preview_height(
+ settings,
+ results,
+ self.results_state.selected(),
+ self.tab_index,
+ compact,
+ border_size,
+ preview_width,
+ );
let show_help = settings.show_help && (!compact || f.size().height > 1);
let show_tabs = settings.show_tabs;
let chunks = Layout::default()
@@ -1141,3 +1175,135 @@ fn set_clipboard(s: String) {
any(target_os = "windows", target_os = "macos", target_os = "linux")
)))]
fn set_clipboard(_s: String) {}
+
+#[cfg(test)]
+mod tests {
+ use atuin_client::history::History;
+ use atuin_client::settings::Settings;
+
+ use super::State;
+
+ #[test]
+ fn calc_preview_height_test() {
+ let settings_preview_auto = Settings {
+ show_preview_auto: true,
+ ..Settings::utc()
+ };
+
+ let settings_preview_auto_h2 = Settings {
+ show_preview_auto: true,
+ max_preview_height: 2,
+ ..Settings::utc()
+ };
+
+ let settings_preview_h4 = Settings {
+ show_preview_auto: false,
+ show_preview: true,
+ max_preview_height: 4,
+ ..Settings::utc()
+ };
+
+ let cmd_60: History = History::capture()
+ .timestamp(time::OffsetDateTime::now_utc())
+ .command("for i in $(seq -w 10); do echo \"item number $i - abcd\"; done")
+ .cwd("/")
+ .build()
+ .into();
+
+ let cmd_124: History = History::capture()
+ .timestamp(time::OffsetDateTime::now_utc())
+ .command("echo 'Aurea prima sata est aetas, quae vindice nullo, sponte sua, sine lege fidem rectumque colebat. Poena metusque aberant'")
+ .cwd("/")
+ .build()
+ .into();
+
+ let cmd_200: History = History::capture()
+ .timestamp(time::OffsetDateTime::now_utc())
+ .command("CREATE USER atuin WITH ENCRYPTED PASSWORD 'supersecretpassword'; CREATE DATABASE atuin WITH OWNER = atuin; \\c atuin; REVOKE ALL PRIVILEGES ON SCHEMA public FROM PUBLIC; echo 'All done. 200 characters'")
+ .cwd("/")
+ .build()
+ .into();
+
+ let results: Vec<History> = vec![cmd_60, cmd_124, cmd_200];
+
+ // the selected command does not require a preview
+ let no_preview = State::calc_preview_height(
+ &settings_preview_auto,
+ &results,
+ 0 as usize,
+ 0 as usize,
+ false,
+ 1,
+ 80,
+ );
+ // the selected command requires 2 lines
+ let preview_h2 = State::calc_preview_height(
+ &settings_preview_auto,
+ &results,
+ 1 as usize,
+ 0 as usize,
+ false,
+ 1,
+ 80,
+ );
+ // the selected command requires 3 lines
+ let preview_h3 = State::calc_preview_height(
+ &settings_preview_auto,
+ &results,
+ 2 as usize,
+ 0 as usize,
+ false,
+ 1,
+ 80,
+ );
+ // the selected command requires a preview of 1 line (happens when the command is between preview_width-19 and preview_width)
+ let preview_one_line = State::calc_preview_height(
+ &settings_preview_auto,
+ &results,
+ 0 as usize,
+ 0 as usize,
+ false,
+ 1,
+ 66,
+ );
+ // the selected command requires 3 lines, but we have a max preview height limit of 2
+ let preview_limit_at_2 = State::calc_preview_height(
+ &settings_preview_auto_h2,
+ &results,
+ 2 as usize,
+ 0 as usize,
+ false,
+ 1,
+ 80,
+ );
+ // the longest command requires 3 lines
+ let preview_static_h3 = State::calc_preview_height(
+ &settings_preview_h4,
+ &results,
+ 1 as usize,
+ 0 as usize,
+ false,
+ 1,
+ 80,
+ );
+ // the longest command requires 10 lines, but we have a max preview height limit of 4
+ let preview_static_limit_at_4 = State::calc_preview_height(
+ &settings_preview_h4,
+ &results,
+ 1 as usize,
+ 0 as usize,
+ false,
+ 1,
+ 20,
+ );
+
+ assert_eq!(no_preview, 1);
+ // 1*2 is the space for the border
+ assert_eq!(preview_h2, 2 + 1 * 2);
+ assert_eq!(preview_h3, 3 + 1 * 2);
+ assert_eq!(preview_one_line, 1 + 1 * 2);
+ assert_eq!(preview_limit_at_2, 2 + 1 * 2);
+ assert_eq!(preview_static_h3, 3 + 1 * 2);
+ assert_eq!(preview_static_limit_at_4, 4 + 1 * 2);
+ }
+}