branch: elpa/casual
commit 7fc55bf74b070e21feb0d254e27dabea76d8923a
Merge: 1683cb85bb d6a890c70e
Author: Charles Choi <[email protected]>
Commit: GitHub <[email protected]>

    Merge pull request #75 from 
kickingvegas/merge-development-to-main-20241112_152321
    
    Merge development to main 20241112_152321
---
 docs/dired.org                                    |   7 ++-
 docs/editkit.org                                  |   2 +-
 docs/images/casual-dired-link.png                 | Bin 0 -> 118128 bytes
 docs/images/casual-dired-screenshot-unicode.png   | Bin 375797 -> 357137 bytes
 docs/images/casual-dired-screenshot.png           | Bin 924166 -> 728609 bytes
 docs/images/casual-dired-settings-screenshot.png  | Bin 239246 -> 233223 bytes
 docs/images/casual-editkit-open-screenshot.png    | Bin 158382 -> 170624 bytes
 lisp/Makefile--defines.make                       |  38 +++++++++++++
 lisp/{Makefile-info.make => Makefile--rules.make} |  23 --------
 lisp/Makefile-agenda.make                         |  60 +-------------------
 lisp/Makefile-bookmarks.make                      |  61 +--------------------
 lisp/Makefile-calc.make                           |  61 +--------------------
 lisp/Makefile-dired.make                          |  61 +--------------------
 lisp/Makefile-editkit.make                        |  62 +--------------------
 lisp/Makefile-ibuffer.make                        |  61 +--------------------
 lisp/Makefile-info.make                           |  61 +--------------------
 lisp/Makefile-isearch.make                        |  16 +-----
 lisp/Makefile-lib.make                            |  13 +----
 lisp/Makefile-re-builder.make                     |  60 +-------------------
 lisp/casual-calc-conversion.el                    |  37 +++++++++++--
 lisp/casual-calc-settings.el                      |   3 +-
 lisp/casual-calc-utils.el                         |   7 ++-
 lisp/casual-dired-settings.el                     |  20 ++++++-
 lisp/casual-dired-utils.el                        |  14 ++++-
 lisp/casual-dired.el                              |   3 +-
 lisp/casual-editkit-utils.el                      |  11 +++-
 lisp/casual.el                                    |   2 +-
 tests/test-casual-calc-conversion.el              |   2 +
 tests/test-casual-calc-labels.el                  |   4 +-
 tests/test-casual-calc-utils.el                   |  64 ++++++++++++++++++++++
 tests/test-casual-dired-settings.el               |   1 +
 tests/test-casual-dired-utils.el                  |   6 +-
 tests/test-casual-dired.el                        |   3 +-
 tests/test-casual-editkit-utils.el                |   6 +-
 34 files changed, 224 insertions(+), 545 deletions(-)

diff --git a/docs/dired.org b/docs/dired.org
index 2586ce2149..1951f6308c 100644
--- a/docs/dired.org
+++ b/docs/dired.org
@@ -48,7 +48,6 @@ Included is a standard keymap for Dired sorting commands 
(~casual-dired-sort-men
 #+end_src
 
 
-
 ** Configuration
 
 As Dired has been around for a long time, the different ways of configuring it 
are myriad. Described below is a configuration used by the author that is 
consistent with the bindings used in Casual Dired.
@@ -137,6 +136,12 @@ Casual Dired organizes a number of Dired commands that 
work on a set of marked f
 
 [[file:images/casual-dired-utils-screenshot.png]]
 
+** Link
+Create symbolic and hard links via the *Link* menu. Both absolute and relative 
symbolic links (symlinks) are supported.
+
+[[file:images/casual-dired-link.png]]
+
+
 * Sponsorship
 If you enjoy using Casual Dired, consider making a modest financial 
contribution to help support its development and maintenance.
 
diff --git a/docs/editkit.org b/docs/editkit.org
index f8a9dcfb51..52bbf01eec 100644
--- a/docs/editkit.org
+++ b/docs/editkit.org
@@ -128,7 +128,7 @@ Operations related to search and replace are captured by 
this menu. Note that th
 [[file:images/casual-editkit-search-screenshot.png]]
 
 ** Open commands (~casual-editkit-open-tmenu~)
-Commands related to opening a file (either for writing or read-only) are 
supported here. The *Project* sub-menu is also offered here.
+Commands related to opening a file (either for writing or read-only) are 
supported here. Included are commands for visiting and renaming a file or 
buffer. The *Project* sub-menu is also offered here.
 
 [[file:images/casual-editkit-open-screenshot.png]]
 
diff --git a/docs/images/casual-dired-link.png 
b/docs/images/casual-dired-link.png
new file mode 100644
index 0000000000..17f1286caa
Binary files /dev/null and b/docs/images/casual-dired-link.png differ
diff --git a/docs/images/casual-dired-screenshot-unicode.png 
b/docs/images/casual-dired-screenshot-unicode.png
index 3bab71e5ad..3b5a1a39d6 100644
Binary files a/docs/images/casual-dired-screenshot-unicode.png and 
b/docs/images/casual-dired-screenshot-unicode.png differ
diff --git a/docs/images/casual-dired-screenshot.png 
b/docs/images/casual-dired-screenshot.png
index bd50a2b036..30ef3d2d17 100644
Binary files a/docs/images/casual-dired-screenshot.png and 
b/docs/images/casual-dired-screenshot.png differ
diff --git a/docs/images/casual-dired-settings-screenshot.png 
b/docs/images/casual-dired-settings-screenshot.png
index 8f21b4e3ba..857df381c7 100644
Binary files a/docs/images/casual-dired-settings-screenshot.png and 
b/docs/images/casual-dired-settings-screenshot.png differ
diff --git a/docs/images/casual-editkit-open-screenshot.png 
b/docs/images/casual-editkit-open-screenshot.png
index 23cc9e8aef..d6d1773808 100644
Binary files a/docs/images/casual-editkit-open-screenshot.png and 
b/docs/images/casual-editkit-open-screenshot.png differ
diff --git a/lisp/Makefile--defines.make b/lisp/Makefile--defines.make
new file mode 100644
index 0000000000..e29b86b516
--- /dev/null
+++ b/lisp/Makefile--defines.make
@@ -0,0 +1,38 @@
+##
+# 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/>.
+
+TIMESTAMP := $(shell /bin/date "+%Y%m%d_%H%M%S")
+
+# If local Emacs install is not in typical PATH such as on macOS, define the
+# environment variable EMACS_APP_EXEC to point to the Emacs executable. The
+# following Elisp configuration needs to be set if running these Makefiles from
+# Emacs.
+
+# (setenv "EMACS_APP_EXEC"
+#         "<path to Emacs executable>")
+
+
+ifdef EMACS_APP_EXEC
+  EXEC_NAME=$(EMACS_APP_EXEC)
+else
+  EXEC_NAME=emacs
+endif
+
+CASUAL_BASE_DIR=$(HOME)/Projects/elisp
+CASUAL_LIB_DIR=$(CASUAL_BASE_DIR)/casual
+CASUAL_LIB_LISP_DIR=$(CASUAL_LIB_DIR)/lisp
+CASUAL_LIB_TEST_INCLUDES=$(CASUAL_LIB_DIR)/tests/casual-lib-test-utils.el
+EMACS_ELPA_DIR=$(HOME)/.config/emacs/elpa
diff --git a/lisp/Makefile-info.make b/lisp/Makefile--rules.make
similarity index 72%
copy from lisp/Makefile-info.make
copy to lisp/Makefile--rules.make
index 4ca43576b1..41a188f493 100644
--- a/lisp/Makefile-info.make
+++ b/lisp/Makefile--rules.make
@@ -14,29 +14,6 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-TIMESTAMP := $(shell /bin/date "+%Y%m%d_%H%M%S")
-
-EMACS_MAC_APP_HOME=/Applications/MacPorts/EmacsMac.app
-EMACS_MAC_APP_SH=$(EMACS_MAC_APP_HOME)/Contents/MacOS/Emacs.sh
-
-ifneq ("$(wildcard $(EMACS_MAC_APP_SH))","")
-  EXEC_NAME=$(EMACS_MAC_APP_SH)
-else
-  EXEC_NAME=emacs
-endif
-
-PACKAGE_NAME=casual-info
-ELISP_INCLUDES=casual-info-variables.el casual-info-utils.el
-ELISP_PACKAGES=casual-info-settings.el
-ELISP_TEST_INCLUDES=casual-info-test-utils.el
-CASUAL_BASE_DIR=$(HOME)/Projects/elisp
-CASUAL_LIB_DIR=$(CASUAL_BASE_DIR)/casual
-CASUAL_LIB_LISP_DIR=$(CASUAL_LIB_DIR)/lisp
-CASUAL_LIB_TEST_INCLUDES=$(CASUAL_LIB_DIR)/tests/casual-lib-test-utils.el
-EMACS_CONFIG_DIR=$(HOME)/.config/emacs
-PACKAGE_PATHS=-L $(CASUAL_LIB_LISP_DIR)
-
-
 .PHONY: tests compile regression
 
 .SUFFIXES: .el .elc .elt
diff --git a/lisp/Makefile-agenda.make b/lisp/Makefile-agenda.make
index d026754ed4..0611693120 100644
--- a/lisp/Makefile-agenda.make
+++ b/lisp/Makefile-agenda.make
@@ -14,73 +14,17 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-TIMESTAMP := $(shell /bin/date "+%Y%m%d_%H%M%S")
-
-EMACS_MAC_APP_HOME=/Applications/MacPorts/EmacsMac.app
-EMACS_MAC_APP_SH=$(EMACS_MAC_APP_HOME)/Contents/MacOS/Emacs.sh
-
-ifneq ("$(wildcard $(EMACS_MAC_APP_SH))","")
-  EXEC_NAME=$(EMACS_MAC_APP_SH)
-else
-  EXEC_NAME=emacs
-endif
+include Makefile--defines.make
 
 PACKAGE_NAME=casual-agenda
 ELISP_INCLUDES=casual-agenda-utils.el          \
 casual-agenda-settings.el
 ELISP_PACKAGES=
 ELISP_TEST_INCLUDES=casual-agenda-test-utils.el
-CASUAL_BASE_DIR=$(HOME)/Projects/elisp
-CASUAL_LIB_DIR=$(CASUAL_BASE_DIR)/casual
-CASUAL_LIB_LISP_DIR=$(CASUAL_LIB_DIR)/lisp
-CASUAL_LIB_TEST_INCLUDES=$(CASUAL_LIB_DIR)/tests/casual-lib-test-utils.el
-EMACS_ELPA_DIR=$(HOME)/.config/emacs/elpa
 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)
 
