How to get readable mode in emacs w3m?
Table of Contents
I’ve made the switch to w3m from eww, which has been great overall since the eww thread-blocking was insufferable. However, one of the biggest benefits of eww was the ability to engage a readability mode that cut all but the content of the page, which is also a feature I use a lot on Firefox on my phone. A previous answer from 20201 did something like this but was referencing elfeed, which has nothing to do with my use case, and used a bootstrap Python script. With CURL and an external library, I got it working for emacs-w3m.
The question is how to succinctly get eww-like Reader-mode into emacs-w3m. The answer follows2.
1. Obtain the CLI API
Obtain the CLI API to the actual readability.js3 that Mozilla has created, and verify you can use it from the CLI like this:
curl https://cnn.com | readability https://cnn.com
If all is working and you’ve installed correctly, you should see some HTML written to stdout.
2. Implement the readable call-function
This is the function that actually invokes the APi we’ve installed and collects its results. Note the 2>/dev/null
following the curl command; this is because curl itself sends output to stdio reporting how much it downloaded and how fast; we don’t want this showing up in our webpage, so we silence it.
(defun tsa/readability (url)
"Get the Readable.JS version of URL"
(interactive "P")
(message "readabilizing...")
(erase-buffer)
(insert (shell-command-to-string (concat "curl " url " 2>/dev/null | readability " url))))
Then we load that to the front of our filter list, which contains all the default filters used by w3m:
(add-to-list 'w3m-filter-configuration '(t "Make page readable" ".*" tsa/readability))
3. add w3m-filter and a wrapper-function to toggle readability
Emacs-w3m has filters that tweak the layout of certain pages. In my case I don’t want any tweaking unless I want all tweaking, so basically I’m replacing the more nuanced filtering mechanism with a single master-filter which will run on any page I wish with a keystroke, replacing the entire text with the readable results. Generally I frown upon any “fix” which is tantamount to a loss of functionality, but with this hack I want readability and really don’t use any site-specific tweaks other than that. As such, we have two steps remaining: create a w3m filter which applies readability, and then a wrapper function which toggles the use of w3m filters. The readable key I’m familar with from eww is R
so I bind our toggle function it to that key (binding not shown).
(defun tsa/w3m-toggle-readability (&arg)
"Toggle readibility and reload the current page"
(interactive "P")
(w3m-toggle-filtering nil) ;; switch filtering on...
(w3m-reload-this-page) ;; reload readably
(w3m-toggle-filtering nil) ;; and switch filtering back off again
)
Altogether final product
Don’t forget to install Readable-cli. Then, putting the elisp all together, I have this use-package line for w3m that includes it all:
(use-package w3m
:demand t
:straight (emacs-w3m :type git :host github :repo "emacs-w3m/emacs-w3m")
:bind (:map w3m-mode-map
("R" . tsa/w3m-toggle-readability)
("M-o" . ace-link-w3m))
:custom
(w3m-search-default-engine "duckduckgo")
(w3m-quick-start nil)
(w3m-display-mode 'plain)
(w3m-use-title-buffer-name t)
:config
(defun tsa/readability (url)
"Get the Readable.JS version of URL"
(interactive "P")
(message "readabilizing...")
(erase-buffer)
(insert (shell-command-to-string (concat "curl " url " 2>/dev/null | readability " url))))
(defun tsa/w3m-toggle-readability (&arg)
"Toggle readibility and reload the current page"
(interactive "P")
(w3m-toggle-filtering nil)
(w3m-reload-this-page)
(w3m-toggle-filtering nil))
(add-to-list 'w3m-filter-configuration '(t "Make page readable" ".*" tsa/readability)))
Footnotes
1 The old Reddit thread and uses Python and elfeed in its solution: https://www.reddit.com/r/emacs/comments/gc4v8f/ewwreadable_like_mode_for_w3m/?utm_medium=android_app&utm_source=share
2 admittedly, this isn’t a very good answer; it’s a hack that utilizes requires two external dependencies and has no error support, and trumps any other use you are making of w3m filters. But hey, it’s small enough to fit in my config file and gets me reader mode, so it works for me.