1122 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			EmacsLisp
		
	
	
	
	
	
			
		
		
	
	
			1122 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			EmacsLisp
		
	
	
	
	
	
;;; magit-mode.el --- create and refresh Magit buffers  -*- lexical-binding: t -*-
 | 
						|
 | 
						|
;; Copyright (C) 2010-2016  The Magit Project Contributors
 | 
						|
;;
 | 
						|
;; You should have received a copy of the AUTHORS.md file which
 | 
						|
;; lists all contributors.  If not, see http://magit.vc/authors.
 | 
						|
 | 
						|
;; Author: Jonas Bernoulli <jonas@bernoul.li>
 | 
						|
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
 | 
						|
 | 
						|
;; Magit 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, or (at your option)
 | 
						|
;; any later version.
 | 
						|
;;
 | 
						|
;; Magit 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 Magit.  If not, see http://www.gnu.org/licenses.
 | 
						|
 | 
						|
;;; Commentary:
 | 
						|
 | 
						|
;; This library implements the abstract major-mode `magit-mode' from
 | 
						|
;; which almost all other Magit major-modes derive.  The code in here
 | 
						|
;; is mostly concerned with creating and refreshing Magit buffers.
 | 
						|
 | 
						|
;;; Code:
 | 
						|
 | 
						|
(require 'cl-lib)
 | 
						|
(require 'dash)
 | 
						|
 | 
						|
(require 'magit-section)
 | 
						|
(require 'magit-git)
 | 
						|
 | 
						|
;; For `magit-xref-insert-buttons' from `magit'
 | 
						|
(defvar magit-diff-show-xref-buttons)
 | 
						|
(defvar magit-revision-show-xref-buttons)
 | 
						|
;; For `magit-refresh' and `magit-refresh-all'
 | 
						|
(declare-function magit-auto-revert-buffers 'magit-autorevert)
 | 
						|
 | 
						|
(require 'format-spec)
 | 
						|
(require 'help-mode)
 | 
						|
 | 
						|
;;; Options
 | 
						|
 | 
						|
(defcustom magit-mode-hook
 | 
						|
  '(magit-load-config-extensions
 | 
						|
    magit-xref-setup)
 | 
						|
  "Hook run when entering a mode derived from Magit mode."
 | 
						|
  :group 'magit-modes
 | 
						|
  :type 'hook
 | 
						|
  :options '(magit-load-config-extensions
 | 
						|
             magit-xref-setup
 | 
						|
             bug-reference-mode))
 | 
						|
 | 
						|
(defcustom magit-mode-setup-hook
 | 
						|
  '(magit-maybe-save-repository-buffers
 | 
						|
    magit-maybe-show-margin)
 | 
						|
  "Hook run by `magit-mode-setup'."
 | 
						|
  :package-version '(magit . "2.3.0")
 | 
						|
  :group 'magit-modes
 | 
						|
  :type 'hook
 | 
						|
  :options '(magit-maybe-save-repository-buffers
 | 
						|
             magit-maybe-show-margin))
 | 
						|
 | 
						|