-.PHONY: tests compile regression
-
-.SUFFIXES: .el .elc .elt
-
-.el.elc :
-       $(EXEC_NAME) -Q --batch $(patsubst %, -l %, $(ELISP_INCLUDES)) \
--f batch-byte-compile $<
-
-.el.elt :
-       $(EXEC_NAME) -Q --batch                         \
-$(PACKAGE_PATHS)                                       \
-$(patsubst %, -l %, $(ELISP_INCLUDES))                 \
--l $<                                                  \
--l $(CASUAL_LIB_TEST_INCLUDES)                         \
--l $(patsubst %, ../tests/%, $(ELISP_TEST_INCLUDES))   \
--l $(patsubst %, ../tests/test-%, $<)                  \
--f ert-run-tests-batch-and-exit
-
-tests: $(ELISP_PACKAGES:.el=.elt) $(ELISP_INCLUDES:.el=.elt) 
$(PACKAGE_NAME).elt
-
-compile: $(ELISP_PACKAGES:.el=.elc) $(ELISP_INCLUDES:.el=.elc) 
$(PACKAGE_NAME).elc
-
-$(PACKAGE_NAME).elc: $(PACKAGE_NAME).el
-       $(EXEC_NAME) -Q --batch $(patsubst %, -l %, $(ELISP_INCLUDES))  \
-$(patsubst %, -l %, $(ELISP_PACKAGES))                                 \
-$(PACKAGE_PATHS)                                                       \
--f batch-byte-compile $<
-
-$(PACKAGE_NAME).elt: $(PACKAGE_NAME).el
-       $(EXEC_NAME) -Q --batch                 \
-$(PACKAGE_PATHS)                               \
-$(patsubst %, -l %, $(ELISP_INCLUDES))         \
-$(patsubst %, -l %, $(ELISP_PACKAGES))         \
--l $<                                          \
--l $(CASUAL_LIB_TEST_INCLUDES)                 \
--l ../tests/$(ELISP_TEST_INCLUDES)             \
--l $(patsubst %, ../tests/test-%, $<)          \
--f ert-run-tests-batch-and-exit
-
-regression: clean compile tests
-
-clean:
-       rm -f *.elc
+include Makefile--rules.make
diff --git a/lisp/Makefile-bookmarks.make b/lisp/Makefile-bookmarks.make
index b3c07754f5..c50a194d2f 100644
--- a/lisp/Makefile-bookmarks.make
+++ b/lisp/Makefile-bookmarks.make
@@ -14,74 +14,17 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-TIMESTAMP := $(shell /bin/date "+%Y%m%d_%H%M%S")
-
-EMACS_MAC_APP_HOME=/Applications/MacPorts/EmacsMac.app
-EMACS_MAC_APP_SH=$(EMACS_MAC_APP_HOME)/Contents/MacOS/Emacs.sh
-
-ifneq ("$(wildcard $(EMACS_MAC_APP_SH))","")
-  EXEC_NAME=$(EMACS_MAC_APP_SH)
-else
-  EXEC_NAME=emacs
-endif
+include Makefile--defines.make
 
 PACKAGE_NAME=casual-bookmarks
 ELISP_INCLUDES=casual-bookmarks-utils.el       \
 casual-bookmarks-settings.el
 ELISP_PACKAGES=
 ELISP_TEST_INCLUDES=casual-bookmarks-test-utils.el
-CASUAL_BASE_DIR=$(HOME)/Projects/elisp
-CASUAL_LIB_DIR=$(CASUAL_BASE_DIR)/casual
-CASUAL_LIB_LISP_DIR=$(CASUAL_LIB_DIR)/lisp
-CASUAL_LIB_TEST_INCLUDES=$(CASUAL_LIB_DIR)/tests/casual-lib-test-utils.el
-EMACS_ELPA_DIR=$(HOME)/.config/emacs/elpa
 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)
 
-.PHONY: tests compile regression
-
-.SUFFIXES: .el .elc .elt
-
-.el.elc :
-       $(EXEC_NAME) -Q --batch $(patsubst %, -l %, $(ELISP_INCLUDES))  \
-$(PACKAGE_PATHS)                                                       \
--f batch-byte-compile $<
-
-.el.elt :
-       $(EXEC_NAME) -Q --batch                         \
-$(PACKAGE_PATHS)                                       \
-$(patsubst %, -l %, $(ELISP_INCLUDES))                 \
--l $<                                                  \
--l $(CASUAL_LIB_TEST_INCLUDES)                         \
--l $(patsubst %, ../tests/%, $(ELISP_TEST_INCLUDES))   \
--l $(patsubst %, ../tests/test-%, $<)                  \
--f ert-run-tests-batch-and-exit
-
-tests: $(ELISP_PACKAGES:.el=.elt) $(ELISP_INCLUDES:.el=.elt) 
$(PACKAGE_NAME).elt
-
-compile: $(ELISP_PACKAGES:.el=.elc) $(ELISP_INCLUDES:.el=.elc) 
$(PACKAGE_NAME).elc
-
-$(PACKAGE_NAME).elc: $(PACKAGE_NAME).el
-       $(EXEC_NAME) -Q --batch $(patsubst %, -l %, $(ELISP_INCLUDES))  \
-$(patsubst %, -l %, $(ELISP_PACKAGES))                                 \
-$(PACKAGE_PATHS)                                                       \
--f batch-byte-compile $<
-
-$(PACKAGE_NAME).elt: $(PACKAGE_NAME).el
-       $(EXEC_NAME) -Q --batch                 \
-$(PACKAGE_PATHS)                               \
-$(patsubst %, -l %, $(ELISP_INCLUDES))         \
-$(patsubst %, -l %, $(ELISP_PACKAGES))         \
--l $<                                          \
--l $(CASUAL_LIB_TEST_INCLUDES)                 \
--l ../tests/$(ELISP_TEST_INCLUDES)             \
--l $(patsubst %, ../tests/test-%, $<)          \
--f ert-run-tests-batch-and-exit
-
-regression: clean compile tests
-
-clean:
-       rm -f *.elc
+include Makefile--rules.make
diff --git a/lisp/Makefile-calc.make b/lisp/Makefile-calc.make
index 1731acf6f0..1920d77cf3 100644
--- a/lisp/Makefile-calc.make
+++ b/lisp/Makefile-calc.make
@@ -13,17 +13,7 @@
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-TIMESTAMP := $(shell /bin/date "+%Y%m%d_%H%M%S")
-
-EMACS_MAC_APP_HOME=/Applications/MacPorts/EmacsMac.app
-EMACS_MAC_APP_SH=$(EMACS_MAC_APP_HOME)/Contents/MacOS/Emacs.sh
-
-ifneq ("$(wildcard $(EMACS_MAC_APP_SH))","")
-  EXEC_NAME=$(EMACS_MAC_APP_SH)
-else
-  EXEC_NAME=emacs
-endif
+include Makefile--defines.make
 
 PACKAGE_NAME=casual-calc
 
