aboutsummaryrefslogtreecommitdiffstats
path: root/crates
diff options
context:
space:
mode:
authorEllie Huxtable <ellie@atuin.sh>2026-01-26 11:16:42 -0800
committerGitHub <noreply@github.com>2026-01-26 11:16:42 -0800
commitd4dc1ab3d4e5746066173ae3b66931d7605fde79 (patch)
tree61341e481869da3fcf1397fc91823a1d66f3c8e5 /crates
parentfeat: add more vim movement bindings for navigation (#3041) (diff)
parentfix(ui): align cursor with the expand column (usually the command) (diff)
downloadatuin-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.rs2
-rw-r--r--crates/atuin/src/command/client/search/history_list.rs10
-rw-r--r--crates/atuin/src/command/client/search/interactive.rs33
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(),);