From d8b7232a475a7e79d86458096954b354fc4faeca Mon Sep 17 00:00:00 2001
From: spectre256 <72505298+spectre256@users.noreply.github.com>
Date: Fri, 16 Jun 2023 15:13:23 -0400
Subject: [PATCH] Add yank_joined command (#7195)

Resolves issue #6888 by adding a command to join all selections and yank
them to the specified register. The typed command takes an argument as
the separator to use when joining the selections.
---
 book/src/generated/typable-cmd.md |  1 +
 helix-term/src/commands.rs        | 33 +++++++++++++++++++++++++++++++
 helix-term/src/commands/typed.rs  | 26 ++++++++++++++++++++++++
 3 files changed, 60 insertions(+)

diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md
index 5fcafd5c..a3949960 100644
--- a/book/src/generated/typable-cmd.md
+++ b/book/src/generated/typable-cmd.md
@@ -31,6 +31,7 @@
 | `:cquit`, `:cq` | Quit with exit code (default 1). Accepts an optional integer exit code (:cq 2). |
 | `:cquit!`, `:cq!` | Force quit with exit code (default 1) ignoring unsaved changes. Accepts an optional integer exit code (:cq! 2). |
 | `:theme` | Change the editor theme (show current theme if no name specified). |
+| `:yank-join` | Yank joined selections. A separator can be provided as first argument. Default value is newline. |
 | `:clipboard-yank` | Yank main selection into system clipboard. |
 | `:clipboard-yank-join` | Yank joined selections into system clipboard. A separator can be provided as first argument. Default value is newline. |
 | `:primary-clipboard-yank` | Yank main selection into system primary clipboard. |
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index b7a22c7b..5fb4a70e 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -376,6 +376,7 @@ impl MappableCommand {
         later, "Move forward in history",
         commit_undo_checkpoint, "Commit changes to new checkpoint",
         yank, "Yank selection",
+        yank_joined, "Join and yank selections",
         yank_joined_to_clipboard, "Join and yank selections to clipboard",
         yank_main_selection_to_clipboard, "Yank main selection to clipboard",
         yank_joined_to_primary_clipboard, "Join and yank selections to primary clipboard",
@@ -3724,6 +3725,38 @@ fn yank(cx: &mut Context) {
     exit_select_mode(cx);
 }
 
+fn yank_joined_impl(editor: &mut Editor, separator: &str, register: char) {
+    let (view, doc) = current!(editor);
+    let text = doc.text().slice(..);
+
+    let selection = doc.selection(view.id);
+    let joined = selection
+        .fragments(text)
+        .fold(String::new(), |mut acc, fragment| {
+            if !acc.is_empty() {
+                acc.push_str(separator);
+            }
+            acc.push_str(&fragment);
+            acc
+        });
+
+    let msg = format!(
+        "joined and yanked {} selection(s) to register {}",
+        selection.len(),
+        register,
+    );
+
+    editor.registers.write(register, vec![joined]);
+    editor.set_status(msg);
+}
+
+fn yank_joined(cx: &mut Context) {
+    let line_ending = doc!(cx.editor).line_ending;
+    let register = cx.register.unwrap_or('"');
+    yank_joined_impl(cx.editor, line_ending.as_str(), register);
+    exit_select_mode(cx);
+}
+
 fn yank_joined_to_clipboard_impl(
     editor: &mut Editor,
     separator: &str,
diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs
index 80beab31..5198e5bd 100644
--- a/helix-term/src/commands/typed.rs
+++ b/helix-term/src/commands/typed.rs
@@ -895,6 +895,25 @@ fn yank_main_selection_to_clipboard(
     yank_main_selection_to_clipboard_impl(cx.editor, ClipboardType::Clipboard)
 }
 
+fn yank_joined(
+    cx: &mut compositor::Context,
+    args: &[Cow<str>],
+    event: PromptEvent,
+) -> anyhow::Result<()> {
+    if event != PromptEvent::Validate {
+        return Ok(());
+    }
+
+    ensure!(args.len() <= 1, ":yank-join takes at most 1 argument");
+
+    let doc = doc!(cx.editor);
+    let default_sep = Cow::Borrowed(doc.line_ending.as_str());
+    let separator = args.first().unwrap_or(&default_sep);
+    let register = cx.editor.selected_register.unwrap_or('"');
+    yank_joined_impl(cx.editor, separator, register);
+    Ok(())
+}
+
 fn yank_joined_to_clipboard(
     cx: &mut compositor::Context,
     args: &[Cow<str>],
@@ -2474,6 +2493,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
             fun: theme,
             signature: CommandSignature::positional(&[completers::theme]),
         },
+        TypableCommand {
+            name: "yank-join",
+            aliases: &[],
+            doc: "Yank joined selections. A separator can be provided as first argument. Default value is newline.",
+            fun: yank_joined,
+            signature: CommandSignature::none(),
+        },
         TypableCommand {
             name: "clipboard-yank",
             aliases: &[],