emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/git-commit 68be0584f4 2/2: Implement numeric and version s


From: ELPA Syncer
Subject: [nongnu] elpa/git-commit 68be0584f4 2/2: Implement numeric and version sort for repository lists
Date: Mon, 21 Feb 2022 17:58:02 -0500 (EST)

branch: elpa/git-commit
commit 68be0584f464b6aa2a7d026339835ee70f472e92
Author: Jonas Bernoulli <jonas@bernoul.li>
Commit: Jonas Bernoulli <jonas@bernoul.li>

    Implement numeric and version sort for repository lists
---
 docs/magit.org          | 50 +++++++++++++++++++++++++-----------
 docs/magit.texi         | 50 +++++++++++++++++++++++++-----------
 lisp/magit-repos.el     | 68 ++++++++++++++++++++++++++++++++++++++++---------
 lisp/magit-submodule.el | 38 +++++++++++++++++++++------
 4 files changed, 156 insertions(+), 50 deletions(-)

diff --git a/docs/magit.org b/docs/magit.org
index bd0d5ccd18..a88dde8c56 100644
--- a/docs/magit.org
+++ b/docs/magit.org
@@ -2481,18 +2481,25 @@ buffers.
 
   Each element has the form ~(HEADER WIDTH FORMAT PROPS)~.
 
-  HEADER is the string displayed in the header.  WIDTH is the width of
-  the column.  FORMAT is a function that is called with one argument,
-  the repository identification (usually its basename), and with
-  ~default-directory~ bound to the toplevel of its working tree.  It
-  has to return a string to be inserted or nil.  PROPS is an alist
-  that supports the keys ~:right-align~ and ~:pad-right~.
+  HEADER is the string displayed in the header.  WIDTH is the width
+  of the column.  FORMAT is a function that is called with one
+  argument, the repository identification (usually its basename),
+  and with ~default-directory~ bound to the toplevel of its working
+  tree.  It has to return a string to be inserted or nil.  PROPS is
+  an alist that supports the keys ~:right-align~, ~:pad-right~ and
+  ~:sort~.
+
+  The ~:sort~ function has a weird interface described in the
+  docstring of ~tabulated-list--get-sort~.  Alternatively ~<~ and
+  ~magit-repolist-version<~ can be used as those functions are
+  automatically replaced with functions that satisfy the interface.
+  Set ~:sort~ to ~nil~ to inhibit sorting; if unspecifed, then the
+  column is sortable using the default sorter.
 
   You may wish to display a range of numeric columns using just one
   character per column and without any padding between columns, in
-  which case you should use an appropriate HEADER, set WIDTH to 1,
-  and set ~:pad-right~ to 0.  ~+~ is substituted for numbers higher
-  than 9.
+  which case you should use an appropriat HEADER, set WIDTH to 1,
+  and set ~:pad-right~ to 9. ~+~ is substituted for numbers higher than 9.
 
 #+texinfo: @noindent
 The following functions can be added to the above option:
@@ -6864,12 +6871,25 @@ the super-repository by adding ~magit-insert-modules~ 
to the hook
 
   Each element has the form ~(HEADER WIDTH FORMAT PROPS)~.
 
-  HEADER is the string displayed in the header.  WIDTH is the width of
-  the column.  FORMAT is a function that is called with one argument,
-  the repository identification (usually its basename), and with
-  ~default-directory~ bound to the toplevel of its working tree.  It
-  has to return a string to be inserted or nil.  PROPS is an alist
-  that supports the keys ~:right-align~ and ~:pad-right~.
+  HEADER is the string displayed in the header.  WIDTH is the width
+  of the column.  FORMAT is a function that is called with one
+  argument, the repository identification (usually its basename),
+  and with ~default-directory~ bound to the toplevel of its working
+  tree.  It has to return a string to be inserted or nil.  PROPS is
+  an alist that supports the keys ~:right-align~, ~:pad-right~ and
+  ~:sort~.
+
+  The ~:sort~ function has a weird interface described in the
+  docstring of ~tabulated-list--get-sort~.  Alternatively ~<~ and
+  ~magit-repolist-version<~ can be used as those functions are
+  automatically replaced with functions that satisfy the interface.
+  Set ~:sort~ to ~nil~ to inhibit sorting; if unspecifed, then the
+  column is sortable using the default sorter.
+
+  You may wish to display a range of numeric columns using just one
+  character per column and without any padding between columns, in
+  which case you should use an appropriat HEADER, set WIDTH to 1,
+  and set ~:pad-right~ to 9. ~+~ is substituted for numbers higher than 9.
 
 *** Submodule Transient
 
