* Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functions in C @ 2024-10-23 5:01 Jimmy Yuen Ho Wong 2024-10-23 8:01 ` Eli Zaretskii 0 siblings, 1 reply; 17+ messages in thread From: Jimmy Yuen Ho Wong @ 2024-10-23 5:01 UTC (permalink / raw) To: Emacs-Devel devel [-- Attachment #1: Type: text/plain, Size: 1815 bytes --] Dear emacs-devel, Recently I've been trying to mold Corfu <https://github.com/minad/corfu/pull/508> to render every string in every face in pixel precision but I've run into some slight performance issues when truncating strings. The motivation for this is `truncate-string-to-width` not only does not speak pixels, but also doesn't understand composed characters such as emojis. It just chops off the emoji byte sequence in the middle as described in the PR, so I had to write a custom `truncate-string-to-pixel-width` function using `string-glyph-split` and `string-pixel-width` to measure character widths, which seems... silly. I've looked into how to get the width of a glyph from a font object by employing some dark magic of undocumented internal functions and wrongly documented functions such as `char-displayable-p`, `font-info`, `lglyth-width`, `lgstring-glyph`, `open-font` etc in combination of `composition-get-gstring`, which is correct and fast enough.... for glyph strings with no faces. Then I looked into reverse engineering the face font selection process, which quickly pushed the run time up 2 orders of magnitude due to the anonymous face + face attribute inheritance + face lists madness. Then when I realized I still didn't deal with display text properties, I threw my hands up. It'd be really nice if we could have a really performant C function that can truncate strings correctly and preferably in pixel precision. Alternatively, a `glyph-pixel-width` that implements a fast path in C that's somewhat akin to the process I described above, but also handles display text properties correctly would be nice. I don't really know enough about Emacs C internals WRT to font rendering to implement this so I'm just throwing this idea out there. Does this make sense? Jimmy Yuen Ho Wong [-- Attachment #2: Type: text/html, Size: 2224 bytes --] ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functions in C 2024-10-23 5:01 Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functions in C Jimmy Yuen Ho Wong @ 2024-10-23 8:01 ` Eli Zaretskii 2024-10-23 13:52 ` Jimmy Yuen Ho Wong 0 siblings, 1 reply; 17+ messages in thread From: Eli Zaretskii @ 2024-10-23 8:01 UTC (permalink / raw) To: Jimmy Yuen Ho Wong; +Cc: emacs-devel > From: Jimmy Yuen Ho Wong <wyuenho@gmail.com> > Date: Wed, 23 Oct 2024 06:01:18 +0100 > > Recently I've been trying to mold Corfu to render every string in every face in pixel precision but I've run into > some slight performance issues when truncating strings. The motivation for this is `truncate-string-to-width` > not only does not speak pixels, but also doesn't understand composed characters such as emojis. It just > chops off the emoji byte sequence in the middle as described in the PR, so I had to write a custom > `truncate-string-to-pixel-width` function using `string-glyph-split` and `string-pixel-width` to measure character > widths, which seems... silly. > > I've looked into how to get the width of a glyph from a font object by employing some dark magic of > undocumented internal functions and wrongly documented functions such as `char-displayable-p`, `font-info`, > `lglyth-width`, `lgstring-glyph`, `open-font` etc in combination of `composition-get-gstring`, which is correct and > fast enough.... for glyph strings with no faces. Then I looked into reverse engineering the face font selection > process, which quickly pushed the run time up 2 orders of magnitude due to the anonymous face + face > attribute inheritance + face lists madness. Then when I realized I still didn't deal with display text properties, I > threw my hands up. > > It'd be really nice if we could have a really performant C function that can truncate strings correctly and > preferably in pixel precision. Alternatively, a `glyph-pixel-width` that implements a fast path in C that's > somewhat akin to the process I described above, but also handles display text properties correctly would be > nice. > > I don't really know enough about Emacs C internals WRT to font rendering to implement this so I'm just > throwing this idea out there. I know next to nothing about Corfu, so I have hard time understanding what you are trying to do and why. Basically, the Emacs display engine already truncates stuff it displays, so it is completely unclear to me why you'd need to do that in Lisp. In particular, "truncate strings in pixel precision" makes no sense to me, since strings on display are made of characters (more accurately, "grapheme clusters"), so any reasonable truncation will always work at the grapheme-cluster granularity, not at pixel granularity. So please describe your problem in much more detail, assuming that I know nothing about Corfu and its display-related tricks. Thanks. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functions in C 2024-10-23 8:01 ` Eli Zaretskii @ 2024-10-23 13:52 ` Jimmy Yuen Ho Wong 2024-10-23 17:39 ` Eli Zaretskii 0 siblings, 1 reply; 17+ messages in thread From: Jimmy Yuen Ho Wong @ 2024-10-23 13:52 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel [-- Attachment #1: Type: text/plain, Size: 1689 bytes --] On Wed, Oct 23, 2024 at 9:01 AM Eli Zaretskii <eliz@gnu.org> wrote: > I know next to nothing about Corfu, so I have hard time understanding > what you are trying to do and why. Basically, the Emacs display > engine already truncates stuff it displays, so it is completely > unclear to me why you'd need to do that in Lisp. > Corfu is like Company, it's a completion frontend that formats a list of completion candidates to fit inside a confined pop up box. > In particular, "truncate strings in pixel precision" makes no sense to > me, since strings on display are made of characters (more accurately, > "grapheme clusters"), so any reasonable truncation will always work at > the grapheme-cluster granularity, not at pixel granularity. > As described, `truncate-string-to-width` doesn't even truncate at grapheme cluster granularity correctly. A `truncate-string-to-pixel-width` function is needed because propertized strings may consist of display space text properties, images, emojis in a different font, and faces in variable fonts, which all affect glyph widths, you can't simply assume every glyph will take up 1 column. As a result, when you calculate some `end-column` and whether it has reached the width constraint in pixels, one would necessarily need to know the exact width in pixels for each glyph. Converting the width constraint in pixels to columns in order to supply it as the second parameter to a correctly implemented `truncate-string-to-width` amounts to the exact same procedure. Therefore, either a `truncate-string-to-pixel-width` or `glyph-pixel-width` function is needed, because `string-pixel-width` is very expensive. [-- Attachment #2: Type: text/html, Size: 2282 bytes --] ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functions in C 2024-10-23 13:52 ` Jimmy Yuen Ho Wong @ 2024-10-23 17:39 ` Eli Zaretskii 2024-10-23 20:03 ` Jimmy Yuen Ho Wong 0 siblings, 1 reply; 17+ messages in thread From: Eli Zaretskii @ 2024-10-23 17:39 UTC (permalink / raw) To: Jimmy Yuen Ho Wong; +Cc: emacs-devel > From: Jimmy Yuen Ho Wong <wyuenho@gmail.com> > Date: Wed, 23 Oct 2024 14:52:53 +0100 > Cc: emacs-devel@gnu.org > > On Wed, Oct 23, 2024 at 9:01 AM Eli Zaretskii <eliz@gnu.org> wrote: > > I know next to nothing about Corfu, so I have hard time understanding > what you are trying to do and why. Basically, the Emacs display > engine already truncates stuff it displays, so it is completely > unclear to me why you'd need to do that in Lisp. > > Corfu is like Company, it's a completion frontend that formats a list of completion candidates to fit inside a > confined pop up box. Thanks, but that doesn't explain enough. Please tell more about the need to truncate completion candidates "inside a confined pop up box". If that box is displayed, why doesn't Emacs truncate the text automatically? Or maybe I don't understand how this "pop up box", whatever it is, is displayed? > A `truncate-string-to-pixel-width` function is needed because propertized strings may consist of display space > text properties, images, emojis in a different font, and faces in variable fonts, which all affect glyph widths, you > can't simply assume every glyph will take up 1 column. As a result, when you calculate some `end-column` > and whether it has reached the width constraint in pixels, one would necessarily need to know the exact width > in pixels for each glyph. Converting the width constraint in pixels to columns in order to supply it as the second > parameter to a correctly implemented `truncate-string-to-width` amounts to the exact same procedure. > Therefore, either a `truncate-string-to-pixel-width` or `glyph-pixel-width` function is needed, because > `string-pixel-width` is very expensive. So the issue is not "pixel-wise truncation", the issue is to take variable-width display elements into account when truncating, is that right? ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functions in C 2024-10-23 17:39 ` Eli Zaretskii @ 2024-10-23 20:03 ` Jimmy Yuen Ho Wong 2024-10-24 9:55 ` Eli Zaretskii 0 siblings, 1 reply; 17+ messages in thread From: Jimmy Yuen Ho Wong @ 2024-10-23 20:03 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel [-- Attachment #1: Type: text/plain, Size: 1653 bytes --] > > Thanks, but that doesn't explain enough. Please tell more about the > need to truncate completion candidates "inside a confined pop up box". > If that box is displayed, why doesn't Emacs truncate the text > automatically? Or maybe I don't understand how this "pop up box", > whatever it is, is displayed? Each completion in a list of completion candidates is a triple of (candidate string, prefix, annotation), all in varying widths. Aligning these 3 columns requires calculating paddings. Since there are paddings, the padding between the candidate string and the annotation can also be arbitrarily large. Naive truncation that truncates the entire concatenated line against the width of the pop up box, which is actually the window width in a child frame, may leave some arbitrarily long empty space in the end. In addition, naive truncation does not replace extra characters in the relevant columns with ellipses to indicate truncation happened. Please look at the link in my first email for further details. > So the issue is not "pixel-wise truncation", the issue is to take > variable-width display elements into account when truncating, is that > right? > To be precise, by " truncate strings correctly and preferably in pixel precision", I mean truncation that respects pixel width constraints (and grapheme clusters, as clarified by you). Truncating variable-width display elements on GUIs necessitate the ability to calculate the widths of the individual elements, I call this the hypothetical `glyph-pixel-width`. Whether it is exposed to Elisp is less important to a hypothetical `truncate-string-to-pixel-width` for my use case. [-- Attachment #2: Type: text/html, Size: 2107 bytes --] ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functions in C 2024-10-23 20:03 ` Jimmy Yuen Ho Wong @ 2024-10-24 9:55 ` Eli Zaretskii 2024-10-24 14:26 ` Jimmy Yuen Ho Wong 0 siblings, 1 reply; 17+ messages in thread From: Eli Zaretskii @ 2024-10-24 9:55 UTC (permalink / raw) To: Jimmy Yuen Ho Wong; +Cc: emacs-devel > From: Jimmy Yuen Ho Wong <wyuenho@gmail.com> > Date: Wed, 23 Oct 2024 21:03:55 +0100 > Cc: emacs-devel@gnu.org > > Each completion in a list of completion candidates is a triple of (candidate string, prefix, annotation), all in > varying widths. Aligning these 3 columns requires calculating paddings. Since there are paddings, the > padding between the candidate string and the annotation can also be arbitrarily large. Naive truncation that > truncates the entire concatenated line against the width of the pop up box, which is actually the window width > in a child frame, may leave some arbitrarily long empty space in the end. In addition, naive truncation does > not replace extra characters in the relevant columns with ellipses to indicate truncation happened. Please look > at the link in my first email for further details. > > So the issue is not "pixel-wise truncation", the issue is to take > variable-width display elements into account when truncating, is that > right? > > To be precise, by " truncate strings correctly and preferably in pixel precision", I mean truncation that respects > pixel width constraints (and grapheme clusters, as clarified by you). Truncating variable-width display > elements on GUIs necessitate the ability to calculate the widths of the individual elements, I call this the > hypothetical `glyph-pixel-width`. Whether it is exposed to Elisp is less important to a hypothetical > `truncate-string-to-pixel-width` for my use case. OK, thanks. So let me see if I understand the issue. You want to create in a child frame a display such as below: <icon1><candidate1> <Type1> <icon2><longer-name-candidate> <AnotherType> ... And you want to do it in a way that all the "Type"s are aligned to the right (i.e. end at the right edge of the frame), no matter what is shown in the <icon>s and in the <candidate>s, which could be of different width and could include characters of different fonts and even images/emoji. Is that correct, or is there something else? If the above is what you want, and since the popup is actually a frame, my first suggestion would be to use :align-to display property on the whitespace between the <candidate>s and the <Type>s. Did you try that? The advantage of :align-to is that you don't have to measure the pixel-width of the candidate names, only the pixel-width of each <Type> string (to correctly set up the offset from the right edge of the text area) -- the rest will be done by the display engine. And the display engine always does everything in pixel resolution. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functions in C 2024-10-24 9:55 ` Eli Zaretskii @ 2024-10-24 14:26 ` Jimmy Yuen Ho Wong 2024-10-24 14:39 ` Eli Zaretskii 0 siblings, 1 reply; 17+ messages in thread From: Jimmy Yuen Ho Wong @ 2024-10-24 14:26 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel [-- Attachment #1: Type: text/plain, Size: 1717 bytes --] > > So let me see if I understand the issue. You want to create in a > child frame a display such as below: > > <icon1><candidate1> <Type1> > <icon2><longer-name-candidate> <AnotherType> > ... > > And you want to do it in a way that all the "Type"s are aligned to the > right (i.e. end at the right edge of the frame), no matter what is > shown in the <icon>s and in the <candidate>s, which could be of > different width and could include characters of different fonts and > even images/emoji. Is that correct, or is there something else? > > If the above is what you want, and since the popup is actually a > frame, my first suggestion would be to use :align-to display property > on the whitespace between the <candidate>s and the <Type>s. Did you > try that? > > The advantage of :align-to is that you don't have to measure the > pixel-width of the candidate names, only the pixel-width of each > <Type> string (to correctly set up the offset from the right edge of > the text area) -- the rest will be done by the display engine. And > the display engine always does everything in pixel resolution. > The current implementation wraps every line with some additional margin and a custom thin scrollbar after formatting, both are propertized strings with a display space property, before giving the final result to a buffer and then the child frame. Letting the windowing system to do truncation will truncate off the custom scrollbar and margin first, in addition to breaking an existing API that downstream extension packages rely on and being a much larger refactoring that will bring forth the much thicker and intrusive default Emacs scroll bars. Otherwise, this will work. [-- Attachment #2: Type: text/html, Size: 2090 bytes --] ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functions in C 2024-10-24 14:26 ` Jimmy Yuen Ho Wong @ 2024-10-24 14:39 ` Eli Zaretskii 2024-10-24 15:33 ` Jimmy Yuen Ho Wong 0 siblings, 1 reply; 17+ messages in thread From: Eli Zaretskii @ 2024-10-24 14:39 UTC (permalink / raw) To: Jimmy Yuen Ho Wong; +Cc: emacs-devel > From: Jimmy Yuen Ho Wong <wyuenho@gmail.com> > Date: Thu, 24 Oct 2024 15:26:46 +0100 > Cc: emacs-devel@gnu.org > > If the above is what you want, and since the popup is actually a > frame, my first suggestion would be to use :align-to display property > on the whitespace between the <candidate>s and the <Type>s. Did you > try that? > > The advantage of :align-to is that you don't have to measure the > pixel-width of the candidate names, only the pixel-width of each > <Type> string (to correctly set up the offset from the right edge of > the text area) -- the rest will be done by the display engine. And > the display engine always does everything in pixel resolution. > > The current implementation wraps every line with some additional margin and a custom thin scrollbar after > formatting, both are propertized strings with a display space property, before giving the final result to a buffer > and then the child frame. Letting the windowing system to do truncation will truncate off the custom scrollbar > and margin first, in addition to breaking an existing API that downstream extension packages rely on and > being a much larger refactoring that will bring forth the much thicker and intrusive default Emacs scroll bars. > Otherwise, this will work. If the scroll bar and the margin are generated programmatically, then presumably the program which creates them knows their width, or can calculate that? If so, the :align-to value should take that into consideration. (Assuming I understood what you were describing.) ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functions in C 2024-10-24 14:39 ` Eli Zaretskii @ 2024-10-24 15:33 ` Jimmy Yuen Ho Wong 2024-10-24 16:02 ` Eli Zaretskii 0 siblings, 1 reply; 17+ messages in thread From: Jimmy Yuen Ho Wong @ 2024-10-24 15:33 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel [-- Attachment #1: Type: text/plain, Size: 591 bytes --] > > If the scroll bar and the margin are generated programmatically, then > presumably the program which creates them knows their width, or can > calculate that? If so, the :align-to value should take that into > consideration. > As I said, the problem is letting the window system do the truncation rather than in code. There's no way to tell Emacs to start truncating from the actual content rather than UI elements that Emacs thinks are content. Hence, the original ask. Correct and performant custom truncation that respects pixel width is much much harder than it should be in Emacs. [-- Attachment #2: Type: text/html, Size: 803 bytes --] ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functions in C 2024-10-24 15:33 ` Jimmy Yuen Ho Wong @ 2024-10-24 16:02 ` Eli Zaretskii 2024-10-24 16:49 ` Jimmy Yuen Ho Wong 0 siblings, 1 reply; 17+ messages in thread From: Eli Zaretskii @ 2024-10-24 16:02 UTC (permalink / raw) To: Jimmy Yuen Ho Wong; +Cc: emacs-devel > From: Jimmy Yuen Ho Wong <wyuenho@gmail.com> > Date: Thu, 24 Oct 2024 16:33:14 +0100 > Cc: emacs-devel@gnu.org > > If the scroll bar and the margin are generated programmatically, then > presumably the program which creates them knows their width, or can > calculate that? If so, the :align-to value should take that into > consideration. > > As I said, the problem is letting the window system do the truncation rather than in code. There's no way to > tell Emacs to start truncating from the actual content rather than UI elements that Emacs thinks are content. I guess I don't understand the issue you are describing. Where does window system come into play here? What are "UI elements that Emacs thinks are content", and where are they in the screenshots shown in https://github.com/minad/corfu/pull/508 ? And where in my suggestion did I propose anything that would cause "truncation by window system"? > Hence, the original ask. Correct and performant custom truncation that respects pixel width is much much > harder than it should be in Emacs. Lisp programs are not supposed to do layout calculations, plain and simple. The reason is that layout calculations are impossible without having a window with lots of stuff that determines how text is displayed. So doing that on strings is meaningless. Therefore, I'm trying to help you do the job using the existing display facilities, because the kind of solution you have in mind is unlikely to emerge. If you want me to keep coming up with ideas, please help me understand better the issues you are describing. I hope you do realize that to suggest viable solutions, I need to have a good understanding of the problem. But if my suggestions and questions annoy you, I can easily stop. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functions in C 2024-10-24 16:02 ` Eli Zaretskii @ 2024-10-24 16:49 ` Jimmy Yuen Ho Wong 2024-10-24 17:56 ` Eli Zaretskii 0 siblings, 1 reply; 17+ messages in thread From: Jimmy Yuen Ho Wong @ 2024-10-24 16:49 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel [-- Attachment #1: Type: text/plain, Size: 1914 bytes --] > > I guess I don't understand the issue you are describing. Where does > window system come into play here? What are "UI elements that Emacs > thinks are content", and where are they in the screenshots shown in > https://github.com/minad/corfu/pull/508 ? And where in my suggestion > did I propose anything that would cause "truncation by window system"? > That thin white bar on the right of the box from the third screenshot onwards is actually a string with a display space property in pixels, not a real scroll bar. Using :align-to in the padding between the candidate and annotation is not a problem, the problem is if the concatenated line is too long, I'll need to truncate. There are 2 options - `truncate-string-to-width`, which is bugged, or set the `truncate-line` buffer local to t and let Emacs' window system do its magic, which will be performant and correct, and I can even replace the arrow in an ellipsis, but truncation will start to truncate off the emulated scroll bar. > Lisp programs are not supposed to do layout calculations, plain and > simple. The reason is that layout calculations are impossible without > having a window with lots of stuff that determines how text is > displayed. So doing that on strings is meaningless. > As I described in my first email, this can almost be achieved from the existing Elisp functions and C functions exposed Elisp. The performance problem associated with resolving a font WRT the anonymous face and face list craziness can be done in C, and already exists. The width of the display space and string replacement text properties can be calculated by `check_display_width` in `indent.c`, and rest is surely somewhere in `image.c`. I hope you are not telling me that Emacs devs still refuse to give people the ability to align text in pixel precisions programmatically at the end of 2024. Browsers have had this ability for almost 30 years. [-- Attachment #2: Type: text/html, Size: 2432 bytes --] ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functions in C 2024-10-24 16:49 ` Jimmy Yuen Ho Wong @ 2024-10-24 17:56 ` Eli Zaretskii 2024-10-24 21:11 ` Jimmy Yuen Ho Wong 0 siblings, 1 reply; 17+ messages in thread From: Eli Zaretskii @ 2024-10-24 17:56 UTC (permalink / raw) To: Jimmy Yuen Ho Wong; +Cc: emacs-devel > From: Jimmy Yuen Ho Wong <wyuenho@gmail.com> > Date: Thu, 24 Oct 2024 17:49:27 +0100 > Cc: emacs-devel@gnu.org > > I guess I don't understand the issue you are describing. Where does > window system come into play here? What are "UI elements that Emacs > thinks are content", and where are they in the screenshots shown in > https://github.com/minad/corfu/pull/508 ? And where in my suggestion > did I propose anything that would cause "truncation by window system"? > > That thin white bar on the right of the box from the third screenshot onwards is actually a string with a display > space property in pixels, not a real scroll bar. OK, but then the Lisp program which produces that bar knows its pixel-width, and can account for it in the :align-to spec. > Using :align-to in the padding between the candidate and annotation is not a problem, the problem is if the > concatenated line is too long, I'll need to truncate. Why would you need to truncate? and which part needs to be truncated? My suggestion is to align the <Type>s part so that it and the following pseudo-scrollbar end exactly at the window edge. With this arrangement, you shouldn't need to truncate at least the <Type>s part. This can be dome by using :align-to which counts from 'right', which is the right edge of the text area. Actually, I don't understand why you'd need to truncate anything, since the dimensions of the child frame can be calculated such that the longest completion candidate will still fit without truncation. Or what am I missing? > There are 2 options - `truncate-string-to-width`, which is > bugged, or set the `truncate-line` buffer local to t and let Emacs' window system do its magic, which will be > performant and correct, and I can even replace the arrow in an ellipsis, but truncation will start to truncate off > the emulated scroll bar. You assumed something I didn't say and didn't have in mind. There should be no need to use truncate-lines. > Lisp programs are not supposed to do layout calculations, plain and > simple. The reason is that layout calculations are impossible without > having a window with lots of stuff that determines how text is > displayed. So doing that on strings is meaningless. > > As I described in my first email, this can almost be achieved from the existing Elisp functions and C functions > exposed Elisp. The performance problem associated with resolving a font WRT the anonymous face and face > list craziness can be done in C, and already exists. The width of the display space and string replacement text > properties can be calculated by `check_display_width` in `indent.c`, and rest is surely somewhere in `image.c`. I don't think you fully understand the code you are referring to, because it will not do what you want. E.g., check_display_width calls string-width, which you found problematic, and image.c doesn't handle layout of images. More importantly, the _only_ place in Emacs where we have code that lays out glyphs until it hits some specified coordinates is in the display engine, where it arranges text for display, one "display element" at a time. Exposing that to Lisp in a useful way is a hellishly hard job, because that code was never meant to be useful from a Lisp program, and from a POV of a Lisp programmer in certain cases behaves nonsensically. That's one of the reasons why vertical-motion has such a complicated implementation which deals with half a dozen different complications when using the display code in such way. Of course, if someone wants to write such a code, and it will be clean and correct, such patches will be welcome. But please believe me when I tell you that it is much better to try to avoid that and use existing display capabilities (which will also allow you to support this in current Emacs versions, instead of waiting for some future one). > I hope you are not telling me that Emacs devs still refuse to give people the ability to align text in pixel > precisions programmatically at the end of 2024. Browsers have had this ability for almost 30 years. This is not about refusal. It isn't like what you are asking is easy to do, and the "Emacs devs" are just a lazy bunch. I looked at the code involved, and I currently have no idea how to implement what you have in mind so that it works in all the cases, those which you mentioned and those you didn't, and works in a way that will be useful for Lisp programs. You may think it's easy, but it isn't. Some things are even conceptually not simple, for example whether it is okay or not to break a string between U+1F3C2 and the following U+1F3FF, and if so, how to discover that subject to how the current character-composition machinery in Emacs was designed and implemented. Of course, it is possible that I'm missing something, so if someone has ideas about implementing this, let alone code, I'm all ears. But even if such ideas/code emerge, I think doing this job using existing display capabilities is a better way, because it will work immediately with existing Emacs versions, and will probably be more reliable. I still don't see why you couldn't solve the problem using :align-to and the other ideas I suggested. Last, but not least: please don't forget that Emacs is a volunteer-driven project, and the only resources we have are those of people who decide they want to work on something, for whatever reasons. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functions in C 2024-10-24 17:56 ` Eli Zaretskii @ 2024-10-24 21:11 ` Jimmy Yuen Ho Wong 2024-10-25 7:21 ` Eli Zaretskii 0 siblings, 1 reply; 17+ messages in thread From: Jimmy Yuen Ho Wong @ 2024-10-24 21:11 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel [-- Attachment #1: Type: text/plain, Size: 5361 bytes --] > > Why would you need to truncate? and which part needs to be truncated? > > My suggestion is to align the <Type>s part so that it and the > following pseudo-scrollbar end exactly at the window edge. With this > arrangement, you shouldn't need to truncate at least the <Type>s part. > This can be dome by using :align-to which counts from 'right', which > is the right edge of the text area. > Actually, I don't understand why you'd need to truncate anything, > since the dimensions of the child frame can be calculated such that > the longest completion candidate will still fit without truncation. > Or what am I missing? The :align-to of the padding between candidate and annotation can only be calculated by adding the prefix column width, calculated from the longest prefix width, the candidate width, calculated the same way, and the suffix column width minus the pixel width of the suffix. The reason for this is that `string-pixel-width` will be called on all of these concatenated strings, and the maximum of which will be given as the width to a function to render the child frame. This also answers your next question, yes the pop up width is already calculated dynamically, but against a max width, this is what I mean by "confined", hence the need for truncation before blitzing the strings to a child frame. :align-to (- right suffix-width) will lead `string-pixel-width` to return a ridiculously large number that, funnily enough, is calculated from the current window's text area width, instead of the child frame's window, of which the size is unknown at this time. As to the reason for a max width, let's just say there exists language servers such as Rust Analyzer, that will return the signature of a function as the completion annotation, which can be quite long. Nobody wants their completion pop up box taking up half the screen. Of course, one can also adjusts the child frame parameters to let it deal with min/max size, margins and allow the user to resize, but the beautifully emulated scroll bar will have to be sacrificed because either I delete it from Corfu or the window will start truncating from the scroll bar when the user resizes the window to be smaller than the content width. > > There are 2 options - `truncate-string-to-width`, which is > > bugged, or set the `truncate-line` buffer local to t and let Emacs' > window system do its magic, which will be > > performant and correct, and I can even replace the arrow in an ellipsis, > but truncation will start to truncate off > > the emulated scroll bar. > > You assumed something I didn't say and didn't have in mind. There > should be no need to use truncate-lines. > I didn't assume anything. It's just a logical conclusion. Do you have it in mind now? This is not about refusal. It isn't like what you are asking is easy to do, and the "Emacs devs" are just a lazy bunch. I looked at the > code involved, and I currently have no idea how to implement what you > have in mind so that it works in all the cases, those which you > mentioned and those you didn't, and works in a way that will be useful > for Lisp programs. You may think it's easy, but it isn't. Some > things are even conceptually not simple, for example whether it is > okay or not to break a string between U+1F3C2 and the following > U+1F3FF, and if so, how to discover that subject to how the current > character-composition machinery in Emacs was designed and implemented. > You already have `string-glyph-split` which works correctly, (a job well done BTW, even more comformant than Chrome and Webkit). There are only 3 things you need to do for a hypothetical `glyph-pixel-width`: 1. With no faces, find the width of a character glyph from the default font or whatever `char-displayable-p` returns. This is easy, I can already do this from Elisp reasonably fast by going straight to the terminal using `composite-get-gstring`. 2. With faces, resolve the font from the faces, go to 1. Still no need to deal with windows. Can be done correctly in Elisp, but incredibly slowly due to anon faces, face lists and having to go through the recursive `face-attribute-merged-with`. The logic in `face-attribute-merged-with` can be duplicated and modified to deal with anon faces, and run iteratively, but still a few orders of magnitude slower than it needs to be. 3. Display properties is when you start to need a window, as a first try, you can delegate this back to the current slow path via `window-text-pixel-size`. 1 and 2 will be the vast vast majority of the use case. It's okay to be slower for 3 due to the involvement of a window. As a point of reference, this benchmark finishes in ~0.10s in my MacBook Pro M1 Pro, this is 6 FPS for measuring 10k glyph widths. ```elisp (let ((s "1")) 'face 'completions-common-part))) (benchmark-run 10000 (string-pixel-width s))) ``` The following finishes in ~0.9s. Using the procedure described in case 1 above already cuts the time down by half. ```elisp (benchmark-run 10000 (string-pixel-width "1")) ``` Getting boths cases down 1 order of magnitude is all I'm hoping for. I'm not saying emacs-devs are lazy, I'm just saying after 14 years, Emacs finally can split strings with emojis correctly, can we go one step further and give Emacs users the ability to layout in pixel precision in a more performant manner please? [-- Attachment #2: Type: text/html, Size: 6732 bytes --] ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functions in C 2024-10-24 21:11 ` Jimmy Yuen Ho Wong @ 2024-10-25 7:21 ` Eli Zaretskii 2024-10-25 13:35 ` Jimmy Yuen Ho Wong 0 siblings, 1 reply; 17+ messages in thread From: Eli Zaretskii @ 2024-10-25 7:21 UTC (permalink / raw) To: Jimmy Yuen Ho Wong; +Cc: emacs-devel > From: Jimmy Yuen Ho Wong <wyuenho@gmail.com> > Date: Thu, 24 Oct 2024 22:11:36 +0100 > Cc: emacs-devel@gnu.org > > Why would you need to truncate? and which part needs to be truncated? > > My suggestion is to align the <Type>s part so that it and the > following pseudo-scrollbar end exactly at the window edge. With this > arrangement, you shouldn't need to truncate at least the <Type>s part. > This can be dome by using :align-to which counts from 'right', which > is the right edge of the text area. > > Actually, I don't understand why you'd need to truncate anything, > since the dimensions of the child frame can be calculated such that > the longest completion candidate will still fit without truncation. > Or what am I missing? > > The :align-to of the padding between candidate and annotation can only be calculated by adding the prefix > column width, calculated from the longest prefix width, the candidate width, calculated the same way, and the > suffix column width minus the pixel width of the suffix. We are mis-communicating. My suggestion is _not_ to compute the :align-to from the width of the prefix+candidate+suffix. My suggestion is to calculate the width of <Type>+scroll-bar, then use :align-to relative to the right edge of the window, like this: :align-to (- right (N)) where N is the pixel-width of <Type>+scroll-bar > The reason for this is that `string-pixel-width` will be > called on all of these concatenated strings, and the maximum of which will be given as the width to a function > to render the child frame. This also answers your next question, yes the pop up width is already calculated > dynamically, but against a max width, this is what I mean by "confined", hence the need for truncation before > blitzing the strings to a child frame. :align-to (- right suffix-width) will lead `string-pixel-width` to return a > ridiculously large number that, funnily enough, is calculated from the current window's text area width, instead > of the child frame's window, of which the size is unknown at this time. I don't understand this. What is "suffix-width" in the above text, and in what units is it measured? And why the size of the window is unknown? > As to the reason for a max width, let's just say there exists language servers such as Rust Analyzer, that will > return the signature of a function as the completion annotation, which can be quite long. Nobody wants their > completion pop up box taking up half the screen. Long strings can be truncated with one of the known methods. Those methods will not give you pixel accuracy, you don't need that if you use :align-to relative to the right edge of the window. > Of course, one can also adjusts the child frame parameters to let it deal with min/max size, margins and allow > the user to resize, but the beautifully emulated scroll bar will have to be sacrificed because either I delete it > from Corfu or the window will start truncating from the scroll bar when the user resizes the window to be > smaller than the content width. I don't understand this, either. Why cannot the calculation of the frame parameters take the scroll-bar into account, so as to avoid its deletion/truncation? > You assumed something I didn't say and didn't have in mind. There > should be no need to use truncate-lines. > > I didn't assume anything. It's just a logical conclusion. Do you have it in mind now? Your logic applied to my suggestions will only be correct if you understand my suggestions completely. Which I don't think happens yet, because we still seem to be mis-communicating. > This is not about refusal. It isn't like what you are asking is easy > > to do, and the "Emacs devs" are just a lazy bunch. I looked at the > code involved, and I currently have no idea how to implement what you > have in mind so that it works in all the cases, those which you > mentioned and those you didn't, and works in a way that will be useful > for Lisp programs. You may think it's easy, but it isn't. Some > things are even conceptually not simple, for example whether it is > okay or not to break a string between U+1F3C2 and the following > U+1F3FF, and if so, how to discover that subject to how the current > character-composition machinery in Emacs was designed and implemented. > > You already have `string-glyph-split` which works correctly, (a job well done BTW, even more comformant > than Chrome and Webkit). There are only 3 things you need to do for a hypothetical `glyph-pixel-width`: You originally asked for truncate-string-to-pixel-width which would avoid splitting grapheme clusters. What is glyph-pixel-width, and what should it do? > 1. With no faces, find the width of a character glyph from the default font or whatever `char-displayable-p` > returns. This is easy, I can already do this from Elisp reasonably fast by going straight to the terminal using > `composite-get-gstring`. This is incomplete and inaccurate, because it ignores some important complications. First, you forget images. You also ignore the problematic aspects of getting width from composite-get-gstring. And there are other complications, for example with TAB characters. > 2. With faces, resolve the font from the faces, go to 1. Still no need to deal with windows. Can be done > correctly in Elisp, but incredibly slowly due to anon faces, face lists and having to go through the recursive > `face-attribute-merged-with`. The logic in `face-attribute-merged-with` can be duplicated and modified to deal > with anon faces, and run iteratively, but still a few orders of magnitude slower than it needs to be. Faces cannot be resolved without a frame (because each frame can have a different definition of the same face), thus a window is required. A window is also required because overlays (which can define faces) can be window-specific. In general you also need a buffer, because there's buffer-face-mode. And knowing the font is far from enough, because of text shaping (what we call "character composition"), without which we cannot reliably know what glyph(s) from the font to use for the metrics. IOW, your proposed idea will work for the simple cases, but falls apart for a general-purpose API which will rightfully be expected to work in any situation and use case supported by Emacs. > 3. Display properties is when you start to need a window, as a first try, you can delegate this back to the > current slow path via `window-text-pixel-size`. This is only a small part of the problem. > I'm not saying emacs-devs are lazy, I'm just saying after 14 years, Emacs finally can split strings with emojis > correctly, can we go one step further and give Emacs users the ability to layout in pixel precision in a more > performant manner please? I explained why this is hard to implement correctly, at least as long as we are talking about truncate-string-to-pixel-width which should avoid splitting grapheme clusters. string-glyph-split was relatively easy because we were lucky to already have everything exposed to Lisp. We are very far from that point with this request. The existing high-level C APIs, which we use in window-text-pixel-size and its ilk, are inappropriate, because they are unable to reliably find a buffer or string position that corresponds to a given pixel-width. AFAIU, to implement what you asked for, we'd need a whole new set of C APIs, which will have to be implemented from scratch using the low-level functions which move one display element at a time, and pay attention to all the Emacs display complications: faces, character compositions, display properties, overlays, images, xwidgets, word-wrap, line-truncation, etc. Sure, the elements of all this exist, so "we have the technology", but the problem is the higher-level logic that would combine those elements into a coherent whole and produce results that Lisp programs expect. IOW, this is not just "go one step further", this is a huge step that will require a lot of coding and debugging. Of course, if someone sees a way to do it easier, let's see the code or at least an idea of such a code. The ideas you presented are too simplistic to fit the bill, unfortunately. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functions in C 2024-10-25 7:21 ` Eli Zaretskii @ 2024-10-25 13:35 ` Jimmy Yuen Ho Wong 2024-10-25 15:11 ` Eli Zaretskii 0 siblings, 1 reply; 17+ messages in thread From: Jimmy Yuen Ho Wong @ 2024-10-25 13:35 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel [-- Attachment #1: Type: text/plain, Size: 4899 bytes --] > > We are mis-communicating. My suggestion is _not_ to compute the > :align-to from the width of the prefix+candidate+suffix. My > suggestion is to calculate the width of <Type>+scroll-bar, then use > :align-to relative to the right edge of the window, like this: > > :align-to (- right (N)) > > where N is the pixel-width of <Type>+scroll-bar > > > The reason for this is that `string-pixel-width` will be > > called on all of these concatenated strings, and the maximum of which > will be given as the width to a function > > to render the child frame. This also answers your next question, yes the > pop up width is already calculated > > dynamically, but against a max width, this is what I mean by "confined", > hence the need for truncation before > > blitzing the strings to a child frame. :align-to (- right suffix-width) > will lead `string-pixel-width` to return a > > ridiculously large number that, funnily enough, is calculated from the > current window's text area width, instead > > of the child frame's window, of which the size is unknown at this time. > > I don't understand this. What is "suffix-width" in the above text, > and in what units is it measured? And why the size of the window is > unknown? > > > As to the reason for a max width, let's just say there exists language > servers such as Rust Analyzer, that will > > return the signature of a function as the completion annotation, which > can be quite long. Nobody wants their > > completion pop up box taking up half the screen. > > Long strings can be truncated with one of the known methods. Those > methods will not give you pixel accuracy, you don't need that if you > use :align-to relative to the right edge of the window. > > Here are more gaps to fill in for you. The margin and the scroll bar widths are both calculated relative to the `default-font-width`, the reason for that is, assuming most of the text is in the default font, if it is 20px wide, it's undesirable to have a fixed scroll bar size of 3px. The scroll bar and the margin need to scale with the default font size to fight for just enough of the user's attention when viewed. This can be known with some refactoring by the time `string-pixel-width` is called on all the formatted completion strings, but the whole issue is the "right" in :align-to (- right <whatever>) would be referring to the window from which you calculate `string-pixel-width` from, not the window in the child frame, because we are trying calculate the child frame width from the content width at this point. What you are suggesting has a logical circular dependency here, which is why I explained to you that :align-to can only be calculated from `(+ prefix-column-width candidate--column-width (- suffix-column-width suffix-width)`. The suffix width means the annotation's pixel width, the part you keep calling type, which is not necessarily the case. I.e: ``` ;; you just calculated the width of the space from the left to the right of the __current-window__ minus some offset (let ((content-width (cl-loop for (prefix candidate suffix) in formatted-lines maximize (string-pixel-width (concat prefix candidate (propertize " " :align-to `(- right ,(whatever))) suffix))))) .... ;; now you just made a child frame as large as your current window's width minus whatever, presumably much smaller than your current window's width, thus this frame now covers most of your screen. (make-frame `((width . ,content-width))) ``` > I don't understand this, either. Why cannot the calculation of the > frame parameters take the scroll-bar into account, so as to avoid its > deletion/truncation? > For the second time, there's a max child frame width variable that "confines" how large it can be, the implication is it can be < content width, therefore necessitates programmatic truncation of the content width, which __does not__ include the scroll bar. > IOW, your proposed idea will work for the simple cases, but falls > apart for a general-purpose API which will rightfully be expected to > work in any situation and use case supported by Emacs. > Ok, makes sense. Thanks for filling in the missing parts for me. Here's some further questions. WRT case 1, translating tab sizes is a simple multiplication, it sounds to me it can still be fast by bypassing windows. Is this correct? Anything else that can slow this case down? WRT case 2, boldly extrapolating from my simple benchmarks, resolving the font from faces takes ~10% of the time in `string-pixel-width`, besides saving and restoring window states and scanning window positions, what else does "string-pixel-width" spend on the other 90% of the time? > The existing > high-level C APIs, which we use in window-text-pixel-size and its ilk, > are inappropriate, because they are unable to reliably find a buffer > or string position that corresponds to a given pixel-width. > Agreed. [-- Attachment #2: Type: text/html, Size: 5951 bytes --] ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functions in C 2024-10-25 13:35 ` Jimmy Yuen Ho Wong @ 2024-10-25 15:11 ` Eli Zaretskii 2024-10-28 20:21 ` Jimmy Yuen Ho Wong 0 siblings, 1 reply; 17+ messages in thread From: Eli Zaretskii @ 2024-10-25 15:11 UTC (permalink / raw) To: Jimmy Yuen Ho Wong; +Cc: emacs-devel > From: Jimmy Yuen Ho Wong <wyuenho@gmail.com> > Date: Fri, 25 Oct 2024 14:35:16 +0100 > Cc: emacs-devel@gnu.org > > Here are more gaps to fill in for you. The margin and the scroll bar widths are both calculated relative to the > `default-font-width`, the reason for that is, assuming most of the text is in the default font, if it is 20px wide, it's > undesirable to have a fixed scroll bar size of 3px. The scroll bar and the margin need to scale with the default > font size to fight for just enough of the user's attention when viewed. This can be known with some refactoring > by the time `string-pixel-width` is called on all the formatted completion strings, but the whole issue is the > "right" in :align-to (- right <whatever>) would be referring to the window from which you calculate > `string-pixel-width` from, not the window in the child frame, because we are trying calculate the child frame > width from the content width at this point. What you are suggesting has a logical circular dependency here, > which is why I explained to you that :align-to can only be calculated from `(+ prefix-column-width > candidate--column-width (- suffix-column-width suffix-width)`. The suffix width means the annotation's pixel > width, the part you keep calling type, which is not necessarily the case. I.e: So the problem is that you perform all the calculations _before_ the child frame is created and shown? If so, the :align-to will indeed be incorrect, but the difference between the alignment you calculate and the one you need is fixed: it's the difference in pixels between the width of the selected window when you calculate the alignment and the actual width of the window in the child frame where you will show the completion candidates. How hard is it to walk over all the candidates you prepared for display and adjust the :align-to values once the child frame is created? And if the problem is that the dimensions of the child frame depend on the width of the candidates+suffix to begin with, then you could perhaps break this circular dependency by estimating the expected width of the candidates by some coarse method that ignores the subtleties and adds some slack to be on the safe side. > IOW, your proposed idea will work for the simple cases, but falls > apart for a general-purpose API which will rightfully be expected to > work in any situation and use case supported by Emacs. > > Ok, makes sense. Thanks for filling in the missing parts for me. Here's some further questions. > > WRT case 1, translating tab sizes is a simple multiplication, it sounds to me it can still be fast by bypassing > windows. Is this correct? Anything else that can slow this case down? The problem is that the actual width of a TAB on display depends on the column where the TAB starts. IOW, a TAB is not shown as 8 columns, it is shown as the number of columns till the next tab stop. So its width cannot be reliably known for an arbitrary string until you know at which column that string will start on display. string-pixel-width assumes the string starts at column zero, but that might not be true. > WRT case 2, boldly extrapolating from my simple benchmarks, resolving the font from faces takes ~10% of the > time in `string-pixel-width`, besides saving and restoring window states and scanning window positions, what > else does "string-pixel-width" spend on the other 90% of the time? In what version of Emacs did you benchmark it? In Emacs 30, my profiling indicates a large portion of the time is taken by with-current-buffer. Emacs 31 cuts the time in half by using a fixed work buffer, but still, the actual pixel-width calculation takes only about 30% of the running time. (You can profile it yourself using profiler-start, but I suggest to load subr-x.el first as the .el file, so that the profile will be more detailed in terms of Lisp code.) Bottom line: string-pixel-width is hardly efficient enough when invoked in a tight loop, so if you need to call it many times for many strings, perhaps a better idea would be to insert all the strings into a work buffer, then measure their width one by one using window-text-pixel-size, each time calling it with different FROM and TO values? That involves switching a window's buffer and then switching it back, but maybe it will be faster? Alternatively, if you only need the width of the widest string in a collection, you could concatenate them separated by newlines, then call string-pixel-width on the result. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functions in C 2024-10-25 15:11 ` Eli Zaretskii @ 2024-10-28 20:21 ` Jimmy Yuen Ho Wong 0 siblings, 0 replies; 17+ messages in thread From: Jimmy Yuen Ho Wong @ 2024-10-28 20:21 UTC (permalink / raw) To: Eli Zaretskii; +Cc: emacs-devel [-- Attachment #1: Type: text/plain, Size: 946 bytes --] > > Bottom line: string-pixel-width is hardly efficient enough when > invoked in a tight loop, so if you need to call it many times for many > strings, perhaps a better idea would be to insert all the strings into > a work buffer, then measure their width one by one using > window-text-pixel-size, each time calling it with different FROM and > TO values? That involves switching a window's buffer and then > switching it back, but maybe it will be faster? > > Alternatively, if you only need the width of the widest string in a > collection, you could concatenate them separated by newlines, then > call string-pixel-width on the result. > It took me a while to understand what this means, that's some leaky abstraction we have here :) I've found a solution after some refactoring. The simplest solution is just don't use relative :align-to. As long as it's not used, `string-pixel-width` will behave as expected. Thanks for all your help. [-- Attachment #2: Type: text/html, Size: 1210 bytes --] ^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2024-10-28 20:21 UTC | newest] Thread overview: 17+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-10-23 5:01 Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functions in C Jimmy Yuen Ho Wong 2024-10-23 8:01 ` Eli Zaretskii 2024-10-23 13:52 ` Jimmy Yuen Ho Wong 2024-10-23 17:39 ` Eli Zaretskii 2024-10-23 20:03 ` Jimmy Yuen Ho Wong 2024-10-24 9:55 ` Eli Zaretskii 2024-10-24 14:26 ` Jimmy Yuen Ho Wong 2024-10-24 14:39 ` Eli Zaretskii 2024-10-24 15:33 ` Jimmy Yuen Ho Wong 2024-10-24 16:02 ` Eli Zaretskii 2024-10-24 16:49 ` Jimmy Yuen Ho Wong 2024-10-24 17:56 ` Eli Zaretskii 2024-10-24 21:11 ` Jimmy Yuen Ho Wong 2024-10-25 7:21 ` Eli Zaretskii 2024-10-25 13:35 ` Jimmy Yuen Ho Wong 2024-10-25 15:11 ` Eli Zaretskii 2024-10-28 20:21 ` Jimmy Yuen Ho Wong
Code repositories for project(s) associated with this public inbox https://git.savannah.gnu.org/cgit/emacs.git This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).