mirror of https://github.com/Chizi123/.emacs.d.git

Chizi123
2018-11-18 c655eea759be1db69c5e6b45c228139d8390122a
commit | author | age
5cb5f7 1 ;;; magit-status.el --- the grand overview  -*- lexical-binding: t -*-
C 2
3 ;; Copyright (C) 2010-2018  The Magit Project Contributors
4 ;;
5 ;; You should have received a copy of the AUTHORS.md file which
6 ;; lists all contributors.  If not, see http://magit.vc/authors.
7
8 ;; Author: Jonas Bernoulli <jonas@bernoul.li>
9 ;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
10
11 ;; Magit is free software; you can redistribute it and/or modify it
12 ;; under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 3, or (at your option)
14 ;; any later version.
15 ;;
16 ;; Magit is distributed in the hope that it will be useful, but WITHOUT
17 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 ;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
19 ;; License for more details.
20 ;;
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with Magit.  If not, see http://www.gnu.org/licenses.
23
24 ;;; Commentary:
25
26 ;; This library implements the status buffer.
27
28 ;;; Code:
29
30 (eval-when-compile
31   (require 'subr-x))
32
33 (require 'magit)
34
35 (defvar bookmark-make-record-function)
36
37 ;;; Options
38
39 (defgroup magit-status nil
40   "Inspect and manipulate Git repositories."
41   :link '(info-link "(magit)Status Buffer")
42   :group 'magit-modes)
43
44 (defcustom magit-status-mode-hook nil
45   "Hook run after entering Magit-Status mode."
46   :group 'magit-status
47   :type 'hook)
48
49 (defcustom magit-status-headers-hook
50   '(magit-insert-error-header
51     magit-insert-diff-filter-header
52     magit-insert-head-branch-header
53     magit-insert-upstream-branch-header
54     magit-insert-push-branch-header
55     magit-insert-tags-header)
56   "Hook run to insert headers into the status buffer.
57
58 This hook is run by `magit-insert-status-headers', which in turn
59 has to be a member of `magit-status-sections-hook' to be used at
60 all."
61   :package-version '(magit . "2.1.0")
62   :group 'magit-status
63   :type 'hook
64   :options '(magit-insert-error-header
65              magit-insert-diff-filter-header
66              magit-insert-repo-header
67              magit-insert-remote-header
68              magit-insert-head-branch-header
69              magit-insert-upstream-branch-header
70              magit-insert-push-branch-header
71              magit-insert-tags-header))
72
73 (defcustom magit-status-sections-hook
74   '(magit-insert-status-headers
75     magit-insert-merge-log
76     magit-insert-rebase-sequence
77     magit-insert-am-sequence
78     magit-insert-sequencer-sequence
79     magit-insert-bisect-output
80     magit-insert-bisect-rest
81     magit-insert-bisect-log
82     magit-insert-untracked-files
83     magit-insert-unstaged-changes
84     magit-insert-staged-changes
85     magit-insert-stashes
86     magit-insert-unpushed-to-pushremote
87     magit-insert-unpushed-to-upstream-or-recent
88     magit-insert-unpulled-from-pushremote
89     magit-insert-unpulled-from-upstream)
90   "Hook run to insert sections into a status buffer."
91   :package-version '(magit . "2.12.0")
92   :group 'magit-status
93   :type 'hook)
94
95 (defcustom magit-status-initial-section '(1)
96   "The section point is placed on when a status buffer is created.
97
98 When such a buffer is merely being refreshed or being shown again
99 after it was merely burried, then this option has no effect.
100
101 If this is nil, then point remains on the very first section as
102 usual.  Otherwise it has to be a list of integers and section
103 identity lists.  The members of that list are tried in order
104 until a matching section is found.
105
106 An integer means to jump to the nth section, 1 for example
107 jumps over the headings.  To get a section's \"identity list\"
108 use \\[universal-argument] \\[magit-describe-section-briefly].
109
110 If, for example, you want to jump to the commits that haven't
111 been pulled from the upstream, or else the second section, then
112 use: (((unpulled . \"..@{upstream}\") (status)) 1).
113
114 See option `magit-section-initial-visibility-alist' for how to
115 control the initial visibility of the jumped to section."
116   :package-version '(magit . "2.90.0")
117   :group 'magit-status
118   :type '(choice (const :tag "as usual" nil)
119                  (repeat (choice (number :tag "nth top-level section")
120                                  (sexp   :tag "section identity")))))
121
122 (defcustom magit-status-show-hashes-in-headers nil
123   "Whether headers in the status buffer show hashes.
124 The functions which respect this option are
125 `magit-insert-head-branch-header',
126 `magit-insert-upstream-branch-header', and
127 `magit-insert-push-branch-header'."
128   :package-version '(magit . "2.4.0")
129   :group 'magit-status
130   :type 'boolean)
131
132 (defcustom magit-status-margin
133   (list nil
134         (nth 1 magit-log-margin)
135         'magit-log-margin-width nil
136         (nth 4 magit-log-margin))
137   "Format of the margin in `magit-status-mode' buffers.
138
139 The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).
140
141 If INIT is non-nil, then the margin is shown initially.
142 STYLE controls how to format the committer date.  It can be one
143   of `age' (to show the age of the commit), `age-abbreviated' (to
144   abbreviate the time unit to a character), or a string (suitable
145   for `format-time-string') to show the actual date.
146 WIDTH controls the width of the margin.  This exists for forward
147   compatibility and currently the value should not be changed.
148 AUTHOR controls whether the name of the author is also shown by
149   default.
150 AUTHOR-WIDTH has to be an integer.  When the name of the author
151   is shown, then this specifies how much space is used to do so."
152   :package-version '(magit . "2.9.0")
153   :group 'magit-status
154   :group 'magit-margin
155   :type magit-log-margin--custom-type
156   :initialize 'magit-custom-initialize-reset
157   :set-after '(magit-log-margin)
158   :set (apply-partially #'magit-margin-set-variable 'magit-status-mode))
159
160 ;;; Commands
161
162 ;;;###autoload
163 (defun magit-init (directory)
164   "Initialize a Git repository, then show its status.
165
166 If the directory is below an existing repository, then the user
167 has to confirm that a new one should be created inside.  If the
168 directory is the root of the existing repository, then the user
169 has to confirm that it should be reinitialized.
170
171 Non-interactively DIRECTORY is (re-)initialized unconditionally."
172   (interactive
173    (let ((directory (file-name-as-directory
174                      (expand-file-name
175                       (read-directory-name "Create repository in: ")))))
176      (when-let ((toplevel (magit-toplevel directory)))
177        (setq toplevel (expand-file-name toplevel))
178        (unless (y-or-n-p (if (file-equal-p toplevel directory)
179                              (format "Reinitialize existing repository %s? "
180                                      directory)
181                            (format "%s is a repository.  Create another in %s? "
182                                    toplevel directory)))
183          (user-error "Abort")))
184      (list directory)))
185   ;; `git init' does not understand the meaning of "~"!
186   (magit-call-git "init" (magit-convert-filename-for-git
187                           (expand-file-name directory)))
188   (magit-status-internal directory))
189
190 ;;;###autoload
191 (defun magit-status (&optional directory cache)
192   "Show the status of the current Git repository in a buffer.
193 With a prefix argument prompt for a repository to be shown.
194 With two prefix arguments prompt for an arbitrary directory.
195 If that directory isn't the root of an existing repository,
196 then offer to initialize it as a new repository."
197   (interactive
198    (let ((magit--refresh-cache (list (cons 0 0))))
199      (list (and (or current-prefix-arg (not (magit-toplevel)))
200                 (magit-read-repository
201                  (>= (prefix-numeric-value current-prefix-arg) 16)))
202            magit--refresh-cache)))
203   (let ((magit--refresh-cache (or cache (list (cons 0 0)))))
204     (if directory
205         (let ((toplevel (magit-toplevel directory)))
206           (setq directory (file-name-as-directory
207                            (expand-file-name directory)))
208           (if (and toplevel (file-equal-p directory toplevel))
209               (magit-status-internal directory)
210             (when (y-or-n-p
211                    (if toplevel
212                        (format "%s is a repository.  Create another in %s? "
213                                toplevel directory)
214                      (format "Create repository in %s? " directory)))
215               ;; Creating a new repository will invalidate cached
216               ;; values.
217               (setq magit--refresh-cache nil)
218               (magit-init directory))))
219       (magit-status-internal default-directory))))
220
221 (put 'magit-status 'interactive-only 'magit-status-internal)
222
223 (defalias 'magit 'magit-status
224   "An alias for `magit-status' for better discoverability.
225
226 Instead of invoking this alias for `magit-status' using
227 \"M-x magit RET\", you should bind a key to `magit-status'
228 and read the info node `(magit)Getting Started', which
229 also contains other useful hints.")
230
231 ;;;###autoload
232 (defun magit-status-internal (directory)
233   (magit--tramp-asserts directory)
234   (let ((default-directory directory))
235     (magit-mode-setup #'magit-status-mode)))
236
237 (defvar magit--remotes-using-recent-git nil)
238
239 (defun magit--tramp-asserts (directory)
240   (when-let ((remote (file-remote-p directory)))
241     (unless (member remote magit--remotes-using-recent-git)
242       (if-let ((version (let ((default-directory directory))
243                           (magit-git-version))))
244           (if (version<= magit--minimal-git version)
245               (push version magit--remotes-using-recent-git)
246             (display-warning 'magit (format "\
247 Magit requires Git >= %s, but on %s the version is %s.
248
249 If multiple Git versions are installed on the host, then the
250 problem might be that TRAMP uses the wrong executable.
251
252 First check the value of `magit-git-executable'.  Its value is
253 used when running git locally as well as when running it on a
254 remote host.  The default value is \"git\", except on Windows
255 where an absolute path is used for performance reasons.
256
257 If the value already is just \"git\" but TRAMP never-the-less
258 doesn't use the correct executable, then consult the info node
259 `(tramp)Remote programs'.\n" magit--minimal-git remote version) :error))
260         (display-warning 'magit (format "\
261 Magit cannot find Git on %s.
262
263 First check the value of `magit-git-executable'.  Its value is
264 used when running git locally as well as when running it on a
265 remote host.  The default value is \"git\", except on Windows
266 where an absolute path is used for performance reasons.
267
268 If the value already is just \"git\" but TRAMP never-the-less
269 doesn't find the executable, then consult the info node
270 `(tramp)Remote programs'.\n" remote) :error)))))
271
272 ;;; Mode
273
274 (defvar magit-status-mode-map
275   (let ((map (make-sparse-keymap)))
276     (set-keymap-parent map magit-mode-map)
277     (define-key map "jz" 'magit-jump-to-stashes)
278     (define-key map "jt" 'magit-jump-to-tracked)
279     (define-key map "jn" 'magit-jump-to-untracked)
280     (define-key map "ju" 'magit-jump-to-unstaged)
281     (define-key map "js" 'magit-jump-to-staged)
282     (define-key map "jfu" 'magit-jump-to-unpulled-from-upstream)
283     (define-key map "jfp" 'magit-jump-to-unpulled-from-pushremote)
284     (define-key map "jpu" 'magit-jump-to-unpushed-to-upstream)
285     (define-key map "jpp" 'magit-jump-to-unpushed-to-pushremote)
286     (define-key map [remap dired-jump] 'magit-dired-jump)
287     map)
288   "Keymap for `magit-status-mode'.")
289
290 (define-derived-mode magit-status-mode magit-mode "Magit"
291   "Mode for looking at Git status.
292
293 This mode is documented in info node `(magit)Status Buffer'.
294
295 \\<magit-mode-map>\
296 Type \\[magit-refresh] to refresh the current buffer.
297 Type \\[magit-section-toggle] to expand or hide the section at point.
298 Type \\[magit-visit-thing] to visit the change or commit at point.
299
300 Type \\[magit-dispatch-popup] to see available prefix popups.
301
302 Staging and applying changes is documented in info node
303 `(magit)Staging and Unstaging' and info node `(magit)Applying'.
304
305 \\<magit-hunk-section-map>Type \
306 \\[magit-apply] to apply the change at point, \
307 \\[magit-stage] to stage,
308 \\[magit-unstage] to unstage, \
309 \\[magit-discard] to discard, or \
310 \\[magit-reverse] to reverse it.
311
312 \\<magit-status-mode-map>\
313 Type \\[magit-commit-popup] to create a commit.
314
315 \\{magit-status-mode-map}"
316   :group 'magit-status
317   (hack-dir-local-variables-non-file-buffer)
318   (setq imenu-create-index-function
319         'magit-imenu--status-create-index-function)
320   (setq-local bookmark-make-record-function
321               #'magit-bookmark--status-make-record))
322
323 (defun magit-status-refresh-buffer ()
324   (magit-git-exit-code "update-index" "--refresh")
325   (magit-insert-section (status)
326     (magit-run-section-hook 'magit-status-sections-hook)))
327
328 (defun magit-status-goto-initial-section ()
329   "In a `magit-status-mode' buffer, jump `magit-status-initial-section'.
330 Actually doing so is deferred until `magit-refresh-buffer-hook'
331 runs `magit-status-goto-initial-section-1'.  That function then
332 removes itself from the hook, so that this only happens when the
333 status buffer is first created."
334   (when (and magit-status-initial-section
335              (derived-mode-p 'magit-status-mode))
336     (add-hook 'magit-refresh-buffer-hook
337               'magit-status-goto-initial-section-1 nil t)))
338
339 (defun magit-status-goto-initial-section-1 ()
340   "In a `magit-status-mode' buffer, jump `magit-status-initial-section'.
341 This function removes itself from `magit-refresh-buffer-hook'."
342   (when-let ((section
343               (--some (if (integerp it)
344                           (nth (1- it)
345                                (magit-section-siblings (magit-current-section)
346                                                        'next))
347                         (magit-get-section it))
348                       magit-status-initial-section)))
349     (goto-char (oref section start))
350     (when-let ((vis (cdr (assq 'magit-status-initial-section
351                                magit-section-initial-visibility-alist))))
352       (if (eq vis 'hide)
353           (magit-section-hide section)
354         (magit-section-show section))))
355   (remove-hook 'magit-refresh-buffer-hook
356                'magit-status-goto-initial-section-1 t))
357
358 (defun magit-status-maybe-update-revision-buffer (&optional _)
359   "When moving in the status buffer, update the revision buffer.
360 If there is no revision buffer in the same frame, then do nothing."
361   (when (derived-mode-p 'magit-status-mode)
362     (magit-log-maybe-update-revision-buffer-1)))
363
364 (defun magit-status-maybe-update-blob-buffer (&optional _)
365   "When moving in the status buffer, update the blob buffer.
366 If there is no blob buffer in the same frame, then do nothing."
367   (when (derived-mode-p 'magit-status-mode)
368     (magit-log-maybe-update-blob-buffer-1)))
369
370 ;;; Sections
371 ;;;; Special Headers
372
373 (defun magit-insert-status-headers ()
374   "Insert header sections appropriate for `magit-status-mode' buffers.
375 The sections are inserted by running the functions on the hook
376 `magit-status-headers-hook'."
377   (if (magit-rev-verify "HEAD")
378       (magit-insert-headers 'magit-status-headers-hook)
379     (insert "In the beginning there was darkness\n\n")))
380
381 (defvar magit-error-section-map
382   (let ((map (make-sparse-keymap)))
383     (define-key map [remap magit-visit-thing] 'magit-process-buffer)
384     map)
385   "Keymap for `error' sections.")
386
387 (defun magit-insert-error-header ()
388   "Insert the message about the Git error that just occured.
389
390 This function is only aware of the last error that occur when Git
391 was run for side-effects.  If, for example, an error occurs while
392 generating a diff, then that error won't be inserted.  Refreshing
393 the status buffer causes this section to disappear again."
394   (when magit-this-error
395     (magit-insert-section (error 'git)
396       (insert (propertize (format "%-10s" "GitError! ")
397                           'face 'magit-section-heading))
398       (insert (propertize magit-this-error 'face 'font-lock-warning-face))
399       (when-let ((key (car (where-is-internal 'magit-process-buffer))))
400         (insert (format "  [Type `%s' for details]" (key-description key))))
401       (insert ?\n))
402     (setq magit-this-error nil)))
403
404 (defun magit-insert-diff-filter-header ()
405   "Insert a header line showing the effective diff filters."
406   (let ((ignore-modules (magit-ignore-submodules-p)))
407     (when (or ignore-modules
408               magit-diff-section-file-args)
409       (insert (propertize (format "%-10s" "Filter! ")
410                           'face 'magit-section-heading))
411       (when ignore-modules
412         (insert ignore-modules)
413         (when magit-diff-section-file-args
414           (insert " -- ")))
415       (when magit-diff-section-file-args
416         (insert (mapconcat #'identity magit-diff-section-file-args " ")))
417       (insert ?\n))))
418
419 ;;;; Reference Headers
420
421 (cl-defun magit-insert-head-branch-header
422     (&optional (branch (magit-get-current-branch)))
423   "Insert a header line about BRANCH.
424 When BRANCH is nil, use the current branch or, if none, the
425 detached `HEAD'."
426   (let ((output (magit-rev-format "%h %s" (or branch "HEAD"))))
427     (string-match "^\\([^ ]+\\) \\(.*\\)" output)
428     (magit-bind-match-strings (commit summary) output
429       (if branch
430           (magit-insert-section (branch branch)
431             (insert (format "%-10s" "Head: "))
432             (when magit-status-show-hashes-in-headers
433               (insert (propertize commit 'face 'magit-hash) ?\s))
434             (insert (propertize branch 'face 'magit-branch-local))
435             (insert ?\s)
436             (insert (funcall magit-log-format-message-function branch summary))
437             (insert ?\n))
438         (magit-insert-section (commit commit)
439           (insert (format "%-10s" "Head: "))
440           (insert (propertize commit 'face 'magit-hash))
441           (insert ?\s summary ?\n))))))
442
443 (cl-defun magit-insert-upstream-branch-header
444     (&optional (branch (magit-get-current-branch))
445                (pull   (magit-get-upstream-branch branch))
446                keyword)
447   "Insert a header line about branch usually pulled into current branch."
448   (when pull
449     (magit-insert-section (branch pull)
450       (let ((rebase (magit-get "branch" branch "rebase")))
451         (pcase rebase
452           ("true")
453           ("false" (setq rebase nil))
454           (_       (setq rebase (magit-get-boolean "pull.rebase"))))
455         (insert (format "%-10s" (or keyword (if rebase "Rebase: " "Merge: ")))))
456       (--when-let (and magit-status-show-hashes-in-headers
457                        (not (string-match-p " " pull))
458                        (magit-rev-format "%h" pull))
459         (insert (propertize it 'face 'magit-hash) " "))
460       (if (string-match-p " " pull)
461           (pcase-let ((`(,url ,branch) (split-string pull " ")))
462             (insert branch " from " url " "))
463         (insert pull " ")
464         (--if-let (and (magit-rev-verify pull)
465                        (magit-rev-format "%s" pull))
466             (insert (funcall magit-log-format-message-function pull it))
467           (insert (propertize "is missing" 'face 'font-lock-warning-face))))
468       (insert ?\n))))
469
470 (cl-defun magit-insert-push-branch-header
471     (&optional (branch (magit-get-current-branch))
472                (push   (magit-get-push-branch branch)))
473   "Insert a header line about the branch the current branch is pushed to."
474   (when push
475     (magit-insert-section (branch push)
476       (insert (format "%-10s" "Push: "))
477       (--when-let (and magit-status-show-hashes-in-headers
478                        (magit-rev-format "%h" push))
479         (insert (propertize it 'face 'magit-hash) ?\s))
480       (insert (propertize push 'face 'magit-branch-remote) ?\s)
481       (--if-let (and (magit-rev-verify push)
482                      (magit-rev-format "%s" push))
483           (insert (funcall magit-log-format-message-function push it))
484         (insert (propertize "is missing" 'face 'font-lock-warning-face)))
485       (insert ?\n))))
486
487 (defun magit-insert-tags-header ()
488   "Insert a header line about the current and/or next tag."
489   (let* ((this-tag (magit-get-current-tag nil t))
490          (next-tag (magit-get-next-tag nil t))
491          (this-cnt (cadr this-tag))
492          (next-cnt (cadr next-tag))
493          (this-tag (car this-tag))
494          (next-tag (car next-tag))
495          (both-tags (and this-tag next-tag t)))
496     (when (or this-tag next-tag)
497       (magit-insert-section (tag (or this-tag next-tag))
498         (insert (format "%-10s" (if both-tags "Tags: " "Tag: ")))
499         (cl-flet ((insert-count
500                    (tag count face)
501                    (insert (concat (propertize tag 'face 'magit-tag)
502                                    (and (> count 0)
503                                         (format " (%s)"
504                                                 (propertize (format "%s" count)
505                                                             'face face)))))))
506           (when this-tag  (insert-count this-tag this-cnt 'magit-branch-local))
507           (when both-tags (insert ", "))
508           (when next-tag  (insert-count next-tag next-cnt 'magit-tag)))
509         (insert ?\n)))))
510
511 ;;;; Auxiliary Headers
512
513 (defun magit-insert-user-header ()
514   "Insert a header line about the current user."
515   (let ((name  (magit-get "user.name"))
516         (email (magit-get "user.email")))
517     (when (and name email)
518       (magit-insert-section (user name)
519         (insert (format "%-10s" "User: "))
520         (insert (propertize name 'face 'magit-log-author))
521         (insert " <" email ">\n")))))
522
523 (defun magit-insert-repo-header ()
524   "Insert a header line showing the path to the repository top-level."
525   (let ((topdir (magit-toplevel)))
526     (magit-insert-section (repo topdir)
527       (insert (format "%-10s%s\n" "Repo: " (abbreviate-file-name topdir))))))
528
529 (defun magit-insert-remote-header ()
530   "Insert a header line about the remote of the current branch.
531
532 If no remote is configured for the current branch, then fall back
533 showing the \"origin\" remote, or if that does not exist the first
534 remote in alphabetic order."
535   (when-let ((name (magit-get-some-remote))
536              ;; Under certain configurations it's possible for url
537              ;; to be nil, when name is not, see #2858.
538              (url (magit-get "remote" name "url")))
539     (magit-insert-section (remote name)
540       (insert (format "%-10s" "Remote: "))
541       (insert (propertize name 'face 'magit-branch-remote) ?\s)
542       (insert url ?\n))))
543
544 ;;;; File Sections
545
546 (defvar magit-untracked-section-map
547   (let ((map (make-sparse-keymap)))
548     (define-key map [remap magit-delete-thing] 'magit-discard)
549     (define-key map "s" 'magit-stage)
550     map)
551   "Keymap for the `untracked' section.")
552
553 (magit-define-section-jumper magit-jump-to-untracked "Untracked files" untracked)
554
555 (defun magit-insert-untracked-files ()
556   "Maybe insert a list or tree of untracked files.
557
558 Do so depending on the value of `status.showUntrackedFiles'.
559 Note that even if the value is `all', Magit still initially
560 only shows directories.  But the directory sections can then
561 be expanded using \"TAB\".
562
563 If the first element of `magit-diff-section-arguments' is a
564 directory, then limit the list to files below that.  The value
565 value of that variable can be set using \"D = f DIRECTORY RET g\"."
566   (let* ((show (or (magit-get "status.showUntrackedFiles") "normal"))
567          (base (car magit-diff-section-file-args))
568          (base (and base (file-directory-p base) base)))
569     (unless (equal show "no")
570       (if (equal show "all")
571           (when-let ((files (magit-untracked-files nil base)))
572             (magit-insert-section (untracked)
573               (magit-insert-heading "Untracked files:")
574               (magit-insert-files files base)
575               (insert ?\n)))
576         (when-let ((files
577                     (--mapcat (and (eq (aref it 0) ??)
578                                    (list (substring it 3)))
579                               (magit-git-items "status" "-z" "--porcelain"
580                                                (magit-ignore-submodules-p)
581                                                "--" base))))
582           (magit-insert-section (untracked)
583             (magit-insert-heading "Untracked files:")
584             (dolist (file files)
585               (magit-insert-section (file file)
586                 (insert (propertize file 'face 'magit-filename) ?\n)))
587             (insert ?\n)))))))
588
589 (magit-define-section-jumper magit-jump-to-tracked "Tracked files" tracked)
590
591 (defun magit-insert-tracked-files ()
592   "Insert a tree of tracked files.
593
594 If the first element of `magit-diff-section-arguments' is a
595 directory, then limit the list to files below that.  The value
596 value of that variable can be set using \"D = f DIRECTORY RET g\"."
597   (when-let ((files (magit-list-files)))
598     (let* ((base (car magit-diff-section-file-args))
599            (base (and base (file-directory-p base) base)))
600       (magit-insert-section (tracked nil t)
601         (magit-insert-heading "Tracked files:")
602         (magit-insert-files files base)
603         (insert ?\n)))))
604
605 (defun magit-insert-ignored-files ()
606   "Insert a tree of ignored files.
607
608 If the first element of `magit-diff-section-arguments' is a
609 directory, then limit the list to files below that.  The value
610 of that variable can be set using \"D = f DIRECTORY RET g\"."
611   (when-let ((files (magit-ignored-files)))
612     (let* ((base (car magit-diff-section-file-args))
613            (base (and base (file-directory-p base) base)))
614       (magit-insert-section (tracked nil t)
615         (magit-insert-heading "Ignored files:")
616         (magit-insert-files files base)
617         (insert ?\n)))))
618
619 (defun magit-insert-files (files directory)
620   (while (and files (string-prefix-p (or directory "") (car files)))
621     (let ((dir (file-name-directory (car files))))
622       (if (equal dir directory)
623           (let ((file (pop files)))
624             (magit-insert-section (file file)
625               (insert (propertize file 'face 'magit-filename) ?\n)))
626         (magit-insert-section (file dir t)
627           (insert (propertize dir 'file 'magit-filename) ?\n)
628           (magit-insert-heading)
629           (setq files (magit-insert-files files dir))))))
630   files)
631
632 ;;; _
633 (provide 'magit-status)
634 ;;; magit-status.el ends here