diff --git a/docs/magit.texi b/docs/magit.texi
index 0a8028fbb5..b171dc9d5b 100644
--- a/docs/magit.texi
+++ b/docs/magit.texi
@@ -3094,18 +3094,25 @@ This option controls what columns are displayed by the 
command
 
 Each element has the form @code{(HEADER WIDTH FORMAT PROPS)}.
 
-HEADER is the string displayed in the header.  WIDTH is the width of
-the column.  FORMAT is a function that is called with one argument,
-the repository identification (usually its basename), and with
-@code{default-directory} bound to the toplevel of its working tree.  It
-has to return a string to be inserted or nil.  PROPS is an alist
-that supports the keys @code{:right-align} and @code{:pad-right}.
+HEADER is the string displayed in the header.  WIDTH is the width
+of the column.  FORMAT is a function that is called with one
+argument, the repository identification (usually its basename),
+and with @code{default-directory} bound to the toplevel of its working
+tree.  It has to return a string to be inserted or nil.  PROPS is
+an alist that supports the keys @code{:right-align}, @code{:pad-right} and
+@code{:sort}.
+
+The @code{:sort} function has a weird interface described in the
+docstring of @code{tabulated-list--get-sort}.  Alternatively @code{<} and
+@code{magit-repolist-version<} can be used as those functions are
+automatically replaced with functions that satisfy the interface.
+Set @code{:sort} to @code{nil} to inhibit sorting; if unspecifed, then the
+column is sortable using the default sorter.
 
 You may wish to display a range of numeric columns using just one
 character per column and without any padding between columns, in
-which case you should use an appropriate HEADER, set WIDTH to 1,
-and set @code{:pad-right} to 0.  @code{+} is substituted for numbers higher
-than 9.
+which case you should use an appropriat HEADER, set WIDTH to 1,
+and set @code{:pad-right} to 9. @code{+} is substituted for numbers higher 
than 9.
 @end defopt
 
 @noindent
@@ -8582,12 +8589,25 @@ This option controls what columns are displayed by the 
command
 
 Each element has the form @code{(HEADER WIDTH FORMAT PROPS)}.
 
-HEADER is the string displayed in the header.  WIDTH is the width of
-the column.  FORMAT is a function that is called with one argument,
-the repository identification (usually its basename), and with
-@code{default-directory} bound to the toplevel of its working tree.  It
-has to return a string to be inserted or nil.  PROPS is an alist
-that supports the keys @code{:right-align} and @code{:pad-right}.
+HEADER is the string displayed in the header.  WIDTH is the width
+of the column.  FORMAT is a function that is called with one
+argument, the repository identification (usually its basename),
+and with @code{default-directory} bound to the toplevel of its working
+tree.  It has to return a string to be inserted or nil.  PROPS is
+an alist that supports the keys @code{:right-align}, @code{:pad-right} and
+@code{:sort}.
+
+The @code{:sort} function has a weird interface described in the
+docstring of @code{tabulated-list--get-sort}.  Alternatively @code{<} and
+@code{magit-repolist-version<} can be used as those functions are
+automatically replaced with functions that satisfy the interface.
+Set @code{:sort} to @code{nil} to inhibit sorting; if unspecifed, then the
+column is sortable using the default sorter.
+
+You may wish to display a range of numeric columns using just one
+character per column and without any padding between columns, in
+which case you should use an appropriat HEADER, set WIDTH to 1,
+and set @code{:pad-right} to 9. @code{+} is substituted for numbers higher 
than 9.
 @end defopt
 
 @node Submodule Transient
