diff options
| author | Ellie Huxtable <ellie@atuin.sh> | 2026-01-26 11:16:42 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-26 11:16:42 -0800 |
| commit | d4dc1ab3d4e5746066173ae3b66931d7605fde79 (patch) | |
| tree | 61341e481869da3fcf1397fc91823a1d66f3c8e5 /crates | |
| parent | feat: add more vim movement bindings for navigation (#3041) (diff) | |
| parent | fix(ui): align cursor with the expand column (usually the command) (diff) | |
| download | atuin-d4dc1ab3d4e5746066173ae3b66931d7605fde79.zip | |
Align cursor with the expand column (usually the command) (#3095)
<!-- Thank you for making a PR! Bug fixes are always welcome, but if
you're adding a new feature or changing an existing one, we'd really
appreciate if you open an issue, post on the forum, or drop in on
Discord -->
## Checks
- [x] I am happy for maintainers to push small adjustments to this PR,
to speed up the review cycle
- [x] I have checked that there are no existing pull requests for the
same thing
This pr improves the following:
<img width="842" height="444" alt="before"
src="https://github.com/user-attachments/assets/aa6414f6-5d24-4053-97d2-093e2bc1bbe3"
/>
<img width="1512" height="440" alt="before2"
src="https://github.com/user-attachments/assets/cdc14909-02a3-4484-8306-0bca5648406d"
/>
into:
<img width="1034" height="444" alt="after"
src="https://github.com/user-attachments/assets/fbcd7bcd-dc03-448a-93b5-0537faaa490e"
/>
<img width="1160" height="436" alt="after2"
src="https://github.com/user-attachments/assets/728c125f-6c0a-4b67-ab25-e1b58430f195"
/>
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/atuin-client/src/settings.rs | 2 | ||||
| -rw-r--r-- | crates/atuin/src/command/client/search/history_list.rs | 10 | ||||
| -rw-r--r-- | crates/atuin/src/command/client/search/interactive.rs | 33 |
3 files changed, 29 insertions, 16 deletions
diff --git a/crates/atuin-client/src/settings.rs b/crates/atuin-client/src/settings.rs index bfe9278d..916172ba 100644 --- a/crates/atuin-client/src/settings.rs +++ b/crates/atuin-client/src/settings.rs @@ -479,7 +479,7 @@ impl UiColumnType { pub fn default_width(&self) -> u16 { match self { UiColumnType::Duration => 5, - UiColumnType::Time => 8, // "59m ago" with padding + UiColumnType::Time => 9, // "459ms ago" with padding UiColumnType::Datetime => 16, // "2025-01-22 14:35" UiColumnType::Directory => 20, UiColumnType::Host => 15, diff --git a/crates/atuin/src/command/client/search/history_list.rs b/crates/atuin/src/command/client/search/history_list.rs index b1bf8176..565a7972 100644 --- a/crates/atuin/src/command/client/search/history_list.rs +++ b/crates/atuin/src/command/client/search/history_list.rs @@ -178,10 +178,6 @@ struct DrawState<'a> { columns: &'a [UiColumn], } -// Default prefix length for backwards compatibility (used by interactive.rs) -#[allow(clippy::cast_possible_truncation)] // we know that this is <65536 length -pub const PREFIX_LENGTH: u16 = " > 123ms 59s ago".len() as u16; - // these encode the slices of `" > "`, `" {n} "`, or `" "` in a compact form. // Yes, this is a hack, but it makes me feel happy static SLICES: &str = " > 1 2 3 4 5 6 7 8 9 "; @@ -302,7 +298,9 @@ impl DrawState<'_> { let mut pos = 0; for section in h.command.escape_control().split_ascii_whitespace() { - self.draw(" ", style.into()); + if pos != 0 { + self.draw(" ", style.into()); + } for ch in section.chars() { if self.x > self.list_area.width { // Avoid attempting to draw a command section beyond the width @@ -362,7 +360,7 @@ impl DrawState<'_> { /// Render the host column (just the hostname) fn host(&mut self, h: &History, width: u16) { let style = self.theme.as_style(Meaning::Annotation); - let w = width as usize; + let w = width as usize - 1; // Database stores hostname as "hostname:username" let host = h.hostname.split(':').next().unwrap_or(&h.hostname); let char_count = host.chars().count(); diff --git a/crates/atuin/src/command/client/search/interactive.rs b/crates/atuin/src/command/client/search/interactive.rs index e28323c8..bda4873d 100644 --- a/crates/atuin/src/command/client/search/interactive.rs +++ b/crates/atuin/src/command/client/search/interactive.rs @@ -13,7 +13,7 @@ use unicode_width::UnicodeWidthStr; use super::{ cursor::Cursor, engines::{SearchEngine, SearchState}, - history_list::{HistoryList, ListState, PREFIX_LENGTH}, + history_list::{HistoryList, ListState}, }; use atuin_client::{ database::{Database, current_context}, @@ -1004,11 +1004,27 @@ impl State { preview_chunk.width.into(), theme, ); - self.draw_preview(f, style, input_chunk, compactness, preview_chunk, preview); + #[allow(clippy::cast_possible_truncation)] + let prefix_width = settings + .ui + .columns + .iter() + .filter_map(|col| if col.expand { None } else { Some(col.width) }) + .sum::<u16>() + + " > ".len() as u16; + self.draw_preview( + f, + style, + input_chunk, + compactness, + preview_chunk, + preview, + prefix_width, + ); } } - #[allow(clippy::cast_possible_truncation)] + #[allow(clippy::cast_possible_truncation, clippy::too_many_arguments)] fn draw_preview( &self, f: &mut Frame, @@ -1017,8 +1033,9 @@ impl State { compactness: Compactness, preview_chunk: Rect, preview: Paragraph, + prefix_width: u16, ) { - let input = self.build_input(style); + let input = self.build_input(style, prefix_width - 2); f.render_widget(input, input_chunk); f.render_widget(preview, preview_chunk); @@ -1031,7 +1048,7 @@ impl State { }; f.set_cursor_position(( // Put cursor past the end of the input text - input_chunk.x + extra_width as u16 + PREFIX_LENGTH + 1 + cursor_offset, + input_chunk.x + extra_width as u16 + prefix_width + 1 + cursor_offset, input_chunk.y + cursor_offset, )); } @@ -1146,15 +1163,13 @@ impl State { } } - fn build_input(&self, style: StyleState) -> Paragraph<'_> { - /// Max width of the UI box showing current mode - const MAX_WIDTH: usize = 14; + fn build_input(&self, style: StyleState, max_width: u16) -> Paragraph<'_> { let (pref, mode) = if self.switched_search_mode { (" SRCH:", self.search_mode.as_str()) } else { ("", self.search.filter_mode.as_str()) }; - let mode_width = MAX_WIDTH - pref.len(); + let mode_width = usize::from(max_width) - pref.len(); // sanity check to ensure we don't exceed the layout limits debug_assert!(mode_width >= mode.len(), "mode name '{mode}' is too long!"); let input = format!("[{pref}{mode:^mode_width$}] {}", self.search.input.as_str(),); |
