Subject: bug#73032: 31.0.50; vtable header is not aligned

From: Aleksandr Vityazev <[email-masked]>
Date: Thu, 05 Sep 2024 19:39:37 +0300

On 2024-09-05 10:36, Eli Zaretskii wrote:

>> Date: Thu, 05 Sep 2024 01:45:14 +0300
>> From:  Aleksandr Vityazev via "Bug reports for GNU Emacs,
>>  the Swiss army knife of text editors" <[email-masked]>
>> 
>> There is a problem in vtable.el when an emoji is specified as a delimiter; the
>> header and row delimiters are not aligned.
>> 
>> Minimal reproducer for emacs -Q:
>> 
>> (require 'vtable)
>> (with-current-buffer (get-buffer-create "*test*")
>>   (make-vtable
>>    :columns '((:name "Name" :width 20) "Size" "File")
>>    :objects (buffer-list)
>>    :actions '("k" kill-buffer
>>               "RET" display-buffer)
>>    :divider " 🍉 "
>>    :getter (lambda (object column vtable)
>>              (pcase (vtable-column vtable column)
>>                ("Name" (buffer-name object))
>>                ("Size" (buffer-size object))
>>                ("File" (or (buffer-file-name object) "")))))
>>   (switch-to-buffer "*test*"))
>> 
>> Screenshot is attached.
>
> I cannot get them aligned even if I replace the Emoji character with
> an ASCII character, like 'x'.  Can you?
No, I can't.

> AFAICT, there's inconsistency in whitespace calculation between the
> header line and the body of the table, due to the desire to display
> the sorting indicator not quite right-aligned.  The patch below
> attempts to fix that; does it give good results?

The patch helped, but there are still some issues. I was able to achieve
alignment with the following settings:
(set-face-attribute 'default nil :family "monospace" :height 210)

With: (set-face-attribute 'default nil :family "monospace" :height 220)
the header separators are also misaligned. My patch is based on the one
that was sent; I just commented out the insertion of an extra space
after the column name.

diff --git a/lisp/emacs-lisp/vtable.el b/lisp/emacs-lisp/vtable.el
index cb7ea397314..e5bcb54f28e 100644
--- a/lisp/emacs-lisp/vtable.el
+++ b/lisp/emacs-lisp/vtable.el
@@ -722,15 +722,17 @@ vtable--insert-header-line
                    (vtable--limit-string
                     name (- (elt widths index) indicator-width))
                  name))
-         (let ((fill-width
-                (+ (- (elt widths index)
-                      (string-pixel-width displayed)
-                      indicator-width
-                      (vtable-separator-width table)
-                      ;; We want the indicator to not be quite flush
-                      ;; right.
-                      (/ (vtable--char-width table) 2.0))
-                   (if last 0 spacer))))
+         (let* ((indicator-lead-width
+                 ;; We want the indicator to not be quite flush right.
+                 (/ (vtable--char-width table) 2.0))
+                (indicator-pad-width (- (vtable--char-width table)
+                                        indicator-lead-width))
+                (fill-width
+                 (+ (- (elt widths index)
+                       (string-pixel-width displayed)
+                       indicator-width
+                       indicator-lead-width)
+                    (if last 0 spacer))))
            (if (or (not last)
                    (zerop indicator-width)
                    (< (seq-reduce #'+ widths 0) (window-width nil t)))
@@ -739,7 +741,9 @@ vtable--insert-header-line
                 displayed
                 (propertize " " 'display
                             (list 'space :width (list fill-width)))
-                indicator)
+                indicator
+                (propertize " " 'display
+                            (list 'space :width (list indicator-pad-width))))
              ;; This is the final column, and we have a sorting
              ;; indicator, and the table is too wide for the window.
              (let* ((pre-indicator (string-pixel-width
@@ -758,10 +762,10 @@ vtable--insert-header-line
                                   (list (- fill-width pre-fill))))))))
          (when (and divider (not last))
            (insert (propertize divider 'keymap dmap)))
-         (insert (propertize
-                  " " 'display
-                  (list 'space :width (list
-                                       (/ (vtable--char-width table) 2.0)))))
+         ;; (insert (propertize
+         ;;          " " 'display
+         ;;          (list 'space :width (list
+         ;;                               (/ (vtable--char-width table) 2.0)))))
          (put-text-property start (point) 'vtable-column index)))
      (vtable-columns table))
     (insert "\n")

-- 
Best regards,
Aleksandr Vityazev