branch: elpa/casual
commit c13dcf78ea345b0f7abcb2c8317b5b880270a506
Merge: 6787b1bb42 e0b3e68ffa
Author: Charles Choi <[email protected]>
Commit: GitHub <[email protected]>

    Merge pull request #363 from kickingvegas/299-build-casual-eww
    
    Add EWW support
---
 docs/casual.info                                   | Bin 148783 -> 153025 bytes
 docs/casual.org                                    |   2 +
 docs/eww.org                                       | 104 ++++++++++++
 docs/html.org                                      |   2 +-
 docs/images/casual-eww-bookmarks-screenshot.png    | Bin 0 -> 42926 bytes
 docs/images/casual-eww-display-screenshot.png      | Bin 0 -> 43366 bytes
 docs/images/casual-eww-screenshot.png              | Bin 0 -> 131453 bytes
 docs/images/casual-eww-settings-screenshot.png     | Bin 0 -> 77441 bytes
 docs/images/casual-eww-unicode-screenshot.png      | Bin 0 -> 76178 bytes
 lisp/Makefile                                      |   7 +-
 lisp/Makefile-eww.make                             |  31 ++++
 lisp/casual-eww-settings.el                        | 143 ++++++++++++++++
 lisp/casual-eww-utils.el                           | 123 ++++++++++++++
 lisp/casual-eww.el                                 | 180 +++++++++++++++++++++
 lisp/casual.el                                     |   5 +-
 templates/tests/casual-MODULE-test-utils.el        |   2 +-
 templates/tests/test-casual-MODULE-settings.el     |   2 +-
 templates/tests/test-casual-MODULE-utils.el        |   2 +-
 templates/tests/test-casual-MODULE.el              |   2 +-
 tests/Makefile                                     |   5 +
 .../casual-eww-test-utils.el                       |  16 +-
 tests/test-casual-eww-settings.el                  |  66 ++++++++
 tests/test-casual-eww-utils.el                     |  97 +++++++++++
 tests/test-casual-eww.el                           | 126 +++++++++++++++
 24 files changed, 900 insertions(+), 15 deletions(-)

