aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-06-28 13:55:36 -0400
committerCraig Jennings <c@cjennings.net>2026-06-28 13:55:36 -0400
commita8a04377beab10c187e33b9af0536812dca9cd76 (patch)
tree462f5a54e9d7ec9ed9144ad4ea31a0550dee1e65
parent91405050fcce6424e90b520df67256c59e357915 (diff)
downloaddotemacs-a8a04377beab10c187e33b9af0536812dca9cd76.tar.gz
dotemacs-a8a04377beab10c187e33b9af0536812dca9cd76.zip
feat(dashboard): add a weather launcher (wttrin)
A Weather launcher joins the dashboard's top row after Agenda, on key w, drawn with the nf-weather-day_sunny_overcast Weather Icons glyph. It opens the wttrin forecast through call-interactively so wttrin's location prompt runs. A bare (wttrin) call errors, since the command takes the location as a required argument that its interactive form supplies. Row sizes move from 4-4-3-3 to 5-4-3-3. The launcher table stays the single source for both the navigator icons and the keymap.
-rw-r--r--modules/dashboard-config.el7
-rw-r--r--tests/test-dashboard-config-launchers.el30
2 files changed, 23 insertions, 14 deletions
diff --git a/modules/dashboard-config.el b/modules/dashboard-config.el
index daa75fe99..53f19b72b 100644
--- a/modules/dashboard-config.el
+++ b/modules/dashboard-config.el
@@ -54,6 +54,7 @@
(declare-function nerd-icons-mdicon "nerd-icons")
(declare-function nerd-icons-codicon "nerd-icons")
(declare-function nerd-icons-octicon "nerd-icons")
+(declare-function nerd-icons-wicon "nerd-icons")
;; user-constants.el provides the home-directory constant.
(defvar user-home-dir)
@@ -139,6 +140,7 @@ Adjust this if the title doesn't appear centered under the banner image.")
(list "d" #'nerd-icons-faicon "nf-fa-folder_o" "Files" "Dirvish File Manager" (lambda () (dirvish user-home-dir)))
(list "t" #'nerd-icons-devicon "nf-dev-terminal" "Terminal" "Launch Terminal" (lambda () (cj/term-toggle)))
(list "a" #'nerd-icons-mdicon "nf-md-calendar" "Agenda" "Main Org Agenda" (lambda () (cj/main-agenda-display)))
+ (list "w" #'nerd-icons-wicon "nf-weather-day_sunny_overcast" "Weather" "Wttrin Weather Forecast" (lambda () (call-interactively #'wttrin)))
(list "r" #'nerd-icons-faicon "nf-fa-rss_square" "Feeds" "Elfeed Feed Reader" (lambda () (cj/elfeed-open)))
(list "b" #'nerd-icons-codicon "nf-cod-library" "Books" "Calibre Ebook Reader" (lambda () (calibredb)))
(list "f" #'nerd-icons-mdicon "nf-md-school" "Flashcards" "Org-Drill" (lambda () (cj/drill-start)))
@@ -152,9 +154,10 @@ Adjust this if the title doesn't appear centered under the banner image.")
"Dashboard launcher table: (KEY ICON-FN ICON-NAME LABEL TOOLTIP ACTION).
Drives both `dashboard-navigator-buttons' and the dashboard-mode-map keys.")
-(defconst cj/dashboard--row-sizes '(4 4 3 3)
+(defconst cj/dashboard--row-sizes '(5 4 3 3)
"Navigator row lengths. Must sum to the number of `cj/dashboard--launchers'.
-The last row groups Slack, Linear, and Signal together.")
+The top row carries Weather alongside the core tools; the last row groups
+Slack, Linear, and Signal together.")
(defun cj/dashboard--navigator-button (l)
"Build a `dashboard-navigator-buttons' entry from launcher L."
diff --git a/tests/test-dashboard-config-launchers.el b/tests/test-dashboard-config-launchers.el
index e7e5dcd53..53c46caa9 100644
--- a/tests/test-dashboard-config-launchers.el
+++ b/tests/test-dashboard-config-launchers.el
@@ -27,19 +27,20 @@
;; Telegram moved from "g" to "G" so "g" is free for dashboard refresh.
;; Signal ("S") added as the 14th launcher.
-(defconst test-dash--keys '("c" "d" "t" "a" "r" "b" "f" "m" "e" "i" "G" "s" "l" "S"))
+;; Weather ("w") added after Agenda as the 15th launcher (top-row daily glance).
+(defconst test-dash--keys '("c" "d" "t" "a" "w" "r" "b" "f" "m" "e" "i" "G" "s" "l" "S"))
;; ----------------------------- launcher table --------------------------------
(ert-deftest test-dashboard-launchers-keys-in-order ()
- "Normal: 14 launchers with the expected keys in display order."
- (should (= 14 (length cj/dashboard--launchers)))
+ "Normal: 15 launchers with the expected keys in display order."
+ (should (= 15 (length cj/dashboard--launchers)))
(should (equal test-dash--keys (mapcar (lambda (l) (nth 0 l)) cj/dashboard--launchers))))
(ert-deftest test-dashboard-launchers-labels-in-order ()
"Normal: labels in display order (Telegram and Slack reordered so Slack sits
next to Linear on the last navigator row)."
- (should (equal '("Code" "Files" "Terminal" "Agenda" "Feeds" "Books"
+ (should (equal '("Code" "Files" "Terminal" "Agenda" "Weather" "Feeds" "Books"
"Flashcards" "Music" "Email" "IRC" "Telegram" "Slack" "Linear" "Signal")
(mapcar (lambda (l) (nth 3 l)) cj/dashboard--launchers))))
@@ -50,18 +51,19 @@ next to Linear on the last navigator row)."
;; --------------------------- navigator rows ----------------------------------
-(ert-deftest test-dashboard-navigator-rows-grouped-4-4-3-3 ()
- "Normal: navigator derives rows per `cj/dashboard--row-sizes' (4 4 3 3), with
-Slack, Linear, and Signal sharing the last row."
+(ert-deftest test-dashboard-navigator-rows-grouped-5-4-3-3 ()
+ "Normal: navigator derives rows per `cj/dashboard--row-sizes' (5 4 3 3), with
+Weather joining the top row and Slack, Linear, and Signal sharing the last row."
(cl-letf (((symbol-function 'nerd-icons-faicon) (lambda (n &rest _) (concat "I:" n)))
((symbol-function 'nerd-icons-devicon) (lambda (n &rest _) (concat "I:" n)))
((symbol-function 'nerd-icons-mdicon) (lambda (n &rest _) (concat "I:" n)))
((symbol-function 'nerd-icons-octicon) (lambda (n &rest _) (concat "I:" n)))
- ((symbol-function 'nerd-icons-codicon) (lambda (n &rest _) (concat "I:" n))))
+ ((symbol-function 'nerd-icons-codicon) (lambda (n &rest _) (concat "I:" n)))
+ ((symbol-function 'nerd-icons-wicon) (lambda (n &rest _) (concat "I:" n))))
(let ((rows (cj/dashboard--navigator-rows)))
(should (= 4 (length rows)))
- (should (equal '(4 4 3 3) (mapcar #'length rows)))
- (should (equal '("Code" "Files" "Terminal" "Agenda")
+ (should (equal '(5 4 3 3) (mapcar #'length rows)))
+ (should (equal '("Code" "Files" "Terminal" "Agenda" "Weather")
(mapcar (lambda (b) (nth 1 b)) (nth 0 rows))))
(should (equal '("Slack" "Linear" "Signal")
(mapcar (lambda (b) (nth 1 b)) (nth 3 rows))))
@@ -98,7 +100,10 @@ Slack, Linear, and Signal sharing the last row."
((symbol-function 'cj/slack-start) (lambda (&rest _) (push 'slack calls)))
((symbol-function 'cj/telega) (lambda (&rest _) (push 'tg calls)))
((symbol-function 'pearl-list-issues) (lambda (&rest _) (push 'linear calls)))
- ((symbol-function 'cj/signel-message) (lambda (&rest _) (push 'signal calls))))
+ ((symbol-function 'cj/signel-message) (lambda (&rest _) (push 'signal calls)))
+ ;; wttrin is invoked via `call-interactively', so the stub must be
+ ;; a command -- a plain variadic lambda masked the real arity bug.
+ ((symbol-function 'wttrin) (lambda (&rest _) (interactive) (push 'weather calls))))
(cj/dashboard--bind-launchers map)
(dolist (key test-dash--keys)
(call-interactively (keymap-lookup map key)))
@@ -108,7 +113,8 @@ Slack, Linear, and Signal sharing the last row."
(should (memq 'm-toggle calls))
(should (memq 'm-load calls))
(should (memq 'signal calls))
- (should (= 15 (length calls)))))) ; 14 keys, Music fires two
+ (should (memq 'weather calls))
+ (should (= 16 (length calls)))))) ; 15 keys, Music fires two
(provide 'test-dashboard-config-launchers)
;;; test-dashboard-config-launchers.el ends here