@@ -58,53 +48,6 @@ casual-calc-symbolic.el
 
 ELISP_TEST_INCLUDES=casual-calc-test-utils.el
 
-CASUAL_BASE_DIR=$(HOME)/Projects/elisp
-CASUAL_LIB_DIR=$(CASUAL_BASE_DIR)/casual
-CASUAL_LIB_LISP_DIR=$(CASUAL_LIB_DIR)/lisp
-CASUAL_LIB_TEST_INCLUDES=$(CASUAL_LIB_DIR)/tests/casual-lib-test-utils.el
-EMACS_CONFIG_DIR=$(HOME)/.config/emacs
 PACKAGE_PATHS=-L $(CASUAL_LIB_LISP_DIR)
 
-.PHONY: tests compile regression
-
-.SUFFIXES: .el .elc .elt
-
-.el.elc :
-       $(EXEC_NAME) -Q --batch $(patsubst %, -l %, $(ELISP_INCLUDES)) \
--f batch-byte-compile $<
-
-.el.elt :
-       $(EXEC_NAME) -Q --batch                         \
-$(PACKAGE_PATHS)                                       \
-$(patsubst %, -l %, $(ELISP_INCLUDES))                 \
--l $<                                                  \
--l $(CASUAL_LIB_TEST_INCLUDES)                         \
--l $(patsubst %, ../tests/%, $(ELISP_TEST_INCLUDES))   \
--l $(patsubst %, ../tests/test-%, $<)                  \
--f ert-run-tests-batch-and-exit
-
-tests: $(ELISP_PACKAGES:.el=.elt) $(ELISP_INCLUDES:.el=.elt) 
$(PACKAGE_NAME).elt
-
-compile: $(ELISP_PACKAGES:.el=.elc) $(ELISP_INCLUDES:.el=.elc) 
$(PACKAGE_NAME).elc
-
-$(PACKAGE_NAME).elc: $(PACKAGE_NAME).el
-       $(EXEC_NAME) -Q --batch $(patsubst %, -l %, $(ELISP_INCLUDES))  \
-$(patsubst %, -l %, $(ELISP_PACKAGES))                                 \
-$(PACKAGE_PATHS)                                                       \
--f batch-byte-compile $<
-
-$(PACKAGE_NAME).elt: $(PACKAGE_NAME).el
-       $(EXEC_NAME) -Q --batch                 \
-$(PACKAGE_PATHS)                               \
-$(patsubst %, -l %, $(ELISP_INCLUDES))         \
-$(patsubst %, -l %, $(ELISP_PACKAGES))         \
--l $<                                          \
--l $(CASUAL_LIB_TEST_INCLUDES)                 \
--l ../tests/$(ELISP_TEST_INCLUDES)             \
--l $(patsubst %, ../tests/test-%, $<)          \
--f ert-run-tests-batch-and-exit
-
-regression: clean compile tests
-
-clean:
-       rm -f *.elc
+include Makefile--rules.make
diff --git a/lisp/Makefile-dired.make b/lisp/Makefile-dired.make
index 882a7b565e..bc13b28b8d 100644
--- a/lisp/Makefile-dired.make
+++ b/lisp/Makefile-dired.make
@@ -13,69 +13,12 @@
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-TIMESTAMP := $(shell /bin/date "+%Y%m%d_%H%M%S")
-
-EMACS_MAC_APP_HOME=/Applications/MacPorts/EmacsMac.app
-EMACS_MAC_APP_SH=$(EMACS_MAC_APP_HOME)/Contents/MacOS/Emacs.sh
-
-ifneq ("$(wildcard $(EMACS_MAC_APP_SH))","")
-  EXEC_NAME=$(EMACS_MAC_APP_SH)
-else
-  EXEC_NAME=emacs
-endif
+include Makefile--defines.make
 
 PACKAGE_NAME=casual-dired
 ELISP_INCLUDES=casual-dired-variables.el casual-dired-utils.el
 ELISP_PACKAGES=casual-dired-settings.el casual-dired-sort-by.el
 ELISP_TEST_INCLUDES=casual-dired-test-utils.el
-CASUAL_BASE_DIR=$(HOME)/Projects/elisp
-CASUAL_LIB_DIR=$(CASUAL_BASE_DIR)/casual
-CASUAL_LIB_LISP_DIR=$(CASUAL_LIB_DIR)/lisp
-CASUAL_LIB_TEST_INCLUDES=$(CASUAL_LIB_DIR)/tests/casual-lib-test-utils.el
-EMACS_CONFIG_DIR=$(HOME)/.config/emacs
 PACKAGE_PATHS=-L $(CASUAL_LIB_LISP_DIR)
 
-.PHONY: tests compile regression
-
-.SUFFIXES: .el .elc .elt
-
-.el.elc :
-       $(EXEC_NAME) -Q --batch $(patsubst %, -l %, $(ELISP_INCLUDES)) \
--f batch-byte-compile $<
-
-.el.elt :
-       $(EXEC_NAME) -Q --batch                         \
-$(PACKAGE_PATHS)                                       \
-$(patsubst %, -l %, $(ELISP_INCLUDES))                 \
--l $<                                                  \
--l $(CASUAL_LIB_TEST_INCLUDES)                         \
--l $(patsubst %, ../tests/%, $(ELISP_TEST_INCLUDES))   \
--l $(patsubst %, ../tests/test-%, $<)                  \
--f ert-run-tests-batch-and-exit
-
-tests: $(ELISP_PACKAGES:.el=.elt) $(ELISP_INCLUDES:.el=.elt) 
$(PACKAGE_NAME).elt
-
-compile: $(ELISP_PACKAGES:.el=.elc) $(ELISP_INCLUDES:.el=.elc) 
$(PACKAGE_NAME).elc
-
-$(PACKAGE_NAME).elc: $(PACKAGE_NAME).el
-       $(EXEC_NAME) -Q --batch $(patsubst %, -l %, $(ELISP_INCLUDES))  \
-$(patsubst %, -l %, $(ELISP_PACKAGES))                                 \
-$(PACKAGE_PATHS)                                                       \
--f batch-byte-compile $<
-
-$(PACKAGE_NAME).elt: $(PACKAGE_NAME).el
-       $(EXEC_NAME) -Q --batch                 \
-$(PACKAGE_PATHS)                               \
-$(patsubst %, -l %, $(ELISP_INCLUDES))         \
-$(patsubst %, -l %, $(ELISP_PACKAGES))         \
--l $<                                          \
--l $(CASUAL_LIB_TEST_INCLUDES)                 \
--l ../tests/$(ELISP_TEST_INCLUDES)             \
--l $(patsubst %, ../tests/test-%, $<)          \
--f ert-run-tests-batch-and-exit
-
-regression: clean compile tests
-
-clean:
-       rm -f *.elc
+include Makefile--rules.make
diff --git a/lisp/Makefile-editkit.make b/lisp/Makefile-editkit.make
index 39bf592ae4..576e2f7510 100644
--- a/lisp/Makefile-editkit.make
+++ b/lisp/Makefile-editkit.make
@@ -13,17 +13,7 @@
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-TIMESTAMP := $(shell /bin/date "+%Y%m%d_%H%M%S")
-
-EMACS_MAC_APP_HOME=/Applications/MacPorts/EmacsMac.app
-EMACS_MAC_APP_SH=$(EMACS_MAC_APP_HOME)/Contents/MacOS/Emacs.sh
-
-ifneq ("$(wildcard $(EMACS_MAC_APP_SH))","")
-  EXEC_NAME=$(EMACS_MAC_APP_SH)
-else
-  EXEC_NAME=emacs
-endif
+include Makefile--defines.make
 
 PACKAGE_NAME=casual-editkit
 ELISP_INCLUDES=casual-editkit-constants.el     \
