]> git.eshelyaron.com Git - emacs.git/commitdiff
ibuffer: Display column titles in header line
authorDaniel Mendler <mail@daniel-mendler.de>
Sat, 11 Jan 2025 15:36:56 +0000 (16:36 +0100)
committerEshel Yaron <me@eshelyaron.com>
Sat, 25 Jan 2025 17:48:23 +0000 (18:48 +0100)
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'.
* lisp/ibuf-macs.el (define-ibuffer-sorter): Add "@" to the
interactive specification for clicks on the header line.

* etc/NEWS: Announce the change.
(Bug#75497)

(cherry picked from commit 5294d450da47734bbe2ca259505674bcae5ff573)

etc/NEWS
lisp/ibuf-macs.el
lisp/ibuffer.el

index 157c96393f4d442264cd6542e66c5ad62989d145..4f19e506f9e94b206052cfe0a6cf3bdb6b65bc0f 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -254,6 +254,10 @@ You can now set `asm-comment-char' from 'asm-mode-hook' instead.
 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.
 
index 2d5ef65134081d4c63bf0404a9794ce46ede575d..9c43411e46d5cdb44e9fd17810b00bf7f49ede3d 100644 (file)
@@ -146,7 +146,7 @@ value if and only if `a' is \"less than\" `b'.
   `(progn
      (defun ,(intern (concat "ibuffer-do-sort-by-" (symbol-name name))) ()
        ,(or documentation "No :documentation specified for this sorting method.")
-       (interactive "" ibuffer-mode)
+       (interactive "@" ibuffer-mode)
        (setq ibuffer-sorting-mode ',name)
        (when (eq ibuffer-sorting-mode ibuffer-last-sorting-mode)
         (setq ibuffer-sorting-reversep (not ibuffer-sorting-reversep)))
index e911edcdfc17b145fd2f9b35397239db54ea4b9b..c36804c10331b2f889bcfa3ea8fd089b60b17dd2 100644 (file)
@@ -310,8 +310,10 @@ in completion lists of the `ibuffer-jump-to-buffer' command."
   :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's value is t, the header line displays the current
+filters.  For the value `title', display the column titles."
+  :type '(choice boolean (const :tag "Column titles" :value title)))
 
 (defcustom ibuffer-default-directory nil
   "The default directory to use for a new Ibuffer buffer.
@@ -2050,59 +2052,90 @@ the value of point at the beginning of the line for that buffer."
   (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 negative MIN, since the titles are left-aligned.
+      (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 negative MIN, since the summaries are left-aligned.
+      (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)
@@ -2114,27 +2147,7 @@ the value of point at the beginning of the line for that buffer."
         (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)))))
 
@@ -2199,10 +2212,11 @@ If optional arg SILENT is non-nil, do not display progress messages."
   ;; 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