[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"))))))