@@ -31,11 +21,6 @@ casual-editkit-utils.el                              \
 casual-editkit-settings.el
 ELISP_PACKAGES=
 ELISP_TEST_INCLUDES=casual-editkit-test-utils.el
-CASUAL_BASE_DIR=$(HOME)/Projects/elisp
-CASUAL_LIB_DIR=$(CASUAL_BASE_DIR)/casual
-CASUAL_LIB_LISP_DIR=$(CASUAL_LIB_DIR)/lisp
-CASUAL_LIB_TEST_INCLUDES=$(CASUAL_LIB_DIR)/tests/casual-lib-test-utils.el
-EMACS_ELPA_DIR=$(HOME)/.config/emacs/elpa
 PACKAGE_PATHS=                                 \
 -L $(EMACS_ELPA_DIR)/compat-30.0.0.0           \
 -L $(EMACS_ELPA_DIR)/seq-2.24                  \
@@ -48,47 +33,4 @@ PACKAGE_PATHS=                                       \
 -L $(EMACS_ELPA_DIR)/symbol-overlay-current    \
 -L $(CASUAL_LIB_LISP_DIR)
 
-.PHONY: tests compile regression
-
-.SUFFIXES: .el .elc .elt
-
-.el.elc :
-       $(EXEC_NAME) -Q --batch $(patsubst %, -l %, $(ELISP_INCLUDES))  \
-$(PACKAGE_PATHS)                                                       \
--f batch-byte-compile $<
-
-.el.elt :
-       $(EXEC_NAME) -Q --batch                         \
-$(PACKAGE_PATHS)                                       \
-$(patsubst %, -l %, $(ELISP_INCLUDES))                 \
--l $<                                                  \
--l $(CASUAL_LIB_TEST_INCLUDES)                         \
--l $(patsubst %, ../tests/%, $(ELISP_TEST_INCLUDES))   \
--l $(patsubst %, ../tests/test-%, $<)                  \
--f ert-run-tests-batch-and-exit
-
-tests: $(ELISP_PACKAGES:.el=.elt) $(ELISP_INCLUDES:.el=.elt) 
$(PACKAGE_NAME).elt
-
-compile: $(ELISP_PACKAGES:.el=.elc) $(ELISP_INCLUDES:.el=.elc) 
$(PACKAGE_NAME).elc
-
-$(PACKAGE_NAME).elc: $(PACKAGE_NAME).el
-       $(EXEC_NAME) -Q --batch $(patsubst %, -l %, $(ELISP_INCLUDES))  \
-$(patsubst %, -l %, $(ELISP_PACKAGES))                                 \
-$(PACKAGE_PATHS)                                                       \
--f batch-byte-compile $<
-
-$(PACKAGE_NAME).elt: $(PACKAGE_NAME).el
-       $(EXEC_NAME) -Q --batch                 \
-$(PACKAGE_PATHS)                               \
-$(patsubst %, -l %, $(ELISP_INCLUDES))         \
-$(patsubst %, -l %, $(ELISP_PACKAGES))         \
--l $<                                          \
--l $(CASUAL_LIB_TEST_INCLUDES)                 \
--l ../tests/$(ELISP_TEST_INCLUDES)             \
--l $(patsubst %, ../tests/test-%, $<)          \
--f ert-run-tests-batch-and-exit
-
-regression: clean compile tests
-
-clean:
-       rm -f *.elc
+include Makefile--rules.make
diff --git a/lisp/Makefile-ibuffer.make b/lisp/Makefile-ibuffer.make
index 4f3315b31e..29d6c7868b 100644
--- a/lisp/Makefile-ibuffer.make
+++ b/lisp/Makefile-ibuffer.make
@@ -13,74 +13,17 @@
 
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
-
-TIMESTAMP := $(shell /bin/date "+%Y%m%d_%H%M%S")
-
-EMACS_MAC_APP_HOME=/Applications/MacPorts/EmacsMac.app
-EMACS_MAC_APP_SH=$(EMACS_MAC_APP_HOME)/Contents/MacOS/Emacs.sh
-
-ifneq ("$(wildcard $(EMACS_MAC_APP_SH))","")
-  EXEC_NAME=$(EMACS_MAC_APP_SH)
-else
-  EXEC_NAME=emacs
-endif
+include Makefile--defines.make
 
 PACKAGE_NAME=casual-ibuffer
 ELISP_INCLUDES=casual-ibuffer-utils.el         \
 casual-ibuffer-settings.el
 ELISP_PACKAGES=casual-ibuffer-filter.el
 ELISP_TEST_INCLUDES=casual-ibuffer-test-utils.el
-CASUAL_BASE_DIR=$(HOME)/Projects/elisp
-CASUAL_LIB_DIR=$(CASUAL_BASE_DIR)/casual
-CASUAL_LIB_LISP_DIR=$(CASUAL_LIB_DIR)/lisp
-CASUAL_LIB_TEST_INCLUDES=$(CASUAL_LIB_DIR)/tests/casual-lib-test-utils.el
-EMACS_ELPA_DIR=$(HOME)/.config/emacs/elpa
 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)
 
-.PHONY: tests compile regression
-
-.SUFFIXES: .el .elc .elt
-
-.el.elc :
-       $(EXEC_NAME) -Q --batch $(patsubst %, -l %, $(ELISP_INCLUDES)) \
--f batch-byte-compile $<
-
-.el.elt :
-       $(EXEC_NAME) -Q --batch                         \
-$(PACKAGE_PATHS)                                       \
-$(patsubst %, -l %, $(ELISP_INCLUDES))                 \
--l $<                                                  \
--l $(CASUAL_LIB_TEST_INCLUDES)                         \
--l $(patsubst %, ../tests/%, $(ELISP_TEST_INCLUDES))   \
--l $(patsubst %, ../tests/test-%, $<)                  \
--f ert-run-tests-batch-and-exit
-
-tests: $(ELISP_PACKAGES:.el=.elt) $(ELISP_INCLUDES:.el=.elt) 
$(PACKAGE_NAME).elt
-
-compile: $(ELISP_PACKAGES:.el=.elc) $(ELISP_INCLUDES:.el=.elc) 
$(PACKAGE_NAME).elc
-
-$(PACKAGE_NAME).elc: $(PACKAGE_NAME).el
-       $(EXEC_NAME) -Q --batch $(patsubst %, -l %, $(ELISP_INCLUDES))  \
-$(patsubst %, -l %, $(ELISP_PACKAGES))                                 \
-$(PACKAGE_PATHS)                                                       \
--f batch-byte-compile $<
-
-$(PACKAGE_NAME).elt: $(PACKAGE_NAME).el
-       $(EXEC_NAME) -Q --batch                 \
-$(PACKAGE_PATHS)                               \
-$(patsubst %, -l %, $(ELISP_INCLUDES))         \
-$(patsubst %, -l %, $(ELISP_PACKAGES))         \
--l $<                                          \
--l $(CASUAL_LIB_TEST_INCLUDES)                 \
--l ../tests/$(ELISP_TEST_INCLUDES)             \
--l $(patsubst %, ../tests/test-%, $<)          \
--f ert-run-tests-batch-and-exit
-
-regression: clean compile tests
-
-clean:
-       rm -f *.elc
+include Makefile--rules.make
diff --git a/lisp/Makefile-info.make b/lisp/Makefile-info.make
index 4ca43576b1..f874c31b40 100644
--- a/lisp/Makefile-info.make
+++ b/lisp/Makefile-info.make
@@ -14,69 +14,12 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-TIMESTAMP := $(shell /bin/date "+%Y%m%d_%H%M%S")
-
-EMACS_MAC_APP_HOME=/Applications/MacPorts/EmacsMac.app
-EMACS_MAC_APP_SH=$(EMACS_MAC_APP_HOME)/Contents/MacOS/Emacs.sh
-
-ifneq ("$(wildcard $(EMACS_MAC_APP_SH))","")
-  EXEC_NAME=$(EMACS_MAC_APP_SH)
-else
-  EXEC_NAME=emacs
-endif
+include Makefile--defines.make
 
 PACKAGE_NAME=casual-info
 ELISP_INCLUDES=casual-info-variables.el casual-info-utils.el
 ELISP_PACKAGES=casual-info-settings.el
 ELISP_TEST_INCLUDES=casual-info-test-utils.el
