Subject: 28.0.50; Faulty uses of tabulated-list-format
From: Stephen Berman <[email-masked]>
To: [email-masked]
Date: Sun, 18 Oct 2020 22:00:13 +0200
List-Id: <debbugs-submit.debbugs.gnu.org>

On trying out the new tabulated-list implementation of the bookmarks
list I noticed that, when clicking on the File header, the sort
indicator is not displayed, unlike with the Bookmark header.  Then I
noticed that the same thing happens in the tabulated buffer list (C-x
C-b).  Then I grepped for all uses of tabulated-list-format in the Emacs
sources and found the same problem in most of them.  The reason is that
in these modes the width of at least one of the columns is too narrow,
so that tabulated-list-init-header omits the indicator.  In most cases
the problematic column is the final one, but in a couple of cases there
are also non-final too narrow columns.  And I think these bugs are due
to a misleading description in tabulated-list-format's doc string.  The
attached patch corrects the doc string and the problematic uses of
tabulated-list-format.  The patch also fixes a typo and tries to improve
column alignment in timer-list-mode: this is one of the few modes
derived from tabulated-list-mode whose column widths didn't need to be
corrected, but the alignment seemed suboptimal; however, when the header
line uses a variable-pitch face, the alignment is still suboptimal even
with the patch, and I don't know how to fix that.

In GNU Emacs 28.0.50 (build 34, x86_64-pc-linux-gnu, GTK+ Version 3.24.17, cairo version 1.17.3)
 of 2020-10-18 built on strobe-jhalfs
Repository revision: b7dfae3a8168977013e8de1df0916c51e76e7326
Repository branch: master
Windowing system distributor 'The X.Org Foundation', version 11.0.12008000
System Description: Linux From Scratch SVN-20200401

2020-10-18  Stephen Berman  <[email-masked]>

	Fix uses of tabulated-list-format

	* lisp/emacs-lisp/tabulated-list.el (tabulated-list-format):
	Correct the documentation of the WIDTH element.

	* lisp/bookmark.el (bookmark-bmenu-mode):
	* lisp/buff-menu.el (list-buffers--refresh):
	* lisp/emacs-lisp/package.el (package-menu-mode)
	(package-archive-column-width):
	* lisp/misc.el (list-dynamic-libraries--refresh):
	* lisp/org/org-lint.el (org-lint--report-mode):
	* lisp/progmodes/flymake.el (flymake-diagnostics-buffer-mode):
	* lisp/simple.el (process-menu-mode): Increase column width in
	order to display sort indicator.

	* lisp/emacs-lisp/timer-list.el (timer-list-mode): Improve column
	alignment.
	(timer-list--function-predicate): Correct typo in doc string.

diff --git a/lisp/bookmark.el b/lisp/bookmark.el
index ab7b04ddfe..f37f0b0ce9 100644
--- a/lisp/bookmark.el
+++ b/lisp/bookmark.el
@@ -1783,7 +1783,7 @@ bookmark-bmenu-mode
         `[("" 1) ;; Space to add "*" for bookmark with annotation
           ("Bookmark" ,bookmark-bmenu-file-column bookmark-bmenu--name-predicate)
           ,@(if bookmark-bmenu-toggle-filenames
-                '(("File" 0 bookmark-bmenu--file-predicate)))])
+                '(("File" 6 bookmark-bmenu--file-predicate)))])
   (setq tabulated-list-padding bookmark-bmenu-marks-width)
   (setq tabulated-list-sort-key '("Bookmark" . nil))
   (add-hook 'tabulated-list-revert-hook #'bookmark-bmenu--revert nil t)'
diff --git a/lisp/buff-menu.el b/lisp/buff-menu.el
index d06ba28787..5cf13cb50f 100644
--- a/lisp/buff-menu.el
+++ b/lisp/buff-menu.el
@@ -706,7 +706,7 @@ list-buffers--refresh
 		  `("Size" ,size-width tabulated-list-entry-size->
                     :right-align t)
 		  `("Mode" ,Buffer-menu-mode-width t)
-		  '("File" 1 t)))
+		  '("File" 6 t)))
     (setq tabulated-list-use-header-line Buffer-menu-use-header-line)
     (setq tabulated-list-entries (nreverse entries)))
   (tabulated-list-init-header))
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index 7b192d640b..32b99367c3 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -412,7 +412,7 @@ package-status-column-width
   :type 'number
   :version "28.1")

-(defcustom package-archive-column-width 8
+(defcustom package-archive-column-width 9
   "Column width for the Package status in the package menu."
   :type 'number
   :version "28.1")
@@ -2770,7 +2770,7 @@ package-menu-mode
           ("Status"  ,package-status-column-width  package-menu--status-predicate)
           ,@(if (cdr package-archives)
                 `(("Archive" ,package-archive-column-width package-menu--archive-predicate)))
-          ("Description" 0 package-menu--description-predicate)])
+          ("Description" 13 package-menu--description-predicate)])
   (setq tabulated-list-padding 2)
   (setq tabulated-list-sort-key (cons "Status" nil))
   (add-hook 'tabulated-list-revert-hook #'package-menu--refresh nil t)
