diff options
| author | Craig Jennings <c@cjennings.net> | 2026-07-18 15:50:24 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-07-18 15:50:24 -0500 |
| commit | 18dbd316ef55bed3418bd94407426f18ef1b01a0 (patch) | |
| tree | 8c95335793730346bab7577adbfe43e8c6fe9626 | |
| parent | 97445c8b04327317d617fde7be664a82230f3fb5 (diff) | |
| download | dotemacs-18dbd316ef55bed3418bd94407426f18ef1b01a0.tar.gz dotemacs-18dbd316ef55bed3418bd94407426f18ef1b01a0.zip | |
feat(music): mark the current playlist row on its number
Emacs draws the filled cursor only in the selected window, and the playlist dock is glanced at from other windows constantly. The pinned cursor was invisible exactly when it was wanted. The current row's number now renders in inverse video, updated as point moves and re-applied after each renumber. The mark shows whether or not the window has focus, and the row band from hl-line was already sticky.
| -rw-r--r-- | modules/music-config.el | 38 | ||||
| -rw-r--r-- | tests/test-music-config--renumber-rows.el | 55 |
2 files changed, 91 insertions, 2 deletions
diff --git a/modules/music-config.el b/modules/music-config.el index bff0f5ce..e9f7c2bb 100644 --- a/modules/music-config.el +++ b/modules/music-config.el @@ -364,7 +364,8 @@ that right-aligns the metadata drifts point to arbitrary visual columns and snaps every landing back to the row start. An active isearch owns point until it ends; the snap lands when the search exits." (unless (or (bolp) (bound-and-true-p isearch-mode)) - (beginning-of-line))) + (beginning-of-line)) + (cj/music--highlight-current-number)) (defvar-local cj/music--renumber-timer nil "Pending idle timer for the playlist row renumber, or nil.") @@ -401,7 +402,40 @@ debounce timer can outlive the playlist buffer." (propertize (format "%3d " n) 'face 'cj/music-keyhint-face 'cursor t)))) - (forward-line 1)))))))) + (forward-line 1)))) + ;; The rebuild deleted the marked overlay; re-mark the current row. + (setq cj/music--current-number-overlay nil) + (cj/music--highlight-current-number))))) + +(defvar-local cj/music--current-number-overlay nil + "The number overlay currently rendered as the you-are-here mark, or nil.") + +(defun cj/music--set-number-face (ov current) + "Re-render number overlay OV's string; CURRENT non-nil marks it inverse. +Keeps the text and the cursor property, swaps only the face." + (let ((s (overlay-get ov 'before-string))) + (overlay-put ov 'before-string + (propertize (substring-no-properties s) + 'face (if current + '(:inherit cj/music-keyhint-face :inverse-video t) + 'cj/music-keyhint-face) + 'cursor t)))) + +(defun cj/music--highlight-current-number () + "Render the current row's number in inverse video, restoring the last one. +The block cursor draws only in the selected window, and the playlist dock +is glanced at from other windows constantly, so the number itself carries +the you-are-here mark -- visible whether or not the window has focus." + (let ((ov (seq-find (lambda (o) (overlay-get o 'cj-music-row-number)) + (overlays-in (line-beginning-position) + (min (1+ (line-beginning-position)) (point-max)))))) + (unless (eq ov cj/music--current-number-overlay) + (when (and (overlayp cj/music--current-number-overlay) + (overlay-buffer cj/music--current-number-overlay)) + (cj/music--set-number-face cj/music--current-number-overlay nil)) + (setq cj/music--current-number-overlay ov) + (when ov + (cj/music--set-number-face ov t))))) (defun cj/music--schedule-renumber (&rest _) "Debounced renumber of the current playlist buffer after a text change. diff --git a/tests/test-music-config--renumber-rows.el b/tests/test-music-config--renumber-rows.el index 449f6d2e..656bbfc9 100644 --- a/tests/test-music-config--renumber-rows.el +++ b/tests/test-music-config--renumber-rows.el @@ -83,6 +83,61 @@ can fire after the playlist buffer is gone)." (kill-buffer buf) (should-not (cj/music--renumber-rows buf)))) +;;; Current-row indicator + +(ert-deftest test-music-highlight-current-number-marks-current-row () + "Normal: the current row's number renders inverse-video; moving to another +row restores the old one and marks the new one. The block cursor only +draws in the selected window, so the number itself carries the mark." + (with-temp-buffer + (insert "track one\ntrack two\ntrack three\n") + (cj/music--renumber-rows (current-buffer)) + (goto-char (point-min)) + (forward-line 1) + (cj/music--highlight-current-number) + (let ((numbers (test-music-renumber--numbers (current-buffer)))) + (should-not (plist-get (get-text-property 0 'face (nth 0 numbers)) :inverse-video)) + (should (plist-get (get-text-property 0 'face (nth 1 numbers)) :inverse-video))) + (forward-line 1) + (cj/music--highlight-current-number) + (let ((numbers (test-music-renumber--numbers (current-buffer)))) + (should-not (plist-get (get-text-property 0 'face (nth 1 numbers)) :inverse-video)) + (should (plist-get (get-text-property 0 'face (nth 2 numbers)) :inverse-video))))) + +(ert-deftest test-music-highlight-current-number-survives-renumber () + "Boundary: a renumber rebuilds the overlays; the highlight re-applies to +the current row rather than pointing at a dead overlay." + (with-temp-buffer + (insert "track one\ntrack two\n") + (cj/music--renumber-rows (current-buffer)) + (goto-char (point-min)) + (forward-line 1) + (cj/music--highlight-current-number) + (cj/music--renumber-rows (current-buffer)) + (let ((numbers (test-music-renumber--numbers (current-buffer)))) + (should (plist-get (get-text-property 0 'face (nth 1 numbers)) :inverse-video))))) + +(ert-deftest test-music-highlight-current-number-keeps-cursor-property () + "Boundary: re-facing a number keeps the cursor property intact." + (with-temp-buffer + (insert "track one\n") + (cj/music--renumber-rows (current-buffer)) + (goto-char (point-min)) + (cj/music--highlight-current-number) + (let ((s (car (test-music-renumber--numbers (current-buffer))))) + (should (get-text-property 0 'cursor s))))) + +(ert-deftest test-music-ensure-playlist-buffer-sticky-hl-line () + "Normal: hl-line in the playlist stays visible when the window isn't +selected -- the dock is glanced at from other windows constantly." + (let (created) + (cl-letf (((symbol-function 'emms-playlist-mode) #'ignore)) + (unwind-protect + (progn + (setq created (cj/music--ensure-playlist-buffer)) + (should (buffer-local-value 'hl-line-sticky-flag created))) + (when (buffer-live-p created) (kill-buffer created)))))) + ;;; Hook wiring (ert-deftest test-music-renumber-ensure-playlist-buffer-wires-hook () |
