branch: elpa/casual
commit 7ae03fe439bf4d4d0be4c06345e58460e3d4814f
Author: Charles Choi <[email protected]>
Commit: Charles Choi <[email protected]>
Initial Entry - Casual Calendar
- Initial entry for Casual Calendar UI.
---
README.org | 8 +
docs/agenda.org | 1 +
docs/bookmarks.org | 1 +
docs/calc.org | 3 +-
docs/calendar.org | 94 +++++
docs/dired.org | 1 +
docs/editkit.org | 1 +
docs/ibuffer.org | 1 +
docs/images/casual-calendar-calendars-menu.png | Bin 0 -> 302886 bytes
docs/images/casual-calendar-diary-menu.png | Bin 0 -> 299188 bytes
docs/images/casual-calendar-lunar-menu.png | Bin 0 -> 408235 bytes
docs/images/casual-calendar-screenshot.png | Bin 0 -> 445243 bytes
docs/images/casual-calendar-settings-menu.png | Bin 0 -> 370442 bytes
docs/info.org | 1 +
docs/isearch.org | 1 +
docs/re-builder.org | 3 +-
lisp/Makefile | 5 +
lisp/Makefile-calendar.make | 31 ++
lisp/casual-calendar-constants.el | 152 ++++++++
lisp/casual-calendar-settings.el | 170 +++++++++
lisp/casual-calendar-utils.el | 471 +++++++++++++++++++++++++
lisp/casual-calendar.el | 100 ++++++
lisp/casual.el | 4 +
tests/Makefile | 5 +
tests/casual-calendar-test-utils.el | 41 +++
tests/casual-lib-test-utils.el | 6 +
tests/test-casual-calendar-constants.el | 65 ++++
tests/test-casual-calendar-settings.el | 61 ++++
tests/test-casual-calendar-utils.el | 316 +++++++++++++++++
tests/test-casual-calendar.el | 130 +++++++
30 files changed, 1670 insertions(+), 2 deletions(-)
diff --git a/README.org b/README.org
index 48f43a7435..878750527f 100644
--- a/README.org
+++ b/README.org
@@ -20,6 +20,13 @@ Casual is organized into different user interface (UI)
libraries tuned for diffe
[[file:docs/calc.org][file:docs/images/casual-calc-tmenu.png]]
+** [[file:docs/calendar.org][Calendar]] (Elisp library: ~casual-calendar~)
+
+An interface for
[[https://www.gnu.org/software/emacs/manual/html_node/emacs/Calendar_002fDiary.html][Calendar
& Diary]].
+
+[[file:docs/images/casual-calendar-screenshot.png]]
+
+
** [[file:docs/dired.org][Dired]] (Elisp library: ~casual-dired~)
An interface for the venerable file manager Dired.
@@ -86,6 +93,7 @@ Configuration of a particular Casual user interface is
performed per mode. Go to
- [[file:docs/agenda.org::*Install][Agenda]]
- [[file:docs/bookmarks.org::*Install][Bookmarks]]
- [[file:docs/calc.org::*Install][Calc]]
+- [[file:docs/calendar.org::*Install][Calendar]]
- [[file:docs/dired.org::*Install][Dired]]
- [[file:docs/editkit.org::*Install][EditKit]]
- [[file:docs/ibuffer.org::*Install][IBuffer]]
diff --git a/docs/agenda.org b/docs/agenda.org
index 7a6a6827ac..60b1abfee5 100644
--- a/docs/agenda.org
+++ b/docs/agenda.org
@@ -73,6 +73,7 @@ If you enjoy using Casual Agenda, consider making a modest
financial contributio
* See Also
- [[file:bookmarks.org][Bookmarks]]
- [[file:calc.org][Calc]]
+- [[file:calendar.org][Calendar]]
- [[file:dired.org][Dired]]
- [[file:editkit.org][EditKit (numerous editing commands)]]
- [[file:ibuffer.org][IBuffer]]
diff --git a/docs/bookmarks.org b/docs/bookmarks.org
index 1b664f80fc..91e7f32319 100644
--- a/docs/bookmarks.org
+++ b/docs/bookmarks.org
@@ -70,6 +70,7 @@ If you enjoy using Casual Bookmarks, consider making a modest
financial contribu
* See Also
- [[file:agenda.org][Agenda]]
- [[file:calc.org][Calc]]
+- [[file:calendar.org][Calendar]]
- [[file:dired.org][Dired]]
- [[file:editkit.org][EditKit (numerous editing commands)]]
- [[file:ibuffer.org][IBuffer]]
diff --git a/docs/calc.org b/docs/calc.org
index 43de6ecdd7..d1d5b5c999 100644
--- a/docs/calc.org
+++ b/docs/calc.org
@@ -6,7 +6,7 @@ An opinionated
[[https://github.com/magit/transient][Transient]]-based user inte
[[file:images/casual-calc-tmenu.png]]
* Install
-Casual Calc is available on [[https://melpa.org/#/casual-calc][MELPA]].
+Casual Calc is available on [[https://melpa.org/#/casual][MELPA]].
If installed via ~list-packages~ then add this line to your Emacs
initialization file.
#+begin_src elisp :lexical no
@@ -56,6 +56,7 @@ If you enjoy using Casual Calc, consider making a modest
financial contribution
* See Also
- [[file:agenda.org][Agenda]]
- [[file:bookmarks.org][Bookmarks]]
+- [[file:calendar.org][Calendar]]
- [[file:dired.org][Dired]]
- [[file:editkit.org][EditKit (numerous editing commands)]]
- [[file:ibuffer.org][IBuffer]]
diff --git a/docs/calendar.org b/docs/calendar.org
new file mode 100644
index 0000000000..ed585d05da
--- /dev/null
+++ b/docs/calendar.org
@@ -0,0 +1,94 @@
+[[../README.org][❮ Back to Casual]]
+
+* Casual Calendar
+An opinionated [[https://github.com/magit/transient][Transient]]-based user
interface for
[[https://www.gnu.org/software/emacs/manual/html_node/emacs/Calendar_002fDiary.html][Calendar]].
+
+[[file:images/casual-calendar-screenshot.png]]
+
+* Install
+If installed via [[https://melpa.org/#/casual][MELPA]] then add these lines to
your Emacs initialization file with your binding of preference.
+#+begin_src elisp :lexical no
+ (require 'casual-calendar) ; optional if using autoloaded menu
+ (keymap-set calendar-mode-map "C-o" #'casual-calendar)
+#+end_src
+
+* Usage
+** Basic Usage
+
+Whenever the ~calendar~ window (showing three months) is raised, the Casual
user interface for it can be invoked via the command ~casual-calendar~. This
command is typically bound to a keybinding (e.g. ~C-o~). The menu displayed
will offer the following activities:
+
+- Navigation commands organized by time (day, week, month, year).
+- Conversion commands to different calendar systems.
+- Holiday-related commands.
+- Diary-related commands.
+- Almanac commands.
+
+Also made available is access to a Settings menu (more below) and to the Info
documentation for ~calendar~.
+
+** Diary & Goto Menu
+
+From the main menu, choosing “(D) Diary & Goto›” will present choices for
diary event insertion and to “goto” a particular date via different
specifications.
+
+[[file:images/casual-calendar-diary-menu.png]]
+
+** Calendar System Date Conversion
+Calendar supports conversion of dates from Gregorian (default) to a number of
different calendar systems. Choose "(c) Conversions›" from the main menu to
select from a list of such calendars.
+
+[[file:images/casual-calendar-calendars-menu.png]]
+
+ Supported calendar systems:
+
+- Astronomical
+- Bahá’í
+- Ethiopic
+- French Revolutionary
+- Hebrew
+- Islamic
+- Julian
+- Lunar (Chinese)
+- Mayan
+- Persian
+
+Selecting a calendar system will raise a menu that offers date conversion
commands between it and the Gregorian system. In the screenshot below, the
Lunar (Chinese) calendar system menu is shown.
+
+To convert a Gregorian date to Lunar (Chinese):
+
+1. Move cursor (point) in Calendar window to desired date. (The command “(g)
Goto…” can be used to accomplish this.)
+2. Choose “(c) Date at Cursor”.
+
+To convert a Lunar (Chinese) date to Gregorian:
+
+1. Choose “(G) Goto…” and follow the prompts.
+
+
+[[file:images/casual-calendar-lunar-menu.png]]
+
+Certain non-Gregorian calendar systems are supported by the diary (Bahá’í,
Hebrew, Islamic, Lunar (Chinese)). For such systems, their menus will offer
choices to insert diary events.
+
+Note that inserting non-Gregorian diary events require configuration of the
variables ~diary-nongregorian-listing-hook~ and
~diary-nongregorian-marking-hook~ as detailed in
[[https://www.gnu.org/software/emacs/manual/html_node/emacs/Non_002dGregorian-Diary.html][(emacs)
Non-Gregorian Diary]].
+
+Both of these variables can be configured from the Calendar Settings menu.
+
+** Settings Menu
+From the main menu, choosing “(,) Settings” will provide a menu of frequently
configured calendar and diary-related variables.
+
+[[file:images/casual-calendar-settings-menu.png]]
+
+** Unicode Symbol Support
+By enabling “Use Unicode Symbols” from the Settings menu, Casual Calendar will
use Unicode symbols as appropriate in its menus.
+
+* Sponsorship
+If you enjoy using Casual Calendar, consider making a modest financial
contribution to help support its development and maintenance.
+
+[[https://www.buymeacoffee.com/kickingvegas][file:images/default-yellow.png]]
+
+* See Also
+- [[file:agenda.org][Agenda]]
+- [[file:bookmarks.org][Bookmarks]]
+- [[file:calc.org][Calc]]
+- [[file:dired.org][Dired]]
+- [[file:editkit.org][EditKit (numerous editing commands)]]
+- [[file:ibuffer.org][IBuffer]]
+- [[file:info.org][Info]]
+- [[file:isearch.org][I-Search]]
+- [[file:re-builder.org][RE-Builder]]
diff --git a/docs/dired.org b/docs/dired.org
index 1951f6308c..2f09088cdc 100644
--- a/docs/dired.org
+++ b/docs/dired.org
@@ -152,6 +152,7 @@ If you enjoy using Casual Dired, consider making a modest
financial contribution
- [[file:agenda.org][Agenda]]
- [[file:bookmarks.org][Bookmarks]]
- [[file:calc.org][Calc]]
+- [[file:calendar.org][Calendar]]
- [[file:editkit.org][EditKit (numerous editing commands)]]
- [[file:ibuffer.org][IBuffer]]
- [[file:info.org][Info]]
diff --git a/docs/editkit.org b/docs/editkit.org
index 52bbf01eec..2e205aff3c 100644
--- a/docs/editkit.org
+++ b/docs/editkit.org
@@ -168,6 +168,7 @@ If you enjoy using Casual EditKit, consider making a modest
financial contributi
- [[file:agenda.org][Org Agenda]]
- [[file:bookmarks.org][Bookmarks]]
- [[file:calc.org][Calc]]
+- [[file:calendar.org][Calendar]]
- [[file:dired.org][Dired]]
- [[file:ibuffer.org][IBuffer]]
- [[file:info.org][Info]]
diff --git a/docs/ibuffer.org b/docs/ibuffer.org
index f132ef76b5..25b30ee708 100644
--- a/docs/ibuffer.org
+++ b/docs/ibuffer.org
@@ -163,6 +163,7 @@ If you enjoy using Casual IBuffer, consider making a modest
financial contributi
- [[file:agenda.org][Agenda]]
- [[file:bookmarks.org][Bookmarks]]
- [[file:calc.org][Calc]]
+- [[file:calendar.org][Calendar]]
- [[file:editkit.org][EditKit (numerous editing commands)]]
- [[file:info.org][Info]]
- [[file:isearch.org][I-Search]]
diff --git a/docs/images/casual-calendar-calendars-menu.png
b/docs/images/casual-calendar-calendars-menu.png
new file mode 100644
index 0000000000..f87bcdd580
Binary files /dev/null and b/docs/images/casual-calendar-calendars-menu.png
differ
diff --git a/docs/images/casual-calendar-diary-menu.png
b/docs/images/casual-calendar-diary-menu.png
new file mode 100644
index 0000000000..55d8f4e1c3
Binary files /dev/null and b/docs/images/casual-calendar-diary-menu.png differ
diff --git a/docs/images/casual-calendar-lunar-menu.png
b/docs/images/casual-calendar-lunar-menu.png
new file mode 100644
index 0000000000..132e1459a5
Binary files /dev/null and b/docs/images/casual-calendar-lunar-menu.png differ
diff --git a/docs/images/casual-calendar-screenshot.png
b/docs/images/casual-calendar-screenshot.png
new file mode 100644
index 0000000000..2b4ae27d8c
Binary files /dev/null and b/docs/images/casual-calendar-screenshot.png differ
diff --git a/docs/images/casual-calendar-settings-menu.png
b/docs/images/casual-calendar-settings-menu.png
new file mode 100644
index 0000000000..66c03a0c9a
Binary files /dev/null and b/docs/images/casual-calendar-settings-menu.png
differ
diff --git a/docs/info.org b/docs/info.org
index caed3b3fe6..6c3032c7d1 100644
--- a/docs/info.org
+++ b/docs/info.org
@@ -55,6 +55,7 @@ If you enjoy using Casual Info, consider making a modest
financial contribution
- [[file:agenda.org][Agenda]]
- [[file:bookmarks.org][Bookmarks]]
- [[file:calc.org][Calc]]
+- [[file:calendar.org][Calendar]]
- [[file:dired.org][Dired]]
- [[file:editkit.org][EditKit (numerous editing commands)]]
- [[file:ibuffer.org][IBuffer]]
diff --git a/docs/isearch.org b/docs/isearch.org
index 55e561d10e..2294ddfd8a 100644
--- a/docs/isearch.org
+++ b/docs/isearch.org
@@ -64,6 +64,7 @@ If you enjoy using Casual I-Search, consider making a modest
financial contribut
- [[file:agenda.org][Agenda]]
- [[file:bookmarks.org][Bookmarks]]
- [[file:calc.org][Calc]]
+- [[file:calendar.org][Calendar]]
- [[file:dired.org][Dired]]
- [[file:editkit.org][EditKit (numerous editing commands)]]
- [[file:ibuffer.org][IBuffer]]
diff --git a/docs/re-builder.org b/docs/re-builder.org
index 351d79b3ff..d94762a001 100644
--- a/docs/re-builder.org
+++ b/docs/re-builder.org
@@ -6,7 +6,7 @@ An opinionated
[[https://github.com/magit/transient][Transient]]-based user inte
[[file:images/casual-re-builder-screenshot.png]]
* Install
-If installed via [[https://melpa.org/#/casual-re-builder][MELPA]] then add
these lines to your Emacs initialization file with your binding of preference.
+If installed via [[https://melpa.org/#/casual][MELPA]] then add these lines to
your Emacs initialization file with your binding of preference.
#+begin_src elisp :lexical no
(require 'casual-re-builder) ; optional
(keymap-set reb-mode-map "C-o" #'casual-re-builder-tmenu)
@@ -62,6 +62,7 @@ If you enjoy using Casual RE-Builder, consider making a
modest financial contrib
- [[file:agenda.org][Agenda]]
- [[file:bookmarks.org][Bookmarks]]
- [[file:calc.org][Calc]]
+- [[file:calendar.org][Calendar]]
- [[file:dired.org][Dired]]
- [[file:editkit.org][EditKit (numerous editing commands)]]
- [[file:ibuffer.org][IBuffer]]
diff --git a/lisp/Makefile b/lisp/Makefile
index 5c115f9016..b387f3cda4 100644
--- a/lisp/Makefile
+++ b/lisp/Makefile
@@ -21,6 +21,7 @@ lib-tests \
agenda-tests \
bookmarks-tests \
calc-tests \
+calendar-tests \
dired-tests \
editkit-tests \
ibuffer-tests \
@@ -34,6 +35,7 @@ tests: lib-tests \
agenda-tests \
bookmarks-tests \
calc-tests \
+calendar-tests \
dired-tests \
editkit-tests \
ibuffer-tests \
@@ -53,6 +55,9 @@ bookmarks-tests:
calc-tests:
$(MAKE) -C $(SRC_DIR) -f Makefile-calc.make tests
+calendar-tests:
+ $(MAKE) -C $(SRC_DIR) -f Makefile-calendar.make tests
+
dired-tests:
$(MAKE) -C $(SRC_DIR) -f Makefile-dired.make tests
diff --git a/lisp/Makefile-calendar.make b/lisp/Makefile-calendar.make
new file mode 100644
index 0000000000..5108a54435
--- /dev/null
+++ b/lisp/Makefile-calendar.make
@@ -0,0 +1,31 @@
+##
+# Copyright 2024 Charles Y. Choi
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+include Makefile--defines.make
+
+PACKAGE_NAME=casual-calendar
+ELISP_INCLUDES=casual-calendar-constants.el \
+casual-calendar-utils.el \
+casual-calendar-settings.el
+ELISP_PACKAGES=
+ELISP_TEST_INCLUDES=casual-calendar-test-utils.el
+PACKAGE_PATHS= \
+-L $(EMACS_ELPA_DIR)/compat-30.0.0.0 \
+-L $(EMACS_ELPA_DIR)/seq-2.24 \
+-L $(EMACS_ELPA_DIR)/transient-current \
+-L $(CASUAL_LIB_LISP_DIR)
+
+include Makefile--rules.make
diff --git a/lisp/casual-calendar-constants.el
b/lisp/casual-calendar-constants.el
new file mode 100644
index 0000000000..88742c3b90
--- /dev/null
+++ b/lisp/casual-calendar-constants.el
@@ -0,0 +1,152 @@
+;;; casual-calendar-constants.el --- Casual Calendar Constants -*-
lexical-binding: t; -*-
+
+;; Copyright (C) 2024 Charles Choi
+
+;; Author: Charles Choi <[email protected]>
+;; Keywords: calendar
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+(require 'calendar)
+(require 'casual-lib)
+
+(defconst casual-calendar-unicode-db
+ '((:previous . '("↑" "Previous"))
+ (:next . '("↓" "Next"))
+
+ (:behind . '("←" "Behind"))
+ (:ahead . '("→" "Ahead"))
+
+ (:beginning . '("⇤" "Beginning"))
+ (:end . '("⇥" "End"))
+
+ (:back-3-months . '("← 3 months" "-3 months"))
+ (:forward-3-months . '("→ 3 months" "+3 months"))
+
+ (:redraw . '("⟳" "Refresh"))
+ ;;(:goto . '("🚀" "Goto"))
+ (:goto . '("🔎" "Goto"))
+ (:sunrise . '("🌅" "Sunrise"))
+ (:lunar . '("🌙" "Lunar")))
+
+ "Unicode symbol DB to use for Calendar Transient menus.")
+
+(defun casual-calendar-unicode-get (key)
+ "Lookup Unicode symbol for KEY in DB.
+
+- KEY symbol used to lookup Unicode symbol in DB.
+
+If the value of customizable variable `casual-lib-use-unicode'
+is non-nil, then the Unicode symbol is returned, otherwise a
+plain ASCII-range string."
+ (casual-lib-unicode-db-get key casual-calendar-unicode-db))
+
+
+(defconst casual-calendar--navigation-group
+ ["Navigation"
+ ["Day"
+ ("b" "Behind" calendar-backward-day
+ :description (lambda () (casual-calendar-unicode-get :behind))
+ :transient t)
+ ("f" "Ahead" calendar-forward-day
+ :description (lambda () (casual-calendar-unicode-get :ahead))
+ :transient t)
+ ("." "Today" calendar-goto-today :transient t)
+ ("g" "Goto…" calendar-goto-date
+ ;; :description (lambda () (format "%s…" (casual-calendar-unicode-get
:goto)))
+ :transient t)]
+ ["Week"
+ ("p" "Behind" calendar-backward-week
+ :description (lambda () (casual-calendar-unicode-get :behind))
+ :transient t)
+ ("n" "Ahead" calendar-forward-week
+ :description (lambda () (casual-calendar-unicode-get :ahead))
+ :transient t)
+ ("a" "Beginning" calendar-beginning-of-week
+ :description (lambda () (casual-calendar-unicode-get :beginning))
+ :transient t)
+ ("e" "End" calendar-end-of-week
+ :description (lambda () (casual-calendar-unicode-get :end))
+ :transient t)
+ ("w" "Goto…" calendar-iso-goto-week
+ ;; :description (lambda () (format "%s…" (casual-calendar-unicode-get
:goto)))
+ :transient t)]
+
+ ["Month"
+ :pad-keys t
+ ("{" "Behind" calendar-backward-month
+ :description (lambda () (casual-calendar-unicode-get :behind))
+ :transient t)
+ ("}" "Ahead" calendar-forward-month
+ :description (lambda () (casual-calendar-unicode-get :ahead))
+ :transient t)
+ ("M-a" "Beginning" calendar-beginning-of-month
+ :description (lambda () (casual-calendar-unicode-get :beginning))
+ :transient t)
+ ("M-e" "End" calendar-end-of-month
+ :description (lambda () (casual-calendar-unicode-get :end))
+ :transient t)
+ ("o" "Goto…" calendar-other-month
+ ;; :description (lambda () (format "%s…" (casual-calendar-unicode-get
:goto)))
+ :transient t)]
+
+ ["Year"
+ :pad-keys t
+ ("M-[" "Behind" calendar-backward-year
+ :description (lambda () (casual-calendar-unicode-get :behind))
+ :transient t)
+ ("M-]" "Ahead" calendar-forward-year
+ :description (lambda () (casual-calendar-unicode-get :ahead))
+ :transient t)
+ ("[" "Beginning" calendar-beginning-of-year
+ :description (lambda () (casual-calendar-unicode-get :beginning))
+ :transient t)
+ ("]" "End" calendar-end-of-year
+ :description (lambda () (casual-calendar-unicode-get :end))
+ :transient t)]
+
+ ["Scroll"
+ :pad-keys t
+ ("<" "Behind" calendar-scroll-right
+ :description (lambda () (casual-calendar-unicode-get :behind))
+ :transient t)
+ (">" "Ahead" calendar-scroll-left
+ :description (lambda () (casual-calendar-unicode-get :ahead))
+ :transient t)
+ ("-" "-3 months" calendar-scroll-right-three-months
+ :description (lambda () (casual-calendar-unicode-get :back-3-months))
+ :transient t)
+ ("+" "+3 months" calendar-scroll-left-three-months
+ :description (lambda () (casual-calendar-unicode-get :forward-3-months))
+ :transient t)
+ ("C-l" "Redraw" calendar-redraw
+ :description (lambda () (casual-calendar-unicode-get :redraw))
+ :transient t)]]
+ "Transient navigation group for calendar.")
+
+
+(defconst casual-calendar--menu-navigation-group
+ [:class transient-row
+ (casual-lib-quit-one)
+ ("RET" "Dismiss" transient-quit-all)
+ (casual-lib-quit-all)]
+ "Transient menu navigation group for calendar.")
+
+(provide 'casual-calendar-constants)
+;;; casual-calendar-constants.el ends here
diff --git a/lisp/casual-calendar-settings.el b/lisp/casual-calendar-settings.el
new file mode 100644
index 0000000000..17b91c0df0
--- /dev/null
+++ b/lisp/casual-calendar-settings.el
@@ -0,0 +1,170 @@
+;;; casual-calendar-settings.el --- Casual Calendar Settings -*-
lexical-binding: t; -*-
+
+;; Copyright (C) 2024 Charles Choi
+
+;; Author: Charles Choi <[email protected]>
+;; Keywords: tools
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+
+;;; Code:
+(require 'solar)
+(require 'org-agenda)
+(require 'casual-calendar-constants)
+
+(transient-define-prefix casual-calendar-settings-tmenu ()
+ "Casual Calendar & Diary settings menu.
+
+Customize settings for Calendar and Diary modes."
+
+ ["Calendar"
+ ["Customize"
+ ("G" "Calendar Group" casual-calendar--customize-calendar-group)
+ ("H" "Mark Holidays" casual-calendar--customize-calendar-mark-holidays-flag
+ :description (lambda ()
+ (casual-lib-checkbox-label
+ calendar-mark-holidays-flag
+ "Mark Holidays")))]
+
+ ["Hooks"
+ ("v" "Move Hook" casual-calendar--customize-calendar-move-hook)]
+
+ ["Location"
+ ("N" "Location Name" casual-calendar--customize-calendar-location-name)
+ ("A" "Latitude" casual-calendar--customize-calendar-latitude)
+ ("O" "Longitude" casual-calendar--customize-calendar-longitude)]]
+
+ ["Diary"
+ ["Customize"
+ ("D" "Diary Group" casual-calendar--customize-diary-group)]
+
+ ["Hooks"
+ ("l" "List" casual-calendar--customize-diary-list-entries-hook)
+ ("m" "Mark" casual-calendar--customize-diary-mark-entries-hook)]
+
+ ["Non-Gregorian Hooks"
+ ("L" "List" casual-calendar--customize-diary-nongregorian-listing-hook)
+ ("M" "Mark" casual-calendar--customize-diary-nongregorian-marking-hook)]
+
+ ["Org Agenda"
+ ("d" "Include Diary" casual-calendar--customize-org-agenda-include-diary
+ :description (lambda ()
+ (casual-lib-checkbox-label
+ org-agenda-include-diary
+ "Include Diary")))]]
+
+ ["General"
+ (casual-lib-customize-unicode)
+ (casual-lib-customize-hide-navigation)]
+
+ [:class transient-row
+ (casual-lib-quit-one)
+ ("a" "About" casual-calendar-about :transient nil)
+
+ (casual-lib-quit-all)])
+
+(defun casual-calendar--customize-calendar-group ()
+ "Customize calendar group."
+ (interactive)
+ (customize-group "calendar"))
+
+(defun casual-calendar--customize-diary-group ()
+ "Customize diary group."
+ (interactive)
+ (customize-group "diary"))
+
+(defun casual-calendar--customize-org-agenda-include-diary ()
+ "Customize variable `org-agenda-include-diary'."
+ (interactive)
+ (customize-variable 'org-agenda-include-diary))
+
+(defun casual-calendar--customize-diary-list-entries-hook ()
+ "Customize variable `diary-list-entries-hook'."
+ (interactive)
+ (customize-variable 'diary-list-entries-hook))
+
+(defun casual-calendar--customize-diary-mark-entries-hook ()
+ "Customize variable `diary-mark-entries-hook'."
+ (interactive)
+ (customize-variable 'diary-mark-entries-hook))
+
+(defun casual-calendar--customize-diary-nongregorian-listing-hook ()
+ "Customize variable `diary-nongregorian-listing-hook'."
+ (interactive)
+ (customize-variable 'diary-nongregorian-listing-hook))
+
+(defun casual-calendar--customize-diary-nongregorian-marking-hook ()
+ "Customize variable `diary-nongregorian-marking-hook'."
+ (interactive)
+ (customize-variable 'diary-nongregorian-marking-hook))
+
+(defun casual-calendar--customize-calendar-mark-holidays-flag ()
+ "Customize variable `calendar-mark-holidays-flag'."
+ (interactive)
+ (customize-variable 'calendar-mark-holidays-flag))
+
+(defun casual-calendar--customize-calendar-location-name ()
+ "Customize variable `calendar-location-name'."
+ (interactive)
+ (customize-variable 'calendar-location-name))
+
+(defun casual-calendar--customize-calendar-latitude ()
+ "Customize variable `calendar-latitude'."
+ (interactive)
+ (customize-variable 'calendar-latitude))
+
+(defun casual-calendar--customize-calendar-longitude ()
+ "Customize variable `calendar-longitude'."
+ (interactive)
+ (customize-variable 'calendar-longitude))
+
+(defun casual-calendar--customize-calendar-move-hook ()
+ "Customize variable `calendar-move-hook'."
+ (interactive)
+ (customize-variable 'calendar-move-hook))
+
+
+(defun casual-calendar-about-calendar ()
+ "Casual Calendar is a Transient menu for Calendar.
+
+Learn more about using Casual Calendar at our discussion group on GitHub.
+Any questions or comments about it should be made there.
+URL `https://github.com/kickingvegas/casual/discussions'
+
+If you find a bug or have an enhancement request, please file an issue.
+Our best effort will be made to answer it.
+URL `https://github.com/kickingvegas/casual/issues'
+
+If you enjoy using Casual Calendar, consider making a modest financial
+contribution to help support its development and maintenance.
+URL `https://www.buymeacoffee.com/kickingvegas'
+
+Casual Calendar was conceived and crafted by Charles Choi in
+San Francisco, California.
+
+Thank you for using Casual Calendar.
+
+Always choose love."
+ (ignore))
+
+(defun casual-calendar-about ()
+ "About information for Casual Calendar."
+ (interactive)
+ (describe-function #'casual-calendar-about-calendar))
+
+(provide 'casual-calendar-settings)
+;;; casual-calendar-settings.el ends here
diff --git a/lisp/casual-calendar-utils.el b/lisp/casual-calendar-utils.el
new file mode 100644
index 0000000000..94a70d012f
--- /dev/null
+++ b/lisp/casual-calendar-utils.el
@@ -0,0 +1,471 @@
+;;; casual-calendar-utils.el --- Casual Calendar Utils -*- lexical-binding: t;
-*-
+
+;; Copyright (C) 2024 Charles Choi
+
+;; Author: Charles Choi <[email protected]>
+;; Keywords: tools
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+
+;;; Code:
+(require 'casual-calendar-constants)
+
+(transient-define-prefix casual-calendar-diary-and-goto-tmenu ()
+ "Diary Entry Insertion & Goto Date menu.
+
+Diary entry insertion and general goto date commands are offered
+by this menu."
+
+ ["Diary and Goto"
+ ["Diary Insert"
+ ("e" "Entry" diary-insert-entry :transient t)
+ ("w" "Weekly" diary-insert-weekly-entry :transient t)
+ ("m" "Monthly" diary-insert-monthly-entry :transient t)
+ ("y" "Yearly" diary-insert-yearly-entry :transient t)
+ ("a" "Anniversary" diary-insert-anniversary-entry :transient t)]
+
+ ["Goto"
+ ("g" "Date…" calendar-goto-date :transient t)
+ ("i" "ISO Date…" calendar-iso-goto-date :transient t)
+ ("d" "Day of Year…" calendar-goto-day-of-year :transient t)]]
+
+ casual-calendar--menu-navigation-group)
+
+(transient-define-prefix casual-calendar-conversions-tmenu ()
+ "Casual Calendar Conversions Menu.
+
+Selection of different calendar systems.
+
+- Astronomical
+- Bahá’í
+- Ethiopic
+- French Revolutionary
+- Hebrew
+- Islamic
+- Julian
+- Lunar (Chinese)
+- Mayan
+- Persian
+
+Consult info node `(emacs) Other Calendars' for more detail on
+specific supported non-Gregorian calendar system behavior."
+
+ ["Calendars"
+ [("a" "Astronomical›" casual-calendar-astro-tmenu)
+ ("b" "Bahá’í›" casual-calendar-bahai-tmenu)
+ ("c" "Coptic›" casual-calendar-coptic-tmenu)]
+
+ [("e" "Ethiopic›" casual-calendar-ethiopic-tmenu)
+ ("f" "French Revolutionary›" casual-calendar-french-tmenu)
+ ("h" "Hebrew›" casual-calendar-hebrew-tmenu)]
+
+ [("i" "Islamic›" casual-calendar-islamic-tmenu)
+ ("j" "Julian›" casual-calendar-julian-tmenu)
+ ("l" "Lunar (Chinese)›" casual-calendar-lunar-tmenu)]
+
+ [("m" "Mayan›" casual-calendar-mayan-tmenu)
+ ("p" "Persian›" casual-calendar-persian-tmenu)]]
+
+ ["All"
+ ("A" "Convert to all" calendar-print-other-dates :transient t)]
+
+ [:class transient-row
+ (casual-lib-quit-one)
+ ("RET" "Dismiss" transient-quit-all)
+ ("I" "ⓘ Info" (lambda ()
+ (interactive)
+ (calendar-exit)
+ (info "(emacs) Other Calendars")))
+ (casual-lib-quit-all)])
+
+(transient-define-prefix casual-calendar-lunar-tmenu ()
+ "Casual Calendar Lunar (Chinese) Calendar Menu.
+
+This menu provides date conversion commands between a Gregorian
+and a Lunar (Chinese) calendar.
+
+To convert a Gregorian date to Lunar (Chinese):
+
+ 1. Move cursor (point) in Calendar window to desired date.
+ (The command “(g) Goto…” can be used to accomplish this.)
+
+ 2. Choose “(c) Date at Cursor”.
+
+To convert a Lunar (Chinese) date to Gregorian:
+
+ 1. Choose “(G) Goto…” and follow the prompts.
+
+Diary insertion of Lunar (Chinese) events are supported provided
+proper configuration of the variables
+`diary-nongregorian-listing-hook' and
+`diary-nongregorian-marking-hook' as detailed in info
+node `(emacs) Non-Gregorian Diary'.
+
+Both of these variables can be configured from the Casual Calendar
+menu `casual-calendar-settings-tmenu'."
+
+ ["Lunar (Chinese) Calendar"
+ ["Date"
+ ("c" "Date at cursor" calendar-chinese-print-date :transient t)
+ ("G" "Goto…" calendar-chinese-goto-date :transient t)]
+
+ ["Diary Insert"
+ ("i" "Point" diary-chinese-insert-entry)
+ ("m" "Monthly" diary-chinese-insert-monthly-entry)
+ ("y" "Year" diary-chinese-insert-yearly-entry)
+ ("A" "Anniversary" diary-chinese-insert-anniversary-entry)]
+
+ ["Diary View"
+ ("d" "View" diary-view-entries :transient t)
+ ("s" "Show all" diary-show-all-entries)]]
+
+ casual-calendar--navigation-group
+ casual-calendar--menu-navigation-group)
+
+(transient-define-prefix casual-calendar-astro-tmenu ()
+ "Casual Calendar Astronomical calendar menu.
+
+This menu provides date conversion commands between a Gregorian
+and a Astronomical calendar.
+
+To convert a Gregorian date to Astronomical:
+
+ 1. Move cursor (point) in Calendar window to desired date.
+ (The command “(g) Goto…” can be used to accomplish this.)
+
+ 2. Choose “(c) Date at Cursor”.
+
+To convert a Astronomical date to Gregorian:
+
+ 1. Choose “(G) Goto…” and follow the prompts."
+
+ ["Astronomical Calendar"
+ ["Date"
+ ("c" "Day number at cursor" calendar-astro-print-day-number :transient t)
+ ("G" "Goto…" calendar-astro-goto-day-number :transient t)]
+
+ ["Diary View"
+ ("d" "View" diary-view-entries :transient t)
+ ("s" "Show all" diary-show-all-entries)]]
+
+ casual-calendar--navigation-group
+ casual-calendar--menu-navigation-group)
+
+(transient-define-prefix casual-calendar-islamic-tmenu ()
+ "Casual Calendar Islamic calendar menu.
+
+This menu provides date conversion commands between a Gregorian
+and an Islamic calendar.
+
+To convert a Gregorian date to Islamic:
+
+ 1. Move cursor (point) in Calendar window to desired date.
+ (The command “(g) Goto…” can be used to accomplish this.)
+
+ 2. Choose “(c) Date at Cursor”.
+
+To convert an Islamic date to Gregorian:
+
+ 1. Choose “(G) Goto…” and follow the prompts.
+
+Diary insertion of Islamic events are supported provided
+proper configuration of the variables
+`diary-nongregorian-listing-hook' and
+`diary-nongregorian-marking-hook' as detailed in info
+node `(emacs) Non-Gregorian Diary'.
+
+Both of these variables can be configured from the Casual Calendar
+menu `casual-calendar-settings-tmenu'."
+ ["Islamic Calendar"
+ ["Date"
+ ("c" "Date at cursor" calendar-islamic-print-date :transient t)
+ ("G" "Goto…" calendar-islamic-goto-date :transient t)]
+
+ ["Diary Insert"
+ ("i" "Point" diary-islamic-insert-entry)
+ ("m" "Monthly" diary-islamic-insert-monthly-entry)
+ ("y" "Year" diary-islamic-insert-yearly-entry)]
+
+ ["Diary View"
+ ("d" "View" diary-view-entries :transient t)
+ ("s" "Show all" diary-show-all-entries)]]
+
+ casual-calendar--navigation-group
+ casual-calendar--menu-navigation-group)
+
+(transient-define-prefix casual-calendar-hebrew-tmenu ()
+ "Casual Calendar Hebrew calendar menu.
+
+This menu provides date conversion commands between a Gregorian
+and a Hebrew calendar.
+
+To convert a Gregorian date to Hebrew:
+
+ 1. Move cursor (point) in Calendar window to desired date.
+ (The command “(g) Goto…” can be used to accomplish this.)
+
+ 2. Choose “(c) Date at Cursor”.
+
+To convert a Hebrew date to Gregorian:
+
+ 1. Choose “(G) Goto…” and follow the prompts.
+
+Diary insertion of Hebrew events are supported provided
+proper configuration of the variables
+`diary-nongregorian-listing-hook' and
+`diary-nongregorian-marking-hook' as detailed in info
+node `(emacs) Non-Gregorian Diary'.
+
+Both of these variables can be configured from the Casual Calendar
+menu `casual-calendar-settings-tmenu'."
+
+ ["Hebrew Calendar"
+ ["Date"
+ ("c" "Date at cursor" calendar-hebrew-print-date :transient t)
+ ("G" "Goto…" calendar-hebrew-goto-date :transient t)]
+
+ ["Diary Insert"
+ ("i" "Point" diary-hebrew-insert-entry)
+ ("m" "Monthly" diary-hebrew-insert-monthly-entry)
+ ("y" "Year" diary-hebrew-insert-yearly-entry)]
+
+ ["Diary View"
+ ("d" "View" diary-view-entries :transient t)
+ ("s" "Show all" diary-show-all-entries)]]
+
+ casual-calendar--navigation-group
+ casual-calendar--menu-navigation-group)
+
+(transient-define-prefix casual-calendar-bahai-tmenu ()
+ "Casual Calendar Bahá’í calendar menu.
+
+This menu provides date conversion commands between a Gregorian
+and a Bahá’í calendar.
+
+To convert a Gregorian date to Bahá’í:
+
+ 1. Move cursor (point) in Calendar window to desired date.
+ (The command “(g) Goto…” can be used to accomplish this.)
+
+ 2. Choose “(c) Date at Cursor”.
+
+To convert a Bahá’í date to Gregorian:
+
+ 1. Choose “(G) Goto…” and follow the prompts.
+
+Diary insertion of Bahá’í events are supported provided
+proper configuration of the variables
+`diary-nongregorian-listing-hook' and
+`diary-nongregorian-marking-hook' as detailed in info
+node `(emacs) Non-Gregorian Diary'.
+
+Both of these variables can be configured from the Casual Calendar
+menu `casual-calendar-settings-tmenu'."
+
+ ["Bahá’í Calendar"
+ ["Date"
+ ("c" "Date at cursor" calendar-bahai-print-date :transient t)
+ ("G" "Goto…" calendar-bahai-goto-date :transient t)]
+
+ ["Diary Insert"
+ ("i" "Point" diary-bahai-insert-entry)
+ ("m" "Monthly" diary-bahai-insert-monthly-entry)
+ ("y" "Year" diary-bahai-insert-yearly-entry)]
+
+ ["Diary View"
+ ("d" "View" diary-view-entries :transient t)
+ ("s" "Show all" diary-show-all-entries)]]
+
+ casual-calendar--navigation-group
+ casual-calendar--menu-navigation-group)
+
+(transient-define-prefix casual-calendar-ethiopic-tmenu ()
+ "Casual Calendar Ethiopic calendar menu.
+
+This menu provides date conversion commands between a Gregorian
+and an Ethiopic calendar.
+
+To convert a Gregorian date to Ethiopic:
+
+ 1. Move cursor (point) in Calendar window to desired date.
+ (The command “(g) Goto…” can be used to accomplish this.)
+
+ 2. Choose “(c) Date at Cursor”.
+
+To convert an Ethiopic date to Gregorian:
+
+ 1. Choose “(G) Goto…” and follow the prompts."
+
+ ["Ethiopic Calendar"
+ ["Date"
+ ("c" "Date at cursor" calendar-ethiopic-print-date :transient t)
+ ("G" "Goto…" calendar-ethiopic-goto-date :transient t)]
+
+ ["Diary View"
+ ("d" "View" diary-view-entries :transient t)
+ ("s" "Show all" diary-show-all-entries)]]
+
+ casual-calendar--navigation-group
+ casual-calendar--menu-navigation-group)
+
+(transient-define-prefix casual-calendar-french-tmenu ()
+ "Casual Calendar French Revolutionary calendar menu.
+
+This menu provides date conversion commands between a Gregorian
+and a French Revolutionary calendar.
+
+To convert a Gregorian date to French Revolutionary:
+
+ 1. Move cursor (point) in Calendar window to desired date.
+ (The command “(g) Goto…” can be used to accomplish this.)
+
+ 2. Choose “(c) Date at Cursor”.
+
+To convert a French Revolutionary date to Gregorian:
+
+ 1. Choose “(G) Goto…” and follow the prompts."
+
+ ["French Revolutionary Calendar"
+ ["Date"
+ ("c" "Date at cursor" calendar-french-print-date :transient t)
+ ("G" "Goto…" calendar-french-goto-date :transient t)]
+
+ ["Diary View"
+ ("d" "View" diary-view-entries :transient t)
+ ("s" "Show all" diary-show-all-entries)]]
+
+ casual-calendar--navigation-group
+ casual-calendar--menu-navigation-group)
+
+(transient-define-prefix casual-calendar-julian-tmenu ()
+ "Casual Calendar Julian calendar menu.
+
+This menu provides date conversion commands between a Gregorian
+and a Julian calendar.
+
+To convert a Gregorian date to Julian:
+
+ 1. Move cursor (point) in Calendar window to desired date.
+ (The command “(g) Goto…” can be used to accomplish this.)
+
+ 2. Choose “(c) Date at Cursor”.
+
+To convert a Julian date to Gregorian:
+
+ 1. Choose “(G) Goto…” and follow the prompts."
+
+ ["Julian Calendar"
+ ["Date"
+ ("c" "Date at cursor" calendar-julian-print-date :transient t)
+ ("G" "Goto…" calendar-julian-goto-date :transient t)]
+
+ ["Diary View"
+ ("d" "View" diary-view-entries :transient t)
+ ("s" "Show all" diary-show-all-entries)]]
+
+ casual-calendar--navigation-group
+ casual-calendar--menu-navigation-group)
+
+(transient-define-prefix casual-calendar-coptic-tmenu ()
+ "Casual Calendar Coptic calendar menu.
+
+This menu provides date conversion commands between a Gregorian
+and a Coptic calendar.
+
+To convert a Gregorian date to Coptic:
+
+ 1. Move cursor (point) in Calendar window to desired date.
+ (The command “(g) Goto…” can be used to accomplish this.)
+
+ 2. Choose “(c) Date at Cursor”.
+
+To convert a Coptic date to Gregorian:
+
+ 1. Choose “(G) Goto…” and follow the prompts."
+
+ ["Coptic Calendar"
+ ["Date"
+ ("c" "Date at cursor" calendar-coptic-print-date :transient t)
+ ("G" "Goto…" calendar-coptic-goto-date :transient t)]
+
+ ["Diary View"
+ ("d" "View" diary-view-entries :transient t)
+ ("s" "Show all" diary-show-all-entries)]]
+
+ casual-calendar--navigation-group
+ casual-calendar--menu-navigation-group)
+
+(transient-define-prefix casual-calendar-persian-tmenu ()
+ "Casual Calendar Persian calendar menu.
+
+This menu provides date conversion commands between a Gregorian
+and a Persian calendar.
+
+To convert a Gregorian date to Persian:
+
+ 1. Move cursor (point) in Calendar window to desired date.
+ (The command “(g) Goto…” can be used to accomplish this.)
+
+ 2. Choose “(c) Date at Cursor”.
+
+To convert a Persian date to Gregorian:
+
+ 1. Choose “(G) Goto…” and follow the prompts."
+
+ ["Persian Calendar"
+ ["Date"
+ ("c" "Date at cursor" calendar-persian-print-date :transient t)
+ ("G" "Goto…" calendar-persian-goto-date :transient t)]
+
+ ["Diary View"
+ ("d" "View" diary-view-entries :transient t)
+ ("s" "Show all" diary-show-all-entries)]]
+
+ casual-calendar--navigation-group
+ casual-calendar--menu-navigation-group)
+
+(transient-define-prefix casual-calendar-mayan-tmenu ()
+ "Casual Calendar Mayan calendar menu.
+
+This menu provides date conversion commands between a Gregorian
+and a Mayan calendar.
+
+To convert a Gregorian date to Mayan:
+
+ 1. Move cursor (point) in Calendar window to desired date.
+ (The command “(g) Goto…” can be used to accomplish this.)
+
+ 2. Choose “(c) Date at Cursor”.
+
+To convert a Mayan date to Gregorian:
+
+ 1. Choose “(G) Goto…” and follow the prompts."
+
+ ["Mayan Calendar"
+ ["Date"
+ ("c" "Date at cursor" calendar-mayan-print-date :transient t)
+ ("G" "Goto long count…" calendar-mayan-goto-long-count-date :transient t)]
+
+ ["Diary View"
+ ("d" "View" diary-view-entries :transient t)
+ ("s" "Show all" diary-show-all-entries)]]
+
+ casual-calendar--navigation-group
+ casual-calendar--menu-navigation-group)
+
+(provide 'casual-calendar-utils)
+;;; casual-calendar-utils.el ends here
diff --git a/lisp/casual-calendar.el b/lisp/casual-calendar.el
new file mode 100644
index 0000000000..7a3c604e2a
--- /dev/null
+++ b/lisp/casual-calendar.el
@@ -0,0 +1,100 @@
+;;; casual-calendar.el --- Transient UI for Calendar -*- lexical-binding: t;
-*-
+
+;; Copyright (C) 2024 Charles Choi
+
+;; Author: Charles Choi <[email protected]>
+;; Keywords: tools
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Casual Calendar is an opinionated Transient-based user interface for the
+;; Emacs regular expression editor.
+
+;; INSTALLATION
+;; (require 'casual-calendar) ; optional if using autoloaded menu
+;; (keymap-set calendar-mode-map "C-o" #'casual-calendar)
+
+;; If you are using Emacs ≤ 30.0, you will need to update the built-in package
+;; `transient'. By default, `package.el' will not upgrade a built-in package.
+;; Set the customizable variable `package-install-upgrade-built-in' to `t' to
+;; override this. For more details, please refer to the "Install" section on
+;; this project's repository web page.
+
+;;; Code:
+(require 'casual-calendar-utils)
+(require 'casual-calendar-settings)
+
+;;;###autoload (autoload 'casual-calendar "casual-calendar" nil t)
+(defun casual-calendar ()
+ "Call Casual Calendar main menu.
+
+Helper function for calling `casual-calendar-tmenu'. Calls
+`calendar-redraw' to fix window sizing."
+ (interactive)
+ (call-interactively #'casual-calendar-tmenu)
+ (calendar-redraw))
+
+;;;###autoload (autoload 'casual-calendar-tmenu "casual-calendar" nil t)
+(transient-define-prefix casual-calendar-tmenu ()
+ "Transient menu for Calendar commands.
+
+Main menu for `calendar' commands.
+
+* References
+- Info node `(emacs) Calendar/Diary'"
+ casual-calendar--navigation-group
+
+ [["Conversions"
+ ("c" "Conversions›" casual-calendar-conversions-tmenu)
+ ("A" "Convert to all" calendar-print-other-dates :transient t)
+ ("i" "ISO Date" calendar-iso-print-date :transient t)]
+
+ ["Holidays"
+ ("H" "Holidays in span" calendar-list-holidays :transient t)
+ ("h" "Holidays at point" calendar-cursor-holidays :transient t)
+ ("x" "Mark Holidays" calendar-mark-holidays :transient t)
+ ("u" "Unmark" calendar-unmark :transient t)]
+
+ ["Misc"
+ ("O" "Org Agenda" org-calendar-goto-agenda)
+ ("d" "Diary" diary-view-entries :transient t)
+ ("s" "All Diary" diary-show-all-entries :transient t)
+ ("D" "Diary & Goto›" casual-calendar-diary-and-goto-tmenu)]
+
+ ["Almanac"
+ :pad-keys t
+ ("M" "Lunar Phases" calendar-lunar-phases
+ :description (lambda () (casual-calendar-unicode-get :lunar))
+ :transient t)
+ ("S" "Sunrise/Sunset" calendar-sunrise-sunset
+ :description (lambda () (casual-calendar-unicode-get :sunrise))
+ :transient t)
+ ("M-m" "Sunrise/Sunset Month" calendar-sunrise-sunset-month
+ :description (lambda () (format "%s Month" (casual-calendar-unicode-get
:sunrise)))
+ :transient t)]]
+
+ [:class transient-row
+ (casual-lib-quit-one)
+ ("RET" "Dismiss" transient-quit-all)
+ ("I" "ⓘ Info" (lambda ()
+ (interactive)
+ (calendar-exit)
+ (calendar-goto-info-node)))
+ ("," "Settings›" casual-calendar-settings-tmenu)
+ ("q" "Quit" calendar-exit)])
+
+(provide 'casual-calendar)
+;;; casual-calendar.el ends here
diff --git a/lisp/casual.el b/lisp/casual.el
index 8d473db6ca..d531ffaa91 100644
--- a/lisp/casual.el
+++ b/lisp/casual.el
@@ -44,6 +44,10 @@
;; An interface for Emacs Calc, an embarrasingly feature-rich calculator.
;; URL `https://github.com/kickingvegas/casual/blob/main/docs/calc.org'
+;; - Calendar (Elisp library: `casual-calendar')
+;; An interface for the built-in calendar and diary of Emacs.
+;; URL `https://github.com/kickingvegas/casual/blob/main/docs/calendar.org'
+
;; - Dired (Elisp library: `casual-dired')
;; An interface for the venerable file manager Dired.
;; URL `https://github.com/kickingvegas/casual/blob/main/docs/dired.org'
diff --git a/tests/Makefile b/tests/Makefile
index b69dabdf57..37c2d62e02 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -21,6 +21,7 @@ lib-tests \
agenda-tests \
bookmarks-tests \
calc-tests \
+calendar-tests \
dired-tests \
editkit-tests \
ibuffer-tests \
@@ -34,6 +35,7 @@ tests: lib-tests \
agenda-tests \
bookmarks-tests \
calc-tests \
+calendar-tests \
dired-tests \
editkit-tests \
ibuffer-tests \
@@ -53,6 +55,9 @@ bookmarks-tests:
calc-tests:
$(MAKE) -C $(SRC_DIR) $@
+calendar-tests:
+ $(MAKE) -C $(SRC_DIR) $@
+
dired-tests:
$(MAKE) -C $(SRC_DIR) $@
diff --git a/tests/casual-calendar-test-utils.el
b/tests/casual-calendar-test-utils.el
new file mode 100644
index 0000000000..c6c7c72f5e
--- /dev/null
+++ b/tests/casual-calendar-test-utils.el
@@ -0,0 +1,41 @@
+;;; casual-calendar-test-utils.el --- Casual Test Utils -*-
lexical-binding: t; -*-
+
+;; Copyright (C) 2024 Charles Choi
+
+;; Author: Charles Choi <[email protected]>
+;; Keywords: tools
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+(require 'ert)
+(require 'casual-lib)
+(require 'kmacro)
+(require 'calendar)
+(require 'casual-lib-test-utils)
+
+(defun casualt-calendar-setup ()
+ "Casual menu test setup function."
+ )
+
+(defun casualt-calendar-breakdown (&optional clear)
+ "Casual menu test breakdown function, if CLEAR is non-nil then clear state."
+ )
+
+(provide 'casual-calendar-test-utils)
+;;; casual-calendar-test-utils.el ends here
diff --git a/tests/casual-lib-test-utils.el b/tests/casual-lib-test-utils.el
index 85bae52e0a..7e109be8fa 100644
--- a/tests/casual-lib-test-utils.el
+++ b/tests/casual-lib-test-utils.el
@@ -149,5 +149,11 @@ COMMAND is an interactive function."
(let ((buf (concat (casualt-macro-callable-symbol command) keys)))
(kmacro buf)))
+(defun casualt-unicode-db-assert (key control cmd)
+ "DB Assert."
+ (let ((test (funcall cmd key)))
+ (should (string= test control))))
+
+
(provide 'casual-lib-test-utils)
;;; casual-lib-test-utils.el ends here
diff --git a/tests/test-casual-calendar-constants.el
b/tests/test-casual-calendar-constants.el
new file mode 100644
index 0000000000..a2054b5b39
--- /dev/null
+++ b/tests/test-casual-calendar-constants.el
@@ -0,0 +1,65 @@
+(require 'ert);;; test-casual-calendar-constants.el --- Casual Calendar Tests
-*- lexical-binding: t; -*-
+
+;; Copyright (C) 2024 Charles Choi
+
+;; Author: Charles Choi <[email protected]>
+;; Keywords: tools
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+
+(require 'casual-lib-test-utils)
+(require 'casual-calendar-test-utils)
+(require 'casual-calendar)
+
+(defun casualt-calendar-unicode-assert (key control)
+ (casualt-unicode-db-assert key control #'casual-calendar-unicode-get))
+
+(ert-deftest test-casual-calendar-unicode-get ()
+ (let ((casual-lib-use-unicode nil))
+ (casualt-calendar-unicode-assert :previous "Previous")
+ (casualt-calendar-unicode-assert :next "Next")
+ (casualt-calendar-unicode-assert :behind "Behind")
+ (casualt-calendar-unicode-assert :ahead "Ahead")
+ (casualt-calendar-unicode-assert :beginning "Beginning")
+ (casualt-calendar-unicode-assert :end "End")
+ (casualt-calendar-unicode-assert :back-3-months "-3 months")
+ (casualt-calendar-unicode-assert :forward-3-months "+3 months")
+ (casualt-calendar-unicode-assert :redraw "Refresh")
+ (casualt-calendar-unicode-assert :goto "Goto")
+ (casualt-calendar-unicode-assert :sunrise "Sunrise")
+ (casualt-calendar-unicode-assert :lunar "Lunar"))
+
+ (let ((casual-lib-use-unicode t))
+ (casualt-calendar-unicode-assert :previous "↑")
+ (casualt-calendar-unicode-assert :next "↓")
+ (casualt-calendar-unicode-assert :behind "←")
+ (casualt-calendar-unicode-assert :ahead "→")
+ (casualt-calendar-unicode-assert :beginning "⇤")
+ (casualt-calendar-unicode-assert :end "⇥")
+ (casualt-calendar-unicode-assert :back-3-months "← 3 months")
+ (casualt-calendar-unicode-assert :forward-3-months "→ 3 months")
+ (casualt-calendar-unicode-assert :redraw "⟳")
+ (casualt-calendar-unicode-assert :goto "🔎")
+ (casualt-calendar-unicode-assert :sunrise "🌅")
+ (casualt-calendar-unicode-assert :lunar "🌙")))
+
+(provide 'test-casual-calendar-constants)
+;;; test-casual-calendar-constants.el ends here
diff --git a/tests/test-casual-calendar-settings.el
b/tests/test-casual-calendar-settings.el
new file mode 100644
index 0000000000..d4a468c6d4
--- /dev/null
+++ b/tests/test-casual-calendar-settings.el
@@ -0,0 +1,61 @@
+;;; test-casual-calendar-settings.el --- Casual Calendar Settings Tests -*-
lexical-binding: t; -*-
+
+;; Copyright (C) 2024 Charles Choi
+
+;; Author: Charles Choi <[email protected]>
+;; Keywords: tools
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'ert)
+(require 'casual-calendar-test-utils)
+(require 'casual-calendar-settings)
+
+(ert-deftest test-casual-calendar-settings-tmenu ()
+ (let ()
+ (casualt-calendar-setup)
+ (cl-letf ()
+ (let ((test-vectors
+ '((:binding "G" :command
casual-calendar--customize-calendar-group)
+ (:binding "H" :command
casual-calendar--customize-calendar-mark-holidays-flag)
+ (:binding "v" :command
casual-calendar--customize-calendar-move-hook)
+ (:binding "N" :command
casual-calendar--customize-calendar-location-name)
+ (:binding "A" :command
casual-calendar--customize-calendar-latitude)
+ (:binding "O" :command
casual-calendar--customize-calendar-longitude)
+ (:binding "D" :command casual-calendar--customize-diary-group)
+ (:binding "l" :command
casual-calendar--customize-diary-list-entries-hook)
+ (:binding "m" :command
casual-calendar--customize-diary-mark-entries-hook)
+ (:binding "L" :command
casual-calendar--customize-diary-nongregorian-listing-hook)
+ (:binding "M" :command
casual-calendar--customize-diary-nongregorian-marking-hook)
+ (:binding "d" :command
casual-calendar--customize-org-agenda-include-diary)
+ (:binding "u" :command
casual-lib-customize-casual-lib-use-unicode)
+ (:binding "n" :command
casual-lib-customize-casual-lib-hide-navigation)
+ (:binding "a" :command casual-calendar-about))))
+
+ (casualt-suffix-testcase-runner test-vectors
+ #'casual-calendar-settings-tmenu
+ '(lambda () (random 5000)))))
+ (casualt-calendar-breakdown)))
+
+(ert-deftest test-casual-calendar-about ()
+ (should (stringp (casual-calendar-about))))
+
+(provide 'test-casual-calendar-settings)
+;;; test-casual-calendar-settings.el ends here
diff --git a/tests/test-casual-calendar-utils.el
b/tests/test-casual-calendar-utils.el
new file mode 100644
index 0000000000..5e2ea11ef9
--- /dev/null
+++ b/tests/test-casual-calendar-utils.el
@@ -0,0 +1,316 @@
+;;; test-casual-calendar-utils.el --- Casual Calendar Utils Tests -*-
lexical-binding: t; -*-
+
+;; Copyright (C) 2024 Charles Choi
+
+;; Author: Charles Choi <[email protected]>
+;; Keywords: tools
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+(require 'ert)
+(require 'casual-calendar-test-utils)
+(require 'casual-calendar-utils)
+
+(ert-deftest test-casual-calendar-diary-and-goto-tmenu ()
+ (let ()
+ (casualt-calendar-setup)
+ (cl-letf ((casualt-mock #'diary-insert-entry)
+ (casualt-mock #'diary-insert-weekly-entry)
+ (casualt-mock #'diary-insert-monthly-entry)
+ (casualt-mock #'diary-insert-yearly-entry)
+ (casualt-mock #'diary-insert-anniversary-entry)
+ (casualt-mock #'calendar-goto-date)
+ (casualt-mock #'calendar-iso-goto-date)
+ (casualt-mock #'calendar-goto-day-of-year))
+
+ (let ((test-vectors
+ '((:binding "e" :command diary-insert-entry)
+ (:binding "w" :command diary-insert-weekly-entry)
+ (:binding "m" :command diary-insert-monthly-entry)
+ (:binding "y" :command diary-insert-yearly-entry)
+ (:binding "a" :command diary-insert-anniversary-entry)
+ (:binding "g" :command calendar-goto-date)
+ ;; (:binding "i" :command calendar-iso-goto-date) ; TODO: need
to mock input
+ (:binding "d" :command calendar-goto-day-of-year))))
+
+ (casualt-suffix-testcase-runner test-vectors
+ #'casual-calendar-diary-and-goto-tmenu
+ '(lambda () (random 5000)))))
+ (casualt-calendar-breakdown t)))
+
+(ert-deftest test-casual-calendar-conversions-tmenu ()
+ (let ()
+ (casualt-calendar-setup)
+ (cl-letf ((casualt-mock #'calendar-print-other-dates))
+
+ (let ((test-vectors
+ '((:binding "a" :command casual-calendar-astro-tmenu)
+ (:binding "b" :command casual-calendar-bahai-tmenu)
+ (:binding "c" :command casual-calendar-coptic-tmenu)
+ (:binding "e" :command casual-calendar-ethiopic-tmenu)
+ (:binding "f" :command casual-calendar-french-tmenu)
+ (:binding "h" :command casual-calendar-hebrew-tmenu)
+ (:binding "i" :command casual-calendar-islamic-tmenu)
+ (:binding "j" :command casual-calendar-julian-tmenu)
+ (:binding "l" :command casual-calendar-lunar-tmenu)
+ (:binding "m" :command casual-calendar-mayan-tmenu)
+ (:binding "p" :command casual-calendar-persian-tmenu)
+ (:binding "A" :command calendar-print-other-dates))))
+
+ (casualt-suffix-testcase-runner test-vectors
+ #'casual-calendar-conversions-tmenu
+ '(lambda () (random 5000)))))
+ (casualt-calendar-breakdown)))
+
+(ert-deftest test-casual-calendar-lunar-tmenu ()
+ (let ()
+ (casualt-calendar-setup)
+ (cl-letf ((casualt-mock #'calendar-chinese-print-date)
+ (casualt-mock #'calendar-chinese-goto-date)
+ (casualt-mock #'diary-chinese-insert-entry)
+ (casualt-mock #'diary-chinese-insert-monthly-entry)
+ (casualt-mock #'diary-chinese-insert-yearly-entry)
+ (casualt-mock #'diary-chinese-insert-anniversary-entry)
+ (casualt-mock #'diary-view-entries)
+ (casualt-mock #'diary-show-all-entries))
+
+ (let ((test-vectors
+ '((:binding "c" :command calendar-chinese-print-date)
+ ;;(:binding "G" :command calendar-chinese-goto-date)
+ (:binding "i" :command diary-chinese-insert-entry)
+ (:binding "m" :command diary-chinese-insert-monthly-entry)
+ (:binding "y" :command diary-chinese-insert-yearly-entry)
+ (:binding "A" :command diary-chinese-insert-anniversary-entry)
+ (:binding "d" :command diary-view-entries)
+ (:binding "s" :command diary-show-all-entries))))
+
+ (casualt-suffix-testcase-runner test-vectors
+ #'casual-calendar-lunar-tmenu
+ '(lambda () (random 5000)))))
+ (casualt-calendar-breakdown)))
+
+(ert-deftest test-casual-calendar-astro-tmenu ()
+ (let ()
+ (casualt-calendar-setup)
+ (cl-letf ((casualt-mock #'calendar-astro-print-day-number)
+ (casualt-mock #'calendar-astro-goto-day-number)
+ (casualt-mock #'diary-view-entries)
+ (casualt-mock #'diary-show-all-entries))
+
+ (let ((test-vectors
+ '((:binding "c" :command calendar-astro-print-day-number)
+ (:binding "d" :command diary-view-entries)
+ (:binding "s" :command diary-show-all-entries))))
+
+ (casualt-suffix-testcase-runner test-vectors
+ #'casual-calendar-astro-tmenu
+ '(lambda () (random 5000)))))
+ (casualt-calendar-breakdown)))
+
+(ert-deftest test-casual-calendar-islamic-tmenu ()
+ (let ()
+ (casualt-calendar-setup)
+ (cl-letf ((casualt-mock #'calendar-islamic-print-day-number)
+ (casualt-mock #'calendar-islamic-goto-day-number)
+ (casualt-mock #'diary-islamic-insert-entry)
+ (casualt-mock #'diary-islamic-insert-monthly-entry)
+ (casualt-mock #'diary-islamic-insert-yearly-entry)
+ (casualt-mock #'diary-view-entries)
+ (casualt-mock #'diary-show-all-entries))
+
+ (let ((test-vectors
+ '((:binding "c" :command calendar-islamic-print-date)
+ ;;(:binding "G" :command calendar-islamic-goto-date)
+ (:binding "i" :command diary-islamic-insert-entry)
+ (:binding "m" :command diary-islamic-insert-monthly-entry)
+ (:binding "y" :command diary-islamic-insert-yearly-entry)
+ (:binding "d" :command diary-view-entries)
+ (:binding "s" :command diary-show-all-entries))))
+
+ (casualt-suffix-testcase-runner test-vectors
+ #'casual-calendar-islamic-tmenu
+ '(lambda () (random 5000)))))
+ (casualt-calendar-breakdown)))
+
+(ert-deftest test-casual-calendar-hebrew-tmenu ()
+ (let ()
+ (casualt-calendar-setup)
+ (cl-letf ((casualt-mock #'calendar-hebrew-print-day-number)
+ (casualt-mock #'calendar-hebrew-goto-day-number)
+ (casualt-mock #'diary-hebrew-insert-entry)
+ (casualt-mock #'diary-hebrew-insert-monthly-entry)
+ (casualt-mock #'diary-hebrew-insert-yearly-entry)
+ (casualt-mock #'diary-view-entries)
+ (casualt-mock #'diary-show-all-entries))
+
+ (let ((test-vectors
+ '((:binding "c" :command calendar-hebrew-print-date)
+ ;;(:binding "G" :command calendar-hebrew-goto-date)
+ (:binding "i" :command diary-hebrew-insert-entry)
+ (:binding "m" :command diary-hebrew-insert-monthly-entry)
+ (:binding "y" :command diary-hebrew-insert-yearly-entry)
+ (:binding "d" :command diary-view-entries)
+ (:binding "s" :command diary-show-all-entries))))
+
+ (casualt-suffix-testcase-runner test-vectors
+ #'casual-calendar-hebrew-tmenu
+ '(lambda () (random 5000)))))
+ (casualt-calendar-breakdown)))
+
+(ert-deftest test-casual-calendar-bahai-tmenu ()
+ (let ()
+ (casualt-calendar-setup)
+ (cl-letf ((casualt-mock #'calendar-bahai-print-day-number)
+ (casualt-mock #'calendar-bahai-goto-day-number)
+ (casualt-mock #'diary-bahai-insert-entry)
+ (casualt-mock #'diary-bahai-insert-monthly-entry)
+ (casualt-mock #'diary-bahai-insert-yearly-entry)
+ (casualt-mock #'diary-view-entries)
+ (casualt-mock #'diary-show-all-entries))
+
+ (let ((test-vectors
+ '((:binding "c" :command calendar-bahai-print-date)
+ ;;(:binding "G" :command calendar-bahai-goto-date)
+ (:binding "i" :command diary-bahai-insert-entry)
+ (:binding "m" :command diary-bahai-insert-monthly-entry)
+ (:binding "y" :command diary-bahai-insert-yearly-entry)
+ (:binding "d" :command diary-view-entries)
+ (:binding "s" :command diary-show-all-entries))))
+
+ (casualt-suffix-testcase-runner test-vectors
+ #'casual-calendar-bahai-tmenu
+ '(lambda () (random 5000)))))
+ (casualt-calendar-breakdown)))
+
+(ert-deftest test-casual-calendar-ethiopic-tmenu ()
+ (let ()
+ (casualt-calendar-setup)
+ (cl-letf ((casualt-mock #'calendar-ethiopic-print-day-number)
+ (casualt-mock #'calendar-ethiopic-goto-day-number)
+ (casualt-mock #'diary-view-entries)
+ (casualt-mock #'diary-show-all-entries))
+
+ (let ((test-vectors
+ '((:binding "c" :command calendar-ethiopic-print-date)
+ ;;(:binding "G" :command calendar-ethiopic-goto-date)
+ (:binding "d" :command diary-view-entries)
+ (:binding "s" :command diary-show-all-entries))))
+
+ (casualt-suffix-testcase-runner test-vectors
+ #'casual-calendar-ethiopic-tmenu
+ '(lambda () (random 5000)))))
+ (casualt-calendar-breakdown)))
+
+(ert-deftest test-casual-calendar-french-tmenu ()
+ (let ()
+ (casualt-calendar-setup)
+ (cl-letf ((casualt-mock #'calendar-french-print-day-number)
+ (casualt-mock #'calendar-french-goto-day-number)
+ (casualt-mock #'diary-view-entries)
+ (casualt-mock #'diary-show-all-entries))
+
+ (let ((test-vectors
+ '((:binding "c" :command calendar-french-print-date)
+ ;;(:binding "G" :command calendar-french-goto-date)
+ (:binding "d" :command diary-view-entries)
+ (:binding "s" :command diary-show-all-entries))))
+
+ (casualt-suffix-testcase-runner test-vectors
+ #'casual-calendar-french-tmenu
+ '(lambda () (random 5000)))))
+ (casualt-calendar-breakdown)))
+
+(ert-deftest test-casual-calendar-julian-tmenu ()
+ (let ()
+ (casualt-calendar-setup)
+ (cl-letf ((casualt-mock #'calendar-julian-print-day-number)
+ (casualt-mock #'calendar-julian-goto-day-number)
+ (casualt-mock #'diary-view-entries)
+ (casualt-mock #'diary-show-all-entries))
+
+ (let ((test-vectors
+ '((:binding "c" :command calendar-julian-print-date)
+ ;;(:binding "G" :command calendar-julian-goto-date)
+ (:binding "d" :command diary-view-entries)
+ (:binding "s" :command diary-show-all-entries))))
+
+ (casualt-suffix-testcase-runner test-vectors
+ #'casual-calendar-julian-tmenu
+ '(lambda () (random 5000)))))
+ (casualt-calendar-breakdown)))
+
+(ert-deftest test-casual-calendar-coptic-tmenu ()
+ (let ()
+ (casualt-calendar-setup)
+ (cl-letf ((casualt-mock #'calendar-coptic-print-day-number)
+ (casualt-mock #'calendar-coptic-goto-day-number)
+ (casualt-mock #'diary-view-entries)
+ (casualt-mock #'diary-show-all-entries))
+
+ (let ((test-vectors
+ '((:binding "c" :command calendar-coptic-print-date)
+ ;;(:binding "G" :command calendar-coptic-goto-date)
+ (:binding "d" :command diary-view-entries)
+ (:binding "s" :command diary-show-all-entries))))
+
+ (casualt-suffix-testcase-runner test-vectors
+ #'casual-calendar-coptic-tmenu
+ '(lambda () (random 5000)))))
+ (casualt-calendar-breakdown)))
+
+(ert-deftest test-casual-calendar-persian-tmenu ()
+ (let ()
+ (casualt-calendar-setup)
+ (cl-letf ((casualt-mock #'calendar-persian-print-day-number)
+ (casualt-mock #'calendar-persian-goto-day-number)
+ (casualt-mock #'diary-view-entries)
+ (casualt-mock #'diary-show-all-entries))
+
+ (let ((test-vectors
+ '((:binding "c" :command calendar-persian-print-date)
+ ;;(:binding "G" :command calendar-persian-goto-date)
+ (:binding "d" :command diary-view-entries)
+ (:binding "s" :command diary-show-all-entries))))
+
+ (casualt-suffix-testcase-runner test-vectors
+ #'casual-calendar-persian-tmenu
+ '(lambda () (random 5000)))))
+ (casualt-calendar-breakdown)))
+
+(ert-deftest test-casual-calendar-mayan-tmenu ()
+ (let ()
+ (casualt-calendar-setup)
+ (cl-letf ((casualt-mock #'calendar-mayan-print-day-number)
+ (casualt-mock #'calendar-mayan-goto-day-number)
+ (casualt-mock #'diary-view-entries)
+ (casualt-mock #'diary-show-all-entries))
+
+ (let ((test-vectors
+ '((:binding "c" :command calendar-mayan-print-date)
+ ;;(:binding "G" :command calendar-mayan-goto-date)
+ (:binding "d" :command diary-view-entries)
+ (:binding "s" :command diary-show-all-entries))))
+
+ (casualt-suffix-testcase-runner test-vectors
+ #'casual-calendar-mayan-tmenu
+ '(lambda () (random 5000)))))
+ (casualt-calendar-breakdown)))
+
+(provide 'test-casual-calendar-utils)
+;;; test-casual-calendar-utils.el ends here
diff --git a/tests/test-casual-calendar.el b/tests/test-casual-calendar.el
new file mode 100644
index 0000000000..be2593ab83
--- /dev/null
+++ b/tests/test-casual-calendar.el
@@ -0,0 +1,130 @@
+;;; test-casual-calendar.el --- Casual Calendar Tests -*- lexical-binding: t;
-*-
+
+;; Copyright (C) 2024 Charles Choi
+
+;; Author: Charles Choi <[email protected]>
+;; Keywords: tools
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(require 'ert)
+(require 'casual-lib-test-utils)
+(require 'casual-calendar-test-utils)
+(require 'casual-calendar)
+
+(ert-deftest test-casual-calendar-tmenu ()
+ (let ()
+ (casualt-calendar-setup)
+
+ (cl-letf (;; ((symbol-function #'buffer-file-name) (lambda () t))
+ (casualt-mock #'calendar-backward-day)
+ (casualt-mock #'calendar-forward-day)
+ (casualt-mock #'calendar-goto-today)
+ (casualt-mock #'calendar-goto-date)
+
+ (casualt-mock #'calendar-backward-week)
+ (casualt-mock #'calendar-forward-week)
+ (casualt-mock #'calendar-beginning-of-week)
+ (casualt-mock #'calendar-end-of-week)
+ (casualt-mock #'calendar-iso-goto-week)
+ (casualt-mock #'calendar-iso-print-date)
+
+ (casualt-mock #'calendar-backward-month)
+ (casualt-mock #'calendar-forward-month)
+ (casualt-mock #'calendar-beginning-of-month)
+ (casualt-mock #'calendar-end-of-month)
+ (casualt-mock #'calendar-other-month)
+
+ (casualt-mock #'calendar-backward-year)
+ (casualt-mock #'calendar-forward-year)
+ (casualt-mock #'calendar-beginning-of-year)
+ (casualt-mock #'calendar-end-of-year)
+
+ (casualt-mock #'calendar-scroll-right)
+ (casualt-mock #'calendar-scroll-left)
+ (casualt-mock #'calendar-scroll-right-three-months)
+ (casualt-mock #'calendar-scroll-left-three-months)
+ (casualt-mock #'calendar-redraw)
+
+ (casualt-mock #'calendar-print-other-dates)
+ (casualt-mock #'calendar-list-holidays)
+ (casualt-mock #'calendar-cursor-holidays)
+ (casualt-mock #'calendar-mark-holidays)
+ (casualt-mock #'calendar-unmark)
+ (casualt-mock #'org-calendar-goto-agenda)
+ (casualt-mock #'diary-view-entries)
+ (casualt-mock #'diary-show-all-entries)
+ (casualt-mock #'calendar-lunar-phases)
+ (casualt-mock #'calendar-sunrise-sunset)
+ (casualt-mock #'calendar-sunrise-sunset-month)
+
+ (casualt-mock #'calendar-exit))
+
+ (let ((test-vectors
+ '((:binding "b" :command calendar-backward-day)
+ (:binding "f" :command calendar-forward-day)
+ (:binding "." :command calendar-goto-today)
+ (:binding "g" :command calendar-goto-date)
+
+ (:binding "p" :command calendar-backward-week)
+ (:binding "n" :command calendar-forward-week)
+ (:binding "a" :command calendar-beginning-of-week)
+ (:binding "e" :command calendar-end-of-week)
+ ;;(:binding "w" :command calendar-iso-goto-week) ; TODO: needs
input handling
+
+ (:binding "{" :command calendar-backward-month)
+ (:binding "}" :command calendar-forward-month)
+ (:binding "M-a" :command calendar-beginning-of-month)
+ (:binding "M-e" :command calendar-end-of-month)
+ (:binding "o" :command calendar-other-month)
+
+ (:binding "M-]" :command calendar-forward-year)
+ (:binding "M-[" :command calendar-backward-year)
+ (:binding "[" :command calendar-beginning-of-year)
+ (:binding "]" :command calendar-end-of-year)
+
+ (:binding "<" :command calendar-scroll-right)
+ (:binding ">" :command calendar-scroll-left)
+ (:binding "-" :command calendar-scroll-right-three-months)
+ (:binding "+" :command calendar-scroll-left-three-months)
+ (:binding "C-l" :command calendar-redraw)
+
+ (:binding "c" :command casual-calendar-conversions-tmenu)
+ (:binding "A" :command calendar-print-other-dates)
+ (:binding "i" :command calendar-iso-print-date)
+ (:binding "H" :command calendar-list-holidays)
+ (:binding "h" :command calendar-cursor-holidays)
+ (:binding "x" :command calendar-mark-holidays)
+ (:binding "u" :command calendar-unmark)
+ (:binding "O" :command org-calendar-goto-agenda)
+ (:binding "d" :command diary-view-entries)
+ (:binding "D" :command casual-calendar-diary-and-goto-tmenu)
+ (:binding "s" :command diary-show-all-entries)
+ (:binding "M" :command calendar-lunar-phases)
+ (:binding "S" :command calendar-sunrise-sunset)
+ (:binding "M-m" :command calendar-sunrise-sunset-month))))
+
+ (casualt-suffix-testcase-runner test-vectors
+ #'casual-calendar-tmenu
+ '(lambda () (random 5000)))))
+ (casualt-calendar-breakdown)))
+
+(provide 'test-casual-calendar)
+;;; test-casual-calendar.el ends here