7

If I load a local file, I'd like eww to refresh when the source is changed. This would be similar to auto-revert mode. Is there any way to do this? Right now I have to manually refresh by hitting g in the *eww* buffer.

  • If you're comfortable with elisp, then [How can I make ibuffer auto-refresh the list of buffers?](http://emacs.stackexchange.com/a/2179/454) has some useful details on implementing custom support for `auto-revert-mode`, which may point you in the right direction. – phils Oct 22 '14 at 06:36
  • 1
    You should probably fill a bug report requesting `eww` to respect `auto-revert-mode` for local files (also `file-buffer-name` for that matter). If you don't want to that you can try to combine `(info "(elisp) File Notifications")` and `eww-current-url`. You might have to map through all `*eww*` buffers when something changes to find the right one. – rasmus Oct 24 '14 at 14:35

2 Answers2

4

Solution

  • Start a file-notify watch when opening a file in eww.
  • In the callback function for that watch, do 2 things:
    • Reload the *eww* buffer every time the function is triggered by file-notify event.
    • Log the event descriptors specific to file opening actions in eww. This is because you need to know which file-notify watches to remove when you quit eww (especially if you use the watches for other purposes than this too).
  • On quitting eww remove all the watches related to eww. You have to make sure that you call this specific function to quit eww and clean up the now-not-required watches.

How to use

  • Copy the below implementation to your init.el.
  • Launch any file you want to load in eww using C-u M-x eww-open-file.
  • Make sure you quit eww by calling modi/eww-quit-and-update-fn-descriptors. For convenience, the default binding q in eww-mode-map is now bound to this function. If you use any other binding to quit eww or to kill windows, make sure you call this function. modi/eww-quit-and-update-fn-descriptors ensures that the eww-specific file-notify watches are removed.

Implementation

(defvar modi/eww--file-notify-descriptors-list ()
  "List to store file-notify descriptor for all files that have an
associated auto-reloading eww buffer.")

(defun modi/advice-eww-open-file-to-auto-reload (orig-fun &rest args)
  "When `eww-open-file' is called with \\[universal-argument], open
the file in eww and also add `file-notify' watch for it so that the eww
buffer auto-reloads when the HTML file changes."
  (prog1
      (apply orig-fun args)
    (when current-prefix-arg ; C-u M-x eww-open-file
      (require 'filenotify)
      (let ((file-name (car args)))
        (file-notify-add-watch file-name
                               '(change attribute-change)
                               #'modi/file-notify-callback-eww-reload)
        ;; Show the HTML file and its rendered form in eww side-by-side
        (find-file-other-window file-name))
      ;; Redefine the `q' binding in `eww-mode-map'
      (bind-key "q" #'modi/eww-quit-and-update-fn-descriptors eww-mode-map))))
(advice-add 'eww-open-file :around #'modi/advice-eww-open-file-to-auto-reload)

(defun modi/file-notify-callback-eww-reload (event)
  "On getting triggered, switch to the eww buffer, reload and switch
back to the working buffer. Also save the `file-notify-descriptor' of the
triggering event."
  (let* ((working-buffer (buffer-name)))
    (switch-to-buffer-other-window "eww")
    (eww-reload)
    (switch-to-buffer-other-window working-buffer))
  ;; `(car event)' will return the event descriptor
  (add-to-list 'modi/eww--file-notify-descriptors-list (car event)))

(defun modi/eww-quit-and-update-fn-descriptors ()
  "When quitting `eww', first remove any saved file-notify descriptors
specific to eww, while also updating `modi/eww--file-notify-descriptors-list'."
  (interactive)
  (dotimes (index (safe-length modi/eww--file-notify-descriptors-list))
    (file-notify-rm-watch (pop modi/eww--file-notify-descriptors-list)))
  (quit-window :kill))

Assumptions

  • You have only one *eww* buffer open.
  • This solution requires emacs 24.4 or newer.
Kaushal Modi
  • 25,203
  • 3
  • 74
  • 179
  • Awesome. Unfortunately file notification doesn't work yet on OS X. I'll give this a shot on my other machine which runs Linux. – Jack Moffitt Oct 29 '14 at 02:33
2

I fixed the same issue with a noob solution so here it is:

I basically added a hook that calls eww-reload on the "other frame" -that supposedly has the web page open- once the markdown gets saved.

This works fine for me as I usually have my window split into two frames only when I'm writing in markdown, one for md and the other for preview -using either doc-view or eww-

So here is the snippet I added to my init.el, please read carefully and edit according to your situation:

(defun compile-md ()
  "Run available makefile that should compile markdown to whatever."
  (interactive)
  (when (derived-mode-p 'markdown-mode)
    (shell-command "make")); that make file uses pandoc to compile md to html
  (windmove-right); supposing the eww frame is on the right 
  (when (derived-mode-p 'eww-mode)
    (eww-reload))
  (windmove-left); get back to the md buffer
 )

(add-hook 'after-save-hook #'compile-md)
Stefan
  • 26,154
  • 3
  • 46
  • 84
demon36
  • 121
  • 3
  • 2
    You can probably advantageously replace the `windmove-left` with `save-window-excursion` (or even better `save-current-buffer` if you can replace the `windmove-right` with a function which changes the current buffer rather than the selected window). – Stefan Oct 13 '19 at 14:02