unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#69305: outline-minor-mode for tabulated-list-mode
@ 2024-02-21 17:34 Juri Linkov
  2024-02-21 19:12 ` Eli Zaretskii
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-02-21 17:34 UTC (permalink / raw)
  To: 69305

[-- Attachment #1: Type: text/plain, Size: 474 bytes --]

[From emacs-devel]

>> +(defcustom Buffer-menu-group-by nil
>> +  "If non-nil, buffers are grouped by function."
>> +  :type 'function
>> +  :group 'Buffer-menu
>> +  :version "30.1")
>
> Please consider letting users choose a symbol, not a function.  Each
> symbol can be mapped to a function, but having a user option whose
> values are functions makes it harder for users to customize the
> option.

Ok, now the type is changed to 'symbol'.  Here is the complete patch:


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: tabulated-list-groups.patch --]
[-- Type: text/x-diff, Size: 10258 bytes --]

diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi
index 70d1a40f836..bb2100dbb4d 100644
--- a/doc/lispref/modes.texi
+++ b/doc/lispref/modes.texi
@@ -1239,6 +1239,21 @@ Tabulated List Mode
 above form when called with no arguments.
 @end defvar
 
+@defvar tabulated-list-groups
+This buffer-local variable specifies the groups of entries displayed in
+the Tabulated List buffer.  Its value should be either a list, or a
+function.
+
+If the value is a list, each list element corresponds to one group, and
+should have the form @w{@code{(@var{group-name} @var{entries})}}, where
+@var{group-name} is a string inserted before all group entries, and
+@var{entries} have the same format as @code{tabulated-list-entries}
+(see above).
+
+Otherwise, the value should be a function which returns a list of the
+above form when called with no arguments.
+@end defvar
+
 @defvar tabulated-list-revert-hook
 This normal hook is run prior to reverting a Tabulated List buffer.  A
 derived mode can add a function to this hook to recompute
diff --git a/etc/NEWS b/etc/NEWS
index 7b248c3fe78..b549eab9f0b 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1332,6 +1332,11 @@ will return the URL for that bug.
 This allows for rcirc logs to use a custom timestamp format, than the
 chat buffers use by default.
 
+---
+*** New user option 'Buffer-menu-group-by'.
+It splits buffers by groups that are displayed with headings in
+Outline minor mode.
+
 ---
 *** New command 'Buffer-menu-toggle-internal'.
 This command toggles the display of internal buffers in Buffer Menu mode;
@@ -1997,6 +2002,10 @@ inside 'treesit-language-source-alist', so that calling
 It may be useful, for example, for the purposes of bisecting a
 treesitter grammar.
 
++++
+** New buffer-local variable 'tabulated-list-groups'.
+It prints and sorts the groups of entries separately.
+
 \f
 * Changes in Emacs 30.1 on Non-Free Operating Systems
 
diff --git a/lisp/buff-menu.el b/lisp/buff-menu.el
index e13c3b56b4e..62717c4625b 100644
--- a/lisp/buff-menu.el
+++ b/lisp/buff-menu.el
@@ -95,6 +95,18 @@ Buffer-menu-use-frame-buffer-list
   :group 'Buffer-menu
   :version "22.1")
 
+(defcustom Buffer-menu-group-by nil
+  "If non-nil, buffers are grouped by function.
+This function takes one argument: a list of entries in the same format
+as in `tabulated-list-entries', and should return a list in the format
+suitable for `tabulated-list-groups'.  Also when this variable is non-nil,
+then `outline-minor-mode' is enabled in the Buffer Menu.  Then with the
+default value of `outline-regexp' you can use Outline minor mode commands
+to show/hide groups of buffers."
+  :type 'symbol
+  :group 'Buffer-menu
+  :version "30.1")
+
 (defvar-local Buffer-menu-files-only nil
   "Non-nil if the current Buffer Menu lists only file buffers.
 This is set by the prefix argument to `buffer-menu' and related
@@ -674,7 +684,12 @@ list-buffers-noselect
       (setq Buffer-menu-buffer-list buffer-list)
       (setq Buffer-menu-filter-predicate filter-predicate)
       (list-buffers--refresh buffer-list old-buffer)
-      (tabulated-list-print))
+      (tabulated-list-print)
+      (when tabulated-list-groups
+        (setq-local outline-minor-mode-cycle t
+                    outline-minor-mode-highlight t
+                    outline-minor-mode-use-buttons 'in-margins)
+        (outline-minor-mode 1)))
     buffer))
 
 (defun Buffer-menu-mouse-select (event)
@@ -750,7 +765,11 @@ list-buffers--refresh
 		  `("Mode" ,Buffer-menu-mode-width t)
 		  '("File" 1 t)))
     (setq tabulated-list-use-header-line Buffer-menu-use-header-line)
-    (setq tabulated-list-entries (nreverse entries)))
+    (setq tabulated-list-entries (nreverse entries))
+    (when Buffer-menu-group-by
+      (setq tabulated-list-groups
+            (seq-group-by Buffer-menu-group-by
+                          tabulated-list-entries))))
   (tabulated-list-init-header))
 
 (defun tabulated-list-entry-size-> (entry1 entry2)
diff --git a/lisp/emacs-lisp/tabulated-list.el b/lisp/emacs-lisp/tabulated-list.el
index 9884a2fc24b..a78e1726c26 100644
--- a/lisp/emacs-lisp/tabulated-list.el
+++ b/lisp/emacs-lisp/tabulated-list.el
@@ -139,6 +139,21 @@ tabulated-list-entries
 arguments and must return a list of the above form.")
 (put 'tabulated-list-entries 'permanent-local t)
 
+(defvar-local tabulated-list-groups nil
+  "Groups displayed in the current Tabulated List buffer.
+This should be either a function, or a list.
+If a list, each element has the form (GROUP-NAME ENTRIES),
+where:
+
+ - GROUP-NAME is a group name as a string, which is displayed
+   at the top line of each group.
+
+ - ENTRIES is a list described in `tabulated-list-entries'.
+
+If `tabulated-list-groups' is a function, it is called with no
+arguments and must return a list of the above form.")
+(put 'tabulated-list-groups 'permanent-local t)
+
 (defvar-local tabulated-list-padding 0
   "Number of characters preceding each Tabulated List mode entry.
 By default, lines are padded with spaces, but you can use the
@@ -427,6 +444,9 @@ tabulated-list-print
 specified by `tabulated-list-sort-key'.  It then erases the
 buffer and inserts the entries with `tabulated-list-printer'.
 
+If `tabulated-list-groups' is non-nil, each group of entries
+is sorted separately after printing the group header line.
+
 Optional argument REMEMBER-POS, if non-nil, means to move point
 to the entry with the same ID element as the current line.
 
@@ -437,6 +457,9 @@ tabulated-list-print
 `tabulated-list-put-tag').  Don't use this immediately after
 changing `tabulated-list-sort-key'."
   (let ((inhibit-read-only t)
+        (groups (if (functionp tabulated-list-groups)
+		    (funcall tabulated-list-groups)
+		  tabulated-list-groups))
 	(entries (if (functionp tabulated-list-entries)
 		     (funcall tabulated-list-entries)
 		   tabulated-list-entries))
@@ -447,7 +470,14 @@ tabulated-list-print
 	 (setq saved-col (current-column)))
     ;; Sort the entries, if necessary.
     (when sorter
-      (setq entries (sort entries sorter)))
+      (if groups
+          (setq groups
+                (mapcar (lambda (group)
+                          (cons (car group) (sort (cdr group) sorter)))
+                        groups))
+        (setq entries (sort entries sorter))))
+    (unless (functionp tabulated-list-groups)
+      (setq tabulated-list-groups groups))
     (unless (functionp tabulated-list-entries)
       (setq tabulated-list-entries entries))
     ;; Without a sorter, we have no way to just update.
@@ -459,6 +489,25 @@ tabulated-list-print
       (unless tabulated-list-use-header-line
         (tabulated-list-print-fake-header)))
     ;; Finally, print the resulting list.
