Subject: bug#76792: [PATCH] dired-copy-filename-as-kill to support project relative names

From: Dmitry Gutov <[email-masked]>
Date: Fri, 7 Mar 2025 00:39:02 +0200

Here's an implementation for that idea, together with .texi and NEWS 
changes.

Comments welcome!

diff --git a/doc/emacs/dired.texi b/doc/emacs/dired.texi
index 07142e71713..5fc0c3b4a52 100644
--- a/doc/emacs/dired.texi
+++ b/doc/emacs/dired.texi
@@ -1860,8 +1860,9 @@ Misc Dired Features
 you had killed them with @kbd{C-w}.  The names are separated by a
 space.
 
-  With a zero prefix argument, this uses the absolute file name of
-each marked file.  With just @kbd{C-u} as the prefix argument, it uses
+  With a zero prefix argument, this uses the absolute file name of each
+marked file.  With prefix value, it uses names relative to the current
+project root.  With just @kbd{C-u} as the prefix argument, it uses
 file names relative to the Dired buffer's default directory.  (This
 can still contain slashes if in a subdirectory.)  As a special case,
 if point is on a directory header line, @kbd{w} gives you the absolute
diff --git a/etc/NEWS b/etc/NEWS
index 78a241abfd3..0bae8f4fe35 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1136,6 +1136,10 @@ Without 'dired-hide-details-hide-absolute-location':
 When 'dired-make-directory-clickable' is non-nil, clicking on the base
 name of the directory now reverts the Dired buffer.
 
+*** 'dired-copy-filename-as-kill' supports project-relative names.
+With a new value of the prefix argument (1), this command copies file
+names relative to the root directory of the current project.
+
 ** Grep
 
 +++
diff --git a/lisp/dired.el b/lisp/dired.el
index aa766b6170e..9f92e1cb5f8 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -3477,6 +3477,7 @@ dired-copy-filename-as-kill
 quoting is done.)
 
 With a zero prefix arg, use the absolute file name of each marked file.
+With a prefix value 1, use the names relative to the current project root.
 With \\[universal-argument], use the file name relative to the Dired buffer's
 `default-directory'.  (This still may contain slashes if in a subdirectory.)
 
@@ -3488,8 +3489,13 @@ dired-copy-filename-as-kill
   (let* ((files
           (or (ensure-list (dired-get-subdir))
               (if arg
-                  (cond ((zerop (prefix-numeric-value arg))
+                  (cond ((eql 0 arg)
                          (dired-get-marked-files))
+                        ((eql 1 arg)
+                         (let ((root (project-root (project-current t))))
+                           (mapcar
+                            (lambda (file) (file-relative-name file root))
+                            (dired-get-marked-files))))
                         ((consp arg)
                          (dired-get-marked-files t))
                         (t