-CASUAL_BASE_DIR=$(HOME)/Projects/elisp
-CASUAL_LIB_DIR=$(CASUAL_BASE_DIR)/casual
-CASUAL_LIB_LISP_DIR=$(CASUAL_LIB_DIR)/lisp
-CASUAL_LIB_TEST_INCLUDES=$(CASUAL_LIB_DIR)/tests/casual-lib-test-utils.el
-EMACS_CONFIG_DIR=$(HOME)/.config/emacs
 PACKAGE_PATHS=-L $(CASUAL_LIB_LISP_DIR)
 
-
-.PHONY: tests compile regression
-
-.SUFFIXES: .el .elc .elt
-
-.el.elc :
-       $(EXEC_NAME) -Q --batch $(patsubst %, -l %, $(ELISP_INCLUDES)) \
--f batch-byte-compile $<
-
-.el.elt :
-       $(EXEC_NAME) -Q --batch                         \
-$(PACKAGE_PATHS)                                       \
-$(patsubst %, -l %, $(ELISP_INCLUDES))                 \
--l $<                                                  \
--l $(CASUAL_LIB_TEST_INCLUDES)                         \
--l $(patsubst %, ../tests/%, $(ELISP_TEST_INCLUDES))   \
--l $(patsubst %, ../tests/test-%, $<)                  \
--f ert-run-tests-batch-and-exit
-
-tests: $(ELISP_PACKAGES:.el=.elt) $(ELISP_INCLUDES:.el=.elt) 
$(PACKAGE_NAME).elt
-
-compile: $(ELISP_PACKAGES:.el=.elc) $(ELISP_INCLUDES:.el=.elc) 
$(PACKAGE_NAME).elc
-
-$(PACKAGE_NAME).elc: $(PACKAGE_NAME).el
-       $(EXEC_NAME) -Q --batch $(patsubst %, -l %, $(ELISP_INCLUDES))  \
-$(patsubst %, -l %, $(ELISP_PACKAGES))                                 \
-$(PACKAGE_PATHS)                                                       \
--f batch-byte-compile $<
-
-$(PACKAGE_NAME).elt: $(PACKAGE_NAME).el
-       $(EXEC_NAME) -Q --batch                 \
-$(PACKAGE_PATHS)                               \
-$(patsubst %, -l %, $(ELISP_INCLUDES))         \
-$(patsubst %, -l %, $(ELISP_PACKAGES))         \
--l $<                                          \
--l $(CASUAL_LIB_TEST_INCLUDES)                 \
--l ../tests/$(ELISP_TEST_INCLUDES)             \
--l $(patsubst %, ../tests/test-%, $<)          \
--f ert-run-tests-batch-and-exit
-
-regression: clean compile tests
-
-clean:
-       rm -f *.elc
+include Makefile--rules.make
diff --git a/lisp/Makefile-isearch.make b/lisp/Makefile-isearch.make
index aa00ad3832..a1b3cd1cbb 100644
--- a/lisp/Makefile-isearch.make
+++ b/lisp/Makefile-isearch.make
@@ -14,27 +14,13 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-TIMESTAMP := $(shell /bin/date "+%Y%m%d_%H%M%S")
-
-EMACS_MAC_APP_HOME=/Applications/MacPorts/EmacsMac.app
-EMACS_MAC_APP_SH=$(EMACS_MAC_APP_HOME)/Contents/MacOS/Emacs.sh
-
-ifneq ("$(wildcard $(EMACS_MAC_APP_SH))","")
-  EXEC_NAME=$(EMACS_MAC_APP_SH)
-else
-  EXEC_NAME=emacs
-endif
+include Makefile--defines.make
 
 PACKAGE_NAME=casual-isearch
 ELISP_INCLUDES=casual-isearch-utils.el         \
 casual-isearch-settings.el
 ELISP_PACKAGES=
 ELISP_TEST_INCLUDES=casual-isearch-test-utils.el
-CASUAL_BASE_DIR=$(HOME)/Projects/elisp
-CASUAL_LIB_DIR=$(CASUAL_BASE_DIR)/casual
-CASUAL_LIB_LISP_DIR=$(CASUAL_LIB_DIR)/lisp
-CASUAL_LIB_TEST_INCLUDES=$(CASUAL_LIB_DIR)/tests/casual-lib-test-utils.el
-EMACS_ELPA_DIR=$(HOME)/.config/emacs/elpa
 PACKAGE_PATHS=                                 \
 -L $(EMACS_ELPA_DIR)/compat-30.0.0.0           \
 -L $(EMACS_ELPA_DIR)/seq-2.24                  \
diff --git a/lisp/Makefile-lib.make b/lisp/Makefile-lib.make
index 0cc6ff9d17..3cc284bf03 100644
--- a/lisp/Makefile-lib.make
+++ b/lisp/Makefile-lib.make
@@ -14,23 +14,12 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-TIMESTAMP := $(shell /bin/date "+%Y%m%d_%H%M%S")
-
-EMACS_MAC_APP_HOME=/Applications/MacPorts/EmacsMac.app
-EMACS_MAC_APP_SH=$(EMACS_MAC_APP_HOME)/Contents/MacOS/Emacs.sh
-
-ifneq ("$(wildcard $(EMACS_MAC_APP_SH))","")
-  EXEC_NAME=$(EMACS_MAC_APP_SH)
-else
-  EXEC_NAME=emacs
-endif
+include Makefile--defines.make
 
 ELISP_INCLUDES=
 ELISP_PACKAGES=
 ELISP_TEST_INCLUDES=casual-lib-test-utils.el
 PACKAGE_NAME=casual-lib
-CASUAL_BASE_DIR=$(HOME)/Projects/elisp
-EMACS_CONFIG_DIR=$(HOME)/.config/emacs
 PACKAGE_PATHS=
 
 .PHONY: tests compile regression
diff --git a/lisp/Makefile-re-builder.make b/lisp/Makefile-re-builder.make
index 9bc39005b4..bcc8377480 100644
--- a/lisp/Makefile-re-builder.make
+++ b/lisp/Makefile-re-builder.make
@@ -14,73 +14,17 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-TIMESTAMP := $(shell /bin/date "+%Y%m%d_%H%M%S")
-
-EMACS_MAC_APP_HOME=/Applications/MacPorts/EmacsMac.app
-EMACS_MAC_APP_SH=$(EMACS_MAC_APP_HOME)/Contents/MacOS/Emacs.sh
-
-ifneq ("$(wildcard $(EMACS_MAC_APP_SH))","")
-  EXEC_NAME=$(EMACS_MAC_APP_SH)
-else
-  EXEC_NAME=emacs
-endif
+include Makefile--defines.make
 
 PACKAGE_NAME=casual-re-builder
 ELISP_INCLUDES=casual-re-builder-utils.el      \
 casual-re-builder-settings.el
 ELISP_PACKAGES=
 ELISP_TEST_INCLUDES=casual-re-builder-test-utils.el
-CASUAL_BASE_DIR=$(HOME)/Projects/elisp
-CASUAL_LIB_DIR=$(CASUAL_BASE_DIR)/casual
-CASUAL_LIB_LISP_DIR=$(CASUAL_LIB_DIR)/lisp
-CASUAL_LIB_TEST_INCLUDES=$(CASUAL_LIB_DIR)/tests/casual-lib-test-utils.el
-EMACS_ELPA_DIR=$(HOME)/.config/emacs/elpa
 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)
 
