Subject: bug#75497: closed (Re: bug#75497: [PATCH] ibuffer: Display column titles in header line)

From: [email-masked] (GNU bug Tracking System)
Date: Sat, 25 Jan 2025 09:46:03 +0000

Your bug report

#75497: [PATCH] ibuffer: Display column titles in header line

which was filed against the emacs package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
75497: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=75497
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: bug#75497: [PATCH] ibuffer: Display column titles in header line
From: Eli Zaretskii <[email-masked]>
To: Daniel Mendler <[email-masked]>
Cc: [email-masked]
Date: Sat, 25 Jan 2025 11:45:38 +0200
List-Id: <debbugs-submit.debbugs.gnu.org>

> From: Daniel Mendler <[email-masked]>
> Cc: [email-masked]
> Date: Sat, 18 Jan 2025 11:34:01 +0100
> 
> Eli Zaretskii <[email-masked]> writes:
> 
> >> Date: Sun, 12 Jan 2025 13:36:19 +0100
> >> From:  Daniel Mendler via "Bug reports for GNU Emacs,
> >>  the Swiss army knife of text editors" <[email-masked]>
> >> 
> >> Daniel Mendler <[email-masked]> writes:
> >> 
> >> > Add new option value `title' to the customization option
> >> > `ibuffer-use-header-line'.  For this value show the column titles in the
> >> > Ibuffer header line.
> >> 
> >> I have attached an improved version of the patch to this mail. I have
> >> added an "@" interactive spec to the sort commands, such that clicking
> >> on the header line works when the Ibuffer window is not selected.
> >
> > Thanks.
> >
> >>  (defcustom ibuffer-use-header-line t
> >> -  "If non-nil, display a header line containing current filters."
> >> -  :type 'boolean)
> >> +  "If non-nil, display a header line.
> >> +If the variable has the value t, the header line displays the current
> >
> > "Variable has value" sounds weird.  I suggest "If the variable's value
> > is t, ..." instead.
> >
> >> +filters.  For the value `title', the column titles are displayed."
> >                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > Passive tense alert!
> >> +    (pcase-let ((`(,sym ,min ,_max ,align) element))
> >> +      ;; Ignore a negative min when we're inserting the title
> >
> > Please end this comment with a period, to make it a complete sentence.
> >
> > Also, this comment explains what the code does, but not why (yes, I
> > know the original code did that as well).  If you know the reason,
> > please add that to the comment.
> 
> Thank you. I have attached an updated patch to this mail.

Thanks, installed on master, and closing the bug.

Subject: [PATCH] ibuffer: Display column titles in header line
From: Daniel Mendler <[email-masked]>
To: [email-masked]
Date: Sat, 11 Jan 2025 17:01:04 +0100
List-Id: <debbugs-submit.debbugs.gnu.org>

Tags: patch

Add new option value `title' to the customization option
`ibuffer-use-header-line'.  For this value show the column titles in the
Ibuffer header line.

>From d4f745ce0409f1d9ae956ca8cbaf102eecea8563 Mon Sep 17 00:00:00 2001
From: Daniel Mendler <[email-masked]>
Date: Sat, 11 Jan 2025 16:36:56 +0100
Subject: [PATCH] ibuffer: Display column titles in header line

If the option `ibuffer-use-header-line' is set to `title',
display column titles in the header line.

