Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package atuin for openSUSE:Factory checked in at 2026-02-12 17:29:44 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/atuin (Old) and /work/SRC/openSUSE:Factory/.atuin.new.1977 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "atuin" Thu Feb 12 17:29:44 2026 rev:25 rq:1332677 version:18.12.1 Changes: -------- --- /work/SRC/openSUSE:Factory/atuin/atuin.changes 2026-02-10 21:14:32.036871386 +0100 +++ /work/SRC/openSUSE:Factory/.atuin.new.1977/atuin.changes 2026-02-12 17:30:04.614186191 +0100 @@ -1,0 +2,14 @@ +Thu Feb 12 11:13:10 UTC 2026 - Andrei Dziahel <[email protected]> + +- Update to version 18.12.1: + * chore(release): prepare for release 18.12.1 (#3172) + * feat: Add original-input-empty keybind condition (#3171) + * fix(shell): fix ATUIN_SESSION errors in tmux popup (#3170) + * fix: Server start commands for Docker. (#3160) + * feat: expand keybinding system with vim motions, media keys, and inspector improvements (#3161) + * fix(tui): enter in vim normal mode, shift-tab keybind (#3158) + * chore(deps): bump debian from bookworm-20260112-slim to bookworm-20260202-slim (#3150) + * chore(deps): Update to tiny-bip39 2.0.0 (#3151) + * chore: update changelog + +------------------------------------------------------------------- Old: ---- atuin-18.12.0.tar.zst New: ---- atuin-18.12.1.tar.zst ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ atuin.spec ++++++ --- /var/tmp/diff_new_pack.PaNj4x/_old 2026-02-12 17:30:07.738318562 +0100 +++ /var/tmp/diff_new_pack.PaNj4x/_new 2026-02-12 17:30:07.754319240 +0100 @@ -17,7 +17,7 @@ Name: atuin -Version: 18.12.0 +Version: 18.12.1 Release: 0 Summary: Magical shell history License: MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.PaNj4x/_old 2026-02-12 17:30:07.810321613 +0100 +++ /var/tmp/diff_new_pack.PaNj4x/_new 2026-02-12 17:30:07.814321782 +0100 @@ -2,10 +2,10 @@ <service name="cargo_vendor" mode="manual"> <param name="src">https://github.com/atuinsh/atuin</param> <param name="update">true</param> - <param name="revision">v18.11.0</param> + <param name="revision">v18.12.1</param> <param name="versionrewriteregex">^v?(.*)</param> <param name="versionrewritepattern">${1}</param> - <param name="changesgenerate">true</param> + <param name="changesgenerate">false</param> <!-- param name="i-accept-the-risk">RUSTSEC-2023-0071</param --> <!-- param name="i-accept-the-risk">RUSTSEC-2022-0093</param --> <!-- param name="i-accept-the-risk">RUSTSEC-2021-0041</param --> ++++++ atuin-18.12.0.tar.zst -> atuin-18.12.1.tar.zst ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/.codespellrc new/atuin-18.12.1/.codespellrc --- old/atuin-18.12.0/.codespellrc 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/.codespellrc 1970-01-01 01:00:00.000000000 +0100 @@ -3,5 +3,5 @@ skip = .git*,*.lock,.codespellrc,CODE_OF_CONDUCT.md,CONTRIBUTORS check-hidden = true # ignore-regex = -ignore-words-list = crate,ratatui,inbetween +ignore-words-list = crate,ratatui,inbetween,iterm diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/CHANGELOG.md new/atuin-18.12.1/CHANGELOG.md --- old/atuin-18.12.0/CHANGELOG.md 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/CHANGELOG.md 1970-01-01 01:00:00.000000000 +0100 @@ -2,11 +2,12 @@ All notable changes to this project will be documented in this file. -## [unreleased] +## [18.12.0] - 2026-02-09 ### Bug Fixes - *(powershell)* Preserve `$LASTEXITCODE` ([#3120](https://github.com/atuinsh/atuin/issues/3120)) +- *(powershell)* Display search stderr ([#3146](https://github.com/atuinsh/atuin/issues/3146)) - *(search)* Allow hyphen-prefixed query args like `---` ([#3129](https://github.com/atuinsh/atuin/issues/3129)) - *(tui)* Space and F1-F24 keys not handled properly by new keybind system ([#3138](https://github.com/atuinsh/atuin/issues/3138)) - *(ui)* Don't draw a leading space for command @@ -23,6 +24,8 @@ - Halt sync loop if server returns an empty page ([#3122](https://github.com/atuinsh/atuin/issues/3122)) - Use directories crate for home dir resolution ([#3125](https://github.com/atuinsh/atuin/issues/3125)) - Tab behaving like enter, eprintln ([#3135](https://github.com/atuinsh/atuin/issues/3135)) +- Issue with shift and modifier keys ([#3143](https://github.com/atuinsh/atuin/issues/3143)) +- Remove invalid IF EXISTS from sqlite drop column migration ([#3145](https://github.com/atuinsh/atuin/issues/3145)) ### Documentation @@ -42,12 +45,15 @@ - Add PowerShell and Windows install instructions ([#3096](https://github.com/atuinsh/atuin/issues/3096)) - Update the `[keys]` docs ([#3114](https://github.com/atuinsh/atuin/issues/3114)) - Add history deletion guide ([#3130](https://github.com/atuinsh/atuin/issues/3130)) +- Update how to use Docker to self-host ([#3148](https://github.com/atuinsh/atuin/issues/3148)) +- Add IRC contact information to README ### Features - *(dotfiles)* Add sort and filter options to alias/var list ([#3131](https://github.com/atuinsh/atuin/issues/3131)) - *(theme)* Note new default theme name and syntax ([#3080](https://github.com/atuinsh/atuin/issues/3080)) +- *(tui)* Add clear-to-start/end actions ([#3141](https://github.com/atuinsh/atuin/issues/3141)) - *(ui)* Highlight fulltext search as fulltext search instead of fuzzy search - *(ui)* Highlight fulltext search as fulltext search instead of fuzzy search ([#3098](https://github.com/atuinsh/atuin/issues/3098)) - *(ultracompact)* Adds setting for ultracompact mode ([#3079](https://github.com/atuinsh/atuin/issues/3079)) @@ -73,6 +79,7 @@ - Update agents.md ([#3126](https://github.com/atuinsh/atuin/issues/3126)) - Update changelog - Update changelog +- Update changelog ### Theming diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/Cargo.lock new/atuin-18.12.1/Cargo.lock --- old/atuin-18.12.0/Cargo.lock 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/Cargo.lock 1970-01-01 01:00:00.000000000 +0100 @@ -211,7 +211,7 @@ [[package]] name = "atuin" -version = "18.12.0" +version = "18.12.1" dependencies = [ "arboard", "async-trait", @@ -262,7 +262,7 @@ [[package]] name = "atuin-client" -version = "18.12.0" +version = "18.12.1" dependencies = [ "async-trait", "atuin-common", @@ -316,7 +316,7 @@ [[package]] name = "atuin-common" -version = "18.12.0" +version = "18.12.1" dependencies = [ "base64", "directories", @@ -336,7 +336,7 @@ [[package]] name = "atuin-daemon" -version = "18.12.0" +version = "18.12.1" dependencies = [ "atuin-client", "atuin-dotfiles", @@ -363,7 +363,7 @@ [[package]] name = "atuin-dotfiles" -version = "18.12.0" +version = "18.12.1" dependencies = [ "atuin-client", "atuin-common", @@ -377,7 +377,7 @@ [[package]] name = "atuin-history" -version = "18.12.0" +version = "18.12.1" dependencies = [ "atuin-client", "crossterm", @@ -390,7 +390,7 @@ [[package]] name = "atuin-kv" -version = "18.12.0" +version = "18.12.1" dependencies = [ "atuin-client", "atuin-common", @@ -406,7 +406,7 @@ [[package]] name = "atuin-scripts" -version = "18.12.0" +version = "18.12.1" dependencies = [ "atuin-client", "atuin-common", @@ -428,7 +428,7 @@ [[package]] name = "atuin-server" -version = "18.12.0" +version = "18.12.1" dependencies = [ "argon2", "async-trait", @@ -458,7 +458,7 @@ [[package]] name = "atuin-server-database" -version = "18.12.0" +version = "18.12.1" dependencies = [ "async-trait", "atuin-common", @@ -471,7 +471,7 @@ [[package]] name = "atuin-server-postgres" -version = "18.12.0" +version = "18.12.1" dependencies = [ "async-trait", "atuin-common", @@ -489,7 +489,7 @@ [[package]] name = "atuin-server-sqlite" -version = "18.12.0" +version = "18.12.1" dependencies = [ "async-trait", "atuin-common", @@ -2957,11 +2957,12 @@ [[package]] name = "pbkdf2" -version = "0.11.0" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ "digest", + "hmac", ] [[package]] @@ -4803,12 +4804,10 @@ [[package]] name = "tiny-bip39" -version = "1.0.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62cc94d358b5a1e84a5cb9109f559aa3c4d634d2b1b4de3d0fa4adc7c78e2861" +checksum = "a30fd743a02bf35236f6faf99adb03089bb77e91c998dac2c2ad76bb424f668c" dependencies = [ - "anyhow", - "hmac", "once_cell", "pbkdf2", "rand 0.8.5", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/Cargo.toml new/atuin-18.12.1/Cargo.toml --- old/atuin-18.12.0/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 @@ -5,7 +5,7 @@ exclude = ["ui/backend"] [workspace.package] -version = "18.12.0" +version = "18.12.1" authors = ["Ellie Huxtable <[email protected]>"] rust-version = "1.93" license = "MIT" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/Dockerfile new/atuin-18.12.1/Dockerfile --- old/atuin-18.12.0/Dockerfile 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/Dockerfile 1970-01-01 01:00:00.000000000 +0100 @@ -16,7 +16,7 @@ COPY . . RUN cargo build --release --bin atuin-server -FROM debian:bookworm-20260112-slim AS runtime +FROM debian:bookworm-20260202-slim AS runtime RUN useradd -c 'atuin user' atuin && mkdir /config && chown atuin:atuin /config # Install ca-certificates for webhooks to work diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin/Cargo.toml new/atuin-18.12.1/crates/atuin/Cargo.toml --- old/atuin-18.12.0/crates/atuin/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 @@ -41,13 +41,13 @@ check-update = ["atuin-client/check-update"] [dependencies] -atuin-client = { path = "../atuin-client", version = "18.12.0", optional = true, default-features = false } -atuin-common = { path = "../atuin-common", version = "18.12.0" } -atuin-dotfiles = { path = "../atuin-dotfiles", version = "18.12.0" } -atuin-history = { path = "../atuin-history", version = "18.12.0" } -atuin-daemon = { path = "../atuin-daemon", version = "18.12.0", optional = true, default-features = false } -atuin-scripts = { path = "../atuin-scripts", version = "18.12.0" } -atuin-kv = { path = "../atuin-kv", version = "18.12.0" } +atuin-client = { path = "../atuin-client", version = "18.12.1", optional = true, default-features = false } +atuin-common = { path = "../atuin-common", version = "18.12.1" } +atuin-dotfiles = { path = "../atuin-dotfiles", version = "18.12.1" } +atuin-history = { path = "../atuin-history", version = "18.12.1" } +atuin-daemon = { path = "../atuin-daemon", version = "18.12.1", optional = true, default-features = false } +atuin-scripts = { path = "../atuin-scripts", version = "18.12.1" } +atuin-kv = { path = "../atuin-kv", version = "18.12.1" } log = { workspace = true } time = { workspace = true } @@ -69,7 +69,7 @@ semver = { workspace = true } rustix = { workspace = true } runtime-format = "0.1.3" -tiny-bip39 = "1" +tiny-bip39 = "2" futures-util = "0.3" fuzzy-matcher = "0.3.7" colored = "2.0.4" @@ -96,6 +96,6 @@ # Integration tests in tests/ spin up a test server to verify sync functionality. # TODO: Consider moving these tests to atuin-server crate instead (client would become a dev dep there) -atuin-server = { path = "../atuin-server", version = "18.12.0" } -atuin-server-database = { path = "../atuin-server-database", version = "18.12.0" } -atuin-server-postgres = { path = "../atuin-server-postgres", version = "18.12.0" } +atuin-server = { path = "../atuin-server", version = "18.12.1" } +atuin-server-database = { path = "../atuin-server-database", version = "18.12.1" } +atuin-server-postgres = { path = "../atuin-server-postgres", version = "18.12.1" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin/src/command/client/account/login.rs new/atuin-18.12.1/crates/atuin/src/command/client/account/login.rs --- old/atuin-18.12.0/crates/atuin/src/command/client/account/login.rs 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin/src/command/client/account/login.rs 1970-01-01 01:00:00.000000000 +0100 @@ -75,24 +75,16 @@ match bip39::Mnemonic::from_phrase(&key, bip39::Language::English) { Ok(mnemonic) => encode_key(Key::from_slice(mnemonic.entropy()))?, Err(err) => { - match err.downcast_ref::<bip39::ErrorKind>() { - Some(err) => { - match err { - // assume they copied in the base64 key - bip39::ErrorKind::InvalidWord => key, - bip39::ErrorKind::InvalidChecksum => { - bail!("key mnemonic was not valid") - } - bip39::ErrorKind::InvalidKeysize(_) - | bip39::ErrorKind::InvalidWordLength(_) - | bip39::ErrorKind::InvalidEntropyLength(_, _) => { - bail!("key was not the correct length") - } - } + match err { + // assume they copied in the base64 key + bip39::ErrorKind::InvalidWord(_) => key, + bip39::ErrorKind::InvalidChecksum => { + bail!("key mnemonic was not valid") } - _ => { - // unknown error. assume they copied the base64 key - key + bip39::ErrorKind::InvalidKeysize(_) + | bip39::ErrorKind::InvalidWordLength(_) + | bip39::ErrorKind::InvalidEntropyLength(_, _) => { + bail!("key was not the correct length") } } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin/src/command/client/search/cursor.rs new/atuin-18.12.1/crates/atuin/src/command/client/search/cursor.rs --- old/atuin-18.12.0/crates/atuin/src/command/client/search/cursor.rs 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin/src/command/client/search/cursor.rs 1970-01-01 01:00:00.000000000 +0100 @@ -151,6 +151,68 @@ self.index = word_jumper.get_prev_word_pos(&self.source, self.index); } + /// Move cursor to the end of the current/next word (vim `e` motion). + /// + /// If cursor is in the middle of a word, moves to the end of that word. + /// If cursor is at the end of a word (or on whitespace), moves to the + /// end of the next word. + pub fn word_end(&mut self, word_chars: &str) { + let len = self.source.len(); + if self.index >= len { + return; + } + + let chars: Vec<char> = self.source.chars().collect(); + let mut char_idx = self.source[..self.index].chars().count(); + + if char_idx >= chars.len() { + return; + } + + let current = chars[char_idx]; + + // Check if we're at a word boundary (end of current word or on whitespace) + let at_word_boundary = current.is_whitespace() || char_idx + 1 >= chars.len() || { + let next = chars[char_idx + 1]; + next.is_whitespace() || (word_chars.contains(current) != word_chars.contains(next)) + }; + + // If at word boundary, advance past it and skip whitespace to find next word + if at_word_boundary { + char_idx += 1; + while char_idx < chars.len() && chars[char_idx].is_whitespace() { + char_idx += 1; + } + } + + // If we've gone past end, go to end of string + if char_idx >= chars.len() { + self.index = len; + return; + } + + // Find end of word: advance until next char is whitespace or different word type + let in_word_chars = word_chars.contains(chars[char_idx]); + while char_idx < chars.len() { + let next_idx = char_idx + 1; + if next_idx >= chars.len() { + // At last char, move past it + char_idx = next_idx; + break; + } + let next_c = chars[next_idx]; + if next_c.is_whitespace() || (word_chars.contains(next_c) != in_word_chars) { + // Next char is start of new word/whitespace, so current char is end + char_idx = next_idx; + break; + } + char_idx += 1; + } + + // Convert char index back to byte index + self.index = chars.iter().take(char_idx).map(|c| c.len_utf8()).sum(); + } + pub fn insert(&mut self, c: char) { self.source.insert(self.index, c); self.index += c.len_utf8(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin/src/command/client/search/interactive.rs new/atuin-18.12.1/crates/atuin/src/command/client/search/interactive.rs --- old/atuin-18.12.0/crates/atuin/src/command/client/search/interactive.rs 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin/src/command/client/search/interactive.rs 1970-01-01 01:00:00.000000000 +0100 @@ -105,6 +105,7 @@ } #[allow(clippy::struct_field_names)] +#[allow(clippy::struct_excessive_bools)] pub struct State { history_count: i64, update_needed: Option<Version>, @@ -118,6 +119,7 @@ current_cursor: Option<CursorStyle>, tab_index: usize, pending_vim_key: Option<char>, + original_input_empty: bool, pub inspecting_state: InspectingState, @@ -301,6 +303,7 @@ input_byte_len: self.search.input.as_str().len(), selected_index: self.results_state.selected(), results_len: self.results_len, + original_input_empty: self.original_input_empty, }; // Convert KeyEvent to SingleKey @@ -438,6 +441,10 @@ .next_word(&settings.word_chars, settings.word_jump_mode); InputAction::Continue } + Action::CursorWordEnd => { + self.search.input.word_end(&settings.word_chars); + InputAction::Continue + } Action::CursorStart => { self.search.input.start(); InputAction::Continue @@ -690,6 +697,12 @@ self.keymap_mode = KeymapMode::VimInsert; InputAction::Continue } + Action::VimChangeToEnd => { + self.search.input.clear_to_end(); + self.set_keymap_cursor(settings, "vim_insert"); + self.keymap_mode = KeymapMode::VimInsert; + InputAction::Continue + } Action::EnterPrefixMode => { self.prefix = true; InputAction::Continue @@ -1406,6 +1419,7 @@ }, prefix: false, pending_vim_key: None, + original_input_empty: original_query.is_empty(), }; app.initialize_keymap_cursor(settings); @@ -1796,6 +1810,7 @@ current_cursor: None, tab_index: 0, pending_vim_key: None, + original_input_empty: false, inspecting_state: InspectingState { current: None, next: None, @@ -1849,6 +1864,7 @@ current_cursor: None, tab_index: 0, pending_vim_key: None, + original_input_empty: false, inspecting_state: InspectingState { current: None, next: None, @@ -1966,6 +1982,7 @@ current_cursor: None, tab_index: 0, pending_vim_key: None, + original_input_empty: false, inspecting_state: InspectingState { current: None, next: None, @@ -2023,6 +2040,7 @@ current_cursor: None, tab_index: 0, pending_vim_key: None, + original_input_empty: false, inspecting_state: InspectingState { current: None, next: None, @@ -2076,6 +2094,7 @@ current_cursor: None, tab_index: 0, pending_vim_key: None, + original_input_empty: false, inspecting_state: InspectingState { current: None, next: None, @@ -2125,6 +2144,7 @@ current_cursor: None, tab_index: 0, pending_vim_key: None, + original_input_empty: false, inspecting_state: InspectingState { current: None, next: None, @@ -2183,6 +2203,7 @@ current_cursor: None, tab_index: 0, pending_vim_key: None, + original_input_empty: false, inspecting_state: InspectingState { current: None, next: None, @@ -2242,6 +2263,7 @@ current_cursor: None, tab_index: 0, pending_vim_key: None, + original_input_empty: false, inspecting_state: InspectingState { current: None, next: None, @@ -2572,4 +2594,60 @@ state.execute_action(&Action::ClearLine, &settings); assert_eq!(state.search.input.as_str(), ""); } + + #[test] + fn keymap_config_return_query() { + use atuin_client::settings::KeyBindingConfig; + use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; + use std::collections::HashMap; + + let mut settings = Settings::utc(); + // Configure tab to return-query + settings.keymap.emacs = HashMap::from([( + "tab".to_string(), + KeyBindingConfig::Simple("return-query".to_string()), + )]); + + let mut state = State { + history_count: 100, + update_needed: None, + results_state: ListState::default(), + switched_search_mode: false, + search_mode: SearchMode::Fuzzy, + results_len: 100, + accept: false, + keymap_mode: KeymapMode::Emacs, + prefix: false, + current_cursor: None, + tab_index: 0, + pending_vim_key: None, + original_input_empty: false, + inspecting_state: InspectingState { + current: None, + next: None, + previous: None, + }, + keymaps: KeymapSet::from_settings(&settings), + search: SearchState { + input: "test query".to_string().into(), + filter_mode: FilterMode::Global, + context: Context { + session: String::new(), + cwd: String::new(), + hostname: String::new(), + host_id: String::new(), + git_root: None, + }, + }, + engine: engines::engine(SearchMode::Fuzzy), + now: Box::new(OffsetDateTime::now_utc), + }; + + let tab_event = KeyEvent::new(KeyCode::Tab, KeyModifiers::NONE); + let result = state.handle_key_input(&settings, &tab_event); + assert!( + matches!(result, super::InputAction::ReturnQuery), + "Tab configured as return-query should return InputAction::ReturnQuery" + ); + } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin/src/command/client/search/keybindings/actions.rs new/atuin-18.12.1/crates/atuin/src/command/client/search/keybindings/actions.rs --- old/atuin-18.12.0/crates/atuin/src/command/client/search/keybindings/actions.rs 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin/src/command/client/search/keybindings/actions.rs 1970-01-01 01:00:00.000000000 +0100 @@ -10,6 +10,7 @@ CursorRight, CursorWordLeft, CursorWordRight, + CursorWordEnd, CursorStart, CursorEnd, @@ -60,6 +61,7 @@ VimEnterInsertAtStart, VimEnterInsertAtEnd, VimSearchInsert, + VimChangeToEnd, EnterPrefixMode, // Inspector @@ -92,6 +94,7 @@ "cursor-right" => Ok(Action::CursorRight), "cursor-word-left" => Ok(Action::CursorWordLeft), "cursor-word-right" => Ok(Action::CursorWordRight), + "cursor-word-end" => Ok(Action::CursorWordEnd), "cursor-start" => Ok(Action::CursorStart), "cursor-end" => Ok(Action::CursorEnd), @@ -134,6 +137,7 @@ "vim-enter-insert-at-start" => Ok(Action::VimEnterInsertAtStart), "vim-enter-insert-at-end" => Ok(Action::VimEnterInsertAtEnd), "vim-search-insert" => Ok(Action::VimSearchInsert), + "vim-change-to-end" => Ok(Action::VimChangeToEnd), "enter-prefix-mode" => Ok(Action::EnterPrefixMode), "inspect-previous" => Ok(Action::InspectPrevious), @@ -152,6 +156,7 @@ Action::CursorRight => "cursor-right".to_string(), Action::CursorWordLeft => "cursor-word-left".to_string(), Action::CursorWordRight => "cursor-word-right".to_string(), + Action::CursorWordEnd => "cursor-word-end".to_string(), Action::CursorStart => "cursor-start".to_string(), Action::CursorEnd => "cursor-end".to_string(), @@ -196,6 +201,7 @@ Action::VimEnterInsertAtStart => "vim-enter-insert-at-start".to_string(), Action::VimEnterInsertAtEnd => "vim-enter-insert-at-end".to_string(), Action::VimSearchInsert => "vim-search-insert".to_string(), + Action::VimChangeToEnd => "vim-change-to-end".to_string(), Action::EnterPrefixMode => "enter-prefix-mode".to_string(), Action::InspectPrevious => "inspect-previous".to_string(), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin/src/command/client/search/keybindings/conditions.rs new/atuin-18.12.1/crates/atuin/src/command/client/search/keybindings/conditions.rs --- old/atuin-18.12.0/crates/atuin/src/command/client/search/keybindings/conditions.rs 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin/src/command/client/search/keybindings/conditions.rs 1970-01-01 01:00:00.000000000 +0100 @@ -8,6 +8,7 @@ CursorAtStart, CursorAtEnd, InputEmpty, + OriginalInputEmpty, ListAtEnd, ListAtStart, NoResults, @@ -46,6 +47,8 @@ pub selected_index: usize, /// Total number of results. pub results_len: usize, + /// Whether the original input (query passed to the TUI) was empty. + pub original_input_empty: bool, } // --------------------------------------------------------------------------- @@ -59,6 +62,7 @@ ConditionAtom::CursorAtStart => ctx.cursor_position == 0, ConditionAtom::CursorAtEnd => ctx.cursor_position == ctx.input_width, ConditionAtom::InputEmpty => ctx.input_byte_len == 0, + ConditionAtom::OriginalInputEmpty => ctx.original_input_empty, ConditionAtom::ListAtEnd => { ctx.results_len == 0 || ctx.selected_index >= ctx.results_len.saturating_sub(1) } @@ -74,6 +78,7 @@ "cursor-at-start" => Ok(ConditionAtom::CursorAtStart), "cursor-at-end" => Ok(ConditionAtom::CursorAtEnd), "input-empty" => Ok(ConditionAtom::InputEmpty), + "original-input-empty" => Ok(ConditionAtom::OriginalInputEmpty), "list-at-end" => Ok(ConditionAtom::ListAtEnd), "list-at-start" => Ok(ConditionAtom::ListAtStart), "no-results" => Ok(ConditionAtom::NoResults), @@ -88,6 +93,7 @@ ConditionAtom::CursorAtStart => "cursor-at-start", ConditionAtom::CursorAtEnd => "cursor-at-end", ConditionAtom::InputEmpty => "input-empty", + ConditionAtom::OriginalInputEmpty => "original-input-empty", ConditionAtom::ListAtEnd => "list-at-end", ConditionAtom::ListAtStart => "list-at-start", ConditionAtom::NoResults => "no-results", @@ -370,12 +376,24 @@ selected: usize, len: usize, ) -> EvalContext { + ctx_with_original(cursor, width, byte_len, selected, len, false) + } + + fn ctx_with_original( + cursor: usize, + width: usize, + byte_len: usize, + selected: usize, + len: usize, + original_input_empty: bool, + ) -> EvalContext { EvalContext { cursor_position: cursor, input_width: width, input_byte_len: byte_len, selected_index: selected, results_len: len, + original_input_empty, } } @@ -401,6 +419,22 @@ } #[test] + fn atom_original_input_empty() { + // original_input_empty = true + assert!( + ConditionAtom::OriginalInputEmpty.evaluate(&ctx_with_original(0, 0, 0, 0, 10, true)) + ); + // original_input_empty = false + assert!( + !ConditionAtom::OriginalInputEmpty.evaluate(&ctx_with_original(0, 0, 0, 0, 10, false)) + ); + // original_input_empty is independent of current input state + assert!( + ConditionAtom::OriginalInputEmpty.evaluate(&ctx_with_original(0, 5, 5, 0, 10, true)) + ); + } + + #[test] fn atom_list_at_end() { assert!(ConditionAtom::ListAtEnd.evaluate(&ctx(0, 0, 0, 99, 100))); assert!(!ConditionAtom::ListAtEnd.evaluate(&ctx(0, 0, 0, 50, 100))); @@ -428,6 +462,7 @@ "cursor-at-start", "cursor-at-end", "input-empty", + "original-input-empty", "list-at-end", "list-at-start", "no-results", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin/src/command/client/search/keybindings/defaults.rs new/atuin-18.12.1/crates/atuin/src/command/client/search/keybindings/defaults.rs --- old/atuin-18.12.0/crates/atuin/src/command/client/search/keybindings/defaults.rs 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin/src/command/client/search/keybindings/defaults.rs 1970-01-01 01:00:00.000000000 +0100 @@ -1,6 +1,7 @@ use std::collections::HashMap; use atuin_client::settings::{KeyBindingConfig, Settings}; +use tracing::warn; use super::actions::Action; use super::conditions::{ConditionAtom, ConditionExpr}; @@ -272,6 +273,19 @@ km.bind(key("h"), Action::CursorLeft); km.bind(key("l"), Action::CursorRight); + // --- Vim cursor movement --- + km.bind(key("0"), Action::CursorStart); + km.bind(key("$"), Action::CursorEnd); + km.bind(key("w"), Action::CursorWordRight); + km.bind(key("b"), Action::CursorWordLeft); + km.bind(key("e"), Action::CursorWordEnd); + + // --- Vim editing --- + km.bind(key("x"), Action::DeleteCharAfter); + km.bind(key("d d"), Action::ClearLine); + km.bind(key("D"), Action::ClearToEnd); + km.bind(key("C"), Action::VimChangeToEnd); + // --- Mode switching --- km.bind(key("?"), Action::VimSearchInsert); km.bind(key("/"), Action::VimSearchInsert); @@ -306,6 +320,10 @@ km.bind(key("pagedown"), Action::ScrollPageDown); km.bind(key("pageup"), Action::ScrollPageUp); + // --- Accept --- + let accept = accept_action(settings); + km.bind(key("enter"), accept); + km } @@ -330,10 +348,17 @@ // --------------------------------------------------------------------------- /// Build the default inspector keymap (tab index 1). -pub fn default_inspector_keymap(_settings: &Settings) -> Keymap { +/// +/// The inspector shows details about the selected history item and has no +/// text input, so we build a minimal keymap with only inspector-relevant +/// bindings. We respect the user's `keymap_mode` to provide vim-style j/k +/// navigation for vim users. +pub fn default_inspector_keymap(settings: &Settings) -> Keymap { + use atuin_client::settings::KeymapMode; + let mut km = Keymap::new(); - // Common bindings + // Common bindings (same as search tab) km.bind(key("ctrl-c"), Action::ReturnOriginal); km.bind(key("ctrl-g"), Action::ReturnOriginal); km.bind(key("esc"), Action::Exit); @@ -341,10 +366,31 @@ km.bind(key("tab"), Action::ReturnSelection); km.bind(key("ctrl-o"), Action::ToggleTab); - // Inspector-specific + // Accept behavior respects enter_accept setting + let accept = if settings.enter_accept { + Action::Accept + } else { + Action::ReturnSelection + }; + km.bind(key("enter"), accept); + + // Inspector-specific: delete history entry km.bind(key("ctrl-d"), Action::Delete); + + // Inspector navigation km.bind(key("up"), Action::InspectPrevious); km.bind(key("down"), Action::InspectNext); + km.bind(key("pageup"), Action::InspectPrevious); + km.bind(key("pagedown"), Action::InspectNext); + + // For vim users, add j/k navigation + if matches!( + settings.keymap_mode, + KeymapMode::VimNormal | KeymapMode::VimInsert + ) { + km.bind(key("j"), Action::InspectNext); + km.bind(key("k"), Action::InspectPrevious); + } km } @@ -405,7 +451,7 @@ let key = match KeyInput::parse(key_str) { Ok(k) => k, Err(e) => { - eprintln!("[atuin] warning: invalid key in keymap config: {key_str:?}: {e}"); + warn!("invalid key in keymap config: {key_str:?}: {e}"); continue; } }; @@ -414,7 +460,7 @@ keymap.bindings.insert(key, binding); } Err(e) => { - eprintln!("[atuin] warning: invalid binding for {key_str:?} in keymap config: {e}"); + warn!("invalid binding for {key_str:?} in keymap config: {e}"); } } } @@ -483,6 +529,7 @@ input_byte_len: width, selected_index: selected, results_len: len, + original_input_empty: false, } } @@ -728,6 +775,26 @@ ); } + #[test] + fn vim_normal_enter_returns_selection() { + // enter_accept=false in test defaults → ReturnSelection + let km = default_vim_normal_keymap(&default_settings()); + let ctx = make_ctx(0, 0, 0, 10); + assert_eq!( + km.resolve(&key("enter"), &ctx), + Some(Action::ReturnSelection) + ); + } + + #[test] + fn vim_normal_enter_accept_true_uses_accept() { + let mut settings = default_settings(); + settings.enter_accept = true; + let km = default_vim_normal_keymap(&settings); + let ctx = make_ctx(0, 0, 0, 10); + assert_eq!(km.resolve(&key("enter"), &ctx), Some(Action::Accept)); + } + // -- Vim Insert keymap tests -- #[test] @@ -1151,4 +1218,58 @@ modified.prefix = "x".to_string(); assert!(modified.has_non_default_values()); } + + #[test] + fn original_input_empty_condition_in_config() { + use atuin_client::settings::{KeyBindingConfig, KeyRuleConfig}; + use std::collections::HashMap; + + let mut settings = default_settings(); + // Configure esc to: if original-input-empty -> return-query, else return-original + settings.keymap.emacs = HashMap::from([( + "esc".to_string(), + KeyBindingConfig::Rules(vec![ + KeyRuleConfig { + when: Some("original-input-empty".to_string()), + action: "return-query".to_string(), + }, + KeyRuleConfig { + when: None, + action: "return-original".to_string(), + }, + ]), + )]); + + let set = KeymapSet::from_settings(&settings); + + // When original input was empty, should return-query + let ctx_original_empty = EvalContext { + cursor_position: 0, + input_width: 5, + input_byte_len: 5, + selected_index: 0, + results_len: 10, + original_input_empty: true, + }; + assert_eq!( + set.emacs.resolve(&key("esc"), &ctx_original_empty), + Some(Action::ReturnQuery), + "esc with original_input_empty=true should return-query" + ); + + // When original input was not empty, should return-original + let ctx_original_not_empty = EvalContext { + cursor_position: 0, + input_width: 5, + input_byte_len: 5, + selected_index: 0, + results_len: 10, + original_input_empty: false, + }; + assert_eq!( + set.emacs.resolve(&key("esc"), &ctx_original_not_empty), + Some(Action::ReturnOriginal), + "esc with original_input_empty=false should return-original" + ); + } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin/src/command/client/search/keybindings/key.rs new/atuin-18.12.1/crates/atuin/src/command/client/search/keybindings/key.rs --- old/atuin-18.12.0/crates/atuin/src/command/client/search/keybindings/key.rs 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin/src/command/client/search/keybindings/key.rs 1970-01-01 01:00:00.000000000 +0100 @@ -1,6 +1,6 @@ use std::fmt; -use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; +use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers, MediaKeyCode}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; /// A single key press with modifiers (e.g. `ctrl-c`, `alt-f`, `enter`). @@ -23,6 +23,7 @@ Tab, Backspace, Delete, + Insert, Up, Down, Left, @@ -33,6 +34,7 @@ PageDown, Space, F(u8), + Media(MediaKeyCode), } /// A key input that may be a single key or a multi-key sequence (e.g. `g g`). @@ -70,8 +72,19 @@ KeyCode::Enter => KeyCodeValue::Enter, KeyCode::Esc => KeyCodeValue::Esc, KeyCode::Tab => KeyCodeValue::Tab, + // BackTab is sent by many terminals for Shift+Tab + KeyCode::BackTab => { + return Some(SingleKey { + code: KeyCodeValue::Tab, + ctrl, + alt, + shift: true, + super_key, + }); + } KeyCode::Backspace => KeyCodeValue::Backspace, KeyCode::Delete => KeyCodeValue::Delete, + KeyCode::Insert => KeyCodeValue::Insert, KeyCode::Up => KeyCodeValue::Up, KeyCode::Down => KeyCodeValue::Down, KeyCode::Left => KeyCodeValue::Left, @@ -81,6 +94,7 @@ KeyCode::PageUp => KeyCodeValue::PageUp, KeyCode::PageDown => KeyCodeValue::PageDown, KeyCode::F(n) => KeyCodeValue::F(n), + KeyCode::Media(m) => KeyCodeValue::Media(m), _ => return None, }; @@ -125,6 +139,7 @@ "tab" => KeyCodeValue::Tab, "backspace" => KeyCodeValue::Backspace, "delete" | "del" => KeyCodeValue::Delete, + "insert" | "ins" => KeyCodeValue::Insert, "up" => KeyCodeValue::Up, "down" => KeyCodeValue::Down, "left" => KeyCodeValue::Left, @@ -150,6 +165,20 @@ "]" => KeyCodeValue::Char(']'), "?" => KeyCodeValue::Char('?'), "/" => KeyCodeValue::Char('/'), + "$" => KeyCodeValue::Char('$'), + // Media keys (no dashes - the parser splits on dash for modifiers) + "play" => KeyCodeValue::Media(MediaKeyCode::Play), + "pause" => KeyCodeValue::Media(MediaKeyCode::Pause), + "playpause" => KeyCodeValue::Media(MediaKeyCode::PlayPause), + "stop" => KeyCodeValue::Media(MediaKeyCode::Stop), + "fastforward" => KeyCodeValue::Media(MediaKeyCode::FastForward), + "rewind" => KeyCodeValue::Media(MediaKeyCode::Rewind), + "tracknext" => KeyCodeValue::Media(MediaKeyCode::TrackNext), + "trackprevious" => KeyCodeValue::Media(MediaKeyCode::TrackPrevious), + "record" => KeyCodeValue::Media(MediaKeyCode::Record), + "lowervolume" => KeyCodeValue::Media(MediaKeyCode::LowerVolume), + "raisevolume" => KeyCodeValue::Media(MediaKeyCode::RaiseVolume), + "mutevolume" | "mute" => KeyCodeValue::Media(MediaKeyCode::MuteVolume), _ => { let chars: Vec<char> = key_part.chars().collect(); if chars.len() == 1 { @@ -202,6 +231,7 @@ KeyCodeValue::Tab => write!(f, "tab"), KeyCodeValue::Backspace => write!(f, "backspace"), KeyCodeValue::Delete => write!(f, "delete"), + KeyCodeValue::Insert => write!(f, "insert"), KeyCodeValue::Up => write!(f, "up"), KeyCodeValue::Down => write!(f, "down"), KeyCodeValue::Left => write!(f, "left"), @@ -212,6 +242,21 @@ KeyCodeValue::PageDown => write!(f, "pagedown"), KeyCodeValue::Space => write!(f, "space"), KeyCodeValue::F(n) => write!(f, "f{n}"), + KeyCodeValue::Media(m) => match m { + MediaKeyCode::Play => write!(f, "play"), + MediaKeyCode::Pause => write!(f, "media-pause"), + MediaKeyCode::PlayPause => write!(f, "playpause"), + MediaKeyCode::Stop => write!(f, "stop"), + MediaKeyCode::FastForward => write!(f, "fastforward"), + MediaKeyCode::Rewind => write!(f, "rewind"), + MediaKeyCode::TrackNext => write!(f, "tracknext"), + MediaKeyCode::TrackPrevious => write!(f, "trackprevious"), + MediaKeyCode::Record => write!(f, "record"), + MediaKeyCode::LowerVolume => write!(f, "lowervolume"), + MediaKeyCode::RaiseVolume => write!(f, "raisevolume"), + MediaKeyCode::MuteVolume => write!(f, "mutevolume"), + MediaKeyCode::Reverse => write!(f, "reverse"), + }, } } } @@ -523,4 +568,62 @@ let parsed = SingleKey::parse("f12").unwrap(); assert_eq!(from_event, parsed); } + + #[test] + fn from_event_backtab_becomes_shift_tab() { + // Many terminals send BackTab for Shift+Tab + let event = KeyEvent::new(KeyCode::BackTab, KeyModifiers::NONE); + let k = SingleKey::from_event(&event).unwrap(); + assert_eq!(k.code, KeyCodeValue::Tab); + assert!(k.shift); + assert!(!k.ctrl && !k.alt); + } + + #[test] + fn from_event_backtab_matches_parsed_shift_tab() { + let event = KeyEvent::new(KeyCode::BackTab, KeyModifiers::NONE); + let from_event = SingleKey::from_event(&event).unwrap(); + let parsed = SingleKey::parse("shift-tab").unwrap(); + assert_eq!(from_event, parsed); + } + + #[test] + fn from_event_backtab_with_ctrl() { + // BackTab with ctrl modifier + let event = KeyEvent::new(KeyCode::BackTab, KeyModifiers::CONTROL); + let k = SingleKey::from_event(&event).unwrap(); + assert_eq!(k.code, KeyCodeValue::Tab); + assert!(k.shift); + assert!(k.ctrl); + } + + #[test] + fn parse_insert_key() { + let k = SingleKey::parse("insert").unwrap(); + assert_eq!(k.code, KeyCodeValue::Insert); + assert!(!k.ctrl && !k.alt && !k.shift); + + let k = SingleKey::parse("ins").unwrap(); + assert_eq!(k.code, KeyCodeValue::Insert); + + let k = SingleKey::parse("ctrl-insert").unwrap(); + assert_eq!(k.code, KeyCodeValue::Insert); + assert!(k.ctrl); + } + + #[test] + fn from_event_insert_key() { + let event = KeyEvent::new(KeyCode::Insert, KeyModifiers::NONE); + let k = SingleKey::from_event(&event).unwrap(); + assert_eq!(k.code, KeyCodeValue::Insert); + } + + #[test] + fn insert_key_round_trip() { + let k = KeyInput::parse("insert").unwrap(); + let display = k.to_string(); + assert_eq!(display, "insert"); + let k2 = KeyInput::parse(&display).unwrap(); + assert_eq!(k, k2); + } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin/src/command/client/search/keybindings/keymap.rs new/atuin-18.12.1/crates/atuin/src/command/client/search/keybindings/keymap.rs --- old/atuin-18.12.0/crates/atuin/src/command/client/search/keybindings/keymap.rs 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin/src/command/client/search/keybindings/keymap.rs 1970-01-01 01:00:00.000000000 +0100 @@ -126,6 +126,7 @@ input_byte_len: width, selected_index: selected, results_len: len, + original_input_empty: false, } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin/src/command/client/store/rekey.rs new/atuin-18.12.1/crates/atuin/src/command/client/store/rekey.rs --- old/atuin-18.12.0/crates/atuin/src/command/client/store/rekey.rs 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin/src/command/client/store/rekey.rs 1970-01-01 01:00:00.000000000 +0100 @@ -23,24 +23,16 @@ match bip39::Mnemonic::from_phrase(&key, bip39::Language::English) { Ok(mnemonic) => encode_key(Key::from_slice(mnemonic.entropy()))?, Err(err) => { - match err.downcast_ref::<bip39::ErrorKind>() { - Some(err) => { - match err { - // assume they copied in the base64 key - bip39::ErrorKind::InvalidWord => key, - bip39::ErrorKind::InvalidChecksum => { - bail!("key mnemonic was not valid") - } - bip39::ErrorKind::InvalidKeysize(_) - | bip39::ErrorKind::InvalidWordLength(_) - | bip39::ErrorKind::InvalidEntropyLength(_, _) => { - bail!("key was not the correct length") - } - } + match err { + // assume they copied in the base64 key + bip39::ErrorKind::InvalidWord(_) => key, + bip39::ErrorKind::InvalidChecksum => { + bail!("key mnemonic was not valid") } - _ => { - // unknown error. assume they copied the base64 key - key + bip39::ErrorKind::InvalidKeysize(_) + | bip39::ErrorKind::InvalidWordLength(_) + | bip39::ErrorKind::InvalidEntropyLength(_, _) => { + bail!("key was not the correct length") } } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin/src/shell/atuin.bash new/atuin-18.12.1/crates/atuin/src/shell/atuin.bash --- old/atuin-18.12.0/crates/atuin/src/shell/atuin.bash 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin/src/shell/atuin.bash 1970-01-01 01:00:00.000000000 +0100 @@ -262,7 +262,7 @@ # Use global variable to fix scope issues with traps __atuin_popup_tmpdir="" __atuin_tmux_popup_cleanup() { - [[ -n "$__atuin_popup_tmpdir" && -d "$__atuin_popup_tmpdir" ]] && rm -rf "$__atuin_popup_tmpdir" + [[ -n "$__atuin_popup_tmpdir" && -d "$__atuin_popup_tmpdir" ]] && command rm -rf "$__atuin_popup_tmpdir" __atuin_popup_tmpdir="" } @@ -288,7 +288,7 @@ popup_width="${ATUIN_TMUX_POPUP_WIDTH:-80%}" # Keep default value anyways popup_height="${ATUIN_TMUX_POPUP_HEIGHT:-60%}" tmux display-popup -d "$cdir" -w "$popup_width" -h "$popup_height" -E -E -- \ - sh -c "ATUIN_SHELL=bash ATUIN_LOG=error ATUIN_QUERY='$escaped_query' atuin search $escaped_args -i 2>'$result_file'" + sh -c "ATUIN_SESSION='$ATUIN_SESSION' ATUIN_SHELL=bash ATUIN_LOG=error ATUIN_QUERY='$escaped_query' atuin search $escaped_args -i 2>'$result_file'" if [[ -f "$result_file" ]]; then cat "$result_file" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin/src/shell/atuin.fish new/atuin-18.12.1/crates/atuin/src/shell/atuin.fish --- old/atuin-18.12.0/crates/atuin/src/shell/atuin.fish 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin/src/shell/atuin.fish 1970-01-01 01:00:00.000000000 +0100 @@ -99,13 +99,13 @@ set -l popup_width (test -n "$ATUIN_TMUX_POPUP_WIDTH" && echo "$ATUIN_TMUX_POPUP_WIDTH" || echo "80%") set -l popup_height (test -n "$ATUIN_TMUX_POPUP_HEIGHT" && echo "$ATUIN_TMUX_POPUP_HEIGHT" || echo "60%") tmux display-popup -d "$cdir" -w "$popup_width" -h "$popup_height" -E -E -- \ - sh -c "ATUIN_SHELL=fish ATUIN_LOG=error ATUIN_QUERY='$query' atuin search --keymap-mode=$keymap_mode$escaped_args -i 2>'$result_file'" + sh -c "ATUIN_SESSION='$ATUIN_SESSION' ATUIN_SHELL=fish ATUIN_LOG=error ATUIN_QUERY='$query' atuin search --keymap-mode=$keymap_mode$escaped_args -i 2>'$result_file'" if test -f "$result_file" set ATUIN_H (cat "$result_file" | string collect) end - rm -rf "$tmpdir" + command rm -rf "$tmpdir" end else # In fish 3.4 and above we can use `"$(some command)"` to keep multiple lines separate; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin/src/shell/atuin.zsh new/atuin-18.12.1/crates/atuin/src/shell/atuin.zsh --- old/atuin-18.12.0/crates/atuin/src/shell/atuin.zsh 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin/src/shell/atuin.zsh 1970-01-01 01:00:00.000000000 +0100 @@ -74,7 +74,7 @@ # Use global variable to fix scope issues with traps __atuin_popup_tmpdir="" __atuin_tmux_popup_cleanup() { - [[ -n "$__atuin_popup_tmpdir" && -d "$__atuin_popup_tmpdir" ]] && rm -rf "$__atuin_popup_tmpdir" + [[ -n "$__atuin_popup_tmpdir" && -d "$__atuin_popup_tmpdir" ]] && command rm -rf "$__atuin_popup_tmpdir" __atuin_popup_tmpdir="" } @@ -100,7 +100,7 @@ popup_width="${ATUIN_TMUX_POPUP_WIDTH:-80%}" # Keep default value anyways popup_height="${ATUIN_TMUX_POPUP_HEIGHT:-60%}" tmux display-popup -d "$cdir" -w "$popup_width" -h "$popup_height" -E -E -- \ - sh -c "ATUIN_SHELL=zsh ATUIN_LOG=error ATUIN_QUERY='$escaped_query' atuin search $escaped_args -i 2>'$result_file'" + sh -c "ATUIN_SESSION='$ATUIN_SESSION' ATUIN_SHELL=zsh ATUIN_LOG=error ATUIN_QUERY='$escaped_query' atuin search $escaped_args -i 2>'$result_file'" if [[ -f "$result_file" ]]; then cat "$result_file" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin-client/Cargo.toml new/atuin-18.12.1/crates/atuin-client/Cargo.toml --- old/atuin-18.12.0/crates/atuin-client/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin-client/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 @@ -19,7 +19,7 @@ check-update = [] [dependencies] -atuin-common = { path = "../atuin-common", version = "18.12.0" } +atuin-common = { path = "../atuin-common", version = "18.12.1" } log = { workspace = true } base64 = { workspace = true } @@ -65,7 +65,7 @@ hex = { version = "0.4", optional = true } sha2 = { version = "0.10", optional = true } indicatif = "0.18.0" -tiny-bip39 = "=1.0.0" +tiny-bip39 = "2.0.0" # theme crossterm = { version = "0.29.0", features = ["serde"] } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin-client/config.toml new/atuin-18.12.1/crates/atuin-client/config.toml --- old/atuin-18.12.0/crates/atuin-client/config.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin-client/config.toml 1970-01-01 01:00:00.000000000 +0100 @@ -305,8 +305,8 @@ ## When enabled and running inside tmux, Atuin will use a popup window for interactive search. ## Set to false to disable the popup. ## This can also be controlled with the ATUIN_TMUX_POPUP environment variable. -## Note: tmux popup is currently supported in zsh, bash, and fish shells. -# enabled = true +## Note: The tmux popup is currently supported in zsh, bash, and fish shells. This currently doesn't work with iTerm native tmux integration. +# enabled = false ## Width of the tmux popup window ## Can be a percentage, or integer (e.g. "100" means 100 characters wide) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin-client/src/login.rs new/atuin-18.12.1/crates/atuin-client/src/login.rs --- old/atuin-18.12.0/crates/atuin-client/src/login.rs 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin-client/src/login.rs 1970-01-01 01:00:00.000000000 +0100 @@ -23,24 +23,16 @@ let key = match bip39::Mnemonic::from_phrase(&key, bip39::Language::English) { Ok(mnemonic) => encode_key(Key::from_slice(mnemonic.entropy()))?, Err(err) => { - match err.downcast_ref::<bip39::ErrorKind>() { - Some(err) => { - match err { - // assume they copied in the base64 key - bip39::ErrorKind::InvalidWord => key, - bip39::ErrorKind::InvalidChecksum => { - bail!("key mnemonic was not valid") - } - bip39::ErrorKind::InvalidKeysize(_) - | bip39::ErrorKind::InvalidWordLength(_) - | bip39::ErrorKind::InvalidEntropyLength(_, _) => { - bail!("key was not the correct length") - } - } + match err { + // assume they copied in the base64 key + bip39::ErrorKind::InvalidWord(_) => key, + bip39::ErrorKind::InvalidChecksum => { + bail!("key mnemonic was not valid") } - _ => { - // unknown error. assume they copied the base64 key - key + bip39::ErrorKind::InvalidKeysize(_) + | bip39::ErrorKind::InvalidWordLength(_) + | bip39::ErrorKind::InvalidEntropyLength(_, _) => { + bail!("key was not the correct length") } } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin-client/src/settings.rs new/atuin-18.12.1/crates/atuin-client/src/settings.rs --- old/atuin-18.12.0/crates/atuin-client/src/settings.rs 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin-client/src/settings.rs 1970-01-01 01:00:00.000000000 +0100 @@ -519,7 +519,7 @@ impl Default for Tmux { fn default() -> Self { Self { - enabled: true, + enabled: false, width: "80%".to_string(), height: "60%".to_string(), } @@ -1082,7 +1082,7 @@ )? .set_default("theme.name", "default")? .set_default("theme.debug", None::<bool>)? - .set_default("tmux.enabled", true)? + .set_default("tmux.enabled", false)? .set_default("tmux.width", "80%")? .set_default("tmux.height", "60%")? .set_default( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin-daemon/Cargo.toml new/atuin-18.12.1/crates/atuin-daemon/Cargo.toml --- old/atuin-18.12.0/crates/atuin-daemon/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin-daemon/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 @@ -14,9 +14,9 @@ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -atuin-client = { path = "../atuin-client", version = "18.12.0" } -atuin-dotfiles = { path = "../atuin-dotfiles", version = "18.12.0" } -atuin-history = { path = "../atuin-history", version = "18.12.0" } +atuin-client = { path = "../atuin-client", version = "18.12.1" } +atuin-dotfiles = { path = "../atuin-dotfiles", version = "18.12.1" } +atuin-history = { path = "../atuin-history", version = "18.12.1" } time = { workspace = true } uuid = { workspace = true } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin-dotfiles/Cargo.toml new/atuin-18.12.1/crates/atuin-dotfiles/Cargo.toml --- old/atuin-18.12.0/crates/atuin-dotfiles/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin-dotfiles/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 @@ -14,8 +14,8 @@ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -atuin-common = { path = "../atuin-common", version = "18.12.0" } -atuin-client = { path = "../atuin-client", version = "18.12.0" } +atuin-common = { path = "../atuin-common", version = "18.12.1" } +atuin-client = { path = "../atuin-client", version = "18.12.1" } eyre = { workspace = true } tokio = { workspace = true } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin-history/Cargo.toml new/atuin-18.12.1/crates/atuin-history/Cargo.toml --- old/atuin-18.12.0/crates/atuin-history/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin-history/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 @@ -14,7 +14,7 @@ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -atuin-client = { path = "../atuin-client", version = "18.12.0" } +atuin-client = { path = "../atuin-client", version = "18.12.1" } time = { workspace = true } serde = { workspace = true } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin-kv/Cargo.toml new/atuin-18.12.1/crates/atuin-kv/Cargo.toml --- old/atuin-18.12.0/crates/atuin-kv/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin-kv/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 @@ -14,8 +14,8 @@ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -atuin-client = { path = "../atuin-client", version = "18.12.0" } -atuin-common = { path = "../atuin-common", version = "18.12.0" } +atuin-client = { path = "../atuin-client", version = "18.12.1" } +atuin-common = { path = "../atuin-common", version = "18.12.1" } tracing = { workspace = true } tracing-subscriber = { workspace = true } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin-scripts/Cargo.toml new/atuin-18.12.1/crates/atuin-scripts/Cargo.toml --- old/atuin-18.12.0/crates/atuin-scripts/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin-scripts/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 @@ -14,8 +14,8 @@ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -atuin-client = { path = "../atuin-client", version = "18.12.0" } -atuin-common = { path = "../atuin-common", version = "18.12.0" } +atuin-client = { path = "../atuin-client", version = "18.12.1" } +atuin-common = { path = "../atuin-common", version = "18.12.1" } tracing = { workspace = true } tracing-subscriber = { workspace = true } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin-server/Cargo.toml new/atuin-18.12.1/crates/atuin-server/Cargo.toml --- old/atuin-18.12.0/crates/atuin-server/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin-server/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 @@ -19,10 +19,10 @@ path = "src/bin/main.rs" [dependencies] -atuin-common = { path = "../atuin-common", version = "18.12.0" } -atuin-server-database = { path = "../atuin-server-database", version = "18.12.0" } -atuin-server-postgres = { path = "../atuin-server-postgres", version = "18.12.0" } -atuin-server-sqlite = { path = "../atuin-server-sqlite", version = "18.12.0" } +atuin-common = { path = "../atuin-common", version = "18.12.1" } +atuin-server-database = { path = "../atuin-server-database", version = "18.12.1" } +atuin-server-postgres = { path = "../atuin-server-postgres", version = "18.12.1" } +atuin-server-sqlite = { path = "../atuin-server-sqlite", version = "18.12.1" } tracing = { workspace = true } time = { workspace = true } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin-server-database/Cargo.toml new/atuin-18.12.1/crates/atuin-server-database/Cargo.toml --- old/atuin-18.12.0/crates/atuin-server-database/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin-server-database/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 @@ -10,7 +10,7 @@ repository = { workspace = true } [dependencies] -atuin-common = { path = "../atuin-common", version = "18.12.0" } +atuin-common = { path = "../atuin-common", version = "18.12.1" } tracing = { workspace = true } time = { workspace = true } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin-server-postgres/Cargo.toml new/atuin-18.12.1/crates/atuin-server-postgres/Cargo.toml --- old/atuin-18.12.0/crates/atuin-server-postgres/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin-server-postgres/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 @@ -10,8 +10,8 @@ repository = { workspace = true } [dependencies] -atuin-common = { path = "../atuin-common", version = "18.12.0" } -atuin-server-database = { path = "../atuin-server-database", version = "18.12.0" } +atuin-common = { path = "../atuin-common", version = "18.12.1" } +atuin-server-database = { path = "../atuin-server-database", version = "18.12.1" } eyre = { workspace = true } tracing = { workspace = true } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/crates/atuin-server-sqlite/Cargo.toml new/atuin-18.12.1/crates/atuin-server-sqlite/Cargo.toml --- old/atuin-18.12.0/crates/atuin-server-sqlite/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/crates/atuin-server-sqlite/Cargo.toml 1970-01-01 01:00:00.000000000 +0100 @@ -10,8 +10,8 @@ repository = { workspace = true } [dependencies] -atuin-common = { path = "../atuin-common", version = "18.12.0" } -atuin-server-database = { path = "../atuin-server-database", version = "18.12.0" } +atuin-common = { path = "../atuin-common", version = "18.12.1" } +atuin-server-database = { path = "../atuin-server-database", version = "18.12.1" } eyre = { workspace = true } tracing = { workspace = true } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/docker-compose.yml new/atuin-18.12.1/docker-compose.yml --- old/atuin-18.12.0/docker-compose.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/docker-compose.yml 1970-01-01 01:00:00.000000000 +0100 @@ -2,7 +2,7 @@ atuin: restart: always image: ghcr.io/atuinsh/atuin:<LATEST TAGGED RELEASE> - command: server start + command: start volumes: - "./config:/config" ports: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/docs/docs/configuration/advanced-key-binding.md new/atuin-18.12.1/docs/docs/configuration/advanced-key-binding.md --- old/atuin-18.12.0/docs/docs/configuration/advanced-key-binding.md 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/docs/docs/configuration/advanced-key-binding.md 1970-01-01 01:00:00.000000000 +0100 @@ -69,7 +69,34 @@ Some special characters are written out directly: ``` -"?", "/", "[", "]" +"?", "/", "[", "]", "$" +``` + +### Shifted and punctuation keys + +When you press a key like `Shift+1`, your terminal sends the resulting character (`!`) rather than "shift-1". To bind shifted punctuation keys, use the character directly: + +```toml +[keymap.emacs] +"!" = "some-action" # Binds to Shift+1 +"@" = "some-action" # Binds to Shift+2 +"#" = "some-action" # Binds to Shift+3 +"$" = "cursor-end" # Binds to Shift+4 (vim $ motion) +``` + +Any single character can be used as a key binding. + +!!! note + The `shift` modifier is still valid for non-character keys like `"shift-tab"` or `"shift-up"`. + +### Media keys + +Media keys are supported on terminals that implement the kitty keyboard protocol with `DISAMBIGUATE_ESCAPE_CODES` enabled: + +``` +"play", "pause", "playpause", "stop" +"fastforward", "rewind", "tracknext", "trackprevious" +"record", "lowervolume", "raisevolume", "mutevolume", "mute" ``` ### Multi-key sequences @@ -127,6 +154,7 @@ | `cursor-right` | Move cursor one character right | | `cursor-word-left` | Move cursor one word left | | `cursor-word-right` | Move cursor one word right | +| `cursor-word-end` | Move cursor to end of current/next word (vim `e` motion) | | `cursor-start` | Move cursor to start of line | | `cursor-end` | Move cursor to end of line | @@ -191,6 +219,7 @@ | `vim-enter-insert-at-start` | Move to start of line and enter vim insert mode (like vim `I`) | | `vim-enter-insert-at-end` | Move to end of line and enter vim insert mode (like vim `A`) | | `vim-search-insert` | Clear the search input and enter vim insert mode (like vim `?` or `/`) | +| `vim-change-to-end` | Delete to end of line and enter vim insert mode (like vim `C`) | | `enter-prefix-mode` | Enter prefix mode (waits for one more key, e.g. `d` for delete) | ### Inspector @@ -217,6 +246,7 @@ | `cursor-at-start` | The cursor is at position 0 | | `cursor-at-end` | The cursor is at the end of the input | | `input-empty` | The input line is empty (no text entered) | +| `original-input-empty` | The original query passed to the TUI was empty | | `list-at-start` | The selection is at the first entry (index 0) | | `list-at-end` | The selection is at the last entry | | `no-results` | The search returned zero results | diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/docs/docs/configuration/key-binding.md new/atuin-18.12.1/docs/docs/configuration/key-binding.md --- old/atuin-18.12.0/docs/docs/configuration/key-binding.md 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/docs/docs/configuration/key-binding.md 1970-01-01 01:00:00.000000000 +0100 @@ -238,6 +238,15 @@ | j | Normal | Selects the previous item on the list | | h | Normal | Move cursor left | | l | Normal | Move cursor right | +| 0 | Normal | Move cursor to start of line | +| $ | Normal | Move cursor to end of line | +| w | Normal | Move cursor to next word | +| b | Normal | Move cursor to previous word | +| e | Normal | Move cursor to end of current/next word | +| x | Normal | Delete character under cursor | +| dd | Normal | Clear the entire line | +| D | Normal | Delete to end of line | +| C | Normal | Delete to end of line and enter insert | | i | Normal | Enters insert mode | | I | Normal | Move to start of line and enter insert | | a | Normal | Move right and enter insert mode | @@ -253,17 +262,22 @@ | L | Normal | Jump to bottom of visible screen | | ? or / | Normal | Clear input and enter insert mode | | 1-9 | Normal | Select item by number | +| enter | Normal | Execute selected item (respects enter_accept) | | Esc | Insert | Enters normal mode | ### Inspector Open the inspector with ctrl + o -| Shortcut | Action | -| -------- | --------------------------------------------- | -| Esc | Close the inspector, returning to the shell | -| ctrl + o | Close the inspector, returning to search view | -| ctrl + d | Delete the inspected item from the history | -| ↑ | Inspect the previous item in the history | -| ↓ | Inspect the next item in the history | -| tab | Select current item and edit | +| Shortcut | Action | +| --------- | --------------------------------------------- | +| Esc | Close the inspector, returning to the shell | +| ctrl + o | Close the inspector, returning to search view | +| ctrl + d | Delete the inspected item from the history | +| ↑ | Inspect the previous item in the history | +| ↓ | Inspect the next item in the history | +| page up | Inspect the previous item in the history | +| page down | Inspect the next item in the history | +| j / k | Navigate items (when vim mode is enabled) | +| enter | Execute selected item (respects enter_accept) | +| tab | Select current item and edit | diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/atuin-18.12.0/k8s/atuin.yaml new/atuin-18.12.1/k8s/atuin.yaml --- old/atuin-18.12.0/k8s/atuin.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/atuin-18.12.1/k8s/atuin.yaml 1970-01-01 01:00:00.000000000 +0100 @@ -15,7 +15,6 @@ spec: containers: - args: - - server - start env: - name: ATUIN_DB_URI ++++++ vendor.tar.zst ++++++ /work/SRC/openSUSE:Factory/atuin/vendor.tar.zst /work/SRC/openSUSE:Factory/.atuin.new.1977/vendor.tar.zst differ: char 7, line 1
