summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-15 00:23:14 -0500
committerCraig Jennings <c@cjennings.net>2026-05-15 00:23:14 -0500
commite3e904b33ed714d74fae01ae1b631d889b39003b (patch)
tree42f3da91db16ee763569d9ecd8e85685f032046e /modules
parentd79ede35e63b8c227886266dc9f00cc10291dfcb (diff)
downloaddotemacs-e3e904b33ed714d74fae01ae1b631d889b39003b.tar.gz
dotemacs-e3e904b33ed714d74fae01ae1b631d889b39003b.zip
feat(custom-buffer-file): make C-; b p dispatch by major-mode, with tests
Old behavior: `C-; b p' called `cj/copy-path-to-buffer-file-as-kill', which only worked in file-visiting buffers and errored otherwise. That meant the most useful "give me a clickable handle on this buffer" key did nothing in eww, elfeed, dired (file-at-point ≠ buffer's default-directory), and other browsing-shaped modes. Replace with a `major-mode'-aware dispatch: - `cj/buffer-source-functions' alist maps major-mode → thunk returning a string (or nil to fall through). - `cj/copy-buffer-source-as-kill' looks up the current mode, calls the thunk, falls back to `buffer-file-name', errors only when both yield nil. - `cj/copy-path-to-buffer-file-as-kill' kept as a `defalias' for backwards compat (the old name is referenced in adjacent tests). First-batch dispatches: - eww-mode -> (eww-current-url) - elfeed-show-mode -> (elfeed-entry-link elfeed-show-entry) - dired-mode -> (dired-get-filename nil t) - dirvish-mode -> same - doc-view / pdf-view: covered by the buffer-file-name fallback (they already set buffer-file-name correctly). 10 new ERT tests cover the dispatch paths, the buffer-file-name fallback, the user-error on nil source, the alias target, and the `C-; b p' keymap entry. which-key label flipped from "copy file path" to "copy buffer source" to match. Deferred to a follow-up task: mu4e-view-mode, org-mode at a heading, help-mode, Info-mode, magit-log/commit/status, xref/grep/ compilation, image-mode, archive-mode -- each needs a format decision before implementation.
Diffstat (limited to 'modules')
-rw-r--r--modules/custom-buffer-file.el52
1 files changed, 41 insertions, 11 deletions
diff --git a/modules/custom-buffer-file.el b/modules/custom-buffer-file.el
index ef4fc945..8c6014d3 100644
--- a/modules/custom-buffer-file.el
+++ b/modules/custom-buffer-file.el
@@ -214,16 +214,46 @@ When called interactively, prompts for confirmation if target file exists."
(kill-new file-path)
(message "Copied file link to kill ring: %s" file-path))))
-(defun cj/copy-path-to-buffer-file-as-kill ()
- "Copy the full path of the current buffer's file to the kill ring.
-Signal an error if the buffer is not visiting a file."
+(defvar cj/buffer-source-functions
+ '((eww-mode . (lambda () (eww-current-url)))
+ (elfeed-show-mode . (lambda () (elfeed-entry-link elfeed-show-entry)))
+ (dired-mode . (lambda () (dired-get-filename nil t)))
+ (dirvish-mode . (lambda () (dired-get-filename nil t))))
+ "Alist mapping major-mode -> thunk returning the buffer's \"source\".
+
+Each thunk is called with no arguments and should return a string
+to be copied to the kill ring, or nil to fall through to
+`buffer-file-name'. Modes not listed here also fall through to
+`buffer-file-name'.
+
+Used by `cj/copy-buffer-source-as-kill' (`C-; b p'). Doc-view and
+PDF-view modes intentionally aren't listed -- their
+`buffer-file-name' already points at the underlying file, so the
+fallback handles them.")
+
+(defun cj/copy-buffer-source-as-kill ()
+ "Copy the current buffer's \"source\" to the kill ring.
+
+Source means the URL, file path, or other clickable reference that
+identifies what the buffer represents. Dispatches by `major-mode'
+via `cj/buffer-source-functions'; falls back to `buffer-file-name'
+for modes without a dispatch entry.
+
+Signals `user-error' when no source can be determined."
(interactive)
- (let ((path (buffer-file-name)))
- (if (not path)
- (user-error "Current buffer is not visiting a file")
- (kill-new path)
- (message "Copied file path: %s" path)
- path)))
+ (let* ((handler (alist-get major-mode cj/buffer-source-functions))
+ (source (or (and handler (funcall handler))
+ (buffer-file-name))))
+ (unless source
+ (user-error "Buffer has no copyable source"))
+ (kill-new source)
+ (message "Copied: %s" source)
+ source))
+
+;; Backwards-compat alias. The old name predates the dispatch
+;; extension and several test files still reference it; keep the
+;; alias so external callers and existing tests continue to work.
+(defalias 'cj/copy-path-to-buffer-file-as-kill 'cj/copy-buffer-source-as-kill)
(defun cj/copy-whole-buffer ()
"Copy the entire contents of the current buffer to the kill ring.
@@ -445,7 +475,7 @@ Signals an error if:
:doc "Keymap for buffer and file operations."
"m" #'cj/move-buffer-and-file
"r" #'cj/rename-buffer-and-file
- "p" #'cj/copy-path-to-buffer-file-as-kill
+ "p" #'cj/copy-buffer-source-as-kill
"d" #'cj/delete-buffer-and-file
"D" #'cj/diff-buffer-with-file
"c" cj/copy-buffer-content-map
@@ -480,7 +510,7 @@ Signals an error if:
"C-; b" "buffer and file menu"
"C-; b m" "move file"
"C-; b r" "rename file"
- "C-; b p" "copy file path"
+ "C-; b p" "copy buffer source"
"C-; b d" "delete file"
"C-; b D" "diff buffer with file"
"C-; b c" "buffer copy menu"