branch: elpa/casual
commit f6b7e59cc3c29f2974bcd9314cf2aed03abfe93d
Merge: 5e004a06ee f08f781ffe
Author: Charles Choi <[email protected]>
Commit: GitHub <[email protected]>
Merge pull request #301 from
kickingvegas/merge-development-to-main-20250924_143046
Merge development to main 20250924_143046
---
docs/bibtex.org | 170 +++++++++++++++
docs/casual.info | Bin 121770 -> 132097 bytes
docs/casual.org | 4 +-
docs/casual.texi | 246 +++++++++++++++++++++-
docs/images/casual-bibtex-clean-entry-hook.png | Bin 0 -> 118414 bytes
docs/images/casual-bibtex-screenshot.png | Bin 0 -> 126434 bytes
docs/images/casual-bibtex-settings-screenshot.png | Bin 0 -> 62880 bytes
docs/images/casual-bibtex-unicode-screenshot.png | Bin 0 -> 77710 bytes
lisp/Makefile | 5 +
lisp/Makefile-bibtex.make | 30 +++
lisp/casual-bibtex-settings.el | 144 +++++++++++++
lisp/casual-bibtex-utils.el | 85 ++++++++
lisp/casual-bibtex.el | 145 +++++++++++++
lisp/casual.el | 5 +-
tests/Makefile | 5 +
tests/casual-bibtex-test-utils.el | 48 +++++
tests/test-casual-bibtex-settings.el | 62 ++++++
tests/test-casual-bibtex-utils.el | 50 +++++
tests/test-casual-bibtex.el | 112 ++++++++++
19 files changed, 1107 insertions(+), 4 deletions(-)
diff --git a/docs/bibtex.org b/docs/bibtex.org
new file mode 100644
index 0000000000..49f9f086d8
--- /dev/null
+++ b/docs/bibtex.org
@@ -0,0 +1,170 @@
+* BibTeX
+#+CINDEX: BibTeX
+#+CINDEX: bibtex
+#+VINDEX: casual-bibtex-tmenu
+
+Casual BibTeX is an opinionated user interface for BibTeX mode
([[info:emacs#TeX Mode][info "(emacs) TeX Mode"]]), a major mode for working
with BibTeX files ([[https://bibtex.eu][BibTeX Guide]]).
+
+A BibTeX file is typically named using the suffix ~.bib~ to identify its file
type.
+
+To appreciate the benefits of Casual BibTeX, it helps to understand what
BibTex is and what BibTeX mode offers.
+
+BibTeX is a database schema for bibliography data. This data is best
understood as a collection of records (or entries) that is stored in a
plain-text file. Multiple text files can be supported. While most tooling for
BibTeX is tuned for LaTeX documentation workflows, BibTeX can be used as
generalized storage for bibliography data. Org provides extensive support for
citing using BibTeX ([[info:org#Citation handling][info "(org) Citation
handling"]]).
+
+As a BibTeX file is plain-text based, any plain-text editor can be used to
edit it. This flexibility is problematic as plain-text editors will not enforce
the schema of BibTeX by default.
+
+Emacs distinguishes itself from other editors in that support for working with
BibTeX files is built-in with the package ~bibtex~.
+
+The ~bibtex~ package provides commands for both navigating and editing BibTeX
data structures (entries and the fields within an entry) in a
quasi-"form-based" way.
+
+Casual BibTeX organizes and augments BibTeX mode commands into a
keyboard-driven menu.
+
+The screenshot below shows the menu for Casual BibTeX.
+
+[[file:images/casual-bibtex-screenshot.png]]
+
+** BibTeX Install
+:PROPERTIES:
+:CUSTOM_ID: bibtex-install
+:END:
+
+#+CINDEX: BibTeX Install
+
+In your initialization file, bind the Transient ~casual-bibtex-tmenu~ to your
key binding of preference in ~bibtex-mode-map~. The binding {{{kbd(M-m)}}} is
suggested so as to not conflict with {{{kbd(C-o)}}} that is bound to
~casual-editkit-main-tmenu~. ([[#editkit-install][EditKit Install]])
+
+#+begin_src elisp :lexical no
+ (keymap-set bibtex-mode-map "M-m" #'casual-bibtex-tmenu)
+#+end_src
+
+~casual-bibtex-tmenu~ is opinionated in making editing and navigation commands
emulate a form-based interface
([[https://simple.wikipedia.org/wiki/Form-based_interface#:~:text=A%20form%2Dbased%20interface%20is,the%20fields%20that%20accept%20it.][form-based
interface]]) in a ~bibtex-mode~ window. The following keybindings are
recommended to support consistent behavior between ~bibtex-mode-map~ and
~casual-bibtex-tmenu~.
+
+#+begin_src elisp :lexical no
+ (add-hook 'bibtex-mode-hook 'hl-line-mode)
+
+ (keymap-set bibtex-mode-map "<TAB>" #'bibtex-next-field)
+ (keymap-set bibtex-mode-map "<backtab>" #'previous-line)
+
+ (keymap-set bibtex-mode-map "C-n" #'bibtex-next-field)
+ (keymap-set bibtex-mode-map "M-n" #'bibtex-next-entry)
+ (keymap-set bibtex-mode-map "M-p" #'bibtex-previous-entry)
+
+ (keymap-set bibtex-mode-map "<prior>" #'bibtex-previous-entry)
+ (keymap-set bibtex-mode-map "<next>" #'bibtex-next-entry)
+
+ (keymap-set bibtex-mode-map "C-c C-o" #'bibtex-url)
+ (keymap-set bibtex-mode-map "C-c C-c" #'casual-bibtex-fill-and-clean)
+
+ (keymap-set bibtex-mode-map "<clear>" #'bibtex-empty-field)
+ (keymap-set bibtex-mode-map "M-<clear>" #'bibtex-kill-field)
+ (keymap-set bibtex-mode-map "M-DEL" #'bibtex-kill-field)
+
+#+end_src
+
+** BibTeX Usage
+#+CINDEX: BibTeX Usage
+
+[[file:images/casual-bibtex-screenshot.png]]
+
+The main menu for Casual BibTeX is organized into the following sections:
+
+- Field :: Commands to edit or navigate fields within an entry.
+- Entry :: Commands to edit or navigate entries within a BibTeX file.
+- Misc :: Miscellaneous BibTeX commands.
+
+*** BibTeX Navigation
+#+CINDEX: BibTeX Navigation
+
+[[file:images/casual-bibtex-screenshot.png]]
+
+Casual BibTeX re-purposes conventional Emacs navigation bindings so that
instead of navigating a text edit buffer, it instead navigates BibTeX
structures (entry, field).
+
+The following table shows the bindings for BibTeX navigation.
+
+| Binding | Command |
+|----------------+---------------------------------------------------|
+| {{{kbd(C-n)}}} | bibtex-next-field (bound to {{{kbd(n)}}} in menu) |
+| {{{kbd(C-p)}}} | previous-line (bound to {{{kbd(p)}}} in menu) |
+| {{{kbd(C-a)}}} | casual-bibtex-beginning-of-field |
+| {{{kbd(C-e)}}} | casual-bibtex-end-of-field |
+| {{{kbd(M-p)}}} | bibtex-previous-entry |
+| {{{kbd(M-n)}}} | bibtex-next-entry |
+| {{{kbd(<)}}} | bibtex-beginning-of-entry |
+| {{{kbd(>)}}} | bibtex-end-of-entry |
+
+*** Creating, Updating, and Deleting BibTeX Structures
+#+CINDEX: BibTeX CRUD
+
+[[file:images/casual-bibtex-screenshot.png]]
+
+In Casual BibTeX, CRUD (CReate, Update, Delete) operations for entry and field
structures are intended to be achieved through their respective commands. This
contrasts with manual editing of a buffer to achieve the same end, which is
prone to errors.
+
+#+TEXINFO: @subheading Creating an Entry
+
+To create a new entry, use the “{{{kbd(A)}}} Add…” command. You will be
prompted in the mini-buffer with completion support for the entry type. This
new entry will be inserted relative to existing entry where the point is with
all fields supported by the entry type enumerated. Fields with the temporary
prefix of "ALT" or "OPT" denote a field that is alternate or optional. Use the
command “{{{kbd(o)}}} Remove OPT/ALT” to remove this prefix.
+
+When all desired information for a BibTeX entry has been entered, it can be
"cleaned" using the command “{{{kbd(C-c)}}} Clean”. Cleaning an entry will:
+
+1. Generate a unique citation key, if needed.
+2. Remove all unused fields.
+
+By default, cleaning an entry will not format (or "fill") the entry. This can
be changed by setting the customizable variable ~bibtex-clean-entry-hook~ to
include the command ~bibtex-fill-entry~. This can be done from "Hooks" section
in the Settings menu ([[#bibtex-settings][Settings)]].
+
+#+TEXINFO: @subheading Creating a Field
+
+To create a new field, use the “{{{kbd(a)}}} Add…” command. You will be
prompted in the mini-buffer with completion support for the field type. This
new field will be inserted relative to existing field where the point is.
+
+There are two components to a field:
+
+- key :: the field name, referred to in the menu as 'k'.
+- value :: the value of the field, referred to in the menu as 'v'.
+
+A "brute-force" command to enumerate all fields for an entry is provided by
the “{{{kbd(u)}}} Update…” command. Clean the entry to remove all unpopulated
fields after using it.
+
+#+TEXINFO: @subheading BibTeX mode has its own kill-ring
+
+BibTeX has its own kill-ring variable ~bibtex-entry-kill-ring~ which the
following menu commands use:
+
+- {{{kbd(c)}}} Copy∙ k,v :: Copy the whole field, both key and value.
+- {{{kbd(C)}}} Copy∙ :: Copy the entry.
+- {{{kbd(k)}}} Kill∙ :: Kill the entry.
+- {{{kbd(y)}}} Yank∙ :: Yank the entry or field.
+- {{{kbd(M-y)}}} Yank-Pop∙ :: Yank-pop the entry or field.
+
+The "∙" annotation in a menu label denotes commands that do /not/ use the
~kill-ring~, but ~bibtex-entry-kill-ring~ instead.
+
+#+TEXINFO: @subheading Search and Jump
+
+The ability to search and jump to a position in a BibTeX database are offered
by the following menu commands:
+
+- {{{kbd(/)}}} Search… :: Search the BibTeX database.
+- {{{kbd(j)}}} Jump… :: Move point to a citation key.
+
+*** BibTeX Settings
+:PROPERTIES:
+:CUSTOM_ID: bibtex-settings
+:END:
+#+CINDEX: BibTeX Settings
+
+[[file:images/casual-bibtex-settings-screenshot.png]]
+
+
+This menu offers access to commonly configured BibTeX mode settings.
+
+Settings are organized into the following sections:
+
+- Settings :: Miscellaneous BibTeX settings.
+- Files :: File and path related settings.
+- Search :: Search settings.
+- Hooks :: Hook settings for cleaning and adding.
+
+#+TEXINFO: @subsubheading BibTeX Clean Hook
+
+By default BibTeX mode does not format (or "fill") an entry upon cleaning. To
support filling an entry upon clean, add the command ~bibtex-fill-entry~ to
~bibtex-clean-entry-hook~ using the “{{{kbd(C)}}} Clean” command as shown below:
+
+[[file:images/casual-bibtex-clean-entry-hook.png]]
+
+#+TEXINFO: @subsubheading BibTeX Mode Unicode Symbol Support
+
+By enabling “{{{kbd(u)}}} Use Unicode Symbols” from the Settings menu, Casual
BibTeX will use Unicode symbols as appropriate in its menus.
+
+[[file:images/casual-bibtex-unicode-screenshot.png]]
diff --git a/docs/casual.info b/docs/casual.info
index d98d560ce1..0a396eadfa 100644
Binary files a/docs/casual.info and b/docs/casual.info differ
diff --git a/docs/casual.org b/docs/casual.org
index 716792ca31..aadd126484 100644
--- a/docs/casual.org
+++ b/docs/casual.org
@@ -5,7 +5,7 @@
#+EMAIL: [email protected]
#+OPTIONS: ':t toc:t author:t email:t H:4 f:t
#+LANGUAGE: en
-#+MACRO: version 2.8.4
+#+MACRO: version 2.9.0
#+MACRO: kbd (eval (org-texinfo-kbd-macro $1))
#+TEXINFO_FILENAME: casual.info
#+TEXINFO_CLASS: casual
@@ -142,6 +142,7 @@ Standard installation of the ~casual~ package is via
[[https://melpa.org/#/casua
Configuration of a particular Casual user interface is performed per mode. Go
to the *Install* section for a mode of interest below for guidance on its
configuration.
- [[#agenda-install][Agenda]]
+- [[#bibtex-install][BibTeX]]
- [[#bookmarks-install][Bookmarks]]
- [[#calc-install][Calc]]
- [[#calendar-install][Calendar]]
@@ -253,6 +254,7 @@ Casual is organized into different libraries typically
using the naming conventi
The following modes are supported by Casual:
#+INCLUDE: "./agenda.org" :minlevel 2
+#+INCLUDE: "./bibtex.org" :minlevel 2
#+INCLUDE: "./bookmarks.org" :minlevel 2
#+INCLUDE: "./calc.org" :minlevel 2
#+INCLUDE: "./calendar.org" :minlevel 2
diff --git a/docs/casual.texi b/docs/casual.texi
index a63c8fa56c..ab469193bf 100644
--- a/docs/casual.texi
+++ b/docs/casual.texi
@@ -20,7 +20,7 @@ Copyright © 2024-2025 Charles Y@. Choi
@finalout
@titlepage
@title Casual User Guide
-@subtitle for version 2.8.4
+@subtitle for version 2.9.0
@author Charles Y@. Choi (@email{kickingvegas@@gmail.com})
@page
@vskip 0pt plus 1filll
@@ -33,7 +33,7 @@ Copyright © 2024-2025 Charles Y@. Choi
@node Top
@top Casual User Guide
-Version: 2.8.4
+Version: 2.9.0
Casual is a project to re-imagine the primary user interface for Emacs using
keyboard-driven menus.
@@ -100,6 +100,7 @@ Upgrading to Casual 1.x to 2.x
Casual Modes
* Agenda::
+* Bib@TeX{}::
* Bookmarks::
* Calc::
* Calendar::
@@ -123,6 +124,17 @@ Agenda
* Agenda Install::
* Agenda Usage::
+Bib@TeX{}
+
+* Bib@TeX{} Install::
+* Bib@TeX{} Usage::
+
+Bib@TeX{} Usage
+
+* Bib@TeX{} Navigation::
+* Creating, Updating, and Deleting Bib@TeX{} Structures: Creating Updating and
Deleting Bib@TeX{} Structures.
+* Bib@TeX{} Settings::
+
Bookmarks
* Bookmarks Install::
@@ -411,6 +423,8 @@ Configuration of a particular Casual user interface is
performed per mode. Go to
@item
@ref{Agenda Install, , Agenda}
@item
+@ref{Bib@TeX{} Install, , Bib@TeX{}}
+@item
@ref{Bookmarks Install, , Bookmarks}
@item
@ref{Calc Install, , Calc}
@@ -574,6 +588,7 @@ The following modes are supported by Casual:
@menu
* Agenda::
+* Bib@TeX{}::
* Bookmarks::
* Calc::
* Calendar::
@@ -677,6 +692,233 @@ By enabling “@kbd{u} Use Unicode Settings” from the
Settings menu, Casual Ag
@image{images/casual-agenda-unicode-screenshot,,,,png}
+@node Bib@TeX{}
+@section Bib@TeX{}
+
+@cindex BibTeX
+@cindex bibtex
+@vindex casual-bibtex-tmenu
+
+Casual Bib@TeX{} is an opinionated user interface for Bib@TeX{} mode (@ref{TeX
Mode,info ``(emacs) @TeX{} Mode'',,emacs,}), a major mode for working with
Bib@TeX{} files (@uref{https://bibtex.eu, Bib@TeX{} Guide}).
+
+A Bib@TeX{} file is typically named using the suffix @code{.bib} to identify
its file type.
+
+To appreciate the benefits of Casual Bib@TeX{}, it helps to understand what
BibTex is and what Bib@TeX{} mode offers.
+
+Bib@TeX{} is a database schema for bibliography data. This data is best
understood as a collection of records (or entries) that is stored in a
plain-text file. Multiple text files can be supported. While most tooling for
Bib@TeX{} is tuned for @LaTeX{} documentation workflows, Bib@TeX{} can be used
as generalized storage for bibliography data. Org provides extensive support
for citing using Bib@TeX{} (@ref{Citation handling,info ``(org) Citation
handling'',,org,}).
+
+As a Bib@TeX{} file is plain-text based, any plain-text editor can be used to
edit it. This flexibility is problematic as plain-text editors will not enforce
the schema of Bib@TeX{} by default.
+
+Emacs distinguishes itself from other editors in that support for working with
Bib@TeX{} files is built-in with the package @code{bibtex}.
+
+The @code{bibtex} package provides commands for both navigating and editing
Bib@TeX{} data structures (entries and the fields within an entry) in a
quasi-``form-based'' way.
+
+Casual Bib@TeX{} organizes and augments Bib@TeX{} mode commands into a
keyboard-driven menu.
+
+The screenshot below shows the menu for Casual Bib@TeX{}.
+
+@image{images/casual-bibtex-screenshot,,,,png}
+
+@menu
+* Bib@TeX{} Install::
+* Bib@TeX{} Usage::
+@end menu
+
+@node Bib@TeX{} Install
+@subsection Bib@TeX{} Install
+
+@cindex BibTeX Install
+
+In your initialization file, bind the Transient @code{casual-bibtex-tmenu} to
your key binding of preference in @code{bibtex-mode-map}. The binding @kbd{M-m}
is suggested so as to not conflict with @kbd{C-o} that is bound to
@code{casual-editkit-main-tmenu}. (@ref{EditKit Install})
+
+@lisp
+(keymap-set bibtex-mode-map "M-m" #'casual-bibtex-tmenu)
+@end lisp
+
+@code{casual-bibtex-tmenu} is opinionated in making editing and navigation
commands emulate a form-based interface
(@uref{https://simple.wikipedia.org/wiki/Form-based_interface#:~:text=A%20form%2Dbased%20interface%20is,the%20fields%20that%20accept%20it.,
form-based interface}) in a @code{bibtex-mode} window. The following
keybindings are recommended to support consistent behavior between
@code{bibtex-mode-map} and @code{casual-bibtex-tmenu}.
+
+@lisp
+(add-hook 'bibtex-mode-hook 'hl-line-mode)
+
+(keymap-set bibtex-mode-map "<TAB>" #'bibtex-next-field)
+(keymap-set bibtex-mode-map "<backtab>" #'previous-line)
+
+(keymap-set bibtex-mode-map "C-n" #'bibtex-next-field)
+(keymap-set bibtex-mode-map "M-n" #'bibtex-next-entry)
+(keymap-set bibtex-mode-map "M-p" #'bibtex-previous-entry)
+
+(keymap-set bibtex-mode-map "<prior>" #'bibtex-previous-entry)
+(keymap-set bibtex-mode-map "<next>" #'bibtex-next-entry)
+
+(keymap-set bibtex-mode-map "C-c C-o" #'bibtex-url)
+(keymap-set bibtex-mode-map "C-c C-c" #'casual-bibtex-fill-and-clean)
+
+(keymap-set bibtex-mode-map "<clear>" #'bibtex-empty-field)
+(keymap-set bibtex-mode-map "M-<clear>" #'bibtex-kill-field)
+(keymap-set bibtex-mode-map "M-DEL" #'bibtex-kill-field)
+
+@end lisp
+
+@node Bib@TeX{} Usage
+@subsection Bib@TeX{} Usage
+
+@cindex BibTeX Usage
+
+@image{images/casual-bibtex-screenshot,,,,png}
+
+The main menu for Casual Bib@TeX{} is organized into the following sections:
+
+@table @asis
+@item Field
+Commands to edit or navigate fields within an entry.
+@item Entry
+Commands to edit or navigate entries within a Bib@TeX{} file.
+@item Misc
+Miscellaneous Bib@TeX{} commands.
+@end table
+
+@menu
+* Bib@TeX{} Navigation::
+* Creating, Updating, and Deleting Bib@TeX{} Structures: Creating Updating and
Deleting Bib@TeX{} Structures.
+* Bib@TeX{} Settings::
+@end menu
+
+@node Bib@TeX{} Navigation
+@subsubsection Bib@TeX{} Navigation
+
+@cindex BibTeX Navigation
+
+@image{images/casual-bibtex-screenshot,,,,png}
+
+Casual Bib@TeX{} re-purposes conventional Emacs navigation bindings so that
instead of navigating a text edit buffer, it instead navigates Bib@TeX{}
structures (entry, field).
+
+The following table shows the bindings for Bib@TeX{} navigation.
+
+@multitable {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}
{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}
+@headitem Binding
+@tab Command
+@item @kbd{C-n}
+@tab bibtex-next-field (bound to @kbd{n} in menu)
+@item @kbd{C-p}
+@tab previous-line (bound to @kbd{p} in menu)
+@item @kbd{C-a}
+@tab casual-bibtex-beginning-of-field
+@item @kbd{C-e}
+@tab casual-bibtex-end-of-field
+@item @kbd{M-p}
+@tab bibtex-previous-entry
+@item @kbd{M-n}
+@tab bibtex-next-entry
+@item @kbd{<}
+@tab bibtex-beginning-of-entry
+@item @kbd{>}
+@tab bibtex-end-of-entry
+@end multitable
+
+@node Creating Updating and Deleting Bib@TeX{} Structures
+@subsubsection Creating, Updating, and Deleting Bib@TeX{} Structures
+
+@cindex BibTeX CRUD
+
+@image{images/casual-bibtex-screenshot,,,,png}
+
+In Casual Bib@TeX{}, CRUD (CReate, Update, Delete) operations for entry and
field structures are intended to be achieved through their respective commands.
This contrasts with manual editing of a buffer to achieve the same end, which
is prone to errors.
+
+@subheading Creating an Entry
+
+To create a new entry, use the “@kbd{A} Add…” command. You will be prompted in
the mini-buffer with completion support for the entry type. This new entry will
be inserted relative to existing entry where the point is with all fields
supported by the entry type enumerated. Fields with the temporary prefix of
``ALT'' or ``OPT'' denote a field that is alternate or optional. Use the
command “@kbd{o} Remove OPT/ALT” to remove this prefix.
+
+When all desired information for a Bib@TeX{} entry has been entered, it can be
``cleaned'' using the command “@kbd{C-c} Clean”. Cleaning an entry will:
+
+@enumerate
+@item
+Generate a unique citation key, if needed.
+@item
+Remove all unused fields.
+@end enumerate
+
+By default, cleaning an entry will not format (or ``fill'') the entry. This
can be changed by setting the customizable variable
@code{bibtex-clean-entry-hook} to include the command @code{bibtex-fill-entry}.
This can be done from ``Hooks'' section in the Settings menu (@ref{Bib@TeX{}
Settings, , Settings)}.
+
+@subheading Creating a Field
+
+To create a new field, use the “@kbd{a} Add…” command. You will be prompted in
the mini-buffer with completion support for the field type. This new field will
be inserted relative to existing field where the point is.
+
+There are two components to a field:
+
+@table @asis
+@item key
+the field name, referred to in the menu as 'k'.
+@item value
+the value of the field, referred to in the menu as 'v'.
+@end table
+
+A ``brute-force'' command to enumerate all fields for an entry is provided by
the “@kbd{u} Update…” command. Clean the entry to remove all unpopulated fields
after using it.
+
+@subheading BibTeX mode has its own kill-ring
+
+Bib@TeX{} has its own kill-ring variable @code{bibtex-entry-kill-ring} which
the following menu commands use:
+
+@table @asis
+@item @kbd{c} Copy∙ k,v
+Copy the whole field, both key and value.
+@item @kbd{C} Copy∙
+Copy the entry.
+@item @kbd{k} Kill∙
+Kill the entry.
+@item @kbd{y} Yank∙
+Yank the entry or field.
+@item @kbd{M-y} Yank-Pop∙
+Yank-pop the entry or field.
+@end table
+
+The ``∙'' annotation in a menu label denotes commands that do @emph{not} use
the @code{kill-ring}, but @code{bibtex-entry-kill-ring} instead.
+
+@subheading Search and Jump
+
+The ability to search and jump to a position in a Bib@TeX{} database are
offered by the following menu commands:
+
+@table @asis
+@item @kbd{/} Search…
+Search the Bib@TeX{} database.
+@item @kbd{j} Jump…
+Move point to a citation key.
+@end table
+
+@node Bib@TeX{} Settings
+@subsubsection Bib@TeX{} Settings
+
+@cindex BibTeX Settings
+
+@image{images/casual-bibtex-settings-screenshot,,,,png}
+
+
+This menu offers access to commonly configured Bib@TeX{} mode settings.
+
+Settings are organized into the following sections:
+
+@table @asis
+@item Settings
+Miscellaneous Bib@TeX{} settings.
+@item Files
+File and path related settings.
+@item Search
+Search settings.
+@item Hooks
+Hook settings for cleaning and adding.
+@end table
+
+@subsubheading BibTeX Clean Hook
+
+By default Bib@TeX{} mode does not format (or ``fill'') an entry upon
cleaning. To support filling an entry upon clean, add the command
@code{bibtex-fill-entry} to @code{bibtex-clean-entry-hook} using the “@kbd{C}
Clean” command as shown below:
+
+@image{images/casual-bibtex-clean-entry-hook,,,,png}
+
+@subsubheading BibTeX Mode Unicode Symbol Support
+
+By enabling “@kbd{u} Use Unicode Symbols” from the Settings menu, Casual
Bib@TeX{} will use Unicode symbols as appropriate in its menus.
+
+@image{images/casual-bibtex-unicode-screenshot,,,,png}
+
@node Bookmarks
@section Bookmarks
diff --git a/docs/images/casual-bibtex-clean-entry-hook.png
b/docs/images/casual-bibtex-clean-entry-hook.png
new file mode 100644
index 0000000000..9a563d6e6f
Binary files /dev/null and b/docs/images/casual-bibtex-clean-entry-hook.png
differ
diff --git a/docs/images/casual-bibtex-screenshot.png
b/docs/images/casual-bibtex-screenshot.png
new file mode 100644
index 0000000000..21d2cc6500
Binary files /dev/null and b/docs/images/casual-bibtex-screenshot.png differ
diff --git a/docs/images/casual-bibtex-settings-screenshot.png
b/docs/images/casual-bibtex-settings-screenshot.png
new file mode 100644
index 0000000000..7498c094e4
Binary files /dev/null and b/docs/images/casual-bibtex-settings-screenshot.png
differ
diff --git a/docs/images/casual-bibtex-unicode-screenshot.png
b/docs/images/casual-bibtex-unicode-screenshot.png
new file mode 100644
index 0000000000..57b4b9e7b6
Binary files /dev/null and b/docs/images/casual-bibtex-unicode-screenshot.png
differ
diff --git a/lisp/Makefile b/lisp/Makefile
index bcce5008c9..b26f8b2433 100644
--- a/lisp/Makefile
+++ b/lisp/Makefile
@@ -20,6 +20,7 @@ SRC_DIR=.
.PHONY: tests
tests: lib-tests \
agenda-tests \
+bibtex-tests \
bookmarks-tests \
calc-tests \
calendar-tests \
@@ -45,6 +46,10 @@ lib-tests:
agenda-tests:
$(MAKE) -C $(SRC_DIR) -f Makefile-agenda.make tests
+.PHONY: bibtex-tests
+bibtex-tests:
+ $(MAKE) -C $(SRC_DIR) -f Makefile-bibtex.make tests
+
.PHONY: bookmarks-tests
bookmarks-tests:
$(MAKE) -C $(SRC_DIR) -f Makefile-bookmarks.make tests
diff --git a/lisp/Makefile-bibtex.make b/lisp/Makefile-bibtex.make
new file mode 100644
index 0000000000..ffc38630ca
--- /dev/null
+++ b/lisp/Makefile-bibtex.make
@@ -0,0 +1,30 @@
+##
+# Copyright (C) 2025 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-bibtex
+ELISP_INCLUDES=casual-bibtex-utils.el \
+casual-bibtex-settings.el
+ELISP_PACKAGES=
+ELISP_TEST_INCLUDES=casual-bibtex-test-utils.el
+PACKAGE_PATHS= \
+-L $(EMACS_ELPA_DIR)/compat-current \
+-L $(EMACS_ELPA_DIR)/seq-current \
+-L $(EMACS_ELPA_DIR)/transient-current \
+-L $(CASUAL_LIB_LISP_DIR)
+
+include Makefile--rules.make
diff --git a/lisp/casual-bibtex-settings.el b/lisp/casual-bibtex-settings.el
new file mode 100644
index 0000000000..4d47a3a76a
--- /dev/null
+++ b/lisp/casual-bibtex-settings.el
@@ -0,0 +1,144 @@
+;;; casual-bibtex-settings.el --- Casual BibTeX Settings -*- lexical-binding:
t; -*-
+
+;; Copyright (C) 2025 Charles Y. 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)
+
+(transient-define-prefix casual-bibtex-settings-tmenu ()
+ "Casual BibTeX settings menu."
+ ["Casual BibTeX Settings"
+ ["Settings"
+ ("d" "Dialect" casual-bibtex--customize-dialect
+ :description (lambda ()
+ (if bibtex-dialect
+ (format "Dialect (%s)" bibtex-dialect)
+ "Dialect")))
+ ("G" "BibTeX Group" casual-bibtex--customize-group)]
+
+ ["Files"
+ ("p" "Path" casual-bibtex--customize-file-path
+ :description (lambda ()
+ (if bibtex-file-path
+ (format "Path (%s)" bibtex-file-path)
+ "Path")))
+ ("f" "Files" casual-bibtex--customize-files)]
+
+ ["Search"
+ ("g" "Entry Globally" casual-bibtex--customize-search-entry-globally
+ :description (lambda () (casual-lib-checkbox-label
bibtex-search-entry-globally
+ "Entry Globally")))]
+
+ ["Hooks"
+ ("C" "Clean" casual-bibtex--customize-clean-entry-hook)
+ ("A" "Add" casual-bibtex--customize-add-entry-hook)]]
+
+ ["Misc"
+ :class transient-row
+ (casual-lib-customize-unicode)
+ (casual-lib-customize-hide-navigation)]
+
+ [:class transient-row
+ (casual-lib-quit-one)
+ ("a" "About" casual-bibtex-about :transient nil)
+ (casual-lib-quit-all)])
+
+(defun casual-bibtex-about-bibtex ()
+ "Casual BibTeX is a Transient menu for BibTeX.
+
+Learn more about using Casual BibTeX 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 BibTeX, consider making a modest financial
+contribution to help support its development and maintenance.
+URL `https://www.buymeacoffee.com/kickingvegas'
+
+Casual BibTeX was conceived and crafted by Charles Choi in San Francisco,
+California.
+
+Thank you for using Casual BibTeX.
+
+Always choose love."
+ (ignore))
+
+(defun casual-bibtex-about ()
+ "About information for Casual BibTeX."
+ (interactive)
+ (describe-function #'casual-bibtex-about-bibtex))
+
+
+;;; Customize Functions
+(defun casual-bibtex--customize-group ()
+ "Customize BibTeX group."
+ (interactive)
+ (customize-group "bibtex"))
+
+(defun casual-bibtex--customize-dialect ()
+ "Set BibTeX dialect.
+
+This customizes the variable `bibtex-dialect'."
+ (interactive)
+ (customize-variable 'bibtex-dialect))
+
+(defun casual-bibtex--customize-files ()
+ "Set BibTeX files.
+
+This customizes the variable `bibtex-files'."
+ (interactive)
+ (customize-variable 'bibtex-files))
+
+(defun casual-bibtex--customize-file-path ()
+ "Set BibTeX file path.
+
+This customizes the variable `bibtex-file-path'."
+ (interactive)
+ (customize-variable 'bibtex-file-path))
+
+(defun casual-bibtex--customize-search-entry-globally ()
+ "Set BibTeX search to be global.
+
+This customizes the variable `bibtex-search-entry-globally'."
+ (interactive)
+ (customize-variable 'bibtex-search-entry-globally))
+
+(defun casual-bibtex--customize-clean-entry-hook ()
+ "Set hook for cleaning a BibTeX entry.
+
+This customizes the variable `bibtex-clean-entry-hook'."
+ (interactive)
+ (customize-variable 'bibtex-clean-entry-hook))
+
+(defun casual-bibtex--customize-add-entry-hook ()
+ "Set hook for adding a BibTeX entry.
+
+This customizes the variable `bibtex-add-entry-hook'."
+ (interactive)
+ (customize-variable 'bibtex-add-entry-hook))
+
+
+(provide 'casual-bibtex-settings)
+;;; casual-bibtex-settings.el ends here
diff --git a/lisp/casual-bibtex-utils.el b/lisp/casual-bibtex-utils.el
new file mode 100644
index 0000000000..a769f121b7
--- /dev/null
+++ b/lisp/casual-bibtex-utils.el
@@ -0,0 +1,85 @@
+;;; casual-bibtex-utils.el --- Casual BibTeX Utils -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2025 Charles Y. 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 'bibtex)
+(require 'casual-lib)
+
+(defconst casual-bibtex-unicode-db
+ '((:previous . '("↑" "Previous"))
+ (:next . '("↓" "Next"))
+ (:begin-entry . '("⇱" "Begin"))
+ (:end-entry . '("⇲" "End"))
+ (:begin-field . '("⇤" "Begin"))
+ (:end-field . '("⇥" "End"))
+ (:clear . '("⌫" "Clear")))
+
+ "Unicode symbol DB to use for BibTeX Transient menus.")
+
+(defun casual-bibtex-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-bibtex-unicode-db))
+
+(defun casual-bibtex-beginning-of-field (&optional comma)
+ "Move point to beginning of BibTeX field value.
+Optional arg COMMA is as in `bibtex-enclosing-field'. It is t for
+interactive calls."
+ (interactive (list t))
+ (let ((bounds (bibtex-enclosing-field comma)))
+ (goto-char (bibtex-start-of-text-in-field bounds))
+ (if (= (following-char) ?\{)
+ (forward-char 1))))
+
+(defun casual-bibtex-end-of-field (&optional comma)
+ "Move point to end of BibTeX field value.
+Optional arg COMMA is as in `bibtex-enclosing-field'. It is t for
+interactive calls."
+
+ (interactive (list t))
+ (let ((bounds (bibtex-enclosing-field comma)))
+ (goto-char (bibtex-end-of-text-in-field bounds))
+ (if (= (preceding-char) ?\})
+ (backward-char 1))))
+
+(defun casual-bibtex-copy-field-value (&optional comma)
+ "Copy BibTeX field value to `kill-ring'.
+Optional arg COMMA is as in `bibtex-enclosing-field'. It is t for
+interactive calls."
+ (interactive (list t))
+ (let* ((bounds (bibtex-enclosing-field comma))
+ (value (buffer-substring-no-properties
+ (bibtex-start-of-text-in-field bounds)
+ (bibtex-end-of-text-in-field bounds)))
+ (value (string-trim value "{" "}")))
+ (message "Copied “%s” to kill-ring" value)
+ (kill-new value)))
+
+(provide 'casual-bibtex-utils)
+;;; casual-bibtex-utils.el ends here
diff --git a/lisp/casual-bibtex.el b/lisp/casual-bibtex.el
new file mode 100644
index 0000000000..ef9dcd6bb5
--- /dev/null
+++ b/lisp/casual-bibtex.el
@@ -0,0 +1,145 @@
+;;; casual-bibtex.el --- Transient UI for BibTeX -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2025 Charles Y. 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:
+
+;; This library provides a Transient-based user interface for the `bibtex'
+;; package.
+
+;; INSTALLATION
+
+;; In your initialization file, bind the Transient `casual-bibtex-tmenu' to
your
+;; key binding of preference.
+
+;; (require 'casual-bibtex) ; optional if using autoloaded menu
+;; (keymap-set bibtex-mode-map "M-m" #'casual-bibtex-tmenu)
+
+;; It is highly recommended to modify the bindings in `bibtex-mode-map' to be
+;; compatible with the bindings used in `casual-bibtex-tmenu':
+
+;; (keymap-set bibtex-mode-map "<TAB>" #'bibtex-next-field)
+;; (keymap-set bibtex-mode-map "<backtab>" #'previous-line)
+;; (keymap-set bibtex-mode-map "C-n" #'bibtex-next-field)
+;; (keymap-set bibtex-mode-map "M-n" #'bibtex-next-entry)
+;; (keymap-set bibtex-mode-map "M-p" #'bibtex-previous-entry)
+;; (keymap-set bibtex-mode-map "<prior>" #'bibtex-previous-entry)
+;; (keymap-set bibtex-mode-map "<next>" #'bibtex-next-entry)
+;; (keymap-set bibtex-mode-map "C-c C-o" #'bibtex-url)
+;; (keymap-set bibtex-mode-map "C-a" #'casual-bibtex-beginning-of-field)
+;; (keymap-set bibtex-mode-map "C-e" #'casual-bibtex-end-of-field)
+;; (keymap-set bibtex-mode-map "<clear>" #'bibtex-empty-field)
+;; (keymap-set bibtex-mode-map "M-<clear>" #'bibtex-kill-field)
+;; (keymap-set bibtex-mode-map "M-DEL" #'bibtex-kill-field)
+
+;;; Code:
+(require 'bookmark)
+(require 'replace)
+(require 'casual-bibtex-settings)
+(require 'casual-bibtex-utils)
+
+;;;###autoload (autoload 'casual-bibtex-tmenu "casual-bibtex" nil t)
+(transient-define-prefix casual-bibtex-tmenu ()
+ "Transient menu for BibTeX."
+ :refresh-suffixes t
+ ["Casual BibTeX"
+ :pad-keys t
+ ["Field"
+ ("a" "Add…" bibtex-make-field :transient nil)
+ ("c" "Copy∙ k,v" bibtex-copy-field-as-kill :transient nil)]
+
+ [""
+ ("w" "Copy v" casual-bibtex-copy-field-value :transient nil)
+ ("x" "Clear v" bibtex-empty-field :transient nil)]
+
+ [""
+ ("DEL" "Delete k,v" bibtex-kill-field :transient nil)
+ ("o" "Remove OPT/ALT" bibtex-remove-OPT-or-ALT :transient nil)]
+
+ [""
+ ("C-a" "Begin" casual-bibtex-beginning-of-field
+ :description (lambda () (casual-bibtex-unicode-get :begin-field))
+ :transient t)
+ ("C-e" "End" casual-bibtex-end-of-field
+ :description (lambda () (casual-bibtex-unicode-get :end-field))
+ :transient t)]
+
+ [""
+ ("p" "Previous" previous-line
+ :description (lambda () (casual-bibtex-unicode-get :previous))
+ :transient t)
+ ("n" "Next" bibtex-next-field
+ :description (lambda () (casual-bibtex-unicode-get :next))
+ :transient t)]]
+
+ ["Entry"
+ :pad-keys t
+ [("A" "Add…" bibtex-entry :transient nil)
+ ("C" "Copy∙" bibtex-copy-entry-as-kill :transient nil)]
+
+ [("k" "Kill∙" bibtex-kill-entry :transient nil)
+ ("u" "Update" bibtex-entry-update :transient nil)]
+
+ [("m" "Mark" bibtex-mark-entry :transient nil)]
+
+ [("f" "Fill" bibtex-fill-entry :transient nil)
+ ("C-c" "Clean" bibtex-clean-entry :transient nil)]
+
+ [("<" "Begin Entry" bibtex-beginning-of-entry
+ :description (lambda () (casual-bibtex-unicode-get :begin-entry))
+ :transient t)
+ (">" "End Entry" bibtex-end-of-entry
+ :description (lambda () (casual-bibtex-unicode-get :end-entry))
+ :transient t)]
+
+ [("M-p" "Previous Entry" bibtex-previous-entry
+ :description (lambda () (casual-bibtex-unicode-get :previous))
+ :transient t)
+ ("M-n" "Next Entry" bibtex-next-entry
+ :description (lambda () (casual-bibtex-unicode-get :next))
+ :transient t)]]
+
+ ["Misc"
+ :pad-keys t
+ [("y" "Yank∙" bibtex-yank :transient t)
+ ("M-y" "Yank-Pop∙" bibtex-yank-pop :transient t)]
+
+ [("/" "Search…" bibtex-search-entries :transient t)
+ ("j" "Jump…" bibtex-search-entry :transient t)]
+ [("." "Xref…" bibtex-search-crossref :transient t)
+ ("s" "Sort" bibtex-sort-buffer :transient t)]
+ [("O" "Occur…" occur)
+ ("N" "Narrow" bibtex-narrow-to-entry
+ :if-not buffer-narrowed-p
+ :transient nil)
+ ("W" "Widen" widen
+ :if buffer-narrowed-p
+ :transient nil)]
+ [("C-s" "Save" save-buffer :transient t)
+ ("J" "Jump to Bookmark…" bookmark-jump)]]
+
+ [:class transient-row
+ (casual-lib-quit-one)
+ ("RET" "Edit" transient-quit-all)
+ ("U" "Undo" undo :transient t)
+ ("," "Settings›" casual-bibtex-settings-tmenu)
+ (casual-lib-quit-all)])
+
+(provide 'casual-bibtex)
+;;; casual-bibtex.el ends here
diff --git a/lisp/casual.el b/lisp/casual.el
index 0312308906..013182f7b0 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.8.4
+;; Version: 2.8.5-rc.1
;; Package-Requires: ((emacs "29.1") (transient "0.9.0"))
;; This program is free software; you can redistribute it and/or modify
@@ -33,6 +33,9 @@
;; - Agenda (Elisp library: `casual-agenda.el')
;; An interface for Org Agenda to help you plan your day.
+;; - BibTeX (Elisp library: `casual-bibtex.el')
+;; An interface for editing your BibTeX file.
+
;; - Bookmarks (Elisp library: `casual-bookmarks.el')
;; An interface for editing your bookmark collection.
diff --git a/tests/Makefile b/tests/Makefile
index 519268fb45..fa1ef9c71a 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -19,6 +19,7 @@ TIMESTAMP := $(shell /bin/date "+%Y%m%d_%H%M%S")
.PHONY: tests \
lib-tests \
agenda-tests \
+bibtex-tests \
bookmarks-tests \
calc-tests \
calendar-tests \
@@ -40,6 +41,7 @@ SRC_DIR=../lisp
tests: lib-tests \
agenda-tests \
+bibtex-tests \
bookmarks-tests \
calc-tests \
calendar-tests \
@@ -63,6 +65,9 @@ lib-tests:
agenda-tests:
$(MAKE) -C $(SRC_DIR) $@
+bibtex-tests:
+ $(MAKE) -C $(SRC_DIR) $@
+
bookmarks-tests:
$(MAKE) -C $(SRC_DIR) $@
diff --git a/tests/casual-bibtex-test-utils.el
b/tests/casual-bibtex-test-utils.el
new file mode 100644
index 0000000000..1b32779816
--- /dev/null
+++ b/tests/casual-bibtex-test-utils.el
@@ -0,0 +1,48 @@
+;;; casual-bibtex-test-utils.el --- Casual Test Utils -*-
lexical-binding: t; -*-
+
+;; Copyright (C) 2024-2025 Charles Y. 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 'bibtex)
+
+(defun casualt-bibtex-setup (&optional filename)
+ "Casual menu test setup function."
+ (when filename
+ (let ((temp-filename (concat "/tmp/" filename)))
+ (with-temp-file temp-filename
+ (goto-char (point-min)))
+ (find-file temp-filename))))
+
+(defun casualt-bibtex-breakdown (&optional filename)
+ "Casual menu test breakdown function, if CLEAR is non-nil then clear state."
+ (when filename
+ (let ((temp-filename (concat "/tmp/" filename)))
+ (switch-to-buffer filename)
+ (kill-buffer)
+ (delete-file temp-filename))))
+
+(provide 'casual-bibtex-test-utils)
+;;; casual-bibtex-test-utils.el ends here
diff --git a/tests/test-casual-bibtex-settings.el
b/tests/test-casual-bibtex-settings.el
new file mode 100644
index 0000000000..f8f70c7575
--- /dev/null
+++ b/tests/test-casual-bibtex-settings.el
@@ -0,0 +1,62 @@
+;;; test-casual-bibtex-settings.el --- Casual Make Settings Tests -*-
lexical-binding: t; -*-
+
+;; Copyright (C) 2025 Charles Y. 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-bibtex-test-utils)
+(require 'casual-bibtex-settings)
+
+(ert-deftest test-casual-bibtex-settings-tmenu ()
+ (let ()
+ (cl-letf ((casualt-mock #'casual-bibtex--customize-dialect)
+ (casualt-mock #'casual-bibtex--customize-file-path)
+ (casualt-mock #'casual-bibtex--customize-files)
+ (casualt-mock #'casual-bibtex--customize-search-entry-globally)
+ (casualt-mock #'casual-bibtex--customize-clean-entry-hook)
+ (casualt-mock #'casual-bibtex--customize-add-entry-hook)
+ (casualt-mock #'casual-bibtex--customize-group)
+ (casualt-mock #'casual-bibtex-about))
+
+ (let ((test-vectors
+ '((:binding "d" :command casual-bibtex--customize-dialect)
+ (:binding "G" :command casual-bibtex--customize-group)
+ (:binding "p" :command casual-bibtex--customize-file-path)
+ (:binding "f" :command casual-bibtex--customize-files)
+ (:binding "g" :command
casual-bibtex--customize-search-entry-globally)
+ (:binding "C" :command
casual-bibtex--customize-clean-entry-hook)
+ (:binding "A" :command casual-bibtex--customize-add-entry-hook)
+ (:binding "u" :command
casual-lib-customize-casual-lib-use-unicode)
+ (:binding "n" :command
casual-lib-customize-casual-lib-hide-navigation)
+ (:binding "a" :command casual-bibtex-about))))
+
+ (casualt-suffix-testcase-runner test-vectors
+ #'casual-bibtex-settings-tmenu
+ '(lambda () (random 5000)))))))
+
+(ert-deftest test-casual-bibtex-about ()
+ (should (stringp (casual-bibtex-about))))
+
+(provide 'test-casual-bibtex-settings)
+;;; test-casual-bibtex-settings.el ends here
diff --git a/tests/test-casual-bibtex-utils.el
b/tests/test-casual-bibtex-utils.el
new file mode 100644
index 0000000000..5c837ef54c
--- /dev/null
+++ b/tests/test-casual-bibtex-utils.el
@@ -0,0 +1,50 @@
+;;; test-casual-bibtex-utils.el --- Casual Make Utils Tests -*-
lexical-binding: t; -*-
+
+;; Copyright (C) 2025 Charles Y. 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-bibtex-test-utils)
+(require 'casual-bibtex-utils)
+
+(ert-deftest test-casual-bibtex-unicode-get ()
+ (let ((casual-lib-use-unicode nil))
+ (should (string-equal (casual-bibtex-unicode-get :previous) "Previous"))
+ (should (string-equal (casual-bibtex-unicode-get :next) "Next"))
+ (should (string-equal (casual-bibtex-unicode-get :begin-entry) "Begin"))
+ (should (string-equal (casual-bibtex-unicode-get :end-entry) "End"))
+ (should (string-equal (casual-bibtex-unicode-get :begin-field) "Begin"))
+ (should (string-equal (casual-bibtex-unicode-get :end-field) "End"))
+ (should (string-equal (casual-bibtex-unicode-get :clear) "Clear")))
+
+ (let ((casual-lib-use-unicode t))
+ (should (string-equal (casual-bibtex-unicode-get :previous) "↑"))
+ (should (string-equal (casual-bibtex-unicode-get :next) "↓"))
+ (should (string-equal (casual-bibtex-unicode-get :begin-entry) "⇱"))
+ (should (string-equal (casual-bibtex-unicode-get :end-entry) "⇲"))
+ (should (string-equal (casual-bibtex-unicode-get :begin-field) "⇤"))
+ (should (string-equal (casual-bibtex-unicode-get :end-field) "⇥"))
+ (should (string-equal (casual-bibtex-unicode-get :clear) "⌫"))))
+
+(provide 'test-casual-bibtex-utils)
+;;; test-casual-bibtex-utils.el ends here
diff --git a/tests/test-casual-bibtex.el b/tests/test-casual-bibtex.el
new file mode 100644
index 0000000000..d6cd5bba00
--- /dev/null
+++ b/tests/test-casual-bibtex.el
@@ -0,0 +1,112 @@
+;;; test-casual-bibtex.el --- BibTeX Tests -*- lexical-binding: t;
-*-
+
+;; Copyright (C) 2025 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-bibtex-test-utils)
+(require 'casual-lib-test-utils)
+(require 'casual-bibtex)
+
+(ert-deftest test-casual-bibtex-tmenu ()
+ (let ((tmpfile "casual-bibtex-main-tmenu.txt"))
+ (casualt-bibtex-setup)
+ (cl-letf ((casualt-mock #'bibtex-make-field)
+ (casualt-mock #'bibtex-copy-field-as-kill)
+ (casualt-mock #'casual-bibtex-copy-field-value)
+ (casualt-mock #'bibtex-empty-field)
+ (casualt-mock #'bibtex-kill-field)
+ (casualt-mock #'bibtex-remove-OPT-or-ALT)
+ (casualt-mock #'casual-bibtex-beginning-of-field)
+ (casualt-mock #'casual-bibtex-end-of-field)
+ (casualt-mock #'previous-line)
+ (casualt-mock #'bibtex-next-field)
+ (casualt-mock #'bibtex-entry)
+ (casualt-mock #'bibtex-copy-entry-as-kill)
+ (casualt-mock #'bibtex-kill-entry)
+ (casualt-mock #'bibtex-entry-update)
+ (casualt-mock #'bibtex-mark-entry)
+ (casualt-mock #'bibtex-fill-entry)
+ (casualt-mock #'bibtex-clean-entry)
+ (casualt-mock #'bibtex-beginning-of-entry)
+ (casualt-mock #'bibtex-end-of-entry)
+ (casualt-mock #'bibtex-previous-entry)
+ (casualt-mock #'bibtex-next-entry)
+ (casualt-mock #'bibtex-yank)
+ (casualt-mock #'bibtex-yank-pop)
+ (casualt-mock #'bibtex-search-entries)
+ (casualt-mock #'bibtex-search-crossref)
+ (casualt-mock #'bibtex-sort-buffer)
+ (casualt-mock #'bibtex-narrow-to-entry)
+ (casualt-mock #'occur)
+ (casualt-mock #'widen)
+ (casualt-mock #'save-buffer)
+ (casualt-mock #'bookmark-jump)
+ )
+
+ (let ((test-vectors
+ '(
+ ;; (:binding "a" :command bibtex-make-field)
+ (:binding "c" :command bibtex-copy-field-as-kill)
+ (:binding "w" :command casual-bibtex-copy-field-value)
+ (:binding "x" :command bibtex-empty-field)
+ (:binding "DEL" :command bibtex-kill-field)
+ (:binding "o" :command bibtex-remove-OPT-or-ALT)
+ (:binding "C-a" :command casual-bibtex-beginning-of-field)
+ (:binding "C-e" :command casual-bibtex-end-of-field)
+ (:binding "p" :command previous-line)
+ (:binding "n" :command bibtex-next-field)
+
+ (:binding "A" :command bibtex-entry)
+ (:binding "C" :command bibtex-copy-entry-as-kill)
+ (:binding "k" :command bibtex-kill-entry)
+ (:binding "u" :command bibtex-entry-update)
+ (:binding "m" :command bibtex-mark-entry)
+ (:binding "f" :command bibtex-fill-entry)
+ (:binding "C-c" :command bibtex-clean-entry)
+ (:binding "<" :command bibtex-beginning-of-entry)
+ (:binding ">" :command bibtex-end-of-entry)
+ (:binding "M-p" :command bibtex-previous-entry)
+ (:binding "M-n" :command bibtex-next-entry)
+
+ (:binding "y" :command bibtex-yank)
+ (:binding "M-y" :command bibtex-yank-pop)
+ (:binding "/" :command bibtex-search-entries)
+ (:binding "j" :command bibtex-search-entry)
+ ;; (:binding "." :command bibtex-search-crossref)
+ (:binding "s" :command bibtex-sort-buffer)
+ (:binding "O" :command occur)
+ (:binding "N" :command bibtex-narrow-to-entry)
+ (:binding "C-s" :command save-buffer)
+ (:binding "J" :command bookmark-jump)
+ )))
+
+ (casualt-suffix-testcase-runner test-vectors
+ #'casual-bibtex-tmenu
+ '(lambda () (random 5000)))))
+ (casualt-bibtex-breakdown)))
+
+
+(provide 'test-casual-bibtex)
+;;; test-casual-bibtex.el ends here