From 32d071a39207b9f1c1753692e93aff45fcdf12c0 Mon Sep 17 00:00:00 2001
From: Michael Davis <mcarsondavis@gmail.com>
Date: Mon, 10 Jul 2023 17:04:14 -0500
Subject: [PATCH] Add the '%' (current filename) register

This register also comes from Kakoune. It's read-only and produces the
current document's name, defaulting to the scratch buffer name
constant.

(Also see PR5577.)

Co-authored-by: Ivan Tham <pickfire@riseup.net>
---
 helix-view/src/register.rs | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/helix-view/src/register.rs b/helix-view/src/register.rs
index 892d396f..14fd3f7f 100644
--- a/helix-view/src/register.rs
+++ b/helix-view/src/register.rs
@@ -2,7 +2,7 @@ use std::{borrow::Cow, collections::HashMap, iter};
 
 use anyhow::Result;
 
-use crate::Editor;
+use crate::{document::SCRATCH_BUFFER_NAME, Editor};
 
 /// A key-value store for saving sets of values.
 ///
@@ -13,6 +13,7 @@ use crate::Editor;
 /// * Black hole (`_`): all values read and written are discarded
 /// * Selection indices (`#`): index number of each selection starting at 1
 /// * Selection contents (`.`)
+/// * Document path (`%`): filename of the current buffer
 #[derive(Debug, Default)]
 pub struct Registers {
     inner: HashMap<char, Vec<String>>,
@@ -36,6 +37,17 @@ impl Registers {
                 let text = doc.text().slice(..);
                 Some(RegisterValues::new(doc.selection(view.id).fragments(text)))
             }
+            '%' => {
+                let doc = doc!(editor);
+
+                let path = doc
+                    .path()
+                    .as_ref()
+                    .map(|p| p.to_string_lossy())
+                    .unwrap_or_else(|| SCRATCH_BUFFER_NAME.into());
+
+                Some(RegisterValues::new(iter::once(path)))
+            }
             _ => self
                 .inner
                 .get(&name)
@@ -46,7 +58,7 @@ impl Registers {
     pub fn write(&mut self, name: char, values: Vec<String>) -> Result<()> {
         match name {
             '_' => Ok(()),
-            '#' | '.' => Err(anyhow::anyhow!("Register {name} does not support writing")),
+            '#' | '.' | '%' => Err(anyhow::anyhow!("Register {name} does not support writing")),
             _ => {
                 self.inner.insert(name, values);
                 Ok(())
@@ -57,7 +69,7 @@ impl Registers {
     pub fn push(&mut self, name: char, value: String) -> Result<()> {
         match name {
             '_' => Ok(()),
-            '#' | '.' => Err(anyhow::anyhow!("Register {name} does not support pushing")),
+            '#' | '.' | '%' => Err(anyhow::anyhow!("Register {name} does not support pushing")),
             _ => {
                 self.inner.entry(name).or_insert_with(Vec::new).push(value);
                 Ok(())
@@ -89,6 +101,7 @@ impl Registers {
                     ('_', "<empty>"),
                     ('#', "<selection indices>"),
                     ('.', "<selection contents>"),
+                    ('%', "<document path>"),
                 ]
                 .iter()
                 .copied(),
@@ -101,7 +114,7 @@ impl Registers {
 
     pub fn remove(&mut self, name: char) -> bool {
         match name {
-            '_' | '#' | '.' => false,
+            '_' | '#' | '.' | '%' => false,
             _ => self.inner.remove(&name).is_some(),
         }
     }