diff --git a/lisp/magit-repos.el b/lisp/magit-repos.el
index 8fd9e1569f..d99373a33a 100644
--- a/lisp/magit-repos.el
+++ b/lisp/magit-repos.el
@@ -69,13 +69,16 @@ This option controls which repositories are being listed by
 
 (defcustom magit-repolist-columns
   '(("Name"    25 magit-repolist-column-ident nil)
-    ("Version" 25 magit-repolist-column-version nil)
+    ("Version" 25 magit-repolist-column-version
+     ((:sort magit-repolist-version<)))
     ("B<U"      3 magit-repolist-column-unpulled-from-upstream
-     ((:right-align t)
-      (:help-echo "Upstream changes not in branch")))
+     (;; (:help-echo "Upstream changes not in branch")
+      (:right-align t)
+      (:sort <)))
     ("B>U"      3 magit-repolist-column-unpushed-to-upstream
-     ((:right-align t)
-      (:help-echo "Local changes not in upstream")))
+     (;; (:help-echo "Local changes not in upstream")
+      (:right-align t)
+      (:sort <)))
     ("Path"    99 magit-repolist-column-path nil))
   "List of columns displayed by `magit-list-repositories'.
 
@@ -86,9 +89,15 @@ of the column.  FORMAT is a function that is called with one
 argument, the repository identification (usually its basename),
 and with `default-directory' bound to the toplevel of its working
 tree.  It has to return a string to be inserted or nil.  PROPS is
-an alist that supports the keys `:right-align' and `:pad-right'.
-Some entries also use `:help-echo', but `tabulated-list' does not
-actually support that yet.
+an alist that supports the keys `:right-align', `:pad-right' and
+`:sort'.
+
+The `:sort' function has a weird interface described in the
+docstring of `tabulated-list--get-sort'.  Alternatively `<' and
+`magit-repolist-version<' can be used as those functions are
+automatically replaced with functions that satisfy the interface.
+Set `:sort' to nil to inhibit sorting; if unspecifed, then the
+column is sortable using the default sorter.
 
 You may wish to display a range of numeric columns using just one
 character per column and without any padding between columns, in
@@ -105,6 +114,7 @@ than 9."
                                  (list (choice :tag "Property"
                                                (const :right-align)
                                                (const :pad-right)
+                                               (const :sort)
                                                (symbol))
                                        (sexp   :tag "Value"))))))
 
