aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/visual-wrap.el
diff options
context:
space:
mode:
authorJim Porter2024-07-27 20:48:38 -0700
committerJim Porter2024-08-04 10:46:28 -0700
commitf70a6ea0ea86ef461e40d20664a75a92d02679ea (patch)
tree63b555139d21a08e2701acfd23b1cca9f0300025 /lisp/visual-wrap.el
parent0756f3085ea948c945e309e2ce347fc5ab836574 (diff)
downloademacs-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.el113
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.
136POSITION is the position in the buffer where PREFIX is located.
137
138This returns a string prefix to use for subsequent lines; an integer,
139indicating the number of canonical-width spaces to use; or nil, if
140PREFIX 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.
116This is like `fill-context-prefix', but with prefix length adjusted 176This is like `fill-context-prefix', but with prefix length adjusted
117by `visual-wrap-extra-indent'." 177by `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