* lisp/ibuffer.el (ibuffer--format-title)
(ibuffer--format-summary): New functions extracted from
`ibuffer-update-title-and-summary'.
(ibuffer-update-title-and-summary): Use them.
(ibuffer-update): Do not always override `header-line-format'.
(ibuffer-use-header-line): Update docstring and option `:type'.
* etc/NEWS: Announce the change.
---
 etc/NEWS        |   4 ++
 lisp/ibuffer.el | 166 ++++++++++++++++++++++++++----------------------
 2 files changed, 94 insertions(+), 76 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index d20c71897bc..46925cd8a4f 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -338,6 +338,10 @@ modal editing packages.
 The variable 'ibuffer-formats' configures the Ibuffer formats.  Add
 'recency' to the format to display the column.
 
+*** New value 'title' for the user option 'ibuffer-use-header-line'.
+Display column titles in the header line if 'ibuffer-use-header-line' is
+set to 'title'.
+
 *** New user option 'ibuffer-human-readable-size'.
 When non-nil, buffer sizes are shown in human readable format.
 
diff --git a/lisp/ibuffer.el b/lisp/ibuffer.el
index 65f8ca53693..014d8c59b25 100644
--- a/lisp/ibuffer.el
+++ b/lisp/ibuffer.el
@@ -308,8 +308,10 @@ ibuffer-jump-offer-only-visible-buffers
   :type 'boolean)
 
 (defcustom ibuffer-use-header-line t
-  "If non-nil, display a header line containing current filters."
-  :type 'boolean)
+  "If non-nil, display a header line.
+If the variable has the value t, the header line displays the current
+filters.  For the value `title', the column titles are displayed."
+  :type '(choice boolean (const :tag "Column titles" :value title)))
 
 (defcustom ibuffer-default-directory nil
   "The default directory to use for a new Ibuffer buffer.
@@ -2045,59 +2047,90 @@ ibuffer-switch-format
   (ibuffer-update-format)
   (ibuffer-redisplay t))
 