+    (if groups
+        (dolist (group groups)
+          (insert (car group) ?\n)
+          (when-let ((saved-pt-new (tabulated-list-print-entries
+                                    (cdr group) sorter update entry-id)))
+            (setq saved-pt saved-pt-new)))
+      (setq saved-pt (tabulated-list-print-entries
+                      entries sorter update entry-id)))
+    (when update
+      (delete-region (point) (point-max)))
+    (set-buffer-modified-p nil)
+    ;; If REMEMBER-POS was specified, move to the "old" location.
+    (if saved-pt
+	(progn (goto-char saved-pt)
+	       (move-to-column saved-col))
+      (goto-char (point-min)))))
+
+(defun tabulated-list-print-entries (entries sorter update entry-id)
+  (let (saved-pt)
     (while entries
       (let* ((elt (car entries))
              (tabulated-list--near-rows
@@ -495,14 +544,7 @@ tabulated-list-print
               (forward-line 1)
               (delete-region old (point))))))
       (setq entries (cdr entries)))
-    (when update
-      (delete-region (point) (point-max)))
-    (set-buffer-modified-p nil)
-    ;; If REMEMBER-POS was specified, move to the "old" location.
-    (if saved-pt
-	(progn (goto-char saved-pt)
-	       (move-to-column saved-col))
-      (goto-char (point-min)))))
+    saved-pt))
 
 (defun tabulated-list-print-entry (id cols)
   "Insert a Tabulated List entry at point.
diff --git a/test/lisp/emacs-lisp/tabulated-list-tests.el b/test/lisp/emacs-lisp/tabulated-list-tests.el
index 8be2be3139e..e53268b3f14 100644
--- a/test/lisp/emacs-lisp/tabulated-list-tests.el
+++ b/test/lisp/emacs-lisp/tabulated-list-tests.el
@@ -130,4 +130,45 @@ tabulated-list-sort
    (should-error (tabulated-list-sort) :type 'user-error)
    (should-error (tabulated-list-sort 4) :type 'user-error)))
 
+(ert-deftest tabulated-list-groups ()
+  (with-temp-buffer
+    (tabulated-list-mode)
+    (setq tabulated-list-groups
+          (reverse
+           (seq-group-by (lambda (b) (concat "* " (aref (cadr b) 3)))
+                         tabulated-list--test-entries)))
+    (setq tabulated-list-format tabulated-list--test-format)
+    (setq tabulated-list-padding 7)
+    (tabulated-list-init-header)
+    (tabulated-list-print)
+    ;; Basic printing.
+    (should (string-equal
+             (buffer-substring-no-properties (point-min) (point-max))
+             "\
+* installed
+       zzzz-game  zzzz-game  2113      installed   play zzzz in Emacs
+       mode       mode       1128      installed   A simple mode for editing Actionscript 3 files
+* available
+       abc-mode   abc-mode   944       available   Major mode for editing abc music files
+* obsolete
+       4clojure   4clojure   1507      obsolete    Open and evaluate 4clojure.com questions
+"))
+    ;; Sort and preserve position.
+    (forward-line 2)
+    (let ((pos (thing-at-point 'line)))
+      (tabulated-list-next-column 2)
+      (tabulated-list-sort)
+      (should (equal (thing-at-point 'line) pos))
+      (should (string-equal
+               (buffer-substring-no-properties (point-min) (point-max))
+               "\
+* installed
+       mode       mode       1128      installed   A simple mode for editing Actionscript 3 files
+       zzzz-game  zzzz-game  2113      installed   play zzzz in Emacs
+* available
+       abc-mode   abc-mode   944       available   Major mode for editing abc music files
+* obsolete
+       4clojure   4clojure   1507      obsolete    Open and evaluate 4clojure.com questions
+")))))
+
 ;;; tabulated-list-tests.el ends here

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-21 17:34 bug#69305: outline-minor-mode for tabulated-list-mode Juri Linkov
@ 2024-02-21 19:12 ` Eli Zaretskii
  2024-02-22  7:44   ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2024-02-21 19:12 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 69305

> From: Juri Linkov <juri@linkov.net>
> Date: Wed, 21 Feb 2024 19:34:17 +0200
> 
> >> +(defcustom Buffer-menu-group-by nil
> >> +  "If non-nil, buffers are grouped by function."
> >> +  :type 'function
> >> +  :group 'Buffer-menu
> >> +  :version "30.1")
> >
> > Please consider letting users choose a symbol, not a function.  Each
> > symbol can be mapped to a function, but having a user option whose
> > values are functions makes it harder for users to customize the
> > option.
> 
> Ok, now the type is changed to 'symbol'.  Here is the complete patch:

Thanks, but I wonder if we can be a tad more user-friendly?  The user
option exists, and it can accept simple enough data structures for
customizations, but the default is nil, and there's no example or
pre-cooked list of ready-to-use values anywhere in sight, not even in
the doc string.  Users will have to work hard to produce a grouping of
their liking.  E.g., suppose I want to group buffers by mode -- how
would I go about it?  Or what about grouping buffers by their leading
directories -- how can that be done?  Etc. etc. -- this could be a
very powerful feature, but we should make its use easier.  And, after
reading the documentation of tabulated-list-groups and that of
tabulated-list-entries several times, I have no idea how to specify
simple groupings such as those described above.  Which makes examples
or pre-cooked values even more important, IMO.

What I had in mind when I said "choose a symbol" was that a symbol
will stand for a pre-cooked grouping.  For example, 'mode would cause
buffers grouped by major-mode, 'directory will group by leading
directories, 'alphabet will group by the first letter of the name,
etc.  What this patch provides is quite a far cry from that.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-21 19:12 ` Eli Zaretskii
@ 2024-02-22  7:44   ` Juri Linkov
  2024-02-22  8:20     ` Eli Zaretskii
  2024-02-24 18:06     ` Ihor Radchenko
  0 siblings, 2 replies; 37+ messages in thread
From: Juri Linkov @ 2024-02-22  7:44 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 69305

[-- Attachment #1: Type: text/plain, Size: 1633 bytes --]

>> >> +(defcustom Buffer-menu-group-by nil
>> >> +  "If non-nil, buffers are grouped by function."
>> >> +  :type 'function
>> >> +  :group 'Buffer-menu
>> >> +  :version "30.1")
>> >
>> > Please consider letting users choose a symbol, not a function.  Each
>> > symbol can be mapped to a function, but having a user option whose
>> > values are functions makes it harder for users to customize the
>> > option.
>>
>> Ok, now the type is changed to 'symbol'.  Here is the complete patch:
>
> Thanks, but I wonder if we can be a tad more user-friendly?  The user
> option exists, and it can accept simple enough data structures for
> customizations, but the default is nil, and there's no example or
> pre-cooked list of ready-to-use values anywhere in sight, not even in
> the doc string.  Users will have to work hard to produce a grouping of
> their liking.  E.g., suppose I want to group buffers by mode -- how
> would I go about it?  Or what about grouping buffers by their leading
> directories -- how can that be done?  Etc. etc. -- this could be a
> very powerful feature, but we should make its use easier.  And, after
> reading the documentation of tabulated-list-groups and that of
> tabulated-list-entries several times, I have no idea how to specify
> simple groupings such as those described above.  Which makes examples
> or pre-cooked values even more important, IMO.

Ok, then this patch adds two pre-cooked functions as a starting point
for users to understand the principle.  Then users will propose
more functions and we will choose the most useful candidates
for including to the set of default functions later.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: tabulated-list-groups.patch --]
[-- Type: text/x-diff, Size: 11124 bytes --]

diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi
index 70d1a40f836..bb2100dbb4d 100644
--- a/doc/lispref/modes.texi
+++ b/doc/lispref/modes.texi
@@ -1239,6 +1239,21 @@ Tabulated List Mode
 above form when called with no arguments.
 @end defvar
 
+@defvar tabulated-list-groups
+This buffer-local variable specifies the groups of entries displayed in
+the Tabulated List buffer.  Its value should be either a list, or a
+function.
+
+If the value is a list, each list element corresponds to one group, and
+should have the form @w{@code{(@var{group-name} @var{entries})}}, where
+@var{group-name} is a string inserted before all group entries, and
+@var{entries} have the same format as @code{tabulated-list-entries}
+(see above).
+
+Otherwise, the value should be a function which returns a list of the
+above form when called with no arguments.
+@end defvar
+
 @defvar tabulated-list-revert-hook
 This normal hook is run prior to reverting a Tabulated List buffer.  A
 derived mode can add a function to this hook to recompute
diff --git a/etc/NEWS b/etc/NEWS
index 7b248c3fe78..b549eab9f0b 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1332,6 +1332,11 @@ will return the URL for that bug.
 This allows for rcirc logs to use a custom timestamp format, than the
 chat buffers use by default.
 
+---
+*** New user option 'Buffer-menu-group-by'.
+It splits buffers by groups that are displayed with headings in
+Outline minor mode.
+
 ---
 *** New command 'Buffer-menu-toggle-internal'.
 This command toggles the display of internal buffers in Buffer Menu mode;
@@ -1997,6 +2002,10 @@ inside 'treesit-language-source-alist', so that calling
 It may be useful, for example, for the purposes of bisecting a
 treesitter grammar.
 
++++
+** New buffer-local variable 'tabulated-list-groups'.
+It prints and sorts the groups of entries separately.
+
 \f
 * Changes in Emacs 30.1 on Non-Free Operating Systems
 
diff --git a/lisp/buff-menu.el b/lisp/buff-menu.el
index e13c3b56b4e..53bf66fdab1 100644
--- a/lisp/buff-menu.el
+++ b/lisp/buff-menu.el
@@ -95,6 +95,25 @@ Buffer-menu-use-frame-buffer-list
   :group 'Buffer-menu
   :version "22.1")
 
+(defcustom Buffer-menu-group-by nil
+  "If non-nil, buffers are grouped by function.
+This function takes one argument: a list of entries in the same format
+as in `tabulated-list-entries', and should return a list in the format
+suitable for `tabulated-list-groups'.  Also when this variable is non-nil,
+then `outline-minor-mode' is enabled in the Buffer Menu.  Then with the
+default value of `outline-regexp' you can use Outline minor mode commands
+to show/hide groups of buffers.
+The default options can group by a mode, and by a root directory of
+a project or just `default-directory'."
+  :type '(choice (const :tag "No grouping" nil)
+                 (function-item :tag "Group by mode"
+                                Buffer-menu-group-by-mode)
+                 (function-item :tag "Group by root"
+                                Buffer-menu-group-by-root)
+                 (function :tag "Custom function"))
+  :group 'Buffer-menu
+  :version "30.1")
+
 (defvar-local Buffer-menu-files-only nil
   "Non-nil if the current Buffer Menu lists only file buffers.
 This is set by the prefix argument to `buffer-menu' and related
@@ -674,7 +691,12 @@ list-buffers-noselect
       (setq Buffer-menu-buffer-list buffer-list)
       (setq Buffer-menu-filter-predicate filter-predicate)
       (list-buffers--refresh buffer-list old-buffer)
-      (tabulated-list-print))
+      (tabulated-list-print)
+      (when tabulated-list-groups
+        (setq-local outline-minor-mode-cycle t
+                    outline-minor-mode-highlight t
+                    outline-minor-mode-use-buttons 'in-margins)
+        (outline-minor-mode 1)))
     buffer))
 
 (defun Buffer-menu-mouse-select (event)
@@ -750,7 +772,11 @@ list-buffers--refresh
 		  `("Mode" ,Buffer-menu-mode-width t)
 		  '("File" 1 t)))
     (setq tabulated-list-use-header-line Buffer-menu-use-header-line)
-    (setq tabulated-list-entries (nreverse entries)))
+    (setq tabulated-list-entries (nreverse entries))
+    (when Buffer-menu-group-by
+      (setq tabulated-list-groups
+            (seq-group-by Buffer-menu-group-by
+                          tabulated-list-entries))))
   (tabulated-list-init-header))
 
 (defun tabulated-list-entry-size-> (entry1 entry2)
@@ -769,4 +795,13 @@ Buffer-menu--pretty-file-name
          (abbreviate-file-name list-buffers-directory))
 	(t "")))
 
+(defun Buffer-menu-group-by-mode (entry)
+  (concat "* " (aref (cadr entry) 5)))
+
+(defun Buffer-menu-group-by-root (entry)
+  (with-current-buffer (car entry)
+    (if-let ((project (project-current)))
+        (concat "* " (project-root project))
+      (concat "* " default-directory))))
+
 ;;; buff-menu.el ends here
diff --git a/lisp/emacs-lisp/tabulated-list.el b/lisp/emacs-lisp/tabulated-list.el
index 9884a2fc24b..a78e1726c26 100644
--- a/lisp/emacs-lisp/tabulated-list.el
+++ b/lisp/emacs-lisp/tabulated-list.el
@@ -139,6 +139,21 @@ tabulated-list-entries
 arguments and must return a list of the above form.")
 (put 'tabulated-list-entries 'permanent-local t)
 
+(defvar-local tabulated-list-groups nil
+  "Groups displayed in the current Tabulated List buffer.
+This should be either a function, or a list.
+If a list, each element has the form (GROUP-NAME ENTRIES),
+where:
+
+ - GROUP-NAME is a group name as a string, which is displayed
+   at the top line of each group.
+
+ - ENTRIES is a list described in `tabulated-list-entries'.
+
+If `tabulated-list-groups' is a function, it is called with no
+arguments and must return a list of the above form.")
+(put 'tabulated-list-groups 'permanent-local t)
+
 (defvar-local tabulated-list-padding 0
   "Number of characters preceding each Tabulated List mode entry.
 By default, lines are padded with spaces, but you can use the
@@ -427,6 +444,9 @@ tabulated-list-print
 specified by `tabulated-list-sort-key'.  It then erases the
 buffer and inserts the entries with `tabulated-list-printer'.
 
+If `tabulated-list-groups' is non-nil, each group of entries
+is sorted separately after printing the group header line.
+
 Optional argument REMEMBER-POS, if non-nil, means to move point
 to the entry with the same ID element as the current line.
 
@@ -437,6 +457,9 @@ tabulated-list-print
 `tabulated-list-put-tag').  Don't use this immediately after
 changing `tabulated-list-sort-key'."
   (let ((inhibit-read-only t)
+        (groups (if (functionp tabulated-list-groups)
+		    (funcall tabulated-list-groups)
+		  tabulated-list-groups))
 	(entries (if (functionp tabulated-list-entries)
 		     (funcall tabulated-list-entries)
 		   tabulated-list-entries))
@@ -447,7 +470,14 @@ tabulated-list-print
 	 (setq saved-col (current-column)))
     ;; Sort the entries, if necessary.
     (when sorter
-      (setq entries (sort entries sorter)))
+      (if groups
+          (setq groups
+                (mapcar (lambda (group)
+                          (cons (car group) (sort (cdr group) sorter)))
+                        groups))
+        (setq entries (sort entries sorter))))
+    (unless (functionp tabulated-list-groups)
+      (setq tabulated-list-groups groups))
     (unless (functionp tabulated-list-entries)
       (setq tabulated-list-entries entries))
     ;; Without a sorter, we have no way to just update.
@@ -459,6 +489,25 @@ tabulated-list-print
       (unless tabulated-list-use-header-line
         (tabulated-list-print-fake-header)))
     ;; Finally, print the resulting list.
+    (if groups
+        (dolist (group groups)
+          (insert (car group) ?\n)
+          (when-let ((saved-pt-new (tabulated-list-print-entries
+                                    (cdr group) sorter update entry-id)))
+            (setq saved-pt saved-pt-new)))
+      (setq saved-pt (tabulated-list-print-entries
+                      entries sorter update entry-id)))
+    (when update
+      (delete-region (point) (point-max)))
+    (set-buffer-modified-p nil)
+    ;; If REMEMBER-POS was specified, move to the "old" location.
+    (if saved-pt
+	(progn (goto-char saved-pt)
+	       (move-to-column saved-col))
+      (goto-char (point-min)))))
+
+(defun tabulated-list-print-entries (entries sorter update entry-id)
+  (let (saved-pt)
     (while entries
       (let* ((elt (car entries))
              (tabulated-list--near-rows
@@ -495,14 +544,7 @@ tabulated-list-print
               (forward-line 1)
               (delete-region old (point))))))
       (setq entries (cdr entries)))
-    (when update
-      (delete-region (point) (point-max)))
-    (set-buffer-modified-p nil)
-    ;; If REMEMBER-POS was specified, move to the "old" location.
-    (if saved-pt
-	(progn (goto-char saved-pt)
-	       (move-to-column saved-col))
-      (goto-char (point-min)))))
+    saved-pt))
 
 (defun tabulated-list-print-entry (id cols)
   "Insert a Tabulated List entry at point.
diff --git a/test/lisp/emacs-lisp/tabulated-list-tests.el b/test/lisp/emacs-lisp/tabulated-list-tests.el
index 8be2be3139e..e53268b3f14 100644
--- a/test/lisp/emacs-lisp/tabulated-list-tests.el
+++ b/test/lisp/emacs-lisp/tabulated-list-tests.el
@@ -130,4 +130,45 @@ tabulated-list-sort
    (should-error (tabulated-list-sort) :type 'user-error)
    (should-error (tabulated-list-sort 4) :type 'user-error)))
 
+(ert-deftest tabulated-list-groups ()
+  (with-temp-buffer
+    (tabulated-list-mode)
+    (setq tabulated-list-groups
+          (reverse
+           (seq-group-by (lambda (b) (concat "* " (aref (cadr b) 3)))
+                         tabulated-list--test-entries)))
+    (setq tabulated-list-format tabulated-list--test-format)
+    (setq tabulated-list-padding 7)
+    (tabulated-list-init-header)
+    (tabulated-list-print)
+    ;; Basic printing.
+    (should (string-equal
+             (buffer-substring-no-properties (point-min) (point-max))
+             "\
+* installed
+       zzzz-game  zzzz-game  2113      installed   play zzzz in Emacs
+       mode       mode       1128      installed   A simple mode for editing Actionscript 3 files
+* available
+       abc-mode   abc-mode   944       available   Major mode for editing abc music files
+* obsolete
+       4clojure   4clojure   1507      obsolete    Open and evaluate 4clojure.com questions
+"))
+    ;; Sort and preserve position.
+    (forward-line 2)
+    (let ((pos (thing-at-point 'line)))
+      (tabulated-list-next-column 2)
+      (tabulated-list-sort)
+      (should (equal (thing-at-point 'line) pos))
+      (should (string-equal
+               (buffer-substring-no-properties (point-min) (point-max))
+               "\
+* installed
+       mode       mode       1128      installed   A simple mode for editing Actionscript 3 files
+       zzzz-game  zzzz-game  2113      installed   play zzzz in Emacs
+* available
+       abc-mode   abc-mode   944       available   Major mode for editing abc music files
+* obsolete
+       4clojure   4clojure   1507      obsolete    Open and evaluate 4clojure.com questions
+")))))
+
 ;;; tabulated-list-tests.el ends here

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-22  7:44   ` Juri Linkov
@ 2024-02-22  8:20     ` Eli Zaretskii
  2024-02-22 17:30       ` Juri Linkov
  2024-02-24 18:06     ` Ihor Radchenko
  1 sibling, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2024-02-22  8:20 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 69305

> From: Juri Linkov <juri@linkov.net>
> Cc: 69305@debbugs.gnu.org
> Date: Thu, 22 Feb 2024 09:44:40 +0200
> 
> > Thanks, but I wonder if we can be a tad more user-friendly?  The user
> > option exists, and it can accept simple enough data structures for
> > customizations, but the default is nil, and there's no example or
> > pre-cooked list of ready-to-use values anywhere in sight, not even in
> > the doc string.  Users will have to work hard to produce a grouping of
> > their liking.  E.g., suppose I want to group buffers by mode -- how
> > would I go about it?  Or what about grouping buffers by their leading
> > directories -- how can that be done?  Etc. etc. -- this could be a
> > very powerful feature, but we should make its use easier.  And, after
> > reading the documentation of tabulated-list-groups and that of
> > tabulated-list-entries several times, I have no idea how to specify
> > simple groupings such as those described above.  Which makes examples
> > or pre-cooked values even more important, IMO.
> 
> Ok, then this patch adds two pre-cooked functions as a starting point
> for users to understand the principle.  Then users will propose
> more functions and we will choose the most useful candidates
> for including to the set of default functions later.

Thanks.

> +@defvar tabulated-list-groups
> +This buffer-local variable specifies the groups of entries displayed in
> +the Tabulated List buffer.  Its value should be either a list, or a
> +function.
> +
> +If the value is a list, each list element corresponds to one group, and
> +should have the form @w{@code{(@var{group-name} @var{entries})}}, where
> +@var{group-name} is a string inserted before all group entries, and
> +@var{entries} have the same format as @code{tabulated-list-entries}
> +(see above).
> +
> +Otherwise, the value should be a function which returns a list of the
> +above form when called with no arguments.
> +@end defvar

I think the way to specify ENTRIES for this customization should be
described in more detail.  Reading the above description, even the
idea of using ENTRIES for specifying grouping is unclear, since
tabulated-list-entries is basically just a list of column descriptors.

> +(defcustom Buffer-menu-group-by nil
> +  "If non-nil, buffers are grouped by function.
> +This function takes one argument: a list of entries in the same format
> +as in `tabulated-list-entries', and should return a list in the format
> +suitable for `tabulated-list-groups'.  Also when this variable is non-nil,
> +then `outline-minor-mode' is enabled in the Buffer Menu.  Then with the
> +default value of `outline-regexp' you can use Outline minor mode commands
> +to show/hide groups of buffers.
> +The default options can group by a mode, and by a root directory of
> +a project or just `default-directory'."
> +  :type '(choice (const :tag "No grouping" nil)
> +                 (function-item :tag "Group by mode"
> +                                Buffer-menu-group-by-mode)
> +                 (function-item :tag "Group by root"
> +                                Buffer-menu-group-by-root)

I think the description text should be "Group by project" or "Group by
project root directory" or maybe "Group by project or directory".
Just "by root" is too vague.

> +If `tabulated-list-groups' is non-nil, each group of entries
> +is sorted separately after printing the group header line.

The part following "after printing" is IMO more confusing than
helpful.  What will be lost if you remove it?

> +(ert-deftest tabulated-list-groups ()
> +  (with-temp-buffer
> +    (tabulated-list-mode)
> +    (setq tabulated-list-groups
> +          (reverse
> +           (seq-group-by (lambda (b) (concat "* " (aref (cadr b) 3)))
> +                         tabulated-list--test-entries)))
> +    (setq tabulated-list-format tabulated-list--test-format)
> +    (setq tabulated-list-padding 7)
> +    (tabulated-list-init-header)
> +    (tabulated-list-print)

This seems to test only the function value of tabulated-list-groups?
What about the other form of the value?





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-22  8:20     ` Eli Zaretskii
@ 2024-02-22 17:30       ` Juri Linkov
  2024-02-22 19:10         ` Eli Zaretskii
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-02-22 17:30 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 69305

>> +@defvar tabulated-list-groups
>> +This buffer-local variable specifies the groups of entries displayed in
>> +the Tabulated List buffer.  Its value should be either a list, or a
>> +function.
>> +
>> +If the value is a list, each list element corresponds to one group, and
>> +should have the form @w{@code{(@var{group-name} @var{entries})}}, where
>> +@var{group-name} is a string inserted before all group entries, and
>> +@var{entries} have the same format as @code{tabulated-list-entries}
>> +(see above).
>> +
>> +Otherwise, the value should be a function which returns a list of the
>> +above form when called with no arguments.
>> +@end defvar
>
> I think the way to specify ENTRIES for this customization should be
> described in more detail.  Reading the above description, even the
> idea of using ENTRIES for specifying grouping is unclear, since
> tabulated-list-entries is basically just a list of column descriptors.

But ENTRIES are described in 'tabulated-list-entries'.  Here ENTRIES
are no different from 'tabulated-list-entries' that are just
column descriptors.

>> +(defcustom Buffer-menu-group-by nil
>> +  "If non-nil, buffers are grouped by function.
>> +This function takes one argument: a list of entries in the same format
>> +as in `tabulated-list-entries', and should return a list in the format
>> +suitable for `tabulated-list-groups'.  Also when this variable is non-nil,
>> +then `outline-minor-mode' is enabled in the Buffer Menu.  Then with the
>> +default value of `outline-regexp' you can use Outline minor mode commands
>> +to show/hide groups of buffers.
>> +The default options can group by a mode, and by a root directory of
>> +a project or just `default-directory'."
>> +  :type '(choice (const :tag "No grouping" nil)
>> +                 (function-item :tag "Group by mode"
>> +                                Buffer-menu-group-by-mode)
>> +                 (function-item :tag "Group by root"
>> +                                Buffer-menu-group-by-root)
>
> I think the description text should be "Group by project" or "Group by
> project root directory" or maybe "Group by project or directory".
> Just "by root" is too vague.

Ok, then will use "Group by project root or directory".

>> +If `tabulated-list-groups' is non-nil, each group of entries
>> +is sorted separately after printing the group header line.
>
> The part following "after printing" is IMO more confusing than
> helpful.  What will be lost if you remove it?

Oops, this was too ugly, will remove this part.

>> +(ert-deftest tabulated-list-groups ()
>> +  (with-temp-buffer
>> +    (tabulated-list-mode)
>> +    (setq tabulated-list-groups
>> +          (reverse
>> +           (seq-group-by (lambda (b) (concat "* " (aref (cadr b) 3)))
>> +                         tabulated-list--test-entries)))
>> +    (setq tabulated-list-format tabulated-list--test-format)
>> +    (setq tabulated-list-padding 7)
>> +    (tabulated-list-init-header)
>> +    (tabulated-list-print)
>
> This seems to test only the function value of tabulated-list-groups?
> What about the other form of the value?

The other forms have no functional difference.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-22 17:30       ` Juri Linkov
@ 2024-02-22 19:10         ` Eli Zaretskii
  2024-02-23  7:09           ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2024-02-22 19:10 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 69305

> From: Juri Linkov <juri@linkov.net>
> Cc: 69305@debbugs.gnu.org
> Date: Thu, 22 Feb 2024 19:30:20 +0200
> 
> >> +@defvar tabulated-list-groups
> >> +This buffer-local variable specifies the groups of entries displayed in
> >> +the Tabulated List buffer.  Its value should be either a list, or a
> >> +function.
> >> +
> >> +If the value is a list, each list element corresponds to one group, and
> >> +should have the form @w{@code{(@var{group-name} @var{entries})}}, where
> >> +@var{group-name} is a string inserted before all group entries, and
> >> +@var{entries} have the same format as @code{tabulated-list-entries}
> >> +(see above).
> >> +
> >> +Otherwise, the value should be a function which returns a list of the
> >> +above form when called with no arguments.
> >> +@end defvar
> >
> > I think the way to specify ENTRIES for this customization should be
> > described in more detail.  Reading the above description, even the
> > idea of using ENTRIES for specifying grouping is unclear, since
> > tabulated-list-entries is basically just a list of column descriptors.
> 
> But ENTRIES are described in 'tabulated-list-entries'.  Here ENTRIES
> are no different from 'tabulated-list-entries' that are just
> column descriptors.

My point is that it isn't obvious how to describe grouping in terms of
column descriptors.  I think the manual should tell in more detail how
to use column descriptors to specify how entries should be grouped.
Maybe an example or two is all that it takes to do that.

> >> +(ert-deftest tabulated-list-groups ()
> >> +  (with-temp-buffer
> >> +    (tabulated-list-mode)
> >> +    (setq tabulated-list-groups
> >> +          (reverse
> >> +           (seq-group-by (lambda (b) (concat "* " (aref (cadr b) 3)))
> >> +                         tabulated-list--test-entries)))
> >> +    (setq tabulated-list-format tabulated-list--test-format)
> >> +    (setq tabulated-list-padding 7)
> >> +    (tabulated-list-init-header)
> >> +    (tabulated-list-print)
> >
> > This seems to test only the function value of tabulated-list-groups?
> > What about the other form of the value?
> 
> The other forms have no functional difference.

Sorry, I don't follow.  Shouldn't we test the capability of specifying
grouping by the method other than by providing a function?





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-22 19:10         ` Eli Zaretskii
@ 2024-02-23  7:09           ` Juri Linkov
  2024-02-23  8:13             ` Eli Zaretskii
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-02-23  7:09 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 69305

>> >> +@defvar tabulated-list-groups
>> >> +This buffer-local variable specifies the groups of entries displayed in
>> >> +the Tabulated List buffer.  Its value should be either a list, or a
>> >> +function.
>> >> +
>> >> +If the value is a list, each list element corresponds to one group, and
>> >> +should have the form @w{@code{(@var{group-name} @var{entries})}}, where
>> >> +@var{group-name} is a string inserted before all group entries, and
>> >> +@var{entries} have the same format as @code{tabulated-list-entries}
>> >> +(see above).
>> >> +
>> >> +Otherwise, the value should be a function which returns a list of the
>> >> +above form when called with no arguments.
>> >> +@end defvar
>> >
>> > I think the way to specify ENTRIES for this customization should be
>> > described in more detail.  Reading the above description, even the
>> > idea of using ENTRIES for specifying grouping is unclear, since
>> > tabulated-list-entries is basically just a list of column descriptors.
>>
>> But ENTRIES are described in 'tabulated-list-entries'.  Here ENTRIES
>> are no different from 'tabulated-list-entries' that are just
>> column descriptors.
>
> My point is that it isn't obvious how to describe grouping in terms of
> column descriptors.  I think the manual should tell in more detail how
> to use column descriptors to specify how entries should be grouped.
> Maybe an example or two is all that it takes to do that.

Sorry, I don't understand what is unclear here:

  If the value is a list, each list element corresponds to one group, and
  should have the form @w{@code{(@var{group-name} @var{entries})}}, where
  @var{group-name} is a string inserted before all group entries, and
  @var{entries} have the same format as @code{tabulated-list-entries}
  (see above).

Basically this says that the format is (group-name entries) where
entries are described in tabulated-list-entries as having the format
(id contents).  There is no need to duplicate the description of entries.

>> >> +(ert-deftest tabulated-list-groups ()
>> >> +  (with-temp-buffer
>> >> +    (tabulated-list-mode)
>> >> +    (setq tabulated-list-groups
>> >> +          (reverse
>> >> +           (seq-group-by (lambda (b) (concat "* " (aref (cadr b) 3)))
>> >> +                         tabulated-list--test-entries)))
>> >> +    (setq tabulated-list-format tabulated-list--test-format)
>> >> +    (setq tabulated-list-padding 7)
>> >> +    (tabulated-list-init-header)
>> >> +    (tabulated-list-print)
>> >
>> > This seems to test only the function value of tabulated-list-groups?
>> > What about the other form of the value?
>>
>> The other forms have no functional difference.
>
> Sorry, I don't follow.  Shouldn't we test the capability of specifying
> grouping by the method other than by providing a function?

Actually there are no other methods.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-23  7:09           ` Juri Linkov
@ 2024-02-23  8:13             ` Eli Zaretskii
  2024-02-24 17:43               ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2024-02-23  8:13 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 69305

> From: Juri Linkov <juri@linkov.net>
> Cc: 69305@debbugs.gnu.org
> Date: Fri, 23 Feb 2024 09:09:03 +0200
> 
> >> >> +@defvar tabulated-list-groups
> >> >> +This buffer-local variable specifies the groups of entries displayed in
> >> >> +the Tabulated List buffer.  Its value should be either a list, or a
> >> >> +function.
> >> >> +
> >> >> +If the value is a list, each list element corresponds to one group, and
> >> >> +should have the form @w{@code{(@var{group-name} @var{entries})}}, where
> >> >> +@var{group-name} is a string inserted before all group entries, and
> >> >> +@var{entries} have the same format as @code{tabulated-list-entries}
> >> >> +(see above).
> >> >> +
> >> >> +Otherwise, the value should be a function which returns a list of the
> >> >> +above form when called with no arguments.
> >> >> +@end defvar
> >> >
> >> > I think the way to specify ENTRIES for this customization should be
> >> > described in more detail.  Reading the above description, even the
> >> > idea of using ENTRIES for specifying grouping is unclear, since
> >> > tabulated-list-entries is basically just a list of column descriptors.
> >>
> >> But ENTRIES are described in 'tabulated-list-entries'.  Here ENTRIES
> >> are no different from 'tabulated-list-entries' that are just
> >> column descriptors.
> >
> > My point is that it isn't obvious how to describe grouping in terms of
> > column descriptors.  I think the manual should tell in more detail how
> > to use column descriptors to specify how entries should be grouped.
> > Maybe an example or two is all that it takes to do that.
> 
> Sorry, I don't understand what is unclear here:
> 
>   If the value is a list, each list element corresponds to one group, and
>   should have the form @w{@code{(@var{group-name} @var{entries})}}, where
>   @var{group-name} is a string inserted before all group entries, and
>   @var{entries} have the same format as @code{tabulated-list-entries}
>   (see above).
> 
> Basically this says that the format is (group-name entries) where
> entries are described in tabulated-list-entries as having the format
> (id contents).  There is no need to duplicate the description of entries.

Maybe I'm missing something here.  To put it more concretely, can you
show a value of tabulated-list-groups that will cause the buffers in
buffer list grouped by major mode using the above form?

> >> >> +(ert-deftest tabulated-list-groups ()
> >> >> +  (with-temp-buffer
> >> >> +    (tabulated-list-mode)
> >> >> +    (setq tabulated-list-groups
> >> >> +          (reverse
> >> >> +           (seq-group-by (lambda (b) (concat "* " (aref (cadr b) 3)))
> >> >> +                         tabulated-list--test-entries)))
> >> >> +    (setq tabulated-list-format tabulated-list--test-format)
> >> >> +    (setq tabulated-list-padding 7)
> >> >> +    (tabulated-list-init-header)
> >> >> +    (tabulated-list-print)
> >> >
> >> > This seems to test only the function value of tabulated-list-groups?
> >> > What about the other form of the value?
> >>
> >> The other forms have no functional difference.
> >
> > Sorry, I don't follow.  Shouldn't we test the capability of specifying
> > grouping by the method other than by providing a function?
> 
> Actually there are no other methods.

The doc string says the "value can be either a list or a function".  I
see only one value here, so I'm asking what about a value of the other
form.  Or what am I missing here?





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-23  8:13             ` Eli Zaretskii
@ 2024-02-24 17:43               ` Juri Linkov
  2024-02-24 18:09                 ` Eli Zaretskii
  2024-02-24 18:13                 ` Eli Zaretskii
  0 siblings, 2 replies; 37+ messages in thread
From: Juri Linkov @ 2024-02-24 17:43 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 69305

>> >> >> +@defvar tabulated-list-groups
>> >> >> +This buffer-local variable specifies the groups of entries displayed in
>> >> >> +the Tabulated List buffer.  Its value should be either a list, or a
>> >> >> +function.
>> >> >> +
>> >> >> +If the value is a list, each list element corresponds to one group, and
>> >> >> +should have the form @w{@code{(@var{group-name} @var{entries})}}, where
>> >> >> +@var{group-name} is a string inserted before all group entries, and
>> >> >> +@var{entries} have the same format as @code{tabulated-list-entries}
>> >> >> +(see above).
>> >> >> +
>> >> >> +Otherwise, the value should be a function which returns a list of the
>> >> >> +above form when called with no arguments.
>> >> >> +@end defvar
>> >> >
>> >> > I think the way to specify ENTRIES for this customization should be
>> >> > described in more detail.  Reading the above description, even the
>> >> > idea of using ENTRIES for specifying grouping is unclear, since
>> >> > tabulated-list-entries is basically just a list of column descriptors.
>> >>
>> >> But ENTRIES are described in 'tabulated-list-entries'.  Here ENTRIES
>> >> are no different from 'tabulated-list-entries' that are just
>> >> column descriptors.
>> >
>> > My point is that it isn't obvious how to describe grouping in terms of
>> > column descriptors.  I think the manual should tell in more detail how
>> > to use column descriptors to specify how entries should be grouped.
>> > Maybe an example or two is all that it takes to do that.
>>
>> Sorry, I don't understand what is unclear here:
>>
>>   If the value is a list, each list element corresponds to one group, and
>>   should have the form @w{@code{(@var{group-name} @var{entries})}}, where
>>   @var{group-name} is a string inserted before all group entries, and
>>   @var{entries} have the same format as @code{tabulated-list-entries}
>>   (see above).
>>
>> Basically this says that the format is (group-name entries) where
>> entries are described in tabulated-list-entries as having the format
>> (id contents).  There is no need to duplicate the description of entries.
>
> Maybe I'm missing something here.  To put it more concretely, can you
> show a value of tabulated-list-groups that will cause the buffers in
> buffer list grouped by major mode using the above form?

Data structure for `tabulated-list-groups' is a list of elements,
each element should of the form

  (GROUP-NAME (ID . CONTENTS) (ID . CONTENTS) ...)

where GROUP-NAME is the name of the group, ID is a Lisp object that
identifies the entry and CONTENTS is a vector with the same number of
elements as `tabulated-list-format'.  When buffers grouped by major mode:

  (("* Lisp Interaction" (#<buffer *scratch*> ["." " " "*" #("*scratch*" 0 9 ...) "225" "Lisp Interaction" ""]) ...))

>> >> >> +(ert-deftest tabulated-list-groups ()
>> >> >> +  (with-temp-buffer
>> >> >> +    (tabulated-list-mode)
>> >> >> +    (setq tabulated-list-groups
>> >> >> +          (reverse
>> >> >> +           (seq-group-by (lambda (b) (concat "* " (aref (cadr b) 3)))
>> >> >> +                         tabulated-list--test-entries)))
>> >> >> +    (setq tabulated-list-format tabulated-list--test-format)
>> >> >> +    (setq tabulated-list-padding 7)
>> >> >> +    (tabulated-list-init-header)
>> >> >> +    (tabulated-list-print)
>> >> >
>> >> > This seems to test only the function value of tabulated-list-groups?
>> >> > What about the other form of the value?
>> >>
>> >> The other forms have no functional difference.
>> >
>> > Sorry, I don't follow.  Shouldn't we test the capability of specifying
>> > grouping by the method other than by providing a function?
>>
>> Actually there are no other methods.
>
> The doc string says the "value can be either a list or a function".  I
> see only one value here, so I'm asking what about a value of the other
> form.  Or what am I missing here?

Another form is a function.  But there is no need to test this.
It's just a copy from tabulated-list-entries that is unused.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-22  7:44   ` Juri Linkov
  2024-02-22  8:20     ` Eli Zaretskii
@ 2024-02-24 18:06     ` Ihor Radchenko
  2024-02-24 18:16       ` Eli Zaretskii
  2024-02-25 17:20       ` Juri Linkov
  1 sibling, 2 replies; 37+ messages in thread
From: Ihor Radchenko @ 2024-02-24 18:06 UTC (permalink / raw)
  To: Juri Linkov, Adam Porter; +Cc: 69305, Eli Zaretskii

Juri Linkov <juri@linkov.net> writes:

> +@defvar tabulated-list-groups
> +This buffer-local variable specifies the groups of entries displayed in
> +the Tabulated List buffer.  Its value should be either a list, or a
> +function.
> +
> +If the value is a list, each list element corresponds to one group, and
> +should have the form @w{@code{(@var{group-name} @var{entries})}}, where
> +@var{group-name} is a string inserted before all group entries, and
> +@var{entries} have the same format as @code{tabulated-list-entries}
> +(see above).
> +
> +Otherwise, the value should be a function which returns a list of the
> +above form when called with no arguments.
> +@end defvar

I am wondering if flexible grouping system from Adam's org-super-agenda
package may provide some inspiration.
Check out
https://github.com/alphapapa/org-super-agenda/?tab=readme-ov-file#usage

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-24 17:43               ` Juri Linkov
@ 2024-02-24 18:09                 ` Eli Zaretskii
  2024-02-24 18:13                 ` Eli Zaretskii
  1 sibling, 0 replies; 37+ messages in thread
From: Eli Zaretskii @ 2024-02-24 18:09 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 69305






^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-24 17:43               ` Juri Linkov
  2024-02-24 18:09                 ` Eli Zaretskii
@ 2024-02-24 18:13                 ` Eli Zaretskii
  2024-02-25  8:00                   ` Adam Porter
  2024-02-25 17:25                   ` Juri Linkov
  1 sibling, 2 replies; 37+ messages in thread
From: Eli Zaretskii @ 2024-02-24 18:13 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 69305

> From: Juri Linkov <juri@linkov.net>
> Cc: 69305@debbugs.gnu.org
> Date: Sat, 24 Feb 2024 19:43:25 +0200
> 
> >> Sorry, I don't understand what is unclear here:
> >>
> >>   If the value is a list, each list element corresponds to one group, and
> >>   should have the form @w{@code{(@var{group-name} @var{entries})}}, where
> >>   @var{group-name} is a string inserted before all group entries, and
> >>   @var{entries} have the same format as @code{tabulated-list-entries}
> >>   (see above).
> >>
> >> Basically this says that the format is (group-name entries) where
> >> entries are described in tabulated-list-entries as having the format
> >> (id contents).  There is no need to duplicate the description of entries.
> >
> > Maybe I'm missing something here.  To put it more concretely, can you
> > show a value of tabulated-list-groups that will cause the buffers in
> > buffer list grouped by major mode using the above form?
> 
> Data structure for `tabulated-list-groups' is a list of elements,
> each element should of the form
> 
>   (GROUP-NAME (ID . CONTENTS) (ID . CONTENTS) ...)
> 
> where GROUP-NAME is the name of the group, ID is a Lisp object that
> identifies the entry and CONTENTS is a vector with the same number of
> elements as `tabulated-list-format'.  When buffers grouped by major mode:
> 
>   (("* Lisp Interaction" (#<buffer *scratch*> ["." " " "*" #("*scratch*" 0 9 ...) "225" "Lisp Interaction" ""]) ...))

This is the value that the user is supposed to supply for the
defcustom?  That is, the user must specify all the buffers explicitly?
What happens when there's one more buffer in some mode? does the user
have then to modify the value of the defcustom?

> >> >> >> +(ert-deftest tabulated-list-groups ()
> >> >> >> +  (with-temp-buffer
> >> >> >> +    (tabulated-list-mode)
> >> >> >> +    (setq tabulated-list-groups
> >> >> >> +          (reverse
> >> >> >> +           (seq-group-by (lambda (b) (concat "* " (aref (cadr b) 3)))
> >> >> >> +                         tabulated-list--test-entries)))
> >> >> >> +    (setq tabulated-list-format tabulated-list--test-format)
> >> >> >> +    (setq tabulated-list-padding 7)
> >> >> >> +    (tabulated-list-init-header)
> >> >> >> +    (tabulated-list-print)
> >> >> >
> >> >> > This seems to test only the function value of tabulated-list-groups?
> >> >> > What about the other form of the value?
> >> >>
> >> >> The other forms have no functional difference.
> >> >
> >> > Sorry, I don't follow.  Shouldn't we test the capability of specifying
> >> > grouping by the method other than by providing a function?
> >>
> >> Actually there are no other methods.
> >
> > The doc string says the "value can be either a list or a function".  I
> > see only one value here, so I'm asking what about a value of the other
> > form.  Or what am I missing here?
> 
> Another form is a function.  But there is no need to test this.
> It's just a copy from tabulated-list-entries that is unused.

I give up.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-24 18:06     ` Ihor Radchenko
@ 2024-02-24 18:16       ` Eli Zaretskii
  2024-02-24 18:36         ` Ihor Radchenko
  2024-02-25 17:20       ` Juri Linkov
  1 sibling, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2024-02-24 18:16 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: adam, 69305, juri

> From: Ihor Radchenko <yantar92@posteo.net>
> Cc: Eli Zaretskii <eliz@gnu.org>, 69305@debbugs.gnu.org
> Date: Sat, 24 Feb 2024 18:06:46 +0000
> 
> I am wondering if flexible grouping system from Adam's org-super-agenda
> package may provide some inspiration.
> Check out
> https://github.com/alphapapa/org-super-agenda/?tab=readme-ov-file#usage

What I had in mind was much simpler to use.  But I guess I'm the only
one who wants to let users set up grouping in some easy way, because
I'm being shown more and more complicated customizations, claiming
they are suitable.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-24 18:16       ` Eli Zaretskii
@ 2024-02-24 18:36         ` Ihor Radchenko
  2024-02-24 18:49           ` Eli Zaretskii
  0 siblings, 1 reply; 37+ messages in thread
From: Ihor Radchenko @ 2024-02-24 18:36 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: adam, 69305, juri

Eli Zaretskii <eliz@gnu.org> writes:

>> I am wondering if flexible grouping system from Adam's org-super-agenda
>> package may provide some inspiration.
>> Check out
>> https://github.com/alphapapa/org-super-agenda/?tab=readme-ov-file#usage
>
> What I had in mind was much simpler to use.  But I guess I'm the only
> one who wants to let users set up grouping in some easy way, because
> I'm being shown more and more complicated customizations, claiming
> they are suitable.

Don't be deceived by the length of org-super-agenda readme.
Most of the keywords listed there are an equivalent to column names in
tabulated-list-mode.

What might be relevant are the following group customizations:

    :face
    A face to apply to items in the group. If face is a plist containing
    :append t, it will be appended. See function add-face-text-property.
    
    :transformer
    Used to transform item strings before display. Either a function
    called with one argument, the item string, or a sexp, in which case
    the item string is bound to it.

and the following options to provide automatic grouping without a need
to write dedicated function:

    :and
    Group ITEMS that match all selectors in GROUP.
    
    :anything
    Select every item, no matter what. This is probably most useful with
    :discard, because it doesn’t actually test anything, so it’s faster
    than, e.g. ~:regexp “.”~, which has to get the entry text for every
    item.
    
    :discard
    Discard items that match selectors. Any groups processed after this one
    will not see discarded items. You might use this at the beginning or end
    of a list of groups, either to narrow down the list of items (used in
    combination with :not), or to exclude items you’re not interested in.
    
    :not
    Group ITEMS that match no selectors in GROUP.
    Note that the :not group selector creates a group with items it does not
    match; it can be combined with :discard to discard items that don’t
    match. For example, (:discard (:not (:priority "A"))) as the first
    selector would mean that only priority A items would appear in the
    agenda, while (:discard (:priority "C")) would mean that any priority C
    items would not appear in the agenda.
    
    :order
    A number setting the order sections will be displayed in the agenda,
    lowest number first. Defaults to 0.
    
    :order-multi
    Set the order of multiple groups at once, like (:order-multi (2 (groupA)
    (groupB) ...)) to set the order of these groups to 2.
    
    :take
    Take the first N items in GROUP. If N is negative, take the last N
    items. For example, (:take (-3 group)) will take the last 3 items from
    the group. The remainder of items are discarded. Note: The order of
    entries from GROUP is not guaranteed to be preserved, so :take may not
    always show expected entries.

-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-24 18:36         ` Ihor Radchenko
@ 2024-02-24 18:49           ` Eli Zaretskii
  2024-02-25  7:45             ` Adam Porter
  2024-02-25  7:53             ` Adam Porter
  0 siblings, 2 replies; 37+ messages in thread
From: Eli Zaretskii @ 2024-02-24 18:49 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: adam, 69305, juri

> From: Ihor Radchenko <yantar92@posteo.net>
> Cc: juri@linkov.net, adam@alphapapa.net, 69305@debbugs.gnu.org
> Date: Sat, 24 Feb 2024 18:36:23 +0000
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> 
> >> I am wondering if flexible grouping system from Adam's org-super-agenda
> >> package may provide some inspiration.
> >> Check out
> >> https://github.com/alphapapa/org-super-agenda/?tab=readme-ov-file#usage
> >
> > What I had in mind was much simpler to use.  But I guess I'm the only
> > one who wants to let users set up grouping in some easy way, because
> > I'm being shown more and more complicated customizations, claiming
> > they are suitable.
> 
> Don't be deceived by the length of org-super-agenda readme.
> Most of the keywords listed there are an equivalent to column names in
> tabulated-list-mode.

Did you read what I suggested as the preferred way of specifying the
grouping?  It's way simpler than what org-super-agenda expects.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-24 18:49           ` Eli Zaretskii
@ 2024-02-25  7:45             ` Adam Porter
  2024-02-25 17:36               ` Juri Linkov
  2024-02-25  7:53             ` Adam Porter
  1 sibling, 1 reply; 37+ messages in thread
From: Adam Porter @ 2024-02-25  7:45 UTC (permalink / raw)
  To: Eli Zaretskii, Ihor Radchenko; +Cc: 69305, juri

Hi,

On 2/24/24 12:49, Eli Zaretskii wrote:
>> From: Ihor Radchenko <yantar92@posteo.net>
>> Cc: juri@linkov.net, adam@alphapapa.net, 69305@debbugs.gnu.org
>> Date: Sat, 24 Feb 2024 18:36:23 +0000
>>
>> Eli Zaretskii <eliz@gnu.org> writes:
>>
>>>> I am wondering if flexible grouping system from Adam's org-super-agenda
>>>> package may provide some inspiration.
>>>> Check out
>>>> https://github.com/alphapapa/org-super-agenda/?tab=readme-ov-file#usage
>>>
>>> What I had in mind was much simpler to use.  But I guess I'm the only
>>> one who wants to let users set up grouping in some easy way, because
>>> I'm being shown more and more complicated customizations, claiming
>>> they are suitable.
>>
>> Don't be deceived by the length of org-super-agenda readme.
>> Most of the keywords listed there are an equivalent to column names in
>> tabulated-list-mode.
> 
> Did you read what I suggested as the preferred way of specifying the
> grouping?  It's way simpler than what org-super-agenda expects.

I appreciate Ihor's mentioning my org-super-agenda library.  But while 
it is indeed a useful tool, please note that since I wrote it, I learned 
a lot about the topic, and I wrote a new library purposefully designed 
to facilitate grouping arbitrary data in arbitrary ways with a simple 
API: taxy.el, which is on GNU ELPA.  It supports both statically defined 
grouping, as well as user-customizeable grouping using a concise DSL 
defined with top-level forms.

So if you were to use one of these as inspiration (or as a library 
directly), I'd strongly recommend using `taxy', as that's what it's 
designed for.

The documentation is fairly thorough; please see the installed Info 
manual, or the readme at:

https://github.com/alphapapa/taxy.el#usage

Let me know if I can help facilitate a solution using it, or help anyone 
work with the API.

Thanks,
Adam





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-24 18:49           ` Eli Zaretskii
  2024-02-25  7:45             ` Adam Porter
@ 2024-02-25  7:53             ` Adam Porter
  2024-02-25  8:26               ` Eli Zaretskii
  1 sibling, 1 reply; 37+ messages in thread
From: Adam Porter @ 2024-02-25  7:53 UTC (permalink / raw)
  To: Eli Zaretskii, Ihor Radchenko; +Cc: 69305, juri

By the way, with regard to grouping buffers specifically, this is what 
my Bufler package does, again in an extensible, user-programmable way:

https://github.com/alphapapa/bufler.el

I wrote it after putting significant effort into using Ibuffer's 
grouping features, which didn't meet my needs.

Bufler supports grouping buffers by many different attributes, such as 
directory, filename, mode, project, parent-project, TRAMP status, etc. 
And, significantly, it does such grouping dynamically at multiple 
levels.  For example, within a "~/src/emacs" directory, subgroups for 
git projects within that directory can be created dynamically, providing 
a grouping like:

+ Dir: ~/src/emacs
|-+ Project: ~/src/emacs/bufler.el
| |- *magit-status: bufler.el*
|-+ Project: ~/src/emacs/activities.el
   |- README.org

If org-super-agenda was my exploration of the topic, Bufler served as 
the prototype of a better API, which I then factored out into Taxy. 
Eventually I'll rebase Bufler on top of Taxy.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-24 18:13                 ` Eli Zaretskii
@ 2024-02-25  8:00                   ` Adam Porter
  2024-02-25 17:25                   ` Juri Linkov
  1 sibling, 0 replies; 37+ messages in thread
From: Adam Porter @ 2024-02-25  8:00 UTC (permalink / raw)
  To: eliz; +Cc: 69305, juri

>> Data structure for `tabulated-list-groups' is a list of elements,
>> each element should of the form
>> 
>>   (GROUP-NAME (ID . CONTENTS) (ID . CONTENTS) ...)
>> 
>> where GROUP-NAME is the name of the group, ID is a Lisp object that
>> identifies the entry and CONTENTS is a vector with the same number of
>> elements as `tabulated-list-format'.  When buffers grouped by major mode:
>> 
>>   (("* Lisp Interaction" (#<buffer *scratch*> ["." " " "*" #("*scratch*" 0 9 ...) "225" "Lisp Interaction" ""]) ...))
> 
> This is the value that the user is supposed to supply for the
> defcustom?  That is, the user must specify all the buffers explicitly?
> What happens when there's one more buffer in some mode? does the user
> have then to modify the value of the defcustom?

FWIW, using, e.g. Bufler/Taxy to group buffers, the user would define a 
set of group key functions like so:

   (setf buffer-keys '((project) (special mode) mode))

That in effect says, "If a buffer is part of a project, group it by that 
project's directory; otherwise if a buffer is special, group it with 
other special buffers, and create subgroups by mode; otherwise group it 
by mode."

Then the groups are created dynamically at runtime when the buffer list 
buffer is refreshed.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-25  7:53             ` Adam Porter
@ 2024-02-25  8:26               ` Eli Zaretskii
  0 siblings, 0 replies; 37+ messages in thread
From: Eli Zaretskii @ 2024-02-25  8:26 UTC (permalink / raw)
  To: Adam Porter; +Cc: 69305, yantar92, juri

> Date: Sun, 25 Feb 2024 01:53:55 -0600
> Cc: juri@linkov.net, 69305@debbugs.gnu.org
> From: Adam Porter <adam@alphapapa.net>
> 
> By the way, with regard to grouping buffers specifically, this is what 
> my Bufler package does, again in an extensible, user-programmable way:
> 
> https://github.com/alphapapa/bufler.el
> 
> I wrote it after putting significant effort into using Ibuffer's 
> grouping features, which didn't meet my needs.
> 
> Bufler supports grouping buffers by many different attributes, such as 
> directory, filename, mode, project, parent-project, TRAMP status, etc. 
> And, significantly, it does such grouping dynamically at multiple 
> levels.  For example, within a "~/src/emacs" directory, subgroups for 
> git projects within that directory can be created dynamically, providing 
> a grouping like:
> 
> + Dir: ~/src/emacs
> |-+ Project: ~/src/emacs/bufler.el
> | |- *magit-status: bufler.el*
> |-+ Project: ~/src/emacs/activities.el
>    |- README.org

Thanks.  Once again, my proposal (and frankly, an expectation) was
that we provide a much simpler customization facility for grouping
entries in a tabulated-list-mode buffer.  I won't mind that the
current fancy customization is extended to use something like what
bufler.el does (although it needs to be generalize to support more
than buffer lists), but that will not fill the gap that I feel exists
in what we offer now.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-24 18:06     ` Ihor Radchenko
  2024-02-24 18:16       ` Eli Zaretskii
@ 2024-02-25 17:20       ` Juri Linkov
  1 sibling, 0 replies; 37+ messages in thread
From: Juri Linkov @ 2024-02-25 17:20 UTC (permalink / raw)
  To: Ihor Radchenko; +Cc: Adam Porter, 69305, Eli Zaretskii

> I am wondering if flexible grouping system from Adam's org-super-agenda
> package may provide some inspiration.
> Check out
> https://github.com/alphapapa/org-super-agenda/?tab=readme-ov-file#usage

The designed feature of enabling outline-minor-mode in tabulated-list-mode
is intended to be as simple as possible while keeping flexibility
for user's customization.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-24 18:13                 ` Eli Zaretskii
  2024-02-25  8:00                   ` Adam Porter
@ 2024-02-25 17:25                   ` Juri Linkov
  2024-02-25 19:17                     ` Eli Zaretskii
  1 sibling, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-02-25 17:25 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 69305

>> >> Sorry, I don't understand what is unclear here:
>> >>
>> >>   If the value is a list, each list element corresponds to one group, and
>> >>   should have the form @w{@code{(@var{group-name} @var{entries})}}, where
>> >>   @var{group-name} is a string inserted before all group entries, and
>> >>   @var{entries} have the same format as @code{tabulated-list-entries}
>> >>   (see above).
>> >>
>> >> Basically this says that the format is (group-name entries) where
>> >> entries are described in tabulated-list-entries as having the format
>> >> (id contents).  There is no need to duplicate the description of entries.
>> >
>> > Maybe I'm missing something here.  To put it more concretely, can you
>> > show a value of tabulated-list-groups that will cause the buffers in
>> > buffer list grouped by major mode using the above form?
>>
>> Data structure for `tabulated-list-groups' is a list of elements,
>> each element should of the form
>>
>>   (GROUP-NAME (ID . CONTENTS) (ID . CONTENTS) ...)
>>
>> where GROUP-NAME is the name of the group, ID is a Lisp object that
>> identifies the entry and CONTENTS is a vector with the same number of
>> elements as `tabulated-list-format'.  When buffers grouped by major mode:
>>
>>   (("* Lisp Interaction" (#<buffer *scratch*> ["." " " "*" #("*scratch*" 0 9 ...) "225" "Lisp Interaction" ""]) ...))
>
> This is the value that the user is supposed to supply for the
> defcustom?  That is, the user must specify all the buffers explicitly?
> What happens when there's one more buffer in some mode? does the user
> have then to modify the value of the defcustom?

This describes the internal data structure, not a defcustom.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-25  7:45             ` Adam Porter
@ 2024-02-25 17:36               ` Juri Linkov
  2024-02-26  3:31                 ` Adam Porter
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-02-25 17:36 UTC (permalink / raw)
  To: Adam Porter; +Cc: 69305, Eli Zaretskii, Ihor Radchenko

> So if you were to use one of these as inspiration (or as a library
> directly), I'd strongly recommend using `taxy', as that's what it's
> designed for.
> [...]
> Let me know if I can help facilitate a solution using it, or help anyone
> work with the API.

Thanks for proposing help, but for inspiration I'm using
my own package https://github.com/link0ff/emacs-ee
It's much more powerful than anything I have seen so far.
But on the other hand, it became so unmanageable
that I semi-abandoned it due to its overly complexity.

Is your package more light-weight than mine?  I doubt it ;-)

This is why I proposed to do the same with minimal changes relying on
existing core packages tabulated-list-mode and outline-minor-mode that
already handle 95% of required functionality.

What remains to do is just to fill the rest 5%.  In addition to the
first patch, there will be 2-3 equally small patches that will
complete functionality equivalent to the said packages.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-25 17:25                   ` Juri Linkov
@ 2024-02-25 19:17                     ` Eli Zaretskii
  2024-02-27  7:30                       ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2024-02-25 19:17 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 69305

> From: Juri Linkov <juri@linkov.net>
> Cc: 69305@debbugs.gnu.org
> Date: Sun, 25 Feb 2024 19:25:10 +0200
> 
> >> >> Sorry, I don't understand what is unclear here:
> >> >>
> >> >>   If the value is a list, each list element corresponds to one group, and
> >> >>   should have the form @w{@code{(@var{group-name} @var{entries})}}, where
> >> >>   @var{group-name} is a string inserted before all group entries, and
> >> >>   @var{entries} have the same format as @code{tabulated-list-entries}
> >> >>   (see above).
> >> >>
> >> >> Basically this says that the format is (group-name entries) where
> >> >> entries are described in tabulated-list-entries as having the format
> >> >> (id contents).  There is no need to duplicate the description of entries.
> >> >
> >> > Maybe I'm missing something here.  To put it more concretely, can you
> >> > show a value of tabulated-list-groups that will cause the buffers in
> >> > buffer list grouped by major mode using the above form?
> >>
> >> Data structure for `tabulated-list-groups' is a list of elements,
> >> each element should of the form
> >>
> >>   (GROUP-NAME (ID . CONTENTS) (ID . CONTENTS) ...)
> >>
> >> where GROUP-NAME is the name of the group, ID is a Lisp object that
> >> identifies the entry and CONTENTS is a vector with the same number of
> >> elements as `tabulated-list-format'.  When buffers grouped by major mode:
> >>
> >>   (("* Lisp Interaction" (#<buffer *scratch*> ["." " " "*" #("*scratch*" 0 9 ...) "225" "Lisp Interaction" ""]) ...))
> >
> > This is the value that the user is supposed to supply for the
> > defcustom?  That is, the user must specify all the buffers explicitly?
> > What happens when there's one more buffer in some mode? does the user
> > have then to modify the value of the defcustom?
> 
> This describes the internal data structure, not a defcustom.

Well, my question above, viz.:

>> > Maybe I'm missing something here.  To put it more concretely, can you
>> > show a value of tabulated-list-groups that will cause the buffers in
>> > buffer list grouped by major mode using the above form?

was about the value of this defcustom.  I hoped that by having such a
value as part of this discussion, we will be able to clear any
misunderstandings that could be getting in the way.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-25 17:36               ` Juri Linkov
@ 2024-02-26  3:31                 ` Adam Porter
  2024-03-06 17:37                   ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: Adam Porter @ 2024-02-26  3:31 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 69305, Eli Zaretskii, Ihor Radchenko

[-- Attachment #1: Type: text/plain, Size: 2010 bytes --]

Hi Juri,

On 2/25/24 11:36, Juri Linkov wrote:
>> So if you were to use one of these as inspiration (or as a library
>> directly), I'd strongly recommend using `taxy', as that's what it's
>> designed for.
>> [...]
>> Let me know if I can help facilitate a solution using it, or help anyone
>> work with the API.
> 
> Thanks for proposing help, but for inspiration I'm using
> my own package https://github.com/link0ff/emacs-ee
> It's much more powerful than anything I have seen so far.
> But on the other hand, it became so unmanageable
> that I semi-abandoned it due to its overly complexity.

Taxy might be able to help with that, because it's designed to simply 
abstract the matter of classifying data into hierarchies.  It's only 381 
lines of code, which includes macros that allow applications to define 
their own, user-extensible grouping languages with top-level forms.

UI frontends to render the data structures are separated from the 
concern of grouping.  A simple "pretty print" one is provided, but the 
main implementation so far is the associated library, taxy-magit-section.

> Is your package more light-weight than mine?  I doubt it ;-)

Well, judge for yourself.  :)  Attached is a file that provides a simple 
buffer-grouping command based on Taxy.  It's what I would call a "level 
one" implementation, without defining a DSL or user-customizeable 
grouping.  Adding those features would only take a few more lines of 
code, but I'm keeping this example as simple as possible.  This only 
takes 41 lines of code.  It produces a view as seen in the attached 
screenshot.  And it only took about 5 minutes to write by modifying a 
similar example that works on another kind of object.

Anyway, I'm not necessarily pushing a solution here, only trying to 
share what's available.  I did spend a lot of time on this project, and 
IMHO it solves the problem elegantly and powerfully, so I would like to 
see it applied more widely, but things included with Emacs itself are 
another matter.

[-- Attachment #2: buffery.el --]
[-- Type: text/x-emacs-lisp, Size: 2305 bytes --]

;;; buffery.el --- Buffer view with Taxy grouping    -*- lexical-binding: t; -*-

;; Keywords: 

;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <https://www.gnu.org/licenses/>.

;;; Commentary:

;; 

;;; Code:

(require 'cl-lib)
(require 'project)
(require 'taxy)
(require 'taxy-magit-section)

(defvar buffery-taxy
  (cl-labels ((directory (buffer)
                (buffer-local-value 'default-directory buffer))
              (mode (buffer)
                (prin1-to-string (buffer-local-value 'major-mode buffer)))
              (project (buffer)
                (with-current-buffer buffer
                  (when-let ((project (project-current)))
                    (project-root project))))
              (specialp (buffer)
                (when (not (buffer-file-name buffer))
                  "*special*"))
              (make-fn (&rest args)
                (apply #'make-taxy-magit-section
                       :make #'make-fn
                       :format-fn #'buffer-name
                       args)))
    (make-fn
     :name "Buffers"
     :take (apply-partially #'taxy-take-keyed
                            (list (list #'project)
                                  (list #'specialp)
                                  #'directory #'mode)))))

(defun buffery ()
  (interactive)
  (let* ((buffers (buffer-list))
         (buffer (get-buffer-create "*Buffery*"))
         (inhibit-read-only t))
    (with-current-buffer buffer
      (erase-buffer)
      (thread-last buffery-taxy
                   taxy-emptied
                   (taxy-fill buffers)
                   (taxy-sort* #'string< #'taxy-name)
                   taxy-magit-section-insert))
    (pop-to-buffer buffer)))

(provide 'buffery)
;;; buffery.el ends here

[-- Attachment #3: example.png --]
[-- Type: image/png, Size: 63425 bytes --]

^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-25 19:17                     ` Eli Zaretskii
@ 2024-02-27  7:30                       ` Juri Linkov
  2024-02-27  8:31                         ` Eli Zaretskii
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-02-27  7:30 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 69305

>> >> >> Sorry, I don't understand what is unclear here:
>> >> >>
>> >> >>   If the value is a list, each list element corresponds to one group, and
>> >> >>   should have the form @w{@code{(@var{group-name} @var{entries})}}, where
>> >> >>   @var{group-name} is a string inserted before all group entries, and
>> >> >>   @var{entries} have the same format as @code{tabulated-list-entries}
>> >> >>   (see above).
>> >> >>
>> >> >> Basically this says that the format is (group-name entries) where
>> >> >> entries are described in tabulated-list-entries as having the format
>> >> >> (id contents).  There is no need to duplicate the description of entries.
>> >> >
>> >> > Maybe I'm missing something here.  To put it more concretely, can you
>> >> > show a value of tabulated-list-groups that will cause the buffers in
>> >> > buffer list grouped by major mode using the above form?
>> >>
>> >> Data structure for `tabulated-list-groups' is a list of elements,
>> >> each element should of the form
>> >>
>> >>   (GROUP-NAME (ID . CONTENTS) (ID . CONTENTS) ...)
>> >>
>> >> where GROUP-NAME is the name of the group, ID is a Lisp object that
>> >> identifies the entry and CONTENTS is a vector with the same number of
>> >> elements as `tabulated-list-format'.  When buffers grouped by major mode:
>> >>
>> >>   (("* Lisp Interaction" (#<buffer *scratch*> ["." " " "*" #("*scratch*" 0 9 ...) "225" "Lisp Interaction" ""]) ...))
>> >
>> > This is the value that the user is supposed to supply for the
>> > defcustom?  That is, the user must specify all the buffers explicitly?
>> > What happens when there's one more buffer in some mode? does the user
>> > have then to modify the value of the defcustom?
>>
>> This describes the internal data structure, not a defcustom.
>
> Well, my question above, viz.:
>
>>> > Maybe I'm missing something here.  To put it more concretely, can you
>>> > show a value of tabulated-list-groups that will cause the buffers in
>>> > buffer list grouped by major mode using the above form?
>
> was about the value of this defcustom.  I hoped that by having such a
> value as part of this discussion, we will be able to clear any
> misunderstandings that could be getting in the way.

But tabulated-list-groups is not a defcustom.
There are no defcustoms here.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-27  7:30                       ` Juri Linkov
@ 2024-02-27  8:31                         ` Eli Zaretskii
  2024-02-27 17:40                           ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2024-02-27  8:31 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 69305

> From: Juri Linkov <juri@linkov.net>
> Cc: 69305@debbugs.gnu.org
> Date: Tue, 27 Feb 2024 09:30:10 +0200
> 
> >> >> >> Sorry, I don't understand what is unclear here:
> >> >> >>
> >> >> >>   If the value is a list, each list element corresponds to one group, and
> >> >> >>   should have the form @w{@code{(@var{group-name} @var{entries})}}, where
> >> >> >>   @var{group-name} is a string inserted before all group entries, and
> >> >> >>   @var{entries} have the same format as @code{tabulated-list-entries}
> >> >> >>   (see above).
> >> >> >>
> >> >> >> Basically this says that the format is (group-name entries) where
> >> >> >> entries are described in tabulated-list-entries as having the format
> >> >> >> (id contents).  There is no need to duplicate the description of entries.
> >> >> >
> >> >> > Maybe I'm missing something here.  To put it more concretely, can you
> >> >> > show a value of tabulated-list-groups that will cause the buffers in
> >> >> > buffer list grouped by major mode using the above form?
> >> >>
> >> >> Data structure for `tabulated-list-groups' is a list of elements,
> >> >> each element should of the form
> >> >>
> >> >>   (GROUP-NAME (ID . CONTENTS) (ID . CONTENTS) ...)
> >> >>
> >> >> where GROUP-NAME is the name of the group, ID is a Lisp object that
> >> >> identifies the entry and CONTENTS is a vector with the same number of
> >> >> elements as `tabulated-list-format'.  When buffers grouped by major mode:
> >> >>
> >> >>   (("* Lisp Interaction" (#<buffer *scratch*> ["." " " "*" #("*scratch*" 0 9 ...) "225" "Lisp Interaction" ""]) ...))
> >> >
> >> > This is the value that the user is supposed to supply for the
> >> > defcustom?  That is, the user must specify all the buffers explicitly?
> >> > What happens when there's one more buffer in some mode? does the user
> >> > have then to modify the value of the defcustom?
> >>
> >> This describes the internal data structure, not a defcustom.
> >
> > Well, my question above, viz.:
> >
> >>> > Maybe I'm missing something here.  To put it more concretely, can you
> >>> > show a value of tabulated-list-groups that will cause the buffers in
> >>> > buffer list grouped by major mode using the above form?
> >
> > was about the value of this defcustom.  I hoped that by having such a
> > value as part of this discussion, we will be able to clear any
> > misunderstandings that could be getting in the way.
> 
> But tabulated-list-groups is not a defcustom.
> There are no defcustoms here.

Buffer-menu-group-by _is_ a defcustom, and it is documented thusly:

  +  "If non-nil, buffers are grouped by function.
  +This function takes one argument: a list of entries in the same format
  +as in `tabulated-list-entries', and should return a list in the format
  +suitable for `tabulated-list-groups'.

So you are inviting users to write functions that return values of a
certain format, but the format's documentation IMO doesn't make it
clear how to specify a grouping, and for its important part alludes to
another variable (tabulated-list-entries), whose documentation is
suitable for different kind of uses, not for grouping of entries.
Since tabulated-list-groups is such an important part of the
documentation of Buffer-menu-group-by, the doc string of
tabulated-list-groups is in effect part of the doc string of
Buffer-menu-group-by, and should IMO be worded as appropriate for user
options.






^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-27  8:31                         ` Eli Zaretskii
@ 2024-02-27 17:40                           ` Juri Linkov
  2024-02-27 18:44                             ` Eli Zaretskii
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-02-27 17:40 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 69305

>> >> >> >> Sorry, I don't understand what is unclear here:
>> >> >> >>
>> >> >> >>   If the value is a list, each list element corresponds to one group, and
>> >> >> >>   should have the form @w{@code{(@var{group-name} @var{entries})}}, where
>> >> >> >>   @var{group-name} is a string inserted before all group entries, and
>> >> >> >>   @var{entries} have the same format as @code{tabulated-list-entries}
>> >> >> >>   (see above).
>> >> >> >>
>> >> >> >> Basically this says that the format is (group-name entries) where
>> >> >> >> entries are described in tabulated-list-entries as having the format
>> >> >> >> (id contents).  There is no need to duplicate the description of entries.
>> >> >> >
>> >> >> > Maybe I'm missing something here.  To put it more concretely, can you
>> >> >> > show a value of tabulated-list-groups that will cause the buffers in
>> >> >> > buffer list grouped by major mode using the above form?
>> >> >>
>> >> >> Data structure for `tabulated-list-groups' is a list of elements,
>> >> >> each element should of the form
>> >> >>
>> >> >>   (GROUP-NAME (ID . CONTENTS) (ID . CONTENTS) ...)
>> >> >>
>> >> >> where GROUP-NAME is the name of the group, ID is a Lisp object that
>> >> >> identifies the entry and CONTENTS is a vector with the same number of
>> >> >> elements as `tabulated-list-format'.  When buffers grouped by major mode:
>> >> >>
>> >> >>   (("* Lisp Interaction" (#<buffer *scratch*> ["." " " "*" #("*scratch*" 0 9 ...) "225" "Lisp Interaction" ""]) ...))
>> >> >
>> >> > This is the value that the user is supposed to supply for the
>> >> > defcustom?  That is, the user must specify all the buffers explicitly?
>> >> > What happens when there's one more buffer in some mode? does the user
>> >> > have then to modify the value of the defcustom?
>> >>
>> >> This describes the internal data structure, not a defcustom.
>> >
>> > Well, my question above, viz.:
>> >
>> >>> > Maybe I'm missing something here.  To put it more concretely, can you
>> >>> > show a value of tabulated-list-groups that will cause the buffers in
>> >>> > buffer list grouped by major mode using the above form?
>> >
>> > was about the value of this defcustom.  I hoped that by having such a
>> > value as part of this discussion, we will be able to clear any
>> > misunderstandings that could be getting in the way.
>>
>> But tabulated-list-groups is not a defcustom.
>> There are no defcustoms here.
>
> Buffer-menu-group-by _is_ a defcustom, and it is documented thusly:
>
>   +  "If non-nil, buffers are grouped by function.
>   +This function takes one argument: a list of entries in the same format
>   +as in `tabulated-list-entries', and should return a list in the format
>   +suitable for `tabulated-list-groups'.
>
> So you are inviting users to write functions that return values of a
> certain format, but the format's documentation IMO doesn't make it
> clear how to specify a grouping, and for its important part alludes to
> another variable (tabulated-list-entries), whose documentation is
> suitable for different kind of uses, not for grouping of entries.

The format 'tabulated-list-entries' is input.
The format 'tabulated-list-groups' is output.

> Since tabulated-list-groups is such an important part of the
> documentation of Buffer-menu-group-by, the doc string of
> tabulated-list-groups is in effect part of the doc string of
> Buffer-menu-group-by, and should IMO be worded as appropriate for user
> options.

The docstring of 'tabulated-list-groups' already
sufficiently documents the format:

  (defvar-local tabulated-list-groups nil
    "Groups displayed in the current Tabulated List buffer.
  This should be either a function, or a list.
  If a list, each element has the form (GROUP-NAME ENTRIES),
  where:

   - GROUP-NAME is a group name as a string, which is displayed
     at the top line of each group.

   - ENTRIES is a list described in `tabulated-list-entries'.

There is no need to duplicate the description of linked
'tabulated-list-entries'.  And here it's clear that the function
should add GROUP-NAME to groups from 'tabulated-list-entries'.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-27 17:40                           ` Juri Linkov
@ 2024-02-27 18:44                             ` Eli Zaretskii
  2024-02-28  7:36                               ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2024-02-27 18:44 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 69305

> From: Juri Linkov <juri@linkov.net>
> Cc: 69305@debbugs.gnu.org
> Date: Tue, 27 Feb 2024 19:40:10 +0200
> 
> >> But tabulated-list-groups is not a defcustom.
> >> There are no defcustoms here.
> >
> > Buffer-menu-group-by _is_ a defcustom, and it is documented thusly:
> >
> >   +  "If non-nil, buffers are grouped by function.
> >   +This function takes one argument: a list of entries in the same format
> >   +as in `tabulated-list-entries', and should return a list in the format
> >   +suitable for `tabulated-list-groups'.
> >
> > So you are inviting users to write functions that return values of a
> > certain format, but the format's documentation IMO doesn't make it
> > clear how to specify a grouping, and for its important part alludes to
> > another variable (tabulated-list-entries), whose documentation is
> > suitable for different kind of uses, not for grouping of entries.
> 
> The format 'tabulated-list-entries' is input.
> The format 'tabulated-list-groups' is output.

Yes, I'm well aware of that.

> > Since tabulated-list-groups is such an important part of the
> > documentation of Buffer-menu-group-by, the doc string of
> > tabulated-list-groups is in effect part of the doc string of
> > Buffer-menu-group-by, and should IMO be worded as appropriate for user
> > options.
> 
> The docstring of 'tabulated-list-groups' already
> sufficiently documents the format:

No, it doesn't document it sufficiently.  As I already said several
times.

>   (defvar-local tabulated-list-groups nil
>     "Groups displayed in the current Tabulated List buffer.
>   This should be either a function, or a list.
>   If a list, each element has the form (GROUP-NAME ENTRIES),
>   where:
> 
>    - GROUP-NAME is a group name as a string, which is displayed
>      at the top line of each group.
> 
>    - ENTRIES is a list described in `tabulated-list-entries'.
> 
> There is no need to duplicate the description of linked
> 'tabulated-list-entries'.

This is not about duplication.  This is about adding information that
currently isn't there.

> And here it's clear that the function should add GROUP-NAME to
> groups from 'tabulated-list-entries'.

Which doesn't clarify the issue at hand even a single bit.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-27 18:44                             ` Eli Zaretskii
@ 2024-02-28  7:36                               ` Juri Linkov
  2024-02-28 12:16                                 ` Eli Zaretskii
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-02-28  7:36 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 69305

>> >> But tabulated-list-groups is not a defcustom.
>> >> There are no defcustoms here.
>> >
>> > Buffer-menu-group-by _is_ a defcustom, and it is documented thusly:
>> >
>> >   +  "If non-nil, buffers are grouped by function.
>> >   +This function takes one argument: a list of entries in the same format
>> >   +as in `tabulated-list-entries', and should return a list in the format
>> >   +suitable for `tabulated-list-groups'.
>> >
>> > So you are inviting users to write functions that return values of a
>> > certain format, but the format's documentation IMO doesn't make it
>> > clear how to specify a grouping, and for its important part alludes to
>> > another variable (tabulated-list-entries), whose documentation is
>> > suitable for different kind of uses, not for grouping of entries.
>> 
>> The format 'tabulated-list-entries' is input.
>> The format 'tabulated-list-groups' is output.
>
> Yes, I'm well aware of that.
>
>> > Since tabulated-list-groups is such an important part of the
>> > documentation of Buffer-menu-group-by, the doc string of
>> > tabulated-list-groups is in effect part of the doc string of
>> > Buffer-menu-group-by, and should IMO be worded as appropriate for user
>> > options.
>> 
>> The docstring of 'tabulated-list-groups' already
>> sufficiently documents the format:
>
> No, it doesn't document it sufficiently.  As I already said several
> times.
>
>>   (defvar-local tabulated-list-groups nil
>>     "Groups displayed in the current Tabulated List buffer.
>>   This should be either a function, or a list.
>>   If a list, each element has the form (GROUP-NAME ENTRIES),
>>   where:
>> 
>>    - GROUP-NAME is a group name as a string, which is displayed
>>      at the top line of each group.
>> 
>>    - ENTRIES is a list described in `tabulated-list-entries'.
>> 
>> There is no need to duplicate the description of linked
>> 'tabulated-list-entries'.
>
> This is not about duplication.  This is about adding information that
> currently isn't there.
>
>> And here it's clear that the function should add GROUP-NAME to
>> groups from 'tabulated-list-entries'.
>
> Which doesn't clarify the issue at hand even a single bit.

Sorry, I don't understand what is missing here.
Please show an example of changes that you want.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-28  7:36                               ` Juri Linkov
@ 2024-02-28 12:16                                 ` Eli Zaretskii
  2024-02-29  7:45                                   ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2024-02-28 12:16 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 69305

> From: Juri Linkov <juri@linkov.net>
> Cc: 69305@debbugs.gnu.org
> Date: Wed, 28 Feb 2024 09:36:30 +0200
> 
> >> >> But tabulated-list-groups is not a defcustom.
> >> >> There are no defcustoms here.
> >> >
> >> > Buffer-menu-group-by _is_ a defcustom, and it is documented thusly:
> >> >
> >> >   +  "If non-nil, buffers are grouped by function.
> >> >   +This function takes one argument: a list of entries in the same format
> >> >   +as in `tabulated-list-entries', and should return a list in the format
> >> >   +suitable for `tabulated-list-groups'.
> >> >
> >> > So you are inviting users to write functions that return values of a
> >> > certain format, but the format's documentation IMO doesn't make it
> >> > clear how to specify a grouping, and for its important part alludes to
> >> > another variable (tabulated-list-entries), whose documentation is
> >> > suitable for different kind of uses, not for grouping of entries.
> >> 
> >> The format 'tabulated-list-entries' is input.
> >> The format 'tabulated-list-groups' is output.
> >
> > Yes, I'm well aware of that.
> >
> >> > Since tabulated-list-groups is such an important part of the
> >> > documentation of Buffer-menu-group-by, the doc string of
> >> > tabulated-list-groups is in effect part of the doc string of
> >> > Buffer-menu-group-by, and should IMO be worded as appropriate for user
> >> > options.
> >> 
> >> The docstring of 'tabulated-list-groups' already
> >> sufficiently documents the format:
> >
> > No, it doesn't document it sufficiently.  As I already said several
> > times.
> >
> >>   (defvar-local tabulated-list-groups nil
> >>     "Groups displayed in the current Tabulated List buffer.
> >>   This should be either a function, or a list.
> >>   If a list, each element has the form (GROUP-NAME ENTRIES),
> >>   where:
> >> 
> >>    - GROUP-NAME is a group name as a string, which is displayed
> >>      at the top line of each group.
> >> 
> >>    - ENTRIES is a list described in `tabulated-list-entries'.
> >> 
> >> There is no need to duplicate the description of linked
> >> 'tabulated-list-entries'.
> >
> > This is not about duplication.  This is about adding information that
> > currently isn't there.
> >
> >> And here it's clear that the function should add GROUP-NAME to
> >> groups from 'tabulated-list-entries'.
> >
> > Which doesn't clarify the issue at hand even a single bit.
> 
> Sorry, I don't understand what is missing here.
> Please show an example of changes that you want.

Sorry, I cannot show an example of something whose use I don't
understand.  Which is why I asked _you_ to show an example: how to set
up Buffer-menu-group-by to group buffers by major-mode.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-28 12:16                                 ` Eli Zaretskii
@ 2024-02-29  7:45                                   ` Juri Linkov
  2024-02-29 16:33                                     ` Eli Zaretskii
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-02-29  7:45 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 69305

>> >> >> But tabulated-list-groups is not a defcustom.
>> >> >> There are no defcustoms here.
>> >> >
>> >> > Buffer-menu-group-by _is_ a defcustom, and it is documented thusly:
>> >> >
>> >> >   +  "If non-nil, buffers are grouped by function.
>> >> >   +This function takes one argument: a list of entries in the same format
>> >> >   +as in `tabulated-list-entries', and should return a list in the format
>> >> >   +suitable for `tabulated-list-groups'.
>> >> >
>> >> > So you are inviting users to write functions that return values of a
>> >> > certain format, but the format's documentation IMO doesn't make it
>> >> > clear how to specify a grouping, and for its important part alludes to
>> >> > another variable (tabulated-list-entries), whose documentation is
>> >> > suitable for different kind of uses, not for grouping of entries.
>> >>
>> >> The format 'tabulated-list-entries' is input.
>> >> The format 'tabulated-list-groups' is output.
>> >
>> > Yes, I'm well aware of that.
>> >
>> >> > Since tabulated-list-groups is such an important part of the
>> >> > documentation of Buffer-menu-group-by, the doc string of
>> >> > tabulated-list-groups is in effect part of the doc string of
>> >> > Buffer-menu-group-by, and should IMO be worded as appropriate for user
>> >> > options.
>> >>
>> >> The docstring of 'tabulated-list-groups' already
>> >> sufficiently documents the format:
>> >
>> > No, it doesn't document it sufficiently.  As I already said several
>> > times.
>> >
>> >>   (defvar-local tabulated-list-groups nil
>> >>     "Groups displayed in the current Tabulated List buffer.
>> >>   This should be either a function, or a list.
>> >>   If a list, each element has the form (GROUP-NAME ENTRIES),
>> >>   where:
>> >>
>> >>    - GROUP-NAME is a group name as a string, which is displayed
>> >>      at the top line of each group.
>> >>
>> >>    - ENTRIES is a list described in `tabulated-list-entries'.
>> >>
>> >> There is no need to duplicate the description of linked
>> >> 'tabulated-list-entries'.
>> >
>> > This is not about duplication.  This is about adding information that
>> > currently isn't there.
>> >
>> >> And here it's clear that the function should add GROUP-NAME to
>> >> groups from 'tabulated-list-entries'.
>> >
>> > Which doesn't clarify the issue at hand even a single bit.
>>
>> Sorry, I don't understand what is missing here.
>> Please show an example of changes that you want.
>
> Sorry, I cannot show an example of something whose use I don't
> understand.  Which is why I asked _you_ to show an example: how to set
> up Buffer-menu-group-by to group buffers by major-mode.

Ah, you wanted to include a buffer example in "Tabulated List Mode".
Ok, here it is:

diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi
index 630e42e6878..e79b73eb081 100644
--- a/doc/lispref/modes.texi
+++ b/doc/lispref/modes.texi
@@ -1246,6 +1246,41 @@ Tabulated List Mode
 above form when called with no arguments.
 @end defvar
 
+@defvar tabulated-list-groups
+This buffer-local variable specifies the groups of entries displayed in
+the Tabulated List buffer.  Its value should be either a list, or a
+function.
+
+If the value is a list, each list element corresponds to one group, and
+should have the form @w{@code{(@var{group-name} @var{entries})}}, where
+@var{group-name} is a string inserted before all group entries, and
+@var{entries} have the same format as @code{tabulated-list-entries}
+(see above).
+
+Otherwise, the value should be a function which returns a list of the
+above form when called with no arguments.
+@end defvar
+
+You can use @code{seq-group-by} to create @code{tabulated-list-groups}
+from @code{tabulated-list-entries}.  For example:
+
+@smallexample
+@group
+  (setq tabulated-list-groups
+        (seq-group-by 'Buffer-menu-group-by-mode
+                      tabulated-list-entries))
+@end group
+@end smallexample
+
+where you can define @code{Buffer-menu-group-by-mode} like this:
+
+@smallexample
+@group
+(defun Buffer-menu-group-by-mode (entry)
+  (concat "* " (aref (cadr entry) 5)))
+@end group
+@end smallexample
+
 @defvar tabulated-list-revert-hook
 This normal hook is run prior to reverting a Tabulated List buffer.  A
 derived mode can add a function to this hook to recompute





^ permalink raw reply related	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-29  7:45                                   ` Juri Linkov
@ 2024-02-29 16:33                                     ` Eli Zaretskii
  2024-02-29 17:50                                       ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2024-02-29 16:33 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 69305

> From: Juri Linkov <juri@linkov.net>
> Cc: 69305@debbugs.gnu.org
> Date: Thu, 29 Feb 2024 09:45:00 +0200
> 
> > Sorry, I cannot show an example of something whose use I don't
> > understand.  Which is why I asked _you_ to show an example: how to set
> > up Buffer-menu-group-by to group buffers by major-mode.
> 
> Ah, you wanted to include a buffer example in "Tabulated List Mode".
> Ok, here it is:

Thanks!





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-29 16:33                                     ` Eli Zaretskii
@ 2024-02-29 17:50                                       ` Juri Linkov
  2024-03-03  6:53                                         ` Jean Louis
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-02-29 17:50 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 69305

close 69305 30.0.50
thanks

>> Ok, here it is:
>
> Thanks!

So now pushed to master.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-29 17:50                                       ` Juri Linkov
@ 2024-03-03  6:53                                         ` Jean Louis
  2024-03-03  7:52                                           ` Juri Linkov
  0 siblings, 1 reply; 37+ messages in thread
From: Jean Louis @ 2024-03-03  6:53 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 69305, Eli Zaretskii

* Juri Linkov <juri@linkov.net> [2024-02-29 20:54]:
> close 69305 30.0.50
> thanks
> 
> >> Ok, here it is:
> >
> > Thanks!
> 
> So now pushed to master.

I hope that the new change will not affect the standard functionality of tabulated-list-mode which I use heavily.

Major grouping of tabulated-list-mode is by columns, not by rows, so I really wonder what will happen in the new outline-minor-mode for tabulated-list-mode when it is active and then user sort it by column

In my opinion tabulated shall remain tabulated, but I wish to see what is benefit of outline-minor-mode as I cannot understand it yet.


Jean

Take action in Free Software Foundation campaigns:
https://www.fsf.org/campaigns

In support of Richard M. Stallman
https://stallmansupport.org/





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-03-03  6:53                                         ` Jean Louis
@ 2024-03-03  7:52                                           ` Juri Linkov
  0 siblings, 0 replies; 37+ messages in thread
From: Juri Linkov @ 2024-03-03  7:52 UTC (permalink / raw)
  To: Jean Louis; +Cc: 69305, Eli Zaretskii

> I hope that the new change will not affect the standard functionality
> of tabulated-list-mode which I use heavily.

Indeed, it should not affect the default behavior.

> Major grouping of tabulated-list-mode is by columns, not by rows, so
> I really wonder what will happen in the new outline-minor-mode for
> tabulated-list-mode when it is active and then user sort it by column

When sorted by column then rows in all groups will be sorted
by the same column.

> In my opinion tabulated shall remain tabulated, but I wish to see what
> is benefit of outline-minor-mode as I cannot understand it yet.

Rest assured, tabulated will remain tabulated, just outline heading lines
are added between groups.





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-02-26  3:31                 ` Adam Porter
@ 2024-03-06 17:37                   ` Juri Linkov
  2024-03-08 23:13                     ` Adam Porter
  0 siblings, 1 reply; 37+ messages in thread
From: Juri Linkov @ 2024-03-06 17:37 UTC (permalink / raw)
  To: Adam Porter; +Cc: 69305, Eli Zaretskii, Ihor Radchenko

> (defvar buffery-taxy
>   (cl-labels ((directory (buffer)
>                 (buffer-local-value 'default-directory buffer))
>               (mode (buffer)
>                 (prin1-to-string (buffer-local-value 'major-mode buffer)))
>               (project (buffer)
>                 (with-current-buffer buffer
>                   (when-let ((project (project-current)))
>                     (project-root project))))
>               (specialp (buffer)
>                 (when (not (buffer-file-name buffer))
>                   "*special*"))
>               (make-fn (&rest args)
>                 (apply #'make-taxy-magit-section
>                        :make #'make-fn
>                        :format-fn #'buffer-name
>                        args)))
>     (make-fn
>      :name "Buffers"
>      :take (apply-partially #'taxy-take-keyed
>                             (list (list #'project)
>                                   (list #'specialp)
>                                   #'directory #'mode)))))

Thanks for the good example.  This is how the same
is achieved with 'Buffer-menu-group-by':

#+begin_src emacs-lisp
(setq Buffer-menu-group-by
      (lambda (b)
        (concat "* "
         (or
          (with-current-buffer (car b)
            (when-let ((project (project-current)))
              (project-root project)))
          (when (not (buffer-file-name (car b)))
            "*special*")
          (buffer-local-value 'default-directory (car b))
          (aref (cadr b) 5)))))
#+end_src





^ permalink raw reply	[flat|nested] 37+ messages in thread

* bug#69305: outline-minor-mode for tabulated-list-mode
  2024-03-06 17:37                   ` Juri Linkov
@ 2024-03-08 23:13                     ` Adam Porter
  0 siblings, 0 replies; 37+ messages in thread
From: Adam Porter @ 2024-03-08 23:13 UTC (permalink / raw)
  To: Juri Linkov; +Cc: 69305, Eli Zaretskii, Ihor Radchenko

Hi Juri,

On 3/6/24 11:37, Juri Linkov wrote:
>> (defvar buffery-taxy
>>    (cl-labels ((directory (buffer)
>>                  (buffer-local-value 'default-directory buffer))
>>                (mode (buffer)
>>                  (prin1-to-string (buffer-local-value 'major-mode buffer)))
>>                (project (buffer)
>>                  (with-current-buffer buffer
>>                    (when-let ((project (project-current)))
>>                      (project-root project))))
>>                (specialp (buffer)
>>                  (when (not (buffer-file-name buffer))
>>                    "*special*"))
>>                (make-fn (&rest args)
>>                  (apply #'make-taxy-magit-section
>>                         :make #'make-fn
>>                         :format-fn #'buffer-name
>>                         args)))
>>      (make-fn
>>       :name "Buffers"
>>       :take (apply-partially #'taxy-take-keyed
>>                              (list (list #'project)
>>                                    (list #'specialp)
>>                                    #'directory #'mode)))))
> 
> Thanks for the good example.  This is how the same
> is achieved with 'Buffer-menu-group-by':
> 
> #+begin_src emacs-lisp
> (setq Buffer-menu-group-by
>        (lambda (b)
>          (concat "* "
>           (or
>            (with-current-buffer (car b)
>              (when-let ((project (project-current)))
>                (project-root project)))
>            (when (not (buffer-file-name (car b)))
>              "*special*")
>            (buffer-local-value 'default-directory (car b))
>            (aref (cadr b) 5)))))
> #+end_src

Please note that that does not produce the same result.  Your example 
produces one level of grouping.  Taxy, when used with `taxy-take-keyed', 
produces dynamically nested groups according to the list of key 
functions and their nesting.

The Taxy documentation describes these features extensively, with examples:

https://github.com/alphapapa/taxy.el#dynamic-taxys





^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2024-03-08 23:13 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-02-21 17:34 bug#69305: outline-minor-mode for tabulated-list-mode Juri Linkov
2024-02-21 19:12 ` Eli Zaretskii
2024-02-22  7:44   ` Juri Linkov
2024-02-22  8:20     ` Eli Zaretskii
2024-02-22 17:30       ` Juri Linkov
2024-02-22 19:10         ` Eli Zaretskii
2024-02-23  7:09           ` Juri Linkov
2024-02-23  8:13             ` Eli Zaretskii
2024-02-24 17:43               ` Juri Linkov
2024-02-24 18:09                 ` Eli Zaretskii
2024-02-24 18:13                 ` Eli Zaretskii
2024-02-25  8:00                   ` Adam Porter
2024-02-25 17:25                   ` Juri Linkov
2024-02-25 19:17                     ` Eli Zaretskii
2024-02-27  7:30                       ` Juri Linkov
2024-02-27  8:31                         ` Eli Zaretskii
2024-02-27 17:40                           ` Juri Linkov
2024-02-27 18:44                             ` Eli Zaretskii
2024-02-28  7:36                               ` Juri Linkov
2024-02-28 12:16                                 ` Eli Zaretskii
2024-02-29  7:45                                   ` Juri Linkov
2024-02-29 16:33                                     ` Eli Zaretskii
2024-02-29 17:50                                       ` Juri Linkov
2024-03-03  6:53                                         ` Jean Louis
2024-03-03  7:52                                           ` Juri Linkov
2024-02-24 18:06     ` Ihor Radchenko
2024-02-24 18:16       ` Eli Zaretskii
2024-02-24 18:36         ` Ihor Radchenko
2024-02-24 18:49           ` Eli Zaretskii
2024-02-25  7:45             ` Adam Porter
2024-02-25 17:36               ` Juri Linkov
2024-02-26  3:31                 ` Adam Porter
2024-03-06 17:37                   ` Juri Linkov
2024-03-08 23:13                     ` Adam Porter
2024-02-25  7:53             ` Adam Porter
2024-02-25  8:26               ` Eli Zaretskii
2024-02-25 17:20       ` Juri Linkov

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).