@@ -287,10 +297,23 @@ If it contains \"%s\" then the directory is substituted 
for that."
                       (caar magit-repolist-columns))
                   flip))))
   (setq tabulated-list-format
-        (vconcat (mapcar (pcase-lambda (`(,title ,width ,_fn ,props))
-                           (nconc (list title width t)
-                                  (-flatten props)))
-                         magit-repolist-columns))))
+        (vconcat (-map-indexed
+                  (lambda (idx column)
+                    (pcase-let* ((`(,title ,width ,_fn ,props) column)
+                                 (sort-set (assoc :sort props))
+                                 (sort-fn (cadr sort-set)))
+                      (nconc (list title width
+                                   (cond ((eq sort-fn '<)
+                                          (magit-repolist-make-sorter
+                                           sort-fn #'string-to-number idx))
+                                         ((eq sort-fn 'magit-repolist-version<)
+                                          (magit-repolist-make-sorter
+                                           sort-fn #'identity idx))
+                                         (sort-fn sort-fn)
+                                         (sort-set nil)
+                                         (t t)))
+                             (-flatten props))))
+                  magit-repolist-columns))))
 
 (defun magit-repolist-refresh ()
   (setq tabulated-list-entries
@@ -316,6 +339,18 @@ If it contains \"%s\" then the directory is substituted 
for that."
 
 ;;;; Columns
 
+(defun magit-repolist-make-sorter (sort-predicate convert-cell column-idx)
+  "Return a function suitable as a sorter for tabulated lists.
+See `tabulated-list--get-sorter'.  Given a more reasonable API
+this would not be necessary and one could just use SORT-PREDICATE
+directly.  CONVERT-CELL can be used to turn the cell value, which
+is always a string back into e.g. a number.  COLUMN-IDX has to be
+the index of the column that uses the returned sorter function."
+  (lambda (a b)
+    (funcall sort-predicate
+             (funcall convert-cell (aref (cadr a) column-idx))
+             (funcall convert-cell (aref (cadr b) column-idx)))))
+
 (defun magit-repolist-column-ident (spec)
   "Insert the identification of the repository.
 Usually this is just its basename."
@@ -357,6 +392,15 @@ Usually this is just its basename."
           (magit--put-face 0 (match-end 0) 'shadow v))
         v))))
 
+(defun magit-repolist-version< (a b)
+  (save-match-data
+    (let ((re "[0-9]+\\(\\.[0-9]*\\)*"))
+      (setq a (and (string-match re a) (match-string 0 a)))
+      (setq b (and (string-match re b) (match-string 0 b)))
+      (cond ((and a b) (version< a b))
+            (b nil)
+            (t t)))))
+
 (defun magit-repolist-column-branch (_)
   "Insert the current branch."
   (let ((branch (magit-get-current-branch)))
diff --git a/lisp/magit-submodule.el b/lisp/magit-submodule.el
index c43c6beb7d..ffd2c82216 100644
--- a/lisp/magit-submodule.el
+++ b/lisp/magit-submodule.el
@@ -66,14 +66,27 @@ is inserted.  If it is nil, then all sections listed in
 
 (defcustom magit-submodule-list-columns
   '(("Path"     25 magit-modulelist-column-path   nil)
-    ("Version"  25 magit-repolist-column-version  nil)
+    ("Version"  25 magit-repolist-column-version
+     ((:sort magit-repolist-version<)))
     ("Branch"   20 magit-repolist-column-branch   nil)
-    ("B<U" 3 magit-repolist-column-unpulled-from-upstream   ((:right-align t)))
-    ("B>U" 3 magit-repolist-column-unpushed-to-upstream     ((:right-align t)))
-    ("B<P" 3 magit-repolist-column-unpulled-from-pushremote ((:right-align t)))
-    ("B>P" 3 magit-repolist-column-unpushed-to-pushremote   ((:right-align t)))
-    ("B"   3 magit-repolist-column-branches                 ((:right-align t)))
-    ("S"   3 magit-repolist-column-stashes                  ((:right-align 
t))))
+    ("B<U" 3 magit-repolist-column-unpulled-from-upstream
+     ((:right-align t)
+      (:sort <)))
+    ("B>U" 3 magit-repolist-column-unpushed-to-upstream
+     ((:right-align t)
+      (:sort <)))
+    ("B<P" 3 magit-repolist-column-unpulled-from-pushremote
+     ((:right-align t)
+      (:sort <)))
+    ("B>P" 3 magit-repolist-column-unpushed-to-pushremote
+     ((:right-align t)
+      (:sort <)))
+    ("B"   3 magit-repolist-column-branches
+     ((:right-align t)
+      (:sort <)))
+    ("S"   3 magit-repolist-column-stashes
+     ((:right-align t)
+      (:sort <))))
   "List of columns displayed by `magit-list-submodules'.
 
 Each element has the form (HEADER WIDTH FORMAT PROPS).
@@ -83,7 +96,15 @@ of the column.  FORMAT is a function that is called with one
 argument, the repository identification (usually its basename),
 and with `default-directory' bound to the toplevel of its working
 tree.  It has to return a string to be inserted or nil.  PROPS is
-an alist that supports the keys `:right-align' and `:pad-right'.
+an alist that supports the keys `:right-align', `:pad-right' and
+`:sort'.
+
+The `:sort' function has a weird interface described in the
+docstring of `tabulated-list--get-sort'.  Alternatively `<' and
+`magit-repolist-version<' can be used as those functions are
+automatically replaced with functions that satisfy the interface.
+Set `:sort' to nil to inhibit sorting; if unspecifed, then the
+column is sortable using the default sorter.
 
 You may wish to display a range of numeric columns using just one
 character per column and without any padding between columns, in
@@ -100,6 +121,7 @@ than 9."
                                  (list (choice :tag "Property"
                                                (const :right-align)
                                                (const :pad-right)
+                                               (const :sort)
                                                (symbol))
                                        (sexp   :tag "Value"))))))
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]