-.PHONY: tests compile regression
-
-.SUFFIXES: .el .elc .elt
-
-.el.elc :
-       $(EXEC_NAME) -Q --batch $(patsubst %, -l %, $(ELISP_INCLUDES)) \
--f batch-byte-compile $<
-
-.el.elt :
-       $(EXEC_NAME) -Q --batch                         \
-$(PACKAGE_PATHS)                                       \
-$(patsubst %, -l %, $(ELISP_INCLUDES))                 \
--l $<                                                  \
--l $(CASUAL_LIB_TEST_INCLUDES)                         \
--l $(patsubst %, ../tests/%, $(ELISP_TEST_INCLUDES))   \
--l $(patsubst %, ../tests/test-%, $<)                  \
--f ert-run-tests-batch-and-exit
-
-tests: $(ELISP_PACKAGES:.el=.elt) $(ELISP_INCLUDES:.el=.elt) 
$(PACKAGE_NAME).elt
-
-compile: $(ELISP_PACKAGES:.el=.elc) $(ELISP_INCLUDES:.el=.elc) 
$(PACKAGE_NAME).elc
-
-$(PACKAGE_NAME).elc: $(PACKAGE_NAME).el
-       $(EXEC_NAME) -Q --batch $(patsubst %, -l %, $(ELISP_INCLUDES))  \
-$(patsubst %, -l %, $(ELISP_PACKAGES))                                 \
-$(PACKAGE_PATHS)                                                       \
--f batch-byte-compile $<
-
-$(PACKAGE_NAME).elt: $(PACKAGE_NAME).el
-       $(EXEC_NAME) -Q --batch                 \
-$(PACKAGE_PATHS)                               \
-$(patsubst %, -l %, $(ELISP_INCLUDES))         \
-$(patsubst %, -l %, $(ELISP_PACKAGES))         \
--l $<                                          \
--l $(CASUAL_LIB_TEST_INCLUDES)                 \
--l ../tests/$(ELISP_TEST_INCLUDES)             \
--l $(patsubst %, ../tests/test-%, $<)          \
--f ert-run-tests-batch-and-exit
-
-regression: clean compile tests
-
-clean:
-       rm -f *.elc
+include Makefile--rules.make
diff --git a/lisp/casual-calc-conversion.el b/lisp/casual-calc-conversion.el
index 9f71d5d919..fee7b82e08 100644
--- a/lisp/casual-calc-conversion.el
+++ b/lisp/casual-calc-conversion.el
@@ -30,7 +30,9 @@
 
 (transient-define-prefix casual-calc-conversions-tmenu ()
   "Casual conversion functions menu."
-  [["Conversions"
+  ["Conversions"
+
+   ["Angle"
     ("d" "To Degrees" calc-to-degrees
      :description (lambda ()
                     (format "%s %s %s"
@@ -44,10 +46,35 @@
                             (casual-calc-unicode-get :degrees)
                             (casual-calc-unicode-get :to)
                             (casual-calc-unicode-get :radians)))
-     :transient t)
-    ("h" "To HMS" calc-to-hms :transient t)
-    ("f" "To Float" calc-float :transient t)
-    ("F" "To Fraction" calc-fraction :transient t)]]
+     :transient t)]
+
+    ["HMS"
+     ("h" "To β„Žπ‘šπ‘ " calc-to-hms
+      :description (lambda ()
+                    (format "real %s %s"
+                            (casual-calc-unicode-get :to)
+                            (casual-calc-unicode-get :hms)))
+      :transient t)
+     ("H" "From β„Žπ‘šπ‘ " calc-from-hms
+      :description (lambda ()
+                     (format "%s %s real"
+                             (casual-calc-unicode-get :hms)
+                             (casual-calc-unicode-get :to)))
+      :transient t)]
+
+    ["Numeric"
+     ("f" "To Float" calc-float
+      :description (lambda ()
+                     (format "%s %s"
+                             (casual-calc-unicode-get :to)
+                             (casual-calc-unicode-get :float)))
+      :transient t)
+     ("F" "To Fraction" calc-fraction
+      :description (lambda ()
+                     (format "%s %s"
+                             (casual-calc-unicode-get :to)
+                             (casual-calc-unicode-get :fraction)))
+      :transient t)]]
 
   casual-calc-operators-group-row
 
diff --git a/lisp/casual-calc-settings.el b/lisp/casual-calc-settings.el
index 5a88f2175d..466a1f4315 100644
--- a/lisp/casual-calc-settings.el
+++ b/lisp/casual-calc-settings.el
@@ -100,7 +100,8 @@
     ("H" "β„Žπ‘šπ‘  Format" calc-hms-notation
      :description (lambda ()
                     (format
-                     "Set β„Žπ‘šπ‘  Format (now %s)"
+                     "Set %s Format (now %s)"
+                     (casual-calc-unicode-get :hms)
                      (format calc-hms-format "" "" "")))
      :transient t)]
 
