From 8cef1852bfe4dbdf53b063faeacdb1e6a85d15c2 Mon Sep 17 00:00:00 2001 From: Jim Porter Date: Sun, 4 Aug 2024 19:37:00 -0700 Subject: [PATCH] Improve SHR/EWW support for 'visual-wrap-prefix-mode' * lisp/visual-wrap.el (visual-wrap--apply-to-line): Use 'add-display-text-property' so we don't clobber other display properties. (visual-wrap--content-prefix): Remove special-case for spaces-only indent prefix; this was an attempt to be helpful for variable-pitch fonts, but in practice just interferes with matters. This case now falls back to the one immediately following it (return the string of spaces). Use 'string-pixel-width' instead of 'string-width'. * lisp/net/shr.el (shr-indent): Set 'shr-prefix-length' here to help keep track of the prefixes of nestedly-indented elements. Set the specified space width in terms of the default width of the current face. * lisp/net/shr.el (shr-adaptive-fill-function): Use 'shr-prefix-length' as set above to return a fill prefix. * lisp/net/eww.el (eww-render): Enable 'visual-wrap-prefix-mode' alongside of 'visual-line-mode'. (eww-mode): Set 'adaptive-fill-function' to 'shr-adaptive-fill-function'. * etc/NEWS: Announce this change (bug#72485). --- etc/NEWS | 8 ++++++++ lisp/net/eww.el | 5 ++++- lisp/net/shr.el | 28 +++++++++++++++++++++++----- lisp/visual-wrap.el | 18 ++++++++---------- 4 files changed, 43 insertions(+), 16 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 8cd21f5fb74..5063e754730 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -144,6 +144,14 @@ Advanced" node in the EWW manual. By customizing 'shr-image-zoom-levels', you can change the list of zoom levels that SHR cycles through when calling 'shr-zoom-image'. +** EWW + +--- +*** EWW now enables 'visual-wrap-prefix-mode' when 'shr-fill-text' is nil. +This improves the display of multiline, indented text, such as block +quotes or (un)ordered lists. Now, the wrapped lines of indented text +will line up visually with the first line. + ** Go-ts mode +++ diff --git a/lisp/net/eww.el b/lisp/net/eww.el index b2e1c5a72e5..b5d2f20781a 100644 --- a/lisp/net/eww.el +++ b/lisp/net/eww.el @@ -709,7 +709,8 @@ eww-render (and last-coding-system-used (set-buffer-file-coding-system last-coding-system-used)) (unless shr-fill-text - (visual-line-mode)) + (visual-line-mode) + (visual-wrap-prefix-mode)) (run-hooks 'eww-after-render-hook) ;; Enable undo again so that undo works in text input ;; boxes. @@ -1336,6 +1337,8 @@ eww-mode ;; desktop support (setq-local desktop-save-buffer #'eww-desktop-misc-data) (setq truncate-lines t) + ;; visual-wrap-prefix-mode support + (setq-local adaptive-fill-function #'shr-adaptive-fill-function) ;; thingatpt support (setq-local thing-at-point-provider-alist (cons '(url . eww--url-at-point) diff --git a/lisp/net/shr.el b/lisp/net/shr.el index d3c48b34428..b9ac9f0c8c0 100644 --- a/lisp/net/shr.el +++ b/lisp/net/shr.el @@ -938,6 +938,11 @@ shr-fill-line (when (looking-at " $") (delete-region (point) (line-end-position))))))) +(defun shr-adaptive-fill-function () + "Return a fill prefix for the paragraph at point." + (when-let ((prefix (get-text-property (point) 'shr-prefix-length))) + (buffer-substring (point) (+ (point) prefix)))) + (defun shr-parse-base (url) ;; Always chop off anchors. (when (string-match "#.*" url) @@ -1041,11 +1046,24 @@ shr-ensure-paragraph (defun shr-indent () (when (> shr-indentation 0) - (if (not shr-use-fonts) - (insert-char ?\s shr-indentation) - (insert ?\s) - (put-text-property (1- (point)) (point) - 'display `(space :width (,shr-indentation)))))) + (let ((start (point)) + (prefix (or (get-text-property (point) 'shr-prefix-length) 0))) + (if (not shr-use-fonts) + (insert-char ?\s shr-indentation) + (insert ?\s) + (put-text-property + (1- (point)) (point) 'display + ;; Set the specified space width in terms of the default width + ;; of the current face, like (N . width). That way, the + ;; indentation is calculated correctly when using + ;; `text-scale-adjust'. + `(space :width (,(if-let ((font (font-at (1- (point)))) + (info (query-font font))) + (/ (float shr-indentation) (aref info 7)) + shr-indentation) + . width)))) + (put-text-property start (+ (point) prefix) + 'shr-prefix-length (+ prefix (- (point) start)))))) (defun shr-fontize-dom (dom &rest types) (let ((start (point))) diff --git a/lisp/visual-wrap.el b/lisp/visual-wrap.el index cac3bc767b8..56d58ef1d60 100644 --- a/lisp/visual-wrap.el +++ b/lisp/visual-wrap.el @@ -121,9 +121,9 @@ visual-wrap--apply-to-line (next-line-prefix (visual-wrap--content-prefix first-line-prefix position))) (when (numberp next-line-prefix) - (put-text-property - position (+ position (length first-line-prefix)) 'display - `(min-width ((,next-line-prefix . width))))) + (add-display-text-property + position (+ position (length first-line-prefix)) 'min-width + `((,next-line-prefix . width)))) (setq next-line-prefix (visual-wrap--adjust-prefix next-line-prefix)) (put-text-property position (line-end-position) 'wrap-prefix @@ -141,12 +141,6 @@ visual-wrap--content-prefix (cond ((string= prefix "") nil) - ((string-match (rx bos (+ blank) eos) prefix) - ;; If the first-line prefix is all spaces, return its width in - ;; characters. This way, we can set the prefix for all lines to use - ;; the canonical-width of the font, which helps for variable-pitch - ;; fonts where space characters are usually quite narrow. - (string-width prefix)) ((or (and adaptive-fill-first-line-regexp (string-match adaptive-fill-first-line-regexp prefix)) (and comment-start-skip @@ -169,7 +163,11 @@ visual-wrap--content-prefix (max (string-width prefix) (ceiling (string-pixel-width prefix (current-buffer)) (aref info 7))) - (string-width prefix))))) + ;; We couldn't get the font, so we're in a terminal and + ;; `string-pixel-width' is really returning the number of columns. + ;; (This is different from `string-width', since that doesn't + ;; respect specified spaces.) + (string-pixel-width prefix))))) (defun visual-wrap-fill-context-prefix (beg end) "Compute visual wrap prefix from text between BEG and END. -- 2.25.1