Subject: Re: bug#47712: 27.1; Provide `string-display-width` function, which takes properties into account, `substring-width`

From: Daniel Mendler <[email-masked]>
Date: Mon, 12 Apr 2021 16:05:41 +0200

I gave it a quick test. See the function `string-pixel-width` below. It 
seems that it does not take 'invisible and 'display into account. I 
probably have to change something to ensure that the properties are not 
ignored.

But for we can still look at the micro benchmark.  The `string-width` 
function is 200 times faster than the `string-pixel-width` function. 
This is a huge difference, but as usual with microbenchmarks, one can 
argue that the difference will be less pronounced in a realistic 
computation.

I am still not happy with replacing `string-width` with something so 
much slower. However `window-text-pixel-size` also gives a different, 
much more precise result since it takes everything into account (or at 
least it should, invisible and display properties included). In the uses 
cases I mentioned one relies on monospace faces and formatting.

(defmacro bench (&rest body)
   (let ((start (make-symbol "t")))
     `(let (,start)
        (setq ,start (current-time))
        ,@body
        (float-time (time-since ,start)))))

(defun string-pixel-width (string)
   (with-temp-buffer
     (insert string)
     (car (window-text-pixel-size nil (point-min) (point-max)))))

;; returns 56 for all of the following strings, which is wrong
(string-pixel-width "1234")
(string-pixel-width (propertize "1234" 'invisible t))
(string-pixel-width (propertize "1234" 'display " "))

(defvar test-string
   (concat "some string with "
           (propertize "invisible substring" 'invisible t)
           " and "
           (propertize "a displayed substring"
                       'display "an overwritten substring")))

;; 5s
(bench
   (dotimes (_ 10000)
     (string-pixel-width test-string)))

;; 2.5s
(bench
   (dotimes (_ 1000000)
     (string-width test-string)))

;; 3.5s
(bench
   (dotimes (_ 1000000)
     (consult--display-width test-string)))