diff --git a/lisp/casual-calc-utils.el b/lisp/casual-calc-utils.el
index a165047c8b..4cde3bc2e5 100644
--- a/lisp/casual-calc-utils.el
+++ b/lisp/casual-calc-utils.el
@@ -52,8 +52,11 @@
     (:arcsin . '("π‘Žπ‘Ÿπ‘π‘ π‘–π‘›" "arcsin"))
     (:arccos . '("π‘Žπ‘Ÿπ‘π‘π‘œπ‘ " "arccos"))
     (:arctan . '("π‘Žπ‘Ÿπ‘π‘‘π‘Žπ‘›" "arctan"))
-    (:degrees . '("Β°" "Degrees"))
-    (:radians . '("π‘Ÿπ‘Žπ‘‘" "Radians"))
+    (:degrees . '("Β°" "degrees"))
+    (:radians . '("π‘Ÿπ‘Žπ‘‘" "radians"))
+    (:hms . '("β„Žπ‘šπ‘ " "HMS"))
+    (:float . '("π‘“π‘™π‘œπ‘Žπ‘‘" "float"))
+    (:fraction . '("π‘“π‘Ÿπ‘Žπ‘π‘‘π‘–π‘œπ‘›" "fraction"))
     (:to . '("β†’" "to")))
   "Unicode symbol DB to use for Calc Transient menus.")
 
diff --git a/lisp/casual-dired-settings.el b/lisp/casual-dired-settings.el
index f601f7ab61..d9d3479010 100644
--- a/lisp/casual-dired-settings.el
+++ b/lisp/casual-dired-settings.el
@@ -56,7 +56,14 @@
                    (casual-lib-checkbox-label
                     dired-vc-rename-file
                     "Rename via VC"))
-     :transient nil)]
+     :transient nil)
+
+    ("v" "Visit Truename"
+     casual-dired--customize-find-file-visit-truename
+     :description (lambda ()
+                    (casual-lib-checkbox-label
+                     find-file-visit-truename
+                     "Visit Truename")))]
 
    ["GNU β€˜ls’"
     ("l" "Use GNU β€˜ls’ with β€œ--dired”"
@@ -176,10 +183,19 @@ If non-nil, the permissions bits of the files are 
editable."
   "Customize `wdired-allow-to-redirect-links'.
 
 Customize the variable `wdired-allow-to-redirect-links'.
-If non-nil, the permissions bits of the files are editable."
+If non-nil, the target of the symbolic links are editable."
   (interactive)
   (customize-variable 'wdired-allow-to-redirect-links))
 
+(defun casual-dired--customize-find-file-visit-truename ()
+  "Customize `find-file-visit-truename'.
+
+Customize the variable `find-file-visit-truename'. If non-nil,
+visiting a file uses its truename as the visited-file name. This
+effectively follows a symlink to its actual location."
+  (interactive)
+  (customize-variable 'find-file-visit-truename))
+
 (defun casual-dired--customize-dired-group ()
   "Call the Dired customization group."
   (interactive)
diff --git a/lisp/casual-dired-utils.el b/lisp/casual-dired-utils.el
index 9e3ee2c0c9..667e1bddae 100644
--- a/lisp/casual-dired-utils.el
+++ b/lisp/casual-dired-utils.el
@@ -106,9 +106,17 @@ ASCII-range string."
 
 (transient-define-prefix casual-dired-link-tmenu ()
   ["Link"
-    ("h" "Hard link…" dired-do-hardlink :transient nil)
-    ("H" "Hard link names with regexp…" dired-do-hardlink-regexp :transient 
nil)
-    ("S" "Symbolic link names with regexp…" dired-do-symlink-regexp :transient 
nil)]
+   ["Symbolic"
+    ("s" "Absolute…" dired-do-symlink)
+    ("S" "Absolute regexp…" dired-do-symlink-regexp)]
+
+   ["Relative"
+    ("r" "Relative…" dired-do-relsymlink)
+    ("R" "Relative regexp…" dired-do-relsymlink-regexp)]
+
+   ["Hard"
+    ("h" "Hard…" dired-do-hardlink)
+    ("H" "Hard regexp…" dired-do-hardlink-regexp)]]
 
   [:class transient-row
           (casual-lib-quit-one)
diff --git a/lisp/casual-dired.el b/lisp/casual-dired.el
index a7e9cb657d..f661d88557 100644
--- a/lisp/casual-dired.el
+++ b/lisp/casual-dired.el
@@ -52,10 +52,11 @@
   "Transient menu for Dired."
   [["File"
     ("o" "Open Other" dired-find-file-other-window :transient nil)
+    ("v" "View" dired-view-file)
     ("C" "Copy to…" dired-do-copy :transient t)
     ("R" "Rename…" dired-do-rename :transient t)
     ("D" "Delete…" dired-do-delete :transient t)
-    ("S" "Symlink…" dired-do-symlink :transient nil)
+    ("l" "Linkβ€Ί" casual-dired-link-tmenu :transient nil)
     ("c" "Changeβ€Ί" casual-dired-change-tmenu :transient nil)
     ("y" "Type" dired-show-file-type :transient t)
     ("w" "Copy Name" dired-copy-filename-as-kill :transient nil)
diff --git a/lisp/casual-editkit-utils.el b/lisp/casual-editkit-utils.el
index 59014f5ac9..6a4bbe6fb3 100644
--- a/lisp/casual-editkit-utils.el
+++ b/lisp/casual-editkit-utils.el
@@ -136,6 +136,13 @@ also available from here."
     ("V" "Visit other…" find-file-read-only-other-window)
     ("M-v" "Visit in frame…" find-file-read-only-other-frame)]
 
+   ["Rename"
+    :pad-keys t
+    ("r" "File…" rename-visited-file
+     :inapt-if-not buffer-file-name)
+    ("R" "Buffer…" rename-buffer)
+    ("M-r" "Buffer Uniquely" rename-uniquely)]
+
    ["Project"
     ("p" "Projectβ€Ί" casual-editkit-project-tmenu)]]
 
@@ -636,11 +643,11 @@ Commands pertaining to rectangle operations can be 
accessed here."
      :transient t)]
 
    ["Replace"
-    ("s" "String" string-rectangle
+    ("s" "String…" string-rectangle
      :if-not casual-editkit-buffer-read-only-p
      :inapt-if-not use-region-p
      :transient t)
-    ("i" "String Insert" string-insert-rectangle
+    ("i" "String Insert…" string-insert-rectangle
      :if-not casual-editkit-buffer-read-only-p
      :inapt-if-not use-region-p
      :transient t)
diff --git a/lisp/casual.el b/lisp/casual.el
index cdf2577da6..0260827e76 100644
--- a/lisp/casual.el
+++ b/lisp/casual.el
@@ -5,7 +5,7 @@
 ;; Author: Charles Choi <[email protected]>
 ;; URL: https://github.com/kickingvegas/casual
 ;; Keywords: tools, wp
-;; Version: 2.0.8
+;; Version: 2.0.9-rc.1
 ;; Package-Requires: ((emacs "29.1") (transient "0.6.0"))
 
 ;; This program is free software; you can redistribute it and/or modify
diff --git a/tests/test-casual-calc-conversion.el 
b/tests/test-casual-calc-conversion.el
index 7f57e54733..53a18b24ee 100644
--- a/tests/test-casual-calc-conversion.el
+++ b/tests/test-casual-calc-conversion.el
@@ -33,11 +33,13 @@
       (((symbol-function #'calc-to-degrees) (lambda (x) (interactive)(print 
"WARNING: override")))
        ((symbol-function #'calc-to-radians) (lambda (x) (interactive)(print 
"WARNING: override")))
        ((symbol-function #'calc-to-hms) (lambda (x) (interactive)(print 
"WARNING: override")))
+       ((symbol-function #'calc-from-hms) (lambda (x) (interactive)(print 
"WARNING: override")))
        ((symbol-function #'calc-float) (lambda (x) (interactive)(print 
"WARNING: override")))
        ((symbol-function #'calc-fraction) (lambda (x) (interactive)(print 
"WARNING: override"))))
     (let* ((test-vectors '(("d" . calc-to-degrees)
                            ("r" . calc-to-radians)
                            ("h" . calc-to-hms)
+                           ("H" . calc-from-hms)
                            ("f" . calc-float)
                            ("F" . calc-fraction)))
            (test-vectors (append test-vectors casualt-test-operators-group)))
diff --git a/tests/test-casual-calc-labels.el b/tests/test-casual-calc-labels.el
index d540be6d74..00fd826a78 100644
--- a/tests/test-casual-calc-labels.el
+++ b/tests/test-casual-calc-labels.el
@@ -89,9 +89,9 @@
 (ert-deftest test-casual-calc-angle-mode-label ()
   (casualt-calc-setup)
   (setq calc-angle-mode 'deg)
-  (should (equal (casual-calc-angle-mode-label) "Degrees"))
+  (should (equal (casual-calc-angle-mode-label) "degrees"))
   (setq calc-angle-mode 'rad)
-  (should (equal (casual-calc-angle-mode-label) "Radians"))
+  (should (equal (casual-calc-angle-mode-label) "radians"))
   (setq calc-angle-mode 'hms)
   (should (equal (casual-calc-angle-mode-label) "hms"))
   (casualt-calc-breakdown t))
diff --git a/tests/test-casual-calc-utils.el b/tests/test-casual-calc-utils.el
index e77466b9fa..e419a4beb7 100644
--- a/tests/test-casual-calc-utils.el
+++ b/tests/test-casual-calc-utils.el
@@ -25,6 +25,70 @@
 ;;; Code:
 (require 'ert)
 (require 'casual-calc-test-utils)
+(require 'casual-calc)
+
+(ert-deftest test-casual-calc-unicode-get ()
+  (let ((casual-lib-use-unicode nil))
+    (should (string-equal (casual-calc-unicode-get :inv) "1/x"))
+    (should (string-equal (casual-calc-unicode-get :sqrt) "sqrt"))
+    (should (string-equal (casual-calc-unicode-get :change-sign) "+/-"))
+    (should (string-equal (casual-calc-unicode-get :power) "y^x"))
+    (should (string-equal (casual-calc-unicode-get :abs) "|x|"))
+    (should (string-equal (casual-calc-unicode-get :factorial) "!"))
+    (should (string-equal (casual-calc-unicode-get :percent) "%"))
+    (should (string-equal (casual-calc-unicode-get :percent-change) "% 
change"))
+    (should (string-equal (casual-calc-unicode-get :pi) "pi"))
+    (should (string-equal (casual-calc-unicode-get :e) "e"))
+    (should (string-equal (casual-calc-unicode-get :ln) "ln"))
+    (should (string-equal (casual-calc-unicode-get :lnp1) "ln(x+1)"))
+    (should (string-equal (casual-calc-unicode-get :log10) "log10"))
+    (should (string-equal (casual-calc-unicode-get :log) "log"))
+    (should (string-equal (casual-calc-unicode-get :exp) "e^x"))
+    (should (string-equal (casual-calc-unicode-get :expm1) "e^x - 1"))
+    (should (string-equal (casual-calc-unicode-get :sin) "sin"))
+    (should (string-equal (casual-calc-unicode-get :cos) "cos"))
+    (should (string-equal (casual-calc-unicode-get :tan) "tan"))
+    (should (string-equal (casual-calc-unicode-get :stack) "Stack"))
+    (should (string-equal (casual-calc-unicode-get :arcsin) "arcsin"))
+    (should (string-equal (casual-calc-unicode-get :arccos) "arccos"))
+    (should (string-equal (casual-calc-unicode-get :arctan) "arctan"))
+    (should (string-equal (casual-calc-unicode-get :degrees) "degrees"))
+    (should (string-equal (casual-calc-unicode-get :radians) "radians"))
+    (should (string-equal (casual-calc-unicode-get :hms) "HMS"))
+    (should (string-equal (casual-calc-unicode-get :float) "float"))
+    (should (string-equal (casual-calc-unicode-get :fraction) "fraction"))
+    (should (string-equal (casual-calc-unicode-get :to) "to")))
+
+  (let ((casual-lib-use-unicode t))
+    (should (string-equal (casual-calc-unicode-get :inv) "1/π‘₯"))
+    (should (string-equal (casual-calc-unicode-get :sqrt) "√"))
+    (should (string-equal (casual-calc-unicode-get :change-sign) "βˆ“"))
+    (should (string-equal (casual-calc-unicode-get :power) "𝑦ˣ"))
+    (should (string-equal (casual-calc-unicode-get :abs) "|π‘₯|"))
+    (should (string-equal (casual-calc-unicode-get :factorial) " !"))
+    (should (string-equal (casual-calc-unicode-get :percent) " Ωͺ"))
+    (should (string-equal (casual-calc-unicode-get :percent-change) " Ξ”%"))
+    (should (string-equal (casual-calc-unicode-get :pi) "πœ‹"))
+    (should (string-equal (casual-calc-unicode-get :e) "𝑒"))
+    (should (string-equal (casual-calc-unicode-get :ln) "𝑙𝑛"))
+    (should (string-equal (casual-calc-unicode-get :lnp1) "𝑙𝑛(π‘₯+𝟣)"))
+    (should (string-equal (casual-calc-unicode-get :log10) "π‘™π‘œπ‘”β‚β‚€"))
+    (should (string-equal (casual-calc-unicode-get :log) "π‘™π‘œπ‘”β‚(π‘₯)"))
+    (should (string-equal (casual-calc-unicode-get :exp) "𝑒ˣ"))
+    (should (string-equal (casual-calc-unicode-get :expm1) "𝑒ˣ-𝟣"))
+    (should (string-equal (casual-calc-unicode-get :sin) "𝑠𝑖𝑛"))
+    (should (string-equal (casual-calc-unicode-get :cos) "π‘π‘œπ‘ "))
+    (should (string-equal (casual-calc-unicode-get :tan) "π‘‘π‘Žπ‘›"))
+    (should (string-equal (casual-calc-unicode-get :stack) "≣"))
+    (should (string-equal (casual-calc-unicode-get :arcsin) "π‘Žπ‘Ÿπ‘π‘ π‘–π‘›"))
+    (should (string-equal (casual-calc-unicode-get :arccos) "π‘Žπ‘Ÿπ‘π‘π‘œπ‘ "))
+    (should (string-equal (casual-calc-unicode-get :arctan) "π‘Žπ‘Ÿπ‘π‘‘π‘Žπ‘›"))
+    (should (string-equal (casual-calc-unicode-get :degrees) "Β°"))
+    (should (string-equal (casual-calc-unicode-get :radians) "π‘Ÿπ‘Žπ‘‘"))
+    (should (string-equal (casual-calc-unicode-get :hms) "β„Žπ‘šπ‘ "))
+    (should (string-equal (casual-calc-unicode-get :float) "π‘“π‘™π‘œπ‘Žπ‘‘"))
+    (should (string-equal (casual-calc-unicode-get :fraction) "π‘“π‘Ÿπ‘Žπ‘π‘‘π‘–π‘œπ‘›"))
+    (should (string-equal (casual-calc-unicode-get :to) "β†’"))))
 
 (provide 'test-casual-calc-utils)
 ;;; test-casual-calc-utils.el ends here
diff --git a/tests/test-casual-dired-settings.el 
b/tests/test-casual-dired-settings.el
index 44f6206aeb..b968c4f3b5 100644
--- a/tests/test-casual-dired-settings.el
+++ b/tests/test-casual-dired-settings.el
@@ -38,6 +38,7 @@
     (push (casualt-suffix-test-vector "s" 
#'casual-dired--customize-dired-listing-switches) test-vectors)
     (push (casualt-suffix-test-vector "c" 
#'casual-dired--customize-casual-dired-listing-switches) test-vectors)
     (push (casualt-suffix-test-vector "p" 
#'casual-dired--customize-wdired-allow-to-change-permissions) test-vectors)
+    (push (casualt-suffix-test-vector "v" 
#'casual-dired--customize-find-file-visit-truename) test-vectors)
     (push (casualt-suffix-test-vector "L" 
#'casual-dired--customize-wdired-allow-to-redirect-links) test-vectors)
     (push (casualt-suffix-test-vector "u" 
#'casual-lib-customize-casual-lib-use-unicode) test-vectors)
     (push (casualt-suffix-test-vector "R" 
#'casual-dired--customize-dired-vc-rename-file) test-vectors)
diff --git a/tests/test-casual-dired-utils.el b/tests/test-casual-dired-utils.el
index 1b39010707..97ba3ddb91 100644
--- a/tests/test-casual-dired-utils.el
+++ b/tests/test-casual-dired-utils.el
@@ -80,9 +80,13 @@
   (casualt-dired-setup)
 
   (let ((test-vectors (list)))
+    (push (casualt-suffix-test-vector "s" #'dired-do-symlink) test-vectors)
+    (push (casualt-suffix-test-vector "S" #'dired-do-symlink-regexp) 
test-vectors)
+    (push (casualt-suffix-test-vector "r" #'dired-do-relsymlink) test-vectors)
+    (push (casualt-suffix-test-vector "R" #'dired-do-relsymlink-regexp) 
test-vectors)
     (push (casualt-suffix-test-vector "h" #'dired-do-hardlink) test-vectors)
     (push (casualt-suffix-test-vector "H" #'dired-do-hardlink-regexp) 
test-vectors)
-    (push (casualt-suffix-test-vector "S" #'dired-do-symlink-regexp) 
test-vectors)
+
 
     (casualt-suffix-testbench-runner test-vectors
                                      #'casual-dired-link-tmenu
diff --git a/tests/test-casual-dired.el b/tests/test-casual-dired.el
index 421f4b8ceb..91aedf0ef6 100644
--- a/tests/test-casual-dired.el
+++ b/tests/test-casual-dired.el
@@ -38,10 +38,11 @@
 
     (let ((test-vectors (list)))
       (push (casualt-suffix-test-vector "o" #'dired-find-file-other-window) 
test-vectors)
+      (push (casualt-suffix-test-vector "v" #'dired-view-file) test-vectors)
       (push (casualt-suffix-test-vector "C" #'dired-do-copy) test-vectors)
       (push (casualt-suffix-test-vector "R" #'dired-do-rename) test-vectors)
       (push (casualt-suffix-test-vector "D" #'dired-do-delete) test-vectors)
-      (push (casualt-suffix-test-vector "S" #'dired-do-symlink) test-vectors)
+      (push (casualt-suffix-test-vector "l" #'casual-dired-link-tmenu) 
test-vectors)
       (push (casualt-suffix-test-vector "c" #'casual-dired-change-tmenu) 
test-vectors)
       (push (casualt-suffix-test-vector "y" #'dired-show-file-type) 
test-vectors)
       (push (casualt-suffix-test-vector "w" #'dired-copy-filename-as-kill) 
test-vectors)
diff --git a/tests/test-casual-editkit-utils.el 
b/tests/test-casual-editkit-utils.el
index 364577b6e0..41c83f57ba 100644
--- a/tests/test-casual-editkit-utils.el
+++ b/tests/test-casual-editkit-utils.el
@@ -31,8 +31,9 @@
   (let ((tmpfile "casual-editkit-open-tmenu.txt"))
     (casualt-editkit-setup tmpfile)
 
-    (cl-letf (;;((symbol-function #') (lambda () t))
+    (cl-letf (;; ((symbol-function #'buffer-file-name) (lambda () t))
               (casualt-mock #'find-file)
+              (casualt-mock #'rename-visited-file)
               (casualt-mock #'find-file-other-window)
               (casualt-mock #'find-file-other-frame)
               (casualt-mock #'find-alternate-file)
@@ -41,6 +42,9 @@
 
       (let ((test-vectors
              '((:binding "f" :command find-file)
+               (:binding "r" :command rename-visited-file)
+               (:binding "R" :command rename-buffer)
+               (:binding "M-r" :command rename-uniquely)
                (:binding "F" :command find-file-other-window)
                (:binding "M-n" :command find-file-other-frame)
                (:binding "a" :command find-alternate-file)

Reply via email to