diff options
| -rw-r--r-- | doc/lispref/display.texi | 6 | ||||
| -rw-r--r-- | etc/NEWS | 12 | ||||
| -rw-r--r-- | lisp/emacs-lisp/subr-x.el | 11 | ||||
| -rw-r--r-- | lisp/visual-wrap.el | 113 |
4 files changed, 102 insertions, 40 deletions
diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 195464ef7f5..d28ff9ead26 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi | |||
| @@ -2385,9 +2385,11 @@ The optional arguments @var{x-limit} and @var{y-limit} have the same | |||
| 2385 | meaning as with @code{window-text-pixel-size}. | 2385 | meaning as with @code{window-text-pixel-size}. |
| 2386 | @end defun | 2386 | @end defun |
| 2387 | 2387 | ||
| 2388 | @defun string-pixel-width string | 2388 | @defun string-pixel-width string &optional buffer |
| 2389 | This is a convenience function that uses @code{window-text-pixel-size} | 2389 | This is a convenience function that uses @code{window-text-pixel-size} |
| 2390 | to compute the width of @var{string} (in pixels). | 2390 | to compute the width of @var{string} (in pixels). If @var{buffer} is |
| 2391 | non-@code{nil}, use any face remappings (@pxref{Face Remapping}) from | ||
| 2392 | that buffer when computing the width of @var{string}. | ||
| 2391 | @end defun | 2393 | @end defun |
| 2392 | 2394 | ||
| 2393 | @defun line-pixel-height | 2395 | @defun line-pixel-height |
| @@ -83,6 +83,12 @@ aggressively rather than switching to some other buffer in it. | |||
| 83 | *** New language-environment and input method for Tifinagh. | 83 | *** New language-environment and input method for Tifinagh. |
| 84 | The Tifinagh script is used to write the Berber languages. | 84 | The Tifinagh script is used to write the Berber languages. |
| 85 | 85 | ||
| 86 | --- | ||
| 87 | ** 'visual-wrap-prefix-mode' now supports variable-pitch fonts. | ||
| 88 | When using 'visual-wrap-prefix-mode' in buffers with variable-pitch | ||
| 89 | fonts, the wrapped text will now be lined up correctly so that it's | ||
| 90 | exactly below the text after the prefix on the first line. | ||
| 91 | |||
| 86 | 92 | ||
| 87 | * Changes in Specialized Modes and Packages in Emacs 31.1 | 93 | * Changes in Specialized Modes and Packages in Emacs 31.1 |
| 88 | 94 | ||
| @@ -245,6 +251,12 @@ language A will be applied to language B instead. | |||
| 245 | This is useful for reusing font-lock rules and indentation rules of | 251 | This is useful for reusing font-lock rules and indentation rules of |
| 246 | language A for language B, when language B is a strict superset of | 252 | language A for language B, when language B is a strict superset of |
| 247 | language A. | 253 | language A. |
| 254 | |||
| 255 | +++ | ||
| 256 | ** New optional BUFFER argument for 'string-pixel-width'. | ||
| 257 | If supplied, 'string-pixel-width' will use any face remappings from | ||
| 258 | BUFFER when computing the string's width. | ||
| 259 | |||
| 248 | 260 | ||
| 249 | * Changes in Emacs 31.1 on Non-Free Operating Systems | 261 | * Changes in Emacs 31.1 on Non-Free Operating Systems |
| 250 | 262 | ||
diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el index e725c490aba..058c06bc5f6 100644 --- a/lisp/emacs-lisp/subr-x.el +++ b/lisp/emacs-lisp/subr-x.el | |||
| @@ -337,8 +337,10 @@ This construct can only be used with lexical binding." | |||
| 337 | . ,aargs))) | 337 | . ,aargs))) |
| 338 | 338 | ||
| 339 | ;;;###autoload | 339 | ;;;###autoload |
| 340 | (defun string-pixel-width (string) | 340 | (defun string-pixel-width (string &optional buffer) |
| 341 | "Return the width of STRING in pixels." | 341 | "Return the width of STRING in pixels. |
| 342 | If BUFFER is non-nil, use the face remappings from that buffer when | ||
| 343 | determining the width." | ||
| 342 | (declare (important-return-value t)) | 344 | (declare (important-return-value t)) |
| 343 | (if (zerop (length string)) | 345 | (if (zerop (length string)) |
| 344 | 0 | 346 | 0 |
| @@ -352,6 +354,11 @@ This construct can only be used with lexical binding." | |||
| 352 | ;; Disable line-prefix and wrap-prefix, for the same reason. | 354 | ;; Disable line-prefix and wrap-prefix, for the same reason. |
| 353 | (setq line-prefix nil | 355 | (setq line-prefix nil |
| 354 | wrap-prefix nil) | 356 | wrap-prefix nil) |
| 357 | (if buffer | ||
| 358 | (setq-local face-remapping-alist | ||
| 359 | (with-current-buffer buffer | ||
| 360 | face-remapping-alist)) | ||
| 361 | (kill-local-variable 'face-remapping-alist)) | ||
| 355 | (insert (propertize string 'line-prefix nil 'wrap-prefix nil)) | 362 | (insert (propertize string 'line-prefix nil 'wrap-prefix nil)) |
| 356 | (car (buffer-text-pixel-size nil nil t))))) | 363 | (car (buffer-text-pixel-size nil nil t))))) |
| 357 | 364 | ||
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 |