Emacs bookmarks are pretty wonderful, you can bookmark almost anything: files, directories, info and help buffers, Magit buffers, elfeed searches and entries. And (naturally) you can extend Emacs to be able to bookmark almost anything you want. This note demonstrates how to extend Emacs to use the standard bookmark system with the EWW browser.
Let’s start by taking a closer look at what a bookmark looks like under the hood. When you type
M-x bookmark-set Emacs adds a ‘record’ to the
bookmark-alist. This list is then saved to a file (defined in the variable
bookmark-default-file) so you don’t loose your bookmarks when you quit Emacs. The individual bookmark records look like this:
("(emacs) Bookmarks" (front-context-string . "13.8 Bookmarks\n=") (rear-context-string . " Up: Registers\n\n") (position . 251555) (filename . "/Users/oht/Applications/Emacs.app/Contents/Resources/info/emacs") (info-node . "Bookmarks") (handler . Info-bookmark-jump))
Let’s break that down piece-by-piece.
(emacs) Bookmarksis the name of the bookmark, and what gets displayed in the bookmark list.
rear-context-stringhelp keep your bookmarks accurate when you edit a file after setting a bookmark. If you simply recorded the filename and line number subsequent edits to the file would quickly render your bookmarks inaccurate.
positionis the point’s position in the buffer.
filenameis pretty self explanatory, as is
info-node(which is specific to bookmarking the info manuals).
handlerdefines the function that
bookmark-jumpwill use to go to that bookmark.
Detailed information about how bookmark records can be found by describing the variable
With a little imagination, one can envision a bookmark record for a webpage that looks something like this:
("Name of Webpage" (location . "https://example.com") (handler . eww-handler-function))
Emacs refers to a function which creates these records as a "bookmark make record function". In this case that function might look like this:
(defun custom-make-record-function () `(,(name-bookmark-function) (location . ,(get-url-function)) (handler . eww-handler-function)))
Emacs uses different functions to create each kind of bookmark; one function for bookmarking files and another for bookmarking directories. Defining which function to use in which context is the job of the variable
bookmark-make-record-function. In our case we want to set that variable, when using EWW, to the name of our custom make record function. Then, when you type
M-x bookmark-set Emacs will call your make-record function and insert the record into the
Now that we understand how it works, we can enumerate all the pieces we’ll need.
bookmark-make-record-functionlocally when EWW buffers are created.
First, the make-record function. You can grab the url from EWW with the function
eww-current-url but EWW provides no such function for getting the page’s title. You can, however, grab the page title with a little lisp:
(plist-get eww-data :title). All together the complete make-record function looks like this:
(defun oht-eww-bookmark-make-record () "Make a bookmark record for the current eww buffer." `(,(plist-get eww-data :title) ((location . ,(eww-current-url)) (handler . oht-eww-bookmark-handler) (defaults . (,(plist-get eww-data :title))))))
(It’s not clear to me why the
defaults part of this is needed but without it EWW will not properly update the
:title when browsing pages. This fix was suggested by Joe Corneli.)
Second, the handler function for jumping to the URL:
(defun oht-eww-bookmark-handler (record) "Jump to a bookmark's url with bookmarked location." (eww (bookmark-prop-get record 'location)))
Third, we need to set the buffer-local variable
bookmark-make-record-function to the name of our custom make-record function when using EWW. We do this by first defining a function which sets the local variable, then adding a hook to
eww-mode which calls that function. Like this:
(defun oht-eww-set-bookmark-handler () "Assigns `bookmark-make-record-function' to a custom function." (set (make-local-variable 'bookmark-make-record-function) #'oht-eww-bookmark-make-record)) (add-hook 'eww-mode-hook 'oht-eww-set-bookmark-handler)
Now, when visiting a page in EWW you can type
M-x bookmark-set and a bookmark will be created, and jumping to that bookmark will open the URL in EWW.
While this example is specific to the EWW browser, it should give you an idea of how you can extend Emacs’s bookmarking system in other ways.