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'.
* 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)
This commit is contained in:
Daniel Mendler 2025-01-11 16:36:56 +01:00 committed by Eli Zaretskii
parent 35576fde56
commit 5294d450da
3 changed files with 95 additions and 77 deletions

View file

@ -354,6 +354,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.

View 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)
(interactive "@")
(setq ibuffer-sorting-mode ',name)
(when (eq ibuffer-sorting-mode ibuffer-last-sorting-mode)
(setq ibuffer-sorting-reversep (not ibuffer-sorting-reversep)))

View 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.
@ -2048,59 +2050,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)
@ -2112,27 +2145,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)))))
@ -2197,10 +2210,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