diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-15 00:23:14 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-15 00:23:14 -0500 |
| commit | e3e904b33ed714d74fae01ae1b631d889b39003b (patch) | |
| tree | 42f3da91db16ee763569d9ecd8e85685f032046e /modules | |
| parent | d79ede35e63b8c227886266dc9f00cc10291dfcb (diff) | |
| download | dotemacs-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.el | 52 |
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" |
