Began using Emacs eww nowadays, but now seeking to adapt it better for Html websites.

That way some user said to "buffer-locally setting the variable shr-external-rendering-functions", as of What EWW Emacs Web Brower Would Be Used For

But don't know how to do it.

Any idea?

  • Improving eww is a high aim which requires some experience in Elisp. I said in the comment to your other question that you can adapt eww to HTML-like formats with additional tags. That story is a bit different.
    – Tobias
    Mar 27 '20 at 9:04
  • Just adjusted it, @Tobias.
    – Vincent33
    Mar 27 '20 at 9:07
  • If nobody other jumps in I'll answer this weekend.
    – Tobias
    Mar 27 '20 at 9:12
  • What do you mean by "better"? Consider that Emacs has inherent limitations regarding what you can and cannot render. shr-external-rendering-functions is nice for things like adding support for unknown tags or adjusting how an existing tag is rendered (for example making all header tags display as large fonts). What you don't get is the level of control as seen from CSS.
    – wasamasa
    Mar 27 '20 at 10:36
  • 1
    I wrote github.com/xuchunyang/shr-tag-pre-highlight.el, it's sole purpose is add syntax highlight to <pre>, it's done by adding an item to shr-external-rendering-functions, so we can control how shr/eww render <pre>. HTML-only or with little inline-CSS webpage should look fine in EWW, don't forget shr/eww can't really understand CSS and JavaScript.
    – xuchunyang
    Mar 27 '20 at 11:34

If you want to generally change/add the rendering of nodes of a certain tag type you just add an association from the tag as symbol to the rendering function in the list shr-external-rendering-functions.

Example: Render <em> nodes using a self defined function my-tag-em:

(add-to-list 'shr-external-rendering-functions '(em . my-tag-em))

I have tested the code with Emacs 26.3. The rendering function recieves the node as parsed by libxml-parse-html-region and should insert the rendered representation of the node at point of the current buffer (which is the eww-mode buffer).

The structure of the nodes is described in on the page about the Document Object Model (DOM) in the info manual for Elisp M-: (info "(Elisp)Document Object Model") RET.

Each node is a list. The elements are:

  • 0th: tag name as a symbol
  • 1st: association list of attributes, each attribute is represented as a cons:
    • car: attribute name as a symbol
    • cdr: value as a string
  • rest: contents of the tag as children of the node

Example: M-: (libxml-parse-html-region (point-min) (point-max)) RET for the following html buffer returns the subsequent DOM.

<!DOCTYPE html>
  <body style=none>
    Test of <em>emphasis</em>.

The corresponding DOM:

(html nil (head nil (title nil "Test")) (body ((style . "none")) "
    Test of " (em nil "emphasis") ".

Next we define our rendering function my-tag-em such that it frames the contents of the <em> tag by Org-style * characters. One can use shr-generic to render the contents (i.e., the children) of the tag.

(defun my-tag-em (dom)
  "Render <em>-tag DOM as *CONTENT*."
  (insert "*")
  (shr-generic dom)
  ;; point is now behind the contents
  (insert "*"))

Finally, we have a look at shr-tag-em which is normally used by shr for rendering the <em> tag. The used function shr-fontize-dom is listed with additional comments.

(defun shr-tag-em (dom)
  (shr-fontize-dom dom 'italic))

(defun shr-fontize-dom (dom &rest types)
  (let ((start (point))) ;; remember start of inserted region
    (shr-generic dom) ;; inserts the contents of the tag
    (dolist (type types)
      (shr-add-font start (point) type)) ;; puts text properties of TYPES on the inserted contents

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.