(defcustom magit-pre-refresh-hook '(magit-maybe-save-repository-buffers)
 | 
						|
  "Hook run before refreshing in `magit-refresh'.
 | 
						|
 | 
						|
This hook, or `magit-post-refresh-hook', should be used
 | 
						|
for functions that are not tied to a particular buffer.
 | 
						|
 | 
						|
To run a function with a particular buffer current, use
 | 
						|
`magit-refresh-buffer-hook' and use `derived-mode-p'
 | 
						|
inside your function."
 | 
						|
  :package-version '(magit . "2.4.0")
 | 
						|
  :group 'magit-modes
 | 
						|
  :type 'hook
 | 
						|
  :options '(magit-maybe-save-repository-buffers))
 | 
						|
 | 
						|
(defcustom magit-post-refresh-hook nil
 | 
						|
  "Hook run after refreshing in `magit-refresh'.
 | 
						|
 | 
						|
This hook, or `magit-pre-refresh-hook', should be used
 | 
						|
for functions that are not tied to a particular buffer.
 | 
						|
 | 
						|
To run a function with a particular buffer current, use
 | 
						|
`magit-refresh-buffer-hook' and use `derived-mode-p'
 | 
						|
inside your function."
 | 
						|
  :package-version '(magit . "2.4.0")
 | 
						|
  :group 'magit-modes
 | 
						|
  :type 'hook)
 | 
						|
 | 
						|
(defcustom magit-display-buffer-function 'magit-display-buffer-traditional
 | 
						|
  "The function used display a Magit buffer.
 | 
						|
 | 
						|
All Magit buffers (buffers whose major-modes derive from
 | 
						|
`magit-mode') are displayed using `magit-display-buffer',
 | 
						|
which in turn uses the function specified here."
 | 
						|
  :package-version '(magit . "2.3.0")
 | 
						|
  :group 'magit-modes
 | 
						|
  :type '(radio (function-item magit-display-buffer-traditional)
 | 
						|
                (function-item magit-display-buffer-same-window-except-diff-v1)
 | 
						|
                (function-item magit-display-buffer-fullframe-status-v1)
 | 
						|
                (function-item magit-display-buffer-fullframe-status-topleft-v1)
 | 
						|
                (function-item magit-display-buffer-fullcolumn-most-v1)
 | 
						|
                (function-item display-buffer)
 | 
						|
                (function :tag "Function")))
 | 
						|
 | 
						|
(unless (find-lisp-object-file-name 'magit-pre-display-buffer-hook 'defvar)
 | 
						|
  (add-hook 'magit-pre-display-buffer-hook 'magit-save-window-configuration))
 | 
						|
(defcustom magit-pre-display-buffer-hook '(magit-save-window-configuration)
 | 
						|
  "Hook run by `magit-display-buffer' before displaying the buffer."
 | 
						|
  :package-version '(magit . "2.3.0")
 | 
						|
  :group 'magit-modes
 | 
						|
  :type 'hook
 | 
						|
  :options '(magit-save-window-configuration))
 | 
						|
 | 
						|
(unless (find-lisp-object-file-name 'magit-post-display-buffer-hook 'defvar)
 | 
						|
  (add-hook 'magit-post-display-buffer-hook 'magit-maybe-set-dedicated))
 | 
						|
(defcustom magit-post-display-buffer-hook '(magit-maybe-set-dedicated)
 | 
						|
  "Hook run by `magit-display-buffer' after displaying the buffer."
 | 
						|
  :package-version '(magit . "2.3.0")
 | 
						|
  :group 'magit-modes
 | 
						|
  :type 'hook
 | 
						|
  :options '(magit-maybe-set-dedicated))
 | 
						|
 | 
						|
(defcustom magit-generate-buffer-name-function
 | 
						|
  'magit-generate-buffer-name-default-function
 | 
						|
  "The function used to generate the name for a Magit buffer."
 | 
						|
  :package-version '(magit . "2.3.0")
 | 
						|
  :group 'magit-modes
 | 
						|
  :type '(radio (function-item magit-generate-buffer-name-default-function)
 | 
						|
                (function :tag "Function")))
 | 
						|
 | 
						|
(defcustom magit-buffer-name-format "*%M%v: %t"
 | 
						|
  "The format string used to name Magit buffers.
 | 
						|
 | 
						|
The following %-sequences are supported:
 | 
						|
 | 
						|
`%m' The name of the major-mode, but with the `-mode' suffix
 | 
						|
     removed.
 | 
						|
 | 
						|
`%M' Like \"%m\" but abbreviate `magit-status-mode' as `magit'.
 | 
						|
 | 
						|
`%v' The value the buffer is locked to, in parentheses, or an empty
 | 
						|
     string if the buffer is not locked to a value.
 | 
						|
 | 
						|
`%V' Like \"%v\", but the string is prefixed with a space, unless it
 | 
						|
     is an empty string.
 | 
						|
 | 
						|
`%t' The top-level directory of the working tree of the
 | 
						|
     repository, or if `magit-uniquify-buffer-names' is non-nil
 | 
						|
     an abbreviation of that.
 | 
						|
 | 
						|
The value should always contain either \"%m\" or \"%M\" as well as
 | 
						|
\"%t\".  If `magit-uniquify-buffer-names' is non-nil, then the
 | 
						|
value must end with \"%t\".
 | 
						|
 | 
						|
This is used by `magit-generate-buffer-name-default-function'.
 | 
						|
If another `magit-generate-buffer-name-function' is used, then
 | 
						|
it may not respect this option, or on the contrary it may
 | 
						|
support additional %-sequences."
 | 
						|
  :package-version '(magit . "2.3.0")
 | 
						|
  :group 'magit-modes
 | 
						|
  :type 'string)
 | 
						|
 | 
						|
(defcustom magit-uniquify-buffer-names t
 | 
						|
  "Whether to uniquify the names of Magit buffers."
 | 
						|
  :package-version '(magit . "2.3.0")
 | 
						|
  :group 'magit-modes
 | 
						|
  :type 'boolean)
 | 
						|
 | 
						|
(defcustom magit-bury-buffer-function 'magit-restore-window-configuration
 | 
						|
  "The function used to bury or kill the current Magit buffer."
 | 
						|
  :package-version '(magit . "2.3.0")
 | 
						|
  :group 'magit-modes
 | 
						|
  :type '(radio (function-item quit-window)
 | 
						|
                (function-item magit-mode-quit-window)
 | 
						|
                (function-item magit-restore-window-configuration)
 | 
						|
                (function :tag "Function")))
 | 
						|
 | 
						|
(defcustom magit-region-highlight-hook
 | 
						|
  '(magit-section-update-region magit-diff-update-hunk-region)
 | 
						|
  "Functions used to highlight the region.
 | 
						|
Each function is run with the current section as only argument
 | 
						|
until one of them returns non-nil.  When multiple sections are
 | 
						|
selected, then this hook does not run and the region is not
 | 
						|
displayed.  Otherwise fall back to regular region highlighting."
 | 
						|
  :package-version '(magit . "2.1.0")
 | 
						|
  :group 'magit-modes
 | 
						|
  :type 'hook
 | 
						|
  :options '(magit-section-update-region magit-diff-update-hunk-region))
 | 
						|
 | 
						|
(defcustom magit-refresh-verbose nil
 | 
						|
  "Whether to revert Magit buffers verbosely."
 | 
						|
  :package-version '(magit . "2.1.0")
 | 
						|
  :group 'magit-modes
 | 
						|
  :type 'boolean)
 | 
						|
 | 
						|
(defcustom magit-refresh-buffer-hook nil
 | 
						|
  "Normal hook for `magit-refresh-buffer' to run after refreshing."
 | 
						|
  :package-version '(magit . "2.1.0")
 | 
						|
  :group 'magit-modes
 | 
						|
  :type 'hook)
 | 
						|
 | 
						|
(defcustom magit-refresh-status-buffer t
 | 
						|
  "Whether the status buffer is refreshed after running git.
 | 
						|
 | 
						|
When this is non-nil, then the status buffer is automatically
 | 
						|
refreshed after running git for side-effects, in addition to the
 | 
						|
current Magit buffer, which is always refreshed automatically.
 | 
						|
 | 
						|
Only set this to nil after exhausting all other options to
 | 
						|
improve performance."
 | 
						|
  :package-version '(magit . "2.4.0")
 | 
						|
  :group 'magit-status
 | 
						|
  :type 'boolean)
 | 
						|
 | 
						|
(defcustom magit-save-repository-buffers t
 | 
						|
  "Whether to save file-visiting buffers when appropriate.
 | 
						|
 | 
						|
If this is non-nil then all modified file-visiting buffers
 | 
						|
belonging to the current repository may be saved before running
 | 
						|
commands, before creating new Magit buffers, and before
 | 
						|
explicitly refreshing such buffers.  If this is `dontask' then
 | 
						|
this is done without user intervention, if it is t then the user
 | 
						|
has to confirm each save.  `dontask' is the recommended setting."
 | 
						|
  :group 'magit
 | 
						|
  :type '(choice (const :tag "Never" nil)
 | 
						|
                 (const :tag "Ask" t)
 | 
						|
                 (const :tag "Save without asking" dontask)))
 | 
						|
 | 
						|
(defcustom magit-keep-region-overlay nil
 | 
						|
  "Whether to keep the region overlay when there is a valid selection.
 | 
						|
 | 
						|
By default Magit removes the regular region overlay if, and only
 | 
						|
if, that region constitutes a valid selection as understood by
 | 
						|
Magit commands.  Otherwise it does not remove that overlay, and
 | 
						|
the region looks like it would in other buffers.
 | 
						|
 | 
						|
There are two types of such valid selections: hunk-internal
 | 
						|
regions and regions that select two or more sibling sections.
 | 
						|
In such cases Magit removes the region overlay and instead
 | 
						|
highlights a slightly larger range.  All text (for hunk-internal
 | 
						|
regions) or the headings of all sections (for sibling selections)
 | 
						|
that are inside that range (not just inside the region) are acted
 | 
						|
on by commands such as the staging command.  This buffer range
 | 
						|
begins at the beginning of the line on which the region begins
 | 
						|
and ends at the end of the line on which the region ends.
 | 
						|
 | 
						|
Because Magit acts on this larger range and not the region, it is
 | 
						|
actually quite important to visualize that larger range.  If we
 | 
						|
don't do that, then one might think that these commands act on
 | 
						|
the region instead.  If you want to *also* visualize the region,
 | 
						|
then set this option to t.  But please note that when the region
 | 
						|
does *not* constitute a valid selection, then the region is
 | 
						|
*always* visualized as usual, and that it is usually under such
 | 
						|
circumstances that you want to use a non-magit command to act on
 | 
						|
the region.
 | 
						|
 | 
						|
Besides keeping the region overlay, setting this option to t also
 | 
						|
causes all face properties, except for `:foreground', to be
 | 
						|
ignored for the faces used to highlight headings of selected
 | 
						|
sections.  This avoids the worst conflicts that result from
 | 
						|
displaying the region and the selection overlays at the same
 | 
						|
time.  We are not interested in dealing with other conflicts.
 | 
						|
In fact we *already* provide a way to avoid all of these
 | 
						|
conflicts: *not* changing the value of this option.
 | 
						|
 | 
						|
It should be clear by now that we consider it a mistake to set
 | 
						|
this to display the region when the Magit selection is also
 | 
						|
visualized, but since it has been requested a few times and
 | 
						|
because it doesn't cost much to offer this option we do so.
 | 
						|
However that might change.  If the existence of this option
 | 
						|
starts complicating other things, then it will be removed."
 | 
						|
  :package-version '(magit . "2.3.0")
 | 
						|
  :group 'magit-modes
 | 
						|
  :type 'boolean)
 | 
						|
 | 
						|
;;; Magit Mode
 | 
						|
 | 
						|
(defvar magit-mode-map
 | 
						|
  (let ((map (make-keymap)))
 | 
						|
    (suppress-keymap map t)
 | 
						|
    (define-key map "\t"    'magit-section-toggle)
 | 
						|
    (define-key map [C-tab] 'magit-section-cycle)
 | 
						|
    (define-key map [M-tab] 'magit-section-cycle-diffs)
 | 
						|
    (define-key map [S-tab] 'magit-section-cycle-global)
 | 
						|
    ;; Next two are for backward compatibility.
 | 
						|
    (define-key map [s-tab] 'magit-section-cycle-global)
 | 
						|
    (define-key map [backtab] 'magit-section-cycle-global)
 | 
						|
    (define-key map "^"    'magit-section-up)
 | 
						|
    (define-key map "n"    'magit-section-forward)
 | 
						|
    (define-key map "p"    'magit-section-backward)
 | 
						|
    (define-key map "\M-n" 'magit-section-forward-sibling)
 | 
						|
    (define-key map "\M-p" 'magit-section-backward-sibling)
 | 
						|
    (define-key map "+"    'magit-diff-more-context)
 | 
						|
    (define-key map "-"    'magit-diff-less-context)
 | 
						|
    (define-key map "0"    'magit-diff-default-context)
 | 
						|
    (define-key map "1"    'magit-section-show-level-1)
 | 
						|
    (define-key map "2"    'magit-section-show-level-2)
 | 
						|
    (define-key map "3"    'magit-section-show-level-3)
 | 
						|
    (define-key map "4"    'magit-section-show-level-4)
 | 
						|
    (define-key map "\M-1" 'magit-section-show-level-1-all)
 | 
						|
    (define-key map "\M-2" 'magit-section-show-level-2-all)
 | 
						|
    (define-key map "\M-3" 'magit-section-show-level-3-all)
 | 
						|
    (define-key map "\M-4" 'magit-section-show-level-4-all)
 | 
						|
    (define-key map "g" 'magit-refresh)
 | 
						|
    (define-key map "G" 'magit-refresh-all)
 | 
						|
    (define-key map "q" 'magit-mode-bury-buffer)
 | 
						|
    (define-key map "$" 'magit-process-buffer)
 | 
						|
    (define-key map "a" 'magit-cherry-apply)
 | 
						|
    (define-key map "A" 'magit-cherry-pick-popup)
 | 
						|
    (define-key map "b" 'magit-branch-popup)
 | 
						|
    (define-key map "B" 'magit-bisect-popup)
 | 
						|
    (define-key map "c" 'magit-commit-popup)
 | 
						|
    (define-key map "d" 'magit-diff-popup)
 | 
						|
    (define-key map "D" 'magit-diff-refresh-popup)
 | 
						|
    (define-key map "h" 'magit-dispatch-popup)
 | 
						|
    (define-key map "?" 'magit-dispatch-popup)
 | 
						|
    (define-key map "\C-c\C-c" 'magit-dispatch-popup)
 | 
						|
    (define-key map "\C-c\C-e" 'magit-dispatch-popup)
 | 
						|
    (define-key map "e" 'magit-ediff-dwim)
 | 
						|
    (define-key map "E" 'magit-ediff-popup)
 | 
						|
    (define-key map "f" 'magit-fetch-popup)
 | 
						|
    (define-key map "F" 'magit-pull-popup)
 | 
						|
    (define-key map "i" 'magit-gitignore)
 | 
						|
    (define-key map "I" 'magit-gitignore-locally)
 | 
						|
    (define-key map "k" 'magit-delete-thing)
 | 
						|
    (define-key map "K" 'magit-file-untrack)
 | 
						|
    (define-key map "l" 'magit-log-popup)
 | 
						|
    (define-key map "L" 'magit-log-refresh-popup)
 | 
						|
    (define-key map "m" 'magit-merge-popup)
 | 
						|
    (define-key map "M" 'magit-remote-popup)
 | 
						|
    (define-key map "o" 'magit-submodule-popup)
 | 
						|
    (define-key map "O" 'magit-subtree-popup)
 | 
						|
    (define-key map "P" 'magit-push-popup)
 | 
						|
    (define-key map "r" 'magit-rebase-popup)
 | 
						|
    (define-key map "R" 'magit-file-rename)
 | 
						|
    (define-key map "t" 'magit-tag-popup)
 | 
						|
    (define-key map "T" 'magit-notes-popup)
 | 
						|
    (define-key map "\r"       'magit-visit-thing)
 | 
						|
    (define-key map [C-return] 'magit-visit-thing)
 | 
						|
    (define-key map "\M-\r"    'magit-dired-jump)
 | 
						|
    (define-key map "\s"       'magit-diff-show-or-scroll-up)
 | 
						|
    (define-key map "\d"       'magit-diff-show-or-scroll-down)
 | 
						|
    (define-key map "s" 'magit-stage-file)
 | 
						|
    (define-key map "S" 'magit-stage-modified)
 | 
						|
    (define-key map "u" 'magit-unstage-file)
 | 
						|
    (define-key map "U" 'magit-unstage-all)
 | 
						|
    (define-key map "v" 'magit-revert-no-commit)
 | 
						|
    (define-key map "V" 'magit-revert-popup)
 | 
						|
    (define-key map "w" 'magit-am-popup)
 | 
						|
    (define-key map "W" 'magit-patch-popup)
 | 
						|
    (define-key map "x" 'magit-reset)
 | 
						|
    (define-key map "X" 'magit-reset-popup)
 | 
						|
    (define-key map "y" 'magit-show-refs-popup)
 | 
						|
    (define-key map "Y" 'magit-cherry)
 | 
						|
    (define-key map "z" 'magit-stash-popup)
 | 
						|
    (define-key map "Z" 'magit-stash-popup)
 | 
						|
    (define-key map ":" 'magit-git-command)
 | 
						|
    (define-key map "!" 'magit-run-popup)
 | 
						|
    (define-key map "\C-xa"  'magit-add-change-log-entry)
 | 
						|
    (define-key map "\C-x4a" 'magit-add-change-log-entry-other-window)
 | 
						|
    (define-key map "\C-w"   'magit-copy-section-value)
 | 
						|
    (define-key map "\M-w"   'magit-copy-buffer-revision)
 | 
						|
    (define-key map [remap evil-previous-line] 'evil-previous-visual-line)
 | 
						|
    (define-key map [remap evil-next-line] 'evil-next-visual-line)
 | 
						|
    map)
 | 
						|
  "Parent keymap for all keymaps of modes derived from `magit-mode'.")
 | 
						|
 | 
						|
(defun magit-delete-thing ()
 | 
						|
  "This is a placeholder command.
 | 
						|
Where applicable, section-specific keymaps bind another command
 | 
						|
which deletes the thing at point."
 | 
						|
  (interactive)
 | 
						|
  (user-error "There is no thing at point that could be deleted"))
 | 
						|
 | 
						|
(defun magit-visit-thing ()
 | 
						|
  "This is a placeholder command.
 | 
						|
Where applicable, section-specific keymaps bind another command
 | 
						|
which visits the thing at point."
 | 
						|
  (interactive)
 | 
						|
  (user-error "There is no thing at point that could be visited"))
 | 
						|
 | 
						|
(easy-menu-define magit-mode-menu magit-mode-map
 | 
						|
  "Magit menu"
 | 
						|
  '("Magit"
 | 
						|
    ["Refresh" magit-refresh t]
 | 
						|
    ["Refresh all" magit-refresh-all t]
 | 
						|
    "---"
 | 
						|
    ["Stage" magit-stage t]
 | 
						|
    ["Stage modified" magit-stage-modified t]
 | 
						|
    ["Unstage" magit-unstage t]
 | 
						|
    ["Reset index" magit-reset-index t]
 | 
						|
    ["Commit" magit-commit-popup t]
 | 
						|
    ["Add log entry" magit-commit-add-log t]
 | 
						|
    ["Tag" magit-tag t]
 | 
						|
    "---"
 | 
						|
    ["Diff working tree" magit-diff-working-tree t]
 | 
						|
    ["Diff" magit-diff t]
 | 
						|
    ("Log"
 | 
						|
     ["Log" magit-log t]
 | 
						|
     ["Reflog" magit-reflog t]
 | 
						|
     ["Extended..." magit-log-popup t])
 | 
						|
    "---"
 | 
						|
    ["Cherry pick" magit-cherry-pick t]
 | 
						|
    ["Revert commit" magit-revert-popup t]
 | 
						|
    "---"
 | 
						|
    ["Ignore" magit-gitignore t]
 | 
						|
    ["Ignore locally" magit-gitignore-locally t]
 | 
						|
    ["Discard" magit-discard t]
 | 
						|
    ["Reset head" magit-reset-head t]
 | 
						|
    ["Stash" magit-stash t]
 | 
						|
    ["Snapshot" magit-snapshot t]
 | 
						|
    "---"
 | 
						|
    ["Branch..." magit-checkout t]
 | 
						|
    ["Merge" magit-merge t]
 | 
						|
    ["Ediff resolve" magit-ediff-resolve t]
 | 
						|
    ["Rebase..." magit-rebase-popup t]
 | 
						|
    "---"
 | 
						|
    ["Push" magit-push t]
 | 
						|
    ["Pull" magit-pull t]
 | 
						|
    ["Remote update" magit-fetch-all t]
 | 
						|
    ("Submodule"
 | 
						|
     ["Submodule update" magit-submodule-update t]
 | 
						|
     ["Submodule update and init" magit-submodule-setup t]
 | 
						|
     ["Submodule init" magit-submodule-init t]
 | 
						|
     ["Submodule sync" magit-submodule-sync t])
 | 
						|
    "---"
 | 
						|
    ("Extensions")
 | 
						|
    "---"
 | 
						|
    ["Display Git output" magit-process-buffer t]
 | 
						|
    ["Quit Magit" magit-mode-bury-buffer t]))
 | 
						|
 | 
						|
(defun magit-load-config-extensions ()
 | 
						|
  "Load Magit extensions that are defined at the Git config layer."
 | 
						|
  (dolist (ext (magit-get-all "magit.extension"))
 | 
						|
    (let ((sym (intern (format "magit-%s-mode" ext))))
 | 
						|
      (when (fboundp sym)
 | 
						|
        (funcall sym 1)))))
 | 
						|
 | 
						|
(define-derived-mode magit-mode special-mode "Magit"
 | 
						|
  "Parent major mode from which Magit major modes inherit.
 | 
						|
 | 
						|
Magit is documented in info node `(magit)'."
 | 
						|
  :group 'magit-modes
 | 
						|
  (buffer-disable-undo)
 | 
						|
  (setq truncate-lines t)
 | 
						|
  (setq buffer-read-only t)
 | 
						|
  (setq-local line-move-visual t) ; see #1771
 | 
						|
  (setq show-trailing-whitespace nil)
 | 
						|
  (setq list-buffers-directory default-directory)
 | 
						|
  (hack-dir-local-variables-non-file-buffer)
 | 
						|
  (make-local-variable 'text-property-default-nonsticky)
 | 
						|
  (push (cons 'keymap t) text-property-default-nonsticky)
 | 
						|
  (add-hook 'post-command-hook #'magit-section-update-highlight t t)
 | 
						|
  (setq-local redisplay-highlight-region-function 'magit-highlight-region)
 | 
						|
  (setq-local redisplay-unhighlight-region-function 'magit-unhighlight-region)
 | 
						|
  (when (bound-and-true-p global-linum-mode)
 | 
						|
    (linum-mode -1))
 | 
						|
  (when (and (fboundp 'nlinum-mode)
 | 
						|
             (bound-and-true-p global-nlinum-mode))
 | 
						|
    (nlinum-mode -1)))
 | 
						|
 | 
						|
(defvar-local magit-region-overlays nil)
 | 
						|
 | 
						|
(defun magit-delete-region-overlays ()
 | 
						|
  (mapc #'delete-overlay magit-region-overlays)
 | 
						|
  (setq magit-region-overlays nil))
 | 
						|
 | 
						|
(defun magit-highlight-region (start end window rol)
 | 
						|
  (magit-delete-region-overlays)
 | 
						|
  (if (and (run-hook-with-args-until-success 'magit-region-highlight-hook
 | 
						|
                                             (magit-current-section))
 | 
						|
           (not magit-keep-region-overlay))
 | 
						|
      (funcall (default-value 'redisplay-unhighlight-region-function) rol)
 | 
						|
    (funcall (default-value 'redisplay-highlight-region-function)
 | 
						|
             start end window rol)))
 | 
						|
 | 
						|
(defun magit-unhighlight-region (rol)
 | 
						|
  (setq magit-section-highlighted-section nil)
 | 
						|
  (magit-delete-region-overlays)
 | 
						|
  (funcall (default-value 'redisplay-unhighlight-region-function) rol))
 | 
						|
 | 
						|
(defvar-local magit-refresh-args nil
 | 
						|
  "The arguments used to refresh the current buffer.")
 | 
						|
(put 'magit-refresh-args 'permanent-local t)
 | 
						|
 | 
						|
(defvar-local magit-previous-section nil)
 | 
						|
(put 'magit-previous-section 'permanent-local t)
 | 
						|
 | 
						|
(defun magit-mode-setup (mode &rest args)
 | 
						|
  "Setup up a MODE buffer using ARGS to generate its content."
 | 
						|
  (magit-mode-setup-internal mode args))
 | 
						|
 | 
						|
(defun magit-mode-setup-internal (mode args &optional locked)
 | 
						|
  "Setup up a MODE buffer using ARGS to generate its content.
 | 
						|
When optional LOCKED is non-nil, then create a buffer that is
 | 
						|
locked to its value, which is derived from MODE and ARGS."
 | 
						|
  (let ((buffer (magit-mode-get-buffer
 | 
						|
                 mode t nil
 | 
						|
                 (and locked (magit-buffer-lock-value mode args))))
 | 
						|
        (section (magit-current-section)))
 | 
						|
    (with-current-buffer buffer
 | 
						|
      (setq magit-previous-section section)
 | 
						|
      (setq magit-refresh-args args)
 | 
						|
      (funcall mode))
 | 
						|
    (magit-display-buffer buffer)
 | 
						|
    (with-current-buffer buffer
 | 
						|
      (run-hooks 'magit-mode-setup-hook)
 | 
						|
      (magit-refresh-buffer))))
 | 
						|
 | 
						|
(defvar magit-display-buffer-noselect nil
 | 
						|
  "If non-nil, then `magit-display-buffer' doesn't call `select-window'.")
 | 
						|
 | 
						|
(defun magit-display-buffer (buffer)
 | 
						|
  "Display BUFFER in some window and maybe select it.
 | 
						|
 | 
						|
Display the buffer using `magit-display-buffer-function' and
 | 
						|
then, unless `magit-display-buffer-noselect' is non-nil, select
 | 
						|
the window which was used to display the buffer.
 | 
						|
 | 
						|
Also run the hooks `magit-pre-display-buffer-hook'
 | 
						|
and `magit-post-display-buffer-hook'."
 | 
						|
  (with-current-buffer buffer
 | 
						|
    (run-hooks 'magit-pre-display-buffer-hook))
 | 
						|
  (let ((window (funcall magit-display-buffer-function buffer)))
 | 
						|
    (unless magit-display-buffer-noselect
 | 
						|
      (select-window window)))
 | 
						|
  (with-current-buffer buffer
 | 
						|
    (run-hooks 'magit-post-display-buffer-hook)))
 | 
						|
 | 
						|
(defun magit-display-buffer-traditional (buffer)
 | 
						|
  "Display BUFFER the way this has traditionally been done."
 | 
						|
  (display-buffer
 | 
						|
   buffer (if (and (derived-mode-p 'magit-mode)
 | 
						|
                   (not (memq (with-current-buffer buffer major-mode)
 | 
						|
                              '(magit-process-mode
 | 
						|
                                magit-revision-mode
 | 
						|
                                magit-diff-mode
 | 
						|
                                magit-stash-mode
 | 
						|
                                magit-status-mode))))
 | 
						|
              '(display-buffer-same-window)
 | 
						|
            nil))) ; display in another window
 | 
						|
 | 
						|
(defun magit-display-buffer-same-window-except-diff-v1 (buffer)
 | 
						|
  "Display BUFFER in the selected window except for some modes.
 | 
						|
If a buffer's `major-mode' derives from `magit-diff-mode' or
 | 
						|
`magit-process-mode', display it in another window.  Display all
 | 
						|
other buffers in the selected window."
 | 
						|
  (display-buffer
 | 
						|
   buffer (if (with-current-buffer buffer
 | 
						|
                (derived-mode-p 'magit-diff-mode 'magit-process-mode))
 | 
						|
              nil  ; display in another window
 | 
						|
            '(display-buffer-same-window))))
 | 
						|
 | 
						|
(defun magit--display-buffer-fullframe (buffer alist)
 | 
						|
  (-when-let (window (or (display-buffer-reuse-window buffer alist)
 | 
						|
                         (display-buffer-same-window buffer alist)
 | 
						|
                         (display-buffer-pop-up-window buffer alist)
 | 
						|
                         (display-buffer-use-some-window buffer alist)))
 | 
						|
    (delete-other-windows window)
 | 
						|
    window))
 | 
						|
 | 
						|
(defun magit-display-buffer-fullframe-status-v1 (buffer)
 | 
						|
  "Display BUFFER, filling entire frame if BUFFER is a status buffer.
 | 
						|
Otherwise, behave like `magit-display-buffer-traditional'."
 | 
						|
  (if (eq (with-current-buffer buffer major-mode)
 | 
						|
          'magit-status-mode)
 | 
						|
      (display-buffer buffer '(magit--display-buffer-fullframe))
 | 
						|
    (magit-display-buffer-traditional buffer)))
 | 
						|
 | 
						|
(defun magit--display-buffer-topleft (buffer alist)
 | 
						|
  (or (display-buffer-reuse-window buffer alist)
 | 
						|
      (-when-let (window2 (display-buffer-pop-up-window buffer alist))
 | 
						|
        (let ((window1 (get-buffer-window))
 | 
						|
              (buffer1 (current-buffer))
 | 
						|
              (buffer2 (window-buffer window2))
 | 
						|
              (w2-quit-restore (window-parameter window2 'quit-restore)))
 | 
						|
          (set-window-buffer window1 buffer2)
 | 
						|
          (set-window-buffer window2 buffer1)
 | 
						|
          (select-window window2)
 | 
						|
          ;; Swap some window state that `magit-mode-quit-window' and
 | 
						|
          ;; `quit-restore-window' inspect.
 | 
						|
          (set-window-prev-buffers window2 (cdr (window-prev-buffers window1)))
 | 
						|
          (set-window-prev-buffers window1 nil)
 | 
						|
          (set-window-parameter window2 'magit-dedicated
 | 
						|
                                (window-parameter window1 'magit-dedicated))
 | 
						|
          (set-window-parameter window1 'magit-dedicated t)
 | 
						|
          (set-window-parameter window1 'quit-restore
 | 
						|
                                (list 'window 'window
 | 
						|
                                      (nth 2 w2-quit-restore)
 | 
						|
                                      (nth 3 w2-quit-restore)))
 | 
						|
          (set-window-parameter window2 'quit-restore nil)
 | 
						|
          window1))))
 | 
						|
 | 
						|
(defun magit-display-buffer-fullframe-status-topleft-v1 (buffer)
 | 
						|
  "Display BUFFER, filling entire frame if BUFFER is a status buffer.
 | 
						|
When BUFFER derives from `magit-diff-mode' or
 | 
						|
`magit-process-mode', try to display BUFFER to the top or left of
 | 
						|
the current buffer rather than to the bottom or right, as
 | 
						|
`magit-display-buffer-fullframe-status-v1' would.  Whether the
 | 
						|
split is made vertically or horizontally is determined by
 | 
						|
`split-window-preferred-function'."
 | 
						|
  (display-buffer
 | 
						|
   buffer
 | 
						|
   (cond ((eq (with-current-buffer buffer major-mode)
 | 
						|
              'magit-status-mode)
 | 
						|
          '(magit--display-buffer-fullframe))
 | 
						|
         ((with-current-buffer buffer
 | 
						|
            (derived-mode-p 'magit-diff-mode 'magit-process-mode))
 | 
						|
          '(magit--display-buffer-topleft))
 | 
						|
         (t
 | 
						|
          '(display-buffer-same-window)))))
 | 
						|
 | 
						|
(defun magit--display-buffer-fullcolumn (buffer alist)
 | 
						|
  (-when-let (window (or (display-buffer-reuse-window buffer alist)
 | 
						|
                         (display-buffer-same-window buffer alist)
 | 
						|
                         (display-buffer-below-selected buffer alist)))
 | 
						|
    (delete-other-windows-vertically window)
 | 
						|
    window))
 | 
						|
 | 
						|
(defun magit-display-buffer-fullcolumn-most-v1 (buffer)
 | 
						|
  "Display BUFFER using the full column except in some cases.
 | 
						|
For most cases where BUFFER's `major-mode' derives from
 | 
						|
`magit-mode', display it in the selected window and grow that
 | 
						|
window to the full height of the frame, deleting other windows in
 | 
						|
that column as necessary.  However, display BUFFER in another
 | 
						|
window if 1) BUFFER's mode derives from `magit-process-mode', or
 | 
						|
2) BUFFER's mode derives from `magit-diff-mode', provided that
 | 
						|
the mode of the current buffer derives from `magit-log-mode' or
 | 
						|
`magit-cherry-mode'."
 | 
						|
  (display-buffer
 | 
						|
   buffer
 | 
						|
   (cond ((and (derived-mode-p 'magit-log-mode 'magit-cherry-mode)
 | 
						|
               (with-current-buffer buffer
 | 
						|
                 (derived-mode-p 'magit-diff-mode)))
 | 
						|
          nil)
 | 
						|
         ((with-current-buffer buffer
 | 
						|
            (derived-mode-p 'magit-process-mode))
 | 
						|
          nil)
 | 
						|
         (t
 | 
						|
          '(magit--display-buffer-fullcolumn)))))
 | 
						|
 | 
						|
(defun magit-maybe-set-dedicated ()
 | 
						|
  "Mark the selected window as dedicated if appropriate.
 | 
						|
 | 
						|
If a new window was created to display the buffer, then remember
 | 
						|
that fact.  That information is used by `magit-mode-quit-window',
 | 
						|
to determine whether the window should be deleted when its last
 | 
						|
Magit buffer is buried."
 | 
						|
  (let ((window (get-buffer-window (current-buffer))))
 | 
						|
    (when (and (window-live-p window)
 | 
						|
               (not (window-prev-buffers window)))
 | 
						|
      (set-window-parameter window 'magit-dedicated t))))
 | 
						|
 | 
						|
(defvar-local magit--default-directory nil
 | 
						|
  "Value of `default-directory' when buffer is generated.
 | 
						|
This exists to prevent a let-bound `default-directory' from
 | 
						|
tricking `magit-mode-get-buffer' or `magit-mode-get-buffers' into
 | 
						|
thinking a buffer belongs to a repo that it doesn't.")
 | 
						|
(put 'magit--default-directory 'permanent-local t)
 | 
						|
 | 
						|
(defun magit-mode-get-buffers ()
 | 
						|
  (let ((topdir (magit-toplevel)))
 | 
						|
    (--filter (with-current-buffer it
 | 
						|
                (and (derived-mode-p 'magit-mode)
 | 
						|
                     (equal magit--default-directory topdir)))
 | 
						|
              (buffer-list))))
 | 
						|
 | 
						|
(defvar-local magit-buffer-locked-p nil)
 | 
						|
(put 'magit-buffer-locked-p 'permanent-local t)
 | 
						|
 | 
						|
(defun magit-mode-get-buffer (mode &optional create frame value)
 | 
						|
  (-if-let (topdir (magit-toplevel))
 | 
						|
      (or (--first (with-current-buffer it
 | 
						|
                     (and (eq major-mode mode)
 | 
						|
                          (equal magit--default-directory topdir)
 | 
						|
                          (if value
 | 
						|
                              (and magit-buffer-locked-p
 | 
						|
                                   (equal (magit-buffer-lock-value) value))
 | 
						|
                            (not magit-buffer-locked-p))))
 | 
						|
                   (if frame
 | 
						|
                       (-map #'window-buffer
 | 
						|
                             (window-list (unless (eq frame t) frame)))
 | 
						|
                     (buffer-list)))
 | 
						|
          (and create
 | 
						|
               (let ((default-directory topdir))
 | 
						|
                 (magit-generate-new-buffer mode value))))
 | 
						|
    (user-error "Not inside a Git repository")))
 | 
						|
 | 
						|
(defun magit-generate-new-buffer (mode &optional value)
 | 
						|
  (let* ((name (funcall magit-generate-buffer-name-function mode value))
 | 
						|
         (buffer (generate-new-buffer name)))
 | 
						|
    (with-current-buffer buffer
 | 
						|
      (setq magit--default-directory default-directory)
 | 
						|
      (setq magit-buffer-locked-p (and value t)))
 | 
						|
    (when magit-uniquify-buffer-names
 | 
						|
      (add-to-list 'uniquify-list-buffers-directory-modes mode)
 | 
						|
      (with-current-buffer buffer
 | 
						|
        (setq list-buffers-directory default-directory))
 | 
						|
      (let ((uniquify-buffer-name-style
 | 
						|
             (if (memq uniquify-buffer-name-style '(nil forward))
 | 
						|
                 'post-forward-angle-brackets
 | 
						|
               uniquify-buffer-name-style)))
 | 
						|
        (uniquify-rationalize-file-buffer-names
 | 
						|
         name (file-name-directory (directory-file-name default-directory))
 | 
						|
         buffer)))
 | 
						|
    buffer))
 | 
						|
 | 
						|
(defun magit-generate-buffer-name-default-function (mode &optional value)
 | 
						|
  (let ((m (substring (symbol-name mode) 0 -5))
 | 
						|
        (v (and value (format "%s" (if (listp value) value (list value))))))
 | 
						|
    (format-spec
 | 
						|
     magit-buffer-name-format
 | 
						|
     `((?m . ,m)
 | 
						|
       (?M . ,(if (eq mode 'magit-status-mode) "magit" m))
 | 
						|
       (?v . ,(or v ""))
 | 
						|
       (?V . ,(if v (concat " " v) ""))
 | 
						|
       (?t . ,(if magit-uniquify-buffer-names
 | 
						|
                  (file-name-nondirectory
 | 
						|
                   (directory-file-name default-directory))
 | 
						|
                (abbreviate-file-name default-directory)))))))
 | 
						|
 | 
						|
(defun magit-toggle-buffer-lock ()
 | 
						|
  "Lock the current buffer to its value or unlock it.
 | 
						|
 | 
						|
Locking a buffer to its value prevents it from being reused to
 | 
						|
display another value.  The name of a locked buffer contains its
 | 
						|
value, which allows telling it apart from other locked buffers
 | 
						|
and the unlocked buffer.
 | 
						|
 | 
						|
Not all Magit buffers can be locked to their values, for example
 | 
						|
it wouldn't make sense to lock a status buffer.
 | 
						|
 | 
						|
There can only be a single unlocked buffer using a certain
 | 
						|
major-mode per repository.  So when a buffer is being unlocked
 | 
						|
and another unlocked buffer already exists for that mode and
 | 
						|
repository, then the former buffer is instead deleted and the
 | 
						|
latter is displayed in its place."
 | 
						|
  (interactive)
 | 
						|
  (if magit-buffer-locked-p
 | 
						|
      (-if-let (unlocked (magit-mode-get-buffer major-mode))
 | 
						|
          (let ((locked (current-buffer)))
 | 
						|
            (switch-to-buffer unlocked nil t)
 | 
						|
            (kill-buffer locked))
 | 
						|
        (setq magit-buffer-locked-p nil)
 | 
						|
        (rename-buffer (funcall magit-generate-buffer-name-function
 | 
						|
                                major-mode)))
 | 
						|
    (-if-let (value (magit-buffer-lock-value))
 | 
						|
        (-if-let (locked (magit-mode-get-buffer major-mode nil nil value))
 | 
						|
            (let ((unlocked (current-buffer)))
 | 
						|
              (switch-to-buffer locked nil t)
 | 
						|
              (kill-buffer unlocked))
 | 
						|
          (setq magit-buffer-locked-p t)
 | 
						|
          (rename-buffer (funcall magit-generate-buffer-name-function
 | 
						|
                                  major-mode value)))
 | 
						|
      (user-error "Buffer has no value it could be locked to"))))
 | 
						|
 | 
						|
(cl-defun magit-buffer-lock-value
 | 
						|
    (&optional (mode major-mode)
 | 
						|
               (args magit-refresh-args))
 | 
						|
  (cl-case mode
 | 
						|
    (magit-cherry-mode
 | 
						|
     (-let [(upstream head) args]
 | 
						|
       (concat head ".." upstream)))
 | 
						|
    (magit-diff-mode
 | 
						|
     (-let [(rev-or-range const _args files) args]
 | 
						|
       (nconc (cons (or rev-or-range
 | 
						|
                        (if (member "--cached" const)
 | 
						|
                            (progn (setq const (delete "--cached" const))
 | 
						|
                                   'staged)
 | 
						|
                          'unstaged))
 | 
						|
                    const)
 | 
						|
              (and files (cons "--" files)))))
 | 
						|
    (magit-log-mode
 | 
						|
     (-let [(revs _args files) args]
 | 
						|
       (if (and revs files)
 | 
						|
           (append revs (cons "--" files))
 | 
						|
         (append revs files))))
 | 
						|
    (magit-refs-mode
 | 
						|
     (-let [(ref args) args]
 | 
						|
       (cons (or ref "HEAD") args)))
 | 
						|
    (magit-revision-mode
 | 
						|
     (-let [(rev __const _args files) args]
 | 
						|
       (if files (cons rev files) (list rev))))
 | 
						|
    ((magit-reflog-mode   ; (ref ~args)
 | 
						|
      magit-stash-mode    ; (stash _const _args _files)
 | 
						|
      magit-stashes-mode) ; (ref)
 | 
						|
     (car args))))
 | 
						|
 | 
						|
(defun magit-mode-bury-buffer (&optional kill-buffer)
 | 
						|
  "Bury the current buffer.
 | 
						|
With a prefix argument, kill the buffer instead.
 | 
						|
This is done using `magit-bury-buffer-function'."
 | 
						|
  (interactive "P")
 | 
						|
  (funcall magit-bury-buffer-function kill-buffer))
 | 
						|
 | 
						|
(defun magit-mode-quit-window (kill-buffer)
 | 
						|
  "Quit the selected window and bury its buffer.
 | 
						|
 | 
						|
This behaves similar to `quit-window', but when the window
 | 
						|
was originally created to display a Magit buffer and the
 | 
						|
current buffer is the last remaining Magit buffer that was
 | 
						|
ever displayed in the selected window, then delete that
 | 
						|
window."
 | 
						|
  (if (or (one-window-p)
 | 
						|
          (--first (let ((buffer (car it)))
 | 
						|
                     (and (not (eq buffer (current-buffer)))
 | 
						|
                          (buffer-live-p buffer)
 | 
						|
                          (or (not (window-parameter nil 'magit-dedicated))
 | 
						|
                              (with-current-buffer buffer
 | 
						|
                                (derived-mode-p 'magit-mode
 | 
						|
                                                'magit-process-mode)))))
 | 
						|
                   (window-prev-buffers)))
 | 
						|
      (quit-window kill-buffer)
 | 
						|
    (let ((window (selected-window)))
 | 
						|
      (quit-window kill-buffer)
 | 
						|
      (when (window-live-p window)
 | 
						|
        (delete-window window)))))
 | 
						|
 | 
						|
;;; Refresh Magit Buffers
 | 
						|
 | 
						|
(defvar inhibit-magit-refresh nil)
 | 
						|
 | 
						|
(defun magit-refresh ()
 | 
						|
  "Refresh some buffers belonging to the current repository.
 | 
						|
 | 
						|
Refresh the current buffer if its major mode derives from
 | 
						|
`magit-mode', and refresh the corresponding status buffer.
 | 
						|
 | 
						|
Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'."
 | 
						|
  (interactive)
 | 
						|
  (unless inhibit-magit-refresh
 | 
						|
    (let ((start (current-time))
 | 
						|
          (magit--refresh-cache (list (cons 0 0))))
 | 
						|
      (when magit-refresh-verbose
 | 
						|
        (message "Refreshing magit..."))
 | 
						|
      (magit-run-hook-with-benchmark 'magit-pre-refresh-hook)
 | 
						|
      (when (derived-mode-p 'magit-mode)
 | 
						|
        (magit-refresh-buffer))
 | 
						|
      (--when-let (and magit-refresh-status-buffer
 | 
						|
                       (not (derived-mode-p 'magit-status-mode))
 | 
						|
                       (magit-mode-get-buffer 'magit-status-mode))
 | 
						|
        (with-current-buffer it
 | 
						|
          (magit-refresh-buffer)))
 | 
						|
      (magit-auto-revert-buffers)
 | 
						|
      (magit-run-hook-with-benchmark 'magit-post-refresh-hook)
 | 
						|
      (when magit-refresh-verbose
 | 
						|
        (message "Refreshing magit...done (%.3fs, cached %s/%s)"
 | 
						|
                 (float-time (time-subtract (current-time) start))
 | 
						|
                 (caar magit--refresh-cache)
 | 
						|
                 (+ (caar magit--refresh-cache)
 | 
						|
                    (cdar magit--refresh-cache)))))))
 | 
						|
 | 
						|
(defun magit-refresh-all ()
 | 
						|
  "Refresh all buffers belonging to the current repository.
 | 
						|
 | 
						|
Refresh all Magit buffers belonging to the current repository,
 | 
						|
and revert buffers that visit files located inside the current
 | 
						|
repository.
 | 
						|
 | 
						|
Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'."
 | 
						|
  (interactive)
 | 
						|
  (magit-run-hook-with-benchmark 'magit-pre-refresh-hook)
 | 
						|
  (dolist (buffer (magit-mode-get-buffers))
 | 
						|
    (with-current-buffer buffer (magit-refresh-buffer)))
 | 
						|
  (magit-auto-revert-buffers)
 | 
						|
  (magit-run-hook-with-benchmark 'magit-post-refresh-hook))
 | 
						|
 | 
						|
(defvar-local magit-refresh-start-time nil)
 | 
						|
 | 
						|
(defun magit-refresh-buffer ()
 | 
						|
  "Refresh the current Magit buffer."
 | 
						|
  (setq magit-refresh-start-time (current-time))
 | 
						|
  (let ((refresh (intern (format "%s-refresh-buffer"
 | 
						|
                                 (substring (symbol-name major-mode) 0 -5))))
 | 
						|
        (magit--refresh-cache (or magit--refresh-cache (list (cons 0 0)))))
 | 
						|
    (when (functionp refresh)
 | 
						|
      (when magit-refresh-verbose
 | 
						|
        (message "Refreshing buffer `%s'..." (buffer-name)))
 | 
						|
      (let* ((buffer (current-buffer))
 | 
						|
             (windows
 | 
						|
              (--mapcat (with-selected-window it
 | 
						|
                          (with-current-buffer buffer
 | 
						|
                            (-when-let (section (magit-current-section))
 | 
						|
                              (list
 | 
						|
                               (nconc (list it section)
 | 
						|
                                      (magit-refresh-get-relative-position))))))
 | 
						|
                        (or (get-buffer-window-list buffer nil t)
 | 
						|
                            (list (selected-window))))))
 | 
						|
        (deactivate-mark)
 | 
						|
        (setq magit-section-highlight-overlays nil
 | 
						|
              magit-section-highlighted-section nil
 | 
						|
              magit-section-highlighted-sections nil
 | 
						|
              magit-section-unhighlight-sections nil)
 | 
						|
        (let ((inhibit-read-only t))
 | 
						|
          (erase-buffer)
 | 
						|
          (save-excursion
 | 
						|
            (apply refresh magit-refresh-args)))
 | 
						|
        (dolist (window windows)
 | 
						|
          (with-selected-window (car window)
 | 
						|
            (with-current-buffer buffer
 | 
						|
              (apply #'magit-section-goto-successor (cdr window)))))
 | 
						|
        (run-hooks 'magit-refresh-buffer-hook)
 | 
						|
        (magit-section-update-highlight)
 | 
						|
        (set-buffer-modified-p nil))
 | 
						|
      (when magit-refresh-verbose
 | 
						|
        (message "Refreshing buffer `%s'...done (%.3fs)" (buffer-name)
 | 
						|
                 (float-time (time-subtract (current-time)
 | 
						|
                                            magit-refresh-start-time)))))))
 | 
						|
 | 
						|
(defun magit-refresh-get-relative-position ()
 | 
						|
  (-when-let (section (magit-current-section))
 | 
						|
    (let ((start (magit-section-start section)))
 | 
						|
      (list (count-lines start (point))
 | 
						|
            (- (point) (line-beginning-position))
 | 
						|
            (and (eq (magit-section-type section) 'hunk)
 | 
						|
                 (region-active-p)
 | 
						|
                 (progn (goto-char (line-beginning-position))
 | 
						|
                        (when  (looking-at "^[-+]") (forward-line))
 | 
						|
                        (while (looking-at "^[ @]") (forward-line))
 | 
						|
                        (let ((beg (point)))
 | 
						|
                          (cond ((looking-at "^[-+]")
 | 
						|
                                 (forward-line)
 | 
						|
                                 (while (looking-at "^[-+]") (forward-line))
 | 
						|
                                 (while (looking-at "^ ")    (forward-line))
 | 
						|
                                 (forward-line -1)
 | 
						|
                                 (regexp-quote (buffer-substring-no-properties
 | 
						|
                                                beg (line-end-position))))
 | 
						|
                                (t t)))))))))
 | 
						|
 | 
						|
;;; Save File-Visiting Buffers
 | 
						|
 | 
						|
(defvar disable-magit-save-buffers nil)
 | 
						|
 | 
						|
(defun magit-pre-command-hook ()
 | 
						|
  (setq disable-magit-save-buffers nil))
 | 
						|
(add-hook 'pre-command-hook #'magit-pre-command-hook)
 | 
						|
 | 
						|
(defvar magit-after-save-refresh-buffers nil)
 | 
						|
 | 
						|
(defun magit-after-save-refresh-buffers ()
 | 
						|
  (dolist (buffer magit-after-save-refresh-buffers)
 | 
						|
    (when (buffer-live-p buffer)
 | 
						|
      (with-current-buffer buffer
 | 
						|
        (magit-refresh-buffer))))
 | 
						|
  (setq magit-after-save-refresh-buffers nil)
 | 
						|
  (remove-hook 'post-command-hook 'magit-after-save-refresh-buffers))
 | 
						|
 | 
						|
(defun magit-after-save-refresh-status ()
 | 
						|
  "Refresh the status buffer of the current repository.
 | 
						|
 | 
						|
This function is intended to be added to `after-save-hook'.
 | 
						|
 | 
						|
If the status buffer does not exist or the file being visited in
 | 
						|
the current buffer isn't inside the working tree of a repository,
 | 
						|
then do nothing.
 | 
						|
 | 
						|
Note that refreshing a Magit buffer is done by re-creating its
 | 
						|
contents from scratch, which can be slow in large repositories.
 | 
						|
If you are not satisfied with Magit's performance, then you
 | 
						|
should obviously not add this function to that hook."
 | 
						|
  (when (and (not disable-magit-save-buffers)
 | 
						|
             (magit-inside-worktree-p))
 | 
						|
    (--when-let (ignore-errors (magit-mode-get-buffer 'magit-status-mode))
 | 
						|
      (add-to-list 'magit-after-save-refresh-buffers it)
 | 
						|
      (add-hook 'post-command-hook 'magit-after-save-refresh-buffers))))
 | 
						|
 | 
						|
(defun magit-maybe-save-repository-buffers ()
 | 
						|
  "Maybe save file-visiting buffers belonging to the current repository.
 | 
						|
Do so if `magit-save-repository-buffers' is non-nil.  You should
 | 
						|
not remove this from any hooks, instead set that variable to nil
 | 
						|
if you so desire."
 | 
						|
  (when (and magit-save-repository-buffers
 | 
						|
             (not disable-magit-save-buffers))
 | 
						|
    (setq disable-magit-save-buffers t)
 | 
						|
    (let ((msg (current-message)))
 | 
						|
      (magit-save-repository-buffers
 | 
						|
       (eq magit-save-repository-buffers 'dontask))
 | 
						|
      (when (and msg (not (equal msg (current-message))))
 | 
						|
        (message "%s" msg)))))
 | 
						|
 | 
						|
(add-hook 'magit-pre-refresh-hook #'magit-maybe-save-repository-buffers)
 | 
						|
(add-hook 'magit-pre-call-git-hook #'magit-maybe-save-repository-buffers)
 | 
						|
(add-hook 'magit-pre-start-git-hook #'magit-maybe-save-repository-buffers)
 | 
						|
 | 
						|
(defun magit-save-repository-buffers (&optional arg)
 | 
						|
  "Save file-visiting buffers belonging to the current repository.
 | 
						|
After any buffer where `buffer-save-without-query' is non-nil
 | 
						|
is saved without asking, the user is asked about each modified
 | 
						|
buffer which visits a file in the current repository.  Optional
 | 
						|
argument (the prefix) non-nil means save all with no questions."
 | 
						|
  (interactive "P")
 | 
						|
  (-when-let (topdir (magit-rev-parse-safe "--show-toplevel"))
 | 
						|
    (save-some-buffers
 | 
						|
     arg (-partial (lambda (topdir)
 | 
						|
                     (and buffer-file-name
 | 
						|
                          ;; Avoid needlessly connecting to unrelated remotes.
 | 
						|
                          (string-prefix-p topdir buffer-file-name)
 | 
						|
                          (equal (magit-rev-parse-safe "--show-toplevel")
 | 
						|
                                 topdir)))
 | 
						|
                   topdir))))
 | 
						|
 | 
						|
;;; Restore Window Configuration
 | 
						|
 | 
						|
(defvar magit-inhibit-save-previous-winconf nil)
 | 
						|
 | 
						|
(defvar-local magit-previous-window-configuration nil)
 | 
						|
(put 'magit-previous-window-configuration 'permanent-local t)
 | 
						|
 | 
						|
(defun magit-save-window-configuration ()
 | 
						|
  "Save the current window configuration.
 | 
						|
 | 
						|
Later, when the buffer is buried, it may be restored by
 | 
						|
`magit-restore-window-configuration'."
 | 
						|
  (if magit-inhibit-save-previous-winconf
 | 
						|
      (when (eq magit-inhibit-save-previous-winconf 'unset)
 | 
						|
        (setq magit-previous-window-configuration nil))
 | 
						|
    (unless (get-buffer-window (current-buffer) (selected-frame))
 | 
						|
      (setq magit-previous-window-configuration
 | 
						|
            (current-window-configuration)))))
 | 
						|
 | 
						|
(defun magit-restore-window-configuration (&optional kill-buffer)
 | 
						|
  "Bury or kill the current buffer and restore previous window configuration."
 | 
						|
  (let ((winconf magit-previous-window-configuration)
 | 
						|
        (buffer (current-buffer))
 | 
						|
        (frame (selected-frame)))
 | 
						|
    (quit-window kill-buffer (selected-window))
 | 
						|
    (when (and winconf (equal frame (window-configuration-frame winconf)))
 | 
						|
      (set-window-configuration winconf)
 | 
						|
      (when (buffer-live-p buffer)
 | 
						|
        (with-current-buffer buffer
 | 
						|
          (setq magit-previous-window-configuration nil))))))
 | 
						|
 | 
						|
;;; Buffer History
 | 
						|
 | 
						|
(defun magit-go-backward ()
 | 
						|
  "Move backward in current buffer's history."
 | 
						|
  (interactive)
 | 
						|
  (if help-xref-stack
 | 
						|
      (help-xref-go-back (current-buffer))
 | 
						|
    (user-error "No previous entry in buffer's history")))
 | 
						|
 | 
						|
(defun magit-go-forward ()
 | 
						|
  "Move forward in current buffer's history."
 | 
						|
  (interactive)
 | 
						|
  (if help-xref-forward-stack
 | 
						|
      (help-xref-go-forward (current-buffer))
 | 
						|
    (user-error "No next entry in buffer's history")))
 | 
						|
 | 
						|
(defun magit-insert-xref-buttons (&optional _)
 | 
						|
  "Insert xref buttons."
 | 
						|
  (when (or help-xref-stack help-xref-forward-stack)
 | 
						|
    (when help-xref-stack
 | 
						|
      (magit-xref-insert-button help-back-label 'magit-xref-backward))
 | 
						|
    (when help-xref-forward-stack
 | 
						|
      (when help-xref-stack
 | 
						|
        (insert " "))
 | 
						|
      (magit-xref-insert-button help-forward-label 'magit-xref-forward))))
 | 
						|
 | 
						|
(defun magit-xref-insert-button (label type)
 | 
						|
  (magit-insert-section (button label)
 | 
						|
    (insert-text-button label 'type type
 | 
						|
                        'help-args (list (current-buffer)))))
 | 
						|
 | 
						|
(define-button-type 'magit-xref-backward
 | 
						|
  :supertype 'help-back
 | 
						|
  'mouse-face 'magit-section-highlight
 | 
						|
  'help-echo (purecopy "mouse-2, RET: go back to previous history entry"))
 | 
						|
 | 
						|
(define-button-type 'magit-xref-forward
 | 
						|
  :supertype 'help-forward
 | 
						|
  'mouse-face 'magit-section-highlight
 | 
						|
  'help-echo (purecopy "mouse-2, RET: go back to next history entry"))
 | 
						|
 | 
						|
(defun magit-xref-setup ()
 | 
						|
  "Insert backward/forward buttons if the major-mode supports it.
 | 
						|
Currently `magit-log-mode', `magit-reflog-mode',
 | 
						|
`magit-diff-mode', and `magit-revision-mode' support it"
 | 
						|
  (when (memq major-mode '(magit-log-mode
 | 
						|
                           magit-reflog-mode
 | 
						|
                           magit-diff-mode
 | 
						|
                           magit-revision-mode))
 | 
						|
    (when help-xref-stack-item
 | 
						|
      (push (cons (point) help-xref-stack-item) help-xref-stack)
 | 
						|
      (setq help-xref-forward-stack nil))
 | 
						|
    (when (called-interactively-p 'interactive)
 | 
						|
      (--when-let (nthcdr 10 help-xref-stack)
 | 
						|
        (setcdr it nil)))
 | 
						|
    (setq help-xref-stack-item
 | 
						|
          `(magit-xref-restore ,default-directory ,@magit-refresh-args))))
 | 
						|
 | 
						|
(defun magit-xref-restore (&rest args)
 | 
						|
  (magit-xref-setup)
 | 
						|
  (setq default-directory  (car args))
 | 
						|
  (setq magit-refresh-args (cdr args))
 | 
						|
  (magit-refresh-buffer))
 | 
						|
 | 
						|
;;; Utilities
 | 
						|
 | 
						|
(defun magit-run-hook-with-benchmark (hook)
 | 
						|
  (when hook
 | 
						|
    (if magit-refresh-verbose
 | 
						|
        (let ((start (current-time)))
 | 
						|
          (message "Running %s..." hook)
 | 
						|
          (run-hooks hook)
 | 
						|
          (message "Running %s...done (%.3fs)" hook
 | 
						|
                   (float-time (time-subtract (current-time) start))))
 | 
						|
      (run-hooks hook))))
 | 
						|
 | 
						|
;;; magit-mode.el ends soon
 | 
						|
(provide 'magit-mode)
 | 
						|
;; Local Variables:
 | 
						|
;; indent-tabs-mode: nil
 | 
						|
;; End:
 | 
						|
;;; magit-mode.el ends here
 |