diff --git a/lisp/emacs-lisp/tabulated-list.el b/lisp/emacs-lisp/tabulated-list.el
index b13f609f88..20e43d9c4a 100644
--- a/lisp/emacs-lisp/tabulated-list.el
+++ b/lisp/emacs-lisp/tabulated-list.el
@@ -91,7 +91,9 @@ tabulated-list-format
    This is the label for the column in the header line.
    Different columns must have non-`equal' names.
  - WIDTH is the width to reserve for the column.
-   For the final element, its numerical value is ignored.
+   Its value must be at least 2 more than the length of NAME
+   in order to display the column's sort indicator.
+   Not used for computing the width of the final element.
  - SORT specifies how to sort entries by this column.
    If nil, this column cannot be used for sorting.
    If t, sort by comparing the string value printed in the column.
diff --git a/lisp/emacs-lisp/timer-list.el b/lisp/emacs-lisp/timer-list.el
index 00d09696d2..afcd7d3354 100644
--- a/lisp/emacs-lisp/timer-list.el
+++ b/lisp/emacs-lisp/timer-list.el
@@ -93,8 +93,8 @@ timer-list-mode
   (setq-local revert-buffer-function #'list-timers)
   (setq tabulated-list-format
         '[("Idle" 6 timer-list--idle-predicate)
-          ("      Next" 12 timer-list--next-predicate)
-          ("  Repeat" 11 timer-list--repeat-predicate)
+          ("Next" 12 timer-list--next-predicate :right-align t :pad-right 1)
+          ("Repeat" 11 timer-list--repeat-predicate :right-align t :pad-right 1)
           ("Function" 10 timer-list--function-predicate)]))

 (defun timer-list--idle-predicate (A B)
@@ -119,7 +119,7 @@ timer-list--repeat-predicate
     (string< rA rB)))

 (defun timer-list--function-predicate (A B)
-  "Predicate to sort Timer-List by the Next column."
+  "Predicate to sort Timer-List by the Function column."
   (let ((fA (aref (cadr A) 3))
         (fB (aref (cadr B) 3)))
     (string< fA fB)))
diff --git a/lisp/misc.el b/lisp/misc.el
index be191c50d2..b65f56efc3 100644
--- a/lisp/misc.el
+++ b/lisp/misc.el
@@ -170,9 +170,9 @@ list-dynamic-libraries--refresh
                   (name-len (apply 'max (mapcar 'length (cdr lib)))))
               (when (> id-len max-id-len) (setq max-id-len id-len))
               (when (> name-len max-name-len) (setq max-name-len name-len))))
-          (vector (list "Library" (1+ max-id-len) t)
-                  (list "Loaded from" (1+ max-name-len) t)
-                  (list "Candidate names" 0 t))))
+          (vector (list "Library" (+ max-id-len 2) t)
+                  (list "Loaded from" (+ max-name-len 2) t)
+                  (list "Candidate names" 17 t))))
   (tabulated-list-init-header)
   (setq tabulated-list-entries nil)
   (dolist (lib dynamic-library-alist)
diff --git a/lisp/org/org-lint.el b/lisp/org/org-lint.el
index 5be1ec7286..0c3eca7998 100644
--- a/lisp/org/org-lint.el
+++ b/lisp/org/org-lint.el
@@ -1089,8 +1089,8 @@ org-lint--report-mode
 	     (< (string-to-number (aref (cadr a) 0))
 		(string-to-number (aref (cadr b) 0))))
 	   :right-align t)
-	  ("Trust" 5 t)
-	  ("Warning" 0 t)])
+	  ("Trust" 7 t)
+	  ("Warning" 9 t)])
   (tabulated-list-init-header))

 (defun org-lint--generate-reports (buffer checkers)
diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el
index b286208fff..602e8f2609 100644
--- a/lisp/progmodes/flymake.el
+++ b/lisp/progmodes/flymake.el
@@ -1376,7 +1376,7 @@ flymake-diagnostics-buffer-mode
   "Flymake diagnostics"
   "A mode for listing Flymake diagnostics."
   (setq tabulated-list-format
-        `[("Line" 5 ,(lambda (l1 l2)
+        `[("Line" 6 ,(lambda (l1 l2)
                        (< (plist-get (car l1) :line)
                           (plist-get (car l2) :line)))
            :right-align t)
@@ -1384,7 +1384,7 @@ flymake-diagnostics-buffer-mode
           ("Type" 8 ,(lambda (l1 l2)
                        (< (plist-get (car l1) :severity)
                           (plist-get (car l2) :severity))))
-          ("Message" 0 t)])
+          ("Message" 9 t)])
   (setq tabulated-list-entries
         'flymake--diagnostics-buffer-entries)
   (tabulated-list-init-header))
diff --git a/lisp/simple.el b/lisp/simple.el
index d6fce922c4..b34450aeb5 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -4388,13 +4388,13 @@ process-menu-mode
   "Major mode for listing the processes called by Emacs."
   (setq tabulated-list-format [("Process" 15 t)
 			       ("PID"      7 t)
-			       ("Status"   7 t)
+			       ("Status"   8 t)
                                ;; 25 is the length of the long standard buffer
                                ;; name "*Async Shell Command*<10>" (bug#30016)
 			       ("Buffer"  25 t)
 			       ("TTY"     12 t)
 			       ("Thread"  12 t)
-			       ("Command"  0 t)])
+			       ("Command"  9 t)])
   (make-local-variable 'process-menu-query-only)
   (setq tabulated-list-sort-key (cons "Process" nil))
   (add-hook 'tabulated-list-revert-hook 'list-processes--refresh nil t))