* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' @ 2024-06-17 2:56 Jim Porter 2024-06-17 11:37 ` Eli Zaretskii 2024-06-17 14:23 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 2 replies; 27+ messages in thread From: Jim Porter @ 2024-06-17 2:56 UTC (permalink / raw) To: 71605 [-- Attachment #1: Type: text/plain, Size: 1095 bytes --] (Note: I plan to merge this only after we cut the Emacs 30 release branch, since it seems a bit too substantial a change to sneak in right near the end. However, I think the patch is mostly done aside from one remaining issue, so any feedback is very welcome.) 'visual-wrap-prefix-mode' has one small issue: since the wrap prefix is just a string, the wrapped text may not line up for variable-width fonts. This is mainly in cases like so: * here is some text that got visually wrapped If the "* " is variable-width, the second line will probably be indented wrong by a few pixels. The attached patch adds a display spec in this case so that the text lines up perfectly. There's currently one problem though: I'm not sure how to regenerate the wrap prefix automatically if the face changes. It's not hard to handle for 'text-scale-adjust', but I don't know how to handle 'global-text-scale-adjust' (or other things that could change the face[1]). Does anyone have any ideas for this part? [1] There's 'after-setting-font-hook', but that doesn't cover everything either. [-- Attachment #2: 0001-Add-support-for-variable-width-text-in-visual-wrap-p.patch --] [-- Type: text/plain, Size: 9101 bytes --] From 696a271601457f63dd7127261242e21432713402 Mon Sep 17 00:00:00 2001 From: Jim Porter <jporterbugs@gmail.com> Date: Sun, 16 Jun 2024 15:21:52 -0700 Subject: [PATCH] Add support for variable-width text in 'visual-wrap-prefix-mode' This uses a display spec to set the width correctly when indenting with spaces. * lisp/emacs-lisp/subr-x.el (string-pixel-width): New argument BUFFER. * lisp/visual-wrap.el (visual-wrap--adjust-display-width) (visual-wrap--content-prefix): New functions. (visual-wrap--extra-indent): Rename from 'visual-wrap--prefix' and call 'visual-wrap--adjust-display-width'. (visual-wrap-fill-context-prefix): Support display width. (visual-wrap-prefix-function): Allow 'lbp' to be at 'point-min'. (visual-wrap-prefix-mode): Refontify when changing text scale. * doc/lispref/display.texi (Size of Displayed Text): Document BUFFER argument for 'string-pixel-width'. * etc/NEWS: Announce this change. --- doc/lispref/display.texi | 6 ++-- etc/NEWS | 8 ++++- lisp/emacs-lisp/subr-x.el | 11 ++++-- lisp/visual-wrap.el | 73 +++++++++++++++++++++++++++------------ 4 files changed, 70 insertions(+), 28 deletions(-) diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index d5c96d13e02..52957f2ad07 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -2351,9 +2351,11 @@ Size of Displayed Text meaning as with @code{window-text-pixel-size}. @end defun -@defun string-pixel-width string +@defun string-pixel-width string &optional buffer This is a convenience function that uses @code{window-text-pixel-size} -to compute the width of @var{string} (in pixels). +to compute the width of @var{string} (in pixels). If @var{buffer} is +non-@code{nil}, use the face remappings from that buffer when +determining the width (@pxref{Face Remapping}). @end defun @defun line-pixel-height diff --git a/etc/NEWS b/etc/NEWS index b2fdbc4a88f..27a4fd11a87 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -549,7 +549,8 @@ text in any way. The global minor mode buffers. (This minor mode is the 'adaptive-wrap' ELPA package renamed and -lightly edited for inclusion in Emacs.) +enhanced for inclusion in Emacs. It additionally supports prefixes for +variable-width text.) +++ ** New user option 'gud-highlight-current-line'. @@ -2789,6 +2790,11 @@ These functions are like 'user-uid' and 'group-gid', respectively, but are aware of file name handlers, so they will return the remote UID or GID for remote files (or -1 if the connection has no associated user). ++++ +** 'string-pixel-width' now accepts a BUFFER argument. +If BUFFER is non-nil, 'string-pixel-width' will apply BUFFER's face +remappings when computing the string's width. + +++ ** 'fset', 'defalias' and 'defvaralias' now signal an error for cyclic aliases. Previously, 'fset', 'defalias' and 'defvaralias' could be made to diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el index 699be767ee7..2cbe1beb9f1 100644 --- a/lisp/emacs-lisp/subr-x.el +++ b/lisp/emacs-lisp/subr-x.el @@ -333,8 +333,10 @@ named-let . ,aargs))) ;;;###autoload -(defun string-pixel-width (string) - "Return the width of STRING in pixels." +(defun string-pixel-width (string &optional buffer) + "Return the width of STRING in pixels. +If BUFFER is non-nil, use the face remappings from that buffer when +determining the width." (declare (important-return-value t)) (if (zerop (length string)) 0 @@ -348,6 +350,11 @@ string-pixel-width ;; Disable line-prefix and wrap-prefix, for the same reason. (setq line-prefix nil wrap-prefix nil) + (if buffer + (setq-local face-remapping-alist + (with-current-buffer buffer + face-remapping-alist)) + (kill-local-variable 'face-remapping-alist)) (insert (propertize string 'line-prefix nil 'wrap-prefix nil)) (car (buffer-text-pixel-size nil nil t))))) diff --git a/lisp/visual-wrap.el b/lisp/visual-wrap.el index d95cf4bb569..241cd337148 100644 --- a/lisp/visual-wrap.el +++ b/lisp/visual-wrap.el @@ -97,38 +97,60 @@ visual-wrap--prefix-face (if (visual-wrap--face-extend-p f) f)) eol-face))))))) -(defun visual-wrap--prefix (fcp) +(defun visual-wrap--adjust-display-width (fcp n) + (when-let ((display (get-text-property 0 'display fcp)) + ((eq (car-safe display) 'space)) + (width (car (plist-get (cdr display) :width)))) + (put-text-property 0 (length fcp) 'display + `(space :width (,(+ width n))) fcp)) + fcp) + +(defun visual-wrap--extra-indent (fcp) (let ((fcp-len (string-width fcp))) (cond ((= 0 visual-wrap-extra-indent) fcp) ((< 0 visual-wrap-extra-indent) - (concat fcp (make-string visual-wrap-extra-indent ?\s))) + (let* ((extra (make-string visual-wrap-extra-indent ?\s)) + (result (concat fcp extra))) + (visual-wrap--adjust-display-width + result (string-pixel-width extra (current-buffer))))) ((< 0 (+ visual-wrap-extra-indent fcp-len)) - (substring fcp - 0 - (+ visual-wrap-extra-indent fcp-len))) + (let* ((idx (+ visual-wrap-extra-indent fcp-len)) + (trim (substring fcp idx)) + (result (substring fcp 0 idx))) + (remove-text-properties 0 (length trim) '(display) trim) + (visual-wrap--adjust-display-width + result (- (string-pixel-width trim (current-buffer)))))) (t "")))) +(defun visual-wrap--content-prefix (position) + "Get the content prefix for the line starting at POSITION. +This is like `fill-content-prefix' but doesn't check subsequent lines +and uses display specs to handle variable-width faces." + (save-excursion + (goto-char position) + (if (eolp) (forward-line 1)) + ;; Move to the second line unless there is just one. + (move-to-left-margin) + (let ((prefix (fill-match-adaptive-prefix))) + (if (or (and adaptive-fill-first-line-regexp + (string-match adaptive-fill-first-line-regexp prefix)) + (and comment-start-skip + (string-match comment-start-skip prefix))) + prefix + (propertize + (make-string (string-width prefix) ?\s) + 'display `(space :width (,(string-pixel-width + prefix (current-buffer))))))))) + (defun visual-wrap-fill-context-prefix (beg end) "Compute visual wrap prefix from text between BEG and END. -This is like `fill-context-prefix', but with prefix length adjusted -by `visual-wrap-extra-indent'." - (let* ((fcp - ;; `fill-context-prefix' ignores prefixes that look like - ;; paragraph starts, in order to avoid inadvertently - ;; creating a new paragraph while filling, but here we're - ;; only dealing with single-line "paragraphs" and we don't - ;; actually modify the buffer, so this restriction doesn't - ;; make much sense (and is positively harmful in - ;; taskpaper-mode where paragraph-start matches everything). - (or (let ((paragraph-start regexp-unmatchable)) - (fill-context-prefix beg end)) - ;; Note: fill-context-prefix may return nil; See: - ;; http://article.gmane.org/gmane.emacs.devel/156285 - "")) - (prefix (visual-wrap--prefix fcp)) +This is like `fill-context-prefix', but supporting variable-width faces +and with the prefix length adjusted by `visual-wrap-extra-indent'." + (let* ((fcp (visual-wrap--content-prefix beg)) + (prefix (visual-wrap--extra-indent fcp)) (face (visual-wrap--prefix-face fcp beg end))) (if face (propertize prefix 'face face) @@ -160,7 +182,8 @@ visual-wrap-prefix-function (remove-text-properties 0 (length pfx) '(wrap-prefix) pfx) (let ((dp (get-text-property 0 'display pfx))) - (when (and dp (eq dp (get-text-property (1- lbp) 'display))) + (when (and dp (> lbp (point-min)) + (eq dp (get-text-property (1- lbp) 'display))) ;; There's a `display' property which covers not just the ;; prefix but also the previous newline. So it's not ;; just making the prefix more pretty and could interfere @@ -187,8 +210,12 @@ visual-wrap-prefix-mode ;; of the hook (bug#15155). (add-hook 'jit-lock-functions #'visual-wrap-prefix-function 'append t) - (jit-lock-register #'visual-wrap-prefix-function)) + (jit-lock-register #'visual-wrap-prefix-function) + ;; FIXME: What should we do about `global-text-scale-adjust' or + ;; other things that can change the text size? + (add-hook 'text-scale-mode-hook #'jit-lock-refontify nil t)) (jit-lock-unregister #'visual-wrap-prefix-function) + (remove-hook 'text-scale-mode-hook #'jit-lock-refontify) (with-silent-modifications (save-restriction (widen) -- 2.25.1 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-17 2:56 bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' Jim Porter @ 2024-06-17 11:37 ` Eli Zaretskii 2024-06-17 17:42 ` Jim Porter 2024-06-17 14:23 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors 1 sibling, 1 reply; 27+ messages in thread From: Eli Zaretskii @ 2024-06-17 11:37 UTC (permalink / raw) To: Jim Porter; +Cc: 71605 > Date: Sun, 16 Jun 2024 19:56:44 -0700 > From: Jim Porter <jporterbugs@gmail.com> > > (Note: I plan to merge this only after we cut the Emacs 30 release > branch, since it seems a bit too substantial a change to sneak in right > near the end. However, I think the patch is mostly done aside from one > remaining issue, so any feedback is very welcome.) OK. > 'visual-wrap-prefix-mode' has one small issue: since the wrap prefix is > just a string, the wrapped text may not line up for variable-width > fonts. This is mainly in cases like so: > > * here is some text that > got visually wrapped > > If the "* " is variable-width, the second line will probably be indented > wrong by a few pixels. It also means the line after "*", the one that begins with "here is", will also move horizontally. Isn't that a misfeature? Perhaps this mode should align the text to some fixed pixel-coordinate, in which case changes in font should not matter? Or am I missing something? > The attached patch adds a display spec in this case so that the text > lines up perfectly. Can you explain the idea of the patch? I don't think I understand why you use '(space :width)' rather than '(space :align-to)'. > There's currently one problem though: I'm not sure > how to regenerate the wrap prefix automatically if the face changes. > It's not hard to handle for 'text-scale-adjust', but I don't know how to > handle 'global-text-scale-adjust' (or other things that could change the > face[1]). > > Does anyone have any ideas for this part? Perhaps we could provide a function "face-change (&optional frame)" which would access the frame's face_change flag and the global face_change flag. Then you could test those in a post-command-hook or somesuch. (However, using :align-to, if feasible, sounds like a better solution to me.) > -@defun string-pixel-width string > +@defun string-pixel-width string &optional buffer > This is a convenience function that uses @code{window-text-pixel-size} > -to compute the width of @var{string} (in pixels). > +to compute the width of @var{string} (in pixels). If @var{buffer} is > +non-@code{nil}, use the face remappings from that buffer when > +determining the width (@pxref{Face Remapping}). An alternative would be to provide a face to use. In any case, using BUFFER only for face-remapping-alist is only a small part of what a buffer can do to a string: there's the major mode with its fontifications and whatnot. > +(defun string-pixel-width (string &optional buffer) > + "Return the width of STRING in pixels. > +If BUFFER is non-nil, use the face remappings from that buffer when > +determining the width." > (declare (important-return-value t)) > (if (zerop (length string)) > 0 > @@ -348,6 +350,11 @@ string-pixel-width > ;; Disable line-prefix and wrap-prefix, for the same reason. > (setq line-prefix nil > wrap-prefix nil) > + (if buffer ^^^^^^^^^ This should test buffer-live-p, I think, not just buffer non-nil. > +(defun visual-wrap--adjust-display-width (fcp n) > + (when-let ((display (get-text-property 0 'display fcp)) > + ((eq (car-safe display) 'space)) Doesn't this only work with very simple 'display' specs? The 'space' part could be in some place deep in the spec, not just the second symbol. > (defun visual-wrap-fill-context-prefix (beg end) > "Compute visual wrap prefix from text between BEG and END. > -This is like `fill-context-prefix', but with prefix length adjusted > -by `visual-wrap-extra-indent'." > - (let* ((fcp > - ;; `fill-context-prefix' ignores prefixes that look like > - ;; paragraph starts, in order to avoid inadvertently > - ;; creating a new paragraph while filling, but here we're > - ;; only dealing with single-line "paragraphs" and we don't > - ;; actually modify the buffer, so this restriction doesn't > - ;; make much sense (and is positively harmful in > - ;; taskpaper-mode where paragraph-start matches everything). > - (or (let ((paragraph-start regexp-unmatchable)) > - (fill-context-prefix beg end)) > - ;; Note: fill-context-prefix may return nil; See: > - ;; http://article.gmane.org/gmane.emacs.devel/156285 > - "")) The comment above and the URL it included are deleted: is that because they are no longer relevant? If not, maybe move them with the code, so that the information is not lost. ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-17 11:37 ` Eli Zaretskii @ 2024-06-17 17:42 ` Jim Porter 2024-06-17 18:20 ` Eli Zaretskii 0 siblings, 1 reply; 27+ messages in thread From: Jim Porter @ 2024-06-17 17:42 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 71605 [-- Attachment #1: Type: text/plain, Size: 6428 bytes --] On 6/17/2024 4:37 AM, Eli Zaretskii wrote: >> Date: Sun, 16 Jun 2024 19:56:44 -0700 >> From: Jim Porter <jporterbugs@gmail.com> >> The attached patch adds a display spec in this case so that the text >> lines up perfectly. > > Can you explain the idea of the patch? I don't think I understand why > you use '(space :width)' rather than '(space :align-to)'. I tried using :align-to, and it doesn't seem to take effect for the 'wrap-prefix' text property. I haven't looked closely at why that doesn't work, but even if it did, I think it might make things more complex than they already are. I'll try to describe the current process: 1. 'visual-wrap-prefix-mode' goes a line at a time, finding the first-line prefix (for a bulleted item, this is something like "* "). 2. Then it constructs the wrap-prefix string (for a bulleted item, something like " "; for other items it might be the same as the first-line prefix). 3. Finally, it applies the the wrap-prefix to the entire line it's examining. The problem comes up for variable-pitch fonts, where "* " and " " have different pixel widths. Before my patch, this results in the second line not lining up correctly. See the attached image for an example. My patch just sets a display-spec on the " " to make it have the same pixel-width as "* ". Then it all lines up. If I understand your :align-to suggestion, setting :align-to on everything after the "* " bullet could work in theory, but I don't know what value you could set there to make everything correct. If it's a fixed number of pixels, then scaling up the text could mean the "* " becomes too wide for the space we reserved for it, and then things would probably look wrong. If it's based on the canonical character width, that might work so long as that updates when needed, but it might still look off depending on how the canonical width and the pixel width compare. (Ideally, we'd align to the exact pixel-width of "* " or whatever the first-line prefix is.) I couldn't get :align-to to work in the first place though so this is all hypothetical... >> There's currently one problem though: I'm not sure >> how to regenerate the wrap prefix automatically if the face changes. >> It's not hard to handle for 'text-scale-adjust', but I don't know how to >> handle 'global-text-scale-adjust' (or other things that could change the >> face[1]). >> >> Does anyone have any ideas for this part? > > Perhaps we could provide a function "face-change (&optional frame)" > which would access the frame's face_change flag and the global > face_change flag. Then you could test those in a post-command-hook or > somesuch. (However, using :align-to, if feasible, sounds like a > better solution to me.) The 'face-change' idea could work, or here's another possibility: what about using :relative-width? If I set that correctly, then the pixel-size should adjust as the text scales. It wouldn't handle the case where the actual font changes though. It would also have some loss of precision, but I tested out a hacky patch using :relative-width and it looks good in practice. >> -@defun string-pixel-width string >> +@defun string-pixel-width string &optional buffer >> This is a convenience function that uses @code{window-text-pixel-size} >> -to compute the width of @var{string} (in pixels). >> +to compute the width of @var{string} (in pixels). If @var{buffer} is >> +non-@code{nil}, use the face remappings from that buffer when >> +determining the width (@pxref{Face Remapping}). > > An alternative would be to provide a face to use. > > In any case, using BUFFER only for face-remapping-alist is only a > small part of what a buffer can do to a string: there's the major mode > with its fontifications and whatnot. Yeah, I'm not entirely happy with this BUFFER argument either. I don't think we need to worry about fontification in this case though, since you can pass in a fontified string. Maybe this should take the face-remapping-alist directly? Or maybe we should pass in a window? The latter might be better for handling things like frame-specific font settings. (Although as Po Lu points out, frame-specific fonts are challenging to handle correctly here.) >> +(defun visual-wrap--adjust-display-width (fcp n) >> + (when-let ((display (get-text-property 0 'display fcp)) >> + ((eq (car-safe display) 'space)) > > Doesn't this only work with very simple 'display' specs? The 'space' > part could be in some place deep in the spec, not just the second > symbol. Yeah, though the FCP argument is always the prefix we constructed, so we know what the display-spec looks like if it's present. The extra checks are just my natural paranoia. I've added a comment here explaining though. >> (defun visual-wrap-fill-context-prefix (beg end) >> "Compute visual wrap prefix from text between BEG and END. >> -This is like `fill-context-prefix', but with prefix length adjusted >> -by `visual-wrap-extra-indent'." >> - (let* ((fcp >> - ;; `fill-context-prefix' ignores prefixes that look like >> - ;; paragraph starts, in order to avoid inadvertently >> - ;; creating a new paragraph while filling, but here we're >> - ;; only dealing with single-line "paragraphs" and we don't >> - ;; actually modify the buffer, so this restriction doesn't >> - ;; make much sense (and is positively harmful in >> - ;; taskpaper-mode where paragraph-start matches everything). >> - (or (let ((paragraph-start regexp-unmatchable)) >> - (fill-context-prefix beg end)) >> - ;; Note: fill-context-prefix may return nil; See: >> - ;; http://article.gmane.org/gmane.emacs.devel/156285 >> - "")) > > The comment above and the URL it included are deleted: is that because > they are no longer relevant? If not, maybe move them with the code, > so that the information is not lost. Correct, they're no longer relevant. I extracted the logic that we need out of 'fill-content-prefix' and into 'visual-wrap--content-prefix'. The former didn't behave quite the way we wanted (hence all the comments), and it made handling the display-spec parts of my patch even harder, so I just took the relevant logic out and made a function that does exactly what we want. I've added more detail to the commit message explaining the change. [-- Attachment #2: misaligned.png --] [-- Type: image/png, Size: 24816 bytes --] [-- Attachment #3: 0001-Add-support-for-variable-width-text-in-visual-wrap-p.patch --] [-- Type: text/plain, Size: 9981 bytes --] From 120748358b6a717c740e8d4f139ce62a30be7606 Mon Sep 17 00:00:00 2001 From: Jim Porter <jporterbugs@gmail.com> Date: Sun, 16 Jun 2024 15:21:52 -0700 Subject: [PATCH 1/2] Add support for variable-width text in 'visual-wrap-prefix-mode' This uses a display spec to set the width correctly when indenting with spaces. * lisp/emacs-lisp/subr-x.el (string-pixel-width): New argument BUFFER. * lisp/visual-wrap.el (visual-wrap--content-prefix) (visual-wrap--adjust-display-width): New functions. (visual-wrap--extra-indent): Rename from 'visual-wrap--prefix' and call 'visual-wrap--adjust-display-width'. (visual-wrap-fill-context-prefix): Support display width. Use 'visual-wrap--content-prefix' instead of 'fill-content-prefix', which lets us remove the old workarounds. (visual-wrap-prefix-function): Allow 'lbp' to be at 'point-min'. (visual-wrap-prefix-mode): Refontify when changing text scale. * doc/lispref/display.texi (Size of Displayed Text): Document BUFFER argument for 'string-pixel-width'. * etc/NEWS: Announce this change. --- doc/lispref/display.texi | 6 ++- etc/NEWS | 8 +++- lisp/emacs-lisp/subr-x.el | 11 ++++- lisp/visual-wrap.el | 86 ++++++++++++++++++++++++++++----------- 4 files changed, 83 insertions(+), 28 deletions(-) diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index d5c96d13e02..52957f2ad07 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -2351,9 +2351,11 @@ Size of Displayed Text meaning as with @code{window-text-pixel-size}. @end defun -@defun string-pixel-width string +@defun string-pixel-width string &optional buffer This is a convenience function that uses @code{window-text-pixel-size} -to compute the width of @var{string} (in pixels). +to compute the width of @var{string} (in pixels). If @var{buffer} is +non-@code{nil}, use the face remappings from that buffer when +determining the width (@pxref{Face Remapping}). @end defun @defun line-pixel-height diff --git a/etc/NEWS b/etc/NEWS index b2fdbc4a88f..27a4fd11a87 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -549,7 +549,8 @@ text in any way. The global minor mode buffers. (This minor mode is the 'adaptive-wrap' ELPA package renamed and -lightly edited for inclusion in Emacs.) +enhanced for inclusion in Emacs. It additionally supports prefixes for +variable-width text.) +++ ** New user option 'gud-highlight-current-line'. @@ -2789,6 +2790,11 @@ These functions are like 'user-uid' and 'group-gid', respectively, but are aware of file name handlers, so they will return the remote UID or GID for remote files (or -1 if the connection has no associated user). ++++ +** 'string-pixel-width' now accepts a BUFFER argument. +If BUFFER is non-nil, 'string-pixel-width' will apply BUFFER's face +remappings when computing the string's width. + +++ ** 'fset', 'defalias' and 'defvaralias' now signal an error for cyclic aliases. Previously, 'fset', 'defalias' and 'defvaralias' could be made to diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el index 699be767ee7..2cbe1beb9f1 100644 --- a/lisp/emacs-lisp/subr-x.el +++ b/lisp/emacs-lisp/subr-x.el @@ -333,8 +333,10 @@ named-let . ,aargs))) ;;;###autoload -(defun string-pixel-width (string) - "Return the width of STRING in pixels." +(defun string-pixel-width (string &optional buffer) + "Return the width of STRING in pixels. +If BUFFER is non-nil, use the face remappings from that buffer when +determining the width." (declare (important-return-value t)) (if (zerop (length string)) 0 @@ -348,6 +350,11 @@ string-pixel-width ;; Disable line-prefix and wrap-prefix, for the same reason. (setq line-prefix nil wrap-prefix nil) + (if buffer + (setq-local face-remapping-alist + (with-current-buffer buffer + face-remapping-alist)) + (kill-local-variable 'face-remapping-alist)) (insert (propertize string 'line-prefix nil 'wrap-prefix nil)) (car (buffer-text-pixel-size nil nil t))))) diff --git a/lisp/visual-wrap.el b/lisp/visual-wrap.el index d95cf4bb569..886219cff54 100644 --- a/lisp/visual-wrap.el +++ b/lisp/visual-wrap.el @@ -97,38 +97,73 @@ visual-wrap--prefix-face (if (visual-wrap--face-extend-p f) f)) eol-face))))))) -(defun visual-wrap--prefix (fcp) +(defun visual-wrap--content-prefix (position) + "Get the content prefix for the line starting at POSITION. +This is like `fill-content-prefix' but doesn't check subsequent lines +and uses display specs to handle variable-pitch faces." + (save-excursion + (goto-char position) + (if (eolp) (forward-line 1)) + ;; Move to the second line unless there is just one. + (move-to-left-margin) + (let ((prefix (fill-match-adaptive-prefix))) + ;; Check whether we should use our first-line content prefix. + (if (or (and adaptive-fill-first-line-regexp + (string-match adaptive-fill-first-line-regexp prefix)) + (and comment-start-skip + (string-match comment-start-skip prefix))) + prefix + ;; We want the prefix to be whitespace of the same width as the + ;; first-line prefix. + (let ((spaces (make-string (string-width prefix) ?\s))) + ;; If the font for our first-line prefix is variable-pitch, + ;; use a display spec to line the subsequent lines up + ;; correctly. + (when-let ((font (font-at position)) + ((memq (font-get font :spacing) '(nil 0)))) + (put-text-property 0 (length spaces) 'display + `(space :width (,(string-pixel-width + prefix (current-buffer)))) + spaces)) + spaces))))) + +(defun visual-wrap--adjust-display-width (fcp n) + (when-let ((display (get-text-property 0 'display fcp)) + ;; If we have a display spec here, it should be what we + ;; specified in `visual-wrap--content-prefix', but + ;; double-check just to be safe. + ((eq (car-safe display) 'space)) + (width (car (plist-get (cdr display) :width)))) + (put-text-property 0 (length fcp) 'display + `(space :width (,(+ width n))) fcp)) + fcp) + +(defun visual-wrap--extra-indent (fcp) (let ((fcp-len (string-width fcp))) (cond ((= 0 visual-wrap-extra-indent) fcp) ((< 0 visual-wrap-extra-indent) - (concat fcp (make-string visual-wrap-extra-indent ?\s))) + (let* ((extra (make-string visual-wrap-extra-indent ?\s)) + (result (concat fcp extra))) + (visual-wrap--adjust-display-width + result (string-pixel-width extra (current-buffer))))) ((< 0 (+ visual-wrap-extra-indent fcp-len)) - (substring fcp - 0 - (+ visual-wrap-extra-indent fcp-len))) + (let* ((idx (+ visual-wrap-extra-indent fcp-len)) + (trim (substring fcp idx)) + (result (substring fcp 0 idx))) + (remove-text-properties 0 (length trim) '(display) trim) + (visual-wrap--adjust-display-width + result (- (string-pixel-width trim (current-buffer)))))) (t "")))) (defun visual-wrap-fill-context-prefix (beg end) "Compute visual wrap prefix from text between BEG and END. -This is like `fill-context-prefix', but with prefix length adjusted -by `visual-wrap-extra-indent'." - (let* ((fcp - ;; `fill-context-prefix' ignores prefixes that look like - ;; paragraph starts, in order to avoid inadvertently - ;; creating a new paragraph while filling, but here we're - ;; only dealing with single-line "paragraphs" and we don't - ;; actually modify the buffer, so this restriction doesn't - ;; make much sense (and is positively harmful in - ;; taskpaper-mode where paragraph-start matches everything). - (or (let ((paragraph-start regexp-unmatchable)) - (fill-context-prefix beg end)) - ;; Note: fill-context-prefix may return nil; See: - ;; http://article.gmane.org/gmane.emacs.devel/156285 - "")) - (prefix (visual-wrap--prefix fcp)) +This is like `fill-context-prefix', but supporting variable-width faces +and with the prefix length adjusted by `visual-wrap-extra-indent'." + (let* ((fcp (visual-wrap--content-prefix beg)) + (prefix (visual-wrap--extra-indent fcp)) (face (visual-wrap--prefix-face fcp beg end))) (if face (propertize prefix 'face face) @@ -160,7 +195,8 @@ visual-wrap-prefix-function (remove-text-properties 0 (length pfx) '(wrap-prefix) pfx) (let ((dp (get-text-property 0 'display pfx))) - (when (and dp (eq dp (get-text-property (1- lbp) 'display))) + (when (and dp (> lbp (point-min)) + (eq dp (get-text-property (1- lbp) 'display))) ;; There's a `display' property which covers not just the ;; prefix but also the previous newline. So it's not ;; just making the prefix more pretty and could interfere @@ -187,8 +223,12 @@ visual-wrap-prefix-mode ;; of the hook (bug#15155). (add-hook 'jit-lock-functions #'visual-wrap-prefix-function 'append t) - (jit-lock-register #'visual-wrap-prefix-function)) + (jit-lock-register #'visual-wrap-prefix-function) + ;; FIXME: What should we do about `global-text-scale-adjust' or + ;; other things that can change the text size? + (add-hook 'text-scale-mode-hook #'jit-lock-refontify nil t)) (jit-lock-unregister #'visual-wrap-prefix-function) + (remove-hook 'text-scale-mode-hook #'jit-lock-refontify) (with-silent-modifications (save-restriction (widen) -- 2.25.1 ^ permalink raw reply related [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-17 17:42 ` Jim Porter @ 2024-06-17 18:20 ` Eli Zaretskii 2024-06-17 18:44 ` Jim Porter 0 siblings, 1 reply; 27+ messages in thread From: Eli Zaretskii @ 2024-06-17 18:20 UTC (permalink / raw) To: Jim Porter; +Cc: 71605 > Date: Mon, 17 Jun 2024 10:42:56 -0700 > Cc: 71605@debbugs.gnu.org > From: Jim Porter <jporterbugs@gmail.com> > > On 6/17/2024 4:37 AM, Eli Zaretskii wrote: > >> Date: Sun, 16 Jun 2024 19:56:44 -0700 > >> From: Jim Porter <jporterbugs@gmail.com> > >> The attached patch adds a display spec in this case so that the text > >> lines up perfectly. > > > > Can you explain the idea of the patch? I don't think I understand why > > you use '(space :width)' rather than '(space :align-to)'. > > I tried using :align-to, and it doesn't seem to take effect for the > 'wrap-prefix' text property. I haven't looked closely at why that > doesn't work, but even if it did, I think it might make things more > complex than they already are. What exactly did you try? I might be misremembering, but I'm not aware of any limitations wrt use of :align-to in wrap-prefix. In fact, the ELisp reference manual explicitly mentions :align-to in its description of wrap-prefix. > If I understand your :align-to suggestion, setting :align-to on > everything after the "* " bullet could work in theory, but I don't know > what value you could set there to make everything correct. Some multiple of the width of the default font's representative character, or of its average-width property? > The 'face-change' idea could work, or here's another possibility: what > about using :relative-width? :relative-width could work, but you'd need to make sure it takes the width from a fixed character, otherwise different paragraphs won't align the same. The ELisp manual says: ‘:relative-width FACTOR’ Specifies that the width of the stretch should be computed from the first character in the group of consecutive characters that have the same ‘display’ property. The space width is the pixel width of that character, multiplied by FACTOR. > If I set that correctly, then the pixel-size should adjust as the > text scales. It wouldn't handle the case where the actual font > changes though. Why not? > >> -@defun string-pixel-width string > >> +@defun string-pixel-width string &optional buffer > >> This is a convenience function that uses @code{window-text-pixel-size} > >> -to compute the width of @var{string} (in pixels). > >> +to compute the width of @var{string} (in pixels). If @var{buffer} is > >> +non-@code{nil}, use the face remappings from that buffer when > >> +determining the width (@pxref{Face Remapping}). > > > > An alternative would be to provide a face to use. > > > > In any case, using BUFFER only for face-remapping-alist is only a > > small part of what a buffer can do to a string: there's the major mode > > with its fontifications and whatnot. > > Yeah, I'm not entirely happy with this BUFFER argument either. I don't > think we need to worry about fontification in this case though, since > you can pass in a fontified string. > > Maybe this should take the face-remapping-alist directly? Or maybe we > should pass in a window? If you can pass a window, you can use window-text-pixel-size instead. > >> +(defun visual-wrap--adjust-display-width (fcp n) > >> + (when-let ((display (get-text-property 0 'display fcp)) > >> + ((eq (car-safe display) 'space)) > > > > Doesn't this only work with very simple 'display' specs? The 'space' > > part could be in some place deep in the spec, not just the second > > symbol. > > Yeah, though the FCP argument is always the prefix we constructed, so we > know what the display-spec looks like if it's present. Sure, but that means the code is fragile, and you need to comment prominently that if the form of the display spec changes in the future, this code will need to be adapted. ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-17 18:20 ` Eli Zaretskii @ 2024-06-17 18:44 ` Jim Porter 2024-06-18 11:37 ` Eli Zaretskii 0 siblings, 1 reply; 27+ messages in thread From: Jim Porter @ 2024-06-17 18:44 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 71605 Replying to your individual points below, but in the other subthread, I had the idea that maybe a better way to do this would be for the wrap prefix to always be the first-line prefix but to make it transparent when desired. So for the "* some text" example, the wrap-prefix would be "* " but fontified(?) such that you can't see it. A face transparency attribute might do the trick, and be useful for other things too: <https://lists.gnu.org/archive/html/emacs-devel/2024-01/msg00657.html>. Or maybe :align-to could take a string value, which would mean "use the pixel-width of this string as the value". On 6/17/2024 11:20 AM, Eli Zaretskii wrote: >> Date: Mon, 17 Jun 2024 10:42:56 -0700 >> Cc: 71605@debbugs.gnu.org >> From: Jim Porter <jporterbugs@gmail.com> >> >> I tried using :align-to, and it doesn't seem to take effect for the >> 'wrap-prefix' text property. I haven't looked closely at why that >> doesn't work, but even if it did, I think it might make things more >> complex than they already are. > > What exactly did you try? I might be misremembering, but I'm not > aware of any limitations wrt use of :align-to in wrap-prefix. In > fact, the ELisp reference manual explicitly mentions :align-to in its > description of wrap-prefix. My minimal test case is to open a buffer, put some random text in (long enough that it would wrap), and then call: (put-text-property (point-min) (point-max) 'wrap-prefix '(space :align-to 4)) Nothing changes for me. If I replace :align-to with :width, I see the continuation lines get indented by 4 characters. >> The 'face-change' idea could work, or here's another possibility: what >> about using :relative-width? > > :relative-width could work, but you'd need to make sure it takes the > width from a fixed character, otherwise different paragraphs won't > align the same. In this case, the first character is always a space so that's ok. >> If I set that correctly, then the pixel-size should adjust as the >> text scales. It wouldn't handle the case where the actual font >> changes though. > > Why not? I was planning to set :relative-width to <first_line_prefix_width> / <width_of_one_space>. If the font changes, the result of that calculation can change. >>>> -@defun string-pixel-width string >>>> +@defun string-pixel-width string &optional buffer [snip] >> Maybe this should take the face-remapping-alist directly? Or maybe we >> should pass in a window? > > If you can pass a window, you can use window-text-pixel-size instead. I think 'window-text-pixel-size' would compute the size of the text already in the buffer, and I was looking for a function that told the width of some text if I were to later display it in that window. In any case, I might not need to use this function at all depending on how I do things... >> Yeah, though the FCP argument is always the prefix we constructed, so we >> know what the display-spec looks like if it's present. > > Sure, but that means the code is fragile, and you need to comment > prominently that if the form of the display spec changes in the > future, this code will need to be adapted. Assuming I keep going down this route, I'll be sure to comment this extensively. ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-17 18:44 ` Jim Porter @ 2024-06-18 11:37 ` Eli Zaretskii 2024-06-18 22:17 ` Jim Porter 0 siblings, 1 reply; 27+ messages in thread From: Eli Zaretskii @ 2024-06-18 11:37 UTC (permalink / raw) To: Jim Porter; +Cc: 71605 > Date: Mon, 17 Jun 2024 11:44:47 -0700 > Cc: 71605@debbugs.gnu.org > From: Jim Porter <jporterbugs@gmail.com> > > Replying to your individual points below, but in the other subthread, I > had the idea that maybe a better way to do this would be for the wrap > prefix to always be the first-line prefix but to make it transparent > when desired. So for the "* some text" example, the wrap-prefix would be > "* " but fontified(?) such that you can't see it. I don't think I understand how would this do the job. Surely, the indentation space should be visible? > A face transparency attribute might do the trick, and be useful for > other things too: It isn't universally supported, AFAIK. > Or maybe :align-to could take a string value, which would mean "use the > pixel-width of this string as the value". How is that different from using a column (as opposed to pixel) value for :align-to? > >> If I set that correctly, then the pixel-size should adjust as the > >> text scales. It wouldn't handle the case where the actual font > >> changes though. > > > > Why not? > > I was planning to set :relative-width to <first_line_prefix_width> / > <width_of_one_space>. If the font changes, the result of that > calculation can change. The idea is to set it to the multiple of the character's width, which will then scale with the font. > > If you can pass a window, you can use window-text-pixel-size instead. > > I think 'window-text-pixel-size' would compute the size of the text > already in the buffer Yes, and we have with-current-buffer... ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-18 11:37 ` Eli Zaretskii @ 2024-06-18 22:17 ` Jim Porter 2024-06-19 11:45 ` Eli Zaretskii 0 siblings, 1 reply; 27+ messages in thread From: Jim Porter @ 2024-06-18 22:17 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 71605 On 6/18/2024 4:37 AM, Eli Zaretskii wrote: > I don't think I understand how would this do the job. Surely, the > indentation space should be visible? I mean the second-line "* " prefix would be visible but transparent. >> A face transparency attribute might do the trick, and be useful for >> other things too: > > It isn't universally supported, AFAIK. I think it would be feasible to support an opacity level of 1.0 and 0.0. opacity=0.0 could just allocate the space for the text but not actually draw the glyphs. (Whether we want to go this route is another question.) >> Or maybe :align-to could take a string value, which would mean "use the >> pixel-width of this string as the value". > > How is that different from using a column (as opposed to pixel) value > for :align-to? A column wouldn't work, since for a variable-pitch font, N columns is just N * <canonical character width>. If the actual characters you're trying to align to are narrower than the canonical width, they won't line up correctly. Po Lu also raised the issue that in some cases, different frames can be displaying the same buffer using different fonts. Conceptually, I'm really trying to tell the display engine, "Put a space here exactly as wide as <some text> using whatever font you end up using." At the buffer level, I can't provide a numeric width here that works everywhere, since it might really be multiple numbers, one for each frame. Providing a number in pixels is also challenging because then I need to be able to determine when to recompute that number. >>>> If I set that correctly, then the pixel-size should adjust as the >>>> text scales. It wouldn't handle the case where the actual font >>>> changes though. >>> >>> Why not? >> >> I was planning to set :relative-width to <first_line_prefix_width> / >> <width_of_one_space>. If the font changes, the result of that >> calculation can change. > > The idea is to set it to the multiple of the character's width, which > will then scale with the font. Imagine two fonts A and B, where the only difference is that the space character in B is twice as wide. So: <asterisk_width> = 15 <space_width_A> = 10 <space_width_B> = 20 <first_line_prefix_width_A> = 15 + 10 = 25 <first_line_prefix_width_B> = 15 + 20 = 35 If I compute :relative-width for font A, the result is 25/10 = 2.5. Then, 2.5 * <space_width_A> = 25 = <first_line_prefix_width_A> (good) 2.5 * <space_width_B> = 50 != <first_line_prefix_width_B> (bad!) So we'd need a way of keeping the width in-sync with any font changes. ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-18 22:17 ` Jim Porter @ 2024-06-19 11:45 ` Eli Zaretskii 2024-06-19 19:53 ` Jim Porter 0 siblings, 1 reply; 27+ messages in thread From: Eli Zaretskii @ 2024-06-19 11:45 UTC (permalink / raw) To: Jim Porter; +Cc: 71605 > Date: Tue, 18 Jun 2024 15:17:29 -0700 > Cc: 71605@debbugs.gnu.org > From: Jim Porter <jporterbugs@gmail.com> > > On 6/18/2024 4:37 AM, Eli Zaretskii wrote: > >> Or maybe :align-to could take a string value, which would mean "use the > >> pixel-width of this string as the value". > > > > How is that different from using a column (as opposed to pixel) value > > for :align-to? > > A column wouldn't work, since for a variable-pitch font, N columns is > just N * <canonical character width>. If the actual characters you're > trying to align to are narrower than the canonical width, they won't > line up correctly. If both the first line of the paragraph and the rest are aligned on that width, they will all line up. IOW, the idea is to make the text of all the lines :align-to to the same column number, like this: * some text some other text Then you don't care about the actual pixel width of "* ". > Po Lu also raised the issue that in some cases, different frames can be > displaying the same buffer using different fonts. Conceptually, I'm > really trying to tell the display engine, "Put a space here exactly as > wide as <some text> using whatever font you end up using." At the buffer > level, I can't provide a numeric width here that works everywhere, since > it might really be multiple numbers, one for each frame. IMNSHO, this is over-engineering, as we already have the means to do the same with existing features. Asking the display engine to measure and record somewhere the pixel width of a string is a significant complication to how the display code works, because the display routines can be called to start their job at any arbitrary place in the buffer. > Providing a number in pixels is also challenging because then I need to > be able to determine when to recompute that number. Which is why I didn't suggest that. I suggested columns because they scale with text-scale-adjust. > >>>> If I set that correctly, then the pixel-size should adjust as the > >>>> text scales. It wouldn't handle the case where the actual font > >>>> changes though. > >>> > >>> Why not? > >> > >> I was planning to set :relative-width to <first_line_prefix_width> / > >> <width_of_one_space>. If the font changes, the result of that > >> calculation can change. > > > > The idea is to set it to the multiple of the character's width, which > > will then scale with the font. > > Imagine two fonts A and B, where the only difference is that the space > character in B is twice as wide. So: > > <asterisk_width> = 15 > <space_width_A> = 10 > <space_width_B> = 20 > <first_line_prefix_width_A> = 15 + 10 = 25 > <first_line_prefix_width_B> = 15 + 20 = 35 > > If I compute :relative-width for font A, the result is 25/10 = 2.5. Then, > > 2.5 * <space_width_A> = 25 = <first_line_prefix_width_A> (good) > 2.5 * <space_width_B> = 50 != <first_line_prefix_width_B> (bad!) > > So we'd need a way of keeping the width in-sync with any font changes. I don't understand the example. If these are two different paragraphs, then their indentation cannot be guaranteed to be the same anyway, because no one can assure you all the paragraphs will use the same font. So whatever you mean by <width_of_one_space>, it will always be different for different fonts, and I don't see how this can be solved for an arbitrary combination of fonts. So my suggestion is to go back to the simpler idea of using :align-to with an absolute value, either in pixels or in columns (which AFAIR is interpreted in units of the frame's default font's width), and if needed augment that by recalculation when necessary. ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-19 11:45 ` Eli Zaretskii @ 2024-06-19 19:53 ` Jim Porter 2024-06-20 4:58 ` Eli Zaretskii 0 siblings, 1 reply; 27+ messages in thread From: Jim Porter @ 2024-06-19 19:53 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 71605 On 6/19/2024 4:45 AM, Eli Zaretskii wrote: > If both the first line of the paragraph and the rest are aligned on > that width, they will all line up. IOW, the idea is to make the text > of all the lines :align-to to the same column number, like this: > > * some text > some other text > > Then you don't care about the actual pixel width of "* ". Just so I'm sure I understand this: the idea is that the buffer's contents are "* some text some other text" and then we set the :align-to property on "some text some other text" so that the result is displayed like this? +---- Here is the align-to column v * _some text ___some other text The underscores represent the space added by :align-to. In practice, the first line might not have any extra space from :align-to, but the pixel-width of "* " could be less than 2 * <canonical character width> for variable-pitch fonts. I think that would work, provided :align-to were fixed so that it could handle wrapping again. (And so long as we're ok with there being a bit of extra space after the first-line prefix when using some fonts, but I don't see why that would be an issue.) ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-19 19:53 ` Jim Porter @ 2024-06-20 4:58 ` Eli Zaretskii 2024-06-20 5:37 ` Jim Porter 0 siblings, 1 reply; 27+ messages in thread From: Eli Zaretskii @ 2024-06-20 4:58 UTC (permalink / raw) To: Jim Porter; +Cc: 71605 > Date: Wed, 19 Jun 2024 12:53:33 -0700 > Cc: 71605@debbugs.gnu.org > From: Jim Porter <jporterbugs@gmail.com> > > On 6/19/2024 4:45 AM, Eli Zaretskii wrote: > > If both the first line of the paragraph and the rest are aligned on > > that width, they will all line up. IOW, the idea is to make the text > > of all the lines :align-to to the same column number, like this: > > > > * some text > > some other text > > > > Then you don't care about the actual pixel width of "* ". > > Just so I'm sure I understand this: the idea is that the buffer's > contents are "* some text some other text" and then we set the :align-to > property on "some text some other text" so that the result is displayed > like this? > > +---- Here is the align-to column > v > * _some text > ___some other text Yes. > The underscores represent the space added by :align-to. In practice, the > first line might not have any extra space from :align-to, but the > pixel-width of "* " could be less than 2 * <canonical character width> > for variable-pitch fonts. The value calculated for :align-to needs to make sure that never happens. > I think that would work, provided :align-to were fixed so that it could > handle wrapping again. Stay tuned. > (And so long as we're ok with there being a bit of extra space after > the first-line prefix when using some fonts, but I don't see why > that would be an issue.) We _should_ be ok with some extra white space, because that's what I see in word processors all around me. Their indentation of the itemized lists always indents by more than just one SPC after the item symbol (bullet or number or letter). ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-20 4:58 ` Eli Zaretskii @ 2024-06-20 5:37 ` Jim Porter 2024-06-20 9:58 ` Eli Zaretskii 0 siblings, 1 reply; 27+ messages in thread From: Jim Porter @ 2024-06-20 5:37 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 71605 On 6/19/2024 9:58 PM, Eli Zaretskii wrote: >> I think that would work, provided :align-to were fixed so that it could >> handle wrapping again. > > Stay tuned. Thanks. No rush on this, since Emacs 30 takes priority over this small nice-to-have enhancement. (I do have a patch for EWW that would benefit from fixing this bug, but that too can wait.) ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-20 5:37 ` Jim Porter @ 2024-06-20 9:58 ` Eli Zaretskii 2024-06-20 17:36 ` Jim Porter 0 siblings, 1 reply; 27+ messages in thread From: Eli Zaretskii @ 2024-06-20 9:58 UTC (permalink / raw) To: Jim Porter; +Cc: 71605 > Date: Wed, 19 Jun 2024 22:37:33 -0700 > Cc: 71605@debbugs.gnu.org > From: Jim Porter <jporterbugs@gmail.com> > > On 6/19/2024 9:58 PM, Eli Zaretskii wrote: > >> I think that would work, provided :align-to were fixed so that it could > >> handle wrapping again. > > > > Stay tuned. > > Thanks. No rush on this, since Emacs 30 takes priority over this small > nice-to-have enhancement. (I do have a patch for EWW that would benefit > from fixing this bug, but that too can wait.) Should be fixed now on the master branch. ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-20 9:58 ` Eli Zaretskii @ 2024-06-20 17:36 ` Jim Porter 2024-06-20 18:08 ` Eli Zaretskii 0 siblings, 1 reply; 27+ messages in thread From: Jim Porter @ 2024-06-20 17:36 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 71605 On 6/20/2024 2:58 AM, Eli Zaretskii wrote: > Should be fixed now on the master branch. Thanks, it all seems to work now. I think I have a way forward to implement this that should avoid issues, though it's a bit more complex than I'd initially thought. I think there are three cases: "* here is some text": Text Properties "* " (display (min-width (2))) "here is some text" (wrap-prefix (space :align-to 2)) " here is some text": Text Properties " " (display "") " here is some text" (line-prefix (space :align-to 2) wrap-prefix (space :align-to 2)) "// here is some text" (in c-mode): Text Properties "// here is some text" (wrap-prefix "// ") (The last case is just doing what visual-wrap-prefix-mode currently does.) I'm pretty sure all these should be unproblematic in the scenarios Po Lu mentioned. The only case I haven't considered is how this interacts with 'visual-wrap-extra-indent'. I'll have to think about that some more. ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-20 17:36 ` Jim Porter @ 2024-06-20 18:08 ` Eli Zaretskii 2024-06-20 19:01 ` Jim Porter 0 siblings, 1 reply; 27+ messages in thread From: Eli Zaretskii @ 2024-06-20 18:08 UTC (permalink / raw) To: Jim Porter; +Cc: 71605 > Date: Thu, 20 Jun 2024 10:36:23 -0700 > Cc: 71605@debbugs.gnu.org > From: Jim Porter <jporterbugs@gmail.com> > > On 6/20/2024 2:58 AM, Eli Zaretskii wrote: > > Should be fixed now on the master branch. > > Thanks, it all seems to work now. Does this mean we can close this bug, or is there anything else to do here? ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-20 18:08 ` Eli Zaretskii @ 2024-06-20 19:01 ` Jim Porter 2024-07-28 4:53 ` Jim Porter 0 siblings, 1 reply; 27+ messages in thread From: Jim Porter @ 2024-06-20 19:01 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 71605 On 6/20/2024 11:08 AM, Eli Zaretskii wrote: > Does this mean we can close this bug, or is there anything else to do > here? I need to implement a new version of my patch that uses :align-to and such. So there are still things to do in this bug, but the :align-to issue that was blocking progress on this bug is now resolved. ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-20 19:01 ` Jim Porter @ 2024-07-28 4:53 ` Jim Porter 2024-08-02 7:27 ` Eli Zaretskii 0 siblings, 1 reply; 27+ messages in thread From: Jim Porter @ 2024-07-28 4:53 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 71605, Po Lu [-- Attachment #1: Type: text/plain, Size: 1252 bytes --] On 6/20/2024 12:01 PM, Jim Porter wrote: > On 6/20/2024 11:08 AM, Eli Zaretskii wrote: >> Does this mean we can close this bug, or is there anything else to do >> here? > > I need to implement a new version of my patch that uses :align-to and > such. So there are still things to do in this bug, but the :align-to > issue that was blocking progress on this bug is now resolved. After some time away from this bug, I've made a new version of this patch which uses ':align-to' to line up the wrapped lines. All of the text properties in this patch use widths defined in terms of the average width for the current face (using a spec like "(N . width)"), which I think should work correctly in all situations. I've also set the min-width of the first-line prefix to ensure everything lines up just right. That makes it easier to line things up this way, rather than my previous brittle attempts at computing the exact pixel width of the first-line prefix (that width can change for all sorts of reasons). Also attached is a test script I wrote to preview the effects of the patch. If you pass an additional numeric argument on the command line when loading it, it will set 'visual-wrap-extra-indent' so you can see how that affects things. [-- Attachment #2: 0001-Add-support-for-variable-pitch-fonts-in-visual-wrap-.patch --] [-- Type: text/plain, Size: 10149 bytes --] From 1509d9bf0acfab6ea486b96cd6765fc95ccf2b2b Mon Sep 17 00:00:00 2001 From: Jim Porter <jporterbugs@gmail.com> Date: Sat, 27 Jul 2024 20:48:38 -0700 Subject: [PATCH] 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. --- doc/lispref/display.texi | 6 +- etc/NEWS | 11 ++++ lisp/emacs-lisp/subr-x.el | 11 +++- lisp/visual-wrap.el | 114 ++++++++++++++++++++++++++------------ 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 @@ Size of Displayed Text meaning as with @code{window-text-pixel-size}. @end defun -@defun string-pixel-width string +@defun string-pixel-width string &optional buffer This is a convenience function that uses @code{window-text-pixel-size} -to compute the width of @var{string} (in pixels). +to compute the width of @var{string} (in pixels). If @var{buffer} is +non-@code{nil}, use any face remappings (@pxref{Face Remapping}) from +that buffer when computing the width of @var{string}. @end defun @defun line-pixel-height diff --git a/etc/NEWS b/etc/NEWS index c907ec40fa1..0c6cd9771e1 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -52,6 +52,12 @@ usual minibuffer history commands. Each command has a separate history. *** New language-environment and input method for Tifinagh. The Tifinagh script is used to write the Berber languages. +--- +** 'visual-wrap-prefix-mode' now supports variable-pitch fonts. +When using 'visual-wrap-prefix-mode' in buffers with variable-pitch +fonts, the wrapped text will now be lined up correctly so that it's +exactly below the text after the prefix on the first line. + \f * Changes in Specialized Modes and Packages in Emacs 31.1 @@ -194,6 +200,11 @@ authorize the invoked D-Bus method (for example via polkit). ** The customization group 'wp' has been removed. It has been obsolete since Emacs 26.1. Use the group 'text' instead. ++++ +** New optional BUFFER argument for 'string-pixel-width'. +If supplied, 'string-pixel-width' will use any face remappings from +BUFFER when computing the string's width. + \f * Changes in Emacs 31.1 on Non-Free Operating Systems 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 @@ named-let . ,aargs))) ;;;###autoload -(defun string-pixel-width (string) - "Return the width of STRING in pixels." +(defun string-pixel-width (string &optional buffer) + "Return the width of STRING in pixels. +If BUFFER is non-nil, use the face remappings from that buffer when +determining the width." (declare (important-return-value t)) (if (zerop (length string)) 0 @@ -352,6 +354,11 @@ string-pixel-width ;; Disable line-prefix and wrap-prefix, for the same reason. (setq line-prefix nil wrap-prefix nil) + (if buffer + (setq-local face-remapping-alist + (with-current-buffer buffer + face-remapping-alist)) + (kill-local-variable 'face-remapping-alist)) (insert (propertize string 'line-prefix nil 'wrap-prefix nil)) (car (buffer-text-pixel-size nil nil t))))) diff --git a/lisp/visual-wrap.el b/lisp/visual-wrap.el index d95cf4bb569..d2ceb0b17ca 100644 --- a/lisp/visual-wrap.el +++ b/lisp/visual-wrap.el @@ -97,24 +97,86 @@ visual-wrap--prefix-face (if (visual-wrap--face-extend-p f) f)) eol-face))))))) -(defun visual-wrap--prefix (fcp) - (let ((fcp-len (string-width fcp))) - (cond - ((= 0 visual-wrap-extra-indent) - fcp) - ((< 0 visual-wrap-extra-indent) - (concat fcp (make-string visual-wrap-extra-indent ?\s))) - ((< 0 (+ visual-wrap-extra-indent fcp-len)) - (substring fcp - 0 - (+ visual-wrap-extra-indent fcp-len))) - (t - "")))) +(defun visual-wrap--adjust-prefix (prefix) + "Adjust PREFIX with `visual-wrap-extra-indent'." + (if (numberp prefix) + (+ visual-wrap-extra-indent prefix) + (let ((prefix-len (string-width prefix))) + (cond + ((= 0 visual-wrap-extra-indent) + prefix) + ((< 0 visual-wrap-extra-indent) + (concat prefix (make-string visual-wrap-extra-indent ?\s))) + ((< 0 (+ visual-wrap-extra-indent prefix-len)) + (substring prefix + 0 (+ visual-wrap-extra-indent prefix-len))) + (t + ""))))) + +(defun visual-wrap--apply-to-line (position) + "Apply visual-wrapping properties to the logical line starting at POSITION." + (save-excursion + (goto-char position) + (let* ((first-line-prefix (fill-match-adaptive-prefix)) + (next-line-prefix (visual-wrap--content-prefix + first-line-prefix position))) + (when next-line-prefix + (when (numberp next-line-prefix) + (put-text-property + position (+ position (length first-line-prefix)) 'display + `(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 + (if (numberp next-line-prefix) + `(space :align-to (,next-line-prefix . width)) + next-line-prefix)))))) + +(defun visual-wrap--content-prefix (prefix position) + "Get the next-line prefix for the specified first-line PREFIX. +POSITION is the position in the buffer where PREFIX is located. + +This returns a string prefix to use for subsequent lines; an integer, +indicating the number of canonical-width spaces to use; or nil, if +PREFIX was empty." + (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 + (string-match comment-start-skip prefix))) + ;; If we want to repeat the first-line prefix on subsequent lines, + ;; return its string value. However, we remove any `wrap-prefix' + ;; property that might have been added earlier. Otherwise, we end + ;; up with a string containing a `wrap-prefix' string containing a + ;; `wrap-prefix' string... + (remove-text-properties 0 (length prefix) '(wrap-prefix) prefix) + prefix) + (t + ;; Otherwise, we want the prefix to be whitespace of the same width + ;; as the first-line prefix. If possible, compute the real pixel + ;; width of the first-line prefix in canonical-width characters. + ;; This is useful if the first-line prefix uses some very-wide + ;; characters. + (if-let ((font (font-at position)) + (info (query-font font))) + (max (string-width prefix) + (ceiling (string-pixel-width prefix (current-buffer)) + (aref info 7))) + (string-width prefix))))) (defun visual-wrap-fill-context-prefix (beg end) "Compute visual wrap prefix from text between BEG and END. This is like `fill-context-prefix', but with prefix length adjusted by `visual-wrap-extra-indent'." + (declare (obsolete nil "31.1")) (let* ((fcp ;; `fill-context-prefix' ignores prefixes that look like ;; paragraph starts, in order to avoid inadvertently @@ -128,7 +190,7 @@ visual-wrap-fill-context-prefix ;; Note: fill-context-prefix may return nil; See: ;; http://article.gmane.org/gmane.emacs.devel/156285 "")) - (prefix (visual-wrap--prefix fcp)) + (prefix (visual-wrap--adjust-prefix fcp)) (face (visual-wrap--prefix-face fcp beg end))) (if face (propertize prefix 'face face) @@ -147,28 +209,8 @@ visual-wrap-prefix-function (forward-line 0) (setq beg (point)) (while (< (point) end) - (let ((lbp (point))) - (put-text-property - (point) (progn (search-forward "\n" end 'move) (point)) - 'wrap-prefix - (let ((pfx (visual-wrap-fill-context-prefix - lbp (point)))) - ;; Remove any `wrap-prefix' property that might have been - ;; added earlier. Otherwise, we end up with a string - ;; containing a `wrap-prefix' string containing a - ;; `wrap-prefix' string ... - (remove-text-properties - 0 (length pfx) '(wrap-prefix) pfx) - (let ((dp (get-text-property 0 'display pfx))) - (when (and dp (eq dp (get-text-property (1- lbp) 'display))) - ;; There's a `display' property which covers not just the - ;; prefix but also the previous newline. So it's not - ;; just making the prefix more pretty and could interfere - ;; or even defeat our efforts (e.g. it comes from - ;; `adaptive-fill-mode'). - (remove-text-properties - 0 (length pfx) '(display) pfx))) - pfx)))) + (visual-wrap--apply-to-line (point)) + (forward-line)) `(jit-lock-bounds ,beg . ,end)) ;;;###autoload -- 2.25.1 [-- Attachment #3: wrap.el --] [-- Type: text/plain, Size: 676 bytes --] (switch-to-buffer (get-buffer-create "demo")) (buffer-face-set 'variable-pitch) (setq words "Voluptatem est nostrum impedit nesciunt eum. Recusandae voluptatem quaerat hic harum. Consequatur in fuga nihil aliquid commodi rem sunt. Aperiam odio odio amet.") (insert words "\n\n") (insert " " words "\n\n") (insert "* " words "\n\n") (insert "## " words "\n\n") (insert (propertize (concat "## " words "\n") 'face '(:background "red" :height 300))) (goto-char (point-min)) (setq extra-indent (pop command-line-args-left)) (when extra-indent (setq visual-wrap-extra-indent (string-to-number extra-indent))) (visual-line-mode) (visual-wrap-prefix-mode) ^ permalink raw reply related [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-07-28 4:53 ` Jim Porter @ 2024-08-02 7:27 ` Eli Zaretskii 2024-08-04 19:24 ` Jim Porter 0 siblings, 1 reply; 27+ messages in thread From: Eli Zaretskii @ 2024-08-02 7:27 UTC (permalink / raw) To: Jim Porter; +Cc: 71605, luangruo > Date: Sat, 27 Jul 2024 21:53:25 -0700 > From: Jim Porter <jporterbugs@gmail.com> > Cc: 71605@debbugs.gnu.org, Po Lu <luangruo@yahoo.com> > > On 6/20/2024 12:01 PM, Jim Porter wrote: > > On 6/20/2024 11:08 AM, Eli Zaretskii wrote: > >> Does this mean we can close this bug, or is there anything else to do > >> here? > > > > I need to implement a new version of my patch that uses :align-to and > > such. So there are still things to do in this bug, but the :align-to > > issue that was blocking progress on this bug is now resolved. > > After some time away from this bug, I've made a new version of this > patch which uses ':align-to' to line up the wrapped lines. All of the > text properties in this patch use widths defined in terms of the average > width for the current face (using a spec like "(N . width)"), which I > think should work correctly in all situations. > > I've also set the min-width of the first-line prefix to ensure > everything lines up just right. That makes it easier to line things up > this way, rather than my previous brittle attempts at computing the > exact pixel width of the first-line prefix (that width can change for > all sorts of reasons). > > Also attached is a test script I wrote to preview the effects of the > patch. If you pass an additional numeric argument on the command line > when loading it, it will set 'visual-wrap-extra-indent' so you can see > how that affects things. LGTM, thanks. Feel free to install on master. ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-08-02 7:27 ` Eli Zaretskii @ 2024-08-04 19:24 ` Jim Porter 0 siblings, 0 replies; 27+ messages in thread From: Jim Porter @ 2024-08-04 19:24 UTC (permalink / raw) To: Eli Zaretskii; +Cc: 71605-done, luangruo On 8/2/2024 12:27 AM, Eli Zaretskii wrote: > LGTM, thanks. Feel free to install on master. Thanks, merged to master as f70a6ea0ea8. Hopefully this patch maintains all the existing correct behaviors and fixes most of the issues with variable-pitch text. To summarize, this is how things *should* behave (anything else is probably a mistake; just let me know and I'll try to fix it): 1. With fixed-pitch fonts, everything should look the same as before. 2. With variable-pitch fonts in a terminal frame, everything should look the same as before, but... a. If you then open that buffer in a GUI frame, there's a small chance that the first line of a bulleted list will be too wide. This can happen if the prefix contains wider-than-average characters in the specified font. 3. With variable-pitch fonts in a GUI frame, wrapped lines in bulleted lists and the like should now lined up correctly in GUI , but... a. The first line might have a bit of extra space after the bullet. (The space occupied by "* " or what-have-you is rounded up to an integer number of canonical-width spaces.) b. If you then open that same buffer in a terminal frame, there's a small chance that the text after the bullet will have an extra space (same with the wrapped text). This can happen if the prefix contains wider-than-average characters in the specified font. c. If you change the font of the wrapped text to something with different metrics, there's a small chance that the first line of a bulleted list will be too wide. 2a and 3b would probably be fixable by using overlays restricted to a particular window. 3c would probably be fixable by calling 'jit-lock-refontify' at the appropriate time. While that's quite a few caveats with the current implementation, I think overall they should only come up in rare cases, and should never affect fixed-pitch text (which is the only thing 'visual-wrap-prefix-mode' could work correctly with before). ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-17 2:56 bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' Jim Porter 2024-06-17 11:37 ` Eli Zaretskii @ 2024-06-17 14:23 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-06-17 16:13 ` Jim Porter 1 sibling, 1 reply; 27+ messages in thread From: Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-06-17 14:23 UTC (permalink / raw) To: Jim Porter; +Cc: 71605 Jim Porter <jporterbugs@gmail.com> writes: > (Note: I plan to merge this only after we cut the Emacs 30 release > branch, since it seems a bit too substantial a change to sneak in > right near the end. However, I think the patch is mostly done aside > from one remaining issue, so any feedback is very welcome.) > > 'visual-wrap-prefix-mode' has one small issue: since the wrap prefix > is just a string, the wrapped text may not line up for variable-width > fonts. This is mainly in cases like so: > > * here is some text that > got visually wrapped > > If the "* " is variable-width, the second line will probably be > indented wrong by a few pixels. > > The attached patch adds a display spec in this case so that the text > lines up perfectly. There's currently one problem though: I'm not sure > how to regenerate the wrap prefix automatically if the face > changes. It's not hard to handle for 'text-scale-adjust', but I don't Actually, there's more than just this one problem. To start with, the existing format of the generated line prefix properties enables the extracted fill prefix to be displayed consistently on any frame, whatever the metrics of its default font/face. This I consider a far more critical capability than perfect alignment of wrapped text in the presence of a variable-pitch default font, as the latter is virtually unknown among programmers, and also unimplementable within reasonable standards of performance with pixelwise spacers. If this is to be installed, please condition it behind a user option and restore the existing logic that you have effaced as the default. ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-17 14:23 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-06-17 16:13 ` Jim Porter 2024-06-17 18:17 ` Jim Porter 0 siblings, 1 reply; 27+ messages in thread From: Jim Porter @ 2024-06-17 16:13 UTC (permalink / raw) To: Po Lu; +Cc: 71605 On 6/17/2024 7:23 AM, Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors wrote: > Actually, there's more than just this one problem. To start with, the > existing format of the generated line prefix properties enables the > extracted fill prefix to be displayed consistently on any frame, > whatever the metrics of its default font/face. This I consider a far > more critical capability than perfect alignment of wrapped text in the > presence of a variable-pitch default font, as the latter is virtually > unknown among programmers, and also unimplementable within reasonable > standards of performance with pixelwise spacers. That's a good point. In practice, we should only do this if the first-line prefix uses a variable-pitch font, since otherwise we might as well just use the requisite number of space characters as before, sans display-spec. > If this is to be > installed, please condition it behind a user option and restore the > existing logic that you have effaced as the default. I'll add a check for variable-pitch fonts and a user option. With the variable-pitch check, I think it should be ok for the user option to default to enabling this new behavior? For fixed-pitch fonts, the new code would behave the same as before regardless of the option. Note that I haven't removed any of the old logic though; it's all there as before, since the space characters are useful for terminals (where the pixelwise :width display-spec doesn't do anything for us, if I understand correctly). I did extract parts of 'fill-content-prefix' into 'visual-wrap--content-prefix', but the only parts I removed were the ones for handling multiple lines; those don't apply here, since 'visual-wrap-prefix-function' gets the prefixes one line at a time. ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-17 16:13 ` Jim Porter @ 2024-06-17 18:17 ` Jim Porter 2024-06-17 19:55 ` Eli Zaretskii 0 siblings, 1 reply; 27+ messages in thread From: Jim Porter @ 2024-06-17 18:17 UTC (permalink / raw) To: Po Lu; +Cc: 71605 On 6/17/2024 9:13 AM, Jim Porter wrote: > Note that I haven't removed any of the old logic though; it's all there > as before, since the space characters are useful for terminals (where > the pixelwise :width display-spec doesn't do anything for us, if I > understand correctly). Evidently I wasn't understanding this correctly, since further testing and consulting the code shows that the :width display-spec works just fine on terminals. It does make it harder to get this patch working well though... Maybe :align-to could be made to work. It doesn't seem to work at all for me, even in a minimal test case like calling this on a long line of text: (put-text-property (point-min) (point-max) 'wrap-prefix '(space :align-to 4)) Replacing :align-to with :width works just fine though. It's entirely possible I'm just doing something wrong, but maybe this is a bug? (Now what would be great is if :align-to supported a *string* value that meant "use the pixel-width of this string". Which actually gives me an idea... what if the wrap-prefix is just the original text like "* " and we fontify it to be invisible? It's not part of the buffer and you can't select it anyway, so it doesn't really matter what the text is so long as it's not visible.) ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-17 18:17 ` Jim Porter @ 2024-06-17 19:55 ` Eli Zaretskii 2024-06-17 20:08 ` Jim Porter 0 siblings, 1 reply; 27+ messages in thread From: Eli Zaretskii @ 2024-06-17 19:55 UTC (permalink / raw) To: Jim Porter; +Cc: luangruo, 71605 > Cc: 71605@debbugs.gnu.org > Date: Mon, 17 Jun 2024 11:17:45 -0700 > From: Jim Porter <jporterbugs@gmail.com> > > Maybe :align-to could be made to work. It doesn't seem to work at all > for me, even in a minimal test case like calling this on a long line of > text: > > (put-text-property (point-min) (point-max) 'wrap-prefix '(space > :align-to 4)) > > Replacing :align-to with :width works just fine though. It's entirely > possible I'm just doing something wrong, but maybe this is a bug? It's a bug in Emacs 29 and Emacs 30. It works in Emacs 27. > (Now what would be great is if :align-to supported a *string* value that > meant "use the pixel-width of this string". It's already possible: just have a variable that holds the width, and use it in the :align-to expression. > Which actually gives me an > idea... what if the wrap-prefix is just the original text like "* " and > we fontify it to be invisible? It's not part of the buffer and you can't > select it anyway, so it doesn't really matter what the text is so long > as it's not visible.) I don't think I follow: how is this relevant to the issue at hand? ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-17 19:55 ` Eli Zaretskii @ 2024-06-17 20:08 ` Jim Porter 2024-06-18 3:02 ` Jim Porter 2024-06-18 12:39 ` Eli Zaretskii 0 siblings, 2 replies; 27+ messages in thread From: Jim Porter @ 2024-06-17 20:08 UTC (permalink / raw) To: Eli Zaretskii; +Cc: luangruo, 71605 On 6/17/2024 12:55 PM, Eli Zaretskii wrote: >> Cc: 71605@debbugs.gnu.org >> Date: Mon, 17 Jun 2024 11:17:45 -0700 >> From: Jim Porter <jporterbugs@gmail.com> >> >> Replacing :align-to with :width works just fine though. It's entirely >> possible I'm just doing something wrong, but maybe this is a bug? > > It's a bug in Emacs 29 and Emacs 30. It works in Emacs 27. Ah, that explains it. >> (Now what would be great is if :align-to supported a *string* value that >> meant "use the pixel-width of this string". > > It's already possible: just have a variable that holds the width, and > use it in the :align-to expression. That would make the code simpler, but I'd still need to figure out when to reevaluate the variable to update things. >> Which actually gives me an >> idea... what if the wrap-prefix is just the original text like "* " and >> we fontify it to be invisible? It's not part of the buffer and you can't >> select it anyway, so it doesn't really matter what the text is so long >> as it's not visible.) > > I don't think I follow: how is this relevant to the issue at hand? I was thinking you could wrap "* this is some text" like so: * this is * some text The second "* " would come from the wrap-prefix, but we'd make the foreground transparent (or the same color as the background) so it wouldn't be visible. Then it would always take up the same width as the first "* " because it's the same string with the same font and everything. ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-17 20:08 ` Jim Porter @ 2024-06-18 3:02 ` Jim Porter 2024-06-18 6:27 ` Jim Porter 2024-06-18 12:39 ` Eli Zaretskii 1 sibling, 1 reply; 27+ messages in thread From: Jim Porter @ 2024-06-18 3:02 UTC (permalink / raw) To: Eli Zaretskii; +Cc: luangruo, 71605 On 6/17/2024 1:08 PM, Jim Porter wrote: > On 6/17/2024 12:55 PM, Eli Zaretskii wrote: >>> Cc: 71605@debbugs.gnu.org >>> Date: Mon, 17 Jun 2024 11:17:45 -0700 >>> From: Jim Porter <jporterbugs@gmail.com> >>> >>> Replacing :align-to with :width works just fine though. It's entirely >>> possible I'm just doing something wrong, but maybe this is a bug? >> >> It's a bug in Emacs 29 and Emacs 30. It works in Emacs 27. > > Ah, that explains it. Just so others are aware I'm going to try and bisect this. I'll report back when it's finished. ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-18 3:02 ` Jim Porter @ 2024-06-18 6:27 ` Jim Porter 2024-06-18 12:53 ` Eli Zaretskii 0 siblings, 1 reply; 27+ messages in thread From: Jim Porter @ 2024-06-18 6:27 UTC (permalink / raw) To: Eli Zaretskii; +Cc: luangruo, 71605 On 6/17/2024 8:02 PM, Jim Porter wrote: > Just so others are aware I'm going to try and bisect this. I'll report > back when it's finished. Looks like this is the commit that regressed this: commit fb3d582e7ba595b7680e2c2adf22c7ab699e5792 Author: Eli Zaretskii <eliz@gnu.org> Date: Wed Jun 29 20:15:36 2022 +0300 Fix hscrolling of :align-to when display-line-numbers is in effect * src/dispextern.h (struct it): Rename 'tab_offset' member to 'stretch_adjust'. * src/xdisp.c (gui_produce_glyphs, produce_stretch_glyph) (display_line): All users of 'tab_offset' changed. (produce_stretch_glyph): Fix calculation of ':align-to' when line numbers are displayed and the window is hscrolled. (calc_pixel_width_or_height): Fix calculation of width of 'space' display property when 'display-line-numbers' is turned on, but the line number was not yet produced for the current glyph row. (Bug#56176) I'll take a look in more detail tomorrow, but if anyone else wants to fix this, go ahead. I also have a bit of Elisp that checks whether this feature works, and I should be able to make it into a proper regression test with a bit of work. ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-18 6:27 ` Jim Porter @ 2024-06-18 12:53 ` Eli Zaretskii 0 siblings, 0 replies; 27+ messages in thread From: Eli Zaretskii @ 2024-06-18 12:53 UTC (permalink / raw) To: Jim Porter; +Cc: luangruo, 71605 > Date: Mon, 17 Jun 2024 23:27:49 -0700 > From: Jim Porter <jporterbugs@gmail.com> > Cc: luangruo@yahoo.com, 71605@debbugs.gnu.org > > On 6/17/2024 8:02 PM, Jim Porter wrote: > > Just so others are aware I'm going to try and bisect this. I'll report > > back when it's finished. > > Looks like this is the commit that regressed this: > > > commit fb3d582e7ba595b7680e2c2adf22c7ab699e5792 > Author: Eli Zaretskii <eliz@gnu.org> > Date: Wed Jun 29 20:15:36 2022 +0300 > > Fix hscrolling of :align-to when display-line-numbers is in effect > > * src/dispextern.h (struct it): Rename 'tab_offset' member to > 'stretch_adjust'. > * src/xdisp.c (gui_produce_glyphs, produce_stretch_glyph) > (display_line): All users of 'tab_offset' changed. > (produce_stretch_glyph): Fix calculation of ':align-to' when > line numbers are displayed and the window is hscrolled. > (calc_pixel_width_or_height): Fix calculation of width of 'space' > display property when 'display-line-numbers' is turned on, but the > line number was not yet produced for the current glyph row. > (Bug#56176) Thanks. Unfortunately, it means the current behavior is not a bug, but rather an unintended consequence of another bugfix. The above changeset changed :align-to to count from the beginning of the physical line, not the screen line. So, for example, if you have an 80-column line, the continuation line begins from column 80, not 0. Thus, something like ':align-to 4' will never work on continuation lines, because we got past column 4 long ago... So I need to think whether and how to restore the capability of using :align-to in wrap-prefix. ^ permalink raw reply [flat|nested] 27+ messages in thread
* bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' 2024-06-17 20:08 ` Jim Porter 2024-06-18 3:02 ` Jim Porter @ 2024-06-18 12:39 ` Eli Zaretskii 1 sibling, 0 replies; 27+ messages in thread From: Eli Zaretskii @ 2024-06-18 12:39 UTC (permalink / raw) To: Jim Porter; +Cc: luangruo, 71605 > Date: Mon, 17 Jun 2024 13:08:47 -0700 > Cc: luangruo@yahoo.com, 71605@debbugs.gnu.org > From: Jim Porter <jporterbugs@gmail.com> > > >> Which actually gives me an > >> idea... what if the wrap-prefix is just the original text like "* " and > >> we fontify it to be invisible? It's not part of the buffer and you can't > >> select it anyway, so it doesn't really matter what the text is so long > >> as it's not visible.) > > > > I don't think I follow: how is this relevant to the issue at hand? > > I was thinking you could wrap "* this is some text" like so: > > * this is > * some text > > The second "* " would come from the wrap-prefix, but we'd make the > foreground transparent (or the same color as the background) so it > wouldn't be visible. Then it would always take up the same width as the > first "* " because it's the same string with the same font and everything. If it's transparent, some change in the faces could reveal it, which I think will be perceived as a bug. And invisible text cannot take up screen estate, so I'm not sure how would that help... ^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2024-08-04 19:24 UTC | newest] Thread overview: 27+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-06-17 2:56 bug#71605: 30.0.50; [PATCH] Support variable-width text in 'visual-wrap-prefix-mode' Jim Porter 2024-06-17 11:37 ` Eli Zaretskii 2024-06-17 17:42 ` Jim Porter 2024-06-17 18:20 ` Eli Zaretskii 2024-06-17 18:44 ` Jim Porter 2024-06-18 11:37 ` Eli Zaretskii 2024-06-18 22:17 ` Jim Porter 2024-06-19 11:45 ` Eli Zaretskii 2024-06-19 19:53 ` Jim Porter 2024-06-20 4:58 ` Eli Zaretskii 2024-06-20 5:37 ` Jim Porter 2024-06-20 9:58 ` Eli Zaretskii 2024-06-20 17:36 ` Jim Porter 2024-06-20 18:08 ` Eli Zaretskii 2024-06-20 19:01 ` Jim Porter 2024-07-28 4:53 ` Jim Porter 2024-08-02 7:27 ` Eli Zaretskii 2024-08-04 19:24 ` Jim Porter 2024-06-17 14:23 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors 2024-06-17 16:13 ` Jim Porter 2024-06-17 18:17 ` Jim Porter 2024-06-17 19:55 ` Eli Zaretskii 2024-06-17 20:08 ` Jim Porter 2024-06-18 3:02 ` Jim Porter 2024-06-18 6:27 ` Jim Porter 2024-06-18 12:53 ` Eli Zaretskii 2024-06-18 12:39 ` Eli Zaretskii
Code repositories for project(s) associated with this external index https://git.savannah.gnu.org/cgit/emacs.git https://git.savannah.gnu.org/cgit/emacs/org-mode.git This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.