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

Reply via email to