diff options
| author | Jim Porter | 2024-07-27 20:48:38 -0700 |
|---|---|---|
| committer | Jim Porter | 2024-08-04 10:46:28 -0700 |
| commit | f70a6ea0ea86ef461e40d20664a75a92d02679ea (patch) | |
| tree | 63b555139d21a08e2701acfd23b1cca9f0300025 /lisp/visual-wrap.el | |
| parent | 0756f3085ea948c945e309e2ce347fc5ab836574 (diff) | |
| download | emacs-f70a6ea0ea86ef461e40d20664a75a92d02679ea.tar.gz emacs-f70a6ea0ea86ef461e40d20664a75a92d02679ea.zip | |
Add support for variable-pitch fonts in 'visual-wrap-prefix-mode'
* lisp/emacs-lisp/subr-x.el (string-pixel-width): Allow passing BUFFER
to use the face remappings from that buffer when calculating the width.
* lisp/visual-wrap.el (visual-wrap--prefix): Rename to...
(visual-wrap--adjust-prefix): ... this, and support PREFIX as a number.
(visual-wrap-fill-context-prefix): Make obsolete in favor of...
(visual-wrap--content-prefix): ... this.
(visual-wrap-prefix-function): Extract inside of loop into...
(visual-wrap--apply-to-line): ... this.
* doc/lispref/display.texi (Size of Displayed Text): Update
documentation for 'string-pixel-width'.
* etc/NEWS: Announce this change.
Diffstat (limited to 'lisp/visual-wrap.el')
| -rw-r--r-- | lisp/visual-wrap.el | 113 |
1 files changed, 77 insertions, 36 deletions
diff --git a/lisp/visual-wrap.el b/lisp/visual-wrap.el index d95cf4bb569..cac3bc767b8 100644 --- a/lisp/visual-wrap.el +++ b/lisp/visual-wrap.el | |||
| @@ -97,24 +97,85 @@ extra indent = 2 | |||
| 97 | (if (visual-wrap--face-extend-p f) f)) | 97 | (if (visual-wrap--face-extend-p f) f)) |
| 98 | eol-face))))))) | 98 | eol-face))))))) |
| 99 | 99 | ||
| 100 | (defun visual-wrap--prefix (fcp) | 100 | (defun visual-wrap--adjust-prefix (prefix) |
| 101 | (let ((fcp-len (string-width fcp))) | 101 | "Adjust PREFIX with `visual-wrap-extra-indent'." |
| 102 | (cond | 102 | (if (numberp prefix) |
| 103 | ((= 0 visual-wrap-extra-indent) | 103 | (+ visual-wrap-extra-indent prefix) |
| 104 | fcp) | 104 | (let ((prefix-len (string-width prefix))) |
| 105 | ((< 0 visual-wrap-extra-indent) | 105 | (cond |
| 106 | (concat fcp (make-string visual-wrap-extra-indent ?\s))) | 106 | ((= 0 visual-wrap-extra-indent) |
| 107 | ((< 0 (+ visual-wrap-extra-indent fcp-len)) | 107 | prefix) |
| 108 | (substring fcp | 108 | ((< 0 visual-wrap-extra-indent) |
| 109 | 0 | 109 | (concat prefix (make-string visual-wrap-extra-indent ?\s))) |
| 110 | (+ visual-wrap-extra-indent fcp-len))) | 110 | ((< 0 (+ visual-wrap-extra-indent prefix-len)) |
| 111 | (t | 111 | (substring prefix |
| 112 | "")))) | 112 | 0 (+ visual-wrap-extra-indent prefix-len))) |
| 113 | (t | ||
| 114 | ""))))) | ||
| 115 | |||
| 116 | (defun visual-wrap--apply-to-line (position) | ||
| 117 | "Apply visual-wrapping properties to the logical line starting at POSITION." | ||
| 118 | (save-excursion | ||
| 119 | (goto-char position) | ||
| 120 | (when-let ((first-line-prefix (fill-match-adaptive-prefix)) | ||
| 121 | (next-line-prefix (visual-wrap--content-prefix | ||
| 122 | first-line-prefix position))) | ||
| 123 | (when (numberp next-line-prefix) | ||
| 124 | (put-text-property | ||
| 125 | position (+ position (length first-line-prefix)) 'display | ||
| 126 | `(min-width ((,next-line-prefix . width))))) | ||
| 127 | (setq next-line-prefix (visual-wrap--adjust-prefix next-line-prefix)) | ||
| 128 | (put-text-property | ||
| 129 | position (line-end-position) 'wrap-prefix | ||
| 130 | (if (numberp next-line-prefix) | ||
| 131 | `(space :align-to (,next-line-prefix . width)) | ||
| 132 | next-line-prefix))))) | ||
| 133 | |||
| 134 | (defun visual-wrap--content-prefix (prefix position) | ||
| 135 | "Get the next-line prefix for the specified first-line PREFIX. | ||
| 136 | POSITION is the position in the buffer where PREFIX is located. | ||
| 137 | |||
| 138 | This returns a string prefix to use for subsequent lines; an integer, | ||
| 139 | indicating the number of canonical-width spaces to use; or nil, if | ||
| 140 | PREFIX was empty." | ||
| 141 | (cond | ||
| 142 | ((string= prefix "") | ||
| 143 | nil) | ||
| 144 | ((string-match (rx bos (+ blank) eos) prefix) | ||
| 145 | ;; If the first-line prefix is all spaces, return its width in | ||
| 146 | ;; characters. This way, we can set the prefix for all lines to use | ||
| 147 | ;; the canonical-width of the font, which helps for variable-pitch | ||
| 148 | ;; fonts where space characters are usually quite narrow. | ||
| 149 | (string-width prefix)) | ||
| 150 | ((or (and adaptive-fill-first-line-regexp | ||
| 151 | (string-match adaptive-fill-first-line-regexp prefix)) | ||
| 152 | (and comment-start-skip | ||
| 153 | (string-match comment-start-skip prefix))) | ||
| 154 | ;; If we want to repeat the first-line prefix on subsequent lines, | ||
| 155 | ;; return its string value. However, we remove any `wrap-prefix' | ||
| 156 | ;; property that might have been added earlier. Otherwise, we end | ||
| 157 | ;; up with a string containing a `wrap-prefix' string containing a | ||
| 158 | ;; `wrap-prefix' string... | ||
| 159 | (remove-text-properties 0 (length prefix) '(wrap-prefix) prefix) | ||
| 160 | prefix) | ||
| 161 | (t | ||
| 162 | ;; Otherwise, we want the prefix to be whitespace of the same width | ||
| 163 | ;; as the first-line prefix. If possible, compute the real pixel | ||
| 164 | ;; width of the first-line prefix in canonical-width characters. | ||
| 165 | ;; This is useful if the first-line prefix uses some very-wide | ||
| 166 | ;; characters. | ||
| 167 | (if-let ((font (font-at position)) | ||
| 168 | (info (query-font font))) | ||
| 169 | (max (string-width prefix) | ||
| 170 | (ceiling (string-pixel-width prefix (current-buffer)) | ||
| 171 | (aref info 7))) | ||
| 172 | (string-width prefix))))) | ||
| 113 | 173 | ||
| 114 | (defun visual-wrap-fill-context-prefix (beg end) | 174 | (defun visual-wrap-fill-context-prefix (beg end) |
| 115 | "Compute visual wrap prefix from text between BEG and END. | 175 | "Compute visual wrap prefix from text between BEG and END. |
| 116 | This is like `fill-context-prefix', but with prefix length adjusted | 176 | This is like `fill-context-prefix', but with prefix length adjusted |
| 117 | by `visual-wrap-extra-indent'." | 177 | by `visual-wrap-extra-indent'." |
| 178 | (declare (obsolete nil "31.1")) | ||
| 118 | (let* ((fcp | 179 | (let* ((fcp |
| 119 | ;; `fill-context-prefix' ignores prefixes that look like | 180 | ;; `fill-context-prefix' ignores prefixes that look like |
| 120 | ;; paragraph starts, in order to avoid inadvertently | 181 | ;; paragraph starts, in order to avoid inadvertently |
| @@ -128,7 +189,7 @@ by `visual-wrap-extra-indent'." | |||
| 128 | ;; Note: fill-context-prefix may return nil; See: | 189 | ;; Note: fill-context-prefix may return nil; See: |
| 129 | ;; http://article.gmane.org/gmane.emacs.devel/156285 | 190 | ;; http://article.gmane.org/gmane.emacs.devel/156285 |
| 130 | "")) | 191 | "")) |
| 131 | (prefix (visual-wrap--prefix fcp)) | 192 | (prefix (visual-wrap--adjust-prefix fcp)) |
| 132 | (face (visual-wrap--prefix-face fcp beg end))) | 193 | (face (visual-wrap--prefix-face fcp beg end))) |
| 133 | (if face | 194 | (if face |
| 134 | (propertize prefix 'face face) | 195 | (propertize prefix 'face face) |
| @@ -147,28 +208,8 @@ by `visual-wrap-extra-indent'." | |||
| 147 | (forward-line 0) | 208 | (forward-line 0) |
| 148 | (setq beg (point)) | 209 | (setq beg (point)) |
| 149 | (while (< (point) end) | 210 | (while (< (point) end) |
| 150 | (let ((lbp (point))) | 211 | (visual-wrap--apply-to-line (point)) |
| 151 | (put-text-property | 212 | (forward-line)) |
| 152 | (point) (progn (search-forward "\n" end 'move) (point)) | ||
| 153 | 'wrap-prefix | ||
| 154 | (let ((pfx (visual-wrap-fill-context-prefix | ||
| 155 | lbp (point)))) | ||
| 156 | ;; Remove any `wrap-prefix' property that might have been | ||
| 157 | ;; added earlier. Otherwise, we end up with a string | ||
| 158 | ;; containing a `wrap-prefix' string containing a | ||
| 159 | ;; `wrap-prefix' string ... | ||
| 160 | (remove-text-properties | ||
| 161 | 0 (length pfx) '(wrap-prefix) pfx) | ||
| 162 | (let ((dp (get-text-property 0 'display pfx))) | ||
| 163 | (when (and dp (eq dp (get-text-property (1- lbp) 'display))) | ||
| 164 | ;; There's a `display' property which covers not just the | ||
| 165 | ;; prefix but also the previous newline. So it's not | ||
| 166 | ;; just making the prefix more pretty and could interfere | ||
| 167 | ;; or even defeat our efforts (e.g. it comes from | ||
| 168 | ;; `adaptive-fill-mode'). | ||
| 169 | (remove-text-properties | ||
| 170 | 0 (length pfx) '(display) pfx))) | ||
| 171 | pfx)))) | ||
| 172 | `(jit-lock-bounds ,beg . ,end)) | 213 | `(jit-lock-bounds ,beg . ,end)) |
| 173 | 214 | ||
| 174 | ;;;###autoload | 215 | ;;;###autoload |