+(defun ibuffer--format-title (element &optional header-line)
+  (if (stringp element)
+      element
+    (pcase-let ((`(,sym ,min ,_max ,align) element))
+      ;; Ignore a negative min when we're inserting the title
+      (when (cl-minusp min)
+	(setq min (- min)))
+      (let* ((name (or (get sym 'ibuffer-column-name)
+		       (error "Unknown column %s in ibuffer-formats" sym)))
+	     (len (length name))
+	     (hmap (get sym 'header-mouse-map))
+	     (strname (if (< len min)
+			  (ibuffer-format-column name
+						 (- min len)
+						 align)
+			name)))
+	(when hmap
+	  (setq
+	   strname
+	   (propertize strname 'mouse-face 'highlight 'keymap
+                       (if header-line
+                           (define-keymap "<header-line>" hmap)
+                         hmap))))
+	strname))))
+
+(defun ibuffer--format-summary (element)
+  (if (stringp element)
+      (make-string (length element) ?\s)
+    (pcase-let ((`(,sym ,min ,_max ,align) element))
+      ;; Ignore a negative min when we're inserting the title.
+      (when (cl-minusp min)
+        (setq min (- min)))
+      (let* ((summary
+              (if (get sym 'ibuffer-column-summarizer)
+                  (funcall (get sym 'ibuffer-column-summarizer)
+                           (get sym 'ibuffer-column-summary))
+                (make-string
+                 (length (get sym 'ibuffer-column-name))
+                 ?\s)))
+             (len (length summary)))
+        (if (< len min)
+            (ibuffer-format-column summary
+                                   (- min len)
+                                   align)
+          summary)))))
+
 (defun ibuffer-update-title-and-summary (format)
   (ibuffer-assert-ibuffer-mode)
   ;; Don't do funky font-lock stuff here
   (let ((inhibit-modification-hooks t))
-    (if (get-text-property (point-min) 'ibuffer-title)
-	(delete-region (point-min)
-		       (next-single-property-change
-			(point-min) 'ibuffer-title)))
-    (goto-char (point-min))
-    (add-text-properties
-     (point)
-     (progn
-       (let ((opos (point)))
-	 ;; Insert the title names.
-	 (dolist (element format)
-	   (insert
-	    (if (stringp element)
-		element
-	      (pcase-let ((`(,sym ,min ,_max ,align) element))
-		;; Ignore a negative min when we're inserting the title
-		(when (cl-minusp min)
-		  (setq min (- min)))
-		(let* ((name (or (get sym 'ibuffer-column-name)
-				 (error "Unknown column %s in ibuffer-formats" sym)))
-		       (len (length name))
-		       (hmap (get sym 'header-mouse-map))
-		       (strname (if (< len min)
-				    (ibuffer-format-column name
-							   (- min len)
-							   align)
-				  name)))
-		  (when hmap
-		    (setq
-		     strname
-		     (propertize strname 'mouse-face 'highlight 'keymap hmap)))
-		  strname)))))
-	 (add-text-properties opos (point) '(ibuffer-title-header t))
-	 (insert "\n")
-	 ;; Add the underlines
-	 (let ((str (save-excursion
-		      (forward-line -1)
-		      (beginning-of-line)
-		      (buffer-substring (point) (line-end-position)))))
-	   (apply #'insert (mapcar
-			    (lambda (c)
-			      (if (not (or (eq c ?\s)
-					   (eq c ?\n)))
-				  ?-
-				?\s))
-			    str)))
-	 (insert "\n"))
-       (point))
-     `(ibuffer-title t font-lock-face ,ibuffer-title-face))
+    ;; Insert the title names.
+    (if (eq ibuffer-use-header-line 'title)
+        (setq header-line-format
+              `("" header-line-indent
+                ,(propertize " " 'display
+                             '(space :align-to header-line-indent-width))
+                ,@(mapcar (lambda (e) (ibuffer--format-title e t)) format)))
+      (if (get-text-property (point-min) 'ibuffer-title)
+	  (delete-region (point-min)
+		         (next-single-property-change
+			  (point-min) 'ibuffer-title)))
+      (goto-char (point-min))
+      (add-text-properties
+       (point)
+       (progn
+         (let ((opos (point)))
+           (apply #'insert (mapcar #'ibuffer--format-title format))
+	   (add-text-properties opos (point) '(ibuffer-title-header t))
+	   (insert "\n")
+	   ;; Add the underlines
+	   (let ((str (save-excursion
+		        (forward-line -1)
+		        (beginning-of-line)
+		        (buffer-substring (point) (line-end-position)))))
+	     (apply #'insert (mapcar
+			      (lambda (c)
+			        (if (not (or (eq c ?\s)
+					     (eq c ?\n)))
+				    ?-
+				  ?\s))
+			      str)))
+	   (insert "\n"))
+         (point))
+       `(ibuffer-title t font-lock-face ,ibuffer-title-face)))
     ;; Now, insert the summary columns.
     (goto-char (point-max))
     (if (get-text-property (1- (point-max)) 'ibuffer-summary)
@@ -2109,27 +2142,7 @@ ibuffer-update-title-and-summary
 	 (point)
 	 (progn
 	   (insert "\n")
-	   (dolist (element format)
-	     (insert
-	      (if (stringp element)
-		  (make-string (length element) ?\s)
-		(pcase-let ((`(,sym ,min ,_max ,align) element))
-                  ;; Ignore a negative min when we're inserting the title.
-                  (when (cl-minusp min)
-                    (setq min (- min)))
-                  (let* ((summary
-                          (if (get sym 'ibuffer-column-summarizer)
-                              (funcall (get sym 'ibuffer-column-summarizer)
-                                       (get sym 'ibuffer-column-summary))
-                            (make-string
-                             (length (get sym 'ibuffer-column-name))
-                             ?\s)))
-                         (len (length summary)))
-                    (if (< len min)
-                        (ibuffer-format-column summary
-                                               (- min len)
-                                               align)
-                      summary))))))
+           (apply #'insert (mapcar #'ibuffer--format-summary format))
 	   (point))
 	 '(ibuffer-summary t)))))
 
@@ -2194,10 +2207,11 @@ ibuffer-update
   ;; I tried to update this automatically from the mode-line-process format,
   ;; but changing nil-ness of header-line-format while computing
   ;; mode-line-format is asking a bit too much it seems.  --Stef
-  (setq header-line-format
-        (and ibuffer-use-header-line
-             ibuffer-filtering-qualifiers
-             ibuffer-header-line-format)))
+  (unless (eq ibuffer-use-header-line 'title)
+    (setq header-line-format
+          (and ibuffer-use-header-line
+               ibuffer-filtering-qualifiers
+               ibuffer-header-line-format))))
 
 (defun ibuffer-sort-bufferlist (bmarklist)
   (unless ibuffer-sorting-functions-alist
-- 
2.45.2