diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 329b7ab7..6f10848a 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -1911,7 +1911,7 @@ fn search_next_or_prev_impl(cx: &mut Context, movement: Movement, direction: Dir let register = cx.register.unwrap_or('/'); let config = cx.editor.config(); let scrolloff = config.scrolloff; - if let Some(query) = cx.editor.registers.last(register, cx.editor) { + if let Some(query) = cx.editor.registers.first(register, cx.editor) { let doc = doc!(cx.editor); let contents = doc.text().slice(..).to_string(); let search_config = &config.search; @@ -1983,7 +1983,7 @@ fn search_selection(cx: &mut Context) { fn make_search_word_bounded(cx: &mut Context) { let register = cx.register.unwrap_or('/'); - let regex = match cx.editor.registers.last(register, cx.editor) { + let regex = match cx.editor.registers.first(register, cx.editor) { Some(regex) => regex, None => return, }; diff --git a/helix-term/src/ui/prompt.rs b/helix-term/src/ui/prompt.rs index 8dc2906a..702a6e67 100644 --- a/helix-term/src/ui/prompt.rs +++ b/helix-term/src/ui/prompt.rs @@ -307,7 +307,7 @@ impl Prompt { ) { (self.callback_fn)(cx, &self.line, PromptEvent::Abort); let mut values = match cx.editor.registers.read(register, cx.editor) { - Some(values) if values.len() > 0 => values, + Some(values) if values.len() > 0 => values.rev(), _ => return, }; @@ -473,7 +473,7 @@ impl Prompt { // Show the most recently entered value as a suggestion. if let Some(suggestion) = self .history_register - .and_then(|reg| cx.editor.registers.last(reg, cx.editor)) + .and_then(|reg| cx.editor.registers.first(reg, cx.editor)) { surface.set_string(line_area.x, line_area.y, suggestion, suggestion_color); } @@ -570,7 +570,7 @@ impl Component for Prompt { } else { let last_item = self .history_register - .and_then(|reg| cx.editor.registers.last(reg, cx.editor)) + .and_then(|reg| cx.editor.registers.first(reg, cx.editor)) .map(|entry| entry.to_string()) .unwrap_or_else(|| String::from("")); diff --git a/helix-view/src/register.rs b/helix-view/src/register.rs index e82051dd..61912378 100644 --- a/helix-view/src/register.rs +++ b/helix-view/src/register.rs @@ -23,6 +23,10 @@ use crate::{ /// * Primary clipboard (`+`) #[derive(Debug)] pub struct Registers { + /// The mapping of register to values. + /// Values are stored in reverse order when inserted with `Registers::write`. + /// The order is reversed again in `Registers::read`. This allows us to + /// efficiently prepend new values in `Registers::push`. inner: HashMap>, clipboard_provider: Box, } @@ -77,11 +81,11 @@ impl Registers { _ => self .inner .get(&name) - .map(|values| RegisterValues::new(values.iter().map(Cow::from))), + .map(|values| RegisterValues::new(values.iter().map(Cow::from).rev())), } } - pub fn write(&mut self, name: char, values: Vec) -> Result<()> { + pub fn write(&mut self, name: char, mut values: Vec) -> Result<()> { match name { '_' => Ok(()), '#' | '.' | '%' => Err(anyhow::anyhow!("Register {name} does not support writing")), @@ -94,17 +98,19 @@ impl Registers { _ => unreachable!(), }, )?; + values.reverse(); self.inner.insert(name, values); Ok(()) } _ => { + values.reverse(); self.inner.insert(name, values); Ok(()) } } } - pub fn push(&mut self, name: char, value: String) -> Result<()> { + pub fn push(&mut self, name: char, mut value: String) -> Result<()> { match name { '_' => Ok(()), '#' | '.' | '%' => Err(anyhow::anyhow!("Register {name} does not support pushing")), @@ -121,11 +127,13 @@ impl Registers { anyhow::bail!("Failed to push to register {name}: clipboard does not match register contents"); } - saved_values.push(value); - self.clipboard_provider.set_contents( - saved_values.join(NATIVE_LINE_ENDING.as_str()), - clipboard_type, - )?; + saved_values.push(value.clone()); + if !contents.is_empty() { + value.push_str(NATIVE_LINE_ENDING.as_str()); + } + value.push_str(&contents); + self.clipboard_provider + .set_contents(value, clipboard_type)?; Ok(()) } @@ -150,7 +158,7 @@ impl Registers { .filter(|(name, _)| !matches!(name, '*' | '+')) .map(|(name, values)| { let preview = values - .first() + .last() .and_then(|s| s.lines().next()) .unwrap_or(""); @@ -222,7 +230,7 @@ fn read_from_clipboard<'a>( let Some(values) = saved_values else { return RegisterValues::new(iter::once(contents.into())) }; if contents_are_saved(values, &contents) { - RegisterValues::new(values.iter().map(Cow::from)) + RegisterValues::new(values.iter().map(Cow::from).rev()) } else { RegisterValues::new(iter::once(contents.into())) } @@ -243,7 +251,7 @@ fn read_from_clipboard<'a>( fn contents_are_saved(saved_values: &[String], mut contents: &str) -> bool { let line_ending = NATIVE_LINE_ENDING.as_str(); - let mut values = saved_values.iter(); + let mut values = saved_values.iter().rev(); match values.next() { Some(first) if contents.starts_with(first) => {