From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Jimmy Yuen Ho Wong Newsgroups: gmane.emacs.devel Subject: Re: Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functions in C Date: Fri, 25 Oct 2024 14:35:16 +0100 Message-ID: References: <86sesndz8v.fsf@gnu.org> <86ed46en1q.fsf@gnu.org> <86seslddvs.fsf@gnu.org> <86msitd0oy.fsf@gnu.org> <86h691cwuv.fsf@gnu.org> <86frolcrl2.fsf@gnu.org> <865xpgd4vi.fsf@gnu.org> Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="000000000000b1a41806254d322e" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="14116"; mail-complaints-to="usenet@ciao.gmane.io" Cc: emacs-devel@gnu.org To: Eli Zaretskii Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Fri Oct 25 15:36:54 2024 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1t4KUn-0003bb-V0 for ged-emacs-devel@m.gmane-mx.org; Fri, 25 Oct 2024 15:36:54 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1t4KU2-0001Xy-6A; Fri, 25 Oct 2024 09:36:06 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1t4KTt-0001Xa-3X for emacs-devel@gnu.org; Fri, 25 Oct 2024 09:35:57 -0400 Original-Received: from mail-qv1-xf29.google.com ([2607:f8b0:4864:20::f29]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1t4KTq-0002hd-Vw; Fri, 25 Oct 2024 09:35:56 -0400 Original-Received: by mail-qv1-xf29.google.com with SMTP id 6a1803df08f44-6cbe68f787dso11784556d6.2; Fri, 25 Oct 2024 06:35:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1729863353; x=1730468153; darn=gnu.org; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=G9Bk2AbBovO5vKmIdjCWMevb3i8mjeXwjK8uSLT6LA4=; b=FmclS+az7yxz9VBMsGP8uX6H8RKm801a4TfaCm2cxNVOGrVg0etQphYGSSaHc11bpm PM2ss2opMJgQwSeWLVpwIyLd8O3K4tFTw4I/bft9PmUcnkV8CjMXGY1YWVf+LZ0rrA2D pXAITTBal0bHUgnxHaUhC1hne6NDbo829FyLghd19ZOMtI/gdjE83KNfdioc0NbfrQJz Wn+UCW8U+z4TUq+ta4Ozh4DulZ+o8yH6u1MHBkdOoPCnJTseQqY/CgVLkOi7s5oTXC8M VL1PBWl/NZklkO4gM9p6XTYECL/UGkzfvP9YGZQXUxR55SkE1i1dxQ3A0e72+aPsQBVP rvpg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1729863353; x=1730468153; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=G9Bk2AbBovO5vKmIdjCWMevb3i8mjeXwjK8uSLT6LA4=; b=FFCogBv9O2HLMGeb9msT5RgkdDB3r6RwCz/FIyCC3lORzvx9vFoYx3zINIndc7SHmX aQ34NfNjhyHK5OJ9IcCpaAFSoaWmPizG2vcEU/fcWbQ+w4hbwB+T/56Zf35T7bELSIXP KBB523jUiTNKp0cBaGhp8KO2uNnUI4LyJif1zDvvJS5X0AEXbgWxBw3v48h3t/6kbuMW u98Vx9eQMb/OUB48OGoT5GyPtwvynCW5vSF6eprPQc8ijWo411kxCd5H7NIgViXQobZO NLMFSJjZpFJL8/i81uzQMIUA3hkIR06VbflrRX4Yke33iR2BxYXUsVQTn1OR24CicLjM UK5w== X-Gm-Message-State: AOJu0YwJoBndFyRhwHkb6ZDDLBZrcyrZgstLwDguIOTKieyJ8pbQy3QK W4Jpwu/UawHxfbjYWgl4BAuI35mEvutt4gXDyrHaQFf90WkxoecZv5yx9KRiAkdfZK7Fw+EV35g 8kPLAuDj8tKLRSIPq78YJrkRC4oZ11azd X-Google-Smtp-Source: AGHT+IEy+m8AijrWi1+pSW6NIJhImx6GXbafVRBXLXVwdpzEFpPE4YCjGNTKkDxuAAuXarbVW71gSgBjIdI3leMOHf4= X-Received: by 2002:a05:6214:3d08:b0:6cb:f262:aa9b with SMTP id 6a1803df08f44-6ce3431610dmr107288586d6.52.1729863353473; Fri, 25 Oct 2024 06:35:53 -0700 (PDT) In-Reply-To: <865xpgd4vi.fsf@gnu.org> Received-SPF: pass client-ip=2607:f8b0:4864:20::f29; envelope-from=wyuenho@gmail.com; helo=mail-qv1-xf29.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.devel:324838 Archived-At: --000000000000b1a41806254d322e Content-Type: text/plain; charset="UTF-8" > > 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 +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 +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 ) 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. --000000000000b1a41806254d322e Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
We are mis-communicating.=C2=A0 My suggestion is _not_ t= o compute the
:align-to from the width of the prefix+candidate+suffix.=C2=A0 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:

=C2=A0 :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 t= he pop up width is already calculated
> dynamically, but against a max width, this is what I mean by "con= fined", 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.=C2=A0 What is "suffix-width" in the = above text,
and in what units is it measured?=C2=A0 And why the size of the window is unknown?

> As to the reason for a max width, let's just say there exists lang= uage 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.=C2=A0 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 undesirab= le to have a fixed scroll bar size of 3px. The scroll bar and the margin ne= ed 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 th= e time `string-pixel-width` is called on all the formatted completion strin= gs, but the whole issue is the "right" in :align-to (- right <= whatever>) would be referring to the window from which you calculate `st= ring-pixel-width` from, not the window in the child frame, because we are t= rying calculate the child frame width from the content width at this point.= What you are suggesting has a logical circular dependency here, which is w= hy 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 kee= p calling type, which is not necessarily the case. I.e:

```
;; = =C2=A0you just calculated the width of the space from the left to the right= of the __current-window__ minus some offset
(let ((content-width (cl-lo= op for (prefix candidate suffix) in formatted-lines maximize (string-pixel-= width (concat prefix candidate (propertize " " :align-to `(- righ= t ,(whatever))) suffix)))))
=C2=A0 =C2=A0 ....
=C2=A0 =C2=A0=C2=A0;; = 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 wid= th, thus this frame now covers most of your screen.
=C2=A0 =C2=A0 (make-= frame `((width . ,content-width)))=C2=A0
```
=C2=A0
=
I don't understand this, either.=C2=A0 Why cannot the calculation of th= e
frame parameters take the scroll-bar into account, so as to avoid its
deletion/truncation?

For the second tim= e, there's a max child frame width variable that "confines" h= ow large it can be, the implication is it can be < content width, theref= ore necessitates programmatic=C2=A0truncation 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 size= s is a simple multiplication, it sounds to me it can still be fast by bypas= sing windows. Is this correct? Anything else that can slow this case down?<= br>WRT case 2, boldly extrapolating from my simple benchmarks, resolving th= e font from faces takes ~10% of the time in `string-pixel-width`, besides s= aving and restoring window states and scanning window positions, what else = does "string-pixel-width" spend on the other 90% of the time?
=
=C2=A0
=C2=A0Th= e 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.
--000000000000b1a41806254d322e--