+(defun eww-readable ()
+ "View the main \"readable\" parts of the current web page.
+This command uses heuristics to find the parts of the web page that
+contains the main textual portion, leaving out navigation menus and
+the like."
+ (interactive)
+ (let* ((old-data eww-data)
+ (dom (shr-transform-dom
+ (with-temp-buffer
+ (insert (plist-get old-data :source))
+ (condition-case nil
+ (decode-coding-region (point-min) (point-max) 'utf-8)
+ (coding-system-error nil))
+ (libxml-parse-html-region (point-min) (point-max))))))
+ (eww-score-readability dom)
+ (eww-save-history)
+ (eww-display-html nil nil
+ (shr-retransform-dom
+ (eww-highest-readability dom))
+ nil (current-buffer))
+ (dolist (elem '(:source :url :title :next :previous :up))
+ (plist-put eww-data elem (plist-get old-data elem)))
+ (eww-update-header-line-format)))
+
+(defun eww-score-readability (node)
+ (let ((score -1))
+ (cond
+ ((memq (car node) '(script head comment))
+ (setq score -2))
+ ((eq (car node) 'meta)
+ (setq score -1))
+ ((eq (car node) 'img)
+ (setq score 2))
+ ((eq (car node) 'a)
+ (setq score (- (length (split-string
+ (or (cdr (assoc 'text (cdr node))) ""))))))
+ (t
+ (dolist (elem (cdr node))
+ (cond
+ ((and (stringp (cdr elem))
+ (eq (car elem) 'text))
+ (setq score (+ score (length (split-string (cdr elem))))))
+ ((consp (cdr elem))
+ (setq score (+ score
+ (or (cdr (assoc :eww-readability-score (cdr elem)))
+ (eww-score-readability elem)))))))))
+ ;; Cache the score of the node to avoid recomputing all the time.
+ (setcdr node (cons (cons :eww-readability-score score) (cdr node)))
+ score))
+
+(defun eww-highest-readability (node)
+ (let ((result node)
+ highest)
+ (dolist (elem (cdr node))
+ (when (and (consp (cdr elem))
+ (> (or (cdr (assoc
+ :eww-readability-score
+ (setq highest
+ (eww-highest-readability elem))))
+ most-negative-fixnum)
+ (or (cdr (assoc :eww-readability-score (cdr result)))
+ most-negative-fixnum)))
+ (setq result highest)))
+ result))
+