diff options
| -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 () |
