branch: elpa/magit
commit 83d89ee5bb1c488544bae60d52f7ee1987b6449e
Author: Jonas Bernoulli <[email protected]>
Commit: Jonas Bernoulli <[email protected]>
Speed up and simplify listing files in status buffer
---
CHANGELOG | 5 +-
docs/magit.org | 59 +++++++++++-----
docs/magit.texi | 61 +++++++++++-----
lisp/magit-status.el | 192 ++++++++++++++++++++-------------------------------
test/magit-tests.el | 1 +
5 files changed, 160 insertions(+), 158 deletions(-)
diff --git a/CHANGELOG b/CHANGELOG
index 979de2742db..340c0336110 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -7,8 +7,6 @@
offered some fallback methods. The presentation of those has been
improved. #5253 a08b4dd513
-- [IN PROGRESS] Improve listing of untracked files.
-
- Added new hook options ~magit-revision-wash-message-hook~ and
~magit-log-wash-summary-hook~, and populate them with new and existing
highlighting functions, making easier to remove default highlighting
@@ -23,6 +21,9 @@
- Improved commit menu, documentation and implementation details. #5261
+- Speed up listing untracked files in the status buffer, simplify how
+ the list is configured, and give up on optionally using a tree.
+
Bug fixes:
- When applying a stash, it was not always discovered when the trivial
diff --git a/docs/magit.org b/docs/magit.org
index 99487e150b1..f9752ea5238 100644
--- a/docs/magit.org
+++ b/docs/magit.org
@@ -2258,42 +2258,65 @@ hooks and how to customize them.
*** Status File List Sections
-Its possible to limit the diffs in the current buffer to a certain
-directory using ~D = f <DIRECTORY> RET g~. If you do that, then that
-that also affects these functions. The diff filter can be used to
-limit to multiple files. In that case these functions only respect
-the first of the files and only if it is a directory.
+These functions honor the buffer's file filter, which can be set using
+~D - -~.
- Function: magit-insert-untracked-files ::
- Maybe insert a list or tree of untracked files.
+ This function may insert a list of untracked files. Whether it
+ actually does so, depends on the option described next.
- The option ~magit-status-show-untracked-files~ (which see), in
- cooperation with the Git variable ~status.showUntrackedFiles~,
- control whether and how that is done.
+- User Option: magit-status-show-untracked-files ::
- If the first element of ~magit-buffer-diff-files~ is a directory, then
- limit the list to files below that. The value of that variable can
- be set using ~D -- DIRECTORY RET g~.
+ This option controls whether the above function inserts a list of
+ untracked files in the status buffer.
-While the above function is a member of ~magit-status-section-hook~,
-the following functions by default are not.
+ To disable listing untracked files in a specific repository only,
+ add the following to ~.dir-locals.el~:
+
+ #+begin_src emacs-lisp
+ ((magit-status-mode
+ (magit-status-show-untracked-files . \"no\")))
+ #+end_src
+
+ Alternatively (and mostly for historic reasons), it is possible to
+ use ~git config~ to disable listing files for a specific repository,
+ using:
+
+ #+begin_src shell-script
+ git config set --local status.showUntrackedFiles no
+ #+end_src
+
+ This does *not* override the (if any) local value of this Lisp variable.
+ It also is not possible to use the Git variable to enable listing files
+ (in case the global value of this variable is nil).
+
+- User Option: magit-status-file-list-limit ::
+
+ This option controls many files are listed at most in each section
+ that lists files in the status buffer. For performance reasons, it
+ is recommended that you do not increase this limit.
+
+While the above function is a member of ~magit-status-section-hook~ by
+default, the following functions have to be explicitly added by the
+user. Because that negatively affects performance, it is recommended
+that you don't do that.
- Function: magit-insert-tracked-files ::
- Insert a tree of tracked files.
+ Insert a list of tracked files.
- Function: magit-insert-ignored-files ::
- Insert a tree of ignored files.
+ Insert a list of ignored files.
- Function: magit-insert-skip-worktree-files ::
- Insert a tree of skip-worktree files.
+ Insert a list of skip-worktree files.
- Function: magit-insert-assumed-unchanged-files ::
- Insert a tree of files that are assumed to be unchanged.
+ Insert a list of files that are assumed to be unchanged.
*** Status Log Sections
diff --git a/docs/magit.texi b/docs/magit.texi
index 75249101b52..c51b44e2da6 100644
--- a/docs/magit.texi
+++ b/docs/magit.texi
@@ -2641,41 +2641,64 @@ push-remote yet.
@anchor{Status File List Sections}
@subsection Status File List Sections
-Its possible to limit the diffs in the current buffer to a certain
-directory using @code{D = f <DIRECTORY> RET g}. If you do that, then that
-that also affects these functions. The diff filter can be used to
-limit to multiple files. In that case these functions only respect
-the first of the files and only if it is a directory.
+These functions honor the buffer's file filter, which can be set using
+@code{D - -}.
@defun magit-insert-untracked-files
-Maybe insert a list or tree of untracked files.
+This function may insert a list of untracked files. Whether it
+actually does so, depends on the option described next.
+@end defun
-The option @code{magit-status-show-untracked-files} (which see), in
-cooperation with the Git variable @code{status.showUntrackedFiles},
-control whether and how that is done.
+@defopt magit-status-show-untracked-files
+This option controls whether the above function inserts a list of
+untracked files in the status buffer.
-If the first element of @code{magit-buffer-diff-files} is a directory, then
-limit the list to files below that. The value of that variable can
-be set using @code{D -- DIRECTORY RET g}.
-@end defun
+To disable listing untracked files in a specific repository only,
+add the following to @code{.dir-locals.el}:
+
+@lisp
+((magit-status-mode
+ (magit-status-show-untracked-files . \"no\")))
+@end lisp
+
+Alternatively (and mostly for historic reasons), it is possible to
+use @code{git config} to disable listing files for a specific repository,
+using:
+
+@example
+git config set --local status.showUntrackedFiles no
+@end example
+
+This does @strong{not} override the (if any) local value of this Lisp variable.
+It also is not possible to use the Git variable to enable listing files
+(in case the global value of this variable is nil).
+@end defopt
+
+@defopt magit-status-file-list-limit
+This option controls many files are listed at most in each section
+that lists files in the status buffer. For performance reasons, it
+is recommended that you do not increase this limit.
+@end defopt
-While the above function is a member of @code{magit-status-section-hook},
-the following functions by default are not.
+While the above function is a member of @code{magit-status-section-hook} by
+default, the following functions have to be explicitly added by the
+user. Because that negatively affects performance, it is recommended
+that you don't do that.
@defun magit-insert-tracked-files
-Insert a tree of tracked files.
+Insert a list of tracked files.
@end defun
@defun magit-insert-ignored-files
-Insert a tree of ignored files.
+Insert a list of ignored files.
@end defun
@defun magit-insert-skip-worktree-files
-Insert a tree of skip-worktree files.
+Insert a list of skip-worktree files.
@end defun
@defun magit-insert-assumed-unchanged-files
-Insert a tree of files that are assumed to be unchanged.
+Insert a list of files that are assumed to be unchanged.
@end defun
@anchor{Status Log Sections}
diff --git a/lisp/magit-status.el b/lisp/magit-status.el
index 78ed6250f22..d06a32264c1 100644
--- a/lisp/magit-status.el
+++ b/lisp/magit-status.el
@@ -142,57 +142,35 @@ The functions which respect this option are
:group 'magit-status
:type 'boolean)
-(defcustom magit-status-show-untracked-files nil
- "Whether and how to list untracked files in the status buffer.
+(defcustom magit-status-show-untracked-files t
+ "Whether to list untracked files in the status buffer.
-This controls the behavior of function `magit-insert-untracked-files'.
-If that function is removed from `magit-status-sections-hook', then
-untracked files are not shown, regardless of what this option says.
+To disable listing untracked files in a specific repository only, add
+the following to \".dir-locals.el\":
-The behavior can be controled using this option and/or the Git variable
-`status.showUntrackedFiles'. The following settings are used in order:
+ ((magit-status-mode
+ (magit-status-show-untracked-files . \"no\")))
-1. The buffer-local value of this option.
+Alternatively (and mostly for historic reasons), it is possible to use
+`git-config' to disable listing files for a specific repository, using:
- This can be set in \".dir-locals-2.el\" like so:
- ((magit-status-mode
- (magit-status-show-untracked-files . \"no\")))
+ git config set --local status.showUntrackedFiles no
-2. The repository-local value of `status.showUntrackedFiles'.
-
- This can be set using:
- git config --local status.showUntrackedFiles normal
-
-3. The global value of this option.
-
- This can be set using the Custom interface or `setq'.
-
-4. The global value of `status.showUntrackedFiles'.
-
- This can be set using:
- git config --global status.showUntrackedFiles all
-
-5. The default is \"normal\" and is used if all of the above places
- are unspecified or, in the case of the Lisp values, nil.
-
-The valid non-nil values are:
-
-- \"no\" - Show no untracked files.
-
-- \"normal\" - Show top-level untracked files and directories containing
- untracked files. The directories can be expanded to reveal the
- contained untracked files.
+This does *not* override the (if any) local value of this Lisp variable.
+It also is not possible to use the Git variable to enable listing files
+\(in case the global value of this variable is nil)."
+ :package-version '(magit . "4.2.1")
+ :group 'magit-status
+ :type 'boolean
+ :safe 'booleanp)
-- \"all\" - Immediately show all individual untracked files. This is
- potentially expensive and/or overwhelming, and should be avoided."
+(defcustom magit-status-file-list-limit 100
+ "How many files to list in file list sections in the status buffer.
+For performance reasons, it is recommended that you do not
+increase this limit."
:package-version '(magit . "4.2.1")
:group 'magit-status
- :type '(choice
- (const :tag "Show no untracked files" "no")
- (const :tag "Show directories containing untracked files" "normal")
- (const :tag "Show individual untracked files" "all")
- (const :tag "Use value of status.showUntrackedFiles" nil))
- :safe (lambda (value) (member value '("no" "normal" "all" nil))))
+ :type 'natnum)
(defcustom magit-status-margin
(list nil
@@ -755,100 +733,76 @@ remote in alphabetic order."
magit-insert-assume-unchanged-files)
(defun magit-insert-untracked-files ()
- "Maybe insert a list or tree of untracked files.
+ "Maybe insert list of untracked files.
-The option `magit-status-show-untracked-files' (which see), in
-cooperation with the Git variable `status.showUntrackedFiles', control
-whether and how that is done.
+List files if `magit-status-show-untracked-files' is non-nil, but also
+take the local value of Git variable `status.showUntrackedFiles' into
+account. If the Lisp variable has no local value and the local value
+of the Git variable is \"no\" or \"false\", then do not insert files. In
+all other cases only the Lisp variable matters.
-If the first element of `magit-buffer-diff-files' is a directory, then
-limit the list to files below that. The value of that variable can be
-set using \"D -- DIRECTORY RET g\"."
- (let ((show (or (and (local-variable-p 'magit-status-show-untracked-files)
+Honor the buffer's file filter, which can be set using \"D - -\"."
+ (when-let
+ ((value (or (and (local-variable-p 'magit-status-show-untracked-files)
magit-status-show-untracked-files)
- (magit-get "--local" "status.showUntrackedFiles")
- (default-value 'magit-status-show-untracked-files)
- (magit-get "--global" "status.showUntrackedFiles")
- "normal")))
- (unless (equal show "no")
- (let* ((all (equal show "all"))
- (base (car magit-buffer-diff-files))
- (base (and base (file-directory-p base) base)))
+ (and (not (member
+ (magit-get "--local" "status.showUntrackedFiles")
+ '("no" "false")))
+ magit-status-show-untracked-files))))
+ (if (eq value t)
(magit-insert-files 'untracked
- (lambda () (magit-untracked-files nil base))
- all)))))
+ (lambda (args) (magit-untracked-files nil (cdr
args))))
+ (display-warning 'magit-insert-untracked-files
+ (format "Value should be a lisp boolean, not %S." value)
+ :error))))
(defun magit-insert-tracked-files ()
- "Insert a tree of tracked files.
-
-If the first element of `magit-buffer-diff-files' is a
-directory, then limit the list to files below that. The value
-value of that variable can be set using \"D -- DIRECTORY RET g\"."
+ "Insert a list of tracked files.
+Honor the buffer's file filter, which can be set using \"D - -\"."
(magit-insert-files 'tracked #'magit-list-files))
(defun magit-insert-ignored-files ()
- "Insert a tree of ignored files.
-
-If the first element of `magit-buffer-diff-files' is a
-directory, then limit the list to files below that. The value
-of that variable can be set using \"D -- DIRECTORY RET g\"."
- (magit-insert-files 'ignored (lambda () (magit-ignored-files
"--directory"))))
+ "Insert a list of ignored files.
+Honor the buffer's file filter, which can be set using \"D - -\"."
+ (magit-insert-files 'ignored
+ (lambda (args) (magit-ignored-files "--directory"
args))))
(defun magit-insert-skip-worktree-files ()
- "Insert a tree of skip-worktree files.
-
-If the first element of `magit-buffer-diff-files' is a
-directory, then limit the list to files below that. The value
-of that variable can be set using \"D -- DIRECTORY RET g\"."
+ "Insert a list of skip-worktree files.
+Honor the buffer's file filter, which can be set using \"D - -\"."
(magit-insert-files 'skip-worktree #'magit-skip-worktree-files))
(defun magit-insert-assume-unchanged-files ()
- "Insert a tree of files that are assumed to be unchanged.
-
-If the first element of `magit-buffer-diff-files' is a
-directory, then limit the list to files below that. The value
-of that variable can be set using \"D -- DIRECTORY RET g\"."
+ "Insert a list of files that are assumed to be unchanged.
+Honor the buffer's file filter, which can be set using \"D - -\"."
(magit-insert-files 'assume-unchanged #'magit-assume-unchanged-files))
-(defvar magit-file-section-indent nil
- "Indentation used for simple `file' sections.
-If non-nil, this must be a string or character, and is used as
-indentation of `file' sections inserted by `magit-insert-*-files'.
-`file' sections that are part of diffs are not affected. This is mainly
-intended as a workaround for https://github.com/magit/magit/issues/5176,
-in which case ?\N{ZERO WIDTH SPACE} is a good value.")
-
-(defun magit-insert-files (type fn &optional nogroup)
- (when-let ((files (funcall fn)))
- (let* ((base (car magit-buffer-diff-files))
- (base (and base (file-directory-p base) base))
- (title (symbol-name type)))
- (magit-insert-section ((eval type) nil t)
- (magit-insert-heading (length files)
+(defun magit-insert-files (type fn)
+ (when-let ((files (funcall fn
+ (and magit-buffer-diff-files
+ (cons "--" magit-buffer-diff-files)))))
+ (magit-insert-section section ((eval type) nil t)
+ (magit-insert-heading (length files)
+ (let ((title (symbol-name type)))
(format "%c%s files"
(capitalize (aref title 0))
- (substring title 1)))
- (magit-insert-files-1 files base nogroup)
- (insert ?\n)))))
-
-(defun magit-insert-files-1 (files directory &optional nogroup)
- (while (and files (or nogroup
- (not directory)
- (string-prefix-p directory (car files))))
- (let ((dir (file-name-directory (car files))))
- (if (or nogroup (equal dir directory))
- (let ((file (pop files)))
- (magit-insert-section (file file)
- (when magit-file-section-indent
- (insert magit-file-section-indent))
- (insert (propertize file 'font-lock-face 'magit-filename) ?\n)))
- (magit-insert-section (file dir t)
- (when magit-file-section-indent
- (insert magit-file-section-indent))
- (insert (propertize dir 'file 'magit-filename) ?\n)
- (magit-insert-heading)
- (setq files (magit-insert-files-1 files dir))))))
- files)
+ (substring title 1))))
+ (magit-insert-section-body
+ (let ((magit-section-insert-in-reverse t)
+ (limit magit-status-file-list-limit))
+ (while (and files (> limit 0))
+ (cl-decf limit)
+ (let ((file (pop files)))
+ (magit-insert-section (file file)
+ (insert (propertize file 'font-lock-face 'magit-filename))
+ (insert ?\n))))
+ (when files
+ (magit-insert-section (info)
+ (insert (propertize
+ (format "%s files not listed\n" (length files))
+ 'face 'warning)))))
+ (insert ?\n)
+ (oset section children (nreverse (oref section children)))))))
;;; _
(provide 'magit-status)
diff --git a/test/magit-tests.el b/test/magit-tests.el
index 4df82d010fd..bb7f661541c 100644
--- a/test/magit-tests.el
+++ b/test/magit-tests.el
@@ -426,6 +426,7 @@ Enter passphrase for key '/home/user/.ssh/id_rsa': "
(defun magit-test-get-section (list file)
(magit-status-setup-buffer default-directory)
+ (magit-section-show-level-4-all)
(--first (equal (oref it value) file)
(oref (magit-get-section `(,list (status)))
children)))