diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 04e39e5e..a93fa445 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -4401,6 +4401,8 @@ enum Paste { Cursor, } +static LINE_ENDING_REGEX: Lazy = Lazy::new(|| Regex::new(r"\r\n|\r|\n").unwrap()); + fn paste_impl( values: &[String], doc: &mut Document, @@ -4417,26 +4419,26 @@ fn paste_impl( doc.append_changes_to_history(view); } - let repeat = std::iter::repeat( - // `values` is asserted to have at least one entry above. - values - .last() - .map(|value| Tendril::from(value.repeat(count))) - .unwrap(), - ); - // if any of values ends with a line ending, it's linewise paste let linewise = values .iter() .any(|value| get_line_ending_of_str(value).is_some()); - // Only compiled once. - static REGEX: Lazy = Lazy::new(|| Regex::new(r"\r\n|\r|\n").unwrap()); - let mut values = values - .iter() - .map(|value| REGEX.replace_all(value, doc.line_ending.as_str())) - .map(|value| Tendril::from(value.as_ref().repeat(count))) - .chain(repeat); + let map_value = |value| { + let value = LINE_ENDING_REGEX.replace_all(value, doc.line_ending.as_str()); + let mut out = Tendril::from(value.as_ref()); + for _ in 1..count { + out.push_str(&value); + } + out + }; + + let repeat = std::iter::repeat( + // `values` is asserted to have at least one entry above. + map_value(values.last().unwrap()), + ); + + let mut values = values.iter().map(|value| map_value(value)).chain(repeat); let text = doc.text(); let selection = doc.selection(view.id); @@ -4533,19 +4535,24 @@ fn replace_with_yanked_impl(editor: &mut Editor, register: char, count: usize) { else { return; }; - let values: Vec<_> = values.map(|value| value.to_string()).collect(); let scrolloff = editor.config().scrolloff; + let (view, doc) = current_ref!(editor); - let (view, doc) = current!(editor); - let repeat = std::iter::repeat( - values - .last() - .map(|value| Tendril::from(&value.repeat(count))) - .unwrap(), - ); - let mut values = values - .iter() - .map(|value| Tendril::from(&value.repeat(count))) + let map_value = |value: &Cow| { + let value = LINE_ENDING_REGEX.replace_all(value, doc.line_ending.as_str()); + let mut out = Tendril::from(value.as_ref()); + for _ in 1..count { + out.push_str(&value); + } + out + }; + let mut values_rev = values.rev().peekable(); + // `values` is asserted to have at least one entry above. + let last = values_rev.peek().unwrap(); + let repeat = std::iter::repeat(map_value(last)); + let mut values = values_rev + .rev() + .map(|value| map_value(&value)) .chain(repeat); let selection = doc.selection(view.id); let transaction = Transaction::change_by_selection(doc.text(), selection, |range| { @@ -4555,7 +4562,9 @@ fn replace_with_yanked_impl(editor: &mut Editor, register: char, count: usize) { (range.from(), range.to(), None) } }); + drop(values); + let (view, doc) = current!(editor); doc.apply(&transaction, view.id); doc.append_changes_to_history(view); view.ensure_cursor_in_view(doc, scrolloff);