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 /tests/test-custom-buffer-file-copy-buffer-source.el | |
| 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 'tests/test-custom-buffer-file-copy-buffer-source.el')
| -rw-r--r-- | tests/test-custom-buffer-file-copy-buffer-source.el | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/tests/test-custom-buffer-file-copy-buffer-source.el b/tests/test-custom-buffer-file-copy-buffer-source.el new file mode 100644 index 00000000..c4e073ae --- /dev/null +++ b/tests/test-custom-buffer-file-copy-buffer-source.el @@ -0,0 +1,144 @@ +;;; test-custom-buffer-file-copy-buffer-source.el --- Tests for cj/copy-buffer-source-as-kill -*- lexical-binding: t; -*- + +;;; Commentary: +;; Tests the dispatch behavior of `cj/copy-buffer-source-as-kill', the +;; major-mode-aware extension of the old +;; `cj/copy-path-to-buffer-file-as-kill' (which is kept as a +;; `defalias' for backwards compat). +;; +;; Dispatch tiers: +;; eww-mode -> (eww-current-url) +;; elfeed-show-mode -> (elfeed-entry-link elfeed-show-entry) +;; dired-mode -> (dired-get-filename nil t) +;; dirvish-mode -> (dired-get-filename nil t) +;; doc-view-mode -> buffer-file-name +;; pdf-view-mode -> buffer-file-name +;; anything else -> buffer-file-name fallback (errors if nil) + +;;; Code: + +(require 'ert) +(require 'cl-lib) + +(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory)) +(require 'custom-buffer-file) + +;; Top-level defvars so let-bindings reach the dynamic var under +;; lexical scope (and stand-ins for vars defined in modes we don't +;; require here). +(defvar elfeed-show-entry nil) + +;;; Fallback to buffer-file-name + +(ert-deftest test-copy-buffer-source-falls-back-to-buffer-file-name () + "Normal: a file-visiting buffer with no special dispatch falls back +to `buffer-file-name'." + (let (kill-ring) + (with-temp-buffer + (setq buffer-file-name "/tmp/notes.txt") + (fundamental-mode) + (cl-letf (((symbol-function 'message) #'ignore)) + (cj/copy-buffer-source-as-kill)) + (should (equal (car kill-ring) "/tmp/notes.txt"))))) + +(ert-deftest test-copy-buffer-source-errors-on-nil-source () + "Error: a buffer with no file and no mode dispatch signals a user-error." + (with-temp-buffer + (fundamental-mode) + (setq buffer-file-name nil) + (should-error (cj/copy-buffer-source-as-kill) :type 'user-error))) + +;;; eww-mode dispatch + +(ert-deftest test-copy-buffer-source-eww-copies-current-url () + "Normal: in eww-mode, copy `(eww-current-url)'." + (let (kill-ring) + (cl-letf (((symbol-function 'eww-current-url) + (lambda () "https://example.org/article"))) + (with-temp-buffer + (setq major-mode 'eww-mode) + (cl-letf (((symbol-function 'message) #'ignore)) + (cj/copy-buffer-source-as-kill)) + (should (equal (car kill-ring) "https://example.org/article")))))) + +;;; elfeed-show-mode dispatch + +(ert-deftest test-copy-buffer-source-elfeed-copies-entry-link () + "Normal: in elfeed-show-mode, copy the entry's link." + (let ((kill-ring nil) + (elfeed-show-entry (list :link "https://feed.test/post/42"))) + (cl-letf (((symbol-function 'elfeed-entry-link) + (lambda (entry) (plist-get entry :link)))) + (with-temp-buffer + (setq major-mode 'elfeed-show-mode) + (cl-letf (((symbol-function 'message) #'ignore)) + (cj/copy-buffer-source-as-kill)) + (should (equal (car kill-ring) "https://feed.test/post/42")))))) + +;;; dired-mode dispatch + +(ert-deftest test-copy-buffer-source-dired-copies-file-at-point () + "Normal: in dired-mode, copy the absolute path of the file at point +(not the dired buffer's `default-directory')." + (let (kill-ring) + (cl-letf (((symbol-function 'dired-get-filename) + (lambda (&optional _localp _no-error) + "/home/u/projects/notes.org"))) + (with-temp-buffer + (setq major-mode 'dired-mode) + (cl-letf (((symbol-function 'message) #'ignore)) + (cj/copy-buffer-source-as-kill)) + (should (equal (car kill-ring) "/home/u/projects/notes.org")))))) + +(ert-deftest test-copy-buffer-source-dirvish-copies-file-at-point () + "Normal: dirvish-mode dispatches identically to dired-mode." + (let (kill-ring) + (cl-letf (((symbol-function 'dired-get-filename) + (lambda (&optional _localp _no-error) + "/home/u/books/the-book.epub"))) + (with-temp-buffer + (setq major-mode 'dirvish-mode) + (cl-letf (((symbol-function 'message) #'ignore)) + (cj/copy-buffer-source-as-kill)) + (should (equal (car kill-ring) "/home/u/books/the-book.epub")))))) + +;;; doc-view / pdf-view dispatch + +(ert-deftest test-copy-buffer-source-doc-view-copies-buffer-file () + "Normal: doc-view-mode copies the underlying file path +(`buffer-file-name')." + (let (kill-ring) + (with-temp-buffer + (setq buffer-file-name "/home/u/papers/paper.pdf" + major-mode 'doc-view-mode) + (cl-letf (((symbol-function 'message) #'ignore)) + (cj/copy-buffer-source-as-kill)) + (should (equal (car kill-ring) "/home/u/papers/paper.pdf"))))) + +(ert-deftest test-copy-buffer-source-pdf-view-copies-buffer-file () + "Normal: pdf-view-mode copies the underlying file path." + (let (kill-ring) + (with-temp-buffer + (setq buffer-file-name "/home/u/books/manual.pdf" + major-mode 'pdf-view-mode) + (cl-letf (((symbol-function 'message) #'ignore)) + (cj/copy-buffer-source-as-kill)) + (should (equal (car kill-ring) "/home/u/books/manual.pdf"))))) + +;;; Backwards-compat alias + +(ert-deftest test-copy-path-old-name-aliases-new-command () + "Backwards compat: `cj/copy-path-to-buffer-file-as-kill' still +resolves to the new `cj/copy-buffer-source-as-kill' via defalias." + (should (eq (symbol-function 'cj/copy-path-to-buffer-file-as-kill) + 'cj/copy-buffer-source-as-kill))) + +;;; Keybinding + +(ert-deftest test-copy-buffer-source-bound-on-b-p () + "Normal: `p' in `cj/buffer-and-file-map' invokes the new command." + (should (eq (keymap-lookup cj/buffer-and-file-map "p") + #'cj/copy-buffer-source-as-kill))) + +(provide 'test-custom-buffer-file-copy-buffer-source) +;;; test-custom-buffer-file-copy-buffer-source.el ends here |
