on master help sign in
Preview the latest value for regular registers
2d838d7Michael Davis
helix-term/src/commands.rs+2−2
@@ -1911,7 +1911,7 @@ fn search_next_or_prev_impl(cx: &mut Context, movement: Movement, direction: Dir
1911 let register = cx.register.unwrap_or('/');
1911 let register = cx.register.unwrap_or('/');
1912 let config = cx.editor.config();
1912 let config = cx.editor.config();
1913 let scrolloff = config.scrolloff;
1913 let scrolloff = config.scrolloff;
1914− if let Some(query) = cx.editor.registers.last(register, cx.editor) {
1914+ if let Some(query) = cx.editor.registers.first(register, cx.editor) {
1915 let doc = doc!(cx.editor);
1915 let doc = doc!(cx.editor);
1916 let contents = doc.text().slice(..).to_string();
1916 let contents = doc.text().slice(..).to_string();
1917 let search_config = &config.search;
1917 let search_config = &config.search;
@@ -1983,7 +1983,7 @@ fn search_selection(cx: &mut Context) {
1983
1983
1984fn make_search_word_bounded(cx: &mut Context) {
1984fn make_search_word_bounded(cx: &mut Context) {
1985 let register = cx.register.unwrap_or('/');
1985 let register = cx.register.unwrap_or('/');
1986− let regex = match cx.editor.registers.last(register, cx.editor) {
1986+ let regex = match cx.editor.registers.first(register, cx.editor) {
1987 Some(regex) => regex,
1987 Some(regex) => regex,
1988 None => return,
1988 None => return,
1989 };
1989 };
helix-term/src/ui/prompt.rs+3−3
@@ -307,7 +307,7 @@ impl Prompt {
307 ) {
307 ) {
308 (self.callback_fn)(cx, &self.line, PromptEvent::Abort);
308 (self.callback_fn)(cx, &self.line, PromptEvent::Abort);
309 let mut values = match cx.editor.registers.read(register, cx.editor) {
309 let mut values = match cx.editor.registers.read(register, cx.editor) {
310− Some(values) if values.len() > 0 => values,
310+ Some(values) if values.len() > 0 => values.rev(),
311 _ => return,
311 _ => return,
312 };
312 };
313
313
@@ -473,7 +473,7 @@ impl Prompt {
473 // Show the most recently entered value as a suggestion.
473 // Show the most recently entered value as a suggestion.
474 if let Some(suggestion) = self
474 if let Some(suggestion) = self
475 .history_register
475 .history_register
476− .and_then(|reg| cx.editor.registers.last(reg, cx.editor))
476+ .and_then(|reg| cx.editor.registers.first(reg, cx.editor))
477 {
477 {
478 surface.set_string(line_area.x, line_area.y, suggestion, suggestion_color);
478 surface.set_string(line_area.x, line_area.y, suggestion, suggestion_color);
479 }
479 }
@@ -570,7 +570,7 @@ impl Component for Prompt {
570 } else {
570 } else {
571 let last_item = self
571 let last_item = self
572 .history_register
572 .history_register
573− .and_then(|reg| cx.editor.registers.last(reg, cx.editor))
573+ .and_then(|reg| cx.editor.registers.first(reg, cx.editor))
574 .map(|entry| entry.to_string())
574 .map(|entry| entry.to_string())
575 .unwrap_or_else(|| String::from(""));
575 .unwrap_or_else(|| String::from(""));
576
576
helix-view/src/register.rs+19−11
@@ -23,6 +23,10 @@ use crate::{
23/// * Primary clipboard (`+`)
23/// * Primary clipboard (`+`)
24#[derive(Debug)]
24#[derive(Debug)]
25pub struct Registers {
25pub struct Registers {
26+ /// The mapping of register to values.
27+ /// Values are stored in reverse order when inserted with `Registers::write`.
28+ /// The order is reversed again in `Registers::read`. This allows us to
29+ /// efficiently prepend new values in `Registers::push`.
26 inner: HashMap<char, Vec<String>>,
30 inner: HashMap<char, Vec<String>>,
27 clipboard_provider: Box<dyn ClipboardProvider>,
31 clipboard_provider: Box<dyn ClipboardProvider>,
28}
32}
@@ -77,11 +81,11 @@ impl Registers {
77 _ => self
81 _ => self
78 .inner
82 .inner
79 .get(&name)
83 .get(&name)
80− .map(|values| RegisterValues::new(values.iter().map(Cow::from))),
84+ .map(|values| RegisterValues::new(values.iter().map(Cow::from).rev())),
81 }
85 }
82 }
86 }
83
87
84− pub fn write(&mut self, name: char, values: Vec<String>) -> Result<()> {
88+ pub fn write(&mut self, name: char, mut values: Vec<String>) -> Result<()> {
85 match name {
89 match name {
86 '_' => Ok(()),
90 '_' => Ok(()),
87 '#' | '.' | '%' => Err(anyhow::anyhow!("Register {name} does not support writing")),
91 '#' | '.' | '%' => Err(anyhow::anyhow!("Register {name} does not support writing")),
@@ -94,17 +98,19 @@ impl Registers {
94 _ => unreachable!(),
98 _ => unreachable!(),
95 },
99 },
96 )?;
100 )?;
101+ values.reverse();
97 self.inner.insert(name, values);
102 self.inner.insert(name, values);
98 Ok(())
103 Ok(())
99 }
104 }
100 _ => {
105 _ => {
106+ values.reverse();
101 self.inner.insert(name, values);
107 self.inner.insert(name, values);
102 Ok(())
108 Ok(())
103 }
109 }
104 }
110 }
105 }
111 }
106
112
107− pub fn push(&mut self, name: char, value: String) -> Result<()> {
113+ pub fn push(&mut self, name: char, mut value: String) -> Result<()> {
108 match name {
114 match name {
109 '_' => Ok(()),
115 '_' => Ok(()),
110 '#' | '.' | '%' => Err(anyhow::anyhow!("Register {name} does not support pushing")),
116 '#' | '.' | '%' => Err(anyhow::anyhow!("Register {name} does not support pushing")),
@@ -121,11 +127,13 @@ impl Registers {
121 anyhow::bail!("Failed to push to register {name}: clipboard does not match register contents");
127 anyhow::bail!("Failed to push to register {name}: clipboard does not match register contents");
122 }
128 }
123
129
124− saved_values.push(value);
130+ saved_values.push(value.clone());
131+ if !contents.is_empty() {
132+ value.push_str(NATIVE_LINE_ENDING.as_str());
133+ }
134+ value.push_str(&contents);
125− self.clipboard_provider.set_contents(
135+ self.clipboard_provider
126− saved_values.join(NATIVE_LINE_ENDING.as_str()),
127− clipboard_type,
136+ .set_contents(value, clipboard_type)?;
128− )?;
129
137
130 Ok(())
138 Ok(())
131 }
139 }
@@ -150,7 +158,7 @@ impl Registers {
150 .filter(|(name, _)| !matches!(name, '*' | '+'))
158 .filter(|(name, _)| !matches!(name, '*' | '+'))
151 .map(|(name, values)| {
159 .map(|(name, values)| {
152 let preview = values
160 let preview = values
153− .first()
161+ .last()
154 .and_then(|s| s.lines().next())
162 .and_then(|s| s.lines().next())
155 .unwrap_or("<empty>");
163 .unwrap_or("<empty>");
156
164
@@ -222,7 +230,7 @@ fn read_from_clipboard<'a>(
222 let Some(values) = saved_values else { return RegisterValues::new(iter::once(contents.into())) };
230 let Some(values) = saved_values else { return RegisterValues::new(iter::once(contents.into())) };
223
231
224 if contents_are_saved(values, &contents) {
232 if contents_are_saved(values, &contents) {
225− RegisterValues::new(values.iter().map(Cow::from))
233+ RegisterValues::new(values.iter().map(Cow::from).rev())
226 } else {
234 } else {
227 RegisterValues::new(iter::once(contents.into()))
235 RegisterValues::new(iter::once(contents.into()))
228 }
236 }
@@ -243,7 +251,7 @@ fn read_from_clipboard<'a>(
243
251
244fn contents_are_saved(saved_values: &[String], mut contents: &str) -> bool {
252fn contents_are_saved(saved_values: &[String], mut contents: &str) -> bool {
245 let line_ending = NATIVE_LINE_ENDING.as_str();
253 let line_ending = NATIVE_LINE_ENDING.as_str();
246− let mut values = saved_values.iter();
254+ let mut values = saved_values.iter().rev();
247
255
248 match values.next() {
256 match values.next() {
249 Some(first) if contents.starts_with(first) => {
257 Some(first) if contents.starts_with(first) => {