diff --git a/docs/casual.info b/docs/casual.info
index 7393869b73..2b2678bd8a 100644
Binary files a/docs/casual.info and b/docs/casual.info differ
diff --git a/docs/casual.org b/docs/casual.org
index 8020e8c72d..975a94d1eb 100644
--- a/docs/casual.org
+++ b/docs/casual.org
@@ -155,6 +155,7 @@ Configuration of a particular Casual user interface is 
performed per mode. Go to
 - [[#editkit-install][EditKit]]
 - [[#elisp-install][Elisp]]
 - [[#eshell-install][Eshell]]
+- [[#eww-install][EWW]]
 - [[#help-install][Help]]
 - [[#html-install][HTML]]
 - [[#ibuffer-install][IBuffer]]
@@ -271,6 +272,7 @@ The following modes are supported by Casual:
 #+INCLUDE: "./editkit.org" :minlevel 2
 #+INCLUDE: "./elisp.org" :minlevel 2
 #+INCLUDE: "./eshell.org" :minlevel 2
+#+INCLUDE: "./eww.org" :minlevel 2
 #+INCLUDE: "./help.org" :minlevel 2
 #+INCLUDE: "./html.org" :minlevel 2
 #+INCLUDE: "./ibuffer.org" :minlevel 2
diff --git a/docs/eww.org b/docs/eww.org
new file mode 100644
index 0000000000..f152ae9f4e
--- /dev/null
+++ b/docs/eww.org
@@ -0,0 +1,104 @@
+* EWW
+#+CINDEX: EWW
+#+VINDEX: casual-eww-tmenu
+
+Casual EWW is a user interface for Emacs Web Wowser ([[info:eww#Top]]), a web 
browser that runs inside Emacs.
+
+[[file:images/casual-eww-screenshot.png]]
+
+** EWW Install
+:PROPERTIES:
+:CUSTOM_ID: eww-install
+:END:
+
+#+CINDEX: EWW Install
+
+In your initialization file, bind the Transient ~casual-eww-tmenu~ to your key 
binding of preference.
+
+#+begin_src elisp :lexical no
+  (keymap-set eww-mode-map "C-o" #'casual-eww-tmenu)
+#+end_src
+
+Do so similarly to access ~casual-eww-bookmarks-tmenu~ in the EWW bookmarks 
list.
+
+#+begin_src elisp :lexical no
+  (keymap-set eww-bookmark-mode-map "C-o" #'casual-eww-bookmarks-tmenu)
+#+end_src
+
+While not mandatory, the following bindings can make the EWW keymaps 
consistent with those used by Casual.
+
+#+BEGIN_SRC elisp :lexical no
+  (keymap-set eww-mode-map "C-o" #'casual-eww-tmenu)
+  (keymap-set eww-mode-map "C-c C-o" #'eww-browse-with-external-browser)
+  (keymap-set eww-mode-map "j" #'shr-next-link)
+  (keymap-set eww-mode-map "k" #'shr-previous-link)
+  (keymap-set eww-mode-map "[" #'eww-previous-url)
+  (keymap-set eww-mode-map "]" #'eww-next-url)
+  (keymap-set eww-mode-map "M-]" #'eww-forward-url)
+  (keymap-set eww-mode-map "M-[" #'eww-back-url)
+  (keymap-set eww-mode-map "n" #'casual-lib-browse-forward-paragraph)
+  (keymap-set eww-mode-map "p" #'casual-lib-browse-backward-paragraph)
+  (keymap-set eww-mode-map "P" #'casual-eww-backward-paragraph-link)
+  (keymap-set eww-mode-map "N" #'casual-eww-forward-paragraph-link)
+  (keymap-set eww-mode-map "M-l" #'eww)
+
+  (keymap-set eww-bookmark-mode-map "C-o" #'casual-eww-bookmarks-tmenu)
+  (keymap-set eww-bookmark-mode-map "p" #'previous-line)
+  (keymap-set eww-bookmark-mode-map "n" #'next-line)
+  (keymap-set eww-bookmark-mode-map "<double-mouse-1>" #'eww-bookmark-browse)
+#+END_SRC
+
+** EWW Usage
+#+CINDEX: EWW Usage
+
+In an EWW window, invoke ~casual-eww-tmenu~ as shown below.
+
+[[file:images/casual-eww-screenshot.png]]
+
+The following sections are offered in the menu:
+
+- History :: Commands for historical navigation.
+  
+- Document :: Commands for document navigation (~<link rel="">~) provided the 
HTML pages support it.
+  HTML generated from Texinfo ([[info:texinfo#Top]]) supports these commands.
+  
+- Navigate :: Commands to navigate within a page.
+  
+- Link :: Commands to navigate links within a page.
+  
+- Misc :: Miscellaneous commands.
+  
+- URL :: Commands associated with the current web page.
+  
+- EWW Bookmarks :: Commands associated with EWW bookmarks.
+
+#+TEXINFO: @subheading EWW Settings
+#+VINDEX: casual-eww-settings-tmenu
+
+Customize common EWW settings from this menu. These settings can be persisted 
to be used across restarts of Emacs.
+
+[[file:images/casual-eww-settings-screenshot.png]]
+
+
+#+TEXINFO: @subheading EWW Display
+#+VINDEX: casual-eww-display-tmenu
+
+This menu (~casual-eww-display-tmenu~) provides commands to toggle different 
display attributes of a web page.
+
+[[file:images/casual-eww-display-screenshot.png]]
+
+
+#+TEXINFO: @subheading EWW Bookmarks
+#+VINDEX: casual-eww-bookmarks-tmenu
+
+This menu (~casual-eww-bookmarks-tmenu~) provides commands for managing the 
EWW bookmark list.
+
+[[file:images/casual-eww-bookmarks-screenshot.png]]
+
+Note that the EWW bookmarks list has a very limited feature set.
+
+#+TEXINFO: @subheading EWW Unicode Symbol Support
+
+By enabling “{{{kbd(u)}}} Use Unicode Symbols” from the Settings menu, Casual 
EWW will use Unicode symbols as appropriate in its menus.
+
+[[file:images/casual-eww-unicode-screenshot.png]]
diff --git a/docs/html.org b/docs/html.org
index 9862c4240e..1188573f1f 100644
--- a/docs/html.org
+++ b/docs/html.org
@@ -26,7 +26,7 @@ In your initialization file, bind the Transient 
~casual-html-tmenu~ to your key
 
 A different binding ({{{kbd(M-m)}}}) is used as ~casual-html-tmenu~ is 
intended to work alongside with [[#editkit-install][Casual EditKit]].
 
-It is convenient to also bind ~casual-html-tag-tmenu~ as well.
+It is convenient to also bind ~casual-html-tags-tmenu~ as well.
 
 #+begin_src elisp :lexical no
   (keymap-set html-mode-map "C-c m" #'casual-html-tags-tmenu)
diff --git a/docs/images/casual-eww-bookmarks-screenshot.png 
b/docs/images/casual-eww-bookmarks-screenshot.png
new file mode 100644
index 0000000000..328614462e
Binary files /dev/null and b/docs/images/casual-eww-bookmarks-screenshot.png 
differ
diff --git a/docs/images/casual-eww-display-screenshot.png 
b/docs/images/casual-eww-display-screenshot.png
new file mode 100644
index 0000000000..7714977b8f
Binary files /dev/null and b/docs/images/casual-eww-display-screenshot.png 
differ
diff --git a/docs/images/casual-eww-screenshot.png 
b/docs/images/casual-eww-screenshot.png
new file mode 100644
index 0000000000..4c6b583ca8
Binary files /dev/null and b/docs/images/casual-eww-screenshot.png differ
diff --git a/docs/images/casual-eww-settings-screenshot.png 
b/docs/images/casual-eww-settings-screenshot.png
new file mode 100644
index 0000000000..070ac37779
Binary files /dev/null and b/docs/images/casual-eww-settings-screenshot.png 
differ
diff --git a/docs/images/casual-eww-unicode-screenshot.png 
b/docs/images/casual-eww-unicode-screenshot.png
new file mode 100644
index 0000000000..9864627585
Binary files /dev/null and b/docs/images/casual-eww-unicode-screenshot.png 
differ
diff --git a/lisp/Makefile b/lisp/Makefile
index 68310df6a0..555678feb4 100644
--- a/lisp/Makefile
+++ b/lisp/Makefile
@@ -1,5 +1,5 @@
 ##
-# Copyright (C) 2024-2025 Charles Y. Choi
+# Copyright (C) 2024-2026 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
@@ -32,6 +32,7 @@ ediff-tests                                   \
 editkit-tests                                  \
 elisp-tests                                    \
 eshell-tests                                   \
+eww-tests                                      \
 help-tests                                     \
 html-tests                                     \
 ibuffer-tests                                  \
@@ -98,6 +99,10 @@ elisp-tests:
 eshell-tests:
        $(MAKE) -C $(SRC_DIR) -f Makefile-eshell.make tests
 
+.PHONY: eww-tests
+eww-tests:
+       $(MAKE) -C $(SRC_DIR) -f Makefile-eww.make tests
+
 .PHONY: help-tests
 help-tests:
        $(MAKE) -C $(SRC_DIR) -f Makefile-help.make tests
diff --git a/lisp/Makefile-eww.make b/lisp/Makefile-eww.make
new file mode 100644
index 0000000000..7ff4b138b6
--- /dev/null
+++ b/lisp/Makefile-eww.make
@@ -0,0 +1,31 @@
+##
+# Copyright (C) 2026 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-eww
+ELISP_INCLUDES=casual-eww-utils.el     \
+casual-eww-settings.el
+ELISP_PACKAGES=
+ELISP_TEST_INCLUDES=casual-eww-test-utils.el
+PACKAGE_PATHS=                                 \
+-L $(EMACS_ELPA_DIR)/compat-current            \
+-L $(EMACS_ELPA_DIR)/seq-current               \
+-L $(EMACS_ELPA_DIR)/transient-current         \
+-L $(EMACS_ELPA_DIR)/cond-let-current          \
+-L $(CASUAL_LIB_LISP_DIR)
+
+include Makefile--rules.make
diff --git a/lisp/casual-eww-settings.el b/lisp/casual-eww-settings.el
new file mode 100644
index 0000000000..2ed56e1394
--- /dev/null
+++ b/lisp/casual-eww-settings.el
@@ -0,0 +1,143 @@
+;;; casual-eww-settings.el --- Casual EWW Settings -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2026 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 'eww)
+(require 'casual-lib)
+
+(transient-define-prefix casual-eww-settings-tmenu ()
+  "Casual EWW settings menu."
+  ["Casual EWW: Settings"
+
+   ["Browsing"
+    ("r" "Retrieve Command" casual-eww--customize-retrieve-command)
+    ("R" "Readable URLs" casual-eww--customize-readable-urls)
+    ("h" "History Limit" casual-eww--customize-history-limit
+     :description (lambda () (format "History Limit (%d)" eww-history-limit)))]
+
+   ["Directory"
+    ("d" "Download" casual-eww--customize-download-directory
+     :description (lambda () (format "Directory (%s)" 
(eww--download-directory))))
+    ("b" "Bookmarks" casual-eww--customize-bookmarks-directory
+     :description (lambda () (format "Directory (%s)" 
eww-bookmarks-directory)))]
+
+   ["Display"
+    ("f" "Use Fonts" casual-eww--customize-shr-use-fonts
+     :description (lambda () (casual-lib-checkbox-label
+                         shr-use-fonts "Use Fonts"))
+     :transient t)
+    ("c" "Use Colors" casual-eww--customize-shr-use-colors
+     :description (lambda () (casual-lib-checkbox-label
+                         shr-use-colors "Use Colors"))
+     :transient t)
+    ("i" "Inhibit Images" casual-eww--customize-shr-inhibit-images
+     :description (lambda () (casual-lib-checkbox-label
+                         shr-inhibit-images "Inhibit Images"))
+     :transient t)]]
+
+  ["General"
+   :class transient-row
+   (casual-lib-customize-unicode)
+   (casual-lib-customize-hide-navigation)]
+
+  [:class transient-row
+   (casual-lib-quit-one)
+   ("a" "About" casual-eww-about :transient nil)
+   ("G" "EWW Group" casual-eww--customize-group)
+   (casual-lib-quit-all)])
+
+(defun casual-eww--customize-group ()
+  "Customize EWW group."
+  (interactive)
+  (customize-group "eww"))
+
+(defun casual-eww--customize-retrieve-command ()
+  "Customize `eww-retrieve-commmand'."
+  (interactive)
+  (customize-variable 'eww-retrieve-command))
+
+(defun casual-eww--customize-readable-urls ()
+  "Customize `eww-readable-urls'."
+  (interactive)
+  (customize-variable 'eww-readable-urls))
+
+(defun casual-eww--customize-download-directory ()
+  "Customize `eww-download-directory'."
+  (interactive)
+  (customize-variable 'eww-download-directory))
+
+(defun casual-eww--customize-bookmarks-directory ()
+  "Customize `eww-bookmarks-directory'."
+  (interactive)
+  (customize-variable 'eww-bookmarks-directory))
+
+(defun casual-eww--customize-history-limit ()
+  "Customize `eww-history-limit'."
+  (interactive)
+  (customize-variable 'eww-history-limit))
+
+(defun casual-eww--customize-shr-use-fonts ()
+  "Customize `shr-use-fonts'."
+  (interactive)
+  (customize-variable 'shr-use-fonts))
+
+(defun casual-eww--customize-shr-use-colors ()
+  "Customize `shr-use-colors'."
+  (interactive)
+  (customize-variable 'shr-use-colors))
+
+(defun casual-eww--customize-shr-inhibit-images ()
+  "Customize `shr-inhibit-images'."
+  (interactive)
+  (customize-variable 'shr-inhibit-images))
+
+(defun casual-eww-about-eww ()
+  "Casual EWW is a Transient menu for Emacs Web Wowser (EWW).
+
+Learn more about using Casual EWW 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 EWW, consider making a modest financial
+contribution to help support its development and maintenance.
+URL `https://www.buymeacoffee.com/kickingvegas'
+
+Casual EWW was conceived and crafted by Charles Choi in San Francisco,
+California.
+
+Thank you for using Casual EWW.
+
+Always choose love."
+  (ignore))
+
+(defun casual-eww-about ()
+  "About information for Casual EWW."
+  (interactive)
+  (describe-function #'casual-eww-about-eww))
+
+(provide 'casual-eww-settings)
+;;; casual-eww-settings.el ends here
diff --git a/lisp/casual-eww-utils.el b/lisp/casual-eww-utils.el
new file mode 100644
index 0000000000..49babdbcba
--- /dev/null
+++ b/lisp/casual-eww-utils.el
@@ -0,0 +1,123 @@
+;;; casual-eww-utils.el --- Casual EWW Utils -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2026 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 'eww)
+(require 'casual-lib)
+
+(defconst casual-eww-unicode-db
+  '((:history-back . '("❬" "Back"))
+    (:history-forward . '("❭" "Forward"))
+    (:previous . '("↑" "Previous"))
+    (:next . '("↓" "Next"))
+    (:backward-paragraph . '("¶↑" "Previous ¶"))
+    (:forward-paragraph . '("¶↓" "Next ¶"))
+    (:forward . '("→" "Forward"))
+    (:back . '("←" "Back"))
+    (:link . '("🔗" "Link"))
+    (:top . '("⤒" "Top"))
+    (:history . '("≣" "History"))
+    (:page . '("📄" "Page"))
+    (:scroll-up . '("📄↓" "Scroll Up"))
+    (:scroll-down . '("📄↑" "Scroll Down"))
+    (:follow . '("🚀" "Follow"))
+    (:paragraph . '("¶" "Paragraph"))
+    (:beginning-of-buffer . '("⇱" "Beginning"))
+    (:end-of-buffer . '("⇲" "End"))
+    (:reload . '("⟳" "Reload"))
+    (:kill . '("×" "Close"))
+    (:see-also . '("👀" "See Also")))
+
+  "Unicode symbol DB to use for eww Transient menus.")
+
+(defun casual-eww-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-eww-unicode-db))
+
+(defun casual-eww-info ()
+  "Open Info for Emacs Web Wowser (EWW)."
+  (interactive) (info "(eww) Top"))
+
+
+;; -------------------------------------------------------------------
+;;; Commands
+(defun casual-eww-forward-paragraph-link ()
+  "Move point to first link in next paragraph."
+  (interactive)
+  (casual-lib-browse-forward-paragraph)
+  (shr-next-link))
+
+(defun casual-eww-backward-paragraph-link ()
+  "Move point to first link in previous paragraph."
+  (interactive)
+
+  (let ((current-line-number (line-number-at-pos)))
+    (backward-paragraph)
+    (if (= current-line-number (line-number-at-pos))
+        (backward-paragraph))
+    (shr-next-link)))
+
+
+;; -------------------------------------------------------------------
+;;; Transients
+
+(transient-define-prefix casual-eww-display-tmenu ()
+  "Transient menu for EWW display controls.
+
+Note that only the runtime value of variables is changed. Commands in
+`casual-eww-settings-tmenu' will persistently change a variable's value."
+  ["Casual EWW Display"
+   ("f" "Use Fonts" eww-toggle-fonts
+    :description (lambda () (casual-lib-checkbox-label shr-use-fonts "Use 
Fonts"))
+    :transient t)
+   ("c" "Use Colors" eww-toggle-colors
+    :description (lambda () (casual-lib-checkbox-label shr-use-colors "Use 
Colors"))
+    :transient t)
+   ("i" "Use Images" eww-toggle-images
+    :description (lambda () (casual-lib-checkbox-label shr-inhibit-images 
"Inhibit Images"))
+    :transient t)
+   ("d" "Use Direction" eww-toggle-paragraph-direction
+    :description (lambda ()
+                   (format
+                    "¶ direction (%s)"
+                    (cond
+                     ((eq bidi-paragraph-direction 'left-to-right) "L→R")
+                     ((eq bidi-paragraph-direction 'right-to-left) "R←L")
+                     ((not bidi-paragraph-direction) "Auto")
+                     (t "Undefined"))))
+    :transient t)]
+
+  [:class transient-row
+   (casual-lib-quit-one)
+   (casual-lib-quit-all)])
+
+
+
+(provide 'casual-eww-utils)
+;;; casual-eww-utils.el ends here
diff --git a/lisp/casual-eww.el b/lisp/casual-eww.el
new file mode 100644
index 0000000000..6113d85a4d
--- /dev/null
+++ b/lisp/casual-eww.el
@@ -0,0 +1,180 @@
+;;; casual-eww.el --- Transient UI for EWW -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2026 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 EWW, a web 
browser
+;; for GNU Emacs.
+
+;; INSTALLATION
+
+;; In your initialization file, bind the Transient `casual-eww-tmenu' to your
+;; key binding of preference.
+
+;; (require 'casual-eww) ; optional if using autoloaded menu
+;; (keymap-set eww-mode-map "C-o" #'casual-eww-tmenu)
+
+;; Do so similarly to access `casual-eww-bookmarks-tmenu' in the EWW bookmarks
+;; list.
+
+;; (keymap-set eww-bookmark-mode-map "C-o" #'casual-eww-bookmarks-tmenu)
+
+;; While not mandatory, the following bindings can make the EWW keymaps
+;; consistent with those used by Casual.
+
+;; (keymap-set eww-mode-map "C-o" #'casual-eww-tmenu)
+;; (keymap-set eww-mode-map "C-c C-o" #'eww-browse-with-external-browser)
+;; (keymap-set eww-mode-map "j" #'shr-next-link)
+;; (keymap-set eww-mode-map "k" #'shr-previous-link)
+;; (keymap-set eww-mode-map "[" #'eww-previous-url)
+;; (keymap-set eww-mode-map "]" #'eww-next-url)
+;; (keymap-set eww-mode-map "M-]" #'eww-forward-url)
+;; (keymap-set eww-mode-map "M-[" #'eww-back-url)
+;; (keymap-set eww-mode-map "n" #'casual-lib-browse-forward-paragraph)
+;; (keymap-set eww-mode-map "p" #'casual-lib-browse-backward-paragraph)
+;; (keymap-set eww-mode-map "P" #'casual-eww-backward-paragraph-link)
+;; (keymap-set eww-mode-map "N" #'casual-eww-forward-paragraph-link)
+;; (keymap-set eww-mode-map "M-l" #'eww)
+;; (keymap-set eww-bookmark-mode-map "C-o" #'casual-eww-bookmarks-tmenu)
+;; (keymap-set eww-bookmark-mode-map "p" #'previous-line)
+;; (keymap-set eww-bookmark-mode-map "n" #'next-line)
+;; (keymap-set eww-bookmark-mode-map "<double-mouse-1>" #'eww-bookmark-browse)
+
+;;; Code:
+(require 'bookmark)
+(require 'casual-eww-settings)
+(require 'casual-eww-utils)
+
+;;;###autoload (autoload 'casual-eww-tmenu "casual-eww" nil t)
+(transient-define-prefix casual-eww-tmenu ()
+  "Transient menu for EWW.
+
+EWW (Emacs Web Wowser) is a web browser for GNU Emacs.
+
+See Info node `(eww)Top' for more information on it."
+   :refresh-suffixes t
+   ["Casual EWW"
+    ["History"
+     :pad-keys t
+     ("M-[" "❬" eww-back-url
+      :description (lambda () (casual-eww-unicode-get :history-back))
+      :transient t)
+     ("M-]" "❭" eww-forward-url
+      :description (lambda () (casual-eww-unicode-get :history-forward))
+      :transient t)
+     ("H" "History" eww-list-histories
+      :description (lambda () (casual-eww-unicode-get :history))
+      :transient nil)]
+
+    ["Document"
+     ("[" "←" eww-previous-url
+      :description (lambda () (casual-eww-unicode-get :back))
+      :transient t)
+     ("]" "→" eww-next-url
+      :description (lambda () (casual-eww-unicode-get :forward))
+      :transient t)
+     ("^" "↑" eww-up-url
+      :description (lambda () (casual-eww-unicode-get :previous))
+      :transient t)
+     ("t" "⤒" eww-top-url
+      :description (lambda () (casual-eww-unicode-get :top))
+      :transient t)]
+
+    ["Navigate"
+     :pad-keys t
+     ("p" "↑ ¶" casual-lib-browse-backward-paragraph
+      :description (lambda () (casual-eww-unicode-get :backward-paragraph))
+      :transient t)
+     ("n" "↓ ¶" casual-lib-browse-forward-paragraph
+      :description (lambda () (casual-eww-unicode-get :forward-paragraph))
+      :transient t)
+     ("SPC" "↓ 📄" scroll-up-command
+      :description (lambda () (casual-eww-unicode-get :scroll-up))
+      :transient t)
+     ("S-SPC" "↑ 📄" scroll-down-command
+      :description (lambda () (casual-eww-unicode-get :scroll-down))
+      :transient t)]
+
+    ["🔗"
+     :description (lambda () (casual-eww-unicode-get :link))
+     :pad-keys t
+     ("k" "↑" shr-previous-link
+      :description (lambda () (casual-eww-unicode-get :previous))
+      :transient t)
+     ("j" "↓" shr-next-link
+      :description (lambda () (casual-eww-unicode-get :next))
+      :transient t)
+     ("RET" "🚀" eww-follow-link
+      :description (lambda () (casual-eww-unicode-get :follow))
+      :transient t)]
+
+    ["Misc"
+     :pad-keys t
+     ("D" "Display›" casual-eww-display-tmenu)
+     ("R" "Readable" eww-readable)]]
+
+   ["URL"
+    :pad-keys t
+    [("M-l" "Open…" eww)
+     ("&" "Open External…" eww-browse-with-external-browser)]
+    [("c" "Copy" eww-copy-page-url)
+     ("A" "Copy Alt" eww-copy-alternate-url)]
+    [("d" "Download" eww-download)
+     ("g" "Reload" eww-reload
+      :description (lambda () (casual-eww-unicode-get :reload)))]]
+
+   ["EWW Bookmarks"
+    :class transient-row
+    ("b" "Add" eww-add-bookmark)
+    ("B" "List" eww-list-bookmarks)
+    ("M-n" "Next" eww-next-bookmark :transient t)
+    ("M-p" "Previous" eww-previous-bookmark :transient t)]
+
+   [:class transient-row
+    (casual-lib-quit-one)
+    ("," "Settings›" casual-eww-settings-tmenu)
+    ("I" "ⓘ" casual-eww-info)
+    ("J" "Jump to Bookmark…" bookmark-jump)
+    ("q" "Quit" quit-window)
+    (casual-lib-quit-all)])
+
+;;;###autoload (autoload 'casual-eww-bookmarks-tmenu "casual-eww" nil t)
+(transient-define-prefix casual-eww-bookmarks-tmenu ()
+  "Transient menu for EWW bookmarks."
+  :refresh-suffixes t
+
+  ["Casual EWW Bookmarks"
+   ["Bookmark"
+    :pad-keys t
+    ("k" "Kill" eww-bookmark-kill :transient t)
+    ("y" "Yank" eww-bookmark-yank :transient t)
+    ("RET" "Browse" eww-bookmark-browse)]
+
+   ["Navigate"
+    ("p" "Previous" previous-line :transient t)
+    ("n" "Next" next-line :transient t)]]
+
+  [:class transient-row
+   (casual-lib-quit-one)
+   ("q" "Quit" quit-window)
+   (casual-lib-quit-all)])
+
+(provide 'casual-eww)
+;;; casual-eww.el ends here
diff --git a/lisp/casual.el b/lisp/casual.el
index 381e8b4965..bc4ac867d9 100644
--- a/lisp/casual.el
+++ b/lisp/casual.el
@@ -1,6 +1,6 @@
 ;;; casual.el --- Transient user interfaces for various modes -*- 
lexical-binding: t; -*-
 
-;; Copyright (C) 2024-2025 Charles Y. Choi
+;; Copyright (C) 2024-2026 Charles Y. Choi
 
 ;; Author: Charles Choi <[email protected]>
 ;; URL: https://github.com/kickingvegas/casual
@@ -74,6 +74,9 @@
 ;;   An interface for Eshell, a shell-like command interpreter implemented in
 ;;   Emacs Lisp.
 
+;; - EWW (Elisp library: `casual-eww.el')
+;;   An interface for EWW (Emacs Web Wowser), a web browser for GNU Emacs.
+
 ;; - Help (Elisp library: `casual-help.el')
 ;;   An interface for `help-mode', a major mode for viewing help text and
 ;;   navigating references in it.
diff --git a/templates/tests/casual-MODULE-test-utils.el 
b/templates/tests/casual-MODULE-test-utils.el
index 7d9c847e21..aea22cdad6 100644
--- a/templates/tests/casual-MODULE-test-utils.el
+++ b/templates/tests/casual-MODULE-test-utils.el
@@ -1,6 +1,6 @@
 ;;; casual-$MODULE-test-utils.el --- Casual Test Utils       -*- 
lexical-binding: t; -*-
 
-;; Copyright (C) 2025  Charles Y. Choi
+;; Copyright (C) 2026  Charles Y. Choi
 
 ;; Author: Charles Choi <[email protected]>
 ;; Keywords: tools
diff --git a/templates/tests/test-casual-MODULE-settings.el 
b/templates/tests/test-casual-MODULE-settings.el
index a5b55b8ba4..fd7ad1589f 100644
--- a/templates/tests/test-casual-MODULE-settings.el
+++ b/templates/tests/test-casual-MODULE-settings.el
@@ -1,6 +1,6 @@
 ;;; test-casual-$MODULE-settings.el --- Casual Make Settings Tests  -*- 
lexical-binding: t; -*-
 
-;; Copyright (C) 2025  Charles Y. Choi
+;; Copyright (C) 2026  Charles Y. Choi
 
 ;; Author: Charles Choi <[email protected]>
 ;; Keywords: tools
diff --git a/templates/tests/test-casual-MODULE-utils.el 
b/templates/tests/test-casual-MODULE-utils.el
index 8b36bb9993..765c1353bc 100644
--- a/templates/tests/test-casual-MODULE-utils.el
+++ b/templates/tests/test-casual-MODULE-utils.el
@@ -1,6 +1,6 @@
 ;;; test-casual-$MODULE-utils.el --- Casual Make Utils Tests  -*- 
lexical-binding: t; -*-
 
-;; Copyright (C) 2025  Charles Y. Choi
+;; Copyright (C) 2026  Charles Y. Choi
 
 ;; Author: Charles Choi <[email protected]>
 ;; Keywords: tools
diff --git a/templates/tests/test-casual-MODULE.el 
b/templates/tests/test-casual-MODULE.el
index fa47476676..7a74f2aa18 100644
--- a/templates/tests/test-casual-MODULE.el
+++ b/templates/tests/test-casual-MODULE.el
@@ -1,6 +1,6 @@
 ;;; test-casual-$MODULE.el --- Casual Make Tests -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2025  Charles Y. Choi
+;; Copyright (C) 2026 Charles Y. Choi
 
 ;; Author: Charles Choi <[email protected]>
 ;; Keywords: tools
diff --git a/tests/Makefile b/tests/Makefile
index f6c53f514d..4db64c8be5 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -31,6 +31,7 @@ ediff-tests                                   \
 editkit-tests                                  \
 elisp-tests                                    \
 eshell-tests                                   \
+eww-tests                                      \
 help-tests                                     \
 html-tests                                     \
 ibuffer-tests                                  \
@@ -57,6 +58,7 @@ ediff-tests                                   \
 editkit-tests                                  \
 elisp-tests                                    \
 eshell-tests                                   \
+eww-tests                                      \
 help-tests                                     \
 html-tests                                     \
 ibuffer-tests                                  \
@@ -109,6 +111,9 @@ elisp-tests:
 eshell-tests:
        $(MAKE) -C $(SRC_DIR) $@
 
+eww-tests:
+       $(MAKE) -C $(SRC_DIR) $@
+
 help-tests:
        $(MAKE) -C $(SRC_DIR) $@
 
diff --git a/templates/tests/casual-MODULE-test-utils.el 
b/tests/casual-eww-test-utils.el
similarity index 70%
copy from templates/tests/casual-MODULE-test-utils.el
copy to tests/casual-eww-test-utils.el
index 7d9c847e21..b8ee8cb649 100644
--- a/templates/tests/casual-MODULE-test-utils.el
+++ b/tests/casual-eww-test-utils.el
@@ -1,6 +1,6 @@
-;;; casual-$MODULE-test-utils.el --- Casual Test Utils       -*- 
lexical-binding: t; -*-
+;;; casual-eww-test-utils.el --- Casual Test Utils       -*- lexical-binding: 
t; -*-
 
-;; Copyright (C) 2025  Charles Y. Choi
+;; Copyright (C) 2026  Charles Y. Choi
 
 ;; Author: Charles Choi <[email protected]>
 ;; Keywords: tools
@@ -27,13 +27,13 @@
 (require 'casual-lib)
 (require 'kmacro)
 
-(defun casualt-$MODULE-setup ()
-  "Casual $MODULE setup."
+(defun casualt-eww-setup ()
+  "Casual eww setup."
   )
 
-(defun casualt-$MODULE-breakdown ()
-  "Casual $MODULE breakdown."
+(defun casualt-eww-breakdown ()
+  "Casual eww breakdown."
   )
 
-(provide 'casual-$MODULE-test-utils)
-;;; casual-$MODULE-test-utils.el ends here
+(provide 'casual-eww-test-utils)
+;;; casual-eww-test-utils.el ends here
diff --git a/tests/test-casual-eww-settings.el 
b/tests/test-casual-eww-settings.el
new file mode 100644
index 0000000000..b6b2d2d3ec
--- /dev/null
+++ b/tests/test-casual-eww-settings.el
@@ -0,0 +1,66 @@
+;;; test-casual-eww-settings.el --- Casual Make Settings Tests  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2026  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-eww-test-utils)
+(require 'casual-eww-settings)
+
+(ert-deftest test-casual-eww-settings-tmenu ()
+  (let ()
+    (cl-letf ((casualt-mock #'casual-eww--customize-retrieve-command)
+              (casualt-mock #'casual-eww--customize-readable-urls)
+              (casualt-mock #'casual-eww--customize-history-limit)
+              (casualt-mock #'casual-eww--customize-download-directory)
+              (casualt-mock #'casual-eww--customize-bookmarks-directory)
+              (casualt-mock #'casual-eww--customize-shr-use-fonts)
+              (casualt-mock #'casual-eww--customize-shr-use-colors)
+              (casualt-mock #'casual-eww--customize-shr-inhibit-images)
+              (casualt-mock #'casual-eww--customize-group)
+              (casualt-mock #'casual-eww-about))
+
+      (let ((test-vectors
+             '((:binding "r" :command casual-eww--customize-retrieve-command)
+               (:binding "R" :command casual-eww--customize-readable-urls)
+               (:binding "h" :command casual-eww--customize-history-limit)
+               (:binding "d" :command casual-eww--customize-download-directory)
+               (:binding "b" :command 
casual-eww--customize-bookmarks-directory)
+               (:binding "f" :command casual-eww--customize-shr-use-fonts)
+               (:binding "c" :command casual-eww--customize-shr-use-colors)
+               (:binding "i" :command casual-eww--customize-shr-inhibit-images)
+               (:binding "G" :command casual-eww--customize-group)
+               (:binding "u" :command 
casual-lib-customize-casual-lib-use-unicode)
+               (:binding "n" :command 
casual-lib-customize-casual-lib-hide-navigation)
+               (:binding "a" :command casual-eww-about))))
+
+        (casualt-suffix-testcase-runner test-vectors
+                                        #'casual-eww-settings-tmenu
+                                        '(lambda () (random 5000)))))))
+
+(ert-deftest test-casual-eww-about ()
+  (should (stringp (casual-eww-about))))
+
+(provide 'test-casual-eww-settings)
+;;; test-casual-eww-setttings.el ends here
diff --git a/tests/test-casual-eww-utils.el b/tests/test-casual-eww-utils.el
new file mode 100644
index 0000000000..bcc82be22a
--- /dev/null
+++ b/tests/test-casual-eww-utils.el
@@ -0,0 +1,97 @@
+;;; test-casual-eww-utils.el --- Casual Make Utils Tests  -*- lexical-binding: 
t; -*-
+
+;; Copyright (C) 2026  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-eww-test-utils)
+(require 'casual-eww-utils)
+
+(ert-deftest test-casual-eww-unicode-get ()
+  (let ((casual-lib-use-unicode nil))
+    (should (string-equal (casual-eww-unicode-get :history-back) "Back"))
+    (should (string-equal (casual-eww-unicode-get :history-forward) "Forward"))
+    (should (string-equal (casual-eww-unicode-get :previous) "Previous"))
+    (should (string-equal (casual-eww-unicode-get :next) "Next"))
+    (should (string-equal (casual-eww-unicode-get :forward-paragraph) "Next 
¶"))
+    (should (string-equal (casual-eww-unicode-get :backward-paragraph) 
"Previous ¶"))
+    (should (string-equal (casual-eww-unicode-get :forward) "Forward"))
+    (should (string-equal (casual-eww-unicode-get :back) "Back"))
+    (should (string-equal (casual-eww-unicode-get :link) "Link"))
+    (should (string-equal (casual-eww-unicode-get :top) "Top"))
+    (should (string-equal (casual-eww-unicode-get :history) "History"))
+    (should (string-equal (casual-eww-unicode-get :page) "Page"))
+    (should (string-equal (casual-eww-unicode-get :scroll-up) "Scroll Up"))
+    (should (string-equal (casual-eww-unicode-get :scroll-down) "Scroll Down"))
+    (should (string-equal (casual-eww-unicode-get :follow) "Follow"))
+    (should (string-equal (casual-eww-unicode-get :paragraph) "Paragraph"))
+    (should (string-equal (casual-eww-unicode-get :beginning-of-buffer) 
"Beginning"))
+    (should (string-equal (casual-eww-unicode-get :end-of-buffer) "End"))
+    (should (string-equal (casual-eww-unicode-get :reload) "Reload"))
+    (should (string-equal (casual-eww-unicode-get :kill) "Close"))
+    (should (string-equal (casual-eww-unicode-get :see-also) "See Also")))
+
+  (let ((casual-lib-use-unicode t))
+    (should (string-equal (casual-eww-unicode-get :history-back) "❬"))
+    (should (string-equal (casual-eww-unicode-get :history-forward) "❭"))
+    (should (string-equal (casual-eww-unicode-get :previous) "↑"))
+    (should (string-equal (casual-eww-unicode-get :next) "↓"))
+    (should (string-equal (casual-eww-unicode-get :forward-paragraph) "¶↓"))
+    (should (string-equal (casual-eww-unicode-get :backward-paragraph) "¶↑"))
+    (should (string-equal (casual-eww-unicode-get :forward) "→"))
+    (should (string-equal (casual-eww-unicode-get :back) "←"))
+    (should (string-equal (casual-eww-unicode-get :link) "🔗"))
+    (should (string-equal (casual-eww-unicode-get :top) "⤒"))
+    (should (string-equal (casual-eww-unicode-get :history) "≣"))
+    (should (string-equal (casual-eww-unicode-get :page) "📄"))
+    (should (string-equal (casual-eww-unicode-get :scroll-up) "📄↓"))
+    (should (string-equal (casual-eww-unicode-get :scroll-down) "📄↑"))
+    (should (string-equal (casual-eww-unicode-get :follow) "🚀"))
+    (should (string-equal (casual-eww-unicode-get :paragraph) "¶"))
+    (should (string-equal (casual-eww-unicode-get :beginning-of-buffer) "⇱"))
+    (should (string-equal (casual-eww-unicode-get :end-of-buffer) "⇲"))
+    (should (string-equal (casual-eww-unicode-get :reload) "⟳"))
+    (should (string-equal (casual-eww-unicode-get :kill) "×"))
+    (should (string-equal (casual-eww-unicode-get :see-also) "👀"))))
+
+(ert-deftest test-casual-eww-display-tmenu ()
+  (let ((tmpfile "casual-eww-display-tmenu.txt"))
+    (casualt-eww-setup)
+    (cl-letf ((casualt-mock #'eww-toggle-fonts)
+              (casualt-mock #'eww-toggle-colors)
+              (casualt-mock #'eww-toggle-images)
+              (casualt-mock #'eww-toggle-paragraph-direction))
+
+      (let ((test-vectors
+             '((:binding "f" :command eww-toggle-fonts)
+               (:binding "c" :command eww-toggle-colors)
+               (:binding "i" :command eww-toggle-images)
+               (:binding "d" :command eww-toggle-paragraph-direction))))
+
+        (casualt-suffix-testcase-runner test-vectors
+                                        #'casual-eww-display-tmenu
+                                        '(lambda () (random 5000)))))
+    (casualt-eww-breakdown)))
+
+(provide 'test-casual-eww-utils)
+;;; test-casual-eww-utils.el ends here
diff --git a/tests/test-casual-eww.el b/tests/test-casual-eww.el
new file mode 100644
index 0000000000..20c856bd7b
--- /dev/null
+++ b/tests/test-casual-eww.el
@@ -0,0 +1,126 @@
+;;; test-casual-eww.el --- Casual Make Tests -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2026  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-eww-test-utils)
+(require 'casual-lib-test-utils)
+(require 'casual-eww)
+
+(ert-deftest test-casual-eww-tmenu ()
+  (let ()
+    (casualt-eww-setup)
+
+    (cl-letf (
+              (casualt-mock #'eww-back-url)
+              (casualt-mock #'eww-forward-url)
+              (casualt-mock #'eww-list-histories)
+              (casualt-mock #'eww-previous-url)
+              (casualt-mock #'eww-next-url)
+              (casualt-mock #'eww-up-url)
+              (casualt-mock #'eww-top-url)
+              (casualt-mock #'casual-lib-browse-backward-paragraph)
+              (casualt-mock #'casual-lib-browse-forward-paragraph)
+              (casualt-mock #'scroll-up-command)
+              (casualt-mock #'scroll-down-command)
+              (casualt-mock #'shr-previous-link)
+              (casualt-mock #'shr-next-link)
+              (casualt-mock #'eww-follow-link)
+              (casualt-mock #'casual-eww-display-tmenu)
+              (casualt-mock #'eww-readable)
+              (casualt-mock #'eww)
+              (casualt-mock #'eww-browse-with-external-browser)
+              (casualt-mock #'eww-copy-page-url)
+              (casualt-mock #'eww-copy-alternate-url)
+              (casualt-mock #'eww-download)
+              (casualt-mock #'eww-reload)
+              (casualt-mock #'eww-add-bookmark)
+              (casualt-mock #'eww-list-bookmarks)
+              (casualt-mock #'eww-next-bookmark)
+              (casualt-mock #'eww-previous-bookmark)
+              (casualt-mock #'casual-eww-settings-tmenu)
+              (casualt-mock #'casual-eww-info)
+              (casualt-mock #'quit-window))
+
+      (let ((test-vectors
+             '((:binding "M-[" :command eww-back-url)
+               (:binding "M-]" :command eww-forward-url)
+               (:binding "H" :command eww-list-histories)
+               (:binding "[" :command eww-previous-url)
+               (:binding "]" :command eww-next-url)
+               (:binding "^" :command eww-up-url)
+               (:binding "t" :command eww-top-url)
+               (:binding "p" :command casual-lib-browse-backward-paragraph)
+               (:binding "n" :command casual-lib-browse-forward-paragraph)
+               (:binding "SPC" :command scroll-up-command)
+               (:binding "S-SPC" :command scroll-down-command)
+               (:binding "k" :command shr-previous-link)
+               (:binding "j" :command shr-next-link)
+               (:binding "RET" :command eww-follow-link)
+               (:binding "D" :command casual-eww-display-tmenu)
+               (:binding "R" :command eww-readable)
+               (:binding "M-l" :command eww)
+               (:binding "&" :command eww-browse-with-external-browser)
+               (:binding "c" :command eww-copy-page-url)
+               (:binding "A" :command eww-copy-alternate-url)
+               (:binding "d" :command eww-download)
+               (:binding "g" :command eww-reload)
+               (:binding "b" :command eww-add-bookmark)
+               (:binding "B" :command eww-list-bookmarks)
+               (:binding "M-n" :command eww-next-bookmark)
+               (:binding "M-p" :command eww-previous-bookmark)
+               (:binding "," :command casual-eww-settings-tmenu)
+               (:binding "I" :command casual-eww-info)
+               (:binding "q" :command quit-window))))
+
+        (casualt-suffix-testcase-runner test-vectors
+                                        #'casual-eww-tmenu
+                                        '(lambda () (random 5000)))))
+    (casualt-eww-breakdown)))
+
+
+(ert-deftest test-casual-eww-bookmarks-tmenu ()
+  (let ((tmpfile "casual-eww-bookmarks-tmenu.txt"))
+    (casualt-eww-setup)
+    (cl-letf ((casualt-mock #'eww-bookmark-kill)
+              (casualt-mock #'eww-bookmark-yank)
+              (casualt-mock #'eww-bookmark-browse)
+              (casualt-mock #'previous-line)
+              (casualt-mock #'next-line))
+
+      (let ((test-vectors
+             '((:binding "k" :command eww-bookmark-kill)
+               (:binding "y" :command eww-bookmark-yank)
+               (:binding "RET" :command eww-bookmark-browse)
+               (:binding "p" :command previous-line)
+               (:binding "n" :command next-line))))
+
+        (casualt-suffix-testcase-runner test-vectors
+                                        #'casual-eww-bookmarks-tmenu
+                                        '(lambda () (random 5000)))))
+    (casualt-eww-breakdown)))
+
+(provide 'test-casual-eww)
+;;; test-casual-eww.el ends here


Reply via email to