From a3caedf27d62df011796170c04edbed56af45511 Mon Sep 17 00:00:00 2001 From: Gergely Polonkai Date: Mon, 4 May 2015 11:52:24 +0200 Subject: [PATCH] Upgrade packages --- elpa/buffer-move-0.4/buffer-move-autoloads.el | 18 - elpa/buffer-move-0.4/buffer-move-pkg.el | 1 - elpa/buffer-move-0.4/buffer-move.el | 135 - .../buffer-move-autoloads.el | 45 + elpa/buffer-move-0.6.1/buffer-move-pkg.el | 1 + elpa/buffer-move-0.6.1/buffer-move.el | 152 + elpa/company-0.8.12.signed | 1 + .../.dir-locals.el | 0 elpa/company-0.8.12/.elpaignore | 5 + .../ChangeLog | 43 + .../{company-0.8.5 => company-0.8.12}/NEWS.md | 40 +- .../README.md | 0 .../company-abbrev.el | 0 .../company-autoloads.el | 89 +- .../company-bbdb.el | 28 +- .../company-capf.el | 9 +- .../company-clang.el | 17 +- elpa/company-0.8.12/company-cmake.el | 198 + .../company-css.el | 0 .../company-dabbrev-code.el | 8 +- .../company-dabbrev.el | 15 +- .../company-eclim.el | 0 .../company-elisp.el | 0 .../company-etags.el | 2 +- .../company-files.el | 52 +- .../company-gtags.el | 1 + .../company-ispell.el | 13 +- .../company-keywords.el | 0 .../company-nxml.el | 0 .../company-oddmuse.el | 0 elpa/company-0.8.12/company-pkg.el | 2 + .../company-pysmell.el | 0 .../company-ropemacs.el | 0 .../company-semantic.el | 10 + .../company-template.el | 57 +- .../company-tempo.el | 0 .../company-xcode.el | 4 +- .../company-yasnippet.el | 12 +- .../company.el | 587 +- elpa/company-0.8.12/test/all.el | 28 + elpa/company-0.8.12/test/async-tests.el | 217 + elpa/company-0.8.12/test/clang-tests.el | 46 + elpa/company-0.8.12/test/core-tests.el | 481 + .../test/elisp-tests.el} | 9 +- elpa/company-0.8.12/test/frontends-tests.el | 332 + elpa/company-0.8.12/test/keywords-tests.el | 32 + elpa/company-0.8.12/test/template-tests.el | 91 + .../company-0.8.12/test/transformers-tests.el | 58 + elpa/company-0.8.5/.travis.yml | 23 - elpa/company-0.8.5/Makefile | 31 - elpa/company-0.8.5/company-cmake.el | 129 - elpa/company-0.8.5/company-pkg.el | 2 - elpa/company-0.8.5/company-tests.el | 911 -- .../git-commit-mode-autoloads.el | 30 - .../git-commit-mode-pkg.el | 1 - elpa/git-commit-mode-0.13/git-commit-mode.el | 601 -- .../git-commit-mode-autoloads.el | 35 + .../git-commit-mode-pkg.el | 1 + elpa/git-commit-mode-1.0.0/git-commit-mode.el | 668 ++ .../git-rebase-mode-autoloads.el | 29 + .../git-rebase-mode-pkg.el | 1 + elpa/git-rebase-mode-1.0.0/git-rebase-mode.el | 393 + elpa/gitignore-mode-0.1/gitignore-mode-pkg.el | 1 - elpa/gitignore-mode-0.1/gitignore-mode.el | 60 - .../gitignore-mode-autoloads.el | 8 +- .../gitignore-mode-pkg.el | 1 + elpa/gitignore-mode-1.1.0/gitignore-mode.el | 61 + elpa/haml-mode-3.1.5/haml-mode-pkg.el | 1 - .../haml-mode-autoloads.el | 13 +- elpa/haml-mode-3.1.8/haml-mode-pkg.el | 1 + .../haml-mode.el | 5 +- elpa/magit-1.2.1/magit-autoloads.el | 164 - elpa/magit-1.2.1/magit-bisect.el | 195 - elpa/magit-1.2.1/magit-key-mode.el | 521 -- elpa/magit-1.2.1/magit-pkg.el | 1 - elpa/magit-1.2.1/magit-stgit.el | 288 - elpa/magit-1.2.1/magit-svn.el | 240 - elpa/magit-1.2.1/magit-topgit.el | 191 - elpa/magit-1.2.1/magit-wip.el | 153 - elpa/magit-1.2.1/magit.el | 5989 ------------- elpa/magit-1.2.1/magit.info | 1362 --- elpa/magit-1.2.1/rebase-mode.el | 322 - elpa/magit-1.4.1/AUTHORS.md | 184 + elpa/{magit-1.2.1 => magit-1.4.1}/dir | 2 +- elpa/magit-1.4.1/magit-autoloads.el | 579 ++ .../magit-blame.el | 172 +- elpa/magit-1.4.1/magit-key-mode.el | 735 ++ elpa/magit-1.4.1/magit-pkg.el | 5 + elpa/magit-1.4.1/magit-wip.el | 143 + elpa/magit-1.4.1/magit.el | 7838 +++++++++++++++++ elpa/magit-1.4.1/magit.info | 1596 ++++ 91 files changed, 14707 insertions(+), 11818 deletions(-) delete mode 100644 elpa/buffer-move-0.4/buffer-move-autoloads.el delete mode 100644 elpa/buffer-move-0.4/buffer-move-pkg.el delete mode 100644 elpa/buffer-move-0.4/buffer-move.el create mode 100644 elpa/buffer-move-0.6.1/buffer-move-autoloads.el create mode 100644 elpa/buffer-move-0.6.1/buffer-move-pkg.el create mode 100644 elpa/buffer-move-0.6.1/buffer-move.el create mode 100644 elpa/company-0.8.12.signed rename elpa/{company-0.8.5 => company-0.8.12}/.dir-locals.el (100%) create mode 100644 elpa/company-0.8.12/.elpaignore rename elpa/{company-0.8.5 => company-0.8.12}/ChangeLog (86%) rename elpa/{company-0.8.5 => company-0.8.12}/NEWS.md (87%) rename elpa/{company-0.8.5 => company-0.8.12}/README.md (100%) rename elpa/{company-0.8.5 => company-0.8.12}/company-abbrev.el (100%) rename elpa/{company-0.8.5 => company-0.8.12}/company-autoloads.el (73%) rename elpa/{company-0.8.5 => company-0.8.12}/company-bbdb.el (64%) rename elpa/{company-0.8.5 => company-0.8.12}/company-capf.el (95%) rename elpa/{company-0.8.5 => company-0.8.12}/company-clang.el (95%) create mode 100644 elpa/company-0.8.12/company-cmake.el rename elpa/{company-0.8.5 => company-0.8.12}/company-css.el (100%) rename elpa/{company-0.8.5 => company-0.8.12}/company-dabbrev-code.el (93%) rename elpa/{company-0.8.5 => company-0.8.12}/company-dabbrev.el (92%) rename elpa/{company-0.8.5 => company-0.8.12}/company-eclim.el (100%) rename elpa/{company-0.8.5 => company-0.8.12}/company-elisp.el (100%) rename elpa/{company-0.8.5 => company-0.8.12}/company-etags.el (98%) rename elpa/{company-0.8.5 => company-0.8.12}/company-files.el (60%) rename elpa/{company-0.8.5 => company-0.8.12}/company-gtags.el (99%) rename elpa/{company-0.8.5 => company-0.8.12}/company-ispell.el (82%) rename elpa/{company-0.8.5 => company-0.8.12}/company-keywords.el (100%) rename elpa/{company-0.8.5 => company-0.8.12}/company-nxml.el (100%) rename elpa/{company-0.8.5 => company-0.8.12}/company-oddmuse.el (100%) create mode 100644 elpa/company-0.8.12/company-pkg.el rename elpa/{company-0.8.5 => company-0.8.12}/company-pysmell.el (100%) rename elpa/{company-0.8.5 => company-0.8.12}/company-ropemacs.el (100%) rename elpa/{company-0.8.5 => company-0.8.12}/company-semantic.el (92%) rename elpa/{company-0.8.5 => company-0.8.12}/company-template.el (77%) rename elpa/{company-0.8.5 => company-0.8.12}/company-tempo.el (100%) rename elpa/{company-0.8.5 => company-0.8.12}/company-xcode.el (97%) rename elpa/{company-0.8.5 => company-0.8.12}/company-yasnippet.el (90%) rename elpa/{company-0.8.5 => company-0.8.12}/company.el (86%) create mode 100644 elpa/company-0.8.12/test/all.el create mode 100644 elpa/company-0.8.12/test/async-tests.el create mode 100644 elpa/company-0.8.12/test/clang-tests.el create mode 100644 elpa/company-0.8.12/test/core-tests.el rename elpa/{company-0.8.5/company-elisp-tests.el => company-0.8.12/test/elisp-tests.el} (97%) create mode 100644 elpa/company-0.8.12/test/frontends-tests.el create mode 100644 elpa/company-0.8.12/test/keywords-tests.el create mode 100644 elpa/company-0.8.12/test/template-tests.el create mode 100644 elpa/company-0.8.12/test/transformers-tests.el delete mode 100644 elpa/company-0.8.5/.travis.yml delete mode 100644 elpa/company-0.8.5/Makefile delete mode 100644 elpa/company-0.8.5/company-cmake.el delete mode 100644 elpa/company-0.8.5/company-pkg.el delete mode 100644 elpa/company-0.8.5/company-tests.el delete mode 100644 elpa/git-commit-mode-0.13/git-commit-mode-autoloads.el delete mode 100644 elpa/git-commit-mode-0.13/git-commit-mode-pkg.el delete mode 100644 elpa/git-commit-mode-0.13/git-commit-mode.el create mode 100644 elpa/git-commit-mode-1.0.0/git-commit-mode-autoloads.el create mode 100644 elpa/git-commit-mode-1.0.0/git-commit-mode-pkg.el create mode 100644 elpa/git-commit-mode-1.0.0/git-commit-mode.el create mode 100644 elpa/git-rebase-mode-1.0.0/git-rebase-mode-autoloads.el create mode 100644 elpa/git-rebase-mode-1.0.0/git-rebase-mode-pkg.el create mode 100644 elpa/git-rebase-mode-1.0.0/git-rebase-mode.el delete mode 100644 elpa/gitignore-mode-0.1/gitignore-mode-pkg.el delete mode 100644 elpa/gitignore-mode-0.1/gitignore-mode.el rename elpa/{gitignore-mode-0.1 => gitignore-mode-1.1.0}/gitignore-mode-autoloads.el (59%) create mode 100644 elpa/gitignore-mode-1.1.0/gitignore-mode-pkg.el create mode 100644 elpa/gitignore-mode-1.1.0/gitignore-mode.el delete mode 100644 elpa/haml-mode-3.1.5/haml-mode-pkg.el rename elpa/{haml-mode-3.1.5 => haml-mode-3.1.8}/haml-mode-autoloads.el (64%) create mode 100644 elpa/haml-mode-3.1.8/haml-mode-pkg.el rename elpa/{haml-mode-3.1.5 => haml-mode-3.1.8}/haml-mode.el (99%) delete mode 100644 elpa/magit-1.2.1/magit-autoloads.el delete mode 100644 elpa/magit-1.2.1/magit-bisect.el delete mode 100644 elpa/magit-1.2.1/magit-key-mode.el delete mode 100644 elpa/magit-1.2.1/magit-pkg.el delete mode 100644 elpa/magit-1.2.1/magit-stgit.el delete mode 100644 elpa/magit-1.2.1/magit-svn.el delete mode 100644 elpa/magit-1.2.1/magit-topgit.el delete mode 100644 elpa/magit-1.2.1/magit-wip.el delete mode 100644 elpa/magit-1.2.1/magit.el delete mode 100644 elpa/magit-1.2.1/magit.info delete mode 100644 elpa/magit-1.2.1/rebase-mode.el create mode 100644 elpa/magit-1.4.1/AUTHORS.md rename elpa/{magit-1.2.1 => magit-1.4.1}/dir (88%) create mode 100644 elpa/magit-1.4.1/magit-autoloads.el rename elpa/{magit-1.2.1 => magit-1.4.1}/magit-blame.el (70%) create mode 100644 elpa/magit-1.4.1/magit-key-mode.el create mode 100644 elpa/magit-1.4.1/magit-pkg.el create mode 100644 elpa/magit-1.4.1/magit-wip.el create mode 100644 elpa/magit-1.4.1/magit.el create mode 100644 elpa/magit-1.4.1/magit.info diff --git a/elpa/buffer-move-0.4/buffer-move-autoloads.el b/elpa/buffer-move-0.4/buffer-move-autoloads.el deleted file mode 100644 index a12d61c..0000000 --- a/elpa/buffer-move-0.4/buffer-move-autoloads.el +++ /dev/null @@ -1,18 +0,0 @@ -;;; buffer-move-autoloads.el --- automatically extracted autoloads -;; -;;; Code: - - -;;;### (autoloads nil nil ("buffer-move-pkg.el" "buffer-move.el") -;;;;;; (21553 16645 222241 807000)) - -;;;*** - -(provide 'buffer-move-autoloads) -;; Local Variables: -;; version-control: never -;; no-byte-compile: t -;; no-update-autoloads: t -;; coding: utf-8 -;; End: -;;; buffer-move-autoloads.el ends here diff --git a/elpa/buffer-move-0.4/buffer-move-pkg.el b/elpa/buffer-move-0.4/buffer-move-pkg.el deleted file mode 100644 index ebda4a8..0000000 --- a/elpa/buffer-move-0.4/buffer-move-pkg.el +++ /dev/null @@ -1 +0,0 @@ -(define-package "buffer-move" "0.4" "swap buffers between windows" (quote nil)) diff --git a/elpa/buffer-move-0.4/buffer-move.el b/elpa/buffer-move-0.4/buffer-move.el deleted file mode 100644 index f877368..0000000 --- a/elpa/buffer-move-0.4/buffer-move.el +++ /dev/null @@ -1,135 +0,0 @@ -;;; buffer-move.el --- swap buffers between windows - -;; Copyright (C) 2004 Lucas Bonnet - -;; Author: Lucas Bonnet -;; Keywords: lisp,convenience -;; Version: 0.4 -;; URL: http://www.emacswiki.org/cgi-bin/wiki/buffer-move.el - -;; This program 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 2 -;; of the License, or (at your option) any later version. - -;; This program 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 this program; if not, write to the Free Software -;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -;; 02111-1307, USA. - -;;; Commentary: - -;; This file is for lazy people wanting to swap buffers without -;; typing C-x b on each window. This is useful when you have : - -;; +--------------+-------------+ -;; | | | -;; | #emacs | #gnus | -;; | | | -;; +--------------+-------------+ -;; | | -;; | .emacs | -;; | | -;; +----------------------------+ - -;; and you want to have : - -;; +--------------+-------------+ -;; | | | -;; | #gnus | .emacs | -;; | | | -;; +--------------+-------------+ -;; | | -;; | #emacs | -;; | | -;; +----------------------------+ - -;; With buffer-move, just go in #gnus, do buf-move-left, go to #emacs -;; (which now should be on top right) and do buf-move-down. - -;; To use it, simply put a (require 'buffer-move) in your ~/.emacs and -;; define some keybindings. For example, i use : - -;; (global-set-key (kbd "") 'buf-move-up) -;; (global-set-key (kbd "") 'buf-move-down) -;; (global-set-key (kbd "") 'buf-move-left) -;; (global-set-key (kbd "") 'buf-move-right) - - -;;; Code: - - -(require 'windmove) - -(defun buf-move-up () - "Swap the current buffer and the buffer above the split. -If there is no split, ie now window above the current one, an -error is signaled." -;; "Switches between the current buffer, and the buffer above the -;; split, if possible." - (interactive) - (let* ((other-win (windmove-find-other-window 'up)) - (buf-this-buf (window-buffer (selected-window)))) - (if (null other-win) - (error "No window above this one") - ;; swap top with this one - (set-window-buffer (selected-window) (window-buffer other-win)) - ;; move this one to top - (set-window-buffer other-win buf-this-buf) - (select-window other-win)))) - -(defun buf-move-down () -"Swap the current buffer and the buffer under the split. -If there is no split, ie now window under the current one, an -error is signaled." - (interactive) - (let* ((other-win (windmove-find-other-window 'down)) - (buf-this-buf (window-buffer (selected-window)))) - (if (or (null other-win) - (string-match "^ \\*Minibuf" (buffer-name (window-buffer other-win)))) - (error "No window under this one") - ;; swap top with this one - (set-window-buffer (selected-window) (window-buffer other-win)) - ;; move this one to top - (set-window-buffer other-win buf-this-buf) - (select-window other-win)))) - -(defun buf-move-left () -"Swap the current buffer and the buffer on the left of the split. -If there is no split, ie now window on the left of the current -one, an error is signaled." - (interactive) - (let* ((other-win (windmove-find-other-window 'left)) - (buf-this-buf (window-buffer (selected-window)))) - (if (null other-win) - (error "No left split") - ;; swap top with this one - (set-window-buffer (selected-window) (window-buffer other-win)) - ;; move this one to top - (set-window-buffer other-win buf-this-buf) - (select-window other-win)))) - -(defun buf-move-right () -"Swap the current buffer and the buffer on the right of the split. -If there is no split, ie now window on the right of the current -one, an error is signaled." - (interactive) - (let* ((other-win (windmove-find-other-window 'right)) - (buf-this-buf (window-buffer (selected-window)))) - (if (null other-win) - (error "No right split") - ;; swap top with this one - (set-window-buffer (selected-window) (window-buffer other-win)) - ;; move this one to top - (set-window-buffer other-win buf-this-buf) - (select-window other-win)))) - - -(provide 'buffer-move) - -;;; buffer-move.el ends here diff --git a/elpa/buffer-move-0.6.1/buffer-move-autoloads.el b/elpa/buffer-move-0.6.1/buffer-move-autoloads.el new file mode 100644 index 0000000..903bc03 --- /dev/null +++ b/elpa/buffer-move-0.6.1/buffer-move-autoloads.el @@ -0,0 +1,45 @@ +;;; buffer-move-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (or (file-name-directory #$) (car load-path))) + +;;;### (autoloads nil "buffer-move" "buffer-move.el" (21831 16639 +;;;;;; 808187 792000)) +;;; Generated autoloads from buffer-move.el + +(autoload 'buf-move-up "buffer-move" "\ +Swap the current buffer and the buffer above the split. + If there is no split, ie now window above the current one, an + error is signaled. + +\(fn)" t nil) + +(autoload 'buf-move-down "buffer-move" "\ +Swap the current buffer and the buffer under the split. + If there is no split, ie now window under the current one, an + error is signaled. + +\(fn)" t nil) + +(autoload 'buf-move-left "buffer-move" "\ +Swap the current buffer and the buffer on the left of the split. + If there is no split, ie now window on the left of the current + one, an error is signaled. + +\(fn)" t nil) + +(autoload 'buf-move-right "buffer-move" "\ +Swap the current buffer and the buffer on the right of the split. + If there is no split, ie now window on the right of the current + one, an error is signaled. + +\(fn)" t nil) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; buffer-move-autoloads.el ends here diff --git a/elpa/buffer-move-0.6.1/buffer-move-pkg.el b/elpa/buffer-move-0.6.1/buffer-move-pkg.el new file mode 100644 index 0000000..c8001f0 --- /dev/null +++ b/elpa/buffer-move-0.6.1/buffer-move-pkg.el @@ -0,0 +1 @@ +(define-package "buffer-move" "0.6.1" "" 'nil) diff --git a/elpa/buffer-move-0.6.1/buffer-move.el b/elpa/buffer-move-0.6.1/buffer-move.el new file mode 100644 index 0000000..a420b20 --- /dev/null +++ b/elpa/buffer-move-0.6.1/buffer-move.el @@ -0,0 +1,152 @@ +;;; buffer-move.el --- + +;; Copyright (C) 2004-2014 Lucas Bonnet +;; Copyright (C) 2014 Mathis Hofer +;; Copyright (C) 2014 Geyslan G. Bem + +;; Authors: Lucas Bonnet +;; Geyslan G. Bem +;; Mathis Hofer +;; Keywords: lisp,convenience +;; Version: 0.6.1 +;; URL : https://github.com/lukhas/buffer-move + +;; This program 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 2 +;; of the License, or (at your option) any later version. + +;; This program 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 this program; if not, write to the Free Software +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +;; 02111-1307, USA. + +;;; Commentary: + +;; This file is for lazy people wanting to swap buffers without +;; typing C-x b on each window. This is useful when you have : + +;; +--------------+-------------+ +;; | | | +;; | #emacs | #gnus | +;; | | | +;; +--------------+-------------+ +;; | | +;; | .emacs | +;; | | +;; +----------------------------+ + +;; and you want to have : + +;; +--------------+-------------+ +;; | | | +;; | #gnus | .emacs | +;; | | | +;; +--------------+-------------+ +;; | | +;; | #emacs | +;; | | +;; +----------------------------+ + +;; With buffer-move, just go in #gnus, do buf-move-left, go to #emacs +;; (which now should be on top right) and do buf-move-down. + +;; To use it, simply put a (require 'buffer-move) in your ~/.emacs and +;; define some keybindings. For example, i use : + +;; (global-set-key (kbd "") 'buf-move-up) +;; (global-set-key (kbd "") 'buf-move-down) +;; (global-set-key (kbd "") 'buf-move-left) +;; (global-set-key (kbd "") 'buf-move-right) + +;; Alternatively, you may let the current window switch back to the previous +;; buffer, instead of swapping the buffers of both windows. Set the +;; following customization variable to 'move to activate this behavior: + +;; (setq buffer-move-behavior 'move) + + +;;; Code: + + +(require 'windmove) + + +(defconst buffer-move-version "0.6.1" + "Version of buffer-move.el") + +(defgroup buffer-move nil + "Swap buffers without typing C-x b on each window" + :group 'tools) + +(defcustom buffer-move-behavior 'swap + "If set to 'swap (default), the buffers will be exchanged + (i.e. swapped), if set to 'move, the current window is switch back to the + previously displayed buffer (i.e. the buffer is moved)." + :group 'buffer-move + :type 'symbol) + + +(defun buf-move-to (direction) + "Helper function to move the current buffer to the window in the given + direction (with must be 'up, 'down', 'left or 'right). An error is + thrown, if no window exists in this direction." + (let* ((other-win (windmove-find-other-window direction)) + (buf-this-buf (window-buffer (selected-window)))) + (if (null other-win) + (error "No window in this direction") + (if (eq buffer-move-behavior 'move) + ;; switch selected window to previous buffer (moving) + (switch-to-prev-buffer (selected-window)) + + ;; switch selected window to buffer of other window (swapping) + (set-window-buffer (selected-window) (window-buffer other-win)) + ) + + ;; switch other window to this buffer + (set-window-buffer other-win buf-this-buf) + + (select-window other-win)))) + +;;;###autoload +(defun buf-move-up () + "Swap the current buffer and the buffer above the split. + If there is no split, ie now window above the current one, an + error is signaled." + ;; "Switches between the current buffer, and the buffer above the + ;; split, if possible." + (interactive) + (buf-move-to 'up)) + +;;;###autoload +(defun buf-move-down () + "Swap the current buffer and the buffer under the split. + If there is no split, ie now window under the current one, an + error is signaled." + (interactive) + (buf-move-to 'down)) + +;;;###autoload +(defun buf-move-left () + "Swap the current buffer and the buffer on the left of the split. + If there is no split, ie now window on the left of the current + one, an error is signaled." + (interactive) + (buf-move-to 'left)) + +;;;###autoload +(defun buf-move-right () + "Swap the current buffer and the buffer on the right of the split. + If there is no split, ie now window on the right of the current + one, an error is signaled." + (interactive) + (buf-move-to 'right)) + + +(provide 'buffer-move) +;;; buffer-move.el ends here diff --git a/elpa/company-0.8.12.signed b/elpa/company-0.8.12.signed new file mode 100644 index 0000000..38c24e4 --- /dev/null +++ b/elpa/company-0.8.12.signed @@ -0,0 +1 @@ +Good signature from 474F05837FBDEF9B GNU ELPA Signing Agent (trust undefined) created at 2015-03-05T11:05:01+0100 using DSA \ No newline at end of file diff --git a/elpa/company-0.8.5/.dir-locals.el b/elpa/company-0.8.12/.dir-locals.el similarity index 100% rename from elpa/company-0.8.5/.dir-locals.el rename to elpa/company-0.8.12/.dir-locals.el diff --git a/elpa/company-0.8.12/.elpaignore b/elpa/company-0.8.12/.elpaignore new file mode 100644 index 0000000..9f31d8a --- /dev/null +++ b/elpa/company-0.8.12/.elpaignore @@ -0,0 +1,5 @@ +.travis.yml +.gitignore +Makefile +test/ +company-tests.el diff --git a/elpa/company-0.8.5/ChangeLog b/elpa/company-0.8.12/ChangeLog similarity index 86% rename from elpa/company-0.8.5/ChangeLog rename to elpa/company-0.8.12/ChangeLog index 3c3a03c..7ea2c2a 100644 --- a/elpa/company-0.8.5/ChangeLog +++ b/elpa/company-0.8.12/ChangeLog @@ -1,3 +1,46 @@ +2015-03-04 Dmitry Gutov + + Merge commit 'e085a333867959a1b36015a3ad8e12e5bd6550d9' from company + +2015-02-04 Dmitry Gutov + + Merge commit '3e70e12bd942bbd0acac4963b5caca63756ad784' from company + +2015-02-02 Dmitry Gutov + + Merge commit 'a015fb350abe50d250e3e7a9c3c762397326977f' from company + +2015-01-23 Dmitry Gutov + + Merge commit 'a4ac0dead8e9cb440c1f8aec9141d6c64bad4933' from company + +2015-01-15 Stefan Monnier + + * packages/company/test/clang-tests.el: Add copyright notice + +2015-01-13 Dmitry Gutov + + Merge commit 'd12ddaa05f582ecc00e74bc42fd46652153ec7a6' from company + +2015-01-13 Dmitry Gutov + + Merge commit 'eb0d8d9e687e1364098f9abc6f9281fcbc0d3abd' from company + +2014-10-28 Dmitry Gutov + + Merge commit 'd3fcbefcf56d2caad172e22f24de95397c635bf2' from company + +2014-10-15 Stefan Monnier + + * packages/company/company-xcode.el (company-xcode-fetch): Avoid + add-to-list on local var. + * packages/company/company.el (company--window-height) + (company--window-width): Move before first use. + +2014-10-15 Dmitry Gutov + + Merge commit '60d4c09c982a1c562a70cd6aa705f47ab3badcfb' from company + 2014-09-14 Dmitry Gutov Merge commit 'fa4ba155a3e22ddc4b8bc33fcbf8cc69ef8f0043' from company diff --git a/elpa/company-0.8.5/NEWS.md b/elpa/company-0.8.12/NEWS.md similarity index 87% rename from elpa/company-0.8.5/NEWS.md rename to elpa/company-0.8.12/NEWS.md index 47814ff..c7a1afe 100644 --- a/elpa/company-0.8.5/NEWS.md +++ b/elpa/company-0.8.12/NEWS.md @@ -1,11 +1,49 @@ # History of user-visible changes +## 2015-02-02 (0.8.10) + +* New variable `company-lighter-base`. +* Better tracking of the current selection. +* Pressing `M-0`...`M-9` works in the search mode. +* Pressing `` or `` doesn't quit the search mode. + +## 2015-01-23 (0.8.9) + +* New commands `company-next-page` and `company-previous-page`, remapping + `scroll-up-command` and `scroll-down-command` during completion. + +## 2015-01-13 (0.8.8) + +* Pressing `M-n` or `M-p` doesn't quit the search mode. +* New command `company-complete-common-or-cycle`. No default binding. +* `company-search-toggle-filtering` replaced `company-search-kill-others`. +* Quitting the search mode resets the filtering. +* Pressing `backspace` in the search mode deletes the character at the end of + the search string. +* `company-semantic` displays function arguments as annotations. +* New user option, `company-bbdb-modes`. +* `company-show-numbers` and `company-complete-number` now use visual numbering + of the candidates, taking into account only the ones currently displayed. +* `company-complete-number` can be bound to keypad numbers directly, with or + without modifiers. +* `company-cmake` expands `` and `` placeholders inside variable + names. + +## 2014-10-15 (0.8.6) + +* `company-clang` and `company-template-c-like-templatify` support templated + functions and arguments. +* `company-dabbrev` ignores "uninteresting" buffers by default. Depends on the + new user option, `company-dabbrev-ignore-buffers`. +* `company-files` checks directory's last modification time. +* `company-files` supports relative paths and Windows drive letters. + ## 2014-08-13 (0.8.4) * `company-ropemacs` is only used when `ropemacs-mode` is on. * `company-gtags` is enabled in all `prog-mode` derivatives by default. * `company-end-of-buffer-workaround` is not used anymore. -* `company-begin-commands` includes several `cc-mode` commands. +* `company-begin-commands` includes some of `cc-mode` commands. ## 2014-08-27 (0.8.3) diff --git a/elpa/company-0.8.5/README.md b/elpa/company-0.8.12/README.md similarity index 100% rename from elpa/company-0.8.5/README.md rename to elpa/company-0.8.12/README.md diff --git a/elpa/company-0.8.5/company-abbrev.el b/elpa/company-0.8.12/company-abbrev.el similarity index 100% rename from elpa/company-0.8.5/company-abbrev.el rename to elpa/company-0.8.12/company-abbrev.el diff --git a/elpa/company-0.8.5/company-autoloads.el b/elpa/company-0.8.12/company-autoloads.el similarity index 73% rename from elpa/company-0.8.5/company-autoloads.el rename to elpa/company-0.8.12/company-autoloads.el index 5a38f30..4f657b9 100644 --- a/elpa/company-0.8.5/company-autoloads.el +++ b/elpa/company-0.8.12/company-autoloads.el @@ -1,10 +1,10 @@ ;;; company-autoloads.el --- automatically extracted autoloads ;; ;;; Code: - +(add-to-list 'load-path (or (file-name-directory #$) (car load-path))) -;;;### (autoloads (global-company-mode company-mode) "company" "company.el" -;;;;;; (21553 22041 719690 945000)) +;;;### (autoloads nil "company" "company.el" (21831 16638 858187 +;;;;;; 859000)) ;;; Generated autoloads from company.el (autoload 'company-mode "company" "\ @@ -57,8 +57,8 @@ See `company-mode' for more information on Company mode. ;;;*** -;;;### (autoloads (company-abbrev) "company-abbrev" "company-abbrev.el" -;;;;;; (21553 22041 262700 327000)) +;;;### (autoloads nil "company-abbrev" "company-abbrev.el" (21831 +;;;;;; 16638 696187 870000)) ;;; Generated autoloads from company-abbrev.el (autoload 'company-abbrev "company-abbrev" "\ @@ -68,19 +68,19 @@ See `company-mode' for more information on Company mode. ;;;*** -;;;### (autoloads (company-bbdb) "company-bbdb" "company-bbdb.el" -;;;;;; (21553 22041 760690 102000)) +;;;### (autoloads nil "company-bbdb" "company-bbdb.el" (21831 16638 +;;;;;; 863187 858000)) ;;; Generated autoloads from company-bbdb.el (autoload 'company-bbdb "company-bbdb" "\ -`company-mode' completion back-end for `bbdb'. +`company-mode' completion back-end for BBDB. \(fn COMMAND &optional ARG &rest IGNORE)" t nil) ;;;*** -;;;### (autoloads (company-css) "company-css" "company-css.el" (21553 -;;;;;; 22041 295699 650000)) +;;;### (autoloads nil "company-css" "company-css.el" (21831 16638 +;;;;;; 709187 869000)) ;;; Generated autoloads from company-css.el (autoload 'company-css "company-css" "\ @@ -90,8 +90,8 @@ See `company-mode' for more information on Company mode. ;;;*** -;;;### (autoloads (company-dabbrev) "company-dabbrev" "company-dabbrev.el" -;;;;;; (21553 22041 336698 811000)) +;;;### (autoloads nil "company-dabbrev" "company-dabbrev.el" (21831 +;;;;;; 16638 718187 869000)) ;;; Generated autoloads from company-dabbrev.el (autoload 'company-dabbrev "company-dabbrev" "\ @@ -101,8 +101,8 @@ dabbrev-like `company-mode' completion back-end. ;;;*** -;;;### (autoloads (company-dabbrev-code) "company-dabbrev-code" "company-dabbrev-code.el" -;;;;;; (21553 22041 992685 338000)) +;;;### (autoloads nil "company-dabbrev-code" "company-dabbrev-code.el" +;;;;;; (21831 16638 894187 856000)) ;;; Generated autoloads from company-dabbrev-code.el (autoload 'company-dabbrev-code "company-dabbrev-code" "\ @@ -114,8 +114,8 @@ comments or strings. ;;;*** -;;;### (autoloads (company-elisp) "company-elisp" "company-elisp.el" -;;;;;; (21553 22041 461696 242000)) +;;;### (autoloads nil "company-elisp" "company-elisp.el" (21831 16638 +;;;;;; 736187 867000)) ;;; Generated autoloads from company-elisp.el (autoload 'company-elisp "company-elisp" "\ @@ -125,8 +125,8 @@ comments or strings. ;;;*** -;;;### (autoloads (company-etags) "company-etags" "company-etags.el" -;;;;;; (21553 22041 55704 578000)) +;;;### (autoloads nil "company-etags" "company-etags.el" (21831 16638 +;;;;;; 649187 873000)) ;;; Generated autoloads from company-etags.el (autoload 'company-etags "company-etags" "\ @@ -136,19 +136,21 @@ comments or strings. ;;;*** -;;;### (autoloads (company-files) "company-files" "company-files.el" -;;;;;; (21553 22041 511695 221000)) +;;;### (autoloads nil "company-files" "company-files.el" (21831 16638 +;;;;;; 745187 867000)) ;;; Generated autoloads from company-files.el (autoload 'company-files "company-files" "\ `company-mode' completion back-end existing file names. +Completions works for proper absolute and relative files paths. +File paths with spaces are only supported inside strings. \(fn COMMAND &optional ARG &rest IGNORED)" t nil) ;;;*** -;;;### (autoloads (company-gtags) "company-gtags" "company-gtags.el" -;;;;;; (21553 22042 50684 150000)) +;;;### (autoloads nil "company-gtags" "company-gtags.el" (21831 16638 +;;;;;; 899187 856000)) ;;; Generated autoloads from company-gtags.el (autoload 'company-gtags "company-gtags" "\ @@ -158,8 +160,8 @@ comments or strings. ;;;*** -;;;### (autoloads (company-ispell) "company-ispell" "company-ispell.el" -;;;;;; (21553 22041 3705 646000)) +;;;### (autoloads nil "company-ispell" "company-ispell.el" (21831 +;;;;;; 16638 631187 875000)) ;;; Generated autoloads from company-ispell.el (autoload 'company-ispell "company-ispell" "\ @@ -169,8 +171,8 @@ comments or strings. ;;;*** -;;;### (autoloads (company-keywords) "company-keywords" "company-keywords.el" -;;;;;; (21553 22041 88703 901000)) +;;;### (autoloads nil "company-keywords" "company-keywords.el" (21831 +;;;;;; 16638 658187 873000)) ;;; Generated autoloads from company-keywords.el (autoload 'company-keywords "company-keywords" "\ @@ -180,8 +182,8 @@ comments or strings. ;;;*** -;;;### (autoloads (company-nxml) "company-nxml" "company-nxml.el" -;;;;;; (21553 22041 130703 38000)) +;;;### (autoloads nil "company-nxml" "company-nxml.el" (21831 16638 +;;;;;; 667187 872000)) ;;; Generated autoloads from company-nxml.el (autoload 'company-nxml "company-nxml" "\ @@ -191,8 +193,8 @@ comments or strings. ;;;*** -;;;### (autoloads (company-oddmuse) "company-oddmuse" "company-oddmuse.el" -;;;;;; (21553 22041 544694 537000)) +;;;### (autoloads nil "company-oddmuse" "company-oddmuse.el" (21831 +;;;;;; 16638 755187 866000)) ;;; Generated autoloads from company-oddmuse.el (autoload 'company-oddmuse "company-oddmuse" "\ @@ -202,8 +204,8 @@ comments or strings. ;;;*** -;;;### (autoloads (company-pysmell) "company-pysmell" "company-pysmell.el" -;;;;;; (21553 22041 652692 320000)) +;;;### (autoloads nil "company-pysmell" "company-pysmell.el" (21831 +;;;;;; 16638 848187 859000)) ;;; Generated autoloads from company-pysmell.el (autoload 'company-pysmell "company-pysmell" "\ @@ -214,8 +216,8 @@ This requires pysmell.el and pymacs.el. ;;;*** -;;;### (autoloads (company-semantic) "company-semantic" "company-semantic.el" -;;;;;; (21553 22042 308678 850000)) +;;;### (autoloads nil "company-semantic" "company-semantic.el" (21831 +;;;;;; 16638 936187 853000)) ;;; Generated autoloads from company-semantic.el (autoload 'company-semantic "company-semantic" "\ @@ -225,8 +227,8 @@ This requires pysmell.el and pymacs.el. ;;;*** -;;;### (autoloads (company-tempo) "company-tempo" "company-tempo.el" -;;;;;; (21553 22041 835688 555000)) +;;;### (autoloads nil "company-tempo" "company-tempo.el" (21831 16638 +;;;;;; 874187 858000)) ;;; Generated autoloads from company-tempo.el (autoload 'company-tempo "company-tempo" "\ @@ -236,8 +238,8 @@ This requires pysmell.el and pymacs.el. ;;;*** -;;;### (autoloads (company-xcode) "company-xcode" "company-xcode.el" -;;;;;; (21553 22041 901687 207000)) +;;;### (autoloads nil "company-xcode" "company-xcode.el" (21831 16638 +;;;;;; 885187 857000)) ;;; Generated autoloads from company-xcode.el (autoload 'company-xcode "company-xcode" "\ @@ -247,8 +249,8 @@ This requires pysmell.el and pymacs.el. ;;;*** -;;;### (autoloads (company-yasnippet) "company-yasnippet" "company-yasnippet.el" -;;;;;; (21553 22042 158681 930000)) +;;;### (autoloads nil "company-yasnippet" "company-yasnippet.el" +;;;;;; (21831 16638 920187 854000)) ;;; Generated autoloads from company-yasnippet.el (autoload 'company-yasnippet "company-yasnippet" "\ @@ -279,17 +281,14 @@ shadow back-ends that come after it. Recommended usages: ;;;*** ;;;### (autoloads nil nil ("company-capf.el" "company-clang.el" "company-cmake.el" -;;;;;; "company-eclim.el" "company-elisp-tests.el" "company-pkg.el" -;;;;;; "company-ropemacs.el" "company-template.el" "company-tests.el") -;;;;;; (21553 22042 393632 690000)) +;;;;;; "company-eclim.el" "company-pkg.el" "company-ropemacs.el" +;;;;;; "company-template.el") (21831 16638 948260 900000)) ;;;*** -(provide 'company-autoloads) ;; Local Variables: ;; version-control: never ;; no-byte-compile: t ;; no-update-autoloads: t -;; coding: utf-8 ;; End: ;;; company-autoloads.el ends here diff --git a/elpa/company-0.8.5/company-bbdb.el b/elpa/company-0.8.12/company-bbdb.el similarity index 64% rename from elpa/company-0.8.5/company-bbdb.el rename to elpa/company-0.8.12/company-bbdb.el index acdd30a..58be84c 100644 --- a/elpa/company-0.8.5/company-bbdb.el +++ b/elpa/company-0.8.12/company-bbdb.el @@ -27,21 +27,33 @@ (declare-function bbdb-dwim-mail "bbdb-com") (declare-function bbdb-search "bbdb-com") +(defgroup company-bbdb nil + "Completion back-end for BBDB." + :group 'company) + +(defcustom company-bbdb-modes '(message-mode) + "Major modes in which `company-bbdb' may complete." + :type '(repeat (symbol :tag "Major mode")) + :package-version '(company . "0.8.8")) + +(defun company-bbdb--candidates (arg) + (cl-mapcan (lambda (record) + (mapcar (lambda (mail) (bbdb-dwim-mail record mail)) + (bbdb-record-get-field record 'mail))) + (eval '(bbdb-search (bbdb-records) arg nil arg)))) + ;;;###autoload (defun company-bbdb (command &optional arg &rest ignore) - "`company-mode' completion back-end for `bbdb'." + "`company-mode' completion back-end for BBDB." (interactive (list 'interactive)) (cl-case command (interactive (company-begin-backend 'company-bbdb)) - (prefix (and (eq major-mode 'message-mode) + (prefix (and (memq major-mode company-bbdb-modes) (featurep 'bbdb-com) - (looking-back "^\\(To\\|Cc\\|Bcc\\):.*" + (looking-back "^\\(To\\|Cc\\|Bcc\\): *\\(.*\\)" (line-beginning-position)) - (company-grab-symbol))) - (candidates (cl-mapcan (lambda (record) - (mapcar (lambda (mail) (bbdb-dwim-mail record mail)) - (bbdb-record-get-field record 'mail))) - (bbdb-search (bbdb-records) arg nil arg))) + (match-string-no-properties 2))) + (candidates (company-bbdb--candidates arg)) (sorted t) (no-cache t))) diff --git a/elpa/company-0.8.5/company-capf.el b/elpa/company-0.8.12/company-capf.el similarity index 95% rename from elpa/company-0.8.5/company-capf.el rename to elpa/company-0.8.12/company-capf.el index b630025..4962a26 100644 --- a/elpa/company-0.8.5/company-capf.el +++ b/elpa/company-0.8.12/company-capf.el @@ -138,9 +138,14 @@ (`init nil) ;Don't bother: plenty of other ways to initialize the code. (`post-completion (let* ((res (company--capf-data)) - (exit-function (plist-get (nthcdr 4 res) :exit-function))) + (exit-function (plist-get (nthcdr 4 res) :exit-function)) + (table (nth 3 res)) + (pred (plist-get (nthcdr 4 res) :predicate))) (if exit-function - (funcall exit-function arg 'finished)))) + ;; Follow the example of `completion--done'. + (funcall exit-function arg + (if (eq (try-completion arg table pred) t) + 'finished 'sole))))) )) (provide 'company-capf) diff --git a/elpa/company-0.8.5/company-clang.el b/elpa/company-0.8.12/company-clang.el similarity index 95% rename from elpa/company-0.8.5/company-clang.el rename to elpa/company-0.8.12/company-clang.el index a1a3251..e85e865 100644 --- a/elpa/company-0.8.5/company-clang.el +++ b/elpa/company-0.8.12/company-clang.el @@ -51,7 +51,7 @@ and `c-electric-colon', for automatic completion right after \">\" and "Additional arguments to pass to clang when completing. Prefix files (-include ...) can be selected with `company-clang-set-prefix' or automatically through a custom `company-clang-prefix-guesser'." - :type '(repeat (string :tag "Argument" nil))) + :type '(repeat (string :tag "Argument"))) (defcustom company-clang-prefix-guesser 'company-clang-guess-prefix "A function to determine the prefix file for the current buffer." @@ -150,7 +150,13 @@ or automatically through a custom `company-clang-prefix-guesser'." ((string-match "[^:]:[^:]" meta) (substring meta (1+ (match-beginning 0)))) ((string-match "\\((.*)[ a-z]*\\'\\)" meta) - (match-string 1 meta))))) + (let ((paren (match-beginning 1))) + (if (not (eq (aref meta (1- paren)) ?>)) + (match-string 1 meta) + (with-temp-buffer + (insert meta) + (goto-char paren) + (substring meta (1- (search-backward "<")))))))))) (defun company-clang--strip-formatting (text) (replace-regexp-in-string @@ -182,7 +188,9 @@ or automatically through a custom `company-clang-prefix-guesser'." (defun company-clang--start-process (prefix callback &rest args) (let ((objc (derived-mode-p 'objc-mode)) - (buf (get-buffer-create "*clang-output*"))) + (buf (get-buffer-create "*clang-output*")) + ;; Looks unnecessary in Emacs 25.1 and later. + (process-adaptive-read-buffering nil)) (with-current-buffer buf (erase-buffer)) (if (get-buffer-process buf) (funcall callback nil) @@ -320,7 +328,8 @@ passed via standard input." (insert anno) (if (string-match "\\`:[^:]" anno) (company-clang-objc-templatify anno) - (company-template-c-like-templatify anno))))))) + (company-template-c-like-templatify + (concat arg anno)))))))) (provide 'company-clang) ;;; company-clang.el ends here diff --git a/elpa/company-0.8.12/company-cmake.el b/elpa/company-0.8.12/company-cmake.el new file mode 100644 index 0000000..e2962f5 --- /dev/null +++ b/elpa/company-0.8.12/company-cmake.el @@ -0,0 +1,198 @@ +;;; company-cmake.el --- company-mode completion back-end for CMake + +;; Copyright (C) 2013-2014 Free Software Foundation, Inc. + +;; Author: Chen Bin +;; Version: 0.2 + +;; This program 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 of the License, or +;; (at your option) any later version. + +;; This program 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 this program. If not, see . + +;;; Commentary: +;; +;; company-cmake offers completions for module names, variable names and +;; commands used by CMake. And their descriptions. + +;;; Code: + +(require 'company) +(require 'cl-lib) + +(defgroup company-cmake nil + "Completion back-end for CMake." + :group 'company) + +(defcustom company-cmake-executable + (executable-find "cmake") + "Location of cmake executable." + :type 'file) + +(defvar company-cmake-executable-arguments + '("--help-command-list" + "--help-module-list" + "--help-variable-list") + "The arguments we pass to cmake, separately. +They affect which types of symbols we get completion candidates for.") + +(defvar company-cmake--completion-pattern + "^\\(%s[a-zA-Z0-9_<>]%s\\)$" + "Regexp to match the candidates.") + +(defvar company-cmake-modes '(cmake-mode) + "Major modes in which cmake may complete.") + +(defvar company-cmake--candidates-cache nil + "Cache for the raw candidates.") + +(defvar company-cmake--meta-command-cache nil + "Cache for command arguments to retrieve descriptions for the candidates.") + +(defun company-cmake--replace-tags (rlt) + (setq rlt (replace-regexp-in-string + "\\(.*?\\(IS_GNU\\)?\\)\\(.*\\)" + (lambda (_match) + (mapconcat 'identity + (if (match-beginning 2) + '("\\1CXX\\3" "\\1C\\3" "\\1G77\\3") + '("\\1CXX\\3" "\\1C\\3" "\\1Fortran\\3")) + "\n")) + rlt t)) + (setq rlt (replace-regexp-in-string + "\\(.*\\)\\(.*\\)" + (mapconcat 'identity '("\\1DEBUG\\2" "\\1RELEASE\\2" + "\\1RELWITHDEBINFO\\2" "\\1MINSIZEREL\\2") + "\n") + rlt)) + rlt) + +(defun company-cmake--fill-candidates-cache (arg) + "Fill candidates cache if needed." + (let (rlt) + (unless company-cmake--candidates-cache + (setq company-cmake--candidates-cache (make-hash-table :test 'equal))) + + ;; If hash is empty, fill it. + (unless (gethash arg company-cmake--candidates-cache) + (with-temp-buffer + (let ((res (call-process company-cmake-executable nil t nil arg))) + (unless (zerop res) + (message "cmake executable exited with error=%d" res))) + (setq rlt (buffer-string))) + (setq rlt (company-cmake--replace-tags rlt)) + (puthash arg rlt company-cmake--candidates-cache)) + )) + +(defun company-cmake--parse (prefix content cmd) + (let ((start 0) + (pattern (format company-cmake--completion-pattern + (regexp-quote prefix) + (if (zerop (length prefix)) "+" "*"))) + (lines (split-string content "\n")) + match + rlt) + (dolist (line lines) + (when (string-match pattern line) + (let ((match (match-string 1 line))) + (when match + (puthash match cmd company-cmake--meta-command-cache) + (push match rlt))))) + rlt)) + +(defun company-cmake--candidates (prefix) + (let (results + cmd-opts + str) + + (unless company-cmake--meta-command-cache + (setq company-cmake--meta-command-cache (make-hash-table :test 'equal))) + + (dolist (arg company-cmake-executable-arguments) + (company-cmake--fill-candidates-cache arg) + (setq cmd-opts (replace-regexp-in-string "-list$" "" arg) ) + + (setq str (gethash arg company-cmake--candidates-cache)) + (when str + (setq results (nconc results + (company-cmake--parse prefix str cmd-opts))))) + results)) + +(defun company-cmake--unexpand-candidate (candidate) + (cond + ((string-match "^CMAKE_\\(C\\|CXX\\|Fortran\\)\\(_.*\\)$" candidate) + (setq candidate (concat "CMAKE_" (match-string 2 candidate)))) + + ;; C flags + ((string-match "^\\(.*_\\)IS_GNU\\(C\\|CXX\\|G77\\)$" candidate) + (setq candidate (concat (match-string 1 candidate) "IS_GNU"))) + + ;; C flags + ((string-match "^\\(.*_\\)OVERRIDE_\\(C\\|CXX\\|Fortran\\)$" candidate) + (setq candidate (concat (match-string 1 candidate) "OVERRIDE_"))) + + ((string-match "^\\(.*\\)\\(_DEBUG\\|_RELEASE\\|_RELWITHDEBINFO\\|_MINSIZEREL\\)\\(.*\\)$" candidate) + (setq candidate (concat (match-string 1 candidate) + "_" + (match-string 3 candidate))))) + candidate) + +(defun company-cmake--meta (candidate) + (let ((cmd-opts (gethash candidate company-cmake--meta-command-cache)) + result) + (setq candidate (company-cmake--unexpand-candidate candidate)) + + ;; Don't cache the documentation of every candidate (command) + ;; Cache in this case will cost too much memory. + (with-temp-buffer + (call-process company-cmake-executable nil t nil cmd-opts candidate) + ;; Go to the third line, trim it and return the result. + ;; Tested with cmake 2.8.9. + (goto-char (point-min)) + (forward-line 2) + (setq result (buffer-substring-no-properties (line-beginning-position) + (line-end-position))) + (setq result (replace-regexp-in-string "^[ \t\n\r]+" "" result)) + result))) + +(defun company-cmake--doc-buffer (candidate) + (let ((cmd-opts (gethash candidate company-cmake--meta-command-cache))) + + (setq candidate (company-cmake--unexpand-candidate candidate)) + (with-temp-buffer + (call-process company-cmake-executable nil t nil cmd-opts candidate) + ;; Go to the third line, trim it and return the doc buffer. + ;; Tested with cmake 2.8.9. + (goto-char (point-min)) + (forward-line 2) + (company-doc-buffer + (buffer-substring-no-properties (line-beginning-position) + (point-max)))))) + +(defun company-cmake (command &optional arg &rest ignored) + "`company-mode' completion back-end for CMake. +CMake is a cross-platform, open-source make system." + (interactive (list 'interactive)) + (cl-case command + (interactive (company-begin-backend 'company-cmake)) + (init (when (memq major-mode company-cmake-modes) + (unless company-cmake-executable + (error "Company found no cmake executable")))) + (prefix (and (memq major-mode company-cmake-modes) + (not (company-in-string-or-comment)) + (company-grab-symbol))) + (candidates (company-cmake--candidates arg)) + (meta (company-cmake--meta arg)) + (doc-buffer (company-cmake--doc-buffer arg)) + )) + +(provide 'company-cmake) +;;; company-cmake.el ends here diff --git a/elpa/company-0.8.5/company-css.el b/elpa/company-0.8.12/company-css.el similarity index 100% rename from elpa/company-0.8.5/company-css.el rename to elpa/company-0.8.12/company-css.el diff --git a/elpa/company-0.8.5/company-dabbrev-code.el b/elpa/company-0.8.12/company-dabbrev-code.el similarity index 93% rename from elpa/company-0.8.5/company-dabbrev-code.el rename to elpa/company-0.8.12/company-dabbrev-code.el index 0566c50..256b57f 100644 --- a/elpa/company-0.8.5/company-dabbrev-code.el +++ b/elpa/company-0.8.12/company-dabbrev-code.el @@ -47,10 +47,10 @@ complete only symbols, not text in comments or strings. In other modes (defcustom company-dabbrev-code-other-buffers t "Determines whether `company-dabbrev-code' should search other buffers. -If `all', search all other buffers. If t, search buffers with the same -major mode. If `code', search all buffers with major modes in -`company-dabbrev-code-modes', or derived from one of them. -See also `company-dabbrev-code-time-limit'." +If `all', search all other buffers, except the ignored ones. If t, search +buffers with the same major mode. If `code', search all buffers with major +modes in `company-dabbrev-code-modes', or derived from one of them. See +also `company-dabbrev-code-time-limit'." :type '(choice (const :tag "Off" nil) (const :tag "Same major mode" t) (const :tag "Code major modes" code) diff --git a/elpa/company-0.8.5/company-dabbrev.el b/elpa/company-0.8.12/company-dabbrev.el similarity index 92% rename from elpa/company-0.8.5/company-dabbrev.el rename to elpa/company-0.8.12/company-dabbrev.el index 84da305..7519caf 100644 --- a/elpa/company-0.8.5/company-dabbrev.el +++ b/elpa/company-0.8.12/company-dabbrev.el @@ -34,13 +34,16 @@ (defcustom company-dabbrev-other-buffers 'all "Determines whether `company-dabbrev' should search other buffers. -If `all', search all other buffers. If t, search buffers with the same -major mode. -See also `company-dabbrev-time-limit'." +If `all', search all other buffers, except the ignored ones. If t, search +buffers with the same major mode. See also `company-dabbrev-time-limit'." :type '(choice (const :tag "Off" nil) (const :tag "Same major mode" t) (const :tag "All" all))) +(defcustom company-dabbrev-ignore-buffers "\\`[ *]" + "Regexp matching the names of buffers to ignore." + :type 'regexp) + (defcustom company-dabbrev-time-limit .1 "Determines how many seconds `company-dabbrev' should look for matches." :type '(choice (const :tag "Off" nil) @@ -121,8 +124,10 @@ This variable affects both `company-dabbrev' and `company-dabbrev-code'." (when other-buffer-modes (cl-dolist (buffer (delq (current-buffer) (buffer-list))) (with-current-buffer buffer - (when (or (eq other-buffer-modes 'all) - (apply #'derived-mode-p other-buffer-modes)) + (when (if (eq other-buffer-modes 'all) + (not (string-match-p company-dabbrev-ignore-buffers + (buffer-name))) + (apply #'derived-mode-p other-buffer-modes)) (setq symbols (company-dabbrev--search-buffer regexp nil symbols start limit ignore-comments)))) diff --git a/elpa/company-0.8.5/company-eclim.el b/elpa/company-0.8.12/company-eclim.el similarity index 100% rename from elpa/company-0.8.5/company-eclim.el rename to elpa/company-0.8.12/company-eclim.el diff --git a/elpa/company-0.8.5/company-elisp.el b/elpa/company-0.8.12/company-elisp.el similarity index 100% rename from elpa/company-0.8.5/company-elisp.el rename to elpa/company-0.8.12/company-elisp.el diff --git a/elpa/company-0.8.5/company-etags.el b/elpa/company-0.8.12/company-etags.el similarity index 98% rename from elpa/company-0.8.5/company-etags.el rename to elpa/company-0.8.12/company-etags.el index c7ba608..1c01c91 100644 --- a/elpa/company-0.8.5/company-etags.el +++ b/elpa/company-0.8.12/company-etags.el @@ -54,7 +54,7 @@ buffer automatically." (let ((file (locate-dominating-file (or buffer-file-name default-directory) "TAGS"))) - (when file + (when (and file (file-regular-p file)) (list (expand-file-name file))))) (defun company-etags-buffer-table () diff --git a/elpa/company-0.8.5/company-files.el b/elpa/company-0.8.12/company-files.el similarity index 60% rename from elpa/company-0.8.5/company-files.el rename to elpa/company-0.8.12/company-files.el index 3dc4d86..7cfc500 100644 --- a/elpa/company-0.8.5/company-files.el +++ b/elpa/company-0.8.12/company-files.el @@ -1,6 +1,6 @@ -;;; company-files.el --- company-mode completion back-end for file names +;;; company-files.el --- company-mode completion back-end for file paths -;; Copyright (C) 2009-2011, 2013 Free Software Foundation, Inc. +;; Copyright (C) 2009-2011, 2014 Free Software Foundation, Inc. ;; Author: Nikolaj Schumacher @@ -28,24 +28,26 @@ (require 'company) (require 'cl-lib) -(defun company-files-directory-files (dir prefix) +(defun company-files--directory-files (dir prefix) (ignore-errors (if (equal prefix "") (directory-files dir nil "\\`[^.]\\|\\`.[^.]") (file-name-all-completions prefix dir)))) -(defvar company-files-regexps - (let ((begin (if (eq system-type 'windows-nt) - "[a-z][A-Z]\\" - "~?/"))) +(defvar company-files--regexps + (let* ((root (if (eq system-type 'windows-nt) + "[a-zA-Z]:/" + "/")) + (begin (concat "\\(?:\\.\\{1,2\\}/\\|~/\\|" root "\\)"))) (list (concat "\"\\(" begin "[^\"\n]*\\)") (concat "\'\\(" begin "[^\'\n]*\\)") (concat "\\(?:[ \t]\\|^\\)\\(" begin "[^ \t\n]*\\)")))) -(defun company-files-grab-existing-name () - ;; Grab file names with spaces, only when they include quotes. +(defun company-files--grab-existing-name () + ;; Grab the file name. + ;; When surrounded with quotes, it can include spaces. (let (file dir) - (and (cl-dolist (regexp company-files-regexps) + (and (cl-dolist (regexp company-files--regexps) (when (setq file (company-grab-line regexp 1)) (cl-return file))) (setq dir (file-name-directory file)) @@ -54,36 +56,46 @@ (file-name-all-completions (file-name-nondirectory file) dir) file))) -(defvar company-files-completion-cache nil) +(defvar company-files--completion-cache nil) -(defun company-files-complete (prefix) +(defun company-files--complete (prefix) (let* ((dir (file-name-directory prefix)) + (key (list (file-name-nondirectory prefix) + (expand-file-name dir) + (nth 5 (file-attributes dir)))) (file (file-name-nondirectory prefix)) + (completion-ignore-case read-file-name-completion-ignore-case) candidates directories) - (unless (equal dir (car company-files-completion-cache)) - (dolist (file (company-files-directory-files dir file)) + (unless (company-file--keys-match-p key (car company-files--completion-cache)) + (dolist (file (company-files--directory-files dir file)) (setq file (concat dir file)) (push file candidates) (when (file-directory-p file) (push file directories))) (dolist (directory (reverse directories)) ;; Add one level of children. - (dolist (child (company-files-directory-files directory "")) + (dolist (child (company-files--directory-files directory "")) (push (concat directory (unless (eq (aref directory (1- (length directory))) ?/) "/") child) candidates))) - (setq company-files-completion-cache (cons dir (nreverse candidates)))) + (setq company-files--completion-cache (cons key (nreverse candidates)))) (all-completions prefix - (cdr company-files-completion-cache)))) + (cdr company-files--completion-cache)))) + +(defun company-file--keys-match-p (new old) + (and (equal (cdr old) (cdr new)) + (string-prefix-p (car old) (car new)))) ;;;###autoload (defun company-files (command &optional arg &rest ignored) - "`company-mode' completion back-end existing file names." + "`company-mode' completion back-end existing file names. +Completions works for proper absolute and relative files paths. +File paths with spaces are only supported inside strings." (interactive (list 'interactive)) (cl-case command (interactive (company-begin-backend 'company-files)) - (prefix (company-files-grab-existing-name)) - (candidates (company-files-complete arg)) + (prefix (company-files--grab-existing-name)) + (candidates (company-files--complete arg)) (location (cons (dired-noselect (file-name-directory (directory-file-name arg))) 1)) (sorted t) diff --git a/elpa/company-0.8.5/company-gtags.el b/elpa/company-0.8.12/company-gtags.el similarity index 99% rename from elpa/company-0.8.5/company-gtags.el rename to elpa/company-0.8.12/company-gtags.el index 70c5ad5..aaa22b9 100644 --- a/elpa/company-0.8.5/company-gtags.el +++ b/elpa/company-0.8.12/company-gtags.el @@ -95,6 +95,7 @@ completion." (cl-case command (interactive (company-begin-backend 'company-gtags)) (prefix (and company-gtags-executable + buffer-file-name (apply #'derived-mode-p company-gtags-modes) (not (company-in-string-or-comment)) (company-gtags--tags-available-p) diff --git a/elpa/company-0.8.5/company-ispell.el b/elpa/company-0.8.12/company-ispell.el similarity index 82% rename from elpa/company-0.8.5/company-ispell.el rename to elpa/company-0.8.12/company-ispell.el index 1561bee..4ce8dfc 100644 --- a/elpa/company-0.8.5/company-ispell.el +++ b/elpa/company-0.8.12/company-ispell.el @@ -1,6 +1,6 @@ ;;; company-ispell.el --- company-mode completion back-end using Ispell -;; Copyright (C) 2009-2011 Free Software Foundation, Inc. +;; Copyright (C) 2009-2011, 2013-2015 Free Software Foundation, Inc. ;; Author: Nikolaj Schumacher @@ -60,8 +60,15 @@ If nil, use `ispell-complete-word-dict'." (interactive (company-begin-backend 'company-ispell)) (prefix (when (company-ispell-available) (company-grab-word))) - (candidates (lookup-words arg (or company-ispell-dictionary - ispell-complete-word-dict))) + (candidates + (let ((words (lookup-words arg (or company-ispell-dictionary + ispell-complete-word-dict))) + (completion-ignore-case t)) + (if (string= arg "") + ;; Small optimization. + words + ;; Work around issue #284. + (all-completions arg words)))) (sorted t) (ignore-case 'keep-prefix))) diff --git a/elpa/company-0.8.5/company-keywords.el b/elpa/company-0.8.12/company-keywords.el similarity index 100% rename from elpa/company-0.8.5/company-keywords.el rename to elpa/company-0.8.12/company-keywords.el diff --git a/elpa/company-0.8.5/company-nxml.el b/elpa/company-0.8.12/company-nxml.el similarity index 100% rename from elpa/company-0.8.5/company-nxml.el rename to elpa/company-0.8.12/company-nxml.el diff --git a/elpa/company-0.8.5/company-oddmuse.el b/elpa/company-0.8.12/company-oddmuse.el similarity index 100% rename from elpa/company-0.8.5/company-oddmuse.el rename to elpa/company-0.8.12/company-oddmuse.el diff --git a/elpa/company-0.8.12/company-pkg.el b/elpa/company-0.8.12/company-pkg.el new file mode 100644 index 0000000..675f15a --- /dev/null +++ b/elpa/company-0.8.12/company-pkg.el @@ -0,0 +1,2 @@ +;; Generated package description from company.el +(define-package "company" "0.8.12" "Modular text completion framework" '((emacs "24.1") (cl-lib "0.5")) :url "http://company-mode.github.io/" :keywords '("abbrev" "convenience" "matching")) diff --git a/elpa/company-0.8.5/company-pysmell.el b/elpa/company-0.8.12/company-pysmell.el similarity index 100% rename from elpa/company-0.8.5/company-pysmell.el rename to elpa/company-0.8.12/company-pysmell.el diff --git a/elpa/company-0.8.5/company-ropemacs.el b/elpa/company-0.8.12/company-ropemacs.el similarity index 100% rename from elpa/company-0.8.5/company-ropemacs.el rename to elpa/company-0.8.12/company-ropemacs.el diff --git a/elpa/company-0.8.5/company-semantic.el b/elpa/company-0.8.12/company-semantic.el similarity index 92% rename from elpa/company-0.8.5/company-semantic.el rename to elpa/company-0.8.12/company-semantic.el index 6c020a3..a1c7d16 100644 --- a/elpa/company-0.8.5/company-semantic.el +++ b/elpa/company-0.8.12/company-semantic.el @@ -99,6 +99,14 @@ (push tag company-semantic--current-tags))) (delete "" (mapcar 'semantic-tag-name company-semantic--current-tags))) +(defun company-semantic-annotation (argument tags) + (let* ((tag (assoc argument tags)) + (kind (when tag (elt tag 1)))) + (cl-case kind + (function (let* ((prototype (semantic-format-tag-prototype tag nil nil)) + (par-pos (string-match "(" prototype))) + (when par-pos (substring prototype par-pos))))))) + (defun company-semantic--pre-prefix-length (prefix-length) "Sum up the length of all chained symbols before POS. Symbols are chained by \".\" or \"->\"." @@ -133,6 +141,8 @@ Symbols are chained by \".\" or \"->\"." (company-semantic-completions arg))) (meta (funcall company-semantic-metadata-function (assoc arg company-semantic--current-tags))) + (annotation (company-semantic-annotation arg + company-semantic--current-tags)) (doc-buffer (company-semantic-doc-buffer (assoc arg company-semantic--current-tags))) ;; Because "" is an empty context and doesn't return local variables. diff --git a/elpa/company-0.8.5/company-template.el b/elpa/company-0.8.12/company-template.el similarity index 77% rename from elpa/company-0.8.5/company-template.el rename to elpa/company-0.8.12/company-template.el index 576b246..21ae011 100644 --- a/elpa/company-0.8.5/company-template.el +++ b/elpa/company-0.8.12/company-template.el @@ -1,6 +1,6 @@ ;;; company-template.el -;; Copyright (C) 2009, 2010, 2013 Free Software Foundation, Inc. +;; Copyright (C) 2009, 2010, 2014 Free Software Foundation, Inc. ;; Author: Nikolaj Schumacher @@ -149,22 +149,47 @@ Leave point at the end of the field." (defun company-template-c-like-templatify (call) (let* ((end (point-marker)) (beg (- (point) (length call))) - (cnt 0)) - (when (re-search-backward ")" beg t) - (delete-region (match-end 0) end)) - (goto-char beg) - (when (search-forward "(" end 'move) - (if (eq (char-after) ?\)) + (cnt 0) + (templ (company-template-declare-template beg end)) + paren-open paren-close) + (with-syntax-table (make-syntax-table (syntax-table)) + (modify-syntax-entry ?< "(") + (modify-syntax-entry ?> ")") + (when (search-backward ")" beg t) + (setq paren-close (point-marker)) + (forward-char 1) + (delete-region (point) end) + (backward-sexp) + (forward-char 1) + (setq paren-open (point-marker))) + (when (search-backward ">" beg t) + (let ((angle-close (point-marker))) (forward-char 1) - (let ((templ (company-template-declare-template beg end))) - (while (re-search-forward (concat " *\\([^,)]*\\)[,)]") end t) - (let ((sig (match-string 1))) - (delete-region (match-beginning 1) (match-end 1)) - (save-excursion - (company-template-add-field templ (match-beginning 1) - (format "arg%d" cnt) sig)) - (cl-incf cnt))) - (company-template-move-to-first templ)))))) + (backward-sexp) + (forward-char) + (setq cnt (company-template--c-like-args templ angle-close + cnt)))) + (when paren-open + (goto-char paren-open) + (company-template--c-like-args templ paren-close cnt))) + (if (overlay-get templ 'company-template-fields) + (company-template-move-to-first templ) + (company-template-remove-template templ) + (goto-char end)))) + +(defun company-template--c-like-args (templ end counter) + (let ((last-pos (point))) + (while (re-search-forward "\\([^,]+\\),?" end 'move) + (when (zerop (car (parse-partial-sexp last-pos (point)))) + (let ((sig (buffer-substring-no-properties last-pos (match-end 1)))) + (save-excursion + (company-template-add-field templ last-pos + (format "arg%d" counter) sig) + (delete-region (point) (+ (point) (length sig)))) + (skip-chars-forward " ") + (setq last-pos (point)) + (cl-incf counter))))) + counter) (provide 'company-template) ;;; company-template.el ends here diff --git a/elpa/company-0.8.5/company-tempo.el b/elpa/company-0.8.12/company-tempo.el similarity index 100% rename from elpa/company-0.8.5/company-tempo.el rename to elpa/company-0.8.12/company-tempo.el diff --git a/elpa/company-0.8.5/company-xcode.el b/elpa/company-0.8.12/company-xcode.el similarity index 97% rename from elpa/company-0.8.5/company-xcode.el rename to elpa/company-0.8.12/company-xcode.el index 91ae60b..c7a6f80 100644 --- a/elpa/company-0.8.5/company-xcode.el +++ b/elpa/company-0.8.12/company-xcode.el @@ -1,6 +1,6 @@ ;;; company-xcode.el --- company-mode completion back-end for Xcode projects -;; Copyright (C) 2009-2011 Free Software Foundation, Inc. +;; Copyright (C) 2009-2011, 2014 Free Software Foundation, Inc. ;; Author: Nikolaj Schumacher @@ -80,7 +80,7 @@ valid in most contexts." "\t[^\t\n]*\t[^\t\n]*")) candidates) (while (re-search-forward regexp nil t) - (add-to-list 'candidates (match-string 1))) + (cl-pushnew (match-string 1) candidates :test #'equal)) (message "Retrieving dump from %s...done" project-bundle) candidates)))) diff --git a/elpa/company-0.8.5/company-yasnippet.el b/elpa/company-0.8.12/company-yasnippet.el similarity index 90% rename from elpa/company-0.8.5/company-yasnippet.el rename to elpa/company-0.8.12/company-yasnippet.el index 741a160..f0a7c38 100644 --- a/elpa/company-0.8.5/company-yasnippet.el +++ b/elpa/company-0.8.12/company-yasnippet.el @@ -25,11 +25,17 @@ ;;; Code: +(require 'company) (require 'cl-lib) -(require 'yasnippet) + +(declare-function yas--table-hash "yasnippet") +(declare-function yas--get-snippet-tables "yasnippet") +(declare-function yas-expand-snippet "yasnippet") +(declare-function yas--template-content "yasnippet") +(declare-function yas--template-expand-env "yasnippet") (defun company-yasnippet--candidates (prefix) - (mapcan + (cl-mapcan (lambda (table) (let ((keyhash (yas--table-hash table)) res) @@ -80,7 +86,7 @@ shadow back-ends that come after it. Recommended usages: (prefix ;; Should probably use `yas--current-key', but that's bound to be slower. ;; How many trigger keys start with non-symbol characters anyway? - (and yas-minor-mode + (and (bound-and-true-p yas-minor-mode) (company-grab-symbol))) (annotation (concat diff --git a/elpa/company-0.8.5/company.el b/elpa/company-0.8.12/company.el similarity index 86% rename from elpa/company-0.8.5/company.el rename to elpa/company-0.8.12/company.el index fdf09f7..ce0b5a4 100644 --- a/elpa/company-0.8.5/company.el +++ b/elpa/company-0.8.12/company.el @@ -1,11 +1,11 @@ ;;; company.el --- Modular text completion framework -*- lexical-binding: t -*- -;; Copyright (C) 2009-2014 Free Software Foundation, Inc. +;; Copyright (C) 2009-2015 Free Software Foundation, Inc. ;; Author: Nikolaj Schumacher ;; Maintainer: Dmitry Gutov ;; URL: http://company-mode.github.io/ -;; Version: 0.8.5 +;; Version: 0.8.12 ;; Keywords: abbrev, convenience, matching ;; Package-Requires: ((emacs "24.1") (cl-lib "0.5")) @@ -340,20 +340,20 @@ The first argument is the command requested from the back-end. It is one of the following: `prefix': The back-end should return the text to be completed. It must be -text immediately before point. Returning nil passes control to the next -back-end. The function should return `stop' if it should complete but -cannot (e.g. if it is in the middle of a string). Instead of a string, -the back-end may return a cons where car is the prefix and cdr is used in -`company-minimum-prefix-length' test. It must be either number or t, and -in the latter case the test automatically succeeds. +text immediately before point. Returning nil from this command passes +control to the next back-end. The function should return `stop' if it +should complete but cannot (e.g. if it is in the middle of a string). +Instead of a string, the back-end may return a cons where car is the prefix +and cdr is used in `company-minimum-prefix-length' test. It must be either +number or t, and in the latter case the test automatically succeeds. `candidates': The second argument is the prefix to be completed. The return value should be a list of candidates that match the prefix. Non-prefix matches are also supported (candidates that don't start with the prefix, but match it in some backend-defined way). Backends that use this -feature must disable cache (return t to `no-cache') and should also respond -to `match'. +feature must disable cache (return t to `no-cache') and might also want to +respond to `match'. Optional commands: @@ -384,10 +384,10 @@ be kept if they have different annotations. For that to work properly, backends should store the related information on candidates using text properties. -`match': The second argument is a completion candidate. Backends that -provide non-prefix completions should return the position of the end of -text in the candidate that matches `prefix'. It will be used when -rendering the popup. +`match': The second argument is a completion candidate. Return the index +after the end of text matching `prefix' within the candidate string. It +will be used when rendering the popup. This command only makes sense for +backends that provide non-prefix completion. `require-match': If this returns t, the user is not allowed to enter anything not offered as a candidate. Use with care! The default value nil @@ -449,9 +449,11 @@ even if the back-end uses the asynchronous calling convention." (put 'company-backends 'safe-local-variable 'company-safe-backends-p) (defcustom company-transformers nil - "Functions to change the list of candidates received from backends, -after sorting and removal of duplicates (if appropriate). -Each function gets called with the return value of the previous one." + "Functions to change the list of candidates received from backends. + +Each function gets called with the return value of the previous one. +The first one gets passed the list of candidates, already sorted and +without duplicates." :type '(choice (const :tag "None" nil) (const :tag "Sort by occurrence" (company-sort-by-occurrence)) @@ -551,6 +553,7 @@ happens. The value of nil means no idle completion." (defcustom company-begin-commands '(self-insert-command org-self-insert-command + orgtbl-self-insert-command c-scope-operator c-electric-colon c-electric-lt-gt @@ -611,6 +614,8 @@ asynchronous call into synchronous.") (define-key keymap (kbd "M-p") 'company-select-previous) (define-key keymap (kbd "") 'company-select-next-or-abort) (define-key keymap (kbd "") 'company-select-previous-or-abort) + (define-key keymap [remap scroll-up-command] 'company-next-page) + (define-key keymap [remap scroll-down-command] 'company-previous-page) (define-key keymap [down-mouse-1] 'ignore) (define-key keymap [down-mouse-3] 'ignore) (define-key keymap [mouse-1] 'company-complete-mouse) @@ -627,7 +632,7 @@ asynchronous call into synchronous.") (define-key keymap "\C-s" 'company-search-candidates) (define-key keymap "\C-\M-s" 'company-filter-candidates) (dotimes (i 10) - (define-key keymap (kbd (format "M-%d" i)) 'company-complete-number)) + (define-key keymap (read-kbd-macro (format "M-%d" i)) 'company-complete-number)) keymap) "Keymap that is enabled during an active completion.") @@ -657,9 +662,26 @@ asynchronous call into synchronous.") (unless (keywordp b) (company-init-backend b)))))) -(defvar company-default-lighter " company") +(defcustom company-lighter-base "company" + "Base string to use for the `company-mode' lighter." + :type 'string + :package-version '(company . "0.8.10")) -(defvar-local company-lighter company-default-lighter) +(defvar company-lighter '(" " + (company-backend + (:eval + (if (consp company-backend) + (company--group-lighter (nth company-selection + company-candidates) + company-lighter-base) + (symbol-name company-backend))) + company-lighter-base)) + "Mode line lighter for Company. + +The value of this variable is a mode line template as in +`mode-line-format'.") + +(put 'company-lighter 'risky-local-variable t) ;;;###autoload (define-minor-mode company-mode @@ -766,10 +788,10 @@ means that `company-mode' is always turned on except in `message-mode' buffers." (interactive) (setq this-command last-command)) -(global-set-key '[31415926] 'company-ignore) +(global-set-key '[company-dummy-event] 'company-ignore) (defun company-input-noop () - (push 31415926 unread-command-events)) + (push 'company-dummy-event unread-command-events)) (defun company--posn-col-row (posn) (let ((col (car (posn-col-row posn))) @@ -848,7 +870,7 @@ means that `company-mode' is always turned on except in `message-mode' buffers." res)))) (defun company-call-backend-raw (&rest args) - (condition-case err + (condition-case-unless-debug err (if (functionp company-backend) (apply company-backend args) (apply #'company--multi-backend-adapter company-backend args)) @@ -912,26 +934,26 @@ means that `company-mode' is always turned on except in `message-mode' buffers." (cons :async (lambda (callback) - (let* (lst pending + (let* (lst + (pending (mapcar #'car pairs)) (finisher (lambda () (unless pending (funcall callback (funcall merger (nreverse lst))))))) (dolist (pair pairs) - (let ((val (car pair)) - (mapper (cdr pair))) + (push nil lst) + (let* ((cell lst) + (val (car pair)) + (mapper (cdr pair)) + (this-finisher (lambda (res) + (setq pending (delq val pending)) + (setcar cell (funcall mapper res)) + (funcall finisher)))) (if (not (eq :async (car-safe val))) - (push (funcall mapper val) lst) - (push nil lst) - (let ((cell lst) - (fetcher (cdr val))) - (push fetcher pending) - (funcall fetcher - (lambda (res) - (setq pending (delq fetcher pending)) - (setcar cell (funcall mapper res)) - (funcall finisher))))))))))))) + (funcall this-finisher val) + (let ((fetcher (cdr val))) + (funcall fetcher this-finisher))))))))))) (defun company--prefix-str (prefix) (or (car-safe prefix) prefix)) @@ -977,8 +999,9 @@ Controlled by `company-auto-complete'.") ;; XXX: Return value we check here is subject to change. (if (eq (company-call-backend 'ignore-case) 'keep-prefix) (insert (company-strip-prefix candidate)) - (delete-region (- (point) (length company-prefix)) (point)) - (insert-before-markers candidate))) + (unless (equal company-prefix candidate) + (delete-region (- (point) (length company-prefix)) (point)) + (insert candidate)))) (defmacro company-with-candidate-inserted (candidate &rest body) "Evaluate BODY with CANDIDATE temporarily inserted. @@ -1028,7 +1051,7 @@ can retrieve meta-data for them." (defun company-call-frontends (command) (dolist (frontend company-frontends) - (condition-case err + (condition-case-unless-debug err (funcall frontend command) (error (error "Company: Front-end %s error \"%s\" on command %s" frontend (error-message-string err) command))))) @@ -1039,58 +1062,49 @@ can retrieve meta-data for them." (mod selection company-candidates-length) (max 0 (min (1- company-candidates-length) selection)))) (when (or force-update (not (equal selection company-selection))) - (company--update-group-lighter (nth selection company-candidates)) (setq company-selection selection company-selection-changed t) (company-call-frontends 'update))) -(defun company--update-group-lighter (candidate) - (when (listp company-backend) - (let ((backend (or (get-text-property 0 'company-backend candidate) - (car company-backend)))) - (when (and backend (symbolp backend)) - (let ((name (replace-regexp-in-string "company-\\|-company" "" - (symbol-name backend)))) - (setq company-lighter (format " company-<%s>" name))))))) - -(defun company-apply-predicate (candidates predicate) - (let (new) - (dolist (c candidates) - (when (funcall predicate c) - (push c new))) - (nreverse new))) +(defun company--group-lighter (candidate base) + (let ((backend (or (get-text-property 0 'company-backend candidate) + (car company-backend)))) + (when (and backend (symbolp backend)) + (let ((name (replace-regexp-in-string "company-\\|-company" "" + (symbol-name backend)))) + (format "%s-<%s>" base name))))) (defun company-update-candidates (candidates) (setq company-candidates-length (length candidates)) - (if (> company-selection 0) + (if company-selection-changed ;; Try to restore the selection (let ((selected (nth company-selection company-candidates))) (setq company-selection 0 company-candidates candidates) (when selected - (while (and candidates (string< (pop candidates) selected)) - (cl-incf company-selection)) - (unless candidates - ;; Make sure selection isn't out of bounds. - (setq company-selection (min (1- company-candidates-length) - company-selection))))) + (catch 'found + (while candidates + (let ((candidate (pop candidates))) + (when (and (string= candidate selected) + (equal (company-call-backend 'annotation candidate) + (company-call-backend 'annotation selected))) + (throw 'found t))) + (cl-incf company-selection)) + (setq company-selection 0 + company-selection-changed nil)))) (setq company-selection 0 company-candidates candidates)) - ;; Save in cache: - (push (cons company-prefix company-candidates) company-candidates-cache) ;; Calculate common. (let ((completion-ignore-case (company-call-backend 'ignore-case))) ;; We want to support non-prefix completion, so filtering is the ;; responsibility of each respective backend, not ours. ;; On the other hand, we don't want to replace non-prefix input in - ;; `company-complete-common'. + ;; `company-complete-common', unless there's only one candidate. (setq company-common (if (cdr company-candidates) - (let ((common (try-completion company-prefix company-candidates))) - (if (eq common t) - ;; Mulple equal strings, probably with different - ;; annotations. - company-prefix + (let ((common (try-completion "" company-candidates))) + (when (string-prefix-p company-prefix common + completion-ignore-case) common)) (car company-candidates))))) @@ -1107,11 +1121,14 @@ can retrieve meta-data for them." company-candidates-cache))) (setq candidates (all-completions prefix prev)) (cl-return t))))) - ;; no cache match, call back-end - (setq candidates - (company--process-candidates - (company--fetch-candidates prefix)))) - (setq candidates (company--transform-candidates candidates)) + (progn + ;; No cache match, call the backend. + (setq candidates (company--preprocess-candidates + (company--fetch-candidates prefix))) + ;; Save in cache. + (push (cons prefix candidates) company-candidates-cache))) + ;; Only now apply the predicate and transformers. + (setq candidates (company--postprocess-candidates candidates)) (when candidates (if (or (cdr candidates) (not (eq t (compare-strings (car candidates) nil nil @@ -1136,13 +1153,13 @@ can retrieve meta-data for them." (cdr c) (lambda (candidates) (if (not (and candidates (eq res 'done))) - ;; Fetcher called us back right away. + ;; There's no completions to display, + ;; or the fetcher called us back right away. (setq res candidates) (setq company-backend backend company-candidates-cache (list (cons prefix - (company--process-candidates - candidates)))) + (company--preprocess-candidates candidates)))) (company-idle-begin buf win tick pt))))) ;; FIXME: Relying on the fact that the callers ;; will interpret nil as "do nothing" is shaky. @@ -1150,33 +1167,40 @@ can retrieve meta-data for them." (or res (progn (setq res 'done) nil))))) -(defun company--process-candidates (candidates) - (when company-candidates-predicate - (setq candidates - (company-apply-predicate candidates - company-candidates-predicate))) +(defun company--preprocess-candidates (candidates) (unless (company-call-backend 'sorted) (setq candidates (sort candidates 'string<))) (when (company-call-backend 'duplicates) (company--strip-duplicates candidates)) candidates) +(defun company--postprocess-candidates (candidates) + (when (or company-candidates-predicate company-transformers) + (setq candidates (copy-sequence candidates))) + (when company-candidates-predicate + (setq candidates (cl-delete-if-not company-candidates-predicate candidates))) + (company--transform-candidates candidates)) + (defun company--strip-duplicates (candidates) - (let ((c2 candidates)) + (let ((c2 candidates) + (annos 'unk)) (while c2 (setcdr c2 - (let ((str (car c2)) - (anno 'unk)) - (pop c2) + (let ((str (pop c2))) (while (let ((str2 (car c2))) (if (not (equal str str2)) - nil - (when (eq anno 'unk) - (setq anno (company-call-backend - 'annotation str))) - (equal anno - (company-call-backend - 'annotation str2)))) + (progn + (setq annos 'unk) + nil) + (when (eq annos 'unk) + (setq annos (list (company-call-backend + 'annotation str)))) + (let ((anno2 (company-call-backend + 'annotation str2))) + (if (member anno2 annos) + t + (push anno2 annos) + nil)))) (pop c2)) c2))))) @@ -1279,22 +1303,22 @@ from the rest of the back-ends in the group, if any, will be left at the end." (eq pos (point)) (when (company-auto-begin) (company-input-noop) - (company-post-command)))) + (let ((this-command 'company-idle-begin)) + (company-post-command))))) (defun company-auto-begin () (and company-mode (not company-candidates) (let ((company-idle-delay 'now)) (condition-case-unless-debug err - (company--perform) + (progn + (company--perform) + ;; Return non-nil if active. + company-candidates) (error (message "Company: An error occurred in auto-begin") (message "%s" (error-message-string err)) (company-cancel)) - (quit (company-cancel))))) - (unless company-candidates - (setq company-backend nil)) - ;; Return non-nil if active. - company-candidates) + (quit (company-cancel)))))) (defun company-manual-begin () (interactive) @@ -1302,7 +1326,8 @@ from the rest of the back-ends in the group, if any, will be left at the end." (setq company--manual-action t) (unwind-protect (let ((company-minimum-prefix-length 0)) - (company-auto-begin)) + (or company-candidates + (company-auto-begin))) (unless company-candidates (setq company--manual-action nil)))) @@ -1364,6 +1389,7 @@ from the rest of the back-ends in the group, if any, will be left at the end." ((and (or (not (company-require-match-p)) ;; Don't require match if the new prefix ;; doesn't continue the old one, and the latter was a match. + (not (stringp new-prefix)) (<= (length new-prefix) (length company-prefix))) (member company-prefix company-candidates)) ;; Last input was a success, @@ -1441,9 +1467,6 @@ from the rest of the back-ends in the group, if any, will be left at the end." (message "No completion found")) (when company--manual-action (setq company--manual-prefix prefix)) - (if (symbolp backend) - (setq company-lighter (concat " " (symbol-name backend))) - (company--update-group-lighter (car c))) (company-update-candidates c) (run-hook-with-args 'company-completion-started-hook (company-explicit-action-p)) @@ -1453,7 +1476,8 @@ from the rest of the back-ends in the group, if any, will be left at the end." (defun company--perform () (or (and company-candidates (company--continue)) (and (company--should-complete) (company--begin-new))) - (when company-candidates + (if (not company-candidates) + (setq company-backend nil) (setq company-point (point) company--point-max (point-max)) (company-ensure-emulation-alist) @@ -1480,7 +1504,6 @@ from the rest of the back-ends in the group, if any, will be left at the end." company-selection-changed nil company--manual-action nil company--manual-prefix nil - company-lighter company-default-lighter company--point-max nil company-point nil) (when company-timer @@ -1504,7 +1527,7 @@ from the rest of the back-ends in the group, if any, will be left at the end." (defun company-pre-command () (unless (company-keep this-command) - (condition-case err + (condition-case-unless-debug err (when company-candidates (company-call-frontends 'pre-command) (unless (company--should-continue) @@ -1518,8 +1541,15 @@ from the rest of the back-ends in the group, if any, will be left at the end." (company-uninstall-map)) (defun company-post-command () + (when (null this-command) + ;; Happens when the user presses `C-g' while inside + ;; `flyspell-post-command-hook', for example. + ;; Or any other `post-command-hook' function that can call `sit-for', + ;; or any quittable timer function. + (company-abort) + (setq this-command 'company-abort)) (unless (company-keep this-command) - (condition-case err + (condition-case-unless-debug err (progn (unless (equal (point) company-point) (let (company-idle-delay) ; Against misbehavior while debugging. @@ -1556,15 +1586,22 @@ from the rest of the back-ends in the group, if any, will be left at the end." ;;; search ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defvar-local company-search-string nil) +(defvar-local company-search-string "") -(defvar-local company-search-lighter " Search: \"\"") +(defvar company-search-lighter '(" " + (company-search-filtering "Filter" "Search") + ": \"" + company-search-string + "\"")) -(defvar-local company-search-old-map nil) +(defvar-local company-search-filtering nil + "Non-nil to filter the completion candidates by the search string") -(defvar-local company-search-old-selection 0) +(defvar-local company--search-old-selection 0) -(defun company-search (text lines) +(defvar-local company--search-old-changed nil) + +(defun company--search (text lines) (let ((quoted (regexp-quote text)) (i 0)) (cl-dolist (line lines) @@ -1572,26 +1609,48 @@ from the rest of the back-ends in the group, if any, will be left at the end." (cl-return i)) (cl-incf i)))) +(defun company-search-keypad () + (interactive) + (let* ((name (symbol-name last-command-event)) + (last-command-event (aref name (1- (length name))))) + (company-search-printing-char))) + (defun company-search-printing-char () (interactive) - (company-search-assert-enabled) - (setq company-search-string - (concat (or company-search-string "") (string last-command-event)) - company-search-lighter (concat " Search: \"" company-search-string - "\"")) - (let ((pos (company-search company-search-string - (nthcdr company-selection company-candidates)))) + (company--search-assert-enabled) + (let ((ss (concat company-search-string (string last-command-event)))) + (when company-search-filtering + (company--search-update-predicate ss)) + (company--search-update-string ss))) + +(defun company--search-update-predicate (&optional ss) + (let* ((company-candidates-predicate + (and (not (string= ss "")) + company-search-filtering + (lambda (candidate) (string-match ss candidate)))) + (cc (company-calculate-candidates company-prefix))) + (unless cc (error "No match")) + (company-update-candidates cc))) + +(defun company--search-update-string (new) + (let* ((pos (company--search new (nthcdr company-selection company-candidates)))) (if (null pos) (ding) + (setq company-search-string new) (company-set-selection (+ company-selection pos) t)))) +(defun company--search-assert-input () + (company--search-assert-enabled) + (when (string= company-search-string "") + (error "Empty search string"))) + (defun company-search-repeat-forward () "Repeat the incremental search in completion candidates forward." (interactive) - (company-search-assert-enabled) - (let ((pos (company-search company-search-string - (cdr (nthcdr company-selection - company-candidates))))) + (company--search-assert-input) + (let ((pos (company--search company-search-string + (cdr (nthcdr company-selection + company-candidates))))) (if (null pos) (ding) (company-set-selection (+ company-selection pos 1) t)))) @@ -1599,56 +1658,48 @@ from the rest of the back-ends in the group, if any, will be left at the end." (defun company-search-repeat-backward () "Repeat the incremental search in completion candidates backwards." (interactive) - (company-search-assert-enabled) - (let ((pos (company-search company-search-string - (nthcdr (- company-candidates-length - company-selection) - (reverse company-candidates))))) + (company--search-assert-input) + (let ((pos (company--search company-search-string + (nthcdr (- company-candidates-length + company-selection) + (reverse company-candidates))))) (if (null pos) (ding) (company-set-selection (- company-selection pos 1) t)))) -(defun company-create-match-predicate () - (setq company-candidates-predicate - `(lambda (candidate) - ,(if company-candidates-predicate - `(and (string-match ,company-search-string candidate) - (funcall ,company-candidates-predicate - candidate)) - `(string-match ,company-search-string candidate)))) - (company-update-candidates - (company-apply-predicate company-candidates company-candidates-predicate)) - ;; Invalidate cache. - (setq company-candidates-cache (cons company-prefix company-candidates))) - -(defun company-filter-printing-char () +(defun company-search-toggle-filtering () + "Toggle `company-search-filtering'." (interactive) - (company-search-assert-enabled) - (company-search-printing-char) - (company-create-match-predicate) - (company-call-frontends 'update)) - -(defun company-search-kill-others () - "Limit the completion candidates to the ones matching the search string." - (interactive) - (company-search-assert-enabled) - (company-create-match-predicate) - (company-search-mode 0) - (company-call-frontends 'update)) + (company--search-assert-enabled) + (setq company-search-filtering (not company-search-filtering)) + (let ((ss company-search-string)) + (company--search-update-predicate ss) + (company--search-update-string ss))) (defun company-search-abort () "Abort searching the completion candidates." (interactive) - (company-search-assert-enabled) - (company-set-selection company-search-old-selection t) - (company-search-mode 0)) + (company--search-assert-enabled) + (company-search-mode 0) + (company-set-selection company--search-old-selection t) + (setq company-selection-changed company--search-old-changed)) (defun company-search-other-char () (interactive) - (company-search-assert-enabled) + (company--search-assert-enabled) (company-search-mode 0) (company--unread-last-input)) +(defun company-search-delete-char () + (interactive) + (company--search-assert-enabled) + (if (string= company-search-string "") + (ding) + (let ((ss (substring company-search-string 0 -1))) + (when company-search-filtering + (company--search-update-predicate ss)) + (company--search-update-string ss)))) + (defvar company-search-map (let ((i 0) (keymap (make-keymap))) @@ -1669,18 +1720,26 @@ from the rest of the back-ends in the group, if any, will be left at the end." (while (< i 256) (define-key keymap (vector i) 'company-search-printing-char) (cl-incf i)) + (dotimes (i 10) + (define-key keymap (read (format "[kp-%s]" i)) 'company-search-keypad)) (let ((meta-map (make-sparse-keymap))) (define-key keymap (char-to-string meta-prefix-char) meta-map) (define-key keymap [escape] meta-map)) (define-key keymap (vector meta-prefix-char t) 'company-search-other-char) + (define-key keymap (kbd "M-n") 'company-select-next) + (define-key keymap (kbd "M-p") 'company-select-previous) + (define-key keymap (kbd "") 'company-select-next-or-abort) + (define-key keymap (kbd "") 'company-select-previous-or-abort) (define-key keymap "\e\e\e" 'company-search-other-char) (define-key keymap [escape escape escape] 'company-search-other-char) - (define-key keymap (kbd "DEL") 'company-search-other-char) - + (define-key keymap (kbd "DEL") 'company-search-delete-char) + (define-key keymap [backspace] 'company-search-delete-char) (define-key keymap "\C-g" 'company-search-abort) (define-key keymap "\C-s" 'company-search-repeat-forward) (define-key keymap "\C-r" 'company-search-repeat-backward) - (define-key keymap "\C-o" 'company-search-kill-others) + (define-key keymap "\C-o" 'company-search-toggle-filtering) + (dotimes (i 10) + (define-key keymap (read-kbd-macro (format "M-%d" i)) 'company-complete-number)) keymap) "Keymap used for incrementally searching the completion candidates.") @@ -1692,15 +1751,21 @@ Don't start this directly, use `company-search-candidates' or (if company-search-mode (if (company-manual-begin) (progn - (setq company-search-old-selection company-selection) - (company-call-frontends 'update)) + (setq company--search-old-selection company-selection + company--search-old-changed company-selection-changed) + (company-call-frontends 'update) + (company-enable-overriding-keymap company-search-map)) (setq company-search-mode nil)) (kill-local-variable 'company-search-string) - (kill-local-variable 'company-search-lighter) - (kill-local-variable 'company-search-old-selection) + (kill-local-variable 'company-search-filtering) + (kill-local-variable 'company--search-old-selection) + (kill-local-variable 'company--search-old-changed) + (when company-backend + (company--search-update-predicate "") + (company-call-frontends 'update)) (company-enable-overriding-keymap company-active-map))) -(defun company-search-assert-enabled () +(defun company--search-assert-enabled () (company-assert-enabled) (unless company-search-mode (company-uninstall-map) @@ -1713,14 +1778,14 @@ Don't start this directly, use `company-search-candidates' or - `company-search-repeat-forward' (\\[company-search-repeat-forward]) - `company-search-repeat-backward' (\\[company-search-repeat-backward]) - `company-search-abort' (\\[company-search-abort]) +- `company-search-delete-char' (\\[company-search-delete-char]) Regular characters are appended to the search string. -The command `company-search-kill-others' (\\[company-search-kill-others]) -uses the search string to limit the completion candidates." +The command `company-search-toggle-filtering' (\\[company-search-toggle-filtering]) +uses the search string to filter the completion candidates." (interactive) - (company-search-mode 1) - (company-enable-overriding-keymap company-search-map)) + (company-search-mode 1)) (defvar company-filter-map (let ((keymap (make-keymap))) @@ -1733,10 +1798,10 @@ uses the search string to limit the completion candidates." (defun company-filter-candidates () "Start filtering the completion candidates incrementally. This works the same way as `company-search-candidates' immediately -followed by `company-search-kill-others' after each input." +followed by `company-search-toggle-filtering'." (interactive) (company-search-mode 1) - (company-enable-overriding-keymap company-filter-map)) + (setq company-search-filtering t)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1770,6 +1835,20 @@ and invoke the normal binding." (company-abort) (company--unread-last-input))) +(defun company-next-page () + "Select the candidate one page further." + (interactive) + (when (company-manual-begin) + (company-set-selection (+ company-selection + company-tooltip-limit)))) + +(defun company-previous-page () + "Select the candidate one page earlier." + (interactive) + (when (company-manual-begin) + (company-set-selection (- company-selection + company-tooltip-limit)))) + (defvar company-pseudo-tooltip-overlay) (defvar company-tooltip-offset) @@ -1840,6 +1919,16 @@ and invoke the normal binding." (when company-common (company--insert-candidate company-common))))) +(defun company-complete-common-or-cycle () + "Insert the common part of all candidates, or select the next one." + (interactive) + (when (company-manual-begin) + (let ((tick (buffer-chars-modified-tick))) + (call-interactively 'company-complete-common) + (when (eq tick (buffer-chars-modified-tick)) + (let ((company-selection-wrap-around t)) + (call-interactively 'company-select-next)))))) + (defun company-complete () "Insert the common part of all candidates or the current selection. The first time this is called, the common part is inserted, the second @@ -1854,18 +1943,26 @@ inserted." (setq this-command 'company-complete-common)))) (defun company-complete-number (n) - "Insert the Nth candidate. + "Insert the Nth candidate visible in the tooltip. To show the number next to the candidates in some back-ends, enable `company-show-numbers'. When called interactively, uses the last typed character, stripping the modifiers. That character must be a digit." (interactive - (list (let ((n (- (event-basic-type last-command-event) ?0))) + (list (let* ((type (event-basic-type last-command-event)) + (char (if (characterp type) + ;; Number on the main row. + type + ;; Keypad number, if bound directly. + (car (last (string-to-list (symbol-name type)))))) + (n (- char ?0))) (if (zerop n) 10 n)))) (when (company-manual-begin) - (and (or (< n 1) (> n company-candidates-length)) + (and (or (< n 1) (> n (- company-candidates-length + company-tooltip-offset))) (error "No candidate number %d" n)) (cl-decf n) - (company-finish (nth n company-candidates)))) + (company-finish (nth (+ n company-tooltip-offset) + company-candidates)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -2088,7 +2185,9 @@ If SHOW-VERSION is non-nil, show the version in the echo area." (defun company-fill-propertize (value annotation width selected left right) (let* ((margin (length left)) (common (or (company-call-backend 'match value) - (length company-common))) + (if company-common + (string-width company-common) + 0))) (ann-ralign company-tooltip-align-annotations) (ann-truncate (< width (+ (length value) (length annotation) @@ -2128,16 +2227,15 @@ If SHOW-VERSION is non-nil, show the version in the echo area." mouse-face company-tooltip-mouse) line)) (when selected - (if (and company-search-string + (if (and (not (string= company-search-string "")) (string-match (regexp-quote company-search-string) value (length company-prefix))) (let ((beg (+ margin (match-beginning 0))) - (end (+ margin (match-end 0)))) - (add-text-properties beg end '(face company-tooltip-search) - line) - (when (< beg common) - (add-text-properties beg common - '(face company-tooltip-common-selection) + (end (+ margin (match-end 0))) + (width (- width (length right)))) + (when (< beg width) + (add-text-properties beg (min end width) + '(face company-tooltip-search) line))) (add-text-properties 0 width '(face company-tooltip-selection mouse-face company-tooltip-selection) @@ -2148,12 +2246,32 @@ If SHOW-VERSION is non-nil, show the version in the echo area." line))) line)) +(defun company--clean-string (str) + (replace-regexp-in-string + "\\([^[:graph:] ]\\)\\|\\(\ufeff\\)\\|[[:multibyte:]]" + (lambda (match) + (cond + ((match-beginning 1) + ;; FIXME: Better char for 'non-printable'? + ;; We shouldn't get any of these, but sometimes we might. + "\u2017") + ((match-beginning 2) + ;; Zero-width non-breakable space. + "") + ((> (string-width match) 1) + (concat + (make-string (1- (string-width match)) ?\ufeff) + match)) + (t match))) + str)) + ;;; replace (defun company-buffer-lines (beg end) (goto-char beg) (let (lines lines-moved) - (while (and (> (setq lines-moved (vertical-motion 1)) 0) + (while (and (not (eobp)) ; http://debbugs.gnu.org/19553 + (> (setq lines-moved (vertical-motion 1)) 0) (<= (point) end)) (let ((bound (min end (1- (point))))) ;; A visual line can contain several physical lines (e.g. with outline's @@ -2183,6 +2301,30 @@ If SHOW-VERSION is non-nil, show the version in the echo area." limit (length lst))) +(defsubst company--window-height () + (if (fboundp 'window-screen-lines) + (floor (window-screen-lines)) + (window-body-height))) + +(defun company--window-width () + (let ((ww (window-body-width))) + ;; Account for the line continuation column. + (when (zerop (cadr (window-fringes))) + (cl-decf ww)) + (unless (or (display-graphic-p) + (version< "24.3.1" emacs-version)) + ;; Emacs 24.3 and earlier included margins + ;; in window-width when in TTY. + (cl-decf ww + (let ((margins (window-margins))) + (+ (or (car margins) 0) + (or (cdr margins) 0))))) + (when (and word-wrap + (version< emacs-version "24.4.51.5")) + ;; http://debbugs.gnu.org/18384 + (cl-decf ww)) + ww)) + (defun company--replacement-string (lines old column nl &optional align-top) (cl-decf column company-tooltip-margin) @@ -2207,7 +2349,8 @@ If SHOW-VERSION is non-nil, show the version in the echo area." (while old (push (company-modify-line (pop old) (company--offset-line (pop lines) offset) - column) new)) + column) + new)) ;; Append whole new lines. (while lines (push (concat (company-space-string column) @@ -2229,7 +2372,6 @@ If SHOW-VERSION is non-nil, show the version in the echo area." (defun company--create-lines (selection limit) (let ((len company-candidates-length) - (numbered 99999) (window-width (company--window-width)) lines width @@ -2271,9 +2413,12 @@ If SHOW-VERSION is non-nil, show the version in the echo area." (dotimes (_ len) (let* ((value (pop lines-copy)) (annotation (company-call-backend 'annotation value))) - (when (and annotation company-tooltip-align-annotations) - ;; `lisp-completion-at-point' adds a space. - (setq annotation (comment-string-strip annotation t nil))) + (setq value (company--clean-string (company-reformat value))) + (when annotation + (when company-tooltip-align-annotations + ;; `lisp-completion-at-point' adds a space. + (setq annotation (comment-string-strip annotation t nil))) + (setq annotation (company--clean-string annotation))) (push (cons value annotation) items) (setq width (max (+ (length value) (if (and annotation company-tooltip-align-annotations) @@ -2283,22 +2428,19 @@ If SHOW-VERSION is non-nil, show the version in the echo area." (setq width (min window-width (max company-tooltip-minimum-width - (if (and company-show-numbers - (< company-tooltip-offset 10)) + (if company-show-numbers (+ 2 width) width)))) - ;; number can make tooltip too long - (when company-show-numbers - (setq numbered company-tooltip-offset)) - - (let ((items (nreverse items)) new) + (let ((items (nreverse items)) + (numbered (if company-show-numbers 0 99999)) + new) (when previous (push (company--scrollpos-line previous width) new)) (dotimes (i len) (let* ((item (pop items)) - (str (company-reformat (car item))) + (str (car item)) (annotation (cdr item)) (right (company-space-string company-tooltip-margin)) (width width)) @@ -2342,26 +2484,6 @@ If SHOW-VERSION is non-nil, show the version in the echo area." ;; show -(defsubst company--window-height () - (if (fboundp 'window-screen-lines) - (floor (window-screen-lines)) - (window-body-height))) - -(defsubst company--window-width () - (let ((ww (window-body-width))) - ;; Account for the line continuation column. - (when (zerop (cadr (window-fringes))) - (cl-decf ww)) - (unless (or (display-graphic-p) - (version< "24.3.1" emacs-version)) - ;; Emacs 24.3 and earlier included margins - ;; in window-width when in TTY. - (cl-decf ww - (let ((margins (window-margins))) - (+ (or (car margins) 0) - (or (cdr margins) 0))))) - ww)) - (defun company--pseudo-tooltip-height () "Calculate the appropriate tooltip height. Returns a negative number if the tooltip should be displayed above point." @@ -2493,8 +2615,6 @@ Returns a negative number if the tooltip should be displayed above point." (defun company-preview-show-at-point (pos) (company-preview-hide) - (setq company-preview-overlay (make-overlay pos pos)) - (let ((completion (nth company-selection company-candidates))) (setq completion (propertize completion 'face 'company-preview)) (add-text-properties 0 (length company-common) @@ -2512,11 +2632,26 @@ Returns a negative number if the tooltip should be displayed above point." (and (equal pos (point)) (not (equal completion "")) - (add-text-properties 0 1 '(cursor t) completion)) + (add-text-properties 0 1 '(cursor 1) completion)) - (let ((ov company-preview-overlay)) - (overlay-put ov 'after-string completion) - (overlay-put ov 'window (selected-window))))) + (let* ((beg pos) + (pto company-pseudo-tooltip-overlay) + (ptf-workaround (and + pto + (char-before pos) + (eq pos (overlay-start pto))))) + ;; Try to accomodate for the pseudo-tooltip overlay, + ;; which may start at the same position if it's at eol. + (when ptf-workaround + (cl-decf beg) + (setq completion (concat (buffer-substring beg pos) completion))) + + (setq company-preview-overlay (make-overlay beg pos)) + + (let ((ov company-preview-overlay)) + (overlay-put ov (if ptf-workaround 'display 'after-string) + completion) + (overlay-put ov 'window (selected-window)))))) (defun company-preview-hide () (when company-preview-overlay diff --git a/elpa/company-0.8.12/test/all.el b/elpa/company-0.8.12/test/all.el new file mode 100644 index 0000000..6d64a62 --- /dev/null +++ b/elpa/company-0.8.12/test/all.el @@ -0,0 +1,28 @@ +;;; all-tests.el --- company-mode tests -*- lexical-binding: t -*- + +;; Copyright (C) 2015 Free Software Foundation, Inc. + +;; Author: Dmitry Gutov + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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 of the License, or +;; (at your option) any later version. + +;; GNU Emacs 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 GNU Emacs. If not, see . + +(defvar company-test-path + (file-name-directory (or load-file-name buffer-file-name))) + +(require 'ert) + +(dolist (test-file (directory-files company-test-path t "-tests.el$")) + (load test-file nil t)) diff --git a/elpa/company-0.8.12/test/async-tests.el b/elpa/company-0.8.12/test/async-tests.el new file mode 100644 index 0000000..c548898 --- /dev/null +++ b/elpa/company-0.8.12/test/async-tests.el @@ -0,0 +1,217 @@ +;;; async-tests.el --- company-mode tests -*- lexical-binding: t -*- + +;; Copyright (C) 2015 Free Software Foundation, Inc. + +;; Author: Dmitry Gutov + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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 of the License, or +;; (at your option) any later version. + +;; GNU Emacs 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 GNU Emacs. If not, see . + +(require 'company-tests) + +(defun company-async-backend (command &optional _) + (pcase command + (`prefix "foo") + (`candidates + (cons :async + (lambda (cb) + (run-with-timer 0.05 nil + #'funcall cb '("abc" "abd"))))))) + +(ert-deftest company-call-backend-forces-sync () + (let ((company-backend 'company-async-backend) + (company-async-timeout 0.1)) + (should (equal '("abc" "abd") (company-call-backend 'candidates))))) + +(ert-deftest company-call-backend-errors-on-timeout () + (with-temp-buffer + (let* ((company-backend (lambda (command &optional _arg) + (pcase command + (`candidates (cons :async 'ignore))))) + (company-async-timeout 0.1) + (err (should-error (company-call-backend 'candidates "foo")))) + (should (string-match-p "async timeout" (cadr err)))))) + +(ert-deftest company-call-backend-raw-passes-return-value-verbatim () + (let ((company-backend 'company-async-backend)) + (should (equal "foo" (company-call-backend-raw 'prefix))) + (should (equal :async (car (company-call-backend-raw 'candidates "foo")))) + (should (equal 'closure (cadr (company-call-backend-raw 'candidates "foo")))))) + +(ert-deftest company-manual-begin-forces-async-candidates-to-sync () + (with-temp-buffer + (company-mode) + (let (company-frontends + company-transformers + (company-backends (list 'company-async-backend))) + (company-manual-begin) + (should (equal "foo" company-prefix)) + (should (equal '("abc" "abd") company-candidates))))) + +(ert-deftest company-idle-begin-allows-async-candidates () + (with-temp-buffer + (company-mode) + (let (company-frontends + company-transformers + (company-backends (list 'company-async-backend))) + (company-idle-begin (current-buffer) (selected-window) + (buffer-chars-modified-tick) (point)) + (should (null company-candidates)) + (sleep-for 0.1) + (should (equal "foo" company-prefix)) + (should (equal '("abc" "abd") company-candidates))))) + +(ert-deftest company-idle-begin-cancels-async-candidates-if-buffer-changed () + (with-temp-buffer + (company-mode) + (let (company-frontends + (company-backends (list 'company-async-backend))) + (company-idle-begin (current-buffer) (selected-window) + (buffer-chars-modified-tick) (point)) + (should (null company-candidates)) + (insert "a") + (sleep-for 0.1) + (should (null company-candidates))))) + +(ert-deftest company-idle-begin-async-allows-immediate-callbacks () + (with-temp-buffer + (company-mode) + (let (company-frontends + (company-backends + (list (lambda (command &optional arg) + (pcase command + (`prefix (buffer-substring (point-min) (point))) + (`candidates + (let ((c (all-completions arg '("abc" "def")))) + (cons :async + (lambda (cb) (funcall cb c))))) + (`no-cache t))))) + (company-minimum-prefix-length 0)) + (company-idle-begin (current-buffer) (selected-window) + (buffer-chars-modified-tick) (point)) + (should (equal '("abc" "def") company-candidates)) + (let ((last-command-event ?a)) + (company-call 'self-insert-command 1)) + (should (equal '("abc") company-candidates))))) + +(ert-deftest company-multi-backend-forces-prefix-to-sync () + (with-temp-buffer + (let ((company-backend (list 'ignore + (lambda (command) + (should (eq command 'prefix)) + (cons :async + (lambda (cb) + (run-with-timer + 0.01 nil + (lambda () (funcall cb nil)))))) + (lambda (command) + (should (eq command 'prefix)) + "foo")))) + (should (equal "foo" (company-call-backend-raw 'prefix)))) + (let ((company-backend (list (lambda (_command) + (cons :async + (lambda (cb) + (run-with-timer + 0.01 nil + (lambda () (funcall cb "bar")))))) + (lambda (_command) + "foo")))) + (should (equal "bar" (company-call-backend-raw 'prefix)))))) + +(ert-deftest company-multi-backend-merges-deferred-candidates () + (with-temp-buffer + (let* ((immediate (lambda (command &optional _) + (pcase command + (`prefix "foo") + (`candidates + (cons :async + (lambda (cb) (funcall cb '("f")))))))) + (company-backend (list 'ignore + (lambda (command &optional arg) + (pcase command + (`prefix "foo") + (`candidates + (should (equal arg "foo")) + (cons :async + (lambda (cb) + (run-with-timer + 0.01 nil + (lambda () (funcall cb '("a" "b"))))))))) + (lambda (command &optional _) + (pcase command + (`prefix "foo") + (`candidates '("c" "d" "e")))) + immediate))) + (should (equal :async (car (company-call-backend-raw 'candidates "foo")))) + (should (equal '("a" "b" "c" "d" "e" "f") + (company-call-backend 'candidates "foo"))) + (let ((company-backend (list immediate))) + (should (equal '("f") (company-call-backend 'candidates "foo"))))))) + +(ert-deftest company-multi-backend-merges-deferred-candidates-2 () + (with-temp-buffer + (let ((company-backend (list (lambda (command &optional _) + (pcase command + (`prefix "foo") + (`candidates + (cons :async + (lambda (cb) (funcall cb '("a" "b"))))))) + (lambda (command &optional _) + (pcase command + (`prefix "foo") + (`candidates + (cons :async + (lambda (cb) (funcall cb '("c" "d"))))))) + (lambda (command &optional _) + (pcase command + (`prefix "foo") + (`candidates + (cons :async + (lambda (cb) (funcall cb '("e" "f")))))))))) + (should (equal :async (car (company-call-backend-raw 'candidates "foo")))) + (should (equal '("a" "b" "c" "d" "e" "f") + (company-call-backend 'candidates "foo")))))) + +(ert-deftest company-multi-backend-merges-deferred-candidates-3 () + (with-temp-buffer + (let ((company-backend (list (lambda (command &optional _) + (pcase command + (`prefix "foo") + (`candidates + (cons :async + (lambda (cb) (funcall cb '("a" "b"))))))) + (lambda (command &optional _) + (pcase command + (`prefix "foo") + (`candidates + (cons :async + (lambda (cb) + (run-with-timer + 0.01 nil + (lambda () + (funcall cb '("c" "d"))))))))) + (lambda (command &optional _) + (pcase command + (`prefix "foo") + (`candidates + (cons :async + (lambda (cb) + (run-with-timer + 0.01 nil + (lambda () + (funcall cb '("e" "f")))))))))))) + (should (equal :async (car (company-call-backend-raw 'candidates "foo")))) + (should (equal '("a" "b" "c" "d" "e" "f") + (company-call-backend 'candidates "foo")))))) diff --git a/elpa/company-0.8.12/test/clang-tests.el b/elpa/company-0.8.12/test/clang-tests.el new file mode 100644 index 0000000..09ba114 --- /dev/null +++ b/elpa/company-0.8.12/test/clang-tests.el @@ -0,0 +1,46 @@ +;;; clang-tests.el --- company-mode tests -*- lexical-binding: t -*- + +;; Copyright (C) 2015 Free Software Foundation, Inc. + +;; Author: Dmitry Gutov + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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 of the License, or +;; (at your option) any later version. + +;; GNU Emacs 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 GNU Emacs. If not, see . + +(require 'company-tests) +(require 'company-clang) + +(ert-deftest company-clang-objc-templatify () + (with-temp-buffer + (let ((text "createBookWithTitle:andAuthor:")) + (insert text) + (company-clang-objc-templatify text) + (should (equal "createBookWithTitle:arg0 andAuthor:arg1" (buffer-string))) + (should (looking-at "arg0")) + (should (null (overlay-get (company-template-field-at) 'display)))))) + +(ert-deftest company-clang-simple-annotation () + (let ((str (propertize + "foo" 'meta + "wchar_t * wmemchr(wchar_t *__p, wchar_t __c, size_t __n)"))) + (should (equal (company-clang 'annotation str) + "(wchar_t *__p, wchar_t __c, size_t __n)")))) + +(ert-deftest company-clang-generic-annotation () + (let ((str (propertize + "foo" 'meta + "shared_ptr<_Tp> make_shared(_Args &&__args...)"))) + (should (equal (company-clang 'annotation str) + "(_Args &&__args...)")))) diff --git a/elpa/company-0.8.12/test/core-tests.el b/elpa/company-0.8.12/test/core-tests.el new file mode 100644 index 0000000..13e547e --- /dev/null +++ b/elpa/company-0.8.12/test/core-tests.el @@ -0,0 +1,481 @@ +;;; core-tests.el --- company-mode tests -*- lexical-binding: t -*- + +;; Copyright (C) 2015 Free Software Foundation, Inc. + +;; Author: Dmitry Gutov + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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 of the License, or +;; (at your option) any later version. + +;; GNU Emacs 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 GNU Emacs. If not, see . + +(require 'company-tests) + +(ert-deftest company-good-prefix () + (let ((company-minimum-prefix-length 5) + company-abort-manual-when-too-short + company--manual-action ;idle begin + (company-selection-changed t)) ;has no effect + (should (eq t (company--good-prefix-p "!@#$%"))) + (should (eq nil (company--good-prefix-p "abcd"))) + (should (eq nil (company--good-prefix-p 'stop))) + (should (eq t (company--good-prefix-p '("foo" . 5)))) + (should (eq nil (company--good-prefix-p '("foo" . 4)))) + (should (eq t (company--good-prefix-p '("foo" . t)))))) + +(ert-deftest company--manual-prefix-set-and-unset () + (with-temp-buffer + (insert "ab") + (company-mode) + (let (company-frontends + (company-backends + (list (lambda (command &optional _) + (cl-case command + (prefix (buffer-substring (point-min) (point))) + (candidates '("abc" "abd"))))))) + (company-manual-begin) + (should (equal "ab" company--manual-prefix)) + (company-abort) + (should (null company--manual-prefix))))) + +(ert-deftest company-abort-manual-when-too-short () + (let ((company-minimum-prefix-length 5) + (company-abort-manual-when-too-short t) + (company-selection-changed t)) ;has not effect + (let ((company--manual-action nil)) ;idle begin + (should (eq t (company--good-prefix-p "!@#$%"))) + (should (eq t (company--good-prefix-p '("foo" . 5)))) + (should (eq t (company--good-prefix-p '("foo" . t))))) + (let ((company--manual-action t) + (company--manual-prefix "abc")) ;manual begin from this prefix + (should (eq t (company--good-prefix-p "!@#$"))) + (should (eq nil (company--good-prefix-p "ab"))) + (should (eq nil (company--good-prefix-p 'stop))) + (should (eq t (company--good-prefix-p '("foo" . 4)))) + (should (eq t (company--good-prefix-p "abcd"))) + (should (eq t (company--good-prefix-p "abc"))) + (should (eq t (company--good-prefix-p '("bar" . t))))))) + +(ert-deftest company-common-with-non-prefix-completion () + (let ((company-backend #'ignore) + (company-prefix "abc") + company-candidates + company-candidates-length + company-candidates-cache + company-common) + (company-update-candidates '("abc" "def-abc")) + (should (null company-common)) + (company-update-candidates '("abc" "abe-c")) + (should (null company-common)) + (company-update-candidates '("abcd" "abcde" "abcdf")) + (should (equal "abcd" company-common)))) + +(ert-deftest company-multi-backend-with-lambdas () + (let ((company-backend + (list (lambda (command &optional _ &rest _r) + (cl-case command + (prefix "z") + (candidates '("a" "b")))) + (lambda (command &optional _ &rest _r) + (cl-case command + (prefix "z") + (candidates '("c" "d"))))))) + (should (equal (company-call-backend 'candidates "z") '("a" "b" "c" "d"))))) + +(ert-deftest company-multi-backend-filters-backends-by-prefix () + (let ((company-backend + (list (lambda (command &optional _ &rest _r) + (cl-case command + (prefix (cons "z" t)) + (candidates '("a" "b")))) + (lambda (command &optional _ &rest _r) + (cl-case command + (prefix "t") + (candidates '("c" "d")))) + (lambda (command &optional _ &rest _r) + (cl-case command + (prefix "z") + (candidates '("e" "f"))))))) + (should (equal (company-call-backend 'candidates "z") '("a" "b" "e" "f"))))) + +(ert-deftest company-multi-backend-remembers-candidate-backend () + (let ((company-backend + (list (lambda (command &optional _) + (cl-case command + (ignore-case nil) + (annotation "1") + (candidates '("a" "c")) + (post-completion "13"))) + (lambda (command &optional _) + (cl-case command + (ignore-case t) + (annotation "2") + (candidates '("b" "d")) + (post-completion "42"))) + (lambda (command &optional _) + (cl-case command + (annotation "3") + (candidates '("e")) + (post-completion "74")))))) + (let ((candidates (company-calculate-candidates nil))) + (should (equal candidates '("a" "b" "c" "d" "e"))) + (should (equal t (company-call-backend 'ignore-case))) + (should (equal "1" (company-call-backend 'annotation (nth 0 candidates)))) + (should (equal "2" (company-call-backend 'annotation (nth 1 candidates)))) + (should (equal "13" (company-call-backend 'post-completion (nth 2 candidates)))) + (should (equal "42" (company-call-backend 'post-completion (nth 3 candidates)))) + (should (equal "3" (company-call-backend 'annotation (nth 4 candidates)))) + (should (equal "74" (company-call-backend 'post-completion (nth 4 candidates))))))) + +(ert-deftest company-multi-backend-handles-keyword-with () + (let ((primo (lambda (command &optional _) + (cl-case command + (prefix "a") + (candidates '("abb" "abc" "abd"))))) + (secundo (lambda (command &optional _) + (cl-case command + (prefix "a") + (candidates '("acc" "acd")))))) + (let ((company-backend (list 'ignore 'ignore :with secundo))) + (should (null (company-call-backend 'prefix)))) + (let ((company-backend (list 'ignore primo :with secundo))) + (should (equal "a" (company-call-backend 'prefix))) + (should (equal '("abb" "abc" "abd" "acc" "acd") + (company-call-backend 'candidates "a")))))) + +(ert-deftest company-begin-backend-failure-doesnt-break-company-backends () + (with-temp-buffer + (insert "a") + (company-mode) + (should-error + (company-begin-backend #'ignore)) + (let (company-frontends + (company-backends + (list (lambda (command &optional _) + (cl-case command + (prefix "a") + (candidates '("a" "ab" "ac"))))))) + (let (this-command) + (company-call 'complete)) + (should (eq 3 company-candidates-length))))) + +(ert-deftest company-require-match-explicit () + (with-temp-buffer + (insert "ab") + (company-mode) + (let (company-frontends + (company-require-match 'company-explicit-action-p) + (company-backends + (list (lambda (command &optional _) + (cl-case command + (prefix (buffer-substring (point-min) (point))) + (candidates '("abc" "abd"))))))) + (let (this-command) + (company-complete)) + (let ((last-command-event ?e)) + (company-call 'self-insert-command 1)) + (should (eq 2 company-candidates-length)) + (should (eq 3 (point)))))) + +(ert-deftest company-dont-require-match-when-idle () + (with-temp-buffer + (insert "ab") + (company-mode) + (let (company-frontends + (company-minimum-prefix-length 2) + (company-require-match 'company-explicit-action-p) + (company-backends + (list (lambda (command &optional _) + (cl-case command + (prefix (buffer-substring (point-min) (point))) + (candidates '("abc" "abd"))))))) + (company-idle-begin (current-buffer) (selected-window) + (buffer-chars-modified-tick) (point)) + (should (eq 2 company-candidates-length)) + (let ((last-command-event ?e)) + (company-call 'self-insert-command 1)) + (should (eq nil company-candidates-length)) + (should (eq 4 (point)))))) + +(ert-deftest company-dont-require-match-if-was-a-match-and-old-prefix-ended () + (with-temp-buffer + (insert "ab") + (company-mode) + (let (company-frontends + company-auto-complete + (company-require-match t) + (company-backends + (list (lambda (command &optional _) + (cl-case command + (prefix (company-grab-word)) + (candidates '("abc" "ab" "abd")) + (sorted t)))))) + (let (this-command) + (company-complete)) + (let ((last-command-event ?e)) + (company-call 'self-insert-command 1)) + (should (eq 3 company-candidates-length)) + (should (eq 3 (point))) + (let ((last-command-event ? )) + (company-call 'self-insert-command 1)) + (should (null company-candidates-length)) + (should (eq 4 (point)))))) + +(ert-deftest company-dont-require-match-if-was-a-match-and-new-prefix-is-stop () + (with-temp-buffer + (company-mode) + (insert "c") + (let (company-frontends + (company-require-match t) + (company-backends + (list (lambda (command &optional _) + (cl-case command + (prefix (if (> (point) 2) + 'stop + (buffer-substring (point-min) (point)))) + (candidates '("a" "b" "c"))))))) + (let (this-command) + (company-complete)) + (should (eq 3 company-candidates-length)) + (let ((last-command-event ?e)) + (company-call 'self-insert-command 1)) + (should (not company-candidates))))) + +(ert-deftest company-should-complete-whitelist () + (with-temp-buffer + (insert "ab") + (company-mode) + (let (company-frontends + company-begin-commands + (company-backends + (list (lambda (command &optional _) + (cl-case command + (prefix (buffer-substring (point-min) (point))) + (candidates '("abc" "abd"))))))) + (let ((company-continue-commands nil)) + (let (this-command) + (company-complete)) + (company-call 'backward-delete-char 1) + (should (null company-candidates-length))) + (let ((company-continue-commands '(backward-delete-char))) + (let (this-command) + (company-complete)) + (company-call 'backward-delete-char 1) + (should (eq 2 company-candidates-length)))))) + +(ert-deftest company-should-complete-blacklist () + (with-temp-buffer + (insert "ab") + (company-mode) + (let (company-frontends + company-begin-commands + (company-backends + (list (lambda (command &optional _) + (cl-case command + (prefix (buffer-substring (point-min) (point))) + (candidates '("abc" "abd"))))))) + (let ((company-continue-commands '(not backward-delete-char))) + (let (this-command) + (company-complete)) + (company-call 'backward-delete-char 1) + (should (null company-candidates-length))) + (let ((company-continue-commands '(not backward-delete-char-untabify))) + (let (this-command) + (company-complete)) + (company-call 'backward-delete-char 1) + (should (eq 2 company-candidates-length)))))) + +(ert-deftest company-auto-complete-explicit () + (with-temp-buffer + (insert "ab") + (company-mode) + (let (company-frontends + (company-auto-complete 'company-explicit-action-p) + (company-auto-complete-chars '(? )) + (company-backends + (list (lambda (command &optional _) + (cl-case command + (prefix (buffer-substring (point-min) (point))) + (candidates '("abcd" "abef"))))))) + (let (this-command) + (company-complete)) + (let ((last-command-event ? )) + (company-call 'self-insert-command 1)) + (should (string= "abcd " (buffer-string)))))) + +(ert-deftest company-no-auto-complete-when-idle () + (with-temp-buffer + (insert "ab") + (company-mode) + (let (company-frontends + (company-auto-complete 'company-explicit-action-p) + (company-auto-complete-chars '(? )) + (company-minimum-prefix-length 2) + (company-backends + (list (lambda (command &optional _) + (cl-case command + (prefix (buffer-substring (point-min) (point))) + (candidates '("abcd" "abef"))))))) + (company-idle-begin (current-buffer) (selected-window) + (buffer-chars-modified-tick) (point)) + (let ((last-command-event ? )) + (company-call 'self-insert-command 1)) + (should (string= "ab " (buffer-string)))))) + +(ert-deftest company-clears-explicit-action-when-no-matches () + (with-temp-buffer + (company-mode) + (let (company-frontends + company-backends) + (company-call 'manual-begin) ;; fails + (should (null company-candidates)) + (should (null (company-explicit-action-p)))))) + +(ert-deftest company-ignore-case-replaces-prefix () + (with-temp-buffer + (company-mode) + (let (company-frontends + (company-backends + (list (lambda (command &optional _) + (cl-case command + (prefix (buffer-substring (point-min) (point))) + (candidates '("abcd" "abef")) + (ignore-case t)))))) + (insert "A") + (let (this-command) + (company-complete)) + (should (string= "ab" (buffer-string))) + (delete-char -2) + (insert "A") ; hack, to keep it in one test + (company-complete-selection) + (should (string= "abcd" (buffer-string)))))) + +(ert-deftest company-ignore-case-with-keep-prefix () + (with-temp-buffer + (insert "AB") + (company-mode) + (let (company-frontends + (company-backends + (list (lambda (command &optional _) + (cl-case command + (prefix (buffer-substring (point-min) (point))) + (candidates '("abcd" "abef")) + (ignore-case 'keep-prefix)))))) + (let (this-command) + (company-complete)) + (company-complete-selection) + (should (string= "ABcd" (buffer-string)))))) + +(ert-deftest company-non-prefix-completion () + (with-temp-buffer + (insert "tc") + (company-mode) + (let (company-frontends + (company-backends + (list (lambda (command &optional _) + (cl-case command + (prefix (buffer-substring (point-min) (point))) + (candidates '("tea-cup" "teal-color"))))))) + (let (this-command) + (company-complete)) + (should (string= "tc" (buffer-string))) + (company-complete-selection) + (should (string= "tea-cup" (buffer-string)))))) + +(defvar ct-sorted nil) + +(defun ct-equal-including-properties (list1 list2) + (or (and (not list1) (not list2)) + (and (ert-equal-including-properties (car list1) (car list2)) + (ct-equal-including-properties (cdr list1) (cdr list2))))) + +(ert-deftest company-strips-duplicates-within-groups () + (let* ((kvs '(("a" . "b") + ("a" . nil) + ("a" . "b") + ("a" . "c") + ("a" . "b") + ("b" . "c") + ("b" . nil) + ("a" . "b"))) + (fn (lambda (kvs) + (mapcar (lambda (kv) (propertize (car kv) 'ann (cdr kv))) + kvs))) + (company-backend + (lambda (command &optional arg) + (pcase command + (`prefix "") + (`sorted ct-sorted) + (`duplicates t) + (`annotation (get-text-property 0 'ann arg))))) + (reference '(("a" . "b") + ("a" . nil) + ("a" . "c") + ("b" . "c") + ("b" . nil) + ("a" . "b")))) + (let ((ct-sorted t)) + (should (ct-equal-including-properties + (company--preprocess-candidates (funcall fn kvs)) + (funcall fn reference)))) + (should (ct-equal-including-properties + (company--preprocess-candidates (funcall fn kvs)) + (funcall fn (butlast reference)))))) + +;;; Row and column + +(ert-deftest company-column-with-composition () + :tags '(interactive) + (with-temp-buffer + (save-window-excursion + (set-window-buffer nil (current-buffer)) + (insert "lambda ()") + (compose-region 1 (1+ (length "lambda")) "\\") + (should (= (company--column) 4))))) + +(ert-deftest company-column-with-line-prefix () + :tags '(interactive) + (with-temp-buffer + (save-window-excursion + (set-window-buffer nil (current-buffer)) + (insert "foo") + (put-text-property (point-min) (point) 'line-prefix " ") + (should (= (company--column) 5))))) + +(ert-deftest company-column-with-line-prefix-on-empty-line () + :tags '(interactive) + (with-temp-buffer + (save-window-excursion + (set-window-buffer nil (current-buffer)) + (insert "\n") + (forward-char -1) + (put-text-property (point-min) (point-max) 'line-prefix " ") + (should (= (company--column) 2))))) + +(ert-deftest company-column-with-tabs () + :tags '(interactive) + (with-temp-buffer + (save-window-excursion + (set-window-buffer nil (current-buffer)) + (insert "|\t|\t|\t(") + (let ((tab-width 8)) + (should (= (company--column) 25)))))) + +(ert-deftest company-row-with-header-line-format () + :tags '(interactive) + (with-temp-buffer + (save-window-excursion + (set-window-buffer nil (current-buffer)) + (should (= (company--row) 0)) + (setq header-line-format "aaaaaaa") + (should (= (company--row) 0))))) diff --git a/elpa/company-0.8.5/company-elisp-tests.el b/elpa/company-0.8.12/test/elisp-tests.el similarity index 97% rename from elpa/company-0.8.5/company-elisp-tests.el rename to elpa/company-0.8.12/test/elisp-tests.el index 9b7cba3..7fd02de 100644 --- a/elpa/company-0.8.5/company-elisp-tests.el +++ b/elpa/company-0.8.12/test/elisp-tests.el @@ -1,6 +1,6 @@ -;;; company-elisp-tests.el --- company-elisp tests +;;; elisp-tests.el --- company-elisp tests -;; Copyright (C) 2013-2014 Free Software Foundation, Inc. +;; Copyright (C) 2013-2015 Free Software Foundation, Inc. ;; Author: Dmitry Gutov @@ -19,12 +19,9 @@ ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs. If not, see . - -;;; Commentary: -;; - ;;; Code: +(require 'company-tests) (require 'company-elisp) (defmacro company-elisp-with-buffer (contents &rest body) diff --git a/elpa/company-0.8.12/test/frontends-tests.el b/elpa/company-0.8.12/test/frontends-tests.el new file mode 100644 index 0000000..613856e --- /dev/null +++ b/elpa/company-0.8.12/test/frontends-tests.el @@ -0,0 +1,332 @@ +;;; frontends-tests.el --- company-mode tests -*- lexical-binding: t -*- + +;; Copyright (C) 2015 Free Software Foundation, Inc. + +;; Author: Dmitry Gutov + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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 of the License, or +;; (at your option) any later version. + +;; GNU Emacs 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 GNU Emacs. If not, see . + +(require 'company-tests) + +(ert-deftest company-pseudo-tooltip-does-not-get-displaced () + :tags '(interactive) + (with-temp-buffer + (save-window-excursion + (set-window-buffer nil (current-buffer)) + (save-excursion (insert " ff")) + (company-mode) + (let ((company-frontends '(company-pseudo-tooltip-frontend)) + (company-begin-commands '(self-insert-command)) + (company-backends + (list (lambda (c &optional _) + (cl-case c (prefix "") (candidates '("a" "b" "c"))))))) + (let (this-command) + (company-call 'complete)) + (company-call 'open-line 1) + (should (eq 1 (overlay-start company-pseudo-tooltip-overlay))))))) + +(ert-deftest company-pseudo-tooltip-show () + :tags '(interactive) + (with-temp-buffer + (save-window-excursion + (set-window-buffer nil (current-buffer)) + (insert "aaaa\n bb\nccccccc\nddd") + (search-backward "bb") + (let ((col (company--column)) + (company-candidates-length 2) + (company-candidates '("123" "45")) + (company-backend 'ignore)) + (company-pseudo-tooltip-show (company--row) col 0) + (let ((ov company-pseudo-tooltip-overlay)) + ;; With margins. + (should (eq (overlay-get ov 'company-width) 5)) + ;; FIXME: Make it 2? + (should (eq (overlay-get ov 'company-height) company-tooltip-limit)) + (should (eq (overlay-get ov 'company-column) col)) + (should (string= (overlay-get ov 'company-display) + "\n 123 \nc 45 c\nddd\n"))))))) + +(ert-deftest company-pseudo-tooltip-edit-updates-width () + :tags '(interactive) + (with-temp-buffer + (set-window-buffer nil (current-buffer)) + (let ((company-candidates-length 5) + (company-candidates '("123" "45" "67" "89" "1011")) + (company-backend 'ignore) + (company-tooltip-limit 4) + (company-tooltip-offset-display 'scrollbar)) + (company-pseudo-tooltip-show (company--row) + (company--column) + 0) + (should (eq (overlay-get company-pseudo-tooltip-overlay 'company-width) + 6)) + (company-pseudo-tooltip-edit 4) + (should (eq (overlay-get company-pseudo-tooltip-overlay 'company-width) + 7))))) + +(ert-deftest company-preview-show-with-annotations () + :tags '(interactive) + (with-temp-buffer + (save-window-excursion + (set-window-buffer nil (current-buffer)) + (save-excursion (insert "\n")) + (let ((company-candidates-length 1) + (company-candidates '("123"))) + (company-preview-show-at-point (point)) + (let* ((ov company-preview-overlay) + (str (overlay-get ov 'after-string))) + (should (string= str "123")) + (should (eq (get-text-property 0 'cursor str) 1))))))) + +(ert-deftest company-pseudo-tooltip-show-with-annotations () + :tags '(interactive) + (with-temp-buffer + (save-window-excursion + (set-window-buffer nil (current-buffer)) + (insert " ") + (save-excursion (insert "\n")) + (let ((company-candidates-length 2) + (company-backend (lambda (action &optional arg &rest _ignore) + (when (eq action 'annotation) + (cdr (assoc arg '(("123" . "(4)"))))))) + (company-candidates '("123" "45")) + company-tooltip-align-annotations) + (company-pseudo-tooltip-show-at-point (point) 0) + (let ((ov company-pseudo-tooltip-overlay)) + ;; With margins. + (should (eq (overlay-get ov 'company-width) 8)) + (should (string= (overlay-get ov 'company-display) + "\n 123(4) \n 45 \n"))))))) + +(ert-deftest company-pseudo-tooltip-show-with-annotations-right-aligned () + :tags '(interactive) + (with-temp-buffer + (save-window-excursion + (set-window-buffer nil (current-buffer)) + (insert " ") + (save-excursion (insert "\n")) + (let ((company-candidates-length 3) + (company-backend (lambda (action &optional arg &rest _ignore) + (when (eq action 'annotation) + (cdr (assoc arg '(("123" . "(4)") + ("67" . "(891011)"))))))) + (company-candidates '("123" "45" "67")) + (company-tooltip-align-annotations t)) + (company-pseudo-tooltip-show-at-point (point) 0) + (let ((ov company-pseudo-tooltip-overlay)) + ;; With margins. + (should (eq (overlay-get ov 'company-width) 13)) + (should (string= (overlay-get ov 'company-display) + "\n 123 (4) \n 45 \n 67 (891011) \n"))))))) + +(ert-deftest company-create-lines-shows-numbers () + (let ((company-show-numbers t) + (company-candidates '("x" "y" "z")) + (company-candidates-length 3) + (company-backend 'ignore)) + (should (equal '(" x 1 " " y 2 " " z 3 ") + (company--create-lines 0 999))))) + +(ert-deftest company-create-lines-truncates-annotations () + (let* ((ww (company--window-width)) + (data `(("1" . "(123)") + ("2" . nil) + ("3" . ,(concat "(" (make-string (- ww 2) ?4) ")")) + (,(make-string ww ?4) . "<4>"))) + (company-candidates (mapcar #'car data)) + (company-candidates-length 4) + (company-tooltip-margin 1) + (company-backend (lambda (cmd &optional arg) + (when (eq cmd 'annotation) + (cdr (assoc arg data))))) + company-tooltip-align-annotations) + (should (equal (list (format " 1(123)%s " (company-space-string (- ww 8))) + (format " 2%s " (company-space-string (- ww 3))) + (format " 3(444%s " (make-string (- ww 7) ?4)) + (format " %s " (make-string (- ww 2) ?4))) + (company--create-lines 0 999))) + (let ((company-tooltip-align-annotations t)) + (should (equal (list (format " 1%s(123) " (company-space-string (- ww 8))) + (format " 2%s " (company-space-string (- ww 3))) + (format " 3 (444%s " (make-string (- ww 8) ?4)) + (format " %s " (make-string (- ww 2) ?4))) + (company--create-lines 0 999)))))) + +(ert-deftest company-create-lines-truncates-common-part () + (let* ((ww (company--window-width)) + (company-candidates-length 2) + (company-tooltip-margin 1) + (company-backend #'ignore)) + (let* ((company-common (make-string (- ww 3) ?1)) + (company-candidates `(,(concat company-common "2") + ,(concat company-common "3")))) + (should (equal (list (format " %s2 " (make-string (- ww 3) ?1)) + (format " %s3 " (make-string (- ww 3) ?1))) + (company--create-lines 0 999)))) + (let* ((company-common (make-string (- ww 2) ?1)) + (company-candidates `(,(concat company-common "2") + ,(concat company-common "3")))) + (should (equal (list (format " %s " company-common) + (format " %s " company-common)) + (company--create-lines 0 999)))) + (let* ((company-common (make-string ww ?1)) + (company-candidates `(,(concat company-common "2") + ,(concat company-common "3"))) + (res (company--create-lines 0 999))) + (should (equal (list (format " %s " (make-string (- ww 2) ?1)) + (format " %s " (make-string (- ww 2) ?1))) + res)) + (should (eq 'company-tooltip-common-selection + (get-text-property (- ww 2) 'face + (car res)))) + (should (eq 'company-tooltip-selection + (get-text-property (1- ww) 'face + (car res)))) + ))) + +(ert-deftest company-create-lines-clears-out-non-printables () + :tags '(interactive) + (let (company-show-numbers + (company-candidates (list + (decode-coding-string "avalis\351e" 'utf-8) + "avatar")) + (company-candidates-length 2) + (company-backend 'ignore)) + (should (equal '(" avalis‗e " + " avatar ") + (company--create-lines 0 999))))) + +(ert-deftest company-create-lines-handles-multiple-width () + :tags '(interactive) + (let (company-show-numbers + (company-candidates '("蛙蛙蛙蛙" "è›™abc")) + (company-candidates-length 2) + (company-backend 'ignore)) + (should (equal '(" 蛙蛙蛙蛙 " + " 蛙abc ") + (company--create-lines 0 999))))) + +(ert-deftest company-create-lines-handles-multiple-width-in-annotation () + (let* (company-show-numbers + (alist '(("a" . " ︸") ("b" . " ︸︸"))) + (company-candidates (mapcar #'car alist)) + (company-candidates-length 2) + (company-backend (lambda (c &optional a) + (when (eq c 'annotation) + (assoc-default a alist))))) + (should (equal '(" a ︸ " + " b ︸︸ ") + (company--create-lines 0 999))))) + +(ert-deftest company-create-lines-with-multiple-width-and-keep-prefix () + :tags '(interactive) + (let* (company-show-numbers + (company-candidates '("MIRAI発売1ă‚«æœˆ" + "MIRAI発売2ă‚«æœˆ")) + (company-candidates-length 2) + (company-prefix "MIRAI発") + (company-backend (lambda (c &optional _arg) + (pcase c + (`ignore-case 'keep-prefix))))) + (should (equal '(" MIRAI発売1ï»¿ă‚«ï»¿æœˆ " + " MIRAI発売2ï»¿ă‚«ï»¿æœˆ ") + (company--create-lines 0 999))))) + +(ert-deftest company-fill-propertize-truncates-search-highlight () + (let ((company-search-string "foo") + (company-backend #'ignore) + (company-prefix "")) + (should (equal-including-properties + (company-fill-propertize "barfoo" nil 6 t nil nil) + #("barfoo" + 0 3 (face company-tooltip mouse-face company-tooltip-mouse) + 3 6 (face company-tooltip-search mouse-face company-tooltip-mouse)))) + (should (equal-including-properties + (company-fill-propertize "barfoo" nil 5 t "" " ") + #("barfo " + 0 3 (face company-tooltip mouse-face company-tooltip-mouse) + 3 5 (face company-tooltip-search mouse-face company-tooltip-mouse) + 5 6 (face company-tooltip mouse-face company-tooltip-mouse)))) + (should (equal-including-properties + (company-fill-propertize "barfoo" nil 3 t " " " ") + #(" bar " + 0 5 (face company-tooltip mouse-face company-tooltip-mouse)))))) + +(ert-deftest company-column-with-composition () + :tags '(interactive) + (with-temp-buffer + (save-window-excursion + (set-window-buffer nil (current-buffer)) + (insert "lambda ()") + (compose-region 1 (1+ (length "lambda")) "\\") + (should (= (company--column) 4))))) + +(ert-deftest company-plainify () + (let ((tab-width 8)) + (should (equal-including-properties + (company-plainify "\tabc\td\t") + (concat " " + "abc " + "d ")))) + (should (equal-including-properties + (company-plainify (propertize "foobar" 'line-prefix "-*-")) + "-*-foobar"))) + +(ert-deftest company-buffer-lines-with-lines-folded () + :tags '(interactive) + (with-temp-buffer + (insert (propertize "aaa\nbbb\nccc\nddd\n" 'display "aaa+\n")) + (insert "eee\nfff\nggg") + (should (equal (company-buffer-lines (point-min) (point-max)) + '("aaa" "eee" "fff" "ggg"))))) + +(ert-deftest company-buffer-lines-with-multiline-display () + :tags '(interactive) + (with-temp-buffer + (insert (propertize "a" 'display "bbb\nccc\ndddd\n")) + (insert "eee\nfff\nggg") + (should (equal (company-buffer-lines (point-min) (point-max)) + '("" "" "" "eee" "fff" "ggg"))))) + +(ert-deftest company-buffer-lines-with-multiline-after-string-at-eob () + :tags '(interactive) + (with-temp-buffer + (insert "a\nb\nc\n") + (let ((ov (make-overlay (point-max) (point-max) nil t t))) + (overlay-put ov 'after-string "~\n~\n~")) + (should (equal (company-buffer-lines (point-min) (point-max)) + '("a" "b" "c"))))) + +(ert-deftest company-modify-line () + (let ((str "-*-foobar")) + (should (equal-including-properties + (company-modify-line str "zz" 4) + "-*-fzzbar")) + (should (equal-including-properties + (company-modify-line str "xx" 0) + "xx-foobar")) + (should (equal-including-properties + (company-modify-line str "zz" 10) + "-*-foobar zz")))) + +(ert-deftest company-scrollbar-bounds () + (should (equal nil (company--scrollbar-bounds 0 3 3))) + (should (equal nil (company--scrollbar-bounds 0 4 3))) + (should (equal '(0 . 0) (company--scrollbar-bounds 0 1 2))) + (should (equal '(1 . 1) (company--scrollbar-bounds 2 2 4))) + (should (equal '(2 . 3) (company--scrollbar-bounds 7 4 12))) + (should (equal '(1 . 2) (company--scrollbar-bounds 3 4 12))) + (should (equal '(1 . 3) (company--scrollbar-bounds 4 5 11)))) diff --git a/elpa/company-0.8.12/test/keywords-tests.el b/elpa/company-0.8.12/test/keywords-tests.el new file mode 100644 index 0000000..05843b2 --- /dev/null +++ b/elpa/company-0.8.12/test/keywords-tests.el @@ -0,0 +1,32 @@ +;;; keywords-tests.el --- company-keywords tests -*- lexical-binding: t -*- + +;; Copyright (C) 2011, 2013-2015 Free Software Foundation, Inc. + +;; Author: Nikolaj Schumacher + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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 of the License, or +;; (at your option) any later version. + +;; GNU Emacs 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 GNU Emacs. If not, see . + +(require 'company-keywords) + +(ert-deftest company-sorted-keywords () + "Test that keywords in `company-keywords-alist' are in alphabetical order." + (dolist (pair company-keywords-alist) + (when (consp (cdr pair)) + (let ((prev (cadr pair))) + (dolist (next (cddr pair)) + (should (not (equal prev next))) + (should (string< prev next)) + (setq prev next)))))) diff --git a/elpa/company-0.8.12/test/template-tests.el b/elpa/company-0.8.12/test/template-tests.el new file mode 100644 index 0000000..09548c4 --- /dev/null +++ b/elpa/company-0.8.12/test/template-tests.el @@ -0,0 +1,91 @@ +;;; template-tests.el --- company-mode tests -*- lexical-binding: t -*- + +;; Copyright (C) 2015 Free Software Foundation, Inc. + +;; Author: Dmitry Gutov + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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 of the License, or +;; (at your option) any later version. + +;; GNU Emacs 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 GNU Emacs. If not, see . + +(require 'company-tests) +(require 'company-template) + +(ert-deftest company-template-removed-after-the-last-jump () + (with-temp-buffer + (insert "{ }") + (goto-char 2) + (let ((tpl (company-template-declare-template (point) (1- (point-max))))) + (save-excursion + (dotimes (_ 2) + (insert " ") + (company-template-add-field tpl (point) "foo"))) + (company-call 'template-forward-field) + (should (= 3 (point))) + (company-call 'template-forward-field) + (should (= 7 (point))) + (company-call 'template-forward-field) + (should (= 11 (point))) + (should (zerop (length (overlay-get tpl 'company-template-fields)))) + (should (null (overlay-buffer tpl)))))) + +(ert-deftest company-template-removed-after-input-and-jump () + (with-temp-buffer + (insert "{ }") + (goto-char 2) + (let ((tpl (company-template-declare-template (point) (1- (point-max))))) + (save-excursion + (insert " ") + (company-template-add-field tpl (point) "bar")) + (company-call 'template-move-to-first tpl) + (should (= 3 (point))) + (dolist (c (string-to-list "tee")) + (let ((last-command-event c)) + (company-call 'self-insert-command 1))) + (should (string= "{ tee }" (buffer-string))) + (should (overlay-buffer tpl)) + (company-call 'template-forward-field) + (should (= 7 (point))) + (should (null (overlay-buffer tpl)))))) + +(ert-deftest company-template-c-like-templatify () + (with-temp-buffer + (let ((text "foo(int a, short b)")) + (insert text) + (company-template-c-like-templatify text) + (should (equal "foo(arg0, arg1)" (buffer-string))) + (should (looking-at "arg0")) + (should (equal "int a" + (overlay-get (company-template-field-at) 'display)))))) + +(ert-deftest company-template-c-like-templatify-trims-after-closing-paren () + (with-temp-buffer + (let ((text "foo(int a, short b)!@ #1334 a")) + (insert text) + (company-template-c-like-templatify text) + (should (equal "foo(arg0, arg1)" (buffer-string))) + (should (looking-at "arg0"))))) + +(ert-deftest company-template-c-like-templatify-generics () + (with-temp-buffer + (let ((text "foo(int i, Dict, long l)")) + (insert text) + (company-template-c-like-templatify text) + (should (equal "foo(arg2, arg3, arg4)" (buffer-string))) + (should (looking-at "arg0")) + (should (equal "TKey" (overlay-get (company-template-field-at) 'display))) + (search-forward "arg3") + (forward-char -1) + (should (equal "Dict" + (overlay-get (company-template-field-at) 'display)))))) diff --git a/elpa/company-0.8.12/test/transformers-tests.el b/elpa/company-0.8.12/test/transformers-tests.el new file mode 100644 index 0000000..4d027e5 --- /dev/null +++ b/elpa/company-0.8.12/test/transformers-tests.el @@ -0,0 +1,58 @@ +;;; transformers-tests.el --- company-mode tests -*- lexical-binding: t -*- + +;; Copyright (C) 2015 Free Software Foundation, Inc. + +;; Author: Dmitry Gutov + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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 of the License, or +;; (at your option) any later version. + +;; GNU Emacs 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 GNU Emacs. If not, see . + +(require 'company-tests) + +(ert-deftest company-occurrence-prefer-closest-above () + (with-temp-buffer + (save-window-excursion + (set-window-buffer nil (current-buffer)) + (insert "foo0 +foo1 +") + (save-excursion + (insert " +foo3 +foo2")) + (let ((company-backend 'company-dabbrev) + (company-occurrence-weight-function + 'company-occurrence-prefer-closest-above)) + (should (equal '("foo1" "foo0" "foo3" "foo2" "foo4") + (company-sort-by-occurrence + '("foo0" "foo1" "foo2" "foo3" "foo4")))))))) + +(ert-deftest company-occurrence-prefer-any-closest () + (with-temp-buffer + (save-window-excursion + (set-window-buffer nil (current-buffer)) + (insert "foo0 +foo1 +") + (save-excursion + (insert " +foo3 +foo2")) + (let ((company-backend 'company-dabbrev) + (company-occurrence-weight-function + 'company-occurrence-prefer-any-closest)) + (should (equal '("foo1" "foo3" "foo0" "foo2" "foo4") + (company-sort-by-occurrence + '("foo0" "foo1" "foo2" "foo3" "foo4")))))))) diff --git a/elpa/company-0.8.5/.travis.yml b/elpa/company-0.8.5/.travis.yml deleted file mode 100644 index ed76f79..0000000 --- a/elpa/company-0.8.5/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -# https://github.com/rolandwalker/emacs-travis - -language: emacs-lisp - -env: - matrix: - - EMACS=emacs24 - - EMACS=emacs-snapshot - -install: - - if [ "$EMACS" = "emacs24" ]; then - sudo add-apt-repository -y ppa:cassou/emacs && - sudo apt-get update -qq && - sudo apt-get install -qq emacs24 emacs24-el; - fi - - if [ "$EMACS" = "emacs-snapshot" ]; then - sudo add-apt-repository -y ppa:ubuntu-elisp/ppa && - sudo apt-get update -qq && - sudo apt-get install -qq emacs-snapshot; - fi - -script: - make test-batch EMACS=${EMACS} diff --git a/elpa/company-0.8.5/Makefile b/elpa/company-0.8.5/Makefile deleted file mode 100644 index c52be4b..0000000 --- a/elpa/company-0.8.5/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -EMACS=emacs - -.PHONY: ert test test-batch - -package: *.el - @ver=`grep -o "Version: .*" company.el | cut -c 10-`; \ - tar cjvf company-$$ver.tar.bz2 --mode 644 `git ls-files '*.el' | xargs` - -elpa: *.el - @version=`grep -o "Version: .*" company.el | cut -c 10-`; \ - dir=company-$$version; \ - mkdir -p "$$dir"; \ - cp `git ls-files '*.el' | xargs` company-$$version; \ - echo "(define-package \"company\" \"$$version\" \ - \"Modular in-buffer completion framework\")" \ - > "$$dir"/company-pkg.el; \ - tar cvf company-$$version.tar --mode 644 "$$dir" - -clean: - @rm -rf company-*/ company-*.tar company-*.tar.bz2 *.elc ert.el - -test: - ${EMACS} -Q -nw -L . -l company-tests.el -l company-elisp-tests.el \ - --eval "(let (pop-up-windows) (ert t))" - -test-batch: - ${EMACS} -Q --batch -L . -l company-tests.el -l company-elisp-tests.el \ - --eval "(ert-run-tests-batch-and-exit '(not (tag interactive)))" - -compile: - ${EMACS} -Q --batch -L . -f batch-byte-compile company.el company-*.el diff --git a/elpa/company-0.8.5/company-cmake.el b/elpa/company-0.8.5/company-cmake.el deleted file mode 100644 index a466f60..0000000 --- a/elpa/company-0.8.5/company-cmake.el +++ /dev/null @@ -1,129 +0,0 @@ -;;; company-cmake.el --- company-mode completion back-end for CMake - -;; Copyright (C) 2013 Free Software Foundation, Inc. - -;; Author: Chen Bin -;; Version: 0.1 - -;; This program 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 of the License, or -;; (at your option) any later version. - -;; This program 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 this program. If not, see . - -;;; Commentary: -;; -;; company-cmake offers completions for module names, variable names and -;; commands used by CMake. And their descriptions. - -;;; Code: - -(require 'company) -(require 'cl-lib) - -(defgroup company-cmake nil - "Completion back-end for CMake." - :group 'company) - -(defcustom company-cmake-executable - (executable-find "cmake") - "Location of cmake executable." - :type 'file) - -(defvar company-cmake-executable-arguments - '("--help-command-list" - "--help-module-list" - "--help-variable-list") - "The arguments we pass to cmake, separately. -They affect which types of symbols we get completion candidates for.") - -(defvar company-cmake--completion-pattern - "^\\(%s[a-zA-Z0-9_]%s\\)$" - "Regexp to match the candidates.") - -(defvar company-cmake-modes '(cmake-mode) - "Major modes in which cmake may complete.") - -(defvar company-cmake--meta-command-cache nil - "Cache for command arguments to retrieve descriptions for the candidates.") - -(defun company-cmake--parse-output (prefix cmd) - "Analyze the temp buffer and collect lines." - (goto-char (point-min)) - (let ((pattern (format company-cmake--completion-pattern - (regexp-quote prefix) - (if (zerop (length prefix)) "+" "*"))) - (case-fold-search nil) - lines match) - (while (re-search-forward pattern nil t) - (setq match (match-string-no-properties 1)) - (puthash match cmd company-cmake--meta-command-cache) - (push match lines)) - lines)) - -(defun company-cmake--candidates (prefix) - (let ((res 0) - results - cmd) - (setq company-cmake--meta-command-cache (make-hash-table :test 'equal)) - (dolist (arg company-cmake-executable-arguments) - (with-temp-buffer - (setq res (call-process company-cmake-executable nil t nil arg)) - (unless (eq 0 res) - (message "cmake executable exited with error=%d" res)) - (setq cmd (replace-regexp-in-string "-list$" "" arg) ) - (setq results (nconc results (company-cmake--parse-output prefix cmd))))) - results)) - -(defun company-cmake--meta (prefix) - (let ((cmd-opts (gethash prefix company-cmake--meta-command-cache)) - result) - (with-temp-buffer - (call-process company-cmake-executable nil t nil cmd-opts prefix) - ;; Go to the third line, trim it and return the result. - ;; Tested with cmake 2.8.9. - (goto-char (point-min)) - (forward-line 2) - (setq result (buffer-substring-no-properties (line-beginning-position) - (line-end-position))) - (setq result (replace-regexp-in-string "^[ \t\n\r]+" "" result)) - result))) - -(defun company-cmake--doc-buffer (prefix) - (let ((cmd-opts (gethash prefix company-cmake--meta-command-cache))) - (with-temp-buffer - (call-process company-cmake-executable nil t nil cmd-opts prefix) - ;; Go to the third line, trim it and return the doc buffer. - ;; Tested with cmake 2.8.9. - (goto-char (point-min)) - (forward-line 2) - (company-doc-buffer - (buffer-substring-no-properties (line-beginning-position) - (point-max)))))) - -(defun company-cmake (command &optional arg &rest ignored) - "`company-mode' completion back-end for CMake. -CMake is a cross-platform, open-source make system." - (interactive (list 'interactive)) - (cl-case command - (interactive (company-begin-backend 'company-cmake)) - (init (when (memq major-mode company-cmake-modes) - (unless company-cmake-executable - (error "Company found no cmake executable")))) - (prefix (and (memq major-mode company-cmake-modes) - (not (company-in-string-or-comment)) - (company-grab-symbol))) - (candidates (company-cmake--candidates arg)) - (meta (company-cmake--meta arg)) - (doc-buffer (company-cmake--doc-buffer arg)) - )) - -(provide 'company-cmake) -;;; company-cmake.el ends here diff --git a/elpa/company-0.8.5/company-pkg.el b/elpa/company-0.8.5/company-pkg.el deleted file mode 100644 index 4556708..0000000 --- a/elpa/company-0.8.5/company-pkg.el +++ /dev/null @@ -1,2 +0,0 @@ -;; Generated package description from company.el -(define-package "company" "0.8.5" "Modular text completion framework" '((emacs "24.1") (cl-lib "0.5")) :url "http://company-mode.github.io/" :keywords '("abbrev" "convenience" "matching")) diff --git a/elpa/company-0.8.5/company-tests.el b/elpa/company-0.8.5/company-tests.el deleted file mode 100644 index 6060aed..0000000 --- a/elpa/company-0.8.5/company-tests.el +++ /dev/null @@ -1,911 +0,0 @@ -;;; company-tests.el --- company-mode tests -*- lexical-binding: t -*- - -;; Copyright (C) 2011, 2013-2014 Free Software Foundation, Inc. - -;; Author: Nikolaj Schumacher - -;; This file is part of GNU Emacs. - -;; GNU Emacs 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 of the License, or -;; (at your option) any later version. - -;; GNU Emacs 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 GNU Emacs. If not, see . - - -;;; Commentary: -;; - -;;; Code: - -(require 'ert) -(require 'company) -(require 'company-keywords) -(require 'company-clang) - -(defun company--column (&optional pos) - (car (company--col-row pos))) - -;;; Core - -(ert-deftest company-sorted-keywords () - "Test that keywords in `company-keywords-alist' are in alphabetical order." - (dolist (pair company-keywords-alist) - (when (consp (cdr pair)) - (let ((prev (cadr pair))) - (dolist (next (cddr pair)) - (should (not (equal prev next))) - (should (string< prev next)) - (setq prev next)))))) - -(ert-deftest company-good-prefix () - (let ((company-minimum-prefix-length 5) - company-abort-manual-when-too-short - company--manual-action ;idle begin - (company-selection-changed t)) ;has no effect - (should (eq t (company--good-prefix-p "!@#$%"))) - (should (eq nil (company--good-prefix-p "abcd"))) - (should (eq nil (company--good-prefix-p 'stop))) - (should (eq t (company--good-prefix-p '("foo" . 5)))) - (should (eq nil (company--good-prefix-p '("foo" . 4)))) - (should (eq t (company--good-prefix-p '("foo" . t)))))) - -(ert-deftest company--manual-prefix-set-and-unset () - (with-temp-buffer - (insert "ab") - (company-mode) - (let (company-frontends - (company-backends - (list (lambda (command &optional arg) - (cl-case command - (prefix (buffer-substring (point-min) (point))) - (candidates '("abc" "abd"))))))) - (company-manual-begin) - (should (equal "ab" company--manual-prefix)) - (company-abort) - (should (null company--manual-prefix))))) - -(ert-deftest company-abort-manual-when-too-short () - (let ((company-minimum-prefix-length 5) - (company-abort-manual-when-too-short t) - (company-selection-changed t)) ;has not effect - (let ((company--manual-action nil)) ;idle begin - (should (eq t (company--good-prefix-p "!@#$%"))) - (should (eq t (company--good-prefix-p '("foo" . 5)))) - (should (eq t (company--good-prefix-p '("foo" . t))))) - (let ((company--manual-action t) - (company--manual-prefix "abc")) ;manual begin from this prefix - (should (eq t (company--good-prefix-p "!@#$"))) - (should (eq nil (company--good-prefix-p "ab"))) - (should (eq nil (company--good-prefix-p 'stop))) - (should (eq t (company--good-prefix-p '("foo" . 4)))) - (should (eq t (company--good-prefix-p "abcd"))) - (should (eq t (company--good-prefix-p "abc"))) - (should (eq t (company--good-prefix-p '("bar" . t))))))) - -(ert-deftest company-multi-backend-with-lambdas () - (let ((company-backend - (list (lambda (command &optional arg &rest ignore) - (cl-case command - (prefix "z") - (candidates '("a" "b")))) - (lambda (command &optional arg &rest ignore) - (cl-case command - (prefix "z") - (candidates '("c" "d"))))))) - (should (equal (company-call-backend 'candidates "z") '("a" "b" "c" "d"))))) - -(ert-deftest company-multi-backend-filters-backends-by-prefix () - (let ((company-backend - (list (lambda (command &optional arg &rest ignore) - (cl-case command - (prefix (cons "z" t)) - (candidates '("a" "b")))) - (lambda (command &optional arg &rest ignore) - (cl-case command - (prefix "t") - (candidates '("c" "d")))) - (lambda (command &optional arg &rest ignore) - (cl-case command - (prefix "z") - (candidates '("e" "f"))))))) - (should (equal (company-call-backend 'candidates "z") '("a" "b" "e" "f"))))) - -(ert-deftest company-multi-backend-remembers-candidate-backend () - (let ((company-backend - (list (lambda (command &optional arg) - (cl-case command - (ignore-case nil) - (annotation "1") - (candidates '("a" "c")) - (post-completion "13"))) - (lambda (command &optional arg) - (cl-case command - (ignore-case t) - (annotation "2") - (candidates '("b" "d")) - (post-completion "42"))) - (lambda (command &optional arg) - (cl-case command - (annotation "3") - (candidates '("e")) - (post-completion "74")))))) - (let ((candidates (company-calculate-candidates nil))) - (should (equal candidates '("a" "b" "c" "d" "e"))) - (should (equal t (company-call-backend 'ignore-case))) - (should (equal "1" (company-call-backend 'annotation (nth 0 candidates)))) - (should (equal "2" (company-call-backend 'annotation (nth 1 candidates)))) - (should (equal "13" (company-call-backend 'post-completion (nth 2 candidates)))) - (should (equal "42" (company-call-backend 'post-completion (nth 3 candidates)))) - (should (equal "3" (company-call-backend 'annotation (nth 4 candidates)))) - (should (equal "74" (company-call-backend 'post-completion (nth 4 candidates))))))) - -(ert-deftest company-multi-backend-handles-keyword-with () - (let ((primo (lambda (command &optional arg) - (cl-case command - (prefix "a") - (candidates '("abb" "abc" "abd"))))) - (secundo (lambda (command &optional arg) - (cl-case command - (prefix "a") - (candidates '("acc" "acd")))))) - (let ((company-backend (list 'ignore 'ignore :with secundo))) - (should (null (company-call-backend 'prefix)))) - (let ((company-backend (list 'ignore primo :with secundo))) - (should (equal "a" (company-call-backend 'prefix))) - (should (equal '("abb" "abc" "abd" "acc" "acd") - (company-call-backend 'candidates "a")))))) - -(ert-deftest company-begin-backend-failure-doesnt-break-company-backends () - (with-temp-buffer - (insert "a") - (company-mode) - (should-error - (company-begin-backend (lambda (command &rest ignore)))) - (let (company-frontends - (company-backends - (list (lambda (command &optional arg) - (cl-case command - (prefix "a") - (candidates '("a" "ab" "ac"))))))) - (let (this-command) - (company-call 'complete)) - (should (eq 3 company-candidates-length))))) - -(ert-deftest company-require-match-explicit () - (with-temp-buffer - (insert "ab") - (company-mode) - (let (company-frontends - (company-require-match 'company-explicit-action-p) - (company-backends - (list (lambda (command &optional arg) - (cl-case command - (prefix (buffer-substring (point-min) (point))) - (candidates '("abc" "abd"))))))) - (let (this-command) - (company-complete)) - (let ((last-command-event ?e)) - (company-call 'self-insert-command 1)) - (should (eq 2 company-candidates-length)) - (should (eq 3 (point)))))) - -(ert-deftest company-dont-require-match-when-idle () - (with-temp-buffer - (insert "ab") - (company-mode) - (let (company-frontends - (company-minimum-prefix-length 2) - (company-require-match 'company-explicit-action-p) - (company-backends - (list (lambda (command &optional arg) - (cl-case command - (prefix (buffer-substring (point-min) (point))) - (candidates '("abc" "abd"))))))) - (company-idle-begin (current-buffer) (selected-window) - (buffer-chars-modified-tick) (point)) - (should (eq 2 company-candidates-length)) - (let ((last-command-event ?e)) - (company-call 'self-insert-command 1)) - (should (eq nil company-candidates-length)) - (should (eq 4 (point)))))) - -(ert-deftest company-dont-require-match-if-old-prefix-ended-and-was-a-match () - (with-temp-buffer - (insert "ab") - (company-mode) - (let (company-frontends - (company-require-match 'company-explicit-action-p) - (company-backends - (list (lambda (command &optional arg) - (cl-case command - (prefix (company-grab-word)) - (candidates '("abc" "ab" "abd")) - (sorted t)))))) - (let (this-command) - (company-complete)) - (let ((last-command-event ?e)) - (company-call 'self-insert-command 1)) - (should (eq 3 company-candidates-length)) - (should (eq 3 (point))) - (let ((last-command-event ? )) - (company-call 'self-insert-command 1)) - (should (null company-candidates-length)) - (should (eq 4 (point)))))) - -(ert-deftest company-should-complete-whitelist () - (with-temp-buffer - (insert "ab") - (company-mode) - (let (company-frontends - company-begin-commands - (company-backends - (list (lambda (command &optional arg) - (cl-case command - (prefix (buffer-substring (point-min) (point))) - (candidates '("abc" "abd"))))))) - (let ((company-continue-commands nil)) - (let (this-command) - (company-complete)) - (company-call 'backward-delete-char 1) - (should (null company-candidates-length))) - (let ((company-continue-commands '(backward-delete-char))) - (let (this-command) - (company-complete)) - (company-call 'backward-delete-char 1) - (should (eq 2 company-candidates-length)))))) - -(ert-deftest company-should-complete-blacklist () - (with-temp-buffer - (insert "ab") - (company-mode) - (let (company-frontends - company-begin-commands - (company-backends - (list (lambda (command &optional arg) - (cl-case command - (prefix (buffer-substring (point-min) (point))) - (candidates '("abc" "abd"))))))) - (let ((company-continue-commands '(not backward-delete-char))) - (let (this-command) - (company-complete)) - (company-call 'backward-delete-char 1) - (should (null company-candidates-length))) - (let ((company-continue-commands '(not backward-delete-char-untabify))) - (let (this-command) - (company-complete)) - (company-call 'backward-delete-char 1) - (should (eq 2 company-candidates-length)))))) - -(ert-deftest company-auto-complete-explicit () - (with-temp-buffer - (insert "ab") - (company-mode) - (let (company-frontends - (company-auto-complete 'company-explicit-action-p) - (company-auto-complete-chars '(? )) - (company-backends - (list (lambda (command &optional arg) - (cl-case command - (prefix (buffer-substring (point-min) (point))) - (candidates '("abcd" "abef"))))))) - (let (this-command) - (company-complete)) - (let ((last-command-event ? )) - (company-call 'self-insert-command 1)) - (should (string= "abcd " (buffer-string)))))) - -(ert-deftest company-no-auto-complete-when-idle () - (with-temp-buffer - (insert "ab") - (company-mode) - (let (company-frontends - (company-auto-complete 'company-explicit-action-p) - (company-auto-complete-chars '(? )) - (company-minimum-prefix-length 2) - (company-backends - (list (lambda (command &optional arg) - (cl-case command - (prefix (buffer-substring (point-min) (point))) - (candidates '("abcd" "abef"))))))) - (company-idle-begin (current-buffer) (selected-window) - (buffer-chars-modified-tick) (point)) - (let ((last-command-event ? )) - (company-call 'self-insert-command 1)) - (should (string= "ab " (buffer-string)))))) - -(ert-deftest company-clears-explicit-action-when-no-matches () - (with-temp-buffer - (company-mode) - (let (company-frontends - company-backends) - (company-call 'manual-begin) ;; fails - (should (null company-candidates)) - (should (null (company-explicit-action-p)))))) - -(ert-deftest company-ignore-case-replaces-prefix () - (with-temp-buffer - (company-mode) - (let (company-frontends - company-end-of-buffer-workaround - (company-backends - (list (lambda (command &optional arg) - (cl-case command - (prefix (buffer-substring (point-min) (point))) - (candidates '("abcd" "abef")) - (ignore-case t)))))) - (insert "A") - (let (this-command) - (company-complete)) - (should (string= "ab" (buffer-string))) - (delete-char -2) - (insert "A") ; hack, to keep it in one test - (company-complete-selection) - (should (string= "abcd" (buffer-string)))))) - -(ert-deftest company-ignore-case-with-keep-prefix () - (with-temp-buffer - (insert "AB") - (company-mode) - (let (company-frontends - (company-backends - (list (lambda (command &optional arg) - (cl-case command - (prefix (buffer-substring (point-min) (point))) - (candidates '("abcd" "abef")) - (ignore-case 'keep-prefix)))))) - (let (this-command) - (company-complete)) - (company-complete-selection) - (should (string= "ABcd" (buffer-string)))))) - -(ert-deftest company-non-prefix-completion () - (with-temp-buffer - (insert "tc") - (company-mode) - (let (company-frontends - company-end-of-buffer-workaround - (company-backends - (list (lambda (command &optional arg) - (cl-case command - (prefix (buffer-substring (point-min) (point))) - (candidates '("tea-cup" "teal-color"))))))) - (let (this-command) - (company-complete)) - (should (string= "tc" (buffer-string))) - (company-complete-selection) - (should (string= "tea-cup" (buffer-string)))))) - -(ert-deftest company-pseudo-tooltip-does-not-get-displaced () - :tags '(interactive) - (with-temp-buffer - (save-window-excursion - (set-window-buffer nil (current-buffer)) - (save-excursion (insert " ff")) - (company-mode) - (let ((company-frontends '(company-pseudo-tooltip-frontend)) - (company-begin-commands '(self-insert-command)) - (company-backends - (list (lambda (c &optional arg) - (cl-case c (prefix "") (candidates '("a" "b" "c"))))))) - (let (this-command) - (company-call 'complete)) - (company-call 'open-line 1) - (should (eq 1 (overlay-start company-pseudo-tooltip-overlay))))))) - -(ert-deftest company-pseudo-tooltip-show () - :tags '(interactive) - (with-temp-buffer - (save-window-excursion - (set-window-buffer nil (current-buffer)) - (insert "aaaa\n bb\nccccccc\nddd") - (search-backward "bb") - (let ((col (company--column)) - (company-candidates-length 2) - (company-candidates '("123" "45")) - (company-backend 'ignore)) - (company-pseudo-tooltip-show (company--row) col 0) - (let ((ov company-pseudo-tooltip-overlay)) - ;; With margins. - (should (eq (overlay-get ov 'company-width) 5)) - ;; FIXME: Make it 2? - (should (eq (overlay-get ov 'company-height) company-tooltip-limit)) - (should (eq (overlay-get ov 'company-column) col)) - (should (string= (overlay-get ov 'company-display) - "\n 123 \nc 45 c\nddd\n"))))))) - -(ert-deftest company-pseudo-tooltip-edit-updates-width () - :tags '(interactive) - (with-temp-buffer - (set-window-buffer nil (current-buffer)) - (let ((company-candidates-length 5) - (company-candidates '("123" "45" "67" "89" "1011")) - (company-backend 'ignore) - (company-tooltip-limit 4) - (company-tooltip-offset-display 'scrollbar)) - (company-pseudo-tooltip-show (company--row) - (company--column) - 0) - (should (eq (overlay-get company-pseudo-tooltip-overlay 'company-width) - 6)) - (company-pseudo-tooltip-edit 4) - (should (eq (overlay-get company-pseudo-tooltip-overlay 'company-width) - 7))))) - -(ert-deftest company-preview-show-with-annotations () - :tags '(interactive) - (with-temp-buffer - (save-window-excursion - (set-window-buffer nil (current-buffer)) - (save-excursion (insert "\n")) - (let ((company-candidates-length 1) - (company-candidates '("123"))) - (company-preview-show-at-point (point)) - (let* ((ov company-preview-overlay) - (str (overlay-get ov 'after-string))) - (should (string= str "123")) - (should (eq (get-text-property 0 'cursor str) t))))))) - -(ert-deftest company-pseudo-tooltip-show-with-annotations () - :tags '(interactive) - (with-temp-buffer - (save-window-excursion - (set-window-buffer nil (current-buffer)) - (insert " ") - (save-excursion (insert "\n")) - (let ((company-candidates-length 2) - (company-backend (lambda (action &optional arg &rest _ignore) - (when (eq action 'annotation) - (cdr (assoc arg '(("123" . "(4)"))))))) - (company-candidates '("123" "45")) - company-tooltip-align-annotations) - (company-pseudo-tooltip-show-at-point (point) 0) - (let ((ov company-pseudo-tooltip-overlay)) - ;; With margins. - (should (eq (overlay-get ov 'company-width) 8)) - (should (string= (overlay-get ov 'company-display) - "\n 123(4) \n 45 \n"))))))) - -(ert-deftest company-pseudo-tooltip-show-with-annotations-right-aligned () - :tags '(interactive) - (with-temp-buffer - (save-window-excursion - (set-window-buffer nil (current-buffer)) - (insert " ") - (save-excursion (insert "\n")) - (let ((company-candidates-length 3) - (company-backend (lambda (action &optional arg &rest _ignore) - (when (eq action 'annotation) - (cdr (assoc arg '(("123" . "(4)") - ("67" . "(891011)"))))))) - (company-candidates '("123" "45" "67")) - (company-tooltip-align-annotations t)) - (company-pseudo-tooltip-show-at-point (point) 0) - (let ((ov company-pseudo-tooltip-overlay)) - ;; With margins. - (should (eq (overlay-get ov 'company-width) 13)) - (should (string= (overlay-get ov 'company-display) - "\n 123 (4) \n 45 \n 67 (891011) \n"))))))) - -(ert-deftest company-create-lines-shows-numbers () - (let ((company-show-numbers t) - (company-candidates '("x" "y" "z")) - (company-candidates-length 3) - (company-backend 'ignore)) - (should (equal '(" x 1 " " y 2 " " z 3 ") - (company--create-lines 0 999))))) - -(ert-deftest company-create-lines-truncates-annotations () - (let* ((ww (company--window-width)) - (data `(("1" . "(123)") - ("2" . nil) - ("3" . ,(concat "(" (make-string (- ww 2) ?4) ")")) - (,(make-string ww ?4) . "<4>"))) - (company-candidates (mapcar #'car data)) - (company-candidates-length 4) - (company-tooltip-margin 1) - (company-backend (lambda (cmd &optional arg) - (when (eq cmd 'annotation) - (cdr (assoc arg data))))) - company-tooltip-align-annotations) - (should (equal (list (format " 1(123)%s " (company-space-string (- ww 8))) - (format " 2%s " (company-space-string (- ww 3))) - (format " 3(444%s " (make-string (- ww 7) ?4)) - (format " %s " (make-string (- ww 2) ?4))) - (company--create-lines 0 999))) - (let ((company-tooltip-align-annotations t)) - (should (equal (list (format " 1%s(123) " (company-space-string (- ww 8))) - (format " 2%s " (company-space-string (- ww 3))) - (format " 3 (444%s " (make-string (- ww 8) ?4)) - (format " %s " (make-string (- ww 2) ?4))) - (company--create-lines 0 999)))))) - -(ert-deftest company-create-lines-truncates-common-part () - (let* ((ww (company--window-width)) - (company-candidates-length 2) - (company-tooltip-margin 1) - (company-backend #'ignore)) - (let* ((company-common (make-string (- ww 3) ?1)) - (company-candidates `(,(concat company-common "2") - ,(concat company-common "3")))) - (should (equal (list (format " %s2 " (make-string (- ww 3) ?1)) - (format " %s3 " (make-string (- ww 3) ?1))) - (company--create-lines 0 999)))) - (let* ((company-common (make-string (- ww 2) ?1)) - (company-candidates `(,(concat company-common "2") - ,(concat company-common "3")))) - (should (equal (list (format " %s " company-common) - (format " %s " company-common)) - (company--create-lines 0 999)))) - (let* ((company-common (make-string ww ?1)) - (company-candidates `(,(concat company-common "2") - ,(concat company-common "3"))) - (res (company--create-lines 0 999))) - (should (equal (list (format " %s " (make-string (- ww 2) ?1)) - (format " %s " (make-string (- ww 2) ?1))) - res)) - (should (eq 'company-tooltip-common-selection - (get-text-property (- ww 2) 'face - (car res)))) - (should (eq 'company-tooltip-selection - (get-text-property (1- ww) 'face - (car res)))) - -))) - -(ert-deftest company-column-with-composition () - :tags '(interactive) - (with-temp-buffer - (save-window-excursion - (set-window-buffer nil (current-buffer)) - (insert "lambda ()") - (compose-region 1 (1+ (length "lambda")) "\\") - (should (= (company--column) 4))))) - -(ert-deftest company-column-with-line-prefix () - :tags '(interactive) - (with-temp-buffer - (save-window-excursion - (set-window-buffer nil (current-buffer)) - (insert "foo") - (put-text-property (point-min) (point) 'line-prefix " ") - (should (= (company--column) 5))))) - -(ert-deftest company-column-with-line-prefix-on-empty-line () - :tags '(interactive) - (with-temp-buffer - (save-window-excursion - (set-window-buffer nil (current-buffer)) - (insert "\n") - (forward-char -1) - (put-text-property (point-min) (point-max) 'line-prefix " ") - (should (= (company--column) 2))))) - -(ert-deftest company-column-with-tabs () - :tags '(interactive) - (with-temp-buffer - (save-window-excursion - (set-window-buffer nil (current-buffer)) - (insert "|\t|\t|\t(") - (let ((tab-width 8)) - (should (= (company--column) 25)))))) - -(ert-deftest company-row-with-header-line-format () - :tags '(interactive) - (with-temp-buffer - (save-window-excursion - (set-window-buffer nil (current-buffer)) - (should (= (company--row) 0)) - (setq header-line-format "aaaaaaa") - (should (= (company--row) 0))))) - -(ert-deftest company-plainify () - (let ((tab-width 8)) - (should (equal-including-properties - (company-plainify "\tabc\td\t") - (concat " " - "abc " - "d ")))) - (should (equal-including-properties - (company-plainify (propertize "foobar" 'line-prefix "-*-")) - "-*-foobar"))) - -(ert-deftest company-buffer-lines-with-lines-folded () - :tags '(interactive) - (with-temp-buffer - (insert (propertize "aaa\nbbb\nccc\nddd\n" 'display "aaa+\n")) - (insert "eee\nfff\nggg") - (should (equal (company-buffer-lines (point-min) (point-max)) - '("aaa" "eee" "fff" "ggg"))))) - -(ert-deftest company-buffer-lines-with-multiline-display () - :tags '(interactive) - (with-temp-buffer - (insert (propertize "a" 'display "bbb\nccc\ndddd\n")) - (insert "eee\nfff\nggg") - (should (equal (company-buffer-lines (point-min) (point-max)) - '("" "" "" "eee" "fff" "ggg"))))) - -(ert-deftest company-modify-line () - (let ((str "-*-foobar")) - (should (equal-including-properties - (company-modify-line str "zz" 4) - "-*-fzzbar")) - (should (equal-including-properties - (company-modify-line str "xx" 0) - "xx-foobar")) - (should (equal-including-properties - (company-modify-line str "zz" 10) - "-*-foobar zz")))) - -(ert-deftest company-scrollbar-bounds () - (should (equal nil (company--scrollbar-bounds 0 3 3))) - (should (equal nil (company--scrollbar-bounds 0 4 3))) - (should (equal '(0 . 0) (company--scrollbar-bounds 0 1 2))) - (should (equal '(1 . 1) (company--scrollbar-bounds 2 2 4))) - (should (equal '(2 . 3) (company--scrollbar-bounds 7 4 12))) - (should (equal '(1 . 2) (company--scrollbar-bounds 3 4 12))) - (should (equal '(1 . 3) (company--scrollbar-bounds 4 5 11)))) - -;;; Async - -(defun company-async-backend (command &optional arg) - (pcase command - (`prefix "foo") - (`candidates - (cons :async - (lambda (cb) - (run-with-timer 0.05 nil - #'funcall cb '("abc" "abd"))))))) - -(ert-deftest company-call-backend-forces-sync () - (let ((company-backend 'company-async-backend) - (company-async-timeout 0.1)) - (should (equal '("abc" "abd") (company-call-backend 'candidates))))) - -(ert-deftest company-call-backend-errors-on-timeout () - (with-temp-buffer - (let* ((company-backend (lambda (command &optional _arg) - (pcase command - (`candidates (cons :async 'ignore))))) - (company-async-timeout 0.1) - (err (should-error (company-call-backend 'candidates "foo")))) - (should (string-match-p "async timeout" (cadr err)))))) - -(ert-deftest company-call-backend-raw-passes-return-value-verbatim () - (let ((company-backend 'company-async-backend)) - (should (equal "foo" (company-call-backend-raw 'prefix))) - (should (equal :async (car (company-call-backend-raw 'candidates "foo")))) - (should (equal 'closure (cadr (company-call-backend-raw 'candidates "foo")))))) - -(ert-deftest company-manual-begin-forces-async-candidates-to-sync () - (with-temp-buffer - (company-mode) - (let (company-frontends - company-transformers - (company-backends (list 'company-async-backend))) - (company-manual-begin) - (should (equal "foo" company-prefix)) - (should (equal '("abc" "abd") company-candidates))))) - -(ert-deftest company-idle-begin-allows-async-candidates () - (with-temp-buffer - (company-mode) - (let (company-frontends - company-transformers - (company-backends (list 'company-async-backend))) - (company-idle-begin (current-buffer) (selected-window) - (buffer-chars-modified-tick) (point)) - (should (null company-candidates)) - (sleep-for 0.1) - (should (equal "foo" company-prefix)) - (should (equal '("abc" "abd") company-candidates))))) - -(ert-deftest company-idle-begin-cancels-async-candidates-if-buffer-changed () - (with-temp-buffer - (company-mode) - (let (company-frontends - (company-backends (list 'company-async-backend))) - (company-idle-begin (current-buffer) (selected-window) - (buffer-chars-modified-tick) (point)) - (should (null company-candidates)) - (insert "a") - (sleep-for 0.1) - (should (null company-candidates))))) - -(ert-deftest company-idle-begin-async-allows-immediate-callbacks () - (with-temp-buffer - (company-mode) - (let (company-frontends - (company-backends - (list (lambda (command &optional arg) - (pcase command - (`prefix (buffer-substring (point-min) (point))) - (`candidates - (let ((c (all-completions arg '("abc" "def")))) - (cons :async - (lambda (cb) (funcall cb c))))) - (`no-cache t))))) - (company-minimum-prefix-length 0)) - (company-idle-begin (current-buffer) (selected-window) - (buffer-chars-modified-tick) (point)) - (should (equal '("abc" "def") company-candidates)) - (let ((last-command-event ?a)) - (company-call 'self-insert-command 1)) - (should (equal '("abc") company-candidates))))) - -(ert-deftest company-multi-backend-forces-prefix-to-sync () - (with-temp-buffer - (let ((company-backend (list 'ignore - (lambda (command) - (should (eq command 'prefix)) - (cons :async - (lambda (cb) - (run-with-timer - 0.01 nil - (lambda () (funcall cb nil)))))) - (lambda (command) - (should (eq command 'prefix)) - "foo")))) - (should (equal "foo" (company-call-backend-raw 'prefix)))) - (let ((company-backend (list (lambda (_command) - (cons :async - (lambda (cb) - (run-with-timer - 0.01 nil - (lambda () (funcall cb "bar")))))) - (lambda (_command) - "foo")))) - (should (equal "bar" (company-call-backend-raw 'prefix)))))) - -(ert-deftest company-multi-backend-merges-deferred-candidates () - (with-temp-buffer - (let* ((immediate (lambda (command &optional arg) - (pcase command - (`prefix "foo") - (`candidates - (cons :async - (lambda (cb) (funcall cb '("f")))))))) - (company-backend (list 'ignore - (lambda (command &optional arg) - (pcase command - (`prefix "foo") - (`candidates - (should (equal arg "foo")) - (cons :async - (lambda (cb) - (run-with-timer - 0.01 nil - (lambda () (funcall cb '("a" "b"))))))))) - (lambda (command &optional arg) - (pcase command - (`prefix "foo") - (`candidates '("c" "d" "e")))) - immediate))) - (should (equal :async (car (company-call-backend-raw 'candidates "foo")))) - (should (equal '("a" "b" "c" "d" "e" "f") - (company-call-backend 'candidates "foo"))) - (let ((company-backend (list immediate))) - (should (equal '("f") (company-call-backend 'candidates "foo"))))))) - -;;; Transformers - -(ert-deftest company-occurrence-prefer-closest-above () - (with-temp-buffer - (save-window-excursion - (set-window-buffer nil (current-buffer)) - (insert "foo0 -foo1 -") - (save-excursion - (insert " -foo3 -foo2")) - (let ((company-backend 'company-dabbrev) - (company-occurrence-weight-function - 'company-occurrence-prefer-closest-above)) - (should (equal '("foo1" "foo0" "foo3" "foo2" "foo4") - (company-sort-by-occurrence - '("foo0" "foo1" "foo2" "foo3" "foo4")))))))) - -(ert-deftest company-occurrence-prefer-any-closest () - (with-temp-buffer - (save-window-excursion - (set-window-buffer nil (current-buffer)) - (insert "foo0 -foo1 -") - (save-excursion - (insert " -foo3 -foo2")) - (let ((company-backend 'company-dabbrev) - (company-occurrence-weight-function - 'company-occurrence-prefer-any-closest)) - (should (equal '("foo1" "foo3" "foo0" "foo2" "foo4") - (company-sort-by-occurrence - '("foo0" "foo1" "foo2" "foo3" "foo4")))))))) - -;;; Template - -(ert-deftest company-template-removed-after-the-last-jump () - (with-temp-buffer - (insert "{ }") - (goto-char 2) - (let ((tpl (company-template-declare-template (point) (1- (point-max))))) - (save-excursion - (dotimes (i 2) - (insert " ") - (company-template-add-field tpl (point) "foo"))) - (company-call 'template-forward-field) - (should (= 3 (point))) - (company-call 'template-forward-field) - (should (= 7 (point))) - (company-call 'template-forward-field) - (should (= 11 (point))) - (should (zerop (length (overlay-get tpl 'company-template-fields)))) - (should (null (overlay-buffer tpl)))))) - -(ert-deftest company-template-removed-after-input-and-jump () - (with-temp-buffer - (insert "{ }") - (goto-char 2) - (let ((tpl (company-template-declare-template (point) (1- (point-max))))) - (save-excursion - (insert " ") - (company-template-add-field tpl (point) "bar")) - (company-call 'template-move-to-first tpl) - (should (= 3 (point))) - (dolist (c (string-to-list "tee")) - (let ((last-command-event c)) - (company-call 'self-insert-command 1))) - (should (string= "{ tee }" (buffer-string))) - (should (overlay-buffer tpl)) - (company-call 'template-forward-field) - (should (= 7 (point))) - (should (null (overlay-buffer tpl)))))) - -(defun company-call (name &rest args) - (let* ((maybe (intern (format "company-%s" name))) - (command (if (fboundp maybe) maybe name))) - (let ((this-command command)) - (run-hooks 'pre-command-hook)) - (apply command args) - (let ((this-command command)) - (run-hooks 'post-command-hook)))) - -(ert-deftest company-template-c-like-templatify () - (with-temp-buffer - (let ((text "foo(int a, short b)")) - (insert text) - (company-template-c-like-templatify text) - (should (equal "foo(arg0, arg1)" (buffer-string))) - (should (looking-at "arg0")) - (should (equal "int a" - (overlay-get (company-template-field-at) 'display)))))) - -(ert-deftest company-template-c-like-templatify-trims-after-closing-paren () - (with-temp-buffer - (let ((text "foo(int a, short b)!@ #1334 a")) - (insert text) - (company-template-c-like-templatify text) - (should (equal "foo(arg0, arg1)" (buffer-string))) - (should (looking-at "arg0"))))) - -;;; Clang - -(ert-deftest company-clang-objc-templatify () - (with-temp-buffer - (let ((text "createBookWithTitle:andAuthor:")) - (insert text) - (company-clang-objc-templatify text) - (should (equal "createBookWithTitle:arg0 andAuthor:arg1" (buffer-string))) - (should (looking-at "arg0")) - (should (null (overlay-get (company-template-field-at) 'display)))))) diff --git a/elpa/git-commit-mode-0.13/git-commit-mode-autoloads.el b/elpa/git-commit-mode-0.13/git-commit-mode-autoloads.el deleted file mode 100644 index 44addbe..0000000 --- a/elpa/git-commit-mode-0.13/git-commit-mode-autoloads.el +++ /dev/null @@ -1,30 +0,0 @@ -;;; git-commit-mode-autoloads.el --- automatically extracted autoloads -;; -;;; Code: -(add-to-list 'load-path (or (file-name-directory #$) (car load-path))) - -;;;### (autoloads nil "git-commit-mode" "git-commit-mode.el" (21633 -;;;;;; 45697 22043 886000)) -;;; Generated autoloads from git-commit-mode.el - -(autoload 'git-commit-mode "git-commit-mode" "\ -Major mode for editing git commit messages. - -This mode helps with editing git commit messages both by -providing commands to do common tasks, and by highlighting the -basic structure of and errors in git commit messages. - -\(fn)" t nil) - -(eval-after-load 'magit '(progn (setq git-commit-skip-magit-header-regexp (format "\\(?:\\(?:[A-Za-z0-9-_]+: *.*\n\\)*%s\\)?" (regexp-quote magit-log-header-end))) (defvar git-commit-magit-font-lock-keywords `((,git-commit-skip-magit-header-regexp (0 'git-commit-skip-magit-header-face))) "Font lock keywords for Magit Log Edit Mode.") (define-derived-mode magit-log-edit-mode git-commit-mode "Magit Log Edit" (font-lock-add-keywords nil git-commit-magit-font-lock-keywords) (set (make-local-variable 'git-commit-commit-function) (apply-partially #'call-interactively 'magit-log-edit-commit))) (substitute-key-definition 'magit-log-edit-toggle-signoff 'git-commit-signoff magit-log-edit-mode-map) (substitute-key-definition 'magit-log-edit-commit 'git-commit-commit magit-log-edit-mode-map))) - -(dolist (pattern '("/COMMIT_EDITMSG\\'" "/NOTES_EDITMSG\\'" "/MERGE_MSG\\'" "/TAG_EDITMSG\\'" "/PULLREQ_EDITMSG\\'")) (add-to-list 'auto-mode-alist (cons pattern 'git-commit-mode))) - -;;;*** - -;; Local Variables: -;; version-control: never -;; no-byte-compile: t -;; no-update-autoloads: t -;; End: -;;; git-commit-mode-autoloads.el ends here diff --git a/elpa/git-commit-mode-0.13/git-commit-mode-pkg.el b/elpa/git-commit-mode-0.13/git-commit-mode-pkg.el deleted file mode 100644 index 647599b..0000000 --- a/elpa/git-commit-mode-0.13/git-commit-mode-pkg.el +++ /dev/null @@ -1 +0,0 @@ -(define-package "git-commit-mode" "0.13" "Major mode for editing git commit messages" 'nil) diff --git a/elpa/git-commit-mode-0.13/git-commit-mode.el b/elpa/git-commit-mode-0.13/git-commit-mode.el deleted file mode 100644 index 4a312d6..0000000 --- a/elpa/git-commit-mode-0.13/git-commit-mode.el +++ /dev/null @@ -1,601 +0,0 @@ -;;; git-commit-mode.el --- Major mode for editing git commit messages -*- lexical-binding: t; -*- - -;; Copyright (c) 2012, 2013 Sebastian Wiesner -;; Copyright (c) 2010 Florian Ragwitz. -;; -;; Author: Sebastian Wiesner -;; Florian Ragwitz -;; Maintainer: Sebastian Wiesner -;; URL: https://github.com/lunaryorn/git-modes -;; Version: 0.13 -;; Keywords: convenience vc git - -;; This file is not part of GNU Emacs. - -;; This program 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 2 of the License, or (at your option) any later -;; version. - -;; This program 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 -;; this program; if not, write to the Free Software Foundation, Inc., 51 -;; Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -;;; Commentary: - -;; A major mode for editing Git commit messages. - -;; * Formatting -;; -;; Highlight the formatting of git commit messages and indicate errors according -;; to the guidelines for commit messages (see -;; http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). -;; -;; Highlight the first line (aka "summary") specially if it exceeds 54 -;; characters. -;; -;; Enable `auto-fill-mode' and set the `fill-column' to 72 according to the -;; aforementioned guidelines. - -;; * Headers -;; -;; Provide commands to insert standard headers into commit messages. -;; -;; - C-c C-x s or C-c C-s inserts Signed-off-by (`git-commit-signoff'). -;; - C-C C-x a inserts Acked-by (`git-commit-ack'). -;; - C-c C-x t inserts Tested-by (`git-commit-test'). -;; - C-c C-x r inserts Reviewed-by (`git-commit-review'). -;; - C-c C-x o inserts Cc (`git-commit-cc'). -;; - C-c C-x p inserts Reported-by (`git-commit-reported'). - -;; * Committing -;; -;; C-c C-c finishes a commit. By default this means to save and kill the -;; buffer. Customize `git-commit-commit-function' to change this behaviour. -;; -;; Check a buffer for stylistic errors before committing, and ask for -;; confirmation before committing with style errors. - -;; * Magit integration -;; -;; Overwrite `magit-log-edit-mode' to provide font locking and header insertion -;; for Magit. -;; -;; Change the keymap of `magit-log-edit-mode' to use the header insertion of -;; `git-commit-mode'. - -;;; Code: - -(defgroup git-commit nil - "Mode for editing git commit messages" - :prefix "git-commit-" - :group 'tools) - -(defgroup git-commit-faces nil - "Faces for highlighting git commit messages" - :prefix "git-commit-" - :group 'git-commit - :group 'faces) - -(defface git-commit-summary-face - '((t :inherit font-lock-type-face)) - "Face used to highlight the summary in git commit messages" - :group 'git-commit-faces) - -(defface git-commit-overlong-summary-face - '((t :inherit font-lock-warning-face)) - "Face used to highlight overlong parts of git commit message summaries" - :group 'git-commit-faces) - -(defface git-commit-nonempty-second-line-face - '((t :inherit font-lock-warning-face)) - "Face used to highlight text on the second line of git commit messages" - :group 'git-commit-faces) - -(defface git-commit-note-face - '((t :inherit font-lock-string-face)) - "Face used to highlight notes in git commit messages" - :group 'git-commit-faces) - -(defface git-commit-pseudo-header-face - '((t :inherit font-lock-string-face)) - "Font used to hightlight pseudo headers in git commit messages" - :group 'git-commit-faces) - -(defface git-commit-known-pseudo-header-face - '((t :inherit font-lock-keyword-face)) - "Face used to hightlight common pseudo headers in git commit messages" - :group 'git-commit-faces) - -(defface git-commit-branch-face - '((t :inherit font-lock-variable-name-face)) - "Face used to highlight the branch name in comments in git commit messages" - :group 'git-commit-faces) - -(defface git-commit-no-branch-face - '((t :inherit git-commit-branch-face)) - "Face used when a commit is going to be made outside of any branches" - :group 'git-commit-faces) - -(defface git-commit-comment-heading-face - '((t :inherit git-commit-known-pseudo-header-face)) - "Face used to highlight section headings in the default -comments in git commit messages" - :group 'git-commit-faces) - -(defface git-commit-comment-file-face - '((t :inherit git-commit-pseudo-header-face)) - "Face used to highlight file names in the default comments in -git commit messages" - :group 'git-commit-faces) - -(defface git-commit-comment-action-face - '((t :inherit git-commit-branch-face)) - "Face used to highlight what has happened to files in the -default comments in git commit messages" - :group 'git-commit-faces) - -(defface git-commit-skip-magit-header-face - '((t :inherit font-lock-preprocessor-face)) - "Face used to highlight the magit header that should be skipped" - :group 'git-commit-faces) - -(defun git-commit-end-session () - "Save the buffer and end the session. - -If the current buffer has clients from the Emacs server, call -`server-edit' to mark the buffer as done and let the clients -continue, otherwise kill the buffer via `kill-buffer'." - (save-buffer) - (if (and (fboundp 'server-edit) - (boundp 'server-buffer-clients) - server-buffer-clients) - (server-edit) ; The message buffer comes from emacsclient - (kill-buffer))) - -(defcustom git-commit-commit-function - #'git-commit-end-session - "Function called by `git-commit-commit' to actually perform a commit. - -The function is called without argument, with the current buffer -being the commit message buffer. It shall return t, if the -commit was successful, or nil otherwise." - :group 'git-commit - :type '(radio (function-item :doc "Save the buffer and end the session." - git-commit-end-session) - (function))) - -(defcustom git-commit-confirm-commit t - "Whether to ask for confirmation before committing. - -If t, ask for confirmation before creating a commit with style -errors, unless the commit is forced. If nil, never ask for -confirmation before committing." - :group 'git-commit - :type '(choice (const :tag "On style errors" t) - (const :tag "Never" nil))) - -(defun git-commit-has-style-errors-p () - "Check whether the current buffer has style errors. - -Return t, if the current buffer has style errors, or nil -otherwise." - (save-excursion - (goto-char (point-min)) - (when (re-search-forward (git-commit-find-summary-regexp) nil t) - (or (string-match-p ".+" (or (match-string 2) "")) - (string-match-p "^.+$" (or (match-string 3) "")))))) - -(defun git-commit-may-do-commit (&optional force) - "Check whether a commit may be performed. - -Check for stylistic errors in the current message, unless FORCE -is non-nil. If stylistic errors are found, ask the user to -confirm commit depending on `git-commit-confirm-commit'. - -Return t if the commit may be performed, or nil otherwise." - (cond - ((or force (not git-commit-confirm-commit)) - t) - ((git-commit-has-style-errors-p) - (yes-or-no-p "Buffer has style errors. Commit anyway?")) - (t t))) - -(defun git-commit-commit (&optional force) - "Finish editing the commit message and commit. - -Check for stylistic errors in the current commit, and ask the -user for confirmation depending on `git-commit-confirm-commit'. -If FORCE is non-nil or if a raw prefix arg is given, commit -immediately without asking. - -Call `git-commit-commit-function' to actually perform the commit. - -Return t, if the commit was successful, or nil otherwise." - (interactive "P") - (if (git-commit-may-do-commit force) - (funcall git-commit-commit-function) - (message "Commit canceled due to stylistic errors."))) - -(defun git-commit-git-config-var (key) - "Retrieve a git configuration value. -Invokes 'git config --get' to retrieve the value for the -configuration key KEY." - (ignore-errors - (car (process-lines "git" "config" "--get" key)))) - -(defun git-commit-first-env-var (&rest vars) - "Get the value of the first defined environment variable. -Walk VARS, call `getenv' on each element and return the first -non-nil return value of `getenv'." - (let ((current vars) - (val nil)) - (while (and (not val) current) - (setq val (getenv (car current))) - (setq current (cdr current))) - val)) - -(defun git-commit-committer-name () - "Get the git committer name of the current user. -This uses the same mechanism git itself uses. That is, using the -value of the 'GIT_AUTHOR_NAME' or 'GIT_COMMITTER_NAME' -environment variables, or the 'user.name' git configuration -variable. - -If the above mechanism fails, the value of the variable -`user-full-name' is used." - (or - (git-commit-first-env-var "GIT_AUTHOR_NAME" "GIT_COMMITTER_NAME") - (git-commit-git-config-var "user.name") - user-full-name)) - -(defun git-commit-committer-email () - "Get the git committer email address of the current user. -This uses the same mechanism git itself uses. That is, using the -value of the 'GIT_AUTHOR_EMAIL', 'GIT_COMMITTER_EMAIL', or -'EMAIL' environment variables, or the 'user.email' git -configuration variable. - -If the above mechanism fails, the value of the variable -`user-email-address' is used." - (or - (git-commit-first-env-var "GIT_AUTHOR_EMAIL" "GIT_COMMITTER_EMAIL" "EMAIL") - (git-commit-git-config-var "user.email") - user-mail-address)) - -(defconst git-commit-known-pseudo-headers - '("Signed-off-by" - "Acked-by" - "Cc" - "Reported-by" - "Tested-by" - "Reviewed-by") - "A list of git pseudo headers to be highlighted.") - -(defun git-commit-find-pseudo-header-position () - "Find the position at which commit pseudo headers should be inserted. - -Those headers usually live at the end of a commit message, but -before any trailing comments git or the user might have -inserted." - (save-excursion - (goto-char (point-max)) - (if (not (re-search-backward "^\\S<.+$" nil t)) - ;; no comment lines anywhere before end-of-buffer, so we - ;; want to insert right there - (point-max) - ;; there's some comments at the end, so we want to insert before - ;; those; keep going until we find the first non-empty line - ;; NOTE: if there is no newline at the end of (point), - ;; (forward-line 1) will take us to (point-at-eol). - (if (eq (point-at-bol) (point-at-eol)) (re-search-backward "^.+$" nil t)) - (forward-line 1) - (point)))) - -(defun git-commit-determine-pre-for-pseudo-header () - "Find the characters to insert before the pseudo header. -Returns either zero, one or two newlines after computation. - -`point' either points to an empty line (with a non-empty previous -line) or the end of a non-empty line." - (let ((pre "") - (prev-line nil)) - (if (not (eq (point) (point-at-bol))) - (progn - (setq pre (concat pre "\n")) - (setq prev-line (thing-at-point 'line))) - ;; else: (point) is at an empty line - (when (not (eq (point) (point-min))) - (setq prev-line - (save-excursion - (forward-line -1) - (thing-at-point 'line))))) - - ;; we have prev-line now; if it doesn't match any known pseudo - ;; header, add a newline - (when prev-line - (if (not (delq nil (mapcar (lambda (pseudo-header) (string-match pseudo-header prev-line)) - git-commit-known-pseudo-headers))) - (setq pre (concat pre "\n")))) - pre)) - -(defun git-commit-insert-header (type name email) - "Insert a header into the commit message. -The inserted headers have the format 'TYPE: NAME '. - -The header is inserted at the position returned by -`git-commit-find-pseudo-header-position'. When this position -isn't after an existing header or a newline, an extra newline is -inserted before the header." - (let ((header-at (git-commit-find-pseudo-header-position))) - (save-excursion - (goto-char header-at) - (let ((pre (git-commit-determine-pre-for-pseudo-header))) - (insert (format "%s%s: %s <%s>\n" pre type name email)))))) - -(defun git-commit-insert-header-as-self (type) - "Insert a header with the name and email address of the current user. -Call `git-commit-insert-header' with the user name and email -address provided by `git-commit-committer-name' and -`git-commit-committer-email'. - -TYPE is passed along unmodified." - (let ((committer-name (git-commit-committer-name)) - (committer-email (git-commit-committer-email))) - (git-commit-insert-header type committer-name committer-email))) - -(defmacro git-define-git-commit-self (action header) - "Create function git-commit-ACTION. -ACTION will be part of the function name. -HEADER is the actual header to be inserted into the comment." - (let ((func-name (intern (concat "git-commit-" action)))) - `(defun ,func-name () - ,(format "Insert a '%s' header at the end of the commit message. - -The author name and email address used for the header are -retrieved automatically with the same mechanism git uses." - header) - (interactive) - (git-commit-insert-header-as-self ,header)))) - -(git-define-git-commit-self "ack" "Acked-by") -(git-define-git-commit-self "review" "Reviewed-by") -(git-define-git-commit-self "signoff" "Signed-off-by") -(git-define-git-commit-self "test" "Tested-by") - -(defmacro git-define-git-commit (action header) - "Create interactive function git-commit-ACTION. -ACTION will be part of the function name. -HEADER is the actual header to be inserted into the comment." - (let ((func-name (intern (concat "git-commit-" action)))) - `(defun ,func-name (name email) - ,(format "Insert a '%s' header at the end of the commit message. -The value of the header is determined by NAME and EMAIL. - -When called interactively, both NAME and EMAIL are read from the -minibuffer." - header) - (interactive - (list (read-string "Name: ") - (read-string "Email: "))) - (git-commit-insert-header ,header name email)))) - -(git-define-git-commit "cc" "Cc") -(git-define-git-commit "reported" "Reported-by") - -(defconst git-commit-comment-headings-alist - '(("Not currently on any branch." . git-commit-no-branch-face) - ("Changes to be committed:" . git-commit-comment-heading-face) - ("Untracked files:" . git-commit-comment-heading-face) - ("Changed but not updated:" . git-commit-comment-heading-face) - ("Changes not staged for commit:" . git-commit-comment-heading-face) - ("Unmerged paths:" . git-commit-comment-heading-face)) - "Headings in message comments. - -The `car' of each cell is the heading text, the `cdr' the face to -use for fontification.") - -(defconst git-commit-skip-before-summary-regexp - "\\(?:\\(?:\\s-*\\|\\s<.*\\)\n\\)*" - "Regexp to skip empty lines and comments before the summary. - -Do not use this expression directly, instead call -`git-commit-find-summary-regexp' to create a regular expression -to match the summary line.") - -(defconst git-commit-summary-regexp - "\\(?:^\\(.\\{,50\\}\\)\\(.*?\\)$\\)" - "Regexp to match the summary line. - -Do not use this expression directly, instead call -`git-commit-find-summary-regexp' to create a regular expression -to match the summary line.") - -(defconst git-commit-nonempty-second-line-regexp - "\\(?:\n\\(.*\\)\\)?$" - "Regexp to match a nonempty line following the summary. - -Do not use this expression directly, instead call -`git-commit-find-summary-regexp' to create a regular expression -to match the summary line.") - -(defvar git-commit-skip-magit-header-regexp nil - "Regexp to skip magit header. - -This variable is nil until `magit' is loaded. - -Do not use this expression directly, instead call -`git-commit-find-summary-regexp' to create a regular expression -to match the summary line.") - -(defun git-commit-find-summary-regexp () - "Create a regular expression to find the Git summary line. - -Return a regular expression that starts at the beginning of the -buffer, skips over empty lines, comments and also over the magit -header, if the current buffer is a `magit-log-edit-mode' buffer, -and finds the summary line. - -The regular expression matches three groups. The first group is -the summary line, the second group contains any overlong part of -the summary, and the third group contains a nonempty line -following the summary line. The latter two groups may be empty." - (format "\\`%s%s%s%s" - (if (eq major-mode 'magit-log-edit-mode) - git-commit-skip-magit-header-regexp - "") - git-commit-skip-before-summary-regexp - git-commit-summary-regexp - git-commit-nonempty-second-line-regexp)) - -(defun git-commit-mode-summary-font-lock-keywords (&optional errors) - "Create font lock keywords to fontify the Git summary. - -If ERRORS is non-nil create keywords that highlight errors in the -summary line, not the summary line itself." - (let ((regexp (git-commit-find-summary-regexp))) - (if errors - `(,regexp - (2 'git-commit-overlong-summary-face t t) - (3 'git-commit-nonempty-second-line-face t t)) - `(,regexp (1 'git-commit-summary-face t))))) - -(defun git-commit-mode-heading-keywords () - "Create font lock keywords to fontify comment headings. - -Known comment headings are provided by `git-commit-comment-headings'." - (mapcar (lambda (cell) `(,(format "^\\s<\\s-+\\(%s\\)$" - (regexp-quote (car cell))) - (1 ',(cdr cell) t))) - git-commit-comment-headings-alist)) - -(defvar git-commit-mode-font-lock-keywords - (append - `(("^\\s<.*$" . 'font-lock-comment-face) - ("^\\s<\\s-On branch \\(.*\\)$" (1 'git-commit-branch-face t)) - ("^\\s<\t\\(?:\\([^:]+\\):\\s-+\\)?\\(.*\\)$" - (1 'git-commit-comment-action-face t t) - (2 'git-commit-comment-file-face t)) - (,(concat "^\\(" - (regexp-opt git-commit-known-pseudo-headers) - ":\\)\\(\s.*\\)$") - (1 'git-commit-known-pseudo-header-face) - (2 'git-commit-pseudo-header-face)) - ("^\\<\\S-+:\\s-.*$" . 'git-commit-pseudo-header-face) - (eval . (git-commit-mode-summary-font-lock-keywords)) - ("\\[[^\n]+?\\]" (0 'git-commit-note-face t)) ; Notes override summary line - ;; Warnings from overlong lines and nonempty second line override - ;; everything - (eval . (git-commit-mode-summary-font-lock-keywords t))) - (git-commit-mode-heading-keywords))) - -(defvar git-commit-mode-map - (let ((map (make-sparse-keymap))) - ;; Short shortcut ;) for the frequently used signoff header - (define-key map (kbd "C-c C-s") 'git-commit-signoff) - ;; Verbose shortcuts for all headers to avoid conflicts with magit bindings - (define-key map (kbd "C-c C-x s") 'git-commit-signoff) - (define-key map (kbd "C-c C-x a") 'git-commit-ack) - (define-key map (kbd "C-c C-x t") 'git-commit-test) - (define-key map (kbd "C-c C-x r") 'git-commit-review) - (define-key map (kbd "C-c C-x o") 'git-commit-cc) - (define-key map (kbd "C-c C-x p") 'git-commit-reported) - ;; Committing - (define-key map (kbd "C-c C-c") 'git-commit-commit) - map) - "Key map used by `git-commit-mode'.") - -(defvar git-commit-mode-syntax-table - (let ((table (make-syntax-table text-mode-syntax-table))) - (modify-syntax-entry ?# "<" table) - (modify-syntax-entry ?\n ">" table) - (modify-syntax-entry ?\r ">" table) - table) - "Syntax table used by `git-commit-mode'.") - -(defun git-commit-font-lock-diff () - "Add font lock on diff." - (save-excursion - (goto-char (point-min)) - (when (re-search-forward "^diff --git" nil t) - (let ((beg (match-beginning 0))) - (let* ((buffer (current-buffer)) - (font-lock-verbose nil) - (font-lock-support-mode nil) - (text (with-temp-buffer - (insert - (with-current-buffer buffer - (buffer-substring-no-properties beg (point-max)))) - (diff-mode) - (font-lock-fontify-buffer) - (let ((pos (point-min)) - next) - (while (setq next (next-single-property-change pos 'face)) - (put-text-property pos next 'font-lock-face - (get-text-property pos 'face)) - (setq pos next))) - (buffer-string)))) - (delete-region beg (point-max)) - (insert text)))))) - -;;;###autoload -(define-derived-mode git-commit-mode text-mode "Git Commit" - "Major mode for editing git commit messages. - -This mode helps with editing git commit messages both by -providing commands to do common tasks, and by highlighting the -basic structure of and errors in git commit messages." - ;; Font locking - (setq font-lock-defaults '(git-commit-mode-font-lock-keywords t)) - (set (make-local-variable 'font-lock-multiline) t) - (git-commit-font-lock-diff) - ;; Filling according to the guidelines - (setq fill-column 72) - (turn-on-auto-fill) - ;; Recognize changelog-style paragraphs - (set (make-local-variable 'paragraph-start) - (concat paragraph-start "\\|*\\|(")) - ;; Do not remember point location in commit messages - (when (fboundp 'toggle-save-place) - (toggle-save-place 0))) - -;;;###autoload -;; Overwrite magit-log-edit-mode to derive from git-commit-mode, and change it's -;; key bindings to use our commit and header insertion bindings -(eval-after-load 'magit - '(progn - (setq git-commit-skip-magit-header-regexp - (format - "\\(?:\\(?:[A-Za-z0-9-_]+: *.*\n\\)*%s\\)?" - (regexp-quote magit-log-header-end))) - - (defvar git-commit-magit-font-lock-keywords - `((,git-commit-skip-magit-header-regexp - (0 'git-commit-skip-magit-header-face))) - "Font lock keywords for Magit Log Edit Mode.") - - (define-derived-mode magit-log-edit-mode git-commit-mode "Magit Log Edit" - (font-lock-add-keywords nil git-commit-magit-font-lock-keywords) - (set (make-local-variable 'git-commit-commit-function) - (apply-partially #'call-interactively 'magit-log-edit-commit))) - (substitute-key-definition 'magit-log-edit-toggle-signoff - 'git-commit-signoff - magit-log-edit-mode-map) - (substitute-key-definition 'magit-log-edit-commit - 'git-commit-commit - magit-log-edit-mode-map))) - -;;;###autoload -(dolist (pattern '("/COMMIT_EDITMSG\\'" "/NOTES_EDITMSG\\'" - "/MERGE_MSG\\'" "/TAG_EDITMSG\\'" - "/PULLREQ_EDITMSG\\'")) - (add-to-list 'auto-mode-alist (cons pattern 'git-commit-mode))) - -(provide 'git-commit-mode) - -;;; git-commit-mode.el ends here diff --git a/elpa/git-commit-mode-1.0.0/git-commit-mode-autoloads.el b/elpa/git-commit-mode-1.0.0/git-commit-mode-autoloads.el new file mode 100644 index 0000000..33b0320 --- /dev/null +++ b/elpa/git-commit-mode-1.0.0/git-commit-mode-autoloads.el @@ -0,0 +1,35 @@ +;;; git-commit-mode-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (or (file-name-directory #$) (car load-path))) + +;;;### (autoloads nil "git-commit-mode" "git-commit-mode.el" (21831 +;;;;;; 16636 620188 15000)) +;;; Generated autoloads from git-commit-mode.el + +(autoload 'git-commit-mode "git-commit-mode" "\ +Major mode for editing git commit messages. + +This mode helps with editing git commit messages both by +providing commands to do common tasks, and by highlighting the +basic structure of and errors in git commit messages. + +\(fn)" t nil) + +(add-to-list 'auto-mode-alist '("/MERGE_MSG\\'" . git-commit-mode)) + +(add-to-list 'auto-mode-alist '("/\\(?:COMMIT\\|NOTES\\|TAG\\|PULLREQ\\)_EDITMSG\\'" . git-commit-mode)) + +;;;*** + +;;;### (autoloads nil nil ("git-commit-mode-pkg.el") (21831 16636 +;;;;;; 639156 530000)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; git-commit-mode-autoloads.el ends here diff --git a/elpa/git-commit-mode-1.0.0/git-commit-mode-pkg.el b/elpa/git-commit-mode-1.0.0/git-commit-mode-pkg.el new file mode 100644 index 0000000..4a8e4c6 --- /dev/null +++ b/elpa/git-commit-mode-1.0.0/git-commit-mode-pkg.el @@ -0,0 +1 @@ +(define-package "git-commit-mode" "1.0.0" "Major mode for editing git commit messages" 'nil) diff --git a/elpa/git-commit-mode-1.0.0/git-commit-mode.el b/elpa/git-commit-mode-1.0.0/git-commit-mode.el new file mode 100644 index 0000000..1cedd79 --- /dev/null +++ b/elpa/git-commit-mode-1.0.0/git-commit-mode.el @@ -0,0 +1,668 @@ +;;; git-commit-mode.el --- Major mode for editing git commit messages -*- lexical-binding: t; -*- + +;; Copyright (c) 2010-2012 Florian Ragwitz +;; Copyright (c) 2012-2013 Sebastian Wiesner +;; Copyright (C) 2010-2015 The Magit Project Developers + +;; Authors: Jonas Bernoulli +;; Sebastian Wiesner +;; Florian Ragwitz +;; Maintainer: Jonas Bernoulli +;; Homepage: https://github.com/magit/git-modes +;; Keywords: convenience vc git +;; Package-Version: 1.0.0 + +;; This file is not part of GNU Emacs. + +;; This file 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. + +;; This file 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 this file. If not, see . + +;;; Commentary: + +;; A major mode for editing Git commit messages. + +;;;; Formatting + +;; Highlight the formatting of git commit messages and indicate errors according +;; to the guidelines for commit messages (see +;; http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). +;; +;; Highlight the first line (aka "summary") specially if it exceeds 50 +;; characters (configurable using `git-commit-summary-max-length'). +;; +;; Enable `auto-fill-mode' and set the `fill-column' to 72 according to the +;; aforementioned guidelines (configurable using `git-commit-fill-column'). + +;;;; Headers + +;; Provide commands to insert standard headers into commit messages. +;; +;; - C-c C-s inserts Signed-off-by (`git-commit-signoff'). +;; - C-C C-a inserts Acked-by (`git-commit-ack'). +;; - C-c C-t inserts Tested-by (`git-commit-test'). +;; - C-c C-r inserts Reviewed-by (`git-commit-review'). +;; - C-c C-o inserts Cc (`git-commit-cc'). +;; - C-c C-p inserts Reported-by (`git-commit-reported'). + +;;;; Committing + +;; C-c C-c finishes a commit. +;; +;; Check a buffer for stylistic errors before committing, and ask for +;; confirmation before committing with style errors. + +;;; Code: + +(require 'log-edit) +(require 'ring) +(require 'server) + +;;; Options +;;;; Variables + +(defgroup git-commit nil + "Edit Git commit messages." + :prefix "git-commit-" + :group 'tools) + +(defcustom git-commit-confirm-commit nil + "Whether to ask for confirmation before committing. + +If t, ask for confirmation before creating a commit with style +errors, unless the commit is forced. If nil, never ask for +confirmation before committing." + :group 'git-commit + :type '(choice (const :tag "On style errors" t) + (const :tag "Never" nil))) + +(defcustom git-commit-mode-hook '(turn-on-auto-fill) + "Hook run when entering Git Commit mode." + :options '(turn-on-auto-fill flyspell-mode git-commit-save-message) + :type 'hook + :group 'git-commit) + +(defcustom git-commit-kill-buffer-hook '(git-commit-save-message) + "Hook run when killing a Git Commit mode buffer. +This hook is run by both `git-commit-commit' +and `git-commit-abort'." + :options '(git-commit-save-message) + :type 'hook + :group 'git-commit) + +(defcustom git-commit-summary-max-length 50 + "Fontify characters beyond this column in summary lines as errors." + :group 'git-commit + :type 'number) + +(defcustom git-commit-fill-column 72 + "Automatically wrap commit message lines beyond this column." + :group 'git-commit + :type 'number) + +(defcustom git-commit-known-pseudo-headers + '("Signed-off-by" "Acked-by" "Cc" + "Suggested-by" "Reported-by" "Tested-by" "Reviewed-by") + "A list of git pseudo headers to be highlighted." + :group 'git-commit + :type '(repeat string)) + +;;;; Faces + +(defgroup git-commit-faces nil + "Faces for highlighting Git commit messages." + :prefix "git-commit-" + :group 'git-commit + :group 'faces) + +(defface git-commit-summary-face + '((t :inherit font-lock-type-face)) + "Face used to highlight the summary in git commit messages" + :group 'git-commit-faces) + +(defface git-commit-overlong-summary-face + '((t :inherit font-lock-warning-face)) + "Face used to highlight overlong parts of git commit message summaries" + :group 'git-commit-faces) + +(defface git-commit-nonempty-second-line-face + '((t :inherit font-lock-warning-face)) + "Face used to highlight text on the second line of git commit messages" + :group 'git-commit-faces) + +(defface git-commit-note-face + '((t :inherit font-lock-string-face)) + "Face used to highlight notes in git commit messages" + :group 'git-commit-faces) + +(defface git-commit-pseudo-header-face + '((t :inherit font-lock-string-face)) + "Font used to hightlight pseudo headers in git commit messages" + :group 'git-commit-faces) + +(defface git-commit-known-pseudo-header-face + '((t :inherit font-lock-keyword-face)) + "Face used to hightlight common pseudo headers in git commit messages" + :group 'git-commit-faces) + +(defface git-commit-branch-face + '((t :inherit font-lock-variable-name-face)) + "Face used to highlight the branch name in comments in git commit messages" + :group 'git-commit-faces) + +(defface git-commit-no-branch-face + '((t :inherit git-commit-branch-face)) + "Face used when a commit is going to be made outside of any branches" + :group 'git-commit-faces) + +(defface git-commit-comment-heading-face + '((t :inherit git-commit-known-pseudo-header-face)) + "Face used to highlight section headings in the default +comments in git commit messages" + :group 'git-commit-faces) + +(defface git-commit-comment-file-face + '((t :inherit git-commit-pseudo-header-face)) + "Face used to highlight file names in the default comments in +git commit messages" + :group 'git-commit-faces) + +(defface git-commit-comment-action-face + '((t :inherit git-commit-branch-face)) + "Face used to highlight what has happened to files in the +default comments in git commit messages" + :group 'git-commit-faces) + +;;; Keymap + +(defvar git-commit-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "C-c C-c") 'git-commit-commit) + (define-key map (kbd "C-c C-k") 'git-commit-abort) + (define-key map (kbd "C-c C-s") 'git-commit-signoff) + (define-key map (kbd "C-c C-a") 'git-commit-ack) + (define-key map (kbd "C-c C-t") 'git-commit-test) + (define-key map (kbd "C-c C-r") 'git-commit-review) + (define-key map (kbd "C-c C-o") 'git-commit-cc) + (define-key map (kbd "C-c C-p") 'git-commit-reported) + (define-key map (kbd "C-c C-i") 'git-commit-suggested) + (define-key map (kbd "C-c M-s") 'git-commit-save-message) + (define-key map (kbd "M-p") 'git-commit-prev-message) + (define-key map (kbd "M-n") 'git-commit-next-message) + (define-key map [remap server-edit] 'git-commit-commit) + (define-key map [remap kill-buffer] 'git-commit-abort) + (define-key map [remap ido-kill-buffer] 'git-commit-abort) + (define-key map [remap iswitchb-kill-buffer] 'git-commit-abort) + ;; Old bindings to avoid confusion + (define-key map (kbd "C-c C-x s") 'git-commit-signoff) + (define-key map (kbd "C-c C-x a") 'git-commit-ack) + (define-key map (kbd "C-c C-x t") 'git-commit-test) + (define-key map (kbd "C-c C-x r") 'git-commit-review) + (define-key map (kbd "C-c C-x o") 'git-commit-cc) + (define-key map (kbd "C-c C-x p") 'git-commit-reported) + map) + "Key map used by `git-commit-mode'.") + +;;; Menu + +(require 'easymenu) +(easy-menu-define git-commit-mode-menu git-commit-mode-map + "Git Commit Mode Menu" + '("Commit" + ["Previous" git-commit-prev-message t] + ["Next" git-commit-next-message t] + "-" + ["Ack" git-commit-ack :active t + :help "Insert an 'Acked-by' header"] + ["Sign-Off" git-commit-signoff :active t + :help "Insert a 'Signed-off-by' header"] + ["Tested-by" git-commit-test :active t + :help "Insert a 'Tested-by' header"] + ["Reviewed-by" git-commit-review :active t + :help "Insert a 'Reviewed-by' header"] + ["CC" git-commit-cc t + :help "Insert a 'Cc' header"] + ["Reported" git-commit-reported :active t + :help "Insert a 'Reported-by' header"] + ["Suggested" git-commit-suggested t + :help "Insert a 'Suggested-by' header"] + "-" + ["Save" git-commit-save-message t] + ["Cancel" git-commit-abort t] + ["Commit" git-commit-commit t])) + +;;; Committing + +(defvar git-commit-commit-hook nil + "Hook run by `git-commit-commit' unless clients exist. +Only use this if you know what you are doing.") + +(defvar git-commit-previous-winconf nil) + +(defmacro git-commit-restore-previous-winconf (&rest body) + "Run BODY and then restore `git-commit-previous-winconf'. +When `git-commit-previous-winconf' is nil or was created from +another frame do nothing." + (declare (indent 0)) + (let ((winconf (make-symbol "winconf")) + (frame (make-symbol "frame"))) + `(let ((,winconf git-commit-previous-winconf) + (,frame (selected-frame))) + ,@body + (when (and ,winconf + (equal ,frame (window-configuration-frame ,winconf))) + (set-window-configuration ,winconf) + (setq git-commit-previous-winconf nil))))) + +(defun git-commit-commit (&optional force) + "Finish editing the commit message and commit. + +Check for stylistic errors in the current commit, and ask the +user for confirmation depending on `git-commit-confirm-commit'. +If FORCE is non-nil or if a raw prefix arg is given, commit +immediately without asking. + +Return t, if the commit was successful, or nil otherwise." + (interactive "P") + (if (and git-commit-confirm-commit + (git-commit-has-style-errors-p) + (not force) + (not (y-or-n-p "Commit despite stylistic errors?"))) + (message "Commit canceled due to stylistic errors.") + (save-buffer) + (run-hooks 'git-commit-kill-buffer-hook) + (remove-hook 'kill-buffer-query-functions + 'git-commit-kill-buffer-noop t) + (git-commit-restore-previous-winconf + (if (git-commit-buffer-clients) + (server-edit) + (run-hook-with-args 'git-commit-commit-hook) + (kill-buffer))))) + +(defun git-commit-abort () + "Abort the commit. +The commit message is saved to the kill ring." + (interactive) + (when (< emacs-major-version 24) + ;; Emacsclient doesn't exit with non-zero when -error is used. + ;; Instead cause Git to error out by feeding it an empty file. + (erase-buffer)) + (save-buffer) + (run-hooks 'git-commit-kill-buffer-hook) + (remove-hook 'kill-buffer-hook 'server-kill-buffer t) + (remove-hook 'kill-buffer-query-functions 'git-commit-kill-buffer-noop t) + (git-commit-restore-previous-winconf + (let ((buffer (current-buffer)) + (clients (git-commit-buffer-clients))) + (if clients + (progn + (dolist (client clients) + (ignore-errors + (server-send-string client "-error Commit aborted by user")) + (delete-process client)) + (when (buffer-live-p buffer) + (kill-buffer buffer))) + (kill-buffer)))) + (accept-process-output nil 0.1) + (message (concat "Commit aborted." + (when (memq 'git-commit-save-message + git-commit-kill-buffer-hook) + " Message saved to `log-edit-comment-ring'.")))) + +(defun git-commit-buffer-clients () + (and (fboundp 'server-edit) + (boundp 'server-buffer-clients) + server-buffer-clients)) + +;;; History + +(defun git-commit-save-message () + "Save current message to `log-edit-comment-ring'." + (interactive) + (let ((message (buffer-substring + (point-min) + (git-commit-find-pseudo-header-position)))) + (when (and (string-match "^\\s-*\\sw" message) + (or (ring-empty-p log-edit-comment-ring) + (not (ring-member log-edit-comment-ring message)))) + ;; if index is nil, we end up cycling back to message we just saved! + (unless log-edit-comment-ring-index + (setq log-edit-comment-ring-index 0)) + (ring-insert log-edit-comment-ring message)))) + +(defun git-commit-prev-message (arg) + "Cycle backward through message history, after saving current message. +With a numeric prefix ARG, go back ARG comments." + (interactive "*p") + (when (and (git-commit-save-message) (> arg 0)) + (setq log-edit-comment-ring-index + (log-edit-new-comment-index + arg (ring-length log-edit-comment-ring)))) + (save-restriction + (narrow-to-region (point-min) (git-commit-find-pseudo-header-position)) + (log-edit-previous-comment arg))) + +(defun git-commit-next-message (arg) + "Cycle forward through message history, after saving current message. +With a numeric prefix ARG, go forward ARG comments." + (interactive "*p") + (git-commit-prev-message (- arg))) + +;;; Headers + +(defun git-commit-find-pseudo-header-position () + "Find the position at which commit pseudo headers should be inserted. + +Those headers usually live at the end of a commit message, but +before any trailing comments git or the user might have +inserted." + (save-excursion + (goto-char (point-max)) + (if (re-search-backward "^[^#\n]" nil t) + ;; we found last non-empty non-comment line, headers go after + (forward-line 1) + ;; there's only blanks & comments, headers go before comments + (goto-char (point-min)) + (and (re-search-forward "^#" nil t) (forward-line 0))) + (skip-chars-forward "\n") + (point))) + +(defun git-commit-determine-pre-for-pseudo-header () + "Find the characters to insert before the pseudo header. +Returns either zero, one or two newlines after computation. + +`point' either points to an empty line (with a non-empty previous +line) or the end of a non-empty line." + (let ((pre "") + (prev-line nil)) + (if (not (eq (point) (point-at-bol))) + (progn + (setq pre (concat pre "\n")) + (setq prev-line (thing-at-point 'line))) + ;; else: (point) is at an empty line + (when (not (eq (point) (point-min))) + (setq prev-line + (save-excursion + (forward-line -1) + (thing-at-point 'line))))) + + ;; we have prev-line now; if it doesn't match any known pseudo + ;; header, add a newline + (when prev-line + (if (not (delq nil (mapcar (lambda (pseudo-header) + (string-match pseudo-header prev-line)) + git-commit-known-pseudo-headers))) + (setq pre (concat pre "\n")))) + pre)) + +(defun git-commit-insert-header (type name email) + "Insert a header into the commit message. +The inserted header has the format 'TYPE: NAME '. + +The header is inserted at the position returned by +`git-commit-find-pseudo-header-position'. When this position +isn't after an existing header or a newline, an extra newline is +inserted before the header." + (let ((header-at (git-commit-find-pseudo-header-position))) + (save-excursion + (goto-char header-at) + (let ((pre (git-commit-determine-pre-for-pseudo-header))) + (insert (format "%s%s: %s <%s>\n" pre type name email)))))) + +(defun git-commit-insert-header-as-self (type) + "Insert a header with the name and email of the current user. +The inserted header has the format 'TYPE: NAME '. +Also see `git-commit-insert-header'." + (git-commit-insert-header + type + (or (getenv "GIT_AUTHOR_NAME") + (getenv "GIT_COMMITTER_NAME") + (ignore-errors (car (process-lines "git" "config" "user.name"))) + user-full-name) + (or (getenv "GIT_AUTHOR_EMAIL") + (getenv "GIT_COMMITTER_EMAIL") + (getenv "EMAIL") + (ignore-errors (car (process-lines "git" "config" "user.email"))) + user-mail-address))) + +(defmacro git-define-git-commit-self (action header) + "Create function git-commit-ACTION. +ACTION will be part of the function name. +HEADER is the actual header to be inserted into the comment." + (let ((func-name (intern (concat "git-commit-" action)))) + `(defun ,func-name () + ,(format "Insert a '%s' header at the end of the commit message. + +The author name and email address used for the header are +retrieved automatically with the same mechanism git uses." + header) + (interactive) + (git-commit-insert-header-as-self ,header)))) + +(git-define-git-commit-self "ack" "Acked-by") +(git-define-git-commit-self "review" "Reviewed-by") +(git-define-git-commit-self "signoff" "Signed-off-by") +(git-define-git-commit-self "test" "Tested-by") + +(defmacro git-define-git-commit (action header) + "Create interactive function git-commit-ACTION. +ACTION will be part of the function name. +HEADER is the actual header to be inserted into the comment." + (let ((func-name (intern (concat "git-commit-" action)))) + `(defun ,func-name (name email) + ,(format "Insert a '%s' header at the end of the commit message. +The value of the header is determined by NAME and EMAIL. + +When called interactively, both NAME and EMAIL are read from the +minibuffer." + header) + (interactive + (list (read-string "Name: ") + (read-string "Email: "))) + (git-commit-insert-header ,header name email)))) + +(git-define-git-commit "cc" "Cc") +(git-define-git-commit "reported" "Reported-by") +(git-define-git-commit "suggested" "Suggested-by") + +(defconst git-commit-comment-headings-alist + '(("Not currently on any branch." . git-commit-no-branch-face) + ("Changes to be committed:" . git-commit-comment-heading-face) + ("Untracked files:" . git-commit-comment-heading-face) + ("Changed but not updated:" . git-commit-comment-heading-face) + ("Changes not staged for commit:" . git-commit-comment-heading-face) + ("Unmerged paths:" . git-commit-comment-heading-face)) + "Headings in message comments. + +The `car' of each cell is the heading text, the `cdr' the face to +use for fontification.") + +(defun git-commit-summary-regexp () + (concat + ;; Skip empty lines or comments before the summary + "\\`\\(?:^\\(?:\\s-*\\|\\s<.*\\)\n\\)*" + ;; The summary line + (format "\\(.\\{0,%d\\}\\)\\(.*\\)" git-commit-summary-max-length) + ;; Non-empty non-comment second line + ;; + ;; For instant highlighting of non-empty second lines in font-lock, + ;; the last capturing group must capture the empty string ("") in + ;; "summary line\n". + ;; That's why the simpler regex "\\(?:\n\\([^\n#].*\\)\\)?", + ;; which captures 'nil', can't be used. + "\\(?:\n\\#\\|\n\\(.*\\)\\)?")) + +(defun git-commit-has-style-errors-p () + "Check whether the current buffer has style errors. + +Return t, if the current buffer has style errors, or nil +otherwise." + (save-excursion + (goto-char (point-min)) + (when (re-search-forward (git-commit-summary-regexp) nil t) + (or (string-match-p ".+" (or (match-string 2) "")) + (string-match-p "^.+$" (or (match-string 3) "")))))) + +;;; Font-Lock + +(defun git-commit-mode-summary-font-lock-keywords (&optional errors) + "Create font lock keywords to fontify the Git summary. + +If ERRORS is non-nil create keywords that highlight errors in the +summary line, not the summary line itself." + (if errors + `(,(git-commit-summary-regexp) + (2 'git-commit-overlong-summary-face t t) + (3 'git-commit-nonempty-second-line-face t t)) + `(,(git-commit-summary-regexp) + (1 'git-commit-summary-face t)))) + +(defun git-commit-mode-heading-keywords () + "Create font lock keywords to fontify comment headings. + +Known comment headings are provided by `git-commit-comment-headings'." + (mapcar (lambda (cell) `(,(format "^\\s<\\s-+\\(%s\\)$" + (regexp-quote (car cell))) + (1 ',(cdr cell) t))) + git-commit-comment-headings-alist)) + +(defun git-commit-mode-font-lock-keywords () + (append + `(("^\\s<.*$" . 'font-lock-comment-face) + ("^\\s<\\s-On branch \\(.*\\)$" (1 'git-commit-branch-face t)) + ("^\\s<\t\\(?:\\([^:\n]+\\):\\s-+\\)?\\(.*\\)$" + (1 'git-commit-comment-action-face t t) + (2 'git-commit-comment-file-face t)) + (,(concat "^\\(" + (regexp-opt git-commit-known-pseudo-headers) + ":\\)\\(\s.*\\)$") + (1 'git-commit-known-pseudo-header-face) + (2 'git-commit-pseudo-header-face)) + ("^\\<\\S-+:\\s-.*$" . 'git-commit-pseudo-header-face) + (eval . (git-commit-mode-summary-font-lock-keywords)) + ("\\[[^\n]+?\\]" (0 'git-commit-note-face t)) ; Notes override summary line + ;; Warnings from overlong lines and nonempty second line override + ;; everything + (eval . (git-commit-mode-summary-font-lock-keywords t))) + (git-commit-mode-heading-keywords))) + +(defun git-commit-font-lock-diff () + "Add font lock on diff." + (save-excursion + (goto-char (point-min)) + (when (re-search-forward "^diff --git" nil t) + (let ((beg (match-beginning 0))) + (let* ((buffer (current-buffer)) + (font-lock-verbose nil) + (font-lock-support-mode nil) + (text (with-temp-buffer + (insert + (with-current-buffer buffer + (buffer-substring-no-properties beg (point-max)))) + (diff-mode) + (font-lock-fontify-buffer) + (let ((pos (point-min)) + next) + (while (setq next (next-single-property-change pos 'face)) + (put-text-property pos next 'font-lock-face + (get-text-property pos 'face)) + (setq pos next))) + (buffer-string)))) + (delete-region beg (point-max)) + (insert text)))))) + +;;; Mode + +(defvar git-commit-mode-syntax-table + (let ((table (make-syntax-table text-mode-syntax-table))) + (modify-syntax-entry ?# "<" table) + (modify-syntax-entry ?\n ">" table) + (modify-syntax-entry ?\r ">" table) + table) + "Syntax table used by `git-commit-mode'.") + +;;;###autoload +(define-derived-mode git-commit-mode text-mode "Git Commit" + "Major mode for editing git commit messages. + +This mode helps with editing git commit messages both by +providing commands to do common tasks, and by highlighting the +basic structure of and errors in git commit messages." + ;; Font locking + (setq font-lock-defaults (list (git-commit-mode-font-lock-keywords) t)) + (set (make-local-variable 'font-lock-multiline) t) + (git-commit-font-lock-diff) + ;; Filling according to the guidelines + (setq fill-column git-commit-fill-column) + ;; Recognize changelog-style paragraphs + (set (make-local-variable 'paragraph-start) + (concat paragraph-start "\\|*\\|(")) + ;; Treat lines starting with a hash/pound as comments + (set (make-local-variable 'comment-start) "#") + (set (make-local-variable 'comment-start-skip) + (concat "^" (regexp-quote comment-start) "+" + "\\s-*")) + (set (make-local-variable 'comment-use-syntax) nil) + ;; Do not remember point location in commit messages + (when (boundp 'save-place) + (setq save-place nil)) + ;; If the commit summary is empty, insert a newline after point + (when (string= "" (buffer-substring-no-properties + (line-beginning-position) + (line-end-position))) + (open-line 1)) + ;; That's what happens when every little detail is commented + (make-local-variable 'log-edit-comment-ring-index) + ;; Make sure `git-commit-abort' cannot be by-passed + (add-hook 'kill-buffer-query-functions + 'git-commit-kill-buffer-noop nil t) + ;; Make the wrong usage info from `server-execute' go way + (run-with-timer 0.01 nil (lambda (m) (message "%s" m)) + (substitute-command-keys + (concat "Type \\[git-commit-commit] " + (let ((n (buffer-file-name))) + (cond ((equal n "TAG_EDITMSG") "to tag") + ((or (equal n "NOTES_EDITMSG") + (equal n "PULLREQ_EDITMSG")) + "when done") + (t "to commit"))) + " (\\[git-commit-abort] to abort).")))) + +(defun git-commit-kill-buffer-noop () + (message + (substitute-command-keys + "Don't kill this buffer. Instead abort using \\[git-commit-abort].")) + nil) + +(defun git-commit-mode-flyspell-verify () + (not (nth 4 (syntax-ppss)))) ; not inside a comment + +(eval-after-load 'flyspell + '(put 'git-commit-mode 'flyspell-mode-predicate + 'git-commit-mode-flyspell-verify)) + +;;;###autoload +(add-to-list 'auto-mode-alist '("/MERGE_MSG\\'" . git-commit-mode)) +;;;###autoload +(add-to-list 'auto-mode-alist + '("/\\(?:COMMIT\\|NOTES\\|TAG\\|PULLREQ\\)_EDITMSG\\'" + . git-commit-mode)) + +(defun git-commit-auto-mode-enable () + (message "git-commit-auto-mode-enable is obsolete and doesn't do anything")) +(make-obsolete 'git-commit-auto-mode-enable "This mode is a noop now" "") + +(provide 'git-commit-mode) +;; Local Variables: +;; indent-tabs-mode: nil +;; End: +;;; git-commit-mode.el ends here diff --git a/elpa/git-rebase-mode-1.0.0/git-rebase-mode-autoloads.el b/elpa/git-rebase-mode-1.0.0/git-rebase-mode-autoloads.el new file mode 100644 index 0000000..cd6b8f3 --- /dev/null +++ b/elpa/git-rebase-mode-1.0.0/git-rebase-mode-autoloads.el @@ -0,0 +1,29 @@ +;;; git-rebase-mode-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (or (file-name-directory #$) (car load-path))) + +;;;### (autoloads nil "git-rebase-mode" "git-rebase-mode.el" (21831 +;;;;;; 16621 351189 81000)) +;;; Generated autoloads from git-rebase-mode.el + +(autoload 'git-rebase-mode "git-rebase-mode" "\ +Major mode for editing of a Git rebase file. + +Rebase files are generated when you run 'git rebase -i' or run +`magit-interactive-rebase'. They describe how Git should perform +the rebase. See the documentation for git-rebase (e.g., by +running 'man git-rebase' at the command line) for details. + +\(fn)" t nil) + +(add-to-list 'auto-mode-alist '("/git-rebase-todo\\'" . git-rebase-mode)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; git-rebase-mode-autoloads.el ends here diff --git a/elpa/git-rebase-mode-1.0.0/git-rebase-mode-pkg.el b/elpa/git-rebase-mode-1.0.0/git-rebase-mode-pkg.el new file mode 100644 index 0000000..52e517a --- /dev/null +++ b/elpa/git-rebase-mode-1.0.0/git-rebase-mode-pkg.el @@ -0,0 +1 @@ +(define-package "git-rebase-mode" "1.0.0" "Major mode for editing git rebase files" 'nil) diff --git a/elpa/git-rebase-mode-1.0.0/git-rebase-mode.el b/elpa/git-rebase-mode-1.0.0/git-rebase-mode.el new file mode 100644 index 0000000..75ca2a4 --- /dev/null +++ b/elpa/git-rebase-mode-1.0.0/git-rebase-mode.el @@ -0,0 +1,393 @@ +;;; git-rebase-mode.el --- Major mode for editing git rebase files + +;; Copyright (C) 2010-2015 The Magit Project Developers + +;; Author: Phil Jackson +;; Maintainer: Jonas Bernoulli +;; Homepage: https://github.com/magit/git-modes +;; Keywords: convenience vc git +;; Package-Version: 1.0.0 + +;; This file is not part of GNU Emacs. + +;; This file 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. + +;; This file 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 this file. If not, see . + +;;; Commentary: + +;; Allows the editing of a git rebase file (which you might get when +;; using 'git rebase -i' or hitting 'E' in Magit). Assumes editing is +;; happening in a server. + +;;; Code: + +(require 'easymenu) +(require 'server) +(require 'thingatpt) + +;;; Options +;;;; Variables + +(defgroup git-rebase nil + "Edit Git rebase sequences." + :group 'tools) + +(defcustom git-rebase-auto-advance nil + "If non-nil, moves point forward a line after running an action." + :group 'git-rebase + :type 'boolean) + +(defcustom git-rebase-remove-instructions nil + "Whether to remove the instructions from the rebase buffer. +Because you have seen them before and can still remember." + :group 'git-rebase + :type 'boolean) + +;;;; Faces + +(defgroup git-rebase-faces nil + "Faces used by Git-Rebase mode." + :group 'faces + :group 'git-rebase) + +(defface git-rebase-hash + '((((class color) (background light)) + :foreground "firebrick") + (((class color) (background dark)) + :foreground "tomato")) + "Face for commit hashes." + :group 'git-rebase-faces) + +(defface git-rebase-description nil + "Face for commit descriptions." + :group 'git-rebase-faces) + +(defface git-rebase-killed-action + '((((class color)) + :inherit font-lock-comment-face + :strike-through t)) + "Face for commented action and exec lines." + :group 'git-rebase-faces) + +(define-obsolete-face-alias 'git-rebase-description-face + 'git-rebase-description "1.0.0") +(define-obsolete-face-alias 'git-rebase-killed-action-face + 'git-rebase-killed-action "1.0.0") + +;;; Regexps + +(defconst git-rebase-action-line-re + (concat "^#?" + "\\([efprs]\\|pick\\|reword\\|edit\\|squash\\|fixup\\) " + "\\([a-z0-9]\\{4,40\\}\\) " + "\\(.*\\)") + "Regexp matching action lines in rebase buffers.") + +(defconst git-rebase-exec-line-re + "^#?\\(x\\|exec\\)[[:space:]]\\(.*\\)" + "Regexp matching exec lines in rebase buffer.") + +(defconst git-rebase-dead-line-re + (format "^#\\(?:%s\\|%s\\)" + (substring git-rebase-action-line-re 1) + (substring git-rebase-exec-line-re 1)) + "Regexp matching commented action and exex lines in rebase buffers.") + +;;; Keymaps + +(defvar git-rebase-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map special-mode-map) + (define-key map (kbd "q") 'git-rebase-server-edit) + (define-key map (kbd "C-c C-c") 'git-rebase-server-edit) + (define-key map (kbd "a") 'git-rebase-abort) + (define-key map (kbd "C-c C-k") 'git-rebase-abort) + (define-key map [remap undo] 'git-rebase-undo) + (define-key map (kbd "RET") 'git-rebase-show-commit) + (define-key map (kbd "x") 'git-rebase-exec) + (define-key map (kbd "c") 'git-rebase-pick) + (define-key map (kbd "r") 'git-rebase-reword) + (define-key map (kbd "e") 'git-rebase-edit) + (define-key map (kbd "s") 'git-rebase-squash) + (define-key map (kbd "f") 'git-rebase-fixup) + (define-key map (kbd "y") 'git-rebase-insert) + (define-key map (kbd "k") 'git-rebase-kill-line) + (define-key map (kbd "C-k") 'git-rebase-kill-line) + (define-key map (kbd "p") 'git-rebase-backward-line) + (define-key map (kbd "n") 'forward-line) + (define-key map (kbd "M-p") 'git-rebase-move-line-up) + (define-key map (kbd "M-n") 'git-rebase-move-line-down) + (define-key map (kbd "M-") 'git-rebase-move-line-up) + (define-key map (kbd "M-") 'git-rebase-move-line-down) + map) + "Keymap for Git-Rebase mode.") + +(easy-menu-define git-rebase-mode-menu git-rebase-mode-map + "Git-Rebase mode menu" + '("Rebase" + ["Pick" git-rebase-pick t] + ["Reword" git-rebase-reword t] + ["Edit" git-rebase-edit t] + ["Squash" git-rebase-squash t] + ["Fixup" git-rebase-fixup t] + ["Kill" git-rebase-kill-line t] + ["Move Down" git-rebase-move-line-down t] + ["Move Up" git-rebase-move-line-up t] + ["Execute" git-rebase-exec t] + "---" + ["Abort" git-rebase-abort t] + ["Done" git-rebase-server-edit t])) + +;;; Utilities + +(defun git-rebase-edit-line (change-to) + (when (git-rebase-looking-at-action) + (let ((buffer-read-only nil) + (start (point))) + (goto-char (point-at-bol)) + (delete-region (point) (progn (forward-word 1) (point))) + (insert change-to) + (goto-char start) + (when git-rebase-auto-advance + (forward-line))))) + +(defmacro git-rebase-define-action (sym) + (declare (indent defun)) + (let ((fn (intern (format "git-rebase-%s" sym)))) + `(progn + (defun ,fn () + (interactive) + (git-rebase-edit-line ,(symbol-name sym))) + (put ',fn 'definition-name ',sym)))) + +(defun git-rebase-looking-at-action () + "Return non-nil if looking at an action line." + (save-excursion + (goto-char (point-at-bol)) + (looking-at git-rebase-action-line-re))) + +(defun git-rebase-looking-at-action-or-exec () + "Return non-nil if looking at an action line or exec line." + (save-excursion + (goto-char (point-at-bol)) + (or (looking-at git-rebase-action-line-re) + (looking-at git-rebase-exec-line-re)))) + +(defun git-rebase-looking-at-exec () + "Return non-nil if cursor is on an exec line." + (string-match git-rebase-exec-line-re (thing-at-point 'line))) + +(defun git-rebase-looking-at-killed-exec () + "Return non-nil if looking at an exec line that has been commented out." + (let ((line (thing-at-point 'line))) + (and (eq (aref line 0) ?#) + (string-match git-rebase-exec-line-re line)))) + +;;; Commands + +(git-rebase-define-action pick) +(git-rebase-define-action reword) +(git-rebase-define-action edit) +(git-rebase-define-action squash) +(git-rebase-define-action fixup) + +(defun git-rebase-move-line-up () + "Move the current action line up." + (interactive) + (when (git-rebase-looking-at-action-or-exec) + (let ((buffer-read-only nil) + (col (current-column))) + (goto-char (point-at-bol)) + (unless (bobp) + (transpose-lines 1) + (forward-line -2)) + (move-to-column col)))) + +(defun git-rebase-move-line-down () + "Assuming the next line is also an action line, move the current line down." + (interactive) + ;; if we're on an action and the next line is also an action + (when (and (git-rebase-looking-at-action-or-exec) + (save-excursion + (forward-line) + (git-rebase-looking-at-action-or-exec))) + (let ((buffer-read-only nil) + (col (current-column))) + (forward-line 1) + (transpose-lines 1) + (forward-line -1) + (move-to-column col)))) + +(defun git-rebase-server-edit () + "Save the action buffer and end the session." + (interactive) + (save-buffer) + (server-edit)) + +(defun git-rebase-abort () + "Abort this rebase. +This is dune by emptying the buffer, saving and closing server +connection." + (interactive) + (when (or (not (buffer-modified-p)) + (y-or-n-p "Abort this rebase? ")) + (let ((buffer-read-only nil)) + (erase-buffer) + (save-buffer) + (server-edit)))) + +(defun git-rebase-kill-line () + "Kill the current action line." + (interactive) + (when (and (not (eq (char-after (point-at-bol)) ?#)) + (git-rebase-looking-at-action-or-exec)) + (beginning-of-line) + (let ((inhibit-read-only t)) + (insert "#")) + (forward-line))) + +(defun git-rebase-insert (rev) + "Read an arbitrary commit and insert it below current line." + (interactive + (list (if (fboundp 'magit-read-branch-or-commit) + (magit-read-branch-or-commit "Insert revision") + (read-string "Insert revision: ")))) + (forward-line) + (let ((summary (if (fboundp 'magit-rev-format) + (magit-rev-format "%h %s" rev) + (process-lines "git" "show" "-s" "--format=%h %s" rev)))) + (if summary + (let ((inhibit-read-only t)) + (insert "pick " summary ?\n)) + (user-error "Unknown revision")))) + +(defun git-rebase-exec (edit) + "Prompt the user for a shell command to be executed, and +add it to the todo list. + +If the cursor is on a commented-out exec line, uncomment the +current line instead of prompting. + +When the prefix argument EDIT is non-nil and the cursor is on an +exec line, edit that line instead of inserting a new one. If the +exec line was commented out, also uncomment it." + (interactive "P") + (cond + ((and edit (git-rebase-looking-at-exec)) + (let ((new-line (git-rebase-read-exec-line + (match-string-no-properties 2 (thing-at-point 'line)))) + (inhibit-read-only t)) + (delete-region (point-at-bol) (point-at-eol)) + (if (not (equal "" new-line)) + (insert "exec " new-line) + (delete-char -1) + (forward-line)) + (move-beginning-of-line nil))) + ((git-rebase-looking-at-killed-exec) + (save-excursion + (beginning-of-line) + (let ((buffer-read-only nil)) + (delete-char 1)))) + (t + (let ((inhibit-read-only t) + (line (git-rebase-read-exec-line))) + (unless (equal "" line) + (move-end-of-line nil) + (newline) + (insert (concat "exec " line)))) + (move-beginning-of-line nil)))) + +(defun git-rebase-read-exec-line (&optional initial-line) + (read-shell-command "Execute: " initial-line)) + +(defun git-rebase-undo (&optional arg) + "A thin wrapper around `undo', which allows undoing in read-only buffers." + (interactive "P") + (let ((inhibit-read-only t)) + (undo arg))) + +(defun git-rebase-show-commit (&optional arg) + "Show the commit on the current line if any." + (interactive "P") + (save-excursion + (goto-char (point-at-bol)) + (when (looking-at git-rebase-action-line-re) + (let ((commit (match-string 2))) + (if (fboundp 'magit-show-commit) + (magit-show-commit commit) + (shell-command (concat "git show " commit))))))) + +(defun git-rebase-backward-line (&optional n) + "Move N lines backward (forward if N is negative). +Like `forward-line' but go into the opposite direction." + (interactive "p") + (forward-line (* n -1))) + +;;; Mode + +;;;###autoload +(define-derived-mode git-rebase-mode special-mode "Git Rebase" + "Major mode for editing of a Git rebase file. + +Rebase files are generated when you run 'git rebase -i' or run +`magit-interactive-rebase'. They describe how Git should perform +the rebase. See the documentation for git-rebase (e.g., by +running 'man git-rebase' at the command line) for details." + (setq font-lock-defaults '(git-rebase-mode-font-lock-keywords t t)) + (when git-rebase-remove-instructions + (let ((inhibit-read-only t)) + (flush-lines "^\\($\\|#\\)")))) + +(defvar git-rebase-mode-font-lock-keywords + `((,git-rebase-action-line-re + (1 font-lock-keyword-face) + (2 'git-rebase-hash) + (3 'git-rebase-description)) + (,git-rebase-exec-line-re 1 font-lock-keyword-face) + ("^#.*" 0 font-lock-comment-face) + (,git-rebase-dead-line-re 0 'git-rebase-killed-action t)) + "Font lock keywords for Git-Rebase mode.") + +(defun git-rebase-mode-show-keybindings () + "Modify the \"Commands:\" section of the comment Git generates +at the bottom of the file so that in place of the one-letter +abbreviation for the command, it shows the command's keybinding. +By default, this is the same except for the \"pick\" command." + (save-excursion + (goto-char (point-min)) + (while (search-forward-regexp "^# \\(.\\), \\([[:alpha:]]+\\) = " nil t) + (let ((start (match-beginning 1)) + (end (match-end 1)) + (command (intern (concat "git-rebase-" (match-string 2))))) + (when (fboundp command) + (let ((overlay (make-overlay start end))) + (overlay-put + overlay 'display + (key-description (where-is-internal command nil t))))))))) + +(add-hook 'git-rebase-mode-hook 'git-rebase-mode-show-keybindings t) + +(defun git-rebase-mode-disable-before-save-hook () + (set (make-local-variable 'before-save-hook) nil)) + +(add-hook 'git-rebase-mode-hook 'git-rebase-mode-disable-before-save-hook) + +;;;###autoload +(add-to-list 'auto-mode-alist + '("/git-rebase-todo\\'" . git-rebase-mode)) + +(provide 'git-rebase-mode) +;; Local Variables: +;; indent-tabs-mode: nil +;; End: +;;; git-rebase-mode.el ends here diff --git a/elpa/gitignore-mode-0.1/gitignore-mode-pkg.el b/elpa/gitignore-mode-0.1/gitignore-mode-pkg.el deleted file mode 100644 index bd8fdc4..0000000 --- a/elpa/gitignore-mode-0.1/gitignore-mode-pkg.el +++ /dev/null @@ -1 +0,0 @@ -(define-package "gitignore-mode" "0.1" "Major mode for editing .gitconfig files" 'nil) diff --git a/elpa/gitignore-mode-0.1/gitignore-mode.el b/elpa/gitignore-mode-0.1/gitignore-mode.el deleted file mode 100644 index c4051be..0000000 --- a/elpa/gitignore-mode-0.1/gitignore-mode.el +++ /dev/null @@ -1,60 +0,0 @@ -;;; gitignore-mode.el --- Major mode for editing .gitconfig files -;;; -*- coding: utf-8; lexical-binding: t -*- - -;; Copyright (c) 2012 Sebastian Wiesner -;; -;; Author: Sebastian Wiesner -;; URL: https://github.com/lunaryorn/git-modes -;; Version: 0.1 -;; Keywords: convenience vc git - -;; This file is not part of GNU Emacs. - -;; This program 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 2 of the License, or (at your option) any later -;; version. - -;; This program 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 -;; this program; if not, write to the Free Software Foundation, Inc., 51 -;; Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -;;; Commentary: - -;; A major mode for editing .gitignore files. - -;;; Code: - -(require 'conf-mode) - -(defvar gitignore-mode-font-lock-keywords - '(("^\\s<.*$" . 'font-lock-comment-face) - ("^\\(!?\\)" (1 'font-lock-negation-char-face)) ; Negated patterns - ("/" . 'font-lock-constant-face) ; Directory separators - ("\\(?:\\*\\|\\?\\)" . 'font-lock-keyword-face) ; Glob patterns - ("\\[.+?\\]" . 'font-lock-keyword-face) ; Ranged glob patterns - )) - -;;;###autoload -(define-derived-mode gitignore-mode conf-unix-mode "Gitignore" - "A major mode for editing .gitconfig files." - (conf-mode-initialize "#") - ;; Disable syntactic font locking, because comments are only valid at - ;; beginning of line. - (setq font-lock-defaults '(gitignore-mode-font-lock-keywords t t)) - (set (make-local-variable 'conf-assignment-sign) nil)) - -;;;###autoload -(setq auto-mode-alist - (append '(("/\\.gitignore\\'" . gitignore-mode) - ("/\\.git/info/exclude\\'" . gitignore-mode)) - auto-mode-alist)) - -(provide 'gitignore-mode) - -;;; gitignore-mode.el ends here diff --git a/elpa/gitignore-mode-0.1/gitignore-mode-autoloads.el b/elpa/gitignore-mode-1.1.0/gitignore-mode-autoloads.el similarity index 59% rename from elpa/gitignore-mode-0.1/gitignore-mode-autoloads.el rename to elpa/gitignore-mode-1.1.0/gitignore-mode-autoloads.el index 3798024..82e25c6 100644 --- a/elpa/gitignore-mode-0.1/gitignore-mode-autoloads.el +++ b/elpa/gitignore-mode-1.1.0/gitignore-mode-autoloads.el @@ -3,16 +3,16 @@ ;;; Code: (add-to-list 'load-path (or (file-name-directory #$) (car load-path))) -;;;### (autoloads nil "gitignore-mode" "gitignore-mode.el" (21633 -;;;;;; 45694 775043 851000)) +;;;### (autoloads nil "gitignore-mode" "gitignore-mode.el" (21831 +;;;;;; 16635 816188 71000)) ;;; Generated autoloads from gitignore-mode.el (autoload 'gitignore-mode "gitignore-mode" "\ -A major mode for editing .gitconfig files. +A major mode for editing .gitignore files. \(fn)" t nil) -(setq auto-mode-alist (append '(("/\\.gitignore\\'" . gitignore-mode) ("/\\.git/info/exclude\\'" . gitignore-mode)) auto-mode-alist)) +(dolist (pattern (list "/\\.gitignore\\'" "/\\.git/info/exclude\\'" "/git/ignore\\'")) (add-to-list 'auto-mode-alist (cons pattern 'gitignore-mode))) ;;;*** diff --git a/elpa/gitignore-mode-1.1.0/gitignore-mode-pkg.el b/elpa/gitignore-mode-1.1.0/gitignore-mode-pkg.el new file mode 100644 index 0000000..ae6eaa4 --- /dev/null +++ b/elpa/gitignore-mode-1.1.0/gitignore-mode-pkg.el @@ -0,0 +1 @@ +(define-package "gitignore-mode" "1.1.0" "Major mode for editing .gitignore files" 'nil) diff --git a/elpa/gitignore-mode-1.1.0/gitignore-mode.el b/elpa/gitignore-mode-1.1.0/gitignore-mode.el new file mode 100644 index 0000000..57d8eed --- /dev/null +++ b/elpa/gitignore-mode-1.1.0/gitignore-mode.el @@ -0,0 +1,61 @@ +;;; gitignore-mode.el --- Major mode for editing .gitignore files -*- lexical-binding: t; -*- + +;; Copyright (c) 2012-2013 Sebastian Wiesner +;; Copyright (C) 2012-2015 The Magit Project Developers + +;; Author: Sebastian Wiesner +;; Maintainer: Jonas Bernoulli +;; Homepage: https://github.com/magit/git-modes +;; Keywords: convenience vc git +;; Package-Version: 1.1.0 + +;; This file is not part of GNU Emacs. + +;; This file 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. + +;; This file 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 this file. If not, see . + +;;; Commentary: + +;; A major mode for editing .gitignore files. + +;;; Code: + +(require 'conf-mode) + +(defvar gitignore-mode-font-lock-keywords + '(("^\\s<.*$" . font-lock-comment-face) + ("^!" . font-lock-negation-char-face) ; Negative pattern + ("/" . font-lock-constant-face) ; Directory separators + ("[*?]" . font-lock-keyword-face) ; Glob patterns + ("\\[.+?\\]" . font-lock-keyword-face))) ; Ranged glob patterns + +;;;###autoload +(define-derived-mode gitignore-mode conf-unix-mode "Gitignore" + "A major mode for editing .gitignore files." + (conf-mode-initialize "#") + ;; Disable syntactic font locking, because comments are only valid at + ;; beginning of line. + (setq font-lock-defaults '(gitignore-mode-font-lock-keywords t t)) + (set (make-local-variable 'conf-assignment-sign) nil)) + +;;;###autoload +(dolist (pattern (list "/\\.gitignore\\'" + "/\\.git/info/exclude\\'" + "/git/ignore\\'")) + (add-to-list 'auto-mode-alist (cons pattern 'gitignore-mode))) + +(provide 'gitignore-mode) +;; Local Variables: +;; indent-tabs-mode: nil +;; End: +;;; gitignore-mode.el ends here diff --git a/elpa/haml-mode-3.1.5/haml-mode-pkg.el b/elpa/haml-mode-3.1.5/haml-mode-pkg.el deleted file mode 100644 index 49f6f5e..0000000 --- a/elpa/haml-mode-3.1.5/haml-mode-pkg.el +++ /dev/null @@ -1 +0,0 @@ -(define-package "haml-mode" "3.1.5" "Major mode for editing Haml files" (quote ((ruby-mode "1.0")))) diff --git a/elpa/haml-mode-3.1.5/haml-mode-autoloads.el b/elpa/haml-mode-3.1.8/haml-mode-autoloads.el similarity index 64% rename from elpa/haml-mode-3.1.5/haml-mode-autoloads.el rename to elpa/haml-mode-3.1.8/haml-mode-autoloads.el index dba32b9..c015733 100644 --- a/elpa/haml-mode-3.1.5/haml-mode-autoloads.el +++ b/elpa/haml-mode-3.1.8/haml-mode-autoloads.el @@ -1,10 +1,10 @@ ;;; haml-mode-autoloads.el --- automatically extracted autoloads ;; ;;; Code: - +(add-to-list 'load-path (or (file-name-directory #$) (car load-path))) -;;;### (autoloads (haml-mode) "haml-mode" "haml-mode.el" (21553 16292 -;;;;;; 429141 493000)) +;;;### (autoloads nil "haml-mode" "haml-mode.el" (21831 16635 83188 +;;;;;; 122000)) ;;; Generated autoloads from haml-mode.el (autoload 'haml-mode "haml-mode" "\ @@ -18,16 +18,9 @@ Major mode for editing Haml files. ;;;*** -;;;### (autoloads nil nil ("haml-mode-pkg.el") (21553 16292 546790 -;;;;;; 825000)) - -;;;*** - -(provide 'haml-mode-autoloads) ;; Local Variables: ;; version-control: never ;; no-byte-compile: t ;; no-update-autoloads: t -;; coding: utf-8 ;; End: ;;; haml-mode-autoloads.el ends here diff --git a/elpa/haml-mode-3.1.8/haml-mode-pkg.el b/elpa/haml-mode-3.1.8/haml-mode-pkg.el new file mode 100644 index 0000000..3ce6fa1 --- /dev/null +++ b/elpa/haml-mode-3.1.8/haml-mode-pkg.el @@ -0,0 +1 @@ +(define-package "haml-mode" "3.1.8" "Major mode for editing Haml files" '((ruby-mode "1.0"))) diff --git a/elpa/haml-mode-3.1.5/haml-mode.el b/elpa/haml-mode-3.1.8/haml-mode.el similarity index 99% rename from elpa/haml-mode-3.1.5/haml-mode.el rename to elpa/haml-mode-3.1.8/haml-mode.el index 348d8b8..ad7ed82 100644 --- a/elpa/haml-mode-3.1.5/haml-mode.el +++ b/elpa/haml-mode-3.1.8/haml-mode.el @@ -1,4 +1,3 @@ - ;;; haml-mode.el --- Major mode for editing Haml files ;; Copyright (c) 2007, 2008 Nathan Weizenbaum @@ -6,7 +5,7 @@ ;; Author: Nathan Weizenbaum ;; URL: http://github.com/nex3/haml/tree/master ;; Package-Requires: ((ruby-mode "1.0")) -;; Version: 3.1.5 +;; Version: 3.1.8 ;; Created: 2007-03-08 ;; By: Nathan Weizenbaum ;; Keywords: markup, language, html @@ -238,7 +237,7 @@ END.") "Regexp to match trailing ruby code which may continue onto subsequent lines.") (defconst haml-ruby-script-re - (concat "^[ \t]*\\(-\\|[&!]?[=~]\\) " haml-possibly-multiline-code-re) + (concat "^[ \t]*\\(-\\|[&!]?\\(?:=\\|~\\)\\)[^=]" haml-possibly-multiline-code-re) "Regexp to match -, = or ~ blocks and any continued code lines.") (defun haml-highlight-ruby-script (limit) diff --git a/elpa/magit-1.2.1/magit-autoloads.el b/elpa/magit-1.2.1/magit-autoloads.el deleted file mode 100644 index e07ffc1..0000000 --- a/elpa/magit-1.2.1/magit-autoloads.el +++ /dev/null @@ -1,164 +0,0 @@ -;;; magit-autoloads.el --- automatically extracted autoloads -;; -;;; Code: - - -;;;### (autoloads (magit-status) "magit" "magit.el" (21539 9850 352318 -;;;;;; 953000)) -;;; Generated autoloads from magit.el - -(autoload 'magit-status "magit" "\ -Open a Magit status buffer for the Git repository containing -DIR. If DIR is not within a Git repository, offer to create a -Git repository in DIR. - -Interactively, a prefix argument means to ask the user which Git -repository to use even if `default-directory' is under Git control. -Two prefix arguments means to ignore `magit-repo-dirs' when asking for -user input. - -\(fn DIR)" t nil) - -;;;*** - -;;;### (autoloads (magit-blame-mode) "magit-blame" "magit-blame.el" -;;;;;; (21539 9850 701311 580000)) -;;; Generated autoloads from magit-blame.el - -(autoload 'magit-blame-mode "magit-blame" "\ -Display blame information inline. - -\(fn &optional ARG)" t nil) - -;;;*** - -;;;### (autoloads (turn-on-magit-stgit magit-stgit-mode) "magit-stgit" -;;;;;; "magit-stgit.el" (21539 9850 618313 333000)) -;;; Generated autoloads from magit-stgit.el - -(autoload 'magit-stgit-mode "magit-stgit" "\ -StGit support for Magit - -\(fn &optional ARG)" t nil) - -(autoload 'turn-on-magit-stgit "magit-stgit" "\ -Unconditionally turn on `magit-stgit-mode'. - -\(fn)" nil nil) - -;;;*** - -;;;### (autoloads (turn-on-magit-svn magit-svn-mode) "magit-svn" -;;;;;; "magit-svn.el" (21539 9850 435317 198000)) -;;; Generated autoloads from magit-svn.el - -(autoload 'magit-svn-mode "magit-svn" "\ -SVN support for Magit - -\(fn &optional ARG)" t nil) - -(autoload 'turn-on-magit-svn "magit-svn" "\ -Unconditionally turn on `magit-svn-mode'. - -\(fn)" nil nil) - -;;;*** - -;;;### (autoloads (turn-on-magit-topgit magit-topgit-mode) "magit-topgit" -;;;;;; "magit-topgit.el" (21539 9850 166322 880000)) -;;; Generated autoloads from magit-topgit.el - -(autoload 'magit-topgit-mode "magit-topgit" "\ -Topgit support for Magit - -\(fn &optional ARG)" t nil) - -(autoload 'turn-on-magit-topgit "magit-topgit" "\ -Unconditionally turn on `magit-topgit-mode'. - -\(fn)" nil nil) - -;;;*** - -;;;### (autoloads (global-magit-wip-save-mode magit-wip-save-mode -;;;;;; magit-wip-mode) "magit-wip" "magit-wip.el" (21539 9850 532315 -;;;;;; 150000)) -;;; Generated autoloads from magit-wip.el - -(defvar magit-wip-mode nil "\ -Non-nil if Magit-Wip mode is enabled. -See the command `magit-wip-mode' for a description of this minor mode. -Setting this variable directly does not take effect; -either customize it (see the info node `Easy Customization') -or call the function `magit-wip-mode'.") - -(custom-autoload 'magit-wip-mode "magit-wip" nil) - -(autoload 'magit-wip-mode "magit-wip" "\ -In Magit log buffers; give wip refs a special appearance. - -\(fn &optional ARG)" t nil) - -(autoload 'magit-wip-save-mode "magit-wip" "\ -Magit support for committing to a work-in-progress ref. - -When this minor mode is turned on and a file is saved inside a writable -git repository then it is also committed to a special work-in-progress -ref. - -\(fn &optional ARG)" t nil) - -(defvar global-magit-wip-save-mode nil "\ -Non-nil if Global-Magit-Wip-Save mode is enabled. -See the command `global-magit-wip-save-mode' for a description of this minor mode. -Setting this variable directly does not take effect; -either customize it (see the info node `Easy Customization') -or call the function `global-magit-wip-save-mode'.") - -(custom-autoload 'global-magit-wip-save-mode "magit-wip" nil) - -(autoload 'global-magit-wip-save-mode "magit-wip" "\ -Toggle Magit-Wip-Save mode in all buffers. -With prefix ARG, enable Global-Magit-Wip-Save mode if ARG is positive; -otherwise, disable it. If called from Lisp, enable the mode if -ARG is omitted or nil. - -Magit-Wip-Save mode is enabled in all buffers where -`turn-on-magit-wip-save' would do it. -See `magit-wip-save-mode' for more information on Magit-Wip-Save mode. - -\(fn &optional ARG)" t nil) - -;;;*** - -;;;### (autoloads (rebase-mode) "rebase-mode" "rebase-mode.el" (21539 -;;;;;; 9850 228321 571000)) -;;; Generated autoloads from rebase-mode.el - -(autoload 'rebase-mode "rebase-mode" "\ -Major mode for editing of a Git rebase file. - -Rebase files are generated when you run 'git rebase -i' or run -`magit-interactive-rebase'. They describe how Git should perform -the rebase. See the documentation for git-rebase (e.g., by -running 'man git-rebase' at the command line) for details. - -\(fn)" t nil) - -(add-to-list 'auto-mode-alist '("git-rebase-todo" . rebase-mode)) - -;;;*** - -;;;### (autoloads nil nil ("magit-bisect.el" "magit-key-mode.el" -;;;;;; "magit-pkg.el") (21539 9850 772800 71000)) - -;;;*** - -(provide 'magit-autoloads) -;; Local Variables: -;; version-control: never -;; no-byte-compile: t -;; no-update-autoloads: t -;; coding: utf-8 -;; End: -;;; magit-autoloads.el ends here diff --git a/elpa/magit-1.2.1/magit-bisect.el b/elpa/magit-1.2.1/magit-bisect.el deleted file mode 100644 index cdb6455..0000000 --- a/elpa/magit-1.2.1/magit-bisect.el +++ /dev/null @@ -1,195 +0,0 @@ -(require 'magit) - -(defvar magit--bisect-last-pos) -(defvar magit--bisect-tmp-file) -(defvar magit--bisect-info nil) -(make-variable-buffer-local 'magit--bisect-info) -(put 'magit--bisect-info 'permanent-local t) - -(defun magit--bisecting-p (&optional required-status) - "Return t if a bisect session is running. -If REQUIRED-STATUS is not nil then the current status must also -match REQUIRED-STATUS." - (and (file-exists-p (concat (magit-git-dir) "BISECT_LOG")) - (or (not required-status) - (eq (plist-get (magit--bisect-info) :status) - required-status)))) - -(defun magit--bisect-info () - (with-current-buffer (magit-find-status-buffer) - (or (if (local-variable-p 'magit--bisect-info) magit--bisect-info) - (list :status (if (magit--bisecting-p) 'running 'not-running))))) - -(defun magit--bisect-cmd (&rest args) - "Run `git bisect ...' and update the status buffer" - (with-current-buffer (magit-find-status-buffer) - (let* ((output (apply 'magit-git-lines (append '("bisect") args))) - (cmd (car args)) - (first-line (car output))) - (save-match-data - (setq magit--bisect-info - (cond ((string= cmd "reset") - (list :status 'not-running)) - ;; Bisecting: 78 revisions left to test after this (roughly 6 steps) - ((string-match "^Bisecting:\\s-+\\([0-9]+\\).+roughly\\s-+\\([0-9]+\\)" first-line) - (list :status 'running - :revs (match-string 1 first-line) - :steps (match-string 2 first-line))) - ;; e2596955d9253a80aec9071c18079705597fa102 is the first bad commit - ((string-match "^\\([a-f0-9]+\\)\\s-.*first bad commit" first-line) - (list :status 'finished - :bad (match-string 1 first-line))) - (t - (list :status 'error))))))) - (magit-refresh)) - -(defun magit--bisect-info-for-status (branch) - "Return bisect info suitable for display in the status buffer" - (let* ((info (magit--bisect-info)) - (status (plist-get info :status))) - (cond ((eq status 'not-running) - (or branch "(detached)")) - ((eq status 'running) - (format "(bisecting; %s revisions & %s steps left)" - (or (plist-get info :revs) "unknown number of") - (or (plist-get info :steps) "unknown number of"))) - ((eq status 'finished) - (format "(bisected: first bad revision is %s)" (plist-get info :bad))) - (t - "(bisecting; unknown error occured)")))) - -(defun magit-bisect-start () - "Start a bisect session" - (interactive) - (if (magit--bisecting-p) - (error "Already bisecting")) - (let ((bad (magit-read-rev "Start bisect with known bad revision" "HEAD")) - (good (magit-read-rev "Good revision" (magit-default-rev)))) - (magit--bisect-cmd "start" bad good))) - -(defun magit-bisect-reset () - "Quit a bisect session" - (interactive) - (unless (magit--bisecting-p) - (error "Not bisecting")) - (magit--bisect-cmd "reset")) - -(defun magit-bisect-good () - "Tell git that the current revision is good during a bisect session" - (interactive) - (unless (magit--bisecting-p 'running) - (error "Not bisecting")) - (magit--bisect-cmd "good")) - -(defun magit-bisect-bad () - "Tell git that the current revision is bad during a bisect session" - (interactive) - (unless (magit--bisecting-p 'running) - (error "Not bisecting")) - (magit--bisect-cmd "bad")) - -(defun magit-bisect-skip () - "Tell git to skip the current revision during a bisect session." - (interactive) - (unless (magit--bisecting-p 'running) - (error "Not bisecting")) - (magit--bisect-cmd "skip")) - -(defun magit-bisect-log () - "Show the bisect log" - (interactive) - (unless (magit--bisecting-p) - (error "Not bisecting")) - (magit-run-git "bisect" "log") - (magit-display-process)) - -(defun magit-bisect-visualize () - "Show the remaining suspects with gitk" - (interactive) - (unless (magit--bisecting-p) - (error "Not bisecting")) - (magit-run-git "bisect" "visualize") - (unless (getenv "DISPLAY") - (magit-display-process))) - -(easy-mmode-defmap magit-bisect-minibuffer-local-map - '(("\C-i" . comint-dynamic-complete-filename)) - "Keymap for minibuffer prompting of rebase command." - :inherit minibuffer-local-map) - -(defvar magit-bisect-mode-history nil - "Previously run bisect commands.") - -(defun magit-bisect-run (command) - "Bisect automatically by running commands after each step" - (interactive - (list - (read-from-minibuffer "Run command (like this): " - "" - magit-bisect-minibuffer-local-map - nil - 'magit-bisect-mode-history))) - (unless (magit--bisecting-p) - (error "Not bisecting")) - (let ((file (make-temp-file "magit-bisect-run")) - buffer) - (with-temp-buffer - (insert "#!/bin/sh\n" command "\n") - (write-region (point-min) (point-max) file)) - (set-file-modes file #o755) - (magit-run-git-async "bisect" "run" file) - (magit-display-process) - (setq buffer (get-buffer magit-process-buffer-name)) - (with-current-buffer buffer - (set (make-local-variable 'magit--bisect-last-pos) 0) - (set (make-local-variable 'magit--bisect-tmp-file) file)) - (set-process-filter (get-buffer-process buffer) 'magit--bisect-run-filter) - (set-process-sentinel (get-buffer-process buffer) 'magit--bisect-run-sentinel))) - -(defun magit--bisect-run-filter (process output) - (with-current-buffer (process-buffer process) - (save-match-data - (let ((inhibit-read-only t) - line new-info) - (insert output) - (goto-char magit--bisect-last-pos) - (beginning-of-line) - (while (< (point) (point-max)) - (cond ( ;; Bisecting: 78 revisions left to test after this (roughly 6 steps) - (looking-at "^Bisecting:\\s-+\\([0-9]+\\).+roughly\\s-+\\([0-9]+\\)") - (setq new-info (list :status 'running - :revs (match-string 1) - :steps (match-string 2)))) - ( ;; e2596955d9253a80aec9071c18079705597fa102 is the first bad commit - (looking-at "^\\([a-f0-9]+\\)\\s-.*first bad commit") - (setq new-info (list :status 'finished - :bad (match-string 1))))) - (forward-line 1)) - (goto-char (point-max)) - (setq magit--bisect-last-pos (point)) - (if new-info - (with-current-buffer (magit-find-status-buffer) - (setq magit--bisect-info new-info) - (magit--bisect-update-status-buffer))))))) - -(defun magit--bisect-run-sentinel (process event) - (if (string-match-p "^finish" event) - (with-current-buffer (process-buffer process) - (delete-file magit--bisect-tmp-file))) - (magit-process-sentinel process event)) - -(defun magit--bisect-update-status-buffer () - (with-current-buffer (magit-find-status-buffer) - (save-excursion - (save-match-data - (let ((inhibit-read-only t)) - (goto-char (point-min)) - (when (search-forward-regexp "Local:" nil t) - (beginning-of-line) - (kill-line) - (insert (format "Local: %s %s" - (propertize (magit--bisect-info-for-status (magit-get-current-branch)) - 'face 'magit-branch) - (abbreviate-file-name default-directory))))))))) - -(provide 'magit-bisect) diff --git a/elpa/magit-1.2.1/magit-key-mode.el b/elpa/magit-1.2.1/magit-key-mode.el deleted file mode 100644 index 2fcf296..0000000 --- a/elpa/magit-1.2.1/magit-key-mode.el +++ /dev/null @@ -1,521 +0,0 @@ -(require 'magit) - -(eval-when-compile (require 'cl)) - -(defvar magit-key-mode-key-maps '() - "This will be filled lazily with proper `define-key' built - keymaps as they're requested.") - -(defvar magit-key-mode-buf-name "*magit-key*" - "Name of the buffer.") - -(defvar magit-key-mode-current-args '() - "Will contain the arguments to be passed to git.") - -(defvar magit-key-mode-current-options '() - "Will contain the arguments to be passed to git.") - -(defvar magit-log-mode-window-conf nil - "Will hold the pre-menu configuration of magit.") - -(defvar magit-key-mode-groups - '((logging - (man-page "git-log") - (actions - ("l" "Short" magit-log) - ("L" "Long" magit-log-long) - ("h" "Reflog" magit-reflog) - ("rl" "Ranged short" magit-log-ranged) - ("rL" "Ranged long" magit-log-long-ranged) - ("rh" "Ranged reflog" magit-reflog-ranged)) - (switches - ("-m" "Only merge commits" "--merges") - ("-f" "First parent" "--first-parent") - ("-i" "Case insensitive patterns" "-i") - ("-pr" "Pickaxe regex" "--pickaxe-regex") - ("-n" "Name only" "--name-only") - ("-am" "All match" "--all-match") - ("-al" "All" "--all")) - (arguments - ("=r" "Relative" "--relative=" read-directory-name) - ("=c" "Committer" "--committer=" read-from-minibuffer) - ("=>" "Since" "--since=" read-from-minibuffer) - ("=<" "Before" "--before=" read-from-minibuffer) - ("=s" "Pickaxe search" "-S" read-from-minibuffer) - ("=a" "Author" "--author=" read-from-minibuffer) - ("=g" "Grep" "--grep=" read-from-minibuffer))) - - (running - (actions - ("!" "Command from root" magit-shell-command) - (":" "Git command" magit-git-command) - ("g" "git gui" magit-run-git-gui) - ("k" "gitk" magit-run-gitk))) - - (fetching - (man-page "git-fetch") - (actions - ("f" "Current" magit-fetch-current) - ("a" "All" magit-remote-update) - ("o" "Other" magit-fetch)) - (switches - ("-p" "Prune" "--prune"))) - - (pushing - (man-page "git-push") - (actions - ("P" "Push" magit-push) - ("t" "Push tags" magit-push-tags)) - (switches - ("-f" "Force" "--force") - ("-d" "Dry run" "-n") - ("-u" "Set upstream" "-u"))) - - (pulling - (man-page "git-pull") - (actions - ("F" "Pull" magit-pull)) - (switches - ("-r" "Rebase" "--rebase"))) - - (branching - (man-page "git-branch") - (actions - ("v" "Branch manager" magit-branch-manager) - ("c" "Create" magit-create-branch) - ("r" "Rename" magit-move-branch) - ("k" "Delete" magit-delete-branch) - ("b" "Checkout" magit-checkout))) - - (remoting - (man-page "git-remote") - (actions - ("v" "Branch manager" magit-branch-manager) - ("a" "Add" magit-add-remote) - ("r" "Rename" magit-rename-remote) - ("k" "Remove" magit-remove-remote))) - - (tagging - (man-page "git-tag") - (actions - ("t" "Lightweight" magit-tag) - ("a" "Annotated" magit-annotated-tag)) - (switches - ("-f" "Force" "-f"))) - - (stashing - (man-page "git-stash") - (actions - ("z" "Save" magit-stash) - ("s" "Snapshot" magit-stash-snapshot)) - (switches - ("-k" "Keep index" "--keep-index") - ("-u" "Include untracked files" "--include-untracked") - ("-a" "Include all files" "--all"))) - - (merging - (man-page "git-merge") - (actions - ("m" "Merge" magit-manual-merge)) - (switches - ("-ff" "Fast-forward only" "--ff-only") - ("-nf" "No fast-forward" "--no-ff") - ("-sq" "Squash" "--squash")) - (arguments - ("-st" "Strategy" "--strategy=" read-from-minibuffer))) - - (rewriting - (actions - ("b" "Begin" magit-rewrite-start) - ("s" "Stop" magit-rewrite-stop) - ("a" "Abort" magit-rewrite-abort) - ("f" "Finish" magit-rewrite-finish) - ("*" "Set unused" magit-rewrite-set-unused) - ("." "Set used" magit-rewrite-set-used))) - - (submodule - (man-page "git-submodule") - (actions - ("u" "Update" magit-submodule-update) - ("b" "Both update and init" magit-submodule-update-init) - ("i" "Init" magit-submodule-init) - ("s" "Sync" magit-submodule-sync))) - - (bisecting - (man-page "git-bisect") - (actions - ("b" "Bad" magit-bisect-bad) - ("g" "Good" magit-bisect-good) - ("k" "Skip" magit-bisect-skip) - ("l" "Log" magit-bisect-log) - ("r" "Reset" magit-bisect-reset) - ("s" "Start" magit-bisect-start) - ("u" "Run" magit-bisect-run) - ("v" "Visualize" magit-bisect-visualize)))) - "Holds the key, help, function mapping for the log-mode. If you - modify this make sure you reset `magit-key-mode-key-maps' to - nil.") - -(defun magit-key-mode-delete-group (group) - "Delete a group from `magit-key-mode-key-maps'." - (let ((items (assoc group magit-key-mode-groups))) - (when items - ;; reset the cache - (setq magit-key-mode-key-maps nil) - ;; delete the whole group - (setq magit-key-mode-groups - (delq items magit-key-mode-groups)) - ;; unbind the defun - (magit-key-mode-de-generate group)) - magit-key-mode-groups)) - -(defun magit-key-mode-add-group (group) - "Add a new group to `magit-key-mode-key-maps'. If there's -already a group of that name then this will completely remove it -and put in its place an empty one of the same name." - (when (assoc group magit-key-mode-groups) - (magit-key-mode-delete-group group)) - (setq magit-key-mode-groups - (cons (list group (list 'actions)) magit-key-mode-groups))) - -(defun magit-key-mode-key-defined-p (for-group key) - "If KEY is defined as any of switch, argument or action within -FOR-GROUP then return t" - (catch 'result - (let ((options (magit-key-mode-options-for-group for-group))) - (dolist (type '(actions switches arguments)) - (when (assoc key (assoc type options)) - (throw 'result t)))))) - -(defun magit-key-mode-update-group (for-group thing &rest args) - "Abstraction for setting values in `magit-key-mode-key-maps'." - (let* ((options (magit-key-mode-options-for-group for-group)) - (things (assoc thing options)) - (key (car args))) - (if (cdr things) - (if (magit-key-mode-key-defined-p for-group key) - (error "%s is already defined in the %s group." key for-group) - (setcdr (cdr things) (cons args (cddr things)))) - (setcdr things (list args))) - (setq magit-key-mode-key-maps nil) - things)) - -(defun magit-key-mode-insert-argument (for-group key desc arg read-func) - "Add a new binding (KEY) in FOR-GROUP which will use READ-FUNC -to receive input to apply to argument ARG git is run. DESC should -be a brief description of the binding." - (magit-key-mode-update-group for-group 'arguments key desc arg read-func)) - -(defun magit-key-mode-insert-switch (for-group key desc switch) - "Add a new binding (KEY) in FOR-GROUP which will add SWITCH to git's -command line when it runs. DESC should be a brief description of -the binding." - (magit-key-mode-update-group for-group 'switches key desc switch)) - -(defun magit-key-mode-insert-action (for-group key desc func) - "Add a new binding (KEY) in FOR-GROUP which will run command -FUNC. DESC should be a brief description of the binding." - (magit-key-mode-update-group for-group 'actions key desc func)) - -(defun magit-key-mode-options-for-group (for-group) - "Retrieve the options (switches, commands and arguments) for -the group FOR-GROUP." - (or (cdr (assoc for-group magit-key-mode-groups)) - (error "Unknown group '%s'" for-group))) - -(defun magit-key-mode-help (for-group) - "Provide help for a key (which the user is prompted for) within -FOR-GROUP." - (let* ((opts (magit-key-mode-options-for-group for-group)) - (man-page (cadr (assoc 'man-page opts))) - (seq (read-key-sequence - (format "Enter command prefix%s: " - (if man-page - (format ", `?' for man `%s'" man-page) - "")))) - (actions (cdr (assoc 'actions opts)))) - (cond - ;; if it is an action popup the help for the to-be-run function - ((assoc seq actions) (describe-function (nth 2 (assoc seq actions)))) - ;; if there is "?" show a man page if there is one - ((equal seq "?") - (if man-page - (man man-page) - (error "No man page associated with `%s'" for-group))) - (t (error "No help associated with `%s'" seq))))) - -(defun magit-key-mode-exec-at-point () - "Run action/args/option at point." - (interactive) - (let* ((key (or (get-text-property (point) 'key-group-executor) - (error "Nothing at point to do."))) - (def (lookup-key (current-local-map) key))) - (call-interactively def))) -(defun magit-key-mode-jump-to-next-exec () - "Jump to the next action/args/option point." - (interactive) - (let* ((oldp (point)) - (old (get-text-property oldp 'key-group-executor)) - (p (if (= oldp (point-max)) (point-min) (1+ oldp)))) - (while (let ((new (get-text-property p 'key-group-executor))) - (and (not (= p oldp)) (or (not new) (eq new old)))) - (setq p (if (= p (point-max)) (point-min) (1+ p)))) - (goto-char p) - (skip-chars-forward " "))) - -(defun magit-key-mode-build-keymap (for-group) - "Construct a normal looking keymap for the key mode to use and -put it in magit-key-mode-key-maps for fast lookup." - (let* ((options (magit-key-mode-options-for-group for-group)) - (actions (cdr (assoc 'actions options))) - (switches (cdr (assoc 'switches options))) - (arguments (cdr (assoc 'arguments options))) - (map (make-sparse-keymap))) - (suppress-keymap map 'nodigits) - ;; ret dwim - (define-key map (kbd "RET") 'magit-key-mode-exec-at-point) - ;; tab jumps to the next "button" - (define-key map (kbd "TAB") 'magit-key-mode-jump-to-next-exec) - - ;; all maps should `quit' with `C-g' or `q' - (define-key map (kbd "C-g") `(lambda () - (interactive) - (magit-key-mode-command nil))) - (define-key map (kbd "q") `(lambda () - (interactive) - (magit-key-mode-command nil))) - ;; run help - (define-key map (kbd "?") `(lambda () - (interactive) - (magit-key-mode-help ',for-group))) - - (flet ((defkey (k action) - (when (and (lookup-key map (car k)) - (not (numberp (lookup-key map (car k))))) - (message "Warning: overriding binding for `%s' in %S" - (car k) for-group) - (ding) - (sit-for 2)) - (define-key map (car k) - `(lambda () (interactive) ,action)))) - (when actions - (dolist (k actions) - (defkey k `(magit-key-mode-command ',(nth 2 k))))) - (when switches - (dolist (k switches) - (defkey k `(magit-key-mode-add-option ',for-group ,(nth 2 k))))) - (when arguments - (dolist (k arguments) - (defkey k `(magit-key-mode-add-argument - ',for-group ,(nth 2 k) ',(nth 3 k)))))) - - (push (cons for-group map) magit-key-mode-key-maps) - map)) - -(defvar magit-key-mode-prefix nil - "For internal use. Holds the prefix argument to the command -that brought up the key-mode window, so it can be used by the -command that's eventually invoked.") - -(defun magit-key-mode-command (func) - (let ((args '())) - ;; why can't maphash return a list?! - (maphash (lambda (k v) - (push (concat k (shell-quote-argument v)) args)) - magit-key-mode-current-args) - (let ((magit-custom-options (append args magit-key-mode-current-options)) - (current-prefix-arg (or current-prefix-arg magit-key-mode-prefix))) - (set-window-configuration magit-log-mode-window-conf) - (when func - (call-interactively func)) - (magit-key-mode-kill-buffer)))) - -(defvar magit-key-mode-current-args nil - "A hash-table of current argument set (which will eventually - make it to the git command-line).") - -(defun magit-key-mode-add-argument (for-group arg-name input-func) - (let ((input (funcall input-func (concat arg-name ": ")))) - (puthash arg-name input magit-key-mode-current-args) - (magit-key-mode-redraw for-group))) - -(defvar magit-key-mode-current-options '() - "Current option set (which will eventually make it to the git - command-line).") - -(defun magit-key-mode-add-option (for-group option-name) - "Toggles the appearance of OPTION-NAME in -`magit-key-mode-current-options'." - (if (not (member option-name magit-key-mode-current-options)) - (add-to-list 'magit-key-mode-current-options option-name) - (setq magit-key-mode-current-options - (delete option-name magit-key-mode-current-options))) - (magit-key-mode-redraw for-group)) - -(defun magit-key-mode-kill-buffer () - (interactive) - (kill-buffer magit-key-mode-buf-name)) - -(defvar magit-log-mode-window-conf nil - "Pre-popup window configuration.") - -(defun magit-key-mode (for-group &optional original-opts) - "Mode for magit key selection. All commands, switches and -options can be toggled/actioned with the key combination -highlighted before the description." - (interactive) - ;; save the window config to restore it as was (no need to make this - ;; buffer local) - (setq magit-log-mode-window-conf - (current-window-configuration)) - ;; setup the mode, draw the buffer - (let ((buf (get-buffer-create magit-key-mode-buf-name))) - (delete-other-windows) - (split-window-vertically) - (other-window 1) - (switch-to-buffer buf) - (kill-all-local-variables) - (set (make-local-variable - 'magit-key-mode-current-options) - original-opts) - (set (make-local-variable - 'magit-key-mode-current-args) - (make-hash-table)) - (set (make-local-variable 'magit-key-mode-prefix) current-prefix-arg) - (magit-key-mode-redraw for-group)) - (message - (concat - "Type a prefix key to toggle it. Run 'actions' with their prefixes. " - "'?' for more help."))) - -(defun magit-key-mode-get-key-map (for-group) - "Get or build the keymap for FOR-GROUP." - (or (cdr (assoc for-group magit-key-mode-key-maps)) - (magit-key-mode-build-keymap for-group))) - -(defun magit-key-mode-redraw (for-group) - "(re)draw the magit key buffer." - (let ((buffer-read-only nil) - (old-point (point)) - (is-first (zerop (buffer-size))) - (actions-p nil)) - (erase-buffer) - (make-local-variable 'font-lock-defaults) - (use-local-map (magit-key-mode-get-key-map for-group)) - (setq actions-p (magit-key-mode-draw for-group)) - (delete-trailing-whitespace) - (setq mode-name "magit-key-mode" major-mode 'magit-key-mode) - (if (and is-first actions-p) - (progn (goto-char actions-p) - (magit-key-mode-jump-to-next-exec)) - (goto-char old-point))) - (setq buffer-read-only t) - (fit-window-to-buffer)) - -(defun magit-key-mode-draw-header (header) - "Draw a header with the correct face." - (insert (propertize header 'face 'font-lock-keyword-face) "\n")) - -(defvar magit-key-mode-args-in-cols nil - "When true, draw arguments in columns as with switches and - options.") - -(defun magit-key-mode-draw-args (args) - "Draw the args part of the menu." - (magit-key-mode-draw-buttons - "Args" - args - (lambda (x) - (format "(%s) %s" - (nth 2 x) - (propertize (gethash (nth 2 x) magit-key-mode-current-args "") - 'face 'widget-field))) - (not magit-key-mode-args-in-cols))) - -(defun magit-key-mode-draw-switches (switches) - "Draw the switches part of the menu." - (magit-key-mode-draw-buttons - "Switches" - switches - (lambda (x) - (format "(%s)" (let ((s (nth 2 x))) - (if (member s magit-key-mode-current-options) - (propertize s 'face 'font-lock-warning-face) - s)))))) - -(defun magit-key-mode-draw-actions (actions) - "Draw the actions part of the menu." - (magit-key-mode-draw-buttons "Actions" actions nil)) - -(defun magit-key-mode-draw-buttons (section xs maker - &optional one-col-each) - (when xs - (magit-key-mode-draw-header section) - (magit-key-mode-draw-in-cols - (mapcar (lambda (x) - (let* ((head (propertize (car x) 'face 'font-lock-builtin-face)) - (desc (nth 1 x)) - (more (and maker (funcall maker x))) - (text (format " %s: %s%s%s" - head desc (if more " " "") (or more "")))) - (propertize text 'key-group-executor (car x)))) - xs) - one-col-each))) - -(defun magit-key-mode-draw-in-cols (strings one-col-each) - "Given a list of strings, print in columns (using `insert'). If -ONE-COL-EACH is true then don't columify, but rather, draw each -item on one line." - (let ((longest-act (apply 'max (mapcar 'length strings)))) - (while strings - (let ((str (car strings))) - (let ((padding (make-string (- (+ longest-act 3) (length str)) ? ))) - (insert str) - (if (or one-col-each - (and (> (+ (length padding) ; - (current-column) - longest-act) - (window-width)) - (cdr strings))) - (insert "\n") - (insert padding)))) - (setq strings (cdr strings)))) - (insert "\n")) - -(defun magit-key-mode-draw (for-group) - "Function used to draw actions, switches and parameters. - -Returns the point before the actions part, if any." - (let* ((options (magit-key-mode-options-for-group for-group)) - (switches (cdr (assoc 'switches options))) - (arguments (cdr (assoc 'arguments options))) - (actions (cdr (assoc 'actions options))) - (p nil)) - (magit-key-mode-draw-switches switches) - (magit-key-mode-draw-args arguments) - (when actions (setq p (point-marker))) - (magit-key-mode-draw-actions actions) - (insert "\n") - p)) - -(defun magit-key-mode-de-generate (group) - "Unbind the function for GROUP." - (fmakunbound - (intern (concat "magit-key-mode-popup-" (symbol-name group))))) - -(defun magit-key-mode-generate (group) - "Generate the key-group menu for GROUP" - (let ((opts (magit-key-mode-options-for-group group))) - (eval - `(defun ,(intern (concat "magit-key-mode-popup-" (symbol-name group))) nil - ,(concat "Key menu for " (symbol-name group)) - (interactive) - (magit-key-mode (quote ,group)))))) - -;; create the interactive functions for the key mode popups (which are -;; applied in the top-level key maps) -(mapc (lambda (g) - (magit-key-mode-generate (car g))) - magit-key-mode-groups) - -(provide 'magit-key-mode) diff --git a/elpa/magit-1.2.1/magit-pkg.el b/elpa/magit-1.2.1/magit-pkg.el deleted file mode 100644 index 4922e82..0000000 --- a/elpa/magit-1.2.1/magit-pkg.el +++ /dev/null @@ -1 +0,0 @@ -(define-package "magit" "1.2.1" "Control Git from Emacs.") diff --git a/elpa/magit-1.2.1/magit-stgit.el b/elpa/magit-1.2.1/magit-stgit.el deleted file mode 100644 index b105b71..0000000 --- a/elpa/magit-1.2.1/magit-stgit.el +++ /dev/null @@ -1,288 +0,0 @@ -;;; magit-stgit.el --- StGit plug-in for Magit - -;; Copyright (C) 2011 Lluis Vilanova -;; -;; 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 . - -;;; Commentary: - -;; This plug-in provides StGit functionality as a separate component of Magit. - -;; Available actions: -;; - visit: Shows the patch at point in the series (stg show) -;; - apply: Goes to the patch at point in the series (stg goto) -;; - discard: Deletes the marked/at point patch in the series (stg delete) - -;; Available commands: -;; - `magit-stgit-refresh': Refresh the marked/at point patch in the series -;; (stg refresh) -;; - `magit-stgit-repair': Repair the StGit metadata (stg repair) -;; - `magit-stgit-rebase': Rebase the whole series (stg rebase) - -;; TODO: -;; - Let the user select which files must be included in a refresh. -;; - Missing actions for `magit-show-item-or-scroll-up' and -;; `magit-show-item-or-scroll-down'. -;; - Marking a patch is slow and refreshes all buffers, which resets their -;; position (i.e., the buffer is shown from its first line). - -;;; Code: - -(require 'magit) -(eval-when-compile - (require 'cl)) - -;;; Customizables: - -(defcustom magit-stgit-executable "stg" - "The name of the StGit executable." - :group 'magit - :type 'string) - -(defface magit-stgit-applied - '((t :inherit magit-diff-add)) - "Face for an applied stgit patch." - :group 'magit-faces) - -(defface magit-stgit-current - '((t :inherit magit-item-highlight)) - "Face for the current stgit patch." - :group 'magit-faces) - -(defface magit-stgit-other - '((t :inherit magit-diff-del)) - "Face for a non-applied stgit patch." - :group 'magit-faces) - -(defface magit-stgit-marked - '((t :inherit magit-item-mark)) - "Face for a marked stgit patch." - :group 'magit-faces) - -(defface magit-stgit-empty - '((t :inherit magit-item-mark)) - "Face for an empty stgit patch." - :group 'magit-faces) - -;;; Common code: - -(defvar magit-stgit--enabled nil - "Whether this buffer has StGit support.") -(make-variable-buffer-local 'magit-stgit--enabled) - -(defvar magit-stgit-mode) - -(defun magit-stgit--enabled () - "Whether this buffer has StGit support enabled." - (if (assoc 'magit-stgit--enabled (buffer-local-variables)) - magit-stgit--enabled - (setq magit-stgit--enabled - (and magit-stgit-mode - (not (null - (member (concat (magit-get-current-branch) ".stgit") - (mapcar #'(lambda (line) - (string-match "^\\*?\s*\\([^\s]*\\)" - line) - (match-string 1 line)) - (magit-git-lines "branch"))))))))) - -(defun magit-stgit--enabled-reset () - "Reset the StGit enabled state." - (kill-local-variable 'magit-stgit--enabled)) - -(defvar magit-stgit--marked-patch nil - "The (per-buffer) currently marked patch in an StGit series.") -(make-variable-buffer-local 'magit-stgit--marked-patch) - -;;; Menu: - -(easy-menu-define magit-stgit-extension-menu - nil - "StGit extension menu" - '("StGit" - :active (magit-stgit--enabled) - - ["Refresh patch" magit-stgit-refresh - :help "Refresh the contents of a patch in an StGit series"] - ["Repair" magit-stgit-repair - :help "Repair StGit metadata if branch was modified with git commands"] - ["Rebase series" magit-stgit-rebase - :help "Rebase an StGit patch series"] - )) - -(easy-menu-add-item 'magit-mode-menu - '("Extensions") - magit-stgit-extension-menu) - -;;; Series section: - -(defun magit-stgit--wash-patch () - (if (search-forward-regexp "^\\(.\\)\\(.\\) \\([^\s]*\\)\\(\s*# ?\\)\\(.*\\)" - (line-end-position) t) - (let* ((empty-str "[empty] ") - (indent-str (make-string (string-bytes empty-str) ?\ )) - (empty (match-string 1)) - (state (match-string 2)) - (patch (match-string 3)) - (descr (match-string 5))) - (delete-region (line-beginning-position) (line-end-position)) - (insert - (cond ((string= empty "0") - (propertize (concat empty-str " " state " " descr) 'face 'magit-stgit-empty)) - ((string= magit-stgit--marked-patch patch) - (propertize (concat indent-str " " state " " descr) 'face 'magit-stgit-marked)) - ((string= state "+") - (concat indent-str " " (propertize state 'face 'magit-stgit-applied) " " descr)) - ((string= state ">") - (propertize (concat indent-str " " state " " descr) 'face 'magit-stgit-current)) - ((string= state "-") - (concat indent-str " " (propertize state 'face 'magit-stgit-other) " " descr)))) - (goto-char (line-beginning-position)) - (magit-with-section patch 'series - (magit-set-section-info patch) - (goto-char (line-end-position))) - (forward-line)) - (delete-region (line-beginning-position) (1+ (line-end-position)))) - t) - -(defun magit-stgit--wash-series () - (let ((magit-old-top-section nil)) - (magit-wash-sequence #'magit-stgit--wash-patch))) - -(magit-define-inserter series () - (when (executable-find magit-stgit-executable) - (magit-insert-section 'series - "Series:" 'magit-stgit--wash-series - magit-stgit-executable "series" "-a" "-d" "-e"))) - -;;; Actions: - -;; Copy of `magit-refresh-commit-buffer' (version 1.0.0) -(defun magit-stgit--refresh-patch-buffer (patch) - (magit-create-buffer-sections - (magit-insert-section nil nil - 'magit-wash-commit - magit-stgit-executable - "show" - patch))) - -;; Copy of `magit-show-commit' (version 1.0.0) -(defun magit-stgit--show-patch (patch &optional scroll) - (when (magit-section-p patch) - (setq patch (magit-section-info patch))) - (let ((dir default-directory) - (buf (get-buffer-create magit-commit-buffer-name))) - (cond ((and (equal magit-currently-shown-commit patch) - ;; if it's empty then the buffer was killed - (with-current-buffer buf - (> (length (buffer-string)) 1))) - (let ((win (get-buffer-window buf))) - (cond ((not win) - (display-buffer buf)) - (scroll - (with-selected-window win - (funcall scroll)))))) - (t - (setq magit-currently-shown-commit patch) - (display-buffer buf) - (with-current-buffer buf - (set-buffer buf) - (goto-char (point-min)) - (magit-mode-init dir 'magit-commit-mode - #'magit-stgit--refresh-patch-buffer patch)))))) - -(magit-add-action (item info "visit") - ((series) - (magit-stgit--show-patch info) - (pop-to-buffer magit-commit-buffer-name))) - -(magit-add-action (item info "apply") - ((series) - (magit-run magit-stgit-executable "goto" info))) - -(magit-add-action (item info "discard") - ((series) - (let ((patch (or magit-stgit--marked-patch info))) - (if (yes-or-no-p (format "Delete patch '%s' in series? " patch)) - (progn - (if (string= magit-stgit--marked-patch patch) - (setq magit-stgit--marked-patch nil)) - (magit-run magit-stgit-executable "delete" patch)))))) - -(defun magit-stgit--set-marked-patch (patch) - (setq magit-stgit--marked-patch - (if (string= magit-stgit--marked-patch patch) - nil - patch))) - -(magit-add-action (item info "mark") - ((series) - (magit-stgit--set-marked-patch info) - (magit-refresh-all))) - -;;; Commands: - -(defun magit-stgit-refresh () - "Refresh the contents of a patch in an StGit series. -If there is no marked patch in the series, refreshes the current -patch. -Otherwise, refreshes the marked patch." - (interactive) - (if magit-stgit--marked-patch - (magit-run magit-stgit-executable "refresh" "-p" magit-stgit--marked-patch) - (magit-run magit-stgit-executable "refresh"))) - -(defun magit-stgit-repair () - "Repair StGit metadata if branch was modified with git commands. -In the case of Git commits these will be imported as new patches -into the series." - (interactive) - (message "Repairing series...") - (magit-run magit-stgit-executable "repair") - (message "")) - -(defun magit-stgit-rebase () - "Rebase an StGit patch series." - (interactive) - (if (magit-get-current-remote) - (progn - (if (yes-or-no-p "Update remotes? ") - (progn - (message "Updating remotes...") - (magit-run-git-async "remote" "update"))) - (magit-run magit-stgit-executable "rebase" - (format "remotes/%s/%s" - (magit-get-current-remote) - (magit-get-current-branch)))))) - -;;;###autoload -(define-minor-mode magit-stgit-mode "StGit support for Magit" - :lighter " Stg" :require 'magit-stgit - (or (derived-mode-p 'magit-mode) - (error "This mode only makes sense with magit")) - (if magit-stgit-mode - (progn - (add-hook 'magit-after-insert-stashes-hook 'magit-insert-series nil t)) - (progn - (remove-hook 'magit-after-insert-stashes-hook 'magit-insert-series t))) - (when (called-interactively-p 'any) - (magit-refresh))) - -;;;###autoload -(defun turn-on-magit-stgit () - "Unconditionally turn on `magit-stgit-mode'." - (magit-stgit-mode 1)) - -(provide 'magit-stgit) -;;; magit-stgit.el ends here diff --git a/elpa/magit-1.2.1/magit-svn.el b/elpa/magit-1.2.1/magit-svn.el deleted file mode 100644 index d08c048..0000000 --- a/elpa/magit-1.2.1/magit-svn.el +++ /dev/null @@ -1,240 +0,0 @@ -;;; magit-svn.el --- git-svn plug-in for Magit - -;; Copyright (C) 2008 Alex Ott -;; Copyright (C) 2009 Alexey Voinov -;; Copyright (C) 2009 John Wiegley -;; Copyright (C) 2008 Linh Dang -;; Copyright (C) 2008 Marcin Bachry -;; Copyright (C) 2008, 2009 Marius Vollmer -;; Copyright (C) 2010 Yann Hodique -;; -;; 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 . - -;;; Commentary: - -;; This plug-in provides git-svn functionality as a separate component of Magit - -;;; Code: - -(require 'magit) -(eval-when-compile - (require 'cl)) - -;; git svn commands - -(defun magit-svn-find-rev (rev &optional branch) - (interactive - (list (read-string "SVN revision: ") - (if current-prefix-arg - (read-string "In branch: ")))) - (let* ((sha (apply 'magit-git-string - `("svn" - "find-rev" - ,(concat "r" rev) - ,@(when branch (list branch)))))) - (if sha - (magit-show-commit - (magit-with-section sha 'commit - (magit-set-section-info sha) - sha)) - (error "Revision %s could not be mapped to a commit" rev)))) - -(defun magit-svn-create-branch (name) - (interactive "sBranch name: ") - (magit-run-git "svn" "branch" name)) - -(defun magit-svn-rebase () - (interactive) - (magit-run-git-async "svn" "rebase")) - -(defun magit-svn-dcommit () - (interactive) - (magit-run-git-async "svn" "dcommit")) - -(defun magit-svn-enabled () - (not (null (magit-svn-get-ref-info t)))) - -(defun magit-svn-expand-braces-in-branches (branch) - (if (not (string-match "\\(.+\\){\\(.+,.+\\)}\\(.*\\):\\(.*\\)\\\*" branch)) - (list branch) - (let ((prefix (match-string 1 branch)) - (suffix (match-string 3 branch)) - (rhs (match-string 4 branch)) - (pieces (split-string (match-string 2 branch) ","))) - (mapcar (lambda (p) (concat prefix p suffix ":" rhs p)) pieces)))) - -(defun magit-svn-get-local-ref (url) - (let* ((branches (cons (magit-get "svn-remote" "svn" "fetch") - (magit-get-all "svn-remote" "svn" "branches"))) - (branches (apply 'nconc - (mapcar 'magit-svn-expand-braces-in-branches - branches))) - (base-url (magit-get "svn-remote" "svn" "url")) - (result nil)) - (while branches - (let* ((pats (split-string (pop branches) ":")) - (src (replace-regexp-in-string "\\*" "\\\\(.*\\\\)" (car pats))) - (dst (replace-regexp-in-string "\\*" "\\\\1" (cadr pats))) - (base-url (replace-regexp-in-string "\\+" "\\\\+" base-url)) - (base-url (replace-regexp-in-string "//.+@" "//" base-url)) - (pat1 (concat "^" src "$")) - (pat2 (cond ((equal src "") (concat "^" base-url "$")) - (t (concat "^" base-url "/" src "$"))))) - (cond ((string-match pat1 url) - (setq result (replace-match dst nil nil url)) - (setq branches nil)) - ((string-match pat2 url) - (setq result (replace-match dst nil nil url)) - (setq branches nil))))) - result)) - -(defvar magit-svn-get-ref-info-cache nil - "A cache for svn-ref-info. -As `magit-get-svn-ref-info' might be considered a quite -expensive operation a cache is taken so that `magit-status' -doesn't repeatedly call it.") - -(defun magit-svn-get-ref-info (&optional use-cache) - "Gather details about the current git-svn repository. -Return nil if there isn't one. Keys of the alist are ref-path, -trunk-ref-name and local-ref-name. -If USE-CACHE is non-nil then return the value of `magit-get-svn-ref-info-cache'." - (if (and use-cache magit-svn-get-ref-info-cache) - magit-svn-get-ref-info-cache - (let* ((fetch (magit-get "svn-remote" "svn" "fetch")) - (url) - (revision)) - (when fetch - (let* ((ref (cadr (split-string fetch ":"))) - (ref-path (file-name-directory ref)) - (trunk-ref-name (file-name-nondirectory ref))) - (set (make-local-variable - 'magit-svn-get-ref-info-cache) - (list - (cons 'ref-path ref-path) - (cons 'trunk-ref-name trunk-ref-name) - ;; get the local ref from the log. This is actually - ;; the way that git-svn does it. - (cons 'local-ref - (with-temp-buffer - (insert (or (magit-git-string "log" "--first-parent" - "--grep" "git-svn" "-1") - "")) - (goto-char (point-min)) - (cond ((re-search-forward "git-svn-id: \\(.+/.+?\\)@\\([0-9]+\\)" nil t) - (setq url (match-string 1) - revision (match-string 2)) - (magit-svn-get-local-ref url)) - (t - (setq url (magit-get "svn-remote" "svn" "url")) - nil)))) - (cons 'revision revision) - (cons 'url url)))))))) - -(defun magit-svn-get-ref (&optional use-cache) - "Get the best guess remote ref for the current git-svn based branch. -If USE-CACHE is non nil, use the cached information." - (let ((info (magit-svn-get-ref-info use-cache))) - (cdr (assoc 'local-ref info)))) - -(magit-define-inserter svn-unpulled (&optional use-cache) - (when (magit-svn-enabled) - (apply #'magit-git-section - 'svn-unpulled "Unpulled commits (SVN):" 'magit-wash-log "log" - (append magit-git-log-options - (list - (format "HEAD..%s" (magit-svn-get-ref use-cache))))))) - -(magit-define-inserter svn-unpushed (&optional use-cache) - (when (magit-svn-enabled) - (apply #'magit-git-section - 'svn-unpushed "Unpushed commits (SVN):" 'magit-wash-log "log" - (append magit-git-log-options - (list - (format "%s..HEAD" (magit-svn-get-ref use-cache))))))) - -(magit-define-section-jumper svn-unpushed "Unpushed commits (SVN)") - -(defun magit-svn-remote-string () - (let ((svn-info (magit-svn-get-ref-info))) - (when svn-info - (concat (cdr (assoc 'url svn-info)) - " @ " - (cdr (assoc 'revision svn-info)))))) - -(defun magit-svn-remote-update () - (interactive) - (when (magit-svn-enabled) - (magit-run-git-async "svn" "fetch"))) - -(easy-menu-define magit-svn-extension-menu - nil - "Git SVN extension menu" - '("Git SVN" - :visible magit-svn-mode - ["Create branch" magit-svn-create-branch (magit-svn-enabled)] - ["Rebase" magit-svn-rebase (magit-svn-enabled)] - ["Fetch" magit-svn-remote-update (magit-svn-enabled)] - ["Commit" magit-svn-dcommit (magit-svn-enabled)])) - -(easy-menu-add-item 'magit-mode-menu - '("Extensions") - magit-svn-extension-menu) - -;; add the group and its keys -(progn - ;; (re-)create the group - (magit-key-mode-add-group 'svn) - - (magit-key-mode-insert-action 'svn "r" "Rebase" 'magit-svn-rebase) - (magit-key-mode-insert-action 'svn "c" "DCommit" 'magit-svn-dcommit) - (magit-key-mode-insert-action 'svn "f" "Fetch" 'magit-svn-remote-update) - (magit-key-mode-insert-action 'svn "s" "Find rev" 'magit-svn-find-rev) - (magit-key-mode-insert-action 'svn "B" "Create branch" 'magit-svn-create-branch) - - ;; generate and bind the menu popup function - (magit-key-mode-generate 'svn)) - -(defvar magit-svn-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "N") 'magit-key-mode-popup-svn) - map)) - -;;;###autoload -(define-minor-mode magit-svn-mode "SVN support for Magit" - :lighter " SVN" :require 'magit-svn :keymap 'magit-svn-mode-map - (or (derived-mode-p 'magit-mode) - (error "This mode only makes sense with magit")) - (let ((unpulled-hook (lambda () (magit-insert-svn-unpulled t))) - (unpushed-hook (lambda () (magit-insert-svn-unpushed t))) - (remote-hook 'magit-svn-remote-string)) - (if magit-svn-mode - (progn - (add-hook 'magit-after-insert-unpulled-commits-hook unpulled-hook nil t) - (add-hook 'magit-after-insert-unpushed-commits-hook unpushed-hook nil t) - (add-hook 'magit-remote-string-hook remote-hook nil t)) - (progn - (remove-hook 'magit-after-insert-unpulled-commits-hook unpulled-hook t) - (remove-hook 'magit-after-insert-unpushed-commits-hook unpushed-hook t) - (remove-hook 'magit-remote-string-hook remote-hook t))) - (when (called-interactively-p 'any) - (magit-refresh)))) - -;;;###autoload -(defun turn-on-magit-svn () - "Unconditionally turn on `magit-svn-mode'." - (magit-svn-mode 1)) - -(provide 'magit-svn) -;;; magit-svn.el ends here diff --git a/elpa/magit-1.2.1/magit-topgit.el b/elpa/magit-1.2.1/magit-topgit.el deleted file mode 100644 index 6f0080c..0000000 --- a/elpa/magit-1.2.1/magit-topgit.el +++ /dev/null @@ -1,191 +0,0 @@ -;;; magit-topgit.el --- topgit plug-in for Magit - -;; Copyright (C) 2010 Nathan Weizenbaum -;; Copyright (C) 2010 Yann Hodique -;; -;; 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 . - -;;; Commentary: - -;; This plug-in provides topgit functionality as a separate component of Magit - -;;; Code: - -(require 'magit) -(eval-when-compile - (require 'cl)) - -(defcustom magit-topgit-executable "tg" - "The name of the TopGit executable." - :group 'magit - :type 'string) - -(defcustom magit-topgit-branch-prefix "t/" - "Convention prefix for topic branch creation." - :group 'magit - :type 'string) - -(defface magit-topgit-current - '((t :weight bold :inherit magit-branch)) - "Face for section titles." - :group 'magit-faces) - -;;; Topic branches (using topgit) - -(defun magit-topgit-in-topic-p () - (and (file-exists-p ".topdeps") - (executable-find magit-topgit-executable))) - -(defun magit-topgit-create-branch (branch parent) - (when (zerop (or (string-match magit-topgit-branch-prefix branch) -1)) - (magit-run* (list magit-topgit-executable "create" - branch (magit-rev-to-git parent)) - nil nil nil t) - t)) - -(defun magit-topgit-pull () - (when (magit-topgit-in-topic-p) - (magit-run* (list magit-topgit-executable "update") - nil nil nil t) - t)) - -(defun magit-topgit-push () - (when (magit-topgit-in-topic-p) - (let* ((branch (or (magit-get-current-branch) - (error "Don't push a detached head. That's gross"))) - (remote (magit-get "topgit" "remote")) - (push-remote (if (or current-prefix-arg (not remote)) - (magit-read-remote (format "Push %s to" branch)) - remote))) - (when (and (not remote) - (not current-prefix-arg)) - (magit-set push-remote "topgit" "remote")) - (magit-run magit-topgit-executable "push" "-r" push-remote)) - t)) - -(defun magit-topgit-remote-update (&optional remote) - (when (magit-topgit-in-topic-p) - (let* ((remote (magit-get "topgit" "remote")) - (remote-update (if (or current-prefix-arg (not remote)) - (magit-read-remote) - remote))) - (if (and (not remote) - (not current-prefix-arg)) - (progn - (magit-set remote-update "topgit" "remote") - (magit-run magit-topgit-executable "remote" - "--populate" remote-update))) - (magit-run magit-topgit-executable "remote" remote-update)) - ;; We return nil anyway, as we also want regular "git remote update" to - ;; happen - nil)) - -(defun magit-topgit-parse-flags (flags-string) - (let ((flags (string-to-list flags-string)) - (void-flag ?\ )) - (list :current (not (eq (nth 0 flags) void-flag)) - :empty (not (eq (nth 1 flags) void-flag))))) - -(defun magit-topgit-wash-topic () - (let ((fmt "^\\(.\\{7\\}\\)\\s-\\(\\S-+\\)\\s-+\\(.*\\)")) - (if (search-forward-regexp fmt (line-end-position) t) - (let ((flags (magit-topgit-parse-flags (match-string 1))) - (topic (match-string 2))) - (goto-char (line-beginning-position)) - (delete-char 8) - (insert "\t") - (goto-char (line-beginning-position)) - (magit-with-section topic 'topic - (magit-set-section-info topic) - (let ((beg (1+ (line-beginning-position))) - (end (line-end-position))) - (when (plist-get flags :current) - (put-text-property beg end 'face 'magit-topgit-current)) - (when (plist-get flags :empty) - (put-text-property beg end 'face `(:strike-through t :inherit ,(get-text-property beg 'face))))) - (forward-line))) - (delete-region (line-beginning-position) (1+ (line-end-position)))) - t)) - -(defun magit-topgit-wash-topics () - (let ((magit-old-top-section nil)) - (magit-wash-sequence #'magit-topgit-wash-topic))) - -(defun magit-topgit-section (section title washer &rest args) - (when (executable-find magit-topgit-executable) - (let ((magit-git-executable magit-topgit-executable) - (magit-git-standard-options nil)) - (apply 'magit-git-section section title washer args)))) - -(magit-define-inserter topics () - (magit-topgit-section 'topics - "Topics:" 'magit-topgit-wash-topics - "summary")) - -(magit-add-action (item info "discard") - ((topic) - (when (yes-or-no-p "Discard topic? ") - (magit-run* (list magit-topgit-executable "delete" "-f" info) - nil nil nil t)))) - -(magit-add-action (item info "visit") - ((topic) - (magit-checkout info))) - -(defun magit-topgit-get-top-bases-color (suffix) - (list nil nil)) - -(defun magit-topgit-get-remote-top-bases-color (suffix) - (when (string-match "^\\(?:[^/]+\\)/top-bases" suffix) - (list nil nil))) - -(defconst magit-topgit-ignored-namespace - '("top-bases" magit-topgit-get-top-bases-color)) - -;;;###autoload -(define-minor-mode magit-topgit-mode "Topgit support for Magit" - :lighter " Topgit" :require 'magit-topgit - (or (derived-mode-p 'magit-mode) - (error "This mode only makes sense with magit")) - (if magit-topgit-mode - (progn - (add-hook 'magit-after-insert-stashes-hook 'magit-insert-topics nil t) - (add-hook 'magit-create-branch-command-hook 'magit-topgit-create-branch nil t) - (add-hook 'magit-pull-command-hook 'magit-topgit-pull nil t) - (add-hook 'magit-remote-update-command-hook 'magit-topgit-remote-update nil t) - (add-hook 'magit-push-command-hook 'magit-topgit-push nil t) - ;; hide refs for top-bases namespace in any remote - (add-hook 'magit-log-remotes-color-hook - 'magit-topgit-get-remote-top-bases-color) - ;; hide refs in the top-bases namespace, as they're not meant for the user - (add-to-list 'magit-refs-namespaces magit-topgit-ignored-namespace)) - (progn - (remove-hook 'magit-after-insert-stashes-hook 'magit-insert-topics t) - (remove-hook 'magit-create-branch-command-hook 'magit-topgit-create-branch t) - (remove-hook 'magit-pull-command-hook 'magit-topgit-pull t) - (remove-hook 'magit-remote-update-command-hook 'magit-topgit-remote-update t) - (remove-hook 'magit-push-command-hook 'magit-topgit-push t) - (remove-hook 'magit-log-remotes-color-hook - 'magit-topgit-get-remote-top-bases-color) - (delete magit-topgit-ignored-namespace magit-refs-namespaces))) - (when (called-interactively-p 'any) - (magit-refresh))) - -;;;###autoload -(defun turn-on-magit-topgit () - "Unconditionally turn on `magit-topgit-mode'." - (magit-topgit-mode 1)) - -(provide 'magit-topgit) -;;; magit-topgit.el ends here diff --git a/elpa/magit-1.2.1/magit-wip.el b/elpa/magit-1.2.1/magit-wip.el deleted file mode 100644 index 5c19840..0000000 --- a/elpa/magit-1.2.1/magit-wip.el +++ /dev/null @@ -1,153 +0,0 @@ -;;; magit-wip.el --- git-wip plug-in for Magit - -;; Copyright (C) 2012 Jonas Bernoulli -;; Copyright (C) 2012 Ryan C. Thompson - -;; Maintainer: Jonas Bernoulli - -;; 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 . - -;;; Commentary: - -;; This plug-in provides support for special work-in-progress refs. - -;; This requires the third-party git command "git wip" which is available -;; from https://github.com/bartman/git-wip. - -;; The global mode `magit-wip-mode' provides highlighting of wip refs in -;; Magit buffers while the local mode `magit-wip-save-mode' commits to -;; such a ref when saving a file-visiting buffer. - -;; To enable `magit-wip-save-mode' enable `global-magit-wip-save-mode' -;; and use the Magit extension mechanism to select the repositories in -;; which you want to use a work-in-progress ref. Usually you also want -;; to enable `magit-wip-mode'. -;; -;; (magit-wip-mode 1) -;; (global-magit-wip-save-mode 1) -;; -;; $ git config --add magit.extension wip-save # or -;; $ git config --global --add magit.extension wip-save - -;; Note that `global-magit-wip-save-mode' is the only mode that uses the -;; extension mechanism for file-visiting buffers all other global modes -;; making use of it to turn on local modes in Magit buffers. - -;;; Code: - -(require 'magit) -(require 'format-spec) - -;;; Magit Wip Mode. - -(defface magit-log-head-label-wip - '((((class color) (background light)) - :box t - :background "Grey95" - :foreground "LightSkyBlue3") - (((class color) (background dark)) - :box t - :background "Grey07" - :foreground "LightSkyBlue4")) - "Face for git-wip labels shown in log buffer." - :group 'magit-faces) - -(defun magit-log-get-wip-color (suffix) - (list (concat "(WIP) " suffix) - 'magit-log-head-label-wip)) - -(defconst magit-wip-refs-namespace - '("wip" magit-log-get-wip-color)) - -;;;###autoload -(define-minor-mode magit-wip-mode - "In Magit log buffers; give wip refs a special appearance." - :group 'magit - :global t - (if magit-wip-mode - (add-to-list 'magit-refs-namespaces magit-wip-refs-namespace 'append) - (setq magit-refs-namespaces - (delete magit-wip-refs-namespace magit-refs-namespaces)))) - -;;; Magit Wip Save Mode. - -(defcustom magit-wip-commit-message "WIP %r" - "Commit message for git-wip commits. - -The following `format'-like specs are supported: -%f the full name of the file being saved, and -%r the name of the file being saved, relative to the repository root -%g the root of the git repository." - :group 'magit - :type 'string) - -(defcustom magit-wip-echo-area-message "Wrote %f (wip)" - "Message shown in the echo area after creating a git-wip commit. - -The following `format'-like specs are supported: -%f the full name of the file being saved, and -%r the name of the file being saved, relative to the repository root. -%g the root of the git repository." - :group 'magit - :type '(choice (const :tag "No message" nil) string)) - -(defvar magit-wip-save-mode-lighter " Wip") - -;;;###autoload -(define-minor-mode magit-wip-save-mode - "Magit support for committing to a work-in-progress ref. - -When this minor mode is turned on and a file is saved inside a writable -git repository then it is also committed to a special work-in-progress -ref." - :lighter magit-wip-save-mode-lighter - (if magit-wip-save-mode - (add-hook 'after-save-hook 'magit-wip-save-safe t t) - (remove-hook 'after-save-hook 'magit-wip-save-safe t))) - -;;;###autoload -(define-globalized-minor-mode global-magit-wip-save-mode - magit-wip-save-mode turn-on-magit-wip-save - :group 'magit) - -(defun turn-on-magit-wip-save () - (when (and (buffer-file-name) - (magit-get-top-dir default-directory) - (member "wip-save" (magit-get-all "magit.extension"))) - (if (= (magit-git-exit-code "wip" "-h") 0) - (magit-wip-save-mode 1) - (message "Git command 'git wip' cannot be found")))) - -(defun magit-wip-save-safe () - (condition-case err - (magit-wip-save) - (error - (message "Magit WIP got an error: %S" err)))) - -(defun magit-wip-save () - (let* ((top-dir (magit-get-top-dir default-directory)) - (name (file-truename (buffer-file-name))) - (spec `((?r . ,(file-relative-name name top-dir)) - (?f . ,(buffer-file-name)) - (?g . ,top-dir)))) - (when (and top-dir (file-writable-p top-dir)) - (save-excursion ; kludge see https://github.com/magit/magit/issues/441 - (magit-run-git "wip" "save" - (format-spec magit-wip-commit-message spec) - "--editor" "--" name)) - (when magit-wip-echo-area-message - (message (format-spec magit-wip-echo-area-message spec)))))) - -(provide 'magit-wip) -;;; magit-wip.el ends here diff --git a/elpa/magit-1.2.1/magit.el b/elpa/magit-1.2.1/magit.el deleted file mode 100644 index baa54a8..0000000 --- a/elpa/magit-1.2.1/magit.el +++ /dev/null @@ -1,5989 +0,0 @@ -;;; magit.el --- control Git from Emacs - -;; Copyright (C) 2010 Aaron Culich. -;; Copyright (C) 2010 Alan Falloon. -;; Copyright (C) 2008, 2010 Alex Ott. -;; Copyright (C) 2008, 2009, 2010 Alexey Voinov. -;; Copyright (C) 2010 Ben Walton. -;; Copyright (C) 2010 Chris Bernard. -;; Copyright (C) 2010 Christian Kluge. -;; Copyright (C) 2008 Daniel Farina. -;; Copyright (C) 2010 David Abrahams. -;; Copyright (C) 2009 David Wallin. -;; Copyright (C) 2009, 2010 Hannu Koivisto. -;; Copyright (C) 2009 Ian Eure. -;; Copyright (C) 2009 Jesse Alama. -;; Copyright (C) 2009 John Wiegley. -;; Copyright (C) 2010 Leo. -;; Copyright (C) 2008, 2009 Marcin Bachry. -;; Copyright (C) 2008, 2009 Marius Vollmer. -;; Copyright (C) 2010 Mark Hepburn. -;; Copyright (C) 2010 Moritz Bunkus. -;; Copyright (C) 2010 Nathan Weizenbaum. -;; Copyright (C) 2010 Oscar Fuentes. -;; Copyright (C) 2009 Pavel Holejsovsky. -;; Copyright (C) 2011-2012 Peter J Weisberg -;; Copyright (C) 2009, 2010 Phil Jackson. -;; Copyright (C) 2010 Philip Weaver. -;; Copyright (C) 2010 Ramkumar Ramachandra. -;; Copyright (C) 2010 Remco van 't Veer. -;; Copyright (C) 2009 RenĂ© Stadler. -;; Copyright (C) 2010 Robin Green. -;; Copyright (C) 2010 Roger Crew. -;; Copyright (C) 2009, 2010, 2011 RĂ©mi Vanicat. -;; Copyright (C) 2010 Sean Bryant. -;; Copyright (C) 2009, 2011 Steve Purcell. -;; Copyright (C) 2010 Timo Juhani Lindfors. -;; Copyright (C) 2010, 2011 Yann Hodique. -;; Copyright (C) 2010 Ævar ArnfjörĂ° Bjarmason. -;; Copyright (C) 2010 Ă“scar Fuentes. - -;; Original Author: Marius Vollmer -;; Former Maintainer: Phil Jackson -;; Maintenance Group: https://github.com/organizations/magit/teams/53130 -;; Currently composed of: -;; - Phil Jackson -;; - Peter J Weisberg -;; - Yann Hodique -;; - RĂ©mi Vanicat -;; Version: 1.2.1 -;; Keywords: tools - -;; -;; 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 . - -;;; Commentary: - -;; Invoking the magit-status function will show a buffer with the -;; status of the current git repository and its working tree. That -;; buffer offers key bindings for manipulating the status in simple -;; ways. -;; -;; The status buffer mainly shows the difference between the working -;; tree and the index, and the difference between the index and the -;; current HEAD. You can add individual hunks from the working tree -;; to the index, and you can commit the index. -;; -;; See the Magit User Manual for more information. - -;;; Code: - -(eval-when-compile (require 'cl)) -(require 'log-edit) -(require 'easymenu) -(require 'diff-mode) - -;; Silences byte-compiler warnings -(eval-and-compile - (unless (fboundp 'declare-function) (defmacro declare-function (&rest args)))) - -(eval-when-compile (require 'view)) -(declare-function view-mode 'view) -(eval-when-compile (require 'iswitchb)) -(eval-when-compile (require 'ido)) -(eval-when-compile (require 'ediff)) - -;; Dummy to be used by the defcustoms when first loading the file. -(eval-when (load eval) - (defalias 'magit-set-variable-and-refresh 'set-default)) - -;;; Code: -(defgroup magit nil - "Controlling Git from Emacs." - :prefix "magit-" - :group 'tools) - -(defcustom magit-git-executable "git" - "The name of the Git executable." - :group 'magit - :type 'string) - -(defcustom magit-gitk-executable (concat (file-name-directory magit-git-executable) - "gitk") - "The name of the Gitk executable." - :group 'magit - :type 'string) - -(defcustom magit-git-standard-options '("--no-pager") - "Standard options when running Git." - :group 'magit - :type '(repeat string)) - -(defcustom magit-repo-dirs nil - "Directories containing Git repositories. -Magit will look into these directories for Git repositories and -offer them as choices for `magit-status'." - :group 'magit - :type '(repeat string)) - -(defcustom magit-repo-dirs-depth 3 - "The maximum depth to look for Git repos. -When looking for a Git repository below the directories in `magit-repo-dirs', -Magit will only descend this many levels deep." - :group 'magit - :type 'integer) - -(defcustom magit-set-upstream-on-push nil - "Non-nil means that `magit-push' may use --set-upstream when pushing a branch. -This only applies if the branch does not have an upstream set yet. -Setting this to t will ask if --set-upstream should be used. -Setting it to 'dontask will always use --set-upstream. -Setting it to 'refuse will refuse to push unless a remote branch has already been set. - ---set-upstream is supported with git > 1.7.0" - :group 'magit - :type '(choice (const :tag "Never" nil) - (const :tag "Ask" t) - (const :tag "Refuse" refuse) - (const :tag "Always" dontask))) - -(defcustom magit-save-some-buffers t - "Non-nil means that \\[magit-status] will save modified buffers before running. -Setting this to t will ask which buffers to save, setting it to 'dontask will -save all modified buffers without asking." - :group 'magit - :type '(choice (const :tag "Never" nil) - (const :tag "Ask" t) - (const :tag "Save without asking" dontask))) - -(defcustom magit-save-some-buffers-predicate - 'magit-save-buffers-predicate-tree-only - "A predicate function to decide whether to save a buffer. - -Used by function `magit-save-some-buffers' when the variable of -the same name is non-nil." - - :group 'magit - :type '(radio (function-item magit-save-buffers-predicate-tree-only) - (function-item magit-save-buffers-predicate-all) - (function :tag "Other"))) - -(defcustom magit-default-tracking-name-function - 'magit-default-tracking-name-remote-plus-branch - "Specifies the function to use to generate default tracking branch names -when doing a \\[magit-checkout]. - -The default is magit-default-tracking-name-remote-plus-branch, -which generates a tracking name of the form 'REMOTE-BRANCHNAME'." - :group 'magit - :type '(radio (function-item magit-default-tracking-name-remote-plus-branch) - (function-item magit-default-tracking-name-branch-only) - (function :tag "Other"))) - -(defcustom magit-commit-all-when-nothing-staged 'ask - "Determines what \\[magit-log-edit] does when nothing is staged. -Setting this to nil will make it do nothing, setting it to t will -arrange things so that the actual commit command will use the \"--all\" option, -setting it to 'ask will first ask for confirmation whether to do this, -and setting it to 'ask-stage will cause all changes to be staged, -after a confirmation." - :group 'magit - :type '(choice (const :tag "No" nil) - (const :tag "Always" t) - (const :tag "Ask" ask) - (const :tag "Ask to stage everything" ask-stage))) - -(defcustom magit-commit-signoff nil - "Add the \"Signed-off-by:\" line when committing." - :group 'magit - :type 'boolean) - -(defcustom magit-sha1-abbrev-length 7 - "The number of digits to show when a sha1 is displayed in abbreviated form." - :group 'magit - :type 'integer) - -(defcustom magit-log-cutoff-length 100 - "The maximum number of commits to show in the log and whazzup buffers." - :group 'magit - :type 'integer) - -(defcustom magit-log-infinite-length 99999 - "Number of log used to show as maximum for `magit-log-cutoff-length'." - :group 'magit - :type 'integer) - -(defcustom magit-log-auto-more nil - "Insert more log entries automatically when moving past the last entry. - -Only considered when moving past the last entry with -`magit-goto-*-section' commands." - :group 'magit - :type 'boolean) - -(defcustom magit-process-popup-time -1 - "Popup the process buffer if a command takes longer than this many seconds." - :group 'magit - :type '(choice (const :tag "Never" -1) - (const :tag "Immediately" 0) - (integer :tag "After this many seconds"))) - -(defcustom magit-revert-item-confirm t - "Require acknowledgment before reverting an item." - :group 'magit - :type 'boolean) - -(defcustom magit-log-edit-confirm-cancellation nil - "Require acknowledgment before canceling the log edit buffer." - :group 'magit - :type 'boolean) - -(defcustom magit-remote-ref-format 'branch-then-remote - "What format to use for autocompleting refs, in pariticular for remotes. - -Autocompletion is used by functions like `magit-checkout', -`magit-interactive-rebase' and others which offer branch name -completion. - -The value 'name-then-remote means remotes will be of the -form \"name (remote)\", while the value 'remote-slash-name -means that they'll be of the form \"remote/name\". I.e. something that's -listed as \"remotes/upstream/next\" by \"git branch -l -a\" -will be \"upstream/next\"." - :group 'magit - :type '(choice (const :tag "name (remote)" branch-then-remote) - (const :tag "remote/name" remote-slash-branch))) - -(defcustom magit-process-connection-type (not (eq system-type 'cygwin)) - "Connection type used for the git process. - -If nil, use pipes: this is usually more efficient, and works on Cygwin. -If t, use ptys: this enables magit to prompt for passphrases when needed." - :group 'magit - :type '(choice (const :tag "pipe" nil) - (const :tag "pty" t))) - -(defcustom magit-completing-read-function 'magit-builtin-completing-read - "Function to be called when requesting input from the user." - :group 'magit - :type '(radio (function-item magit-iswitchb-completing-read) - (function-item magit-ido-completing-read) - (function-item magit-builtin-completing-read) - (function :tag "Other"))) - -(defcustom magit-create-branch-behaviour 'at-head - "Where magit will create a new branch if not supplied a branchname or ref. - -The value 'at-head means a new branch will be created at the tip -of your current branch, while the value 'at-point means magit -will try to find a valid reference at point..." - :group 'magit - :type '(choice (const :tag "at HEAD" at-head) - (const :tag "at point" at-point))) - -(defcustom magit-status-buffer-switch-function 'pop-to-buffer - "Function for `magit-status' to use for switching to the status buffer. - -The function is given one argument, the status buffer." - :group 'magit - :type '(radio (function-item switch-to-buffer) - (function-item pop-to-buffer) - (function :tag "Other"))) - -(defcustom magit-rewrite-inclusive t - "Whether magit includes the selected base commit in a rewrite operation. - -t means both the selected commit as well as any subsequent -commits will be rewritten. This is magit's default behaviour, -equivalent to 'git rebase -i ${REV}~1' - - A'---B'---C'---D' - ^ - -nil means the selected commit will be literally used as 'base', -so only subsequent commits will be rewritten. This is consistent -with git-rebase, equivalent to 'git rebase -i ${REV}', yet more -cumbersome to use from the status buffer. - - A---B'---C'---D' - ^" - :group 'magit - :type '(choice (const :tag "Always" t) - (const :tag "Never" nil) - (const :tag "Ask" ask))) - -(defcustom magit-highlight-whitespace t - "Specifies where to highlight whitespace errors. -See `magit-highlight-trailing-whitespace', -`magit-highlight-indentation'. The symbol t means in all diffs, -'status means only in the status buffer, and nil means nowhere." - :group 'magit - :type '(choice (const :tag "Always" t) - (const :tag "Never" nil) - (const :tag "In status buffer" status)) - :set 'magit-set-variable-and-refresh) - -(defcustom magit-highlight-trailing-whitespace t - "Highlight whitespace at the end of a line in diffs. -Used only when `magit-highlight-whitespace' is non-nil." - :group 'magit - :type 'boolean - :set 'magit-set-variable-and-refresh) - -(defcustom magit-highlight-indentation nil - "Highlight the \"wrong\" indentation style. -Used only when `magit-highlight-whitespace' is non-nil. - -The value is a list of cons cells. The car is a regular -expression, and the cdr is the value that applies to repositories -whose directory matches the regular expression. If more than one -item matches, then the *last* item in the list applies. So, the -default value should come first in the list. - -If the value is `tabs', highlight indentation with tabs. If the -value is an integer, highlight indentation with at least that -many spaces. Otherwise, highlight neither." - :group 'magit - :type `(repeat (cons (string :tag "Directory regexp") - (choice (const :tag "Tabs" tabs) - (integer :tag "Spaces" :value ,tab-width) - (const :tag "Neither" nil)))) - :set 'magit-set-variable-and-refresh) - -(defcustom magit-diff-refine-hunk nil - "Show fine (word-granularity) differences within diff hunks. - -There are three possible settings: - - nil means to never show fine differences - - t means to only show fine differences for the currently - selected diff hunk - - `all' means to always show fine differences for all displayed diff hunks" - :group 'magit - :type '(choice (const :tag "Never" nil) - (const :tag "Selected only" t) - (const :tag "All" all)) - :set 'magit-set-variable-and-refresh) - -(defvar magit-current-indentation nil - "Indentation highlight used in the current buffer. -This is calculated from `magit-highlight-indentation'.") -(make-variable-buffer-local 'magit-current-indentation) - -(defgroup magit-faces nil - "Customize the appearance of Magit." - :prefix "magit-" - :group 'faces - :group 'magit) - -(defface magit-header - '((t :inherit header-line)) - "Face for generic header lines. - -Many Magit faces inherit from this one by default." - :group 'magit-faces) - -(defface magit-section-title - '((t :inherit magit-header)) - "Face for section titles." - :group 'magit-faces) - -(defface magit-branch - '((t :inherit magit-header)) - "Face for the current branch." - :group 'magit-faces) - -(defface magit-diff-file-header - '((t :inherit diff-file-header)) - "Face for diff file header lines." - :group 'magit-faces) - -(defface magit-diff-hunk-header - '((t :inherit diff-hunk-header)) - "Face for diff hunk header lines." - :group 'magit-faces) - -(defface magit-diff-add - '((t :inherit diff-added)) - "Face for lines in a diff that have been added." - :group 'magit-faces) - -(defface magit-diff-none - '((t :inherit diff-context)) - "Face for lines in a diff that are unchanged." - :group 'magit-faces) - -(defface magit-diff-del - '((t :inherit diff-removed)) - "Face for lines in a diff that have been deleted." - :group 'magit-faces) - -(defface magit-log-graph - '((((class color) (background light)) - :foreground "grey11") - (((class color) (background dark)) - :foreground "grey80")) - "Face for the graph element of the log output." - :group 'magit-faces) - -(defface magit-log-sha1 - '((((class color) (background light)) - :foreground "firebrick") - (((class color) (background dark)) - :foreground "tomato")) - "Face for the sha1 element of the log output." - :group 'magit-faces) - -(defface magit-log-message - '((t)) - "Face for the message element of the log output." - :group 'magit-faces) - -(defface magit-item-highlight - '((t :inherit highlight)) - "Face for highlighting the current item." - :group 'magit-faces) - -(defface magit-item-mark - '((t :inherit secondary-selection)) - "Face for highlighting marked item." - :group 'magit-faces) - -(defface magit-log-head-label-bisect-good - '((((class color) (background light)) - :box t - :background "light green" - :foreground "dark olive green") - (((class color) (background dark)) - :box t - :background "light green" - :foreground "dark olive green")) - "Face for good bisect refs." - :group 'magit-faces) - -(defface magit-log-head-label-bisect-bad - '((((class color) (background light)) - :box t - :background "IndianRed1" - :foreground "IndianRed4") - (((class color) (background dark)) - :box t - :background "IndianRed1" - :foreground "IndianRed4")) - "Face for bad bisect refs." - :group 'magit-faces) - -(defface magit-log-head-label-remote - '((((class color) (background light)) - :box t - :background "Grey85" - :foreground "OliveDrab4") - (((class color) (background dark)) - :box t - :background "Grey11" - :foreground "DarkSeaGreen2")) - "Face for remote branch head labels shown in log buffer." - :group 'magit-faces) - -(defface magit-log-head-label-tags - '((((class color) (background light)) - :box t - :background "LemonChiffon1" - :foreground "goldenrod4") - (((class color) (background dark)) - :box t - :background "LemonChiffon1" - :foreground "goldenrod4")) - "Face for tag labels shown in log buffer." - :group 'magit-faces) - -(defface magit-log-head-label-patches - '((((class color) (background light)) - :box t - :background "IndianRed1" - :foreground "IndianRed4") - (((class color) (background dark)) - :box t - :background "IndianRed1" - :foreground "IndianRed4")) - "Face for Stacked Git patches." - :group 'magit-faces) - -(defface magit-whitespace-warning-face - '((t :inherit trailing-whitespace)) - "Face for highlighting whitespace errors in Magit diffs." - :group 'magit-faces) - -(defvar magit-custom-options '() - "List of custom options to pass to Git. -Do not customize this (used in the `magit-key-mode' implementation).") - -(defvar magit-read-rev-history nil - "The history of inputs to `magit-read-rev'.") - -(defvar magit-buffer-internal nil - "Track associated *magit* buffers. -Do not customize this (used in the `magit-log-edit-mode' implementation -to switch back to the *magit* buffer associated with a given commit -operation after commit).") - -(defvar magit-back-navigation-history nil - "History items that will be visited by successively going \"back\".") -(make-variable-buffer-local 'magit-back-navigation-history) -(put 'magit-back-navigation-history 'permanent-local t) - -(defvar magit-forward-navigation-history nil - "History items that will be visited by successively going \"forward\".") -(make-variable-buffer-local 'magit-forward-navigation-history) -(put 'magit-forward-navigation-history 'permanent-local t) - -(defvar magit-omit-untracked-dir-contents nil - "When non-nil magit will only list an untracked directory, not its contents.") - -(defvar magit-tmp-buffer-name " *magit-tmp*") - -(defface magit-log-head-label-local - '((((class color) (background light)) - :box t - :background "Grey85" - :foreground "LightSkyBlue4") - (((class color) (background dark)) - :box t - :background "Grey13" - :foreground "LightSkyBlue1")) - "Face for local branch head labels shown in log buffer." - :group 'magit-faces) - -(defface magit-log-head-label-default - '((((class color) (background light)) - :box t - :background "Grey50") - (((class color) (background dark)) - :box t - :background "Grey50")) - "Face for unknown ref labels shown in log buffer." - :group 'magit-faces) - -(defvar magit-mode-map - (let ((map (make-keymap))) - (suppress-keymap map t) - (define-key map (kbd "n") 'magit-goto-next-section) - (define-key map (kbd "p") 'magit-goto-previous-section) - (define-key map (kbd "^") 'magit-goto-parent-section) - (define-key map (kbd "M-n") 'magit-goto-next-sibling-section) - (define-key map (kbd "M-p") 'magit-goto-previous-sibling-section) - (define-key map (kbd "TAB") 'magit-toggle-section) - (define-key map (kbd "") 'magit-expand-collapse-section) - (define-key map (kbd "1") 'magit-show-level-1) - (define-key map (kbd "2") 'magit-show-level-2) - (define-key map (kbd "3") 'magit-show-level-3) - (define-key map (kbd "4") 'magit-show-level-4) - (define-key map (kbd "M-1") 'magit-show-level-1-all) - (define-key map (kbd "M-2") 'magit-show-level-2-all) - (define-key map (kbd "M-3") 'magit-show-level-3-all) - (define-key map (kbd "M-4") 'magit-show-level-4-all) - (define-key map (kbd "M-h") 'magit-show-only-files) - (define-key map (kbd "M-H") 'magit-show-only-files-all) - (define-key map (kbd "M-s") 'magit-show-level-4) - (define-key map (kbd "M-S") 'magit-show-level-4-all) - (define-key map (kbd "g") 'magit-refresh) - (define-key map (kbd "G") 'magit-refresh-all) - (define-key map (kbd "?") 'magit-describe-item) - (define-key map (kbd "!") 'magit-key-mode-popup-running) - (define-key map (kbd ":") 'magit-git-command) - (define-key map (kbd "C-x 4 a") 'magit-add-change-log-entry-other-window) - (define-key map (kbd "L") 'magit-add-change-log-entry-no-option) - (define-key map (kbd "RET") 'magit-visit-item) - (define-key map (kbd "SPC") 'magit-show-item-or-scroll-up) - (define-key map (kbd "DEL") 'magit-show-item-or-scroll-down) - (define-key map (kbd "C-w") 'magit-copy-item-as-kill) - (define-key map (kbd "R") 'magit-rebase-step) - (define-key map (kbd "t") 'magit-key-mode-popup-tagging) - (define-key map (kbd "r") 'magit-key-mode-popup-rewriting) - (define-key map (kbd "P") 'magit-key-mode-popup-pushing) - (define-key map (kbd "f") 'magit-key-mode-popup-fetching) - (define-key map (kbd "b") 'magit-key-mode-popup-branching) - (define-key map (kbd "M") 'magit-key-mode-popup-remoting) - (define-key map (kbd "B") 'magit-key-mode-popup-bisecting) - (define-key map (kbd "F") 'magit-key-mode-popup-pulling) - (define-key map (kbd "l") 'magit-key-mode-popup-logging) - (define-key map (kbd "$") 'magit-display-process) - (define-key map (kbd "c") 'magit-log-edit) - (define-key map (kbd "E") 'magit-interactive-rebase) - (define-key map (kbd "e") 'magit-ediff) - (define-key map (kbd "w") 'magit-wazzup) - (define-key map (kbd "q") 'magit-quit-window) - (define-key map (kbd "m") 'magit-key-mode-popup-merging) - (define-key map (kbd "x") 'magit-reset-head) - (define-key map (kbd "v") 'magit-revert-item) - (define-key map (kbd "a") 'magit-apply-item) - (define-key map (kbd "A") 'magit-cherry-pick-item) - (define-key map (kbd "d") 'magit-diff-working-tree) - (define-key map (kbd "D") 'magit-diff) - (define-key map (kbd "-") 'magit-diff-smaller-hunks) - (define-key map (kbd "+") 'magit-diff-larger-hunks) - (define-key map (kbd "0") 'magit-diff-default-hunks) - (define-key map (kbd "h") 'magit-toggle-diff-refine-hunk) - map)) - -(defvar magit-commit-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "C-c C-b") 'magit-show-commit-backward) - (define-key map (kbd "C-c C-f") 'magit-show-commit-forward) - map)) - -(defvar magit-status-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "s") 'magit-stage-item) - (define-key map (kbd "S") 'magit-stage-all) - (define-key map (kbd "u") 'magit-unstage-item) - (define-key map (kbd "U") 'magit-unstage-all) - (define-key map (kbd "i") 'magit-ignore-item) - (define-key map (kbd "I") 'magit-ignore-item-locally) - (define-key map (kbd ".") 'magit-mark-item) - (define-key map (kbd "=") 'magit-diff-with-mark) - (define-key map (kbd "k") 'magit-discard-item) - (define-key map (kbd "C") 'magit-add-log) - (define-key map (kbd "X") 'magit-reset-working-tree) - (define-key map (kbd "z") 'magit-key-mode-popup-stashing) - map)) - -(eval-after-load 'dired-x - '(define-key magit-status-mode-map [remap dired-jump] 'magit-dired-jump)) - -(defvar magit-log-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd ".") 'magit-mark-item) - (define-key map (kbd "=") 'magit-diff-with-mark) - (define-key map (kbd "e") 'magit-log-show-more-entries) - map)) - -(defvar magit-wazzup-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd ".") 'magit-mark-item) - (define-key map (kbd "=") 'magit-diff-with-mark) - (define-key map (kbd "i") 'magit-ignore-item) - map)) - -(defvar magit-branch-manager-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "c") 'magit-create-branch) - (define-key map (kbd "a") 'magit-add-remote) - (define-key map (kbd "r") 'magit-move-item) - (define-key map (kbd "k") 'magit-discard-item) - (define-key map (kbd "T") 'magit-change-what-branch-tracks) - map)) - -(defvar magit-bug-report-url - "http://github.com/magit/magit/issues") - -(defconst magit-version "1.2.1" - "The version of Magit that you're using.") - -(defun magit-bug-report (str) - "Asks the user to submit a bug report about the error described in STR." -;; XXX - should propose more information to be included. - (message (concat - "Unknown error: %s\n" - "Please, with as much information as possible, file a bug at\n" - "%s\n" - "You are using Magit version %s.") - str magit-bug-report-url magit-version)) - -(defun magit-buffer-switch (buf) - (if (string-match "magit" (buffer-name)) - (switch-to-buffer buf) - (pop-to-buffer buf))) - -;;; Macros - -(defmacro magit-with-refresh (&rest body) - (declare (indent 0)) - `(magit-refresh-wrapper (lambda () ,@body))) - -;;; Git features - -(defvar magit-have-graph 'unset) -(defvar magit-have-decorate 'unset) -(defvar magit-have-abbrev 'unset) -(make-variable-buffer-local 'magit-have-graph) -(put 'magit-have-graph 'permanent-local t) -(make-variable-buffer-local 'magit-have-decorate) -(put 'magit-have-decorate 'permanent-local t) -(make-variable-buffer-local 'magit-have-abbrev) -(put 'magit-have-abbrev 'permanent-local t) - -(defun magit-configure-have-graph () - (if (eq magit-have-graph 'unset) - (let ((res (magit-git-exit-code "log" "--graph" "--max-count=0"))) - (setq magit-have-graph (eq res 0))))) - -(defun magit-configure-have-decorate () - (if (eq magit-have-decorate 'unset) - (let ((res (magit-git-exit-code "log" "--decorate=full" "--max-count=0"))) - (setq magit-have-decorate (eq res 0))))) - -(defun magit-configure-have-abbrev () - (if (eq magit-have-abbrev 'unset) - (let ((res (magit-git-exit-code "log" "--no-abbrev-commit" "--max-count=0"))) - (setq magit-have-abbrev (eq res 0))))) - -;;; Compatibilities - -(eval-and-compile - (if (functionp 'start-file-process) - (defalias 'magit-start-process 'start-file-process) - (defalias 'magit-start-process 'start-process)) - - (unless (fboundp 'string-match-p) - (defun string-match-p (regexp string &optional start) - "Same as `string-match' except this function does not -change the match data." - (let ((inhibit-changing-match-data t)) - (string-match regexp string start)))) - - (if (fboundp 'with-silent-modifications) - (defalias 'magit-with-silent-modifications 'with-silent-modifications) - (defmacro magit-with-silent-modifications (&rest body) - "Execute body without changing `buffer-modified-p'. Also, do not -record undo information." - `(set-buffer-modified-p - (prog1 (buffer-modified-p) - (let ((buffer-undo-list t) - before-change-functions - after-change-functions) - ,@body))))) - ) - -;; RECURSIVE has been introduced with Emacs 23.2, XEmacs still lacks it. -;; This is copied and adapted from `tramp-compat-delete-directory' -(defun magit-delete-directory (directory &optional recursive) - "Compatibility function for `delete-directory'." - (if (null recursive) - (delete-directory directory) - (condition-case nil - (funcall 'delete-directory directory recursive) - (wrong-number-of-arguments - ;; This Emacs version does not support the RECURSIVE flag. - ;; We use the implementation from Emacs 23.2. - (setq directory (directory-file-name (expand-file-name directory))) - (if (not (file-symlink-p directory)) - (mapc (lambda (file) - (if (eq t (car (file-attributes file))) - (org-delete-directory file recursive) - (delete-file file))) - (directory-files - directory 'full "^\\([^.]\\|\\.\\([^.]\\|\\..\\)\\).*"))) - (delete-directory directory))))) - -;;; Utilities - -(defun magit-set-variable-and-refresh (symbol value) - "Set SYMBOL to VALUE and call `magit-refresh-all'" - (set-default symbol value) - (magit-refresh-all)) - -(defun magit-iswitchb-completing-read (prompt choices &optional predicate require-match - initial-input hist def) - "iswitchb-based completing-read almost-replacement." - (require 'iswitchb) - (let ((iswitchb-make-buflist-hook - (lambda () - (setq iswitchb-temp-buflist (if (consp (first choices)) - (mapcar #'car choices) - choices))))) - (iswitchb-read-buffer prompt (or initial-input def) require-match))) - -(defun magit-ido-completing-read (prompt choices &optional predicate require-match initial-input hist def) - "ido-based completing-read almost-replacement." - (require 'ido) - (let ((selected (ido-completing-read prompt (if (consp (first choices)) - (mapcar #'car choices) - choices) - predicate require-match initial-input hist def))) - (if (consp (first choices)) - (or (cdr (assoc selected choices)) - selected) - selected))) - -(defun magit-builtin-completing-read (prompt choices &optional predicate require-match - initial-input hist def) - "Magit wrapper for standard `completing-read' function." - (completing-read (if (and def (> (length prompt) 2) - (string-equal ": " (substring prompt -2))) - (format "%s (default %s): " (substring prompt 0 -2) def) - prompt) - choices predicate require-match initial-input hist def)) - -(defun magit-completing-read (prompt choices &optional predicate require-match - initial-input hist def) - (funcall magit-completing-read-function prompt choices predicate require-match - initial-input hist def)) - -(defun magit-use-region-p () - (if (fboundp 'use-region-p) - (use-region-p) - (and transient-mark-mode mark-active))) - -(defun magit-goto-line (line) - "Like `goto-line' but doesn't set the mark." - (save-restriction - (widen) - (goto-char 1) - (forward-line (1- line)))) - -(defun magit-trim-line (str) - (if (string= str "") - nil - (if (equal (elt str (- (length str) 1)) ?\n) - (substring str 0 (- (length str) 1)) - str))) - -(defun magit-split-lines (str) - (if (string= str "") - nil - (let ((lines (nreverse (split-string str "\n")))) - (if (string= (car lines) "") - (setq lines (cdr lines))) - (nreverse lines)))) - -(defun magit-git-insert (args) - (insert (magit-git-output args))) - -(defun magit-git-output (args) - (magit-cmd-output magit-git-executable (append magit-git-standard-options args))) - -(defun magit-cmd-insert (cmd args) - (insert (magit-cmd-output cmd args))) - -(defun magit-cmd-output (cmd args) - (let ((cmd-output (with-output-to-string - (with-current-buffer standard-output - (apply #'process-file - cmd - nil (list t nil) nil - args))))) - (replace-regexp-in-string "\e\\[.*?m" "" cmd-output))) - -(defun magit-git-string (&rest args) - (magit-trim-line (magit-git-output args))) - -(defun magit-git-lines (&rest args) - (magit-split-lines (magit-git-output args))) - -(defun magit-git-exit-code (&rest args) - (apply #'process-file magit-git-executable nil nil nil - (append magit-git-standard-options args))) - -(defun magit-file-lines (file) - (when (file-exists-p file) - (with-temp-buffer - (insert-file-contents file) - (let ((rev (nreverse (split-string (buffer-string) "\n")))) - (nreverse (if (equal (car rev) "") - (cdr rev) - rev)))))) - -(defun magit-write-file-lines (file lines) - (with-temp-buffer - (dolist (l lines) - (insert l "\n")) - (write-file file))) - -(defun magit-get (&rest keys) - "Return the value of Git config entry specified by KEYS." - (magit-git-string "config" (mapconcat 'identity keys "."))) - -(defun magit-get-all (&rest keys) - "Return all values of the Git config entry specified by KEYS." - (magit-git-lines "config" "--get-all" (mapconcat 'identity keys "."))) - -(defun magit-get-boolean (&rest keys) - "Return the boolean value of Git config entry specified by KEYS." - (equal (magit-git-string "config" "--bool" (mapconcat 'identity keys ".")) - "true")) - -(defun magit-set (val &rest keys) - "Set Git config settings specified by KEYS to VAL." - (if val - (magit-git-string "config" (mapconcat 'identity keys ".") val) - (magit-git-string "config" "--unset" (mapconcat 'identity keys ".")))) - -(defun magit-remove-conflicts (alist) - (let ((dict (make-hash-table :test 'equal)) - (result nil)) - (dolist (a alist) - (puthash (car a) (cons (cdr a) (gethash (car a) dict)) - dict)) - (maphash (lambda (key value) - (if (= (length value) 1) - (push (cons key (car value)) result) - (let ((sub (magit-remove-conflicts - (mapcar (lambda (entry) - (let ((dir (directory-file-name - (substring entry 0 (- (length key)))))) - (cons (concat (file-name-nondirectory dir) "/" key) - entry))) - value)))) - (setq result (append result sub))))) - dict) - result)) - -(defun magit-git-repo-p (dir) - (file-exists-p (expand-file-name ".git" dir))) - -(defun magit-git-dir () - "Returns the .git directory for the current repository." - (concat (expand-file-name (magit-git-string "rev-parse" "--git-dir")) "/")) - -(defun magit-no-commit-p () - "Return non-nil if there is no commit in the current git repository." - (not (magit-git-string - "rev-list" "HEAD" "--max-count=1"))) - -(defun magit-list-repos* (dir level) - (if (magit-git-repo-p dir) - (list dir) - (apply #'append - (mapcar (lambda (entry) - (unless (or (string= (substring entry -3) "/..") - (string= (substring entry -2) "/.")) - (magit-list-repos* entry (+ level 1)))) - (and (file-directory-p dir) - (< level magit-repo-dirs-depth) - (directory-files dir t nil t)))))) - -(defun magit-list-repos (dirs) - (magit-remove-conflicts - (apply #'append - (mapcar (lambda (dir) - (mapcar #'(lambda (repo) - (cons (file-name-nondirectory repo) - repo)) - (magit-list-repos* dir 0))) - dirs)))) - -(defun magit-get-top-dir (cwd) - (let ((cwd (expand-file-name (file-truename cwd)))) - (when (file-directory-p cwd) - (let* ((default-directory (file-name-as-directory cwd)) - (cdup (magit-git-string "rev-parse" "--show-cdup"))) - (when cdup - (file-name-as-directory (expand-file-name cdup cwd))))))) - -(defun magit-get-ref (ref) - (magit-git-string "symbolic-ref" "-q" ref)) - -(defun magit-get-current-branch () - (let* ((head (magit-get-ref "HEAD")) - (pos (and head (string-match "^refs/heads/" head)))) - (if pos - (substring head 11) - nil))) - -(defun magit-get-remote (branch) - "Return the name of the remote for BRANCH. -If branch is nil or it has no remote, but a remote named -\"origin\" exists, return that. Otherwise, return nil." - (let ((remote (or (and branch (magit-get "branch" branch "remote")) - (and (magit-get "remote" "origin" "url") "origin")))) - (if (string= remote "") nil remote))) - -(defun magit-get-current-remote () - "Return the name of the remote for the current branch. -If there is no current branch, or no remote for that branch, -but a remote named \"origin\" is configured, return that. -Otherwise, return nil." - (magit-get-remote (magit-get-current-branch))) - -(defun magit-ref-exists-p (ref) - (= (magit-git-exit-code "show-ref" "--verify" ref) 0)) - -(defun magit-read-top-dir (dir) - "Ask the user for a Git repository. The choices offered by -auto-completion will be the repositories under `magit-repo-dirs'. -If `magit-repo-dirs' is nil or DIR is non-nill, then -autocompletion will offer directory names." - (if (and (not dir) magit-repo-dirs) - (let* ((repos (magit-list-repos magit-repo-dirs)) - (reply (magit-completing-read "Git repository: " repos))) - (file-name-as-directory - (or (cdr (assoc reply repos)) - (if (file-directory-p reply) - (expand-file-name reply) - (error "Not a repository or a directory: %s" reply))))) - (file-name-as-directory - (read-directory-name "Git repository: " - (or (magit-get-top-dir default-directory) - default-directory))))) - -(defun magit-rev-parse (ref) - "Return the SHA hash for REF." - (magit-git-string "rev-parse" ref)) - -(defun magit-ref-ambiguous-p (ref) - "Return whether or not REF is ambiguous." - ;; If REF is ambiguous, rev-parse just prints errors, - ;; so magit-git-string returns nil. - (not (magit-git-string "rev-parse" "--abbrev-ref" ref))) - -(defun magit-name-rev (rev &optional no-trim) - "Return a human-readable name for REV. -Unlike git name-rev, this will remove tags/ and remotes/ prefixes -if that can be done unambiguously (unless optional arg NO-TRIM is -non-nil). In addition, it will filter out revs involving HEAD." - (when rev - (let ((name (magit-git-string "name-rev" "--no-undefined" "--name-only" rev))) - ;; There doesn't seem to be a way of filtering HEAD out from name-rev, - ;; so we have to do it manually. - ;; HEAD-based names are too transient to allow. - (when (and (stringp name) - (string-match "^\\(.*\\" name)) - (setq name (magit-rev-parse rev))))) - (setq rev (or name rev)) - (when (string-match "^\\(?:tags\\|remotes\\)/\\(.*\\)" rev) - (let ((plain-name (match-string 1 rev))) - (unless (or no-trim (magit-ref-ambiguous-p plain-name)) - (setq rev plain-name)))) - rev))) - -(defun magit-highlight-line-whitespace () - (when (and magit-highlight-whitespace - (or (derived-mode-p 'magit-status-mode) - (not (eq magit-highlight-whitespace 'status)))) - (if (and magit-highlight-trailing-whitespace - (looking-at "^[-+].*?\\([ \t]+\\)$")) - (overlay-put (make-overlay (match-beginning 1) (match-end 1)) - 'face 'magit-whitespace-warning-face)) - (if (or (and (eq magit-current-indentation 'tabs) - (looking-at "^[-+]\\( *\t[ \t]*\\)")) - (and (integerp magit-current-indentation) - (looking-at (format "^[-+]\\([ \t]* \\{%s,\\}[ \t]*\\)" - magit-current-indentation)))) - (overlay-put (make-overlay (match-beginning 1) (match-end 1)) - 'face 'magit-whitespace-warning-face)))) - -(defun magit-put-line-property (prop val) - (put-text-property (line-beginning-position) (line-beginning-position 2) - prop val)) - -(defun magit-format-commit (commit format) - (magit-git-string "log" "--max-count=1" - (concat "--pretty=format:" format) - commit)) - -(defun magit-current-line () - (buffer-substring-no-properties (line-beginning-position) - (line-end-position))) - -(defun magit-insert-region (beg end buf) - (let ((text (buffer-substring-no-properties beg end))) - (with-current-buffer buf - (insert text)))) - -(defun magit-insert-current-line (buf) - (let ((text (buffer-substring-no-properties - (line-beginning-position) (line-beginning-position 2)))) - (with-current-buffer buf - (insert text)))) - -(defun magit-file-uptodate-p (file) - (eq (magit-git-exit-code "diff" "--quiet" "--" file) 0)) - -(defun magit-anything-staged-p () - (not (eq (magit-git-exit-code "diff" "--quiet" "--cached") 0))) - -(defun magit-everything-clean-p () - (and (not (magit-anything-staged-p)) - (eq (magit-git-exit-code "diff" "--quiet") 0))) - -(defun magit-commit-parents (commit) - (cdr (split-string (magit-git-string "rev-list" "-1" "--parents" commit)))) - -;; XXX - let the user choose the parent - -(defun magit-choose-parent-id (commit op) - (let* ((parents (magit-commit-parents commit))) - (if (> (length parents) 1) - (error "Can't %s merge commits" op) - nil))) - -;;; Revisions and ranges - -(defvar magit-current-range nil - "The range described by the current buffer. -This is only non-nil in diff and log buffers. - -This has three possible (non-nil) forms. If it's a string REF or -a singleton list (REF), then the range is from REF to the current -working directory state (or HEAD in a log buffer). If it's a -pair (START . END), then the range is START..END.") -(make-variable-buffer-local 'magit-current-range) - -(defun magit-list-interesting-refs (&optional uninteresting) - "Return interesting references as given by `git show-ref'. -Removes references matching UNINTERESTING from the -results. UNINTERESTING can be either a function taking a single -argument or a list of strings used as regexps." - (let ((refs ())) - (dolist (line (magit-git-lines "show-ref")) - (if (string-match "[^ ]+ +\\(.*\\)" line) - (let ((ref (match-string 1 line))) - (cond ((and (functionp uninteresting) - (funcall uninteresting ref))) - ((and (not (functionp uninteresting)) - (loop for i in uninteresting thereis (string-match i ref)))) - (t - (let ((fmt-ref (magit-format-ref ref))) - (when fmt-ref - (push (cons fmt-ref - (replace-regexp-in-string "^refs/heads/" - "" ref)) - refs)))))))) - (nreverse refs))) - -(defun magit-format-ref (ref) - "Convert fully-specified ref REF into its displayable form -according to `magit-remote-ref-format'" - (cond - ((null ref) - nil) - ((string-match "refs/heads/\\(.*\\)" ref) - (match-string 1 ref)) - ((string-match "refs/tags/\\(.*\\)" ref) - (format (if (eq magit-remote-ref-format 'branch-then-remote) - "%s (tag)" - "%s") - (match-string 1 ref))) - ((string-match "refs/remotes/\\([^/]+\\)/\\(.+\\)" ref) - (if (eq magit-remote-ref-format 'branch-then-remote) - (format "%s (%s)" - (match-string 2 ref) - (match-string 1 ref)) - (format "%s/%s" - (match-string 1 ref) - (match-string 2 ref)))))) - -(defun magit-tree-contents (treeish) - "Returns a list of all files under TREEISH. TREEISH can be a tree, -a commit, or any reference to one of those." - (let ((return-value nil)) - (with-temp-buffer - (magit-git-insert (list "ls-tree" "-r" treeish)) - (if (eql 0 (buffer-size)) - (error "%s is not a commit or tree." treeish)) - (goto-char (point-min)) - (while (search-forward-regexp "\t\\(.*\\)" nil 'noerror) - (push (match-string 1) return-value))) - return-value)) - -(defvar magit-uninteresting-refs '("refs/remotes/\\([^/]+\\)/HEAD$" "refs/stash")) - -(defun magit-read-file-from-rev (revision) - (magit-completing-read (format "Retrieve file from %s: " revision) - (magit-tree-contents revision) - nil - 'require-match - nil - 'magit-read-file-hist - (if buffer-file-name - (let ((topdir-length (length (magit-get-top-dir default-directory)))) - (substring (buffer-file-name) topdir-length))))) - -(defun magit-read-rev (prompt &optional default uninteresting) - (let* ((interesting-refs (magit-list-interesting-refs - (or uninteresting magit-uninteresting-refs))) - (reply (magit-completing-read (concat prompt ": ") interesting-refs - nil nil nil 'magit-read-rev-history default)) - (rev (or (cdr (assoc reply interesting-refs)) reply))) - (if (string= rev "") - nil - rev))) - -(defun magit-read-rev-range (op &optional def-beg def-end) - (let ((beg (magit-read-rev (format "%s start" op) - def-beg))) - (if (not beg) - nil - (save-match-data - (if (string-match "^\\(.+\\)\\.\\.\\(.+\\)$" beg) - (cons (match-string 1 beg) (match-string 2 beg)) - (let ((end (magit-read-rev (format "%s end" op) def-end))) - (cons beg end))))))) - -(defun magit-rev-to-git (rev) - (or rev - (error "No revision specified")) - (if (string= rev ".") - (magit-marked-commit) - rev)) - -(defun magit-rev-range-to-git (range) - (or range - (error "No revision range specified")) - (if (stringp range) - range - (if (cdr range) - (format "%s..%s" - (magit-rev-to-git (car range)) - (magit-rev-to-git (cdr range))) - (format "%s" (magit-rev-to-git (car range)))))) - -(defun magit-rev-describe (rev) - (or rev - (error "No revision specified")) - (if (string= rev ".") - "mark" - (magit-name-rev rev))) - -(defun magit-rev-range-describe (range things) - (or range - (error "No revision range specified")) - (if (stringp range) - (format "%s in %s" things range) - (if (cdr range) - (format "%s from %s to %s" things - (magit-rev-describe (car range)) - (magit-rev-describe (cdr range))) - (format "%s at %s" things (magit-rev-describe (car range)))))) - -(defun magit-default-rev (&optional no-trim) - (or (magit-name-rev (magit-commit-at-point t) no-trim) - (let ((branch (magit-guess-branch))) - (if branch - (if (string-match "^refs/\\(.*\\)" branch) - (match-string 1 branch) - branch))))) - -(defun magit-read-remote (&optional prompt def) - "Read the name of a remote. -PROMPT is used as the prompt, and defaults to \"Remote\". -DEF is the default value." - (let* ((prompt (or prompt "Remote")) - (def (or def (magit-guess-remote))) - (remotes (magit-git-lines "remote")) - - (reply (magit-completing-read (concat prompt ": ") remotes - nil nil nil nil def))) - (if (string= reply "") nil reply))) - -(defun magit-read-remote-branch (remote &optional prompt default) - (let* ((prompt (or prompt (format "Remote branch (in %s)" remote))) - (branches (delete nil - (mapcar - (lambda (b) - (and (not (string-match " -> " b)) - (string-match (format "^ *%s/\\(.*\\)$" - (regexp-quote remote)) b) - (match-string 1 b))) - (magit-git-lines "branch" "-r")))) - (reply (magit-completing-read (concat prompt ": ") branches - nil nil nil nil default))) - (if (string= reply "") nil reply))) - -;;; Sections - -;; A buffer in magit-mode is organized into hierarchical sections. -;; These sections are used for navigation and for hiding parts of the -;; buffer. -;; -;; Most sections also represent the objects that Magit works with, -;; such as files, diffs, hunks, commits, etc. The 'type' of a section -;; identifies what kind of object it represents (if any), and the -;; parent and grand-parent, etc provide the context. - -(defstruct magit-section - parent title beginning end children hidden type info - needs-refresh-on-show) - -(defvar magit-top-section nil - "The top section of the current buffer.") -(make-variable-buffer-local 'magit-top-section) -(put 'magit-top-section 'permanent-local t) - -(defvar magit-old-top-section nil) - -(defvar magit-section-hidden-default nil) - -(defun magit-new-section (title type) - "Create a new section with title TITLE and type TYPE in current buffer. - -If not `magit-top-section' exist, the new section will be the new top-section -otherwise, the new-section will be a child of the current top-section. - -If TYPE is nil, the section won't be highlighted." - (let* ((s (make-magit-section :parent magit-top-section - :title title - :type type - :hidden magit-section-hidden-default)) - (old (and magit-old-top-section - (magit-find-section (magit-section-path s) - magit-old-top-section)))) - (if magit-top-section - (push s (magit-section-children magit-top-section)) - (setq magit-top-section s)) - (if old - (setf (magit-section-hidden s) (magit-section-hidden old))) - s)) - -(defun magit-cancel-section (section) - "Delete the section SECTION." - (delete-region (magit-section-beginning section) - (magit-section-end section)) - (let ((parent (magit-section-parent section))) - (if parent - (setf (magit-section-children parent) - (delq section (magit-section-children parent))) - (setq magit-top-section nil)))) - -(defmacro magit-with-section (title type &rest body) - "Create a new section of title TITLE and type TYPE and evaluate BODY there. - -Sections created inside BODY will become children of the new -section. BODY must leave point at the end of the created section. - -If TYPE is nil, the section won't be highlighted." - (declare (indent 2)) - (let ((s (make-symbol "*section*"))) - `(let* ((,s (magit-new-section ,title ,type)) - (magit-top-section ,s)) - (setf (magit-section-beginning ,s) (point)) - ,@body - (setf (magit-section-end ,s) (point)) - (setf (magit-section-children ,s) - (nreverse (magit-section-children ,s))) - ,s))) - -(defun magit-set-section (title type start end) - "Create a new section of title TITLE and type TYPE with specified start and -end positions." - (let ((section (magit-new-section title type))) - (setf (magit-section-beginning section) start) - (setf (magit-section-end section) end) - section)) - -(defun magit-set-section-info (info &optional section) - (setf (magit-section-info (or section magit-top-section)) info)) - -(defun magit-set-section-needs-refresh-on-show (flag &optional section) - (setf (magit-section-needs-refresh-on-show - (or section magit-top-section)) - flag)) - -(defmacro magit-create-buffer-sections (&rest body) - "Empty current buffer of text and Magit's sections, and then evaluate BODY." - (declare (indent 0)) - `(let ((inhibit-read-only t)) - (erase-buffer) - (let ((magit-old-top-section magit-top-section)) - (setq magit-top-section nil) - ,@body - (when (null magit-top-section) - (magit-with-section 'top nil - (insert "(empty)\n"))) - (magit-propertize-section magit-top-section) - (magit-section-set-hidden magit-top-section - (magit-section-hidden magit-top-section))))) - -(defun magit-propertize-section (section) - "Add text-property needed for SECTION." - (put-text-property (magit-section-beginning section) - (magit-section-end section) - 'magit-section section) - (dolist (s (magit-section-children section)) - (magit-propertize-section s))) - -(defun magit-find-section (path top) - "Find the section at the path PATH in subsection of section TOP." - (if (null path) - top - (let ((secs (magit-section-children top))) - (while (and secs (not (equal (car path) - (magit-section-title (car secs))))) - (setq secs (cdr secs))) - (and (car secs) - (magit-find-section (cdr path) (car secs)))))) - -(defun magit-section-path (section) - "Return the path of SECTION." - (if (not (magit-section-parent section)) - '() - (append (magit-section-path (magit-section-parent section)) - (list (magit-section-title section))))) - -(defun magit-find-section-after (pos) - "Find the first section that begins after POS." - (magit-find-section-after* pos (list magit-top-section))) - -(defun magit-find-section-after* (pos secs) - "Find the first section that begins after POS in the list SECS -\(including children of sections in SECS)." - (while (and secs - (<= (magit-section-beginning (car secs)) pos)) - (setq secs (if (magit-section-hidden (car secs)) - (cdr secs) - (append (magit-section-children (car secs)) - (cdr secs))))) - (car secs)) - -(defun magit-find-section-before (pos) - "Return the last section that begins before POS." - (let ((section (magit-find-section-at pos))) - (do* ((current (or (magit-section-parent section) - section) - next) - (next (if (not (magit-section-hidden current)) - (magit-find-section-before* pos (magit-section-children current))) - (if (not (magit-section-hidden current)) - (magit-find-section-before* pos (magit-section-children current))))) - ((null next) current)))) - -(defun magit-find-section-before* (pos secs) - "Find the last section that begins before POS in the list SECS." - (let ((prev nil)) - (while (and secs - (< (magit-section-beginning (car secs)) pos)) - (setq prev (car secs)) - (setq secs (cdr secs))) - prev)) - -(defun magit-current-section () - "Return the Magit section at point." - (magit-find-section-at (point))) - -(defun magit-find-section-at (pos) - "Return the Magit section at POS." - (or (get-text-property pos 'magit-section) - magit-top-section)) - -(defun magit-insert-section (section-title-and-type - buffer-title washer cmd &rest args) - "Run CMD and put its result in a new section. - -SECTION-TITLE-AND-TYPE is either a string that is the title of the section -or (TITLE . TYPE) where TITLE is the title of the section and TYPE is its type. - -If there is no type, or if type is nil, the section won't be highlighted. - -BUFFER-TITLE is the inserted title of the section - -WASHER is a function that will be run after CMD. -The buffer will be narrowed to the inserted text. -It should add sectioning as needed for Magit interaction. - -CMD is an external command that will be run with ARGS as arguments." - (let* ((body-beg nil) - (section-title (if (consp section-title-and-type) - (car section-title-and-type) - section-title-and-type)) - (section-type (if (consp section-title-and-type) - (cdr section-title-and-type) - nil)) - (section - (magit-with-section section-title section-type - (if buffer-title - (insert (propertize buffer-title 'face 'magit-section-title) - "\n")) - (setq body-beg (point)) - (magit-cmd-insert cmd args) - (if (not (eq (char-before) ?\n)) - (insert "\n")) - (if washer - (save-restriction - (narrow-to-region body-beg (point)) - (goto-char (point-min)) - (funcall washer) - (goto-char (point-max))))))) - (if (= body-beg (point)) - (magit-cancel-section section) - (insert "\n")) - section)) - -(defun magit-git-section (section-title-and-type - buffer-title washer &rest args) - "Run git and put its result in a new section. - -see `magit-insert-section' for meaning of the arguments" - (apply #'magit-insert-section - section-title-and-type - buffer-title - washer - magit-git-executable - (append magit-git-standard-options args))) - -(defun magit-goto-next-section () - "Go to the next section." - (interactive) - (let ((next (magit-find-section-after (point)))) - (if next - (magit-goto-section next) - (message "No next section")))) - -(defun magit-goto-previous-section () - "Go to the previous section." - (interactive) - (if (eq (point) 1) - (message "No previous section") - (magit-goto-section (magit-find-section-before (point))))) - -(defun magit-goto-parent-section () - "Go to the parent section." - (interactive) - (let ((parent (magit-section-parent (magit-current-section)))) - (when parent - (goto-char (magit-section-beginning parent))))) - -(defun magit-goto-next-sibling-section () - "Go to the next sibling section." - (interactive) - (let* ((initial (point)) - (section (magit-current-section)) - (end (- (magit-section-end section) 1)) - (parent (magit-section-parent section)) - (siblings (magit-section-children parent)) - (next-sibling (magit-find-section-after* end siblings))) - (if next-sibling - (magit-goto-section next-sibling) - (magit-goto-next-section)))) - -(defun magit-goto-previous-sibling-section () - "Go to the previous sibling section." - (interactive) - (let* ((section (magit-current-section)) - (beginning (magit-section-beginning section)) - (parent (magit-section-parent section)) - (siblings (magit-section-children parent)) - (previous-sibling (magit-find-section-before* beginning siblings))) - (if previous-sibling - (magit-goto-section previous-sibling) - (magit-goto-parent-section)))) - -(defun magit-goto-section (section) - (goto-char (magit-section-beginning section)) - (cond - ((and magit-log-auto-more - (eq (magit-section-type section) 'longer)) - (magit-log-show-more-entries) - (forward-line -1) - (magit-goto-next-section)) - ((and (eq (magit-section-type section) 'commit) - (derived-mode-p 'magit-log-mode)) - (magit-show-commit section)))) - -(defun magit-goto-section-at-path (path) - "Go to the section described by PATH." - (let ((sec (magit-find-section path magit-top-section))) - (if sec - (goto-char (magit-section-beginning sec)) - (message "No such section")))) - -(defun magit-for-all-sections (func &optional top) - "Run FUNC on TOP and recursively on all its children. - -Default value for TOP is `magit-top-section'" - (let ((section (or top magit-top-section))) - (when section - (funcall func section) - (dolist (c (magit-section-children section)) - (magit-for-all-sections func c))))) - -(defun magit-section-set-hidden (section hidden) - "Hide SECTION if HIDDEN is not nil, show it otherwise." - (setf (magit-section-hidden section) hidden) - (if (and (not hidden) - (magit-section-needs-refresh-on-show section)) - (magit-refresh) - (let ((inhibit-read-only t) - (beg (save-excursion - (goto-char (magit-section-beginning section)) - (forward-line) - (point))) - (end (magit-section-end section))) - (if (< beg end) - (put-text-property beg end 'invisible hidden))) - (if (not hidden) - (dolist (c (magit-section-children section)) - (magit-section-set-hidden c (magit-section-hidden c)))))) - -(defun magit-section-any-hidden (section) - "Return true if SECTION or any of its children is hidden." - (or (magit-section-hidden section) - (let ((kids (magit-section-children section))) - (while (and kids (not (magit-section-any-hidden (car kids)))) - (setq kids (cdr kids))) - kids))) - -(defun magit-section-collapse (section) - "Show SECTION and hide all its children." - (dolist (c (magit-section-children section)) - (setf (magit-section-hidden c) t)) - (magit-section-set-hidden section nil)) - -(defun magit-section-expand (section) - "Show SECTION and all its children." - (dolist (c (magit-section-children section)) - (setf (magit-section-hidden c) nil)) - (magit-section-set-hidden section nil)) - -(defun magit-section-expand-all-aux (section) - "Show recursively all SECTION's children." - (dolist (c (magit-section-children section)) - (setf (magit-section-hidden c) nil) - (magit-section-expand-all-aux c))) - -(defun magit-section-expand-all (section) - "Show SECTION and all its children." - (magit-section-expand-all-aux section) - (magit-section-set-hidden section nil)) - -(defun magit-section-hideshow (flag-or-func) - "Show or hide current section depending on FLAG-OR-FUNC. - -If FLAG-OR-FUNC is a function, it will be ran on current section -IF FLAG-OR-FUNC is a Boolean value, the section will be hidden if its true, shown otherwise" - (let ((section (magit-current-section))) - (when (magit-section-parent section) - (goto-char (magit-section-beginning section)) - (if (functionp flag-or-func) - (funcall flag-or-func section) - (magit-section-set-hidden section flag-or-func))))) - -(defun magit-show-section () - "Show current section." - (interactive) - (magit-section-hideshow nil)) - -(defun magit-hide-section () - "Hide current section." - (interactive) - (magit-section-hideshow t)) - -(defun magit-collapse-section () - "Hide all subsection of current section." - (interactive) - (magit-section-hideshow #'magit-section-collapse)) - -(defun magit-expand-section () - "Show all subsection of current section." - (interactive) - (magit-section-hideshow #'magit-section-expand)) - -(defun magit-toggle-file-section () - "Like `magit-toggle-section' but toggle at file granularity." - (interactive) - (when (eq 'hunk (first (magit-section-context-type (magit-current-section)))) - (magit-goto-parent-section)) - (magit-toggle-section)) - -(defun magit-toggle-section () - "Toggle hidden status of current section." - (interactive) - (magit-section-hideshow - (lambda (s) - (magit-section-set-hidden s (not (magit-section-hidden s)))))) - -(defun magit-expand-collapse-section () - "Toggle hidden status of subsections of current section." - (interactive) - (magit-section-hideshow - (lambda (s) - (cond ((magit-section-any-hidden s) - (magit-section-expand-all s)) - (t - (magit-section-collapse s)))))) - -(defun magit-cycle-section () - "Cycle between expanded, hidden and collapsed state for current section. - -Hidden: only the first line of the section is shown -Collapsed: only the first line of the subsection is shown -Expanded: everything is shown." - (interactive) - (magit-section-hideshow - (lambda (s) - (cond ((magit-section-hidden s) - (magit-section-collapse s)) - ((notany #'magit-section-hidden (magit-section-children s)) - (magit-section-set-hidden s t)) - (t - (magit-section-expand s)))))) - -(defun magit-section-lineage (s) - "Return list of parent, grand-parents... for section S." - (when s - (cons s (magit-section-lineage (magit-section-parent s))))) - -(defun magit-section-show-level (section level threshold path) - (magit-section-set-hidden section (>= level threshold)) - (when (and (< level threshold) - (not (magit-no-commit-p))) - (if path - (magit-section-show-level (car path) (1+ level) threshold (cdr path)) - (dolist (c (magit-section-children section)) - (magit-section-show-level c (1+ level) threshold nil))))) - -(defun magit-show-level (level all) - "Show section whose level is less than LEVEL, hide the others. -If ALL is non nil, do this in all sections, -otherwise do it only on ancestors and descendants of current section." - (magit-with-refresh - (if all - (magit-section-show-level magit-top-section 0 level nil) - (let ((path (reverse (magit-section-lineage (magit-current-section))))) - (magit-section-show-level (car path) 0 level (cdr path)))))) - -(defun magit-show-only-files () - "Show section that are files, but not there subsection. - -Do this in on ancestors and descendants of current section." - (interactive) - (if (derived-mode-p 'magit-status-mode) - (call-interactively 'magit-show-level-2) - (call-interactively 'magit-show-level-1))) - -(defun magit-show-only-files-all () - "Show section that are files, but not there subsection. - -Do this for all sections" - (interactive) - (if (derived-mode-p 'magit-status-mode) - (call-interactively 'magit-show-level-2-all) - (call-interactively 'magit-show-level-1-all))) - -(defmacro magit-define-level-shower-1 (level all) - "Define an interactive function to show function of level LEVEL. - -If ALL is non nil, this function will affect all section, -otherwise it will affect only ancestors and descendants of current section." - (let ((fun (intern (format "magit-show-level-%s%s" - level (if all "-all" "")))) - (doc (format "Show sections on level %s." level))) - `(defun ,fun () - ,doc - (interactive) - (magit-show-level ,level ,all)))) - -(defmacro magit-define-level-shower (level) - "Define two interactive function to show function of level LEVEL. -one for all, one for current lineage." - `(progn - (magit-define-level-shower-1 ,level nil) - (magit-define-level-shower-1 ,level t))) - -(defmacro magit-define-section-jumper (sym title) - "Define an interactive function to go to section SYM. - -TITLE is the displayed title of the section." - (let ((fun (intern (format "magit-jump-to-%s" sym))) - (doc (format "Jump to section `%s'." title))) - `(progn - (defun ,fun () - ,doc - (interactive) - (magit-goto-section-at-path '(,sym))) - (put ',fun 'definition-name ',sym)))) - -(defmacro magit-define-inserter (sym arglist &rest body) - (declare (indent defun)) - (let ((fun (intern (format "magit-insert-%s" sym))) - (before (intern (format "magit-before-insert-%s-hook" sym))) - (after (intern (format "magit-after-insert-%s-hook" sym))) - (doc (format "Insert items for `%s'." sym))) - `(progn - (defvar ,before nil) - (defvar ,after nil) - (defun ,fun ,arglist - ,doc - (run-hooks ',before) - ,@body - (run-hooks ',after)) - (put ',before 'definition-name ',sym) - (put ',after 'definition-name ',sym) - (put ',fun 'definition-name ',sym)))) - -(defvar magit-highlighted-section nil) - -(defun magit-refine-section (section) - "Apply temporary refinements to the display of SECTION. -Refinements can be undone with `magit-unrefine-section'." - (let ((type (and section (magit-section-type section)))) - (cond ((and (eq type 'hunk) - magit-diff-refine-hunk - (not (eq magit-diff-refine-hunk 'all))) - ;; Refine the current hunk to show fine details, using - ;; diff-mode machinery. - (save-excursion - (goto-char (magit-section-beginning magit-highlighted-section)) - (diff-refine-hunk)))))) - -(defun magit-unrefine-section (section) - "Remove refinements to the display of SECTION done by `magit-refine-section'." - (let ((type (and section (magit-section-type section)))) - (cond ((and (eq type 'hunk) - magit-diff-refine-hunk - (not (eq magit-diff-refine-hunk 'all))) - ;; XXX this should be in some diff-mode function, like - ;; `diff-unrefine-hunk' - (remove-overlays (magit-section-beginning section) - (magit-section-end section) - 'diff-mode 'fine))))) - -(defvar magit-highlight-overlay nil) - -(defun magit-highlight-section () - "Highlight current section if it has a type." - (let ((section (magit-current-section))) - (when (not (eq section magit-highlighted-section)) - (when magit-highlighted-section - ;; remove any refinement from previous hunk - (magit-unrefine-section magit-highlighted-section)) - (setq magit-highlighted-section section) - (if (not magit-highlight-overlay) - (let ((ov (make-overlay 1 1))) - (overlay-put ov 'face 'magit-item-highlight) - (setq magit-highlight-overlay ov))) - (if (and section (magit-section-type section)) - (progn - (magit-refine-section section) - (move-overlay magit-highlight-overlay - (magit-section-beginning section) - (magit-section-end section) - (current-buffer))) - (delete-overlay magit-highlight-overlay))))) - -(defun magit-section-context-type (section) - (if (null section) - '() - (let ((c (or (magit-section-type section) - (if (symbolp (magit-section-title section)) - (magit-section-title section))))) - (if c - (cons c (magit-section-context-type - (magit-section-parent section))) - '())))) - -(defun magit-prefix-p (prefix list) - "Returns non-nil if PREFIX is a prefix of LIST. PREFIX and LIST should both be -lists. - -If the car of PREFIX is the symbol '*, then return non-nil if the cdr of PREFIX -is a sublist of LIST (as if '* matched zero or more arbitrary elements of LIST)" - ;;; Very schemish... - (or (null prefix) - (if (eq (car prefix) '*) - (or (magit-prefix-p (cdr prefix) list) - (and (not (null list)) - (magit-prefix-p prefix (cdr list)))) - (and (not (null list)) - (equal (car prefix) (car list)) - (magit-prefix-p (cdr prefix) (cdr list)))))) - -(defmacro magit-section-case (head &rest clauses) - "Make different action depending of current section. - -HEAD is (SECTION INFO &optional OPNAME), - SECTION will be bind to the current section, - INFO will be bind to the info's of the current section, - OPNAME is a string that will be used to describe current action, - -CLAUSES is a list of CLAUSE, each clause is (SECTION-TYPE &BODY) -where SECTION-TYPE describe section where BODY will be run. - -This returns non-nil if some section matches. If the -corresponding body return a non-nil value, it is returned, -otherwise it returns t. - -If no section matches, this returns nil if no OPNAME was given -and throws an error otherwise." - (declare (indent 1)) - (let ((section (car head)) - (info (cadr head)) - (type (make-symbol "*type*")) - (context (make-symbol "*context*")) - (opname (caddr head))) - `(let* ((,section (magit-current-section)) - (,info (and ,section (magit-section-info ,section))) - (,type (and ,section (magit-section-type ,section))) - (,context (magit-section-context-type ,section))) - (cond ,@(mapcar (lambda (clause) - (if (eq (car clause) t) - `(t (or (progn ,@(cdr clause)) - t)) - (let ((prefix (reverse (car clause))) - (body (cdr clause))) - `((magit-prefix-p ',prefix ,context) - (or (progn ,@body) - t))))) - clauses) - ,@(when opname - `(((run-hook-with-args-until-success - ',(intern (format "magit-%s-action-hook" opname)))) - ((not ,type) - (error "Nothing to %s here" ,opname)) - (t - (error "Can't %s a %s" - ,opname - (or (get ,type 'magit-description) - ,type))))))))) - -(defmacro magit-section-action (head &rest clauses) - (declare (indent 1)) - `(magit-with-refresh - (magit-section-case ,head ,@clauses))) - -(defmacro magit-add-action (head &rest clauses) - "Add additional actions to a pre-existing operator. -The syntax is identical to `magit-section-case', except that -OPNAME is mandatory and specifies the operation to which to add -the actions." - (declare (indent 1)) - (let ((section (car head)) - (info (cadr head)) - (type (caddr head))) - `(add-hook ',(intern (format "magit-%s-action-hook" type)) - (lambda () - ,(macroexpand - ;; Don't pass in the opname so we don't recursively - ;; run the hook again, and so we don't throw an - ;; error if no action matches. - `(magit-section-case (,section ,info) - ,@clauses)))))) - -(defun magit-wash-sequence (func) - "Run FUNC until end of buffer is reached. - -FUNC should leave point at the end of the modified region" - (while (and (not (eobp)) - (funcall func)))) - -(defmacro magit-define-command (sym arglist &rest body) - "Macro to define a magit command. -It will define the magit-SYM function having ARGLIST as argument. -It will also define the magit-SYM-command-hook variable. - -The defined function will call the function in the hook in -order until one return non nil. If they all return nil then body will be called. - -It is used to define hookable magit command: command defined by this -function can be enriched by magit extension like magit-topgit and magit-svn" - (declare (indent defun) - (debug (&define name lambda-list - [&optional stringp] ; Match the doc string, if present. - [&optional ("interactive" interactive)] - def-body))) - (let ((fun (intern (format "magit-%s" sym))) - (hook (intern (format "magit-%s-command-hook" sym))) - (doc (format "Command for `%s'." sym)) - (inter nil) - (instr body)) - (when (stringp (car body)) - (setq doc (car body) - instr (cdr body))) - (let ((form (car instr))) - (when (eq (car form) 'interactive) - (setq inter form - instr (cdr instr)))) - `(progn - (defvar ,hook nil) - (defun ,fun ,arglist - ,doc - ,inter - (or (run-hook-with-args-until-success - ',hook ,@(remq '&optional (remq '&rest arglist))) - ,@instr)) - (put ',fun 'definition-name ',sym) - (put ',hook 'definition-name ',sym)))) - -;;; Running commands - -(defun magit-set-mode-line-process (str) - (let ((pr (if str (concat " " str) ""))) - (save-excursion - (magit-for-all-buffers (lambda () - (setq mode-line-process pr)))))) - -(defun magit-process-indicator-from-command (comps) - (if (magit-prefix-p (cons magit-git-executable magit-git-standard-options) - comps) - (setq comps (nthcdr (+ (length magit-git-standard-options) 1) comps))) - (cond ((or (null (cdr comps)) - (not (member (car comps) '("remote")))) - (car comps)) - (t - (concat (car comps) " " (cadr comps))))) - -(defvar magit-process nil) -(defvar magit-process-client-buffer nil) -(defvar magit-process-buffer-name "*magit-process*" - "Buffer name for running git commands.") - -(defun magit-run* (cmd-and-args - &optional logline noerase noerror nowait input) - (if (and magit-process - (get-buffer magit-process-buffer-name)) - (error "Git is already running")) - (let ((cmd (car cmd-and-args)) - (args (cdr cmd-and-args)) - (dir default-directory) - (buf (get-buffer-create magit-process-buffer-name)) - (successp nil)) - (magit-set-mode-line-process - (magit-process-indicator-from-command cmd-and-args)) - (setq magit-process-client-buffer (current-buffer)) - (with-current-buffer buf - (view-mode 1) - (set (make-local-variable 'view-no-disable-on-exit) t) - (setq view-exit-action - (lambda (buffer) - (with-current-buffer buffer - (bury-buffer)))) - (setq buffer-read-only t) - (let ((inhibit-read-only t)) - (setq default-directory dir) - (if noerase - (goto-char (point-max)) - (erase-buffer)) - (insert "$ " (or logline - (mapconcat 'identity cmd-and-args " ")) - "\n") - (cond (nowait - (setq magit-process - (let ((process-connection-type magit-process-connection-type)) - (apply 'magit-start-process cmd buf cmd args))) - (set-process-sentinel magit-process 'magit-process-sentinel) - (set-process-filter magit-process 'magit-process-filter) - (when input - (with-current-buffer input - (process-send-region magit-process - (point-min) (point-max))) - (process-send-eof magit-process) - (sit-for 0.1 t)) - (cond ((= magit-process-popup-time 0) - (pop-to-buffer (process-buffer magit-process))) - ((> magit-process-popup-time 0) - (run-with-timer - magit-process-popup-time nil - (function - (lambda (buf) - (with-current-buffer buf - (when magit-process - (display-buffer (process-buffer magit-process)) - (goto-char (point-max)))))) - (current-buffer)))) - (setq successp t)) - (input - (with-current-buffer input - (setq default-directory dir) - (setq magit-process - ;; Don't use a pty, because it would set icrnl - ;; which would modify the input (issue #20). - (let ((process-connection-type nil)) - (apply 'magit-start-process cmd buf cmd args))) - (set-process-filter magit-process 'magit-process-filter) - (process-send-region magit-process - (point-min) (point-max)) - (process-send-eof magit-process) - (while (equal (process-status magit-process) 'run) - (sit-for 0.1 t)) - (setq successp - (equal (process-exit-status magit-process) 0)) - (setq magit-process nil)) - (magit-set-mode-line-process nil) - (magit-need-refresh magit-process-client-buffer)) - (t - (setq successp - (equal (apply 'process-file cmd nil buf nil args) 0)) - (magit-set-mode-line-process nil) - (magit-need-refresh magit-process-client-buffer)))) - (or successp - noerror - (error - "%s ... [Hit %s or see buffer %s for details]" - (or (with-current-buffer (get-buffer magit-process-buffer-name) - (when (re-search-backward - (concat "^error: \\(.*\\)" paragraph-separate) nil t) - (match-string 1))) - "Git failed") - (with-current-buffer magit-process-client-buffer - (key-description (car (where-is-internal - 'magit-display-process)))) - magit-process-buffer-name)) - successp))) - -(autoload 'dired-uncache "dired") -(defun magit-process-sentinel (process event) - (let ((msg (format "%s %s." (process-name process) (substring event 0 -1))) - (successp (string-match "^finished" event)) - (key (with-current-buffer magit-process-client-buffer - (key-description (car (where-is-internal - 'magit-display-process)))))) - (with-current-buffer (process-buffer process) - (let ((inhibit-read-only t)) - (goto-char (point-max)) - (insert msg "\n") - (message (if successp msg - (format "%s Hit %s or see buffer %s for details." - msg key (current-buffer))))) - (unless (memq (process-status process) '(run open)) - (dired-uncache default-directory))) - (setq magit-process nil) - (magit-set-mode-line-process nil) - (magit-refresh-buffer magit-process-client-buffer))) - -(defun magit-password (proc string) - "Checks if git/ssh asks for a password and ask the user for it." - (let (ask) - (cond ((or (string-match "^Enter passphrase for key '\\\(.*\\\)': $" string) - (string-match "^\\\(.*\\\)'s password:" string) - (string-match "^Password for '\\\(.*\\\)':" string)) - (setq ask (format "Password for '%s': " (match-string 1 string)))) - ((string-match "^[pP]assword:" string) - (setq ask "Password:"))) - (when ask - (process-send-string proc (concat (read-passwd ask nil) "\n"))))) - -(defun magit-username (proc string) - "Checks if git asks for a username and ask the user for it." - (when (string-match "^Username for '\\\(.*\\\)':" string) - (process-send-string proc - (concat - (read-string (format "Username for '%s': " - (match-string 1 string)) - nil nil (user-login-name)) - "\n")))) - -(defun magit-process-filter (proc string) - (save-current-buffer - (set-buffer (process-buffer proc)) - (let ((inhibit-read-only t)) - (magit-username proc string) - (magit-password proc string) - (goto-char (process-mark proc)) - ;; Find last ^M in string. If one was found, ignore everything - ;; before it and delete the current line. - (let ((ret-pos (length string))) - (while (and (>= (setq ret-pos (1- ret-pos)) 0) - (/= ?\r (aref string ret-pos)))) - (cond ((>= ret-pos 0) - (goto-char (line-beginning-position)) - (delete-region (point) (line-end-position)) - (insert (substring string (+ ret-pos 1)))) - (t - (insert string)))) - (set-marker (process-mark proc) (point))))) - -(defun magit-run (cmd &rest args) - (magit-with-refresh - (magit-run* (cons cmd args)))) - -(defun magit-run-git (&rest args) - (magit-with-refresh - (magit-run* (append (cons magit-git-executable - magit-git-standard-options) - args)))) - -(defun magit-run-git-with-input (input &rest args) - (magit-with-refresh - (magit-run* (append (cons magit-git-executable - magit-git-standard-options) - args) - nil nil nil nil input))) - -(defun magit-run-git-async (&rest args) - (message "Running %s %s" magit-git-executable (mapconcat 'identity args " ")) - (magit-run* (append (cons magit-git-executable - magit-git-standard-options) - args) - nil nil nil t)) - -(defun magit-run-async-with-input (input cmd &rest args) - (magit-run* (cons cmd args) nil nil nil t input)) - -(defun magit-display-process () - "Display output from most recent git command." - (interactive) - (unless (get-buffer magit-process-buffer-name) - (error "No Git commands have run")) - (display-buffer magit-process-buffer-name)) - -;;; Mode - -;; We define individual functions (instead of using lambda etc) so -;; that the online help can show something meaningful. - -(magit-define-section-jumper untracked "Untracked files") -(magit-define-section-jumper unstaged "Unstaged changes") -(magit-define-section-jumper staged "Staged changes") -(magit-define-section-jumper unpushed "Unpushed commits") - -(magit-define-level-shower 1) -(magit-define-level-shower 2) -(magit-define-level-shower 3) -(magit-define-level-shower 4) - -(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-item t] - ["Stage all" magit-stage-all t] - ["Unstage" magit-unstage-item t] - ["Unstage all" magit-unstage-all t] - ["Commit" magit-log-edit t] - ["Add log entry" magit-add-log t] - ["Tag" magit-tag t] - ["Annotated tag" magit-annotated-tag t] - "---" - ["Diff working tree" magit-diff-working-tree t] - ["Diff" magit-diff t] - ("Log" - ["Short Log" magit-log t] - ["Long Log" magit-log-long t] - ["Reflog" magit-reflog t] - ["Extended..." magit-key-mode-popup-logging t]) - "---" - ["Cherry pick" magit-cherry-pick-item t] - ["Apply" magit-apply-item t] - ["Revert" magit-revert-item t] - "---" - ["Ignore" magit-ignore-item t] - ["Ignore locally" magit-ignore-item-locally t] - ["Discard" magit-discard-item t] - ["Reset head" magit-reset-head t] - ["Reset working tree" magit-reset-working-tree t] - ["Stash" magit-stash t] - ["Snapshot" magit-stash-snapshot t] - "---" - ["Branch..." magit-checkout t] - ["Merge" magit-manual-merge t] - ["Interactive resolve" magit-interactive-resolve-item t] - ["Rebase" magit-rebase-step t] - ("Rewrite" - ["Start" magit-rewrite-start t] - ["Stop" magit-rewrite-stop t] - ["Finish" magit-rewrite-finish t] - ["Abort" magit-rewrite-abort t] - ["Set used" magit-rewrite-set-used t] - ["Set unused" magit-rewrite-set-unused t]) - "---" - ["Push" magit-push t] - ["Pull" magit-pull t] - ["Remote update" magit-remote-update t] - ("Submodule" - ["Submodule update" magit-submodule-update t] - ["Submodule update and init" magit-submodule-update-init t] - ["Submodule init" magit-submodule-init t] - ["Submodule sync" magit-submodule-sync t]) - "---" - ("Extensions") - "---" - ["Display Git output" magit-display-process t] - ["Quit Magit" magit-quit-window t])) - -(defvar magit-mode-hook nil "Hook run by `magit-mode'.") - -(put 'magit-mode 'mode-class 'special) - -(defvar magit-refresh-function nil) -(make-variable-buffer-local 'magit-refresh-function) -(put 'magit-refresh-function 'permanent-local t) - -(defvar magit-refresh-args nil) -(make-variable-buffer-local 'magit-refresh-args) -(put 'magit-refresh-args 'permanent-local t) - -(defvar last-point) - -(defun magit-remember-point () - (setq last-point (point))) - -(defun magit-invisible-region-end (pos) - (while (and (not (= pos (point-max))) (invisible-p pos)) - (setq pos (next-char-property-change pos))) - pos) - -(defun magit-invisible-region-start (pos) - (while (and (not (= pos (point-min))) (invisible-p pos)) - (setq pos (1- (previous-char-property-change pos)))) - pos) - -(defun magit-correct-point-after-command () - "Move point outside of invisible regions. - -Emacs often leaves point in invisible regions, it seems. To fix -this, we move point ourselves and never let Emacs do its own -adjustments. - -When point has to be moved out of an invisible region, it can be -moved to its end or its beginning. We usually move it to its -end, except when that would move point back to where it was -before the last command." - (if (invisible-p (point)) - (let ((end (magit-invisible-region-end (point)))) - (goto-char (if (= end last-point) - (magit-invisible-region-start (point)) - end)))) - (setq disable-point-adjustment t)) - -(defun magit-post-command-hook () - (magit-correct-point-after-command) - (magit-highlight-section)) - -(defun magit-mode () - "Review the status of a git repository and act on it. - -Please see the manual for a complete description of Magit. - -\\{magit-mode-map}" - (kill-all-local-variables) - (buffer-disable-undo) - (setq buffer-read-only t - truncate-lines t - major-mode 'magit-mode - mode-name "Magit" - mode-line-process "") - (add-hook 'pre-command-hook #'magit-remember-point nil t) - (add-hook 'post-command-hook #'magit-post-command-hook t t) - (use-local-map magit-mode-map) - (setq magit-current-indentation (magit-indentation-for default-directory)) - ;; Emacs' normal method of showing trailing whitespace gives weird - ;; results when `magit-whitespace-warning-face' is different from - ;; `trailing-whitespace'. - (if (and magit-highlight-whitespace magit-highlight-trailing-whitespace) - (setq show-trailing-whitespace nil)) - (run-mode-hooks 'magit-mode-hook)) - -(defun magit-mode-init (dir submode refresh-func &rest refresh-args) - (setq default-directory dir - magit-refresh-function refresh-func - magit-refresh-args refresh-args) - (funcall submode) - (magit-refresh-buffer)) - -(defun magit-indentation-for (dir) - (let (result) - (dolist (pair magit-highlight-indentation) - (if (string-match-p (car pair) dir) - (setq result (cdr pair)))) - result)) - -(defun magit-find-buffer (submode &optional dir) - (let ((topdir (magit-get-top-dir (or dir default-directory)))) - (dolist (buf (buffer-list)) - (if (with-current-buffer buf - (and (eq major-mode submode) - default-directory - (equal (expand-file-name default-directory) topdir))) - (return buf))))) - -(defun magit-find-status-buffer (&optional dir) - (magit-find-buffer 'magit-status-mode dir)) - -(defun magit-for-all-buffers (func &optional dir) - (dolist (buf (buffer-list)) - (with-current-buffer buf - (if (and (derived-mode-p 'magit-mode) - (or (null dir) - (equal default-directory dir))) - (funcall func))))) - -(defun magit-refresh-buffer (&optional buffer) - (with-current-buffer (or buffer (current-buffer)) - (let* ((old-line (line-number-at-pos)) - (old-point (point)) - (old-section (magit-current-section)) - (old-path (and old-section - (magit-section-path (magit-current-section))))) - (beginning-of-line) - (let ((section-line (and old-section - (count-lines - (magit-section-beginning old-section) - (point)))) - (line-char (- old-point (point)))) - (if magit-refresh-function - (apply magit-refresh-function - magit-refresh-args)) - (magit-refresh-marked-commits-in-buffer) - (let ((s (and old-path (magit-find-section old-path magit-top-section)))) - (cond (s - (goto-char (magit-section-beginning s)) - (forward-line section-line) - (forward-char line-char)) - (t - (magit-goto-line old-line))) - (dolist (w (get-buffer-window-list (current-buffer))) - (set-window-point w (point))) - (magit-highlight-section)))))) - -(defun magit-string-has-prefix-p (string prefix) - (eq (compare-strings string nil (length prefix) prefix nil nil) t)) - -(defun magit-revert-buffers (dir &optional ignore-modtime) - (dolist (buffer (buffer-list)) - (when (and buffer - (buffer-file-name buffer) - ;; don't revert indirect buffers, as the parent will be reverted - (not (buffer-base-buffer buffer)) - (magit-string-has-prefix-p (buffer-file-name buffer) dir) - (file-readable-p (buffer-file-name buffer)) - (or ignore-modtime (not (verify-visited-file-modtime buffer))) - (not (buffer-modified-p buffer))) - (with-current-buffer buffer - (condition-case var - (revert-buffer t t nil) - (error (let ((signal-data (cadr var))) - (cond (t (magit-bug-report signal-data)))))))))) - -(defun magit-update-vc-modeline (dir) - "Update the modeline for buffers representable by magit." - (dolist (buffer (buffer-list)) - (when (and buffer - (buffer-file-name buffer) - (magit-string-has-prefix-p (buffer-file-name buffer) dir)) - (with-current-buffer buffer - (condition-case var - (vc-find-file-hook) - (error (let ((signal-data (cadr var))) - (cond (t (magit-bug-report signal-data)))))))))) - -(defvar magit-refresh-needing-buffers nil) -(defvar magit-refresh-pending nil) - -(defun magit-refresh-wrapper (func) - (if magit-refresh-pending - (funcall func) - (let* ((dir default-directory) - (status-buffer (magit-find-status-buffer dir)) - (magit-refresh-needing-buffers nil) - (magit-refresh-pending t)) - (unwind-protect - (funcall func) - (when magit-refresh-needing-buffers - (magit-revert-buffers dir) - (dolist (b (adjoin status-buffer - magit-refresh-needing-buffers)) - (magit-refresh-buffer b))))))) - -(defun magit-need-refresh (&optional buffer) - "Mark BUFFER as needing to be refreshed. If BUFFER is nil, use the -current buffer." - (pushnew (or buffer (current-buffer)) magit-refresh-needing-buffers :test 'eq)) - -(defun magit-refresh () - "Refresh current buffer to match repository state. -Also revert every unmodified buffer visiting files -in the corresponding directory." - (interactive) - (magit-with-refresh - (magit-need-refresh))) - -(defun magit-refresh-all () - "Refresh all magit buffers to match respective repository states. -Also revert every unmodified buffer visiting files -in the corresponding directories." - (interactive) - (magit-for-all-buffers #'magit-refresh-buffer default-directory)) - -;;; Untracked files - -(defun magit-wash-untracked-file () - (if (looking-at "^? \\(.*\\)$") - (let ((file (match-string-no-properties 1))) - (delete-region (point) (+ (line-end-position) 1)) - (magit-with-section file 'file - (magit-set-section-info file) - (insert "\t" file "\n")) - t) - nil)) - -(defun magit-wash-untracked-files () - ;; Setting magit-old-top-section to nil speeds up washing: no time - ;; is wasted looking up the old visibility, which doesn't matter for - ;; untracked files. - ;; - ;; XXX - speed this up in a more general way. - ;; - (let ((magit-old-top-section nil)) - (magit-wash-sequence #'magit-wash-untracked-file))) - -(defun magit-insert-untracked-files () - (unless (string= (magit-get "status" "showUntrackedFiles") "no") - (apply 'magit-git-section - `(untracked - "Untracked files:" - magit-wash-untracked-files - "ls-files" "--others" "-t" "--exclude-standard" - ,@(when magit-omit-untracked-dir-contents - '("--directory")))))) - -;;; Diffs and Hunks - -(defvar magit-diff-context-lines 3) - -(defun magit-diff-U-arg () - (format "-U%d" magit-diff-context-lines)) - -(defun magit-diff-smaller-hunks (&optional count) - "Decrease the context for diff hunks by COUNT." - (interactive "p") - (setq magit-diff-context-lines (max 0 (- magit-diff-context-lines count))) - (magit-refresh)) - -(defun magit-diff-larger-hunks (&optional count) - "Increase the context for diff hunks by COUNT." - (interactive "p") - (setq magit-diff-context-lines (+ magit-diff-context-lines count)) - (magit-refresh)) - -(defun magit-diff-default-hunks () - "Reset context for diff hunks to the default size." - (interactive "") - (setq magit-diff-context-lines 3) - (magit-refresh)) - -(defun magit-toggle-diff-refine-hunk (&optional other) - (interactive "P") - "Turn diff-hunk refining on or off. - -If hunk refining is currently on, then hunk refining is turned off. -If hunk refining is off, then hunk refining is turned on, in -`selected' mode (only the currently selected hunk is refined). - -With a prefix argument, the \"third choice\" is used instead: -If hunk refining is currently on, then refining is kept on, but -the refining mode (`selected' or `all') is switched. -If hunk refining is off, then hunk refining is turned on, in -`all' mode (all hunks refined). - -Customize `magit-diff-refine-hunk' to change the default mode." - (let* ((old magit-diff-refine-hunk) - (new - (if other - (if (eq old 'all) t 'all) - (not old)))) - - ;; remove any old refining in currently highlighted section - (when (and magit-highlighted-section old (not (eq old 'all))) - (magit-unrefine-section magit-highlighted-section)) - - ;; set variable to new value locally - (set (make-local-variable 'magit-diff-refine-hunk) new) - - ;; if now highlighting in "selected only" mode, turn refining back - ;; on in the current section - (when (and magit-highlighted-section new (not (eq new 'all))) - (magit-refine-section magit-highlighted-section)) - - ;; `all' mode being turned on or off needs a complete refresh - (when (or (eq old 'all) (eq new 'all)) - (magit-refresh)))) - -(defun magit-diff-line-file () - (cond ((looking-at "^diff --git ./\\(.*\\) ./\\(.*\\)$") - (match-string-no-properties 2)) - ((looking-at "^diff --cc +\\(.*\\)$") - (match-string-no-properties 1)) - (t - nil))) - -(defun magit-wash-diffs () - (magit-wash-sequence #'magit-wash-diff-or-other-file)) - -(defun magit-wash-diff-or-other-file () - (or (magit-wash-diff) - (magit-wash-other-file))) - -(defun magit-wash-other-file () - (if (looking-at "^? \\(.*\\)$") - (let ((file (match-string-no-properties 1))) - (delete-region (point) (+ (line-end-position) 1)) - (magit-with-section file 'file - (magit-set-section-info file) - (insert "\tNew " file "\n")) - t) - nil)) - -(defvar magit-hide-diffs nil) - -(defvar magit-indentation-level 1) - -(defun magit-insert-diff-title (status file file2) - (let ((status-text (case status - ((unmerged) - (format "Unmerged %s" file)) - ((new) - (format "New %s" file)) - ((deleted) - (format "Deleted %s" file)) - ((renamed) - (format "Renamed %s (from %s)" - file file2)) - ((modified) - (format "Modified %s" file)) - ((typechange) - (format "Typechange %s" file)) - (t - (format "? %s" file))))) - (insert (make-string magit-indentation-level ?\t) status-text "\n"))) - -(defvar magit-current-diff-range nil - "Used internally when setting up magit diff sections.") - -(defun magit-wash-typechange-section (file) - (magit-set-section-info (list 'typechange file)) - (let ((first-start (point-marker)) - (second-start (progn (forward-line 1) - (search-forward-regexp "^diff") - (beginning-of-line) - (point-marker)))) - (let ((magit-indentation-level (+ magit-indentation-level 1))) - (save-restriction - (narrow-to-region first-start second-start) - (goto-char (point-min)) - (magit-with-section file 'diff - (magit-wash-diff-section))) - (save-restriction - (narrow-to-region second-start (point-max)) - (goto-char (point-min)) - (magit-with-section file 'diff - (magit-wash-diff-section)))))) - -(defun magit-wash-diff-section () - (cond ((looking-at "^\\* Unmerged path \\(.*\\)") - (let ((file (match-string-no-properties 1))) - (delete-region (point) (line-end-position)) - (insert "\tUnmerged " file "\n") - (magit-set-section-info (list 'unmerged file nil)) - t)) - ((looking-at "^diff") - (let ((file (magit-diff-line-file)) - (end (save-excursion - (forward-line) ;; skip over "diff" line - (if (search-forward-regexp "^diff\\|^@@" nil t) - (goto-char (match-beginning 0)) - (goto-char (point-max))) - (point-marker)))) - (let* ((status (cond - ((looking-at "^diff --cc") - 'unmerged) - ((save-excursion - (search-forward-regexp "^new file" end t)) - 'new) - ((save-excursion - (search-forward-regexp "^deleted" end t)) - 'deleted) - ((save-excursion - (search-forward-regexp "^rename" end t)) - 'renamed) - (t - 'modified))) - (file2 (cond - ((save-excursion - (search-forward-regexp "^rename from \\(.*\\)" - end t)) - (match-string-no-properties 1))))) - (magit-set-section-info (list status - file - (or file2 file) - magit-current-diff-range)) - (magit-insert-diff-title status file file2) - (when (search-forward-regexp "\\(--- \\(.*\\)\n\\+\\+\\+ \\(.*\\)\n\\)" () t) - (when (match-string 1) - (add-text-properties (match-beginning 1) (match-end 1) - '(face magit-diff-hunk-header)) - (add-text-properties (match-beginning 2) (match-end 2) - '(face magit-diff-file-header)) - (add-text-properties (match-beginning 3) (match-end 3) - '(face magit-diff-file-header)))) - (goto-char end) - (let ((magit-section-hidden-default nil)) - (magit-wash-sequence #'magit-wash-hunk)))) - t) - (t - nil))) - -(defun magit-wash-diff () - (let ((magit-section-hidden-default magit-hide-diffs)) - (magit-with-section (magit-current-line) 'diff - (magit-wash-diff-section)))) - -(defun magit-diff-item-kind (diff) - (car (magit-section-info diff))) - -(defun magit-diff-item-file (diff) - (cadr (magit-section-info diff))) - -(defun magit-diff-item-file2 (diff) - (caddr (magit-section-info diff))) - -(defun magit-diff-item-range (diff) - (nth 3 (magit-section-info diff))) - -(defun magit-wash-hunk () - (cond ((looking-at "\\(^@+\\)[^@]*@+.*") - (let ((n-columns (1- (length (match-string 1)))) - (head (match-string 0)) - (hunk-start-pos (point))) - (magit-with-section head 'hunk - (add-text-properties (match-beginning 0) (match-end 0) - '(face magit-diff-hunk-header)) - (forward-line) - (while (not (or (eobp) - (looking-at "^diff\\|^@@"))) - (magit-highlight-line-whitespace) - (let ((prefix (buffer-substring-no-properties - (point) (min (+ (point) n-columns) (point-max))))) - (cond ((string-match "\\+" prefix) - (magit-put-line-property 'face 'magit-diff-add)) - ((string-match "-" prefix) - (magit-put-line-property 'face 'magit-diff-del)) - (t - (magit-put-line-property 'face 'magit-diff-none)))) - (forward-line))) - - (when (eq magit-diff-refine-hunk 'all) - (save-excursion - (goto-char hunk-start-pos) - (diff-refine-hunk)))) - t) - (t - nil))) - -(defvar magit-diff-options nil) - -(defun magit-insert-diff (file status) - (let ((cmd magit-git-executable) - (args (append (list "diff") - (list (magit-diff-U-arg)) - magit-diff-options - (list "--" file)))) - (let ((p (point))) - (magit-git-insert args) - (if (not (eq (char-before) ?\n)) - (insert "\n")) - (save-restriction - (narrow-to-region p (point)) - (goto-char p) - (cond - ((eq status 'typechange) - (magit-insert-diff-title status file file) - (magit-wash-typechange-section file)) - (t - (magit-wash-diff-section))) - (goto-char (point-max)))))) - -(defvar magit-last-raw-diff nil) -(defvar magit-ignore-unmerged-raw-diffs nil) - -(defun magit-wash-raw-diffs () - (let ((magit-last-raw-diff nil)) - (magit-wash-sequence #'magit-wash-raw-diff))) - -(defun magit-wash-raw-diff () - (if (looking-at - ":\\([0-7]+\\) \\([0-7]+\\) [0-9a-f]+ [0-9a-f]+ \\(.\\)[0-9]*\t\\([^\t\n]+\\)$") - (let ((old-perm (match-string-no-properties 1)) - (new-perm (match-string-no-properties 2)) - (status (case (string-to-char (match-string-no-properties 3)) - (?A 'new) - (?D 'deleted) - (?M 'modified) - (?U 'unmerged) - (?T 'typechange) - (t nil))) - (file (match-string-no-properties 4))) - ;; If this is for the same file as the last diff, ignore it. - ;; Unmerged files seem to get two entries. - ;; We also ignore unmerged files when told so. - (if (or (equal file magit-last-raw-diff) - (and magit-ignore-unmerged-raw-diffs (eq status 'unmerged))) - (delete-region (point) (+ (line-end-position) 1)) - (setq magit-last-raw-diff file) - ;; The 'diff' section that is created here will not work with - ;; magit-insert-diff-item-patch etc when we leave it empty. - ;; Luckily, raw diffs are only produced for staged and - ;; unstaged changes, and we never call - ;; magit-insert-diff-item-patch on them. This is a bit - ;; brittle, of course. - (let ((magit-section-hidden-default magit-hide-diffs)) - (magit-with-section file 'diff - (delete-region (point) (+ (line-end-position) 1)) - (if (not (magit-section-hidden magit-top-section)) - (magit-insert-diff file status) - (magit-set-section-info (list status file nil)) - (magit-set-section-needs-refresh-on-show t) - (magit-insert-diff-title status file nil))))) - t) - nil)) - -(defun magit-hunk-item-diff (hunk) - (let ((diff (magit-section-parent hunk))) - (or (eq (magit-section-type diff) 'diff) - (error "Huh? Parent of hunk not a diff")) - diff)) - -(defun magit-diff-item-insert-header (diff buf) - (let ((beg (save-excursion - (goto-char (magit-section-beginning diff)) - (forward-line) - (point))) - (end (if (magit-section-children diff) - (magit-section-beginning (car (magit-section-children diff))) - (magit-section-end diff)))) - (magit-insert-region beg end buf))) - -(defun magit-insert-diff-item-patch (diff buf) - (let ((beg (save-excursion - (goto-char (magit-section-beginning diff)) - (forward-line) - (point))) - (end (magit-section-end diff))) - (magit-insert-region beg end buf))) - -(defun magit-insert-hunk-item-patch (hunk buf) - (magit-diff-item-insert-header (magit-hunk-item-diff hunk) buf) - (magit-insert-region (magit-section-beginning hunk) (magit-section-end hunk) - buf)) - -(defun magit-insert-hunk-item-region-patch (hunk reverse beg end buf) - (magit-diff-item-insert-header (magit-hunk-item-diff hunk) buf) - (save-excursion - (goto-char (magit-section-beginning hunk)) - (magit-insert-current-line buf) - (forward-line) - (let ((copy-op (if reverse "+" "-"))) - (while (< (point) (magit-section-end hunk)) - (if (and (<= beg (point)) (< (point) end)) - (magit-insert-current-line buf) - (cond ((looking-at " ") - (magit-insert-current-line buf)) - ((looking-at copy-op) - (let ((text (buffer-substring-no-properties - (+ (point) 1) (line-beginning-position 2)))) - (with-current-buffer buf - (insert " " text)))))) - (forward-line)))) - (with-current-buffer buf - (diff-fixup-modifs (point-min) (point-max)))) - -(defun magit-hunk-item-is-conflict-p (hunk) - ;;; XXX - Using the title is a bit too clever... - (string-match "^diff --cc" - (magit-section-title (magit-hunk-item-diff hunk)))) - -(defun magit-hunk-item-target-line (hunk) - (save-excursion - (beginning-of-line) - (let ((line (line-number-at-pos))) - (goto-char (magit-section-beginning hunk)) - (if (not (looking-at "@@+ .* \\+\\([0-9]+\\)\\(,[0-9]+\\)? @@+")) - (error "Hunk header not found")) - (let ((target (string-to-number (match-string 1)))) - (forward-line) - (while (< (line-number-at-pos) line) - ;; XXX - deal with combined diffs - (if (not (looking-at "-")) - (setq target (+ target 1))) - (forward-line)) - target)))) - -(defun magit-show (commit filename &optional select prefix) - "Returns a buffer containing the contents of the file FILENAME, as stored in -COMMIT. COMMIT may be one of the following: - -- A string with the name of a commit, such as \"head\" or \"dae86e\". See 'git - help revisions' for syntax. -- The symbol 'index, indicating that you want the version in Git's index or - staging area. -- The symbol 'working, indicating that you want the version in the working - directory. In this case you'll get a buffer visiting the file. If there's - already a buffer visiting that file, you'll get that one. - -When called interactively or when SELECT is non-nil, make the buffer active, -either in another window or (with a prefix argument) in the current window." - (interactive (let* ((revision (magit-read-rev "Retrieve file from revision")) - (filename (magit-read-file-from-rev revision))) - (list revision filename t current-prefix-arg))) - (if (eq commit 'working) - (find-file-noselect filename) - (let ((buffer (create-file-buffer (format "%s.%s" filename (replace-regexp-in-string ".*/" "" (prin1-to-string commit t)))))) - (cond - ((eq commit 'index) - (let ((checkout-string (magit-git-string "checkout-index" - "--temp" - filename))) - (string-match "^\\(.*\\)\t" checkout-string) - (with-current-buffer buffer - (let ((tmpname (match-string 1 checkout-string))) - (magit-with-silent-modifications - (insert-file-contents tmpname nil nil nil t)) - (delete-file tmpname))))) - (t - (with-current-buffer buffer - (magit-with-silent-modifications - (magit-git-insert (list "cat-file" "-p" - (concat commit ":" filename))))))) - (with-current-buffer buffer - (let ((buffer-file-name filename)) - (normal-mode)) - (goto-char (point-min))) - (if select - (if prefix - (switch-to-buffer buffer) - (switch-to-buffer-other-window buffer)) - buffer)))) - -(defmacro with-magit-tmp-buffer (var &rest body) - (declare (indent 1) - (debug (symbolp &rest form))) - `(let ((,var (generate-new-buffer magit-tmp-buffer-name))) - (unwind-protect - (progn ,@body) - (kill-buffer ,var)))) - -(defun magit-apply-diff-item (diff &rest args) - (when (zerop magit-diff-context-lines) - (setq args (cons "--unidiff-zero" args))) - (with-magit-tmp-buffer tmp - (magit-insert-diff-item-patch diff tmp) - (apply #'magit-run-git-with-input tmp - "apply" (append args (list "-"))))) - -(defun magit-apply-hunk-item* (hunk reverse &rest args) - "Apply single hunk or part of a hunk to the index or working file. - -This function is the core of magit's stage, unstage, apply, and -revert operations. HUNK (or the portion of it selected by the -region) will be applied to either the index, if \"--cached\" is a -member of ARGS, or to the working file otherwise." - (let ((zero-context (zerop magit-diff-context-lines)) - (use-region (magit-use-region-p))) - (when zero-context - (setq args (cons "--unidiff-zero" args))) - (when reverse - (setq args (cons "--reverse" args))) - (when (and use-region zero-context) - (error (concat "Not enough context to partially apply hunk. " - "Use `+' to increase context."))) - (with-magit-tmp-buffer tmp - (if use-region - (magit-insert-hunk-item-region-patch - hunk reverse (region-beginning) (region-end) tmp) - (magit-insert-hunk-item-patch hunk tmp)) - (apply #'magit-run-git-with-input tmp - "apply" (append args (list "-")))))) - -(defun magit-apply-hunk-item (hunk &rest args) - (apply #'magit-apply-hunk-item* hunk nil args)) - -(defun magit-apply-hunk-item-reverse (hunk &rest args) - (apply #'magit-apply-hunk-item* hunk t args)) - -(magit-define-inserter unstaged-changes (title) - (let ((magit-hide-diffs t) - (magit-current-diff-range (cons 'index 'working))) - (let ((magit-diff-options (append '() magit-diff-options))) - (magit-git-section 'unstaged title 'magit-wash-raw-diffs - "diff-files")))) - -(magit-define-inserter staged-changes (staged no-commit) - (let ((magit-current-diff-range (cons "HEAD" 'index))) - (when staged - (let ((magit-hide-diffs t) - (base (if no-commit - (magit-git-string "mktree") - "HEAD"))) - (let ((magit-diff-options (append '("--cached") magit-diff-options)) - (magit-ignore-unmerged-raw-diffs t)) - (magit-git-section 'staged "Staged changes:" 'magit-wash-raw-diffs - "diff-index" "--cached" - base)))))) - -;;; Logs and Commits - - ; Note: making this a plain defcustom would probably let users break - ; the parser too easily -(defvar magit-git-log-options - (list - "--pretty=format:* %h %s" - (format "--abbrev=%s" magit-sha1-abbrev-length))) - ; --decorate=full otherwise some ref prefixes are stripped - ; '("--pretty=format:* %H%d %s" "--decorate=full")) - -;; -;; Regexps for parsing ref names -;; -;; see the `git-check-ref-format' manpage for details - -(defconst magit-ref-nonchars "\000-\037\177 ~^:?*[\\" - "Characters specifically disallowed from appearing in Git symbolic refs. - -Evaluate (man \"git-check-ref-format\") for details") - -(defconst magit-ref-nonslash-re - (concat "\\(?:" - ;; "no slash-separated component can begin with a dot ." (rule 1) - "[^" magit-ref-nonchars "./]" - ;; "cannot have two consecutive dots .. anywhere." (rule 3) - "\\.?" - "\\)*") - "Regexp that matches the non-slash parts of a ref name. - -Evaluate (man \"git-check-ref-format\") for details") - -(defconst magit-refname-re - (concat - "\\(?:HEAD\\|" - - "\\(?:tag: \\)?" - - ;; optional non-slash sequence at the beginning - magit-ref-nonslash-re - - ;; any number of slash-prefixed sequences - "\\(?:" - "/" - magit-ref-nonslash-re - "\\)*" - - "/" ;; "must contain at least one /." (rule 2) - magit-ref-nonslash-re - - ;; "cannot end with a slash / nor a dot .." (rule 5) - "[^" magit-ref-nonchars "./]" - - "\\)" - ) - "Regexp that matches a git symbolic reference name. - -Evaluate (man \"git-check-ref-format\") for details") - -(defconst magit-log-oneline-re - (concat - "^\\([_\\*|/ -.]+\\)?" ; graph (1) - "\\(?:" - "\\([0-9a-fA-F]+\\)" ; sha1 (2) - "\\(?:" ; refs (3) - " " - "\\(" - "(" - magit-refname-re "\\(?:, " magit-refname-re "\\)*" - ")" - "\\)" - "\\)?" - "\\)?" - " ?\\(.*\\)$" ; msg (4) - )) - -(defconst magit-log-longline-re - (concat - ;; use \0 delimiter (from -z option) to identify commits. this prevents - ;; commit messages containing lines like "commit 00000" from polluting the - ;; display - "\\(?:\\(?:\\`\\|\0\\)" - "\\([_\\*|/ -.]+\\)?" ; graph (1) - "commit " - "\\([0-9a-fA-F]+\\)" ; sha1 (2) - "\\(?:" ; refs (3) - " " - "\\(" - "(" - magit-refname-re "\\(?:, " magit-refname-re "\\)*" - ")" - "\\)" - "\\)?" - "$\\)?" - " ?\\(.*\\)$" ; msg (4) - )) - -(defvar magit-present-log-line-function 'magit-present-log-line - "The function to use when generating a log line. -It takes four args: CHART, SHA1, REFS and MESSAGE. The function -must return a string which will represent the log line.") - -(defun magit-log-get-bisect-state-color (suffix) - (if (string= suffix "bad") - (list suffix 'magit-log-head-label-bisect-bad) - (list suffix 'magit-log-head-label-bisect-good))) - -(defun magit-log-get-patches-color (suffix) - (list (and (string-match ".+/\\(.+\\)" suffix) - (match-string 1 suffix)) - 'magit-log-head-label-patches)) - -(defvar magit-log-remotes-color-hook nil) - -(defun magit-log-get-remotes-color (suffix) - (or - (run-hook-with-args-until-success - 'magit-log-remotes-color-hook suffix) - (list suffix 'magit-log-head-label-remote))) - -(defvar magit-refs-namespaces - '(("tags" . magit-log-head-label-tags) - ("remotes" magit-log-get-remotes-color) - ("heads" . magit-log-head-label-local) - ("patches" magit-log-get-patches-color) - ("bisect" magit-log-get-bisect-state-color))) - -(defun magit-ref-get-label-color (r) - (let ((uninteresting (loop for re in magit-uninteresting-refs - thereis (string-match re r)))) - (if uninteresting (list nil nil) - (let* ((ref-re "\\(?:tag: \\)?refs/\\(?:\\([^/]+\\)/\\)?\\(.+\\)") - (label (and (string-match ref-re r) - (match-string 2 r))) - (res (let ((colorizer - (cdr (assoc (match-string 1 r) - magit-refs-namespaces)))) - (cond ((null colorizer) - (list r 'magit-log-head-label-default)) - ((symbolp colorizer) - (list label colorizer)) - ((listp colorizer) - (funcall (car colorizer) - (match-string 2 r))) - (t - (list r 'magit-log-head-label-default)))))) - res)))) - -(defun magit-present-log-line (graph sha1 refs message) - "The default log line generator." - (let ((string-refs - (when refs - (let ((colored-labels - (delete nil - (mapcar (lambda (r) - (destructuring-bind (label face) - (magit-ref-get-label-color r) - (and label - (propertize label 'face face)))) - refs)))) - (concat - (mapconcat 'identity colored-labels " ") - " "))))) - - (concat - (if sha1 - (propertize sha1 'face 'magit-log-sha1) - (insert-char ? magit-sha1-abbrev-length)) - " " - (when graph - (propertize graph 'face 'magit-log-graph)) - string-refs - (when message - (propertize message 'face 'magit-log-message))))) - -(defvar magit-log-count () - "Internal var used to count the number of logs actually added in a buffer.") - -(defmacro magit-create-log-buffer-sections (&rest body) - "Empty current buffer of text and magit's section, and then evaluate BODY. - -if the number of logs inserted in the buffer is `magit-log-cutoff-length' -insert a line to tell how to insert more of them" - (declare (indent 0)) - `(let ((magit-log-count 0) (inhibit-read-only t)) - (magit-create-buffer-sections - (magit-with-section 'log nil - ,@body - (if (= magit-log-count magit-log-cutoff-length) - (magit-with-section "longer" 'longer - (insert "type \"e\" to show more logs\n"))))))) - -(defun magit-wash-log-line (style) - (beginning-of-line) - (let ((line-re (cond ((eq style 'long) magit-log-longline-re) - (t magit-log-oneline-re)))) - (cond - ((looking-at line-re) - (let ((chart (match-string 1)) - (sha1 (match-string 2)) - (msg (match-string 4)) - (refs (when (match-string 3) - (delq nil - (mapcar - (lambda (s) - (and (not - (or (string= s "tag:") - (string= s "HEAD"))) ; as of 1.6.6 - s)) - (split-string (match-string 3) "[(), ]" t)))))) - (delete-region (point-at-bol) (point-at-eol)) - (insert (funcall magit-present-log-line-function chart sha1 refs msg)) - (goto-char (point-at-bol)) - (if sha1 - (magit-with-section sha1 'commit - (when magit-log-count (setq magit-log-count (1+ magit-log-count))) - (magit-set-section-info sha1) - (forward-line)) - (forward-line)))) - (t - (forward-line))) - t)) - -(defun magit-wash-log (&optional style) - (let ((magit-old-top-section nil)) - (magit-wash-sequence (apply-partially 'magit-wash-log-line style)))) - -(defvar magit-currently-shown-commit nil) - -(defun magit-wash-commit () - (let ((magit-current-diff-range)) - (when (looking-at "^commit \\([0-9a-fA-F]\\{40\\}\\)") - (setq magit-current-diff-range (match-string 1)) - (add-text-properties (match-beginning 1) (match-end 1) - '(face magit-log-sha1))) - (cond - ((search-forward-regexp "^Merge: \\([0-9a-fA-F]+\\) \\([0-9a-fA-F]+\\)$" nil t) - (setq magit-current-diff-range (cons (cons (match-string 1) - (match-string 2)) - magit-current-diff-range)) - (let ((first (magit-set-section nil 'commit (match-beginning 1) (match-end 1))) - (second (magit-set-section nil 'commit (match-beginning 2) (match-end 2)))) - (magit-set-section-info (match-string 1) first) - (magit-set-section-info (match-string 2) second)) - (make-commit-button (match-beginning 1) (match-end 1)) - (make-commit-button (match-beginning 2) (match-end 2))) - (t - (setq magit-current-diff-range (cons (concat magit-current-diff-range "^") - magit-current-diff-range)))) - (search-forward-regexp "^$") - (while (and - (search-forward-regexp "\\(\\b[0-9a-fA-F]\\{4,40\\}\\b\\)\\|\\(^diff\\)" nil 'noerror) - (not (match-string 2))) - (let ((sha1 (match-string 1)) - (start (match-beginning 1)) - (end (match-end 1))) - (when (string-equal "commit" (magit-git-string "cat-file" "-t" sha1)) - (make-commit-button start end) - (let ((section (magit-set-section sha1 'commit start end))) - (magit-set-section-info sha1 section))))) - (beginning-of-line) - (when (looking-at "^diff") - (magit-wash-diffs)) - (goto-char (point-max)) - (insert "\n") - (if magit-back-navigation-history - (magit-with-section "[back]" 'button - (insert-text-button "[back]" - 'help-echo "Previous commit" - 'action 'magit-show-commit-backward - 'follow-link t - 'mouse-face 'magit-item-highlight))) - (insert " ") - (if magit-forward-navigation-history - (magit-with-section "[forward]" 'button - (insert-text-button "[forward]" - 'help-echo "Next commit" - 'action 'magit-show-commit-forward - 'follow-link t - 'mouse-face 'magit-item-highlight))))) - -(defun make-commit-button (start end) - (make-text-button start end - 'help-echo "Visit commit" - 'action (lambda (button) - (save-excursion - (goto-char button) - (magit-visit-item))) - 'follow-link t - 'mouse-face 'magit-item-highlight - 'face 'magit-log-sha1)) - -(defun magit-refresh-commit-buffer (commit) - (magit-configure-have-abbrev) - (magit-configure-have-decorate) - (magit-create-buffer-sections - (apply #'magit-git-section nil nil - 'magit-wash-commit - "log" - "--max-count=1" - "--pretty=medium" - `(,@(if magit-have-abbrev (list "--no-abbrev-commit")) - ,@(if magit-have-decorate (list "--decorate=full")) - "--cc" - "-p" ,commit)))) - -(define-derived-mode magit-commit-mode magit-mode "Magit" - "Mode to view a git commit. - -\\{magit-commit-mode-map}" - :group 'magit) - -(defvar magit-commit-buffer-name "*magit-commit*" - "Buffer name for displaying commit log messages.") - -(defun magit-show-commit (commit &optional scroll inhibit-history select) - "Show information about a commit in the buffer named by -`magit-commit-buffer-name'. COMMIT can be any valid name for a commit -in the current Git repository. - -When called interactively or when SELECT is non-nil, switch to -the commit buffer using `pop-to-buffer'. - -Unless INHIBIT-HISTORY is non-nil, the commit currently shown -will be pushed onto `magit-back-navigation-history' and -`magit-forward-navigation-history' will be cleared. - -Noninteractively, if the commit is already displayed and SCROLL -is provided, call SCROLL's function definition in the commit -window. (`scroll-up' and `scroll-down' are typically passed in -for this argument.)" - (interactive (list (magit-read-rev "Show commit (hash or ref)") - nil nil t)) - (when (magit-section-p commit) - (setq commit (magit-section-info commit))) - (unless (eql 0 (magit-git-exit-code "cat-file" "commit" commit)) - (error "%s is not a commit" commit)) - (let ((dir default-directory) - (buf (get-buffer-create magit-commit-buffer-name))) - (cond - ((and (equal magit-currently-shown-commit commit) - ;; if it's empty then the buffer was killed - (with-current-buffer buf - (> (length (buffer-string)) 1))) - (let ((win (get-buffer-window buf))) - (cond ((not win) - (display-buffer buf)) - (scroll - (with-selected-window win - (funcall scroll)))))) - (commit - (display-buffer buf) - (with-current-buffer buf - (unless inhibit-history - (push (cons default-directory magit-currently-shown-commit) - magit-back-navigation-history) - (setq magit-forward-navigation-history nil)) - (setq magit-currently-shown-commit commit) - (goto-char (point-min)) - (magit-mode-init dir 'magit-commit-mode - #'magit-refresh-commit-buffer commit)))) - (if select - (pop-to-buffer buf)))) - -(defun magit-show-commit-backward (&optional ignored) - ;; Ignore argument passed by push-button - "Show the commit at the head of `magit-back-navigation-history in -`magit-commit-buffer-name`." - (interactive) - (with-current-buffer magit-commit-buffer-name - (unless magit-back-navigation-history - (error "No previous commit.")) - (let ((histitem (pop magit-back-navigation-history))) - (push (cons default-directory magit-currently-shown-commit) - magit-forward-navigation-history) - (setq default-directory (car histitem)) - (magit-show-commit (cdr histitem) nil 'inhibit-history)))) - -(defun magit-show-commit-forward (&optional ignored) - ;; Ignore argument passed by push-button - "Show the commit at the head of `magit-forward-navigation-history in -`magit-commit-buffer-name`." - (interactive) - (with-current-buffer magit-commit-buffer-name - (unless magit-forward-navigation-history - (error "No next commit.")) - (let ((histitem (pop magit-forward-navigation-history))) - (push (cons default-directory magit-currently-shown-commit) - magit-back-navigation-history) - (setq default-directory (car histitem)) - (magit-show-commit (cdr histitem) nil 'inhibit-history)))) - -(defvar magit-marked-commit nil) - -(defvar magit-mark-overlay nil) -(make-variable-buffer-local 'magit-mark-overlay) -(put 'magit-mark-overlay 'permanent-local t) - -(defun magit-refresh-marked-commits () - (magit-for-all-buffers #'magit-refresh-marked-commits-in-buffer)) - -(defun magit-refresh-marked-commits-in-buffer () - (if (not magit-mark-overlay) - (let ((ov (make-overlay 1 1))) - (overlay-put ov 'face 'magit-item-mark) - (setq magit-mark-overlay ov))) - (delete-overlay magit-mark-overlay) - (magit-for-all-sections - (lambda (section) - (when (and (eq (magit-section-type section) 'commit) - (equal (magit-section-info section) - magit-marked-commit)) - (move-overlay magit-mark-overlay - (magit-section-beginning section) - (magit-section-end section) - (current-buffer)))))) - -(defun magit-set-marked-commit (commit) - (setq magit-marked-commit commit) - (magit-refresh-marked-commits)) - -(defun magit-marked-commit () - (or magit-marked-commit - (error "No commit marked"))) - -(defun magit-remote-branch-name (remote branch) - "Get the name of the branch BRANCH on remote REMOTE" - (if (string= remote ".") - branch - (concat remote "/" branch))) - -(magit-define-inserter unpulled-commits (remote branch) - (when remote - (apply #'magit-git-section - 'unpulled "Unpulled commits:" 'magit-wash-log "log" - (append magit-git-log-options - (list - (format "HEAD..%s" (magit-remote-branch-name remote branch))))))) - -(magit-define-inserter unpushed-commits (remote branch) - (when remote - (apply #'magit-git-section - 'unpushed "Unpushed commits:" 'magit-wash-log "log" - (append magit-git-log-options - (list - (format "%s..HEAD" (magit-remote-branch-name remote branch))))))) - -(defun magit-remote-branch-for (local-branch &optional fully-qualified-name) - "Guess the remote branch name that LOCAL-BRANCH is tracking. -Gives a fully qualified name (e.g., refs/remotes/origin/master) if -FULLY-QUALIFIED-NAME is non-nil." - (let ((merge (magit-get "branch" local-branch "merge"))) - (save-match-data - (if (and merge (string-match "^refs/heads/\\(.+\\)" merge)) - (concat (if fully-qualified-name - (let ((remote-name (magit-get "branch" local-branch "remote"))) - (if (string= "." remote-name) - "refs/heads/" - (concat "refs/remotes/" remote-name "/")))) - (match-string 1 merge)))))) - -;;; Status - -(defvar magit-remote-string-hook nil) - -(defun magit-remote-string (remote remote-branch remote-rebase) - (cond - ((string= "." remote) - (concat - (when remote-rebase "onto ") - "branch " - (propertize remote-branch 'face 'magit-branch))) - (remote - (concat - (when remote-rebase "onto ") - (propertize remote-branch 'face 'magit-branch) - " @ " - remote - " (" - (magit-get "remote" remote "url") - ")")) - (t - (run-hook-with-args-until-success 'magit-remote-string-hook)))) - -(declare-function magit--bisect-info-for-status "magit-bisect" (branch)) - -(defun magit-refresh-status () - (magit-create-buffer-sections - (magit-with-section 'status nil - (let* ((branch (magit-get-current-branch)) - (remote (and branch (magit-get "branch" branch "remote"))) - (remote-rebase (and branch (magit-get-boolean "branch" branch "rebase"))) - (remote-branch (or (and branch (magit-remote-branch-for branch)) branch)) - (remote-string (magit-remote-string remote remote-branch remote-rebase)) - (head (magit-git-string - "log" - "--max-count=1" - "--abbrev-commit" - (format "--abbrev=%s" magit-sha1-abbrev-length) - "--pretty=oneline")) - (no-commit (not head))) - (when remote-string - (insert "Remote: " remote-string "\n")) - (insert (format "Local: %s %s\n" - (propertize (magit--bisect-info-for-status branch) - 'face 'magit-branch) - (abbreviate-file-name default-directory))) - (insert (format "Head: %s\n" - (if no-commit "nothing commited (yet)" head))) - (let ((merge-heads (magit-file-lines (concat (magit-git-dir) - "MERGE_HEAD")))) - (if merge-heads - (insert (format "Merging: %s\n" - (mapconcat 'identity - (mapcar 'magit-name-rev merge-heads) - ", "))))) - (let ((rebase (magit-rebase-info))) - (if rebase - (insert (apply 'format "Rebasing: onto %s (%s of %s); Press \"R\" to Abort, Skip, or Continue\n" rebase)))) - (insert "\n") - (magit-git-exit-code "update-index" "--refresh") - (magit-insert-stashes) - (magit-insert-untracked-files) - (magit-insert-pending-changes) - (magit-insert-pending-commits) - (magit-insert-unpulled-commits remote remote-branch) - (let ((staged (or no-commit (magit-anything-staged-p)))) - (magit-insert-unstaged-changes - (if staged "Unstaged changes:" "Changes:")) - (magit-insert-staged-changes staged no-commit)) - (magit-insert-unpushed-commits remote remote-branch) - (run-hooks 'magit-refresh-status-hook))))) - -(defun magit-init (dir) - "Initialize git repository in the DIR directory." - (interactive (list (read-directory-name "Directory for Git repository: "))) - (let* ((dir (file-name-as-directory (expand-file-name dir))) - (topdir (magit-get-top-dir dir))) - (when (or (not topdir) - (yes-or-no-p - (format - (if (string-equal topdir dir) - "There is already a Git repository in %s. Reinitialize? " - "There is a Git repository in %s. Create another in %s? ") - topdir dir))) - (unless (file-directory-p dir) - (and (y-or-n-p (format "Directory %s does not exists. Create it? " dir)) - (make-directory dir))) - (let ((default-directory dir)) - (magit-run* (list magit-git-executable "init")))))) - -(define-derived-mode magit-status-mode magit-mode "Magit" - "Mode for looking at git status. - -\\{magit-status-mode-map}" - :group 'magit) - -(defvar magit-default-directory nil) - -(defun magit-save-some-buffers (&optional msg pred) - "Save some buffers if variable `magit-save-some-buffers' is non-nil. -If variable `magit-save-some-buffers' is set to 'dontask then -don't ask the user before saving the buffers, just go ahead and -do it. - -Optional argument MSG is displayed in the minibuffer if variable -`magit-save-some-buffers' is nil. - -Optional second argument PRED determines which buffers are considered: -If PRED is nil, all the file-visiting buffers are considered. -If PRED is t, then certain non-file buffers will also be considered. -If PRED is a zero-argument function, it indicates for each buffer whether -to consider it or not when called with that buffer current." - (interactive) - (let ((predicate-function (or pred magit-save-some-buffers-predicate)) - (magit-default-directory default-directory)) - (if magit-save-some-buffers - (save-some-buffers - (eq magit-save-some-buffers 'dontask) - predicate-function) - (when msg - (message msg))))) - -(defun magit-save-buffers-predicate-all () - "Prompt to save all buffers with unsaved changes" - t) - -(defun magit-save-buffers-predicate-tree-only () - "Only prompt to save buffers which are within the current git project (as - determined by the dir passed to `magit-status'." - (and buffer-file-name - (string= (magit-get-top-dir magit-default-directory) - (magit-get-top-dir (file-name-directory buffer-file-name))))) - -;;;###autoload -(defun magit-status (dir) - "Open a Magit status buffer for the Git repository containing -DIR. If DIR is not within a Git repository, offer to create a -Git repository in DIR. - -Interactively, a prefix argument means to ask the user which Git -repository to use even if `default-directory' is under Git control. -Two prefix arguments means to ignore `magit-repo-dirs' when asking for -user input." - (interactive (list (if current-prefix-arg - (magit-read-top-dir - (> (prefix-numeric-value current-prefix-arg) - 4)) - (or (magit-get-top-dir default-directory) - (magit-read-top-dir nil))))) - (magit-save-some-buffers) - (let ((topdir (magit-get-top-dir dir))) - (unless topdir - (when (y-or-n-p (format "There is no Git repository in %S. Create one? " - dir)) - (magit-init dir) - (setq topdir (magit-get-top-dir dir)))) - (when topdir - (let ((buf (or (magit-find-status-buffer topdir) - (generate-new-buffer - (concat "*magit: " - (file-name-nondirectory - (directory-file-name topdir)) "*"))))) - (funcall magit-status-buffer-switch-function buf) - (magit-mode-init topdir 'magit-status-mode #'magit-refresh-status))))) - -(magit-define-command automatic-merge (revision) - "Merge REVISION into the current 'HEAD'; commit unless merge fails. -\('git merge REVISION')." - (interactive (list (magit-read-rev "Merge" (magit-guess-branch)))) - (if revision - (magit-run-git "merge" (magit-rev-to-git revision)))) - -(magit-define-command manual-merge (revision) - "Merge REVISION into the current 'HEAD'; commit unless merge fails. -\('git merge REVISION')." - (interactive (list (magit-read-rev "Merge" (magit-guess-branch)))) - (when revision - (apply 'magit-run-git - "merge" "--no-commit" - (magit-rev-to-git revision) - magit-custom-options) - (when (file-exists-p ".git/MERGE_MSG") - (magit-log-edit)))) - -;;; Staging and Unstaging - -(defun magit-stage-item (&optional ask) - "Add the item at point to the staging area. -If ASK is set, ask for the file name rather than picking the one -at point." - (interactive "P") - (if ask - (magit-run-git "add" (read-file-name "File to stage: ")) - (magit-section-action (item info "stage") - ((untracked file) - (magit-run-git "add" info)) - ((untracked) - (apply #'magit-run-git "add" "--" - (magit-git-lines "ls-files" "--other" "--exclude-standard"))) - ((unstaged diff hunk) - (if (magit-hunk-item-is-conflict-p item) - (error (concat "Can't stage individual resolution hunks. " - "Please stage the whole file."))) - (magit-apply-hunk-item item "--cached")) - ((unstaged diff) - (magit-run-git "add" "-u" (magit-diff-item-file item))) - ((staged *) - (error "Already staged")) - ((diff diff) - (save-excursion - (magit-goto-parent-section) - (magit-stage-item))) - ((diff diff hunk) - (save-excursion - (magit-goto-parent-section) - (magit-goto-parent-section) - (magit-stage-item))) - ((hunk) - (error "Can't stage this hunk")) - ((diff) - (error "Can't stage this diff"))))) - -(defun magit-unstage-item () - "Remove the item at point from the staging area." - (interactive) - (magit-section-action (item info "unstage") - ((staged diff hunk) - (magit-apply-hunk-item-reverse item "--cached")) - ((staged diff) - (if (eq (car info) 'unmerged) - (error "Can't unstage an unmerged file. Resolve it first")) - (if (magit-no-commit-p) - (magit-run-git "rm" "--cached" "--" (magit-diff-item-file item)) - (magit-run-git "reset" "-q" "HEAD" "--" (magit-diff-item-file item)))) - ((unstaged *) - (error "Already unstaged")) - ((diff diff) - (save-excursion - (magit-goto-parent-section) - (magit-unstage-item))) - ((diff diff hunk) - (save-excursion - (magit-goto-parent-section) - (magit-goto-parent-section) - (magit-unstage-item))) - ((hunk) - (error "Can't unstage this hunk")) - ((diff) - (error "Can't unstage this diff")))) - -(defun magit-stage-all (&optional also-untracked-p) - "Add all remaining changes in tracked files to staging area. -With prefix argument, add remaining untracked files as well. -\('git add -u .' or 'git add .', respectively)." - (interactive "P") - (if also-untracked-p - (magit-run-git "add" ".") - (magit-run-git "add" "-u" "."))) - -(defun magit-unstage-all () - "Remove all changes from staging area. -\('git reset --mixed HEAD')." - (interactive) - (magit-run-git "reset" "HEAD")) - -;;; Branches - -(defun escape-branch-name (branch) - "Escapes branch names to remove problematic characters." - (replace-regexp-in-string "[/]" "-" branch)) - -(defun magit-default-tracking-name-remote-plus-branch - (remote branch) - "Use the remote name plus a hyphen plus the escaped branch name for tracking branches." - (concat remote "-" (escape-branch-name branch))) - -(defun magit-default-tracking-name-branch-only - (remote branch) - "Use just the escaped branch name for tracking branches." - (escape-branch-name branch)) - -(defun magit-get-tracking-name (remote branch) - "Given a REMOTE and a BRANCH name, ask the user for a local -tracking brach name suggesting a sensible default." - (when (yes-or-no-p - (format "Create local tracking branch for %s? " branch)) - (let* ((default-name - (funcall magit-default-tracking-name-function remote branch)) - (chosen-name (read-string (format "Call local branch (%s): " default-name) - nil - nil - default-name))) - (when (magit-ref-exists-p (concat "refs/heads/" chosen-name)) - (error "'%s' already exists." chosen-name)) - chosen-name))) - -(defun magit-maybe-create-local-tracking-branch (rev) - "Depending on the users wishes, create a tracking branch for -rev... maybe." - (if (string-match "^\\(?:refs/\\)?remotes/\\([^/]+\\)/\\(.+\\)" rev) - (let* ((remote (match-string 1 rev)) - (branch (match-string 2 rev)) - (tracker-name (magit-get-tracking-name remote branch))) - (when tracker-name - (magit-run-git "checkout" "-b" tracker-name rev) - t)) - nil)) - -(magit-define-command checkout (revision) - "Switch 'HEAD' to REVISION and update working tree. -Fails if working tree or staging area contain uncommitted changes. -If REVISION is a remote branch, offer to create a local tracking branch. -\('git checkout [-b] REVISION')." - (interactive - (list (let ((current-branch (magit-get-current-branch)) - (default (magit-default-rev))) - (magit-read-rev "Switch to" - (unless (string= current-branch default) - default) - (if current-branch - (cons (concat "refs/heads/" current-branch "$") - magit-uninteresting-refs) - magit-uninteresting-refs))))) - (if revision - (when (not (magit-maybe-create-local-tracking-branch revision)) - (magit-save-some-buffers) - (magit-run-git "checkout" (magit-rev-to-git revision)) - (magit-update-vc-modeline default-directory)))) - -(defun magit-read-create-branch-args () - (let* ((cur-branch (magit-get-current-branch)) - (cur-point (magit-default-rev)) - (branch (read-string "Create branch: ")) - (parent (magit-read-rev "Parent" - (cond - ((eq magit-create-branch-behaviour 'at-point) cur-point) - ((eq magit-create-branch-behaviour 'at-head) cur-branch) - (t cur-branch))))) - (list branch parent))) - -(magit-define-command create-branch (branch parent) - "Switch 'HEAD' to new BRANCH at revision PARENT and update working tree. -Fails if working tree or staging area contain uncommitted changes. -\('git checkout -b BRANCH REVISION')." - (interactive (magit-read-create-branch-args)) - (when (and branch (not (string= branch "")) - parent) - (magit-save-some-buffers) - (magit-run-git "checkout" "-b" - branch - (append - magit-custom-options - (magit-rev-to-git parent))) - (magit-update-vc-modeline default-directory))) - -(defun magit-delete-branch (branch &optional force) - "Deletes a branch. -If the branch is the current one, offers to switch to `master' first. -With prefix, forces the removal even if it hasn't been merged. -Works with local or remote branches. -\('git branch [-d|-D] BRANCH' or 'git push :refs/heads/BRANCH')." - (interactive (list (magit-read-rev "Branch to delete" (magit-default-rev 'notrim)) - current-prefix-arg)) - (let* ((remote (magit-remote-part-of-branch branch)) - (is-current (string= branch (magit-get-current-branch))) - (args (list "branch" - (if force "-D" "-d") - branch))) - (cond - (remote - (magit-run-git "push" remote (concat ":refs/heads/" (magit-branch-no-remote branch)))) - (is-current - (when (y-or-n-p "Cannot delete current branch. Switch to master first? ") - (progn - (magit-checkout "master") - (apply 'magit-run-git args)) - (message "The current branch was not deleted."))) - (t - (apply 'magit-run-git args))))) - -(defun magit-move-branch (old new &optional force) - "Renames or moves a branch. -With prefix, forces the move even if NEW already exists. -\('git branch [-m|-M] OLD NEW')." - (interactive (list (magit-read-rev "Old name" (magit-default-rev)) - (read-string "New name: ") - current-prefix-arg)) - (magit-run-git "branch" (if force - "-M" - "-m") - (magit-rev-to-git old) new)) - -(defun magit-guess-branch () - (magit-section-case (item info) - ((branch) - (magit-section-info (magit-current-section))) - ((wazzup commit) - (magit-section-info (magit-section-parent item))) - ((commit) (magit-name-rev (substring info 0 magit-sha1-abbrev-length))) - ((wazzup) info))) - -;;; Remotes - -(defun magit-add-remote (remote url) - "Adds a remote and fetches it. -\('git remote add REMOTE URL')." - (interactive (list (read-string "Add remote: ") - (read-string "URL: "))) - (magit-run-git "remote" "add" "-f" remote url)) - -(defun magit-remove-remote (remote) - "Deletes a remote. -\('git remote rm REMOTE')." - (interactive (list (magit-read-remote "Remote to delete"))) - (magit-run-git "remote" "rm" remote)) - -(defun magit-rename-remote (old new) - "Renames a remote. -\('git remote rename OLD NEW')." - (interactive (list (magit-read-remote "Old name") - (read-string "New name: "))) - (magit-run-git "remote" "rename" old new)) - -(defun magit-guess-remote () - (magit-section-case (item info) - ((branch) - (magit-section-info (magit-section-parent item))) - ((remote) - info) - (t - (if (string= info ".") - info - (magit-get-current-remote))))) - -;;; Merging - -(defun magit-merge (revision) - "Merge REVISION into the current 'HEAD'; leave changes uncommitted. -With a prefix-arg, the merge will be squashed. -\('git merge --no-commit [--squash|--no-ff] REVISION')." - (interactive - (list (magit-read-rev "Merge" (magit-default-rev)))) - (if revision - (apply 'magit-run-git - "merge" - (magit-rev-to-git revision) - magit-custom-options))) - -;;; Rebasing - -(defun magit-rebase-info () - "Returns a list indicating the state of an in-progress rebase, -if any." - (let ((git-dir (magit-git-dir))) - (cond ((file-exists-p (concat git-dir "rebase-merge")) - (list - ;; The commit we're rebasing onto, i.e. git rebase -i - (magit-name-rev (car (magit-file-lines (concat git-dir "rebase-merge/onto")))) - - ;; How many commits we've gone through - (length (magit-file-lines (concat git-dir "rebase-merge/done"))) - - ;; How many commits we have in total, without the comments - ;; at the end of git-rebase-todo.backup - (let ((todo-lines-with-comments (magit-file-lines (concat git-dir "rebase-merge/git-rebase-todo.backup")))) - (loop for i in todo-lines-with-comments - until (string= "" i) - count i)))) - ((and (file-exists-p (concat git-dir "rebase-apply")) - (file-exists-p (concat git-dir "rebase-apply/onto"))) - ;; we might be here because a non-interactive rebase failed: the - ;; patches didn't apply cleanly - (list - ;; The commit we're rebasing onto, i.e. git rebase -i - (magit-name-rev (car (magit-file-lines (concat git-dir "rebase-apply/onto")))) - - ;; How many commits we've gone through - (- (string-to-number (car (magit-file-lines (concat git-dir "rebase-apply/next")))) 1) - - ;; How many commits we have in total - (string-to-number (car (magit-file-lines (concat git-dir "rebase-apply/last")))) - )) - (t nil)))) - -(defun magit-rebase-step () - (interactive) - (let ((info (magit-rebase-info))) - (if (not info) - (let* ((current-branch (magit-get-current-branch)) - (rev (magit-read-rev "Rebase to" - (magit-format-ref (magit-remote-branch-for current-branch t)) - (if current-branch - (cons (concat "refs/heads/" current-branch) - magit-uninteresting-refs) - magit-uninteresting-refs)))) - (if rev - (magit-run-git "rebase" (magit-rev-to-git rev)))) - (let ((cursor-in-echo-area t) - (message-log-max nil)) - (message "Rebase in progress. [A]bort, [S]kip, or [C]ontinue? ") - (let ((reply (read-event))) - (case reply - ((?A ?a) - (magit-run-git-async "rebase" "--abort")) - ((?S ?s) - (magit-run-git-async "rebase" "--skip")) - ((?C ?c) - (magit-run-git-async "rebase" "--continue")))))))) - -;;; Resetting - -(magit-define-command reset-head (revision &optional hard) - "Switch 'HEAD' to REVISION, keeping prior working tree and staging area. -Any differences from REVISION become new changes to be committed. -With prefix argument, all uncommitted changes in working tree -and staging area are lost. -\('git reset [--soft|--hard] REVISION')." - (interactive (list (magit-read-rev (format "%s head to" - (if current-prefix-arg - "Hard reset" - "Reset")) - (or (magit-default-rev) - "HEAD^")) - current-prefix-arg)) - (when revision - (magit-run-git "reset" (if hard "--hard" "--soft") - (magit-rev-to-git revision)) - (magit-update-vc-modeline default-directory))) - -(magit-define-command reset-head-hard (revision) - "Switch 'HEAD' to REVISION, losing all changes. -Uncomitted changes in both working tree and staging area are lost. -\('git reset --hard REVISION')." - (interactive (list (magit-read-rev (format "Hard reset head to") - (or (magit-default-rev) - "HEAD")))) - (magit-reset-head revision t)) - -(magit-define-command reset-working-tree (&optional arg) - "Revert working tree and clear changes from staging area. -\('git reset --hard HEAD'). - -With a prefix arg, also remove untracked files. With two prefix args, remove ignored files as well." - (interactive "p") - (let ((include-untracked (>= arg 4)) - (include-ignored (>= arg 16))) - (when (yes-or-no-p (format "Discard all uncommitted changes%s%s? " - (if include-untracked - ", untracked files" - "") - (if include-ignored - ", ignored files" - ""))) - (magit-reset-head-hard "HEAD") - (if include-untracked - (magit-run-git "clean" "-fd" (if include-ignored - "-x" - "")))))) - -;;; Rewriting - -(defun magit-read-rewrite-info () - (when (file-exists-p (concat (magit-git-dir) "magit-rewrite-info")) - (with-temp-buffer - (insert-file-contents (concat (magit-git-dir) "magit-rewrite-info")) - (goto-char (point-min)) - (read (current-buffer))))) - -(defun magit-write-rewrite-info (info) - (with-temp-file (concat (magit-git-dir) "magit-rewrite-info") - (prin1 info (current-buffer)) - (princ "\n" (current-buffer)))) - -(magit-define-inserter pending-commits () - (let* ((info (magit-read-rewrite-info)) - (pending (cdr (assq 'pending info)))) - (when pending - (magit-with-section 'pending nil - (insert (propertize "Pending commits:\n" - 'face 'magit-section-title)) - (dolist (p pending) - (let* ((commit (car p)) - (properties (cdr p)) - (used (plist-get properties 'used))) - (magit-with-section commit 'commit - (magit-set-section-info commit) - (insert (magit-git-string - "log" "--max-count=1" - (if used - "--pretty=format:. %s" - "--pretty=format:* %s") - commit "--") - "\n"))))) - (insert "\n")))) - -(defun magit-rewrite-set-commit-property (commit prop value) - (let* ((info (magit-read-rewrite-info)) - (pending (cdr (assq 'pending info))) - (p (assoc commit pending))) - (when p - (setf (cdr p) (plist-put (cdr p) prop value)) - (magit-write-rewrite-info info) - (magit-need-refresh)))) - -(defun magit-rewrite-set-used () - (interactive) - (magit-section-action (item info) - ((pending commit) - (magit-rewrite-set-commit-property info 'used t)))) - -(defun magit-rewrite-set-unused () - (interactive) - (magit-section-action (item info) - ((pending commit) - (magit-rewrite-set-commit-property info 'used nil)))) - -(magit-define-inserter pending-changes () - (let* ((info (magit-read-rewrite-info)) - (orig (cadr (assq 'orig info)))) - (when orig - (let ((magit-hide-diffs t)) - (magit-git-section 'pending-changes - "Pending changes" - 'magit-wash-diffs - "diff" (magit-diff-U-arg) "-R" orig))))) - -(defun magit-rewrite-start (from &optional onto) - (interactive (list (magit-read-rev "Rewrite from" (magit-default-rev)))) - (or (magit-everything-clean-p) - (error "You have uncommitted changes")) - (or (not (magit-read-rewrite-info)) - (error "Rewrite in progress")) - (let* ((orig (magit-rev-parse "HEAD")) - (base - (if - (or - (eq magit-rewrite-inclusive t) - (and - (eq magit-rewrite-inclusive 'ask) - (y-or-n-p "Include selected revision in rewrite? "))) - (or - (car (magit-commit-parents from)) - (error "Can't rewrite a parentless commit.")) - from)) - (pending (magit-git-lines "rev-list" (concat base "..")))) - (magit-write-rewrite-info `((orig ,orig) - (pending ,@(mapcar #'list pending)))) - (magit-run-git "reset" "--hard" base))) - -(defun magit-rewrite-stop (&optional noconfirm) - (interactive) - (let* ((info (magit-read-rewrite-info))) - (or info - (error "No rewrite in progress")) - (when (or noconfirm - (yes-or-no-p "Stop rewrite? ")) - (magit-write-rewrite-info nil) - (magit-refresh)))) - -(defun magit-rewrite-abort () - (interactive) - (let* ((info (magit-read-rewrite-info)) - (orig (cadr (assq 'orig info)))) - (or info - (error "No rewrite in progress")) - (or (magit-everything-clean-p) - (error "You have uncommitted changes")) - (when (yes-or-no-p "Abort rewrite? ") - (magit-write-rewrite-info nil) - (magit-run-git "reset" "--hard" orig)))) - -(defun magit-rewrite-finish () - (interactive) - (magit-with-refresh - (magit-rewrite-finish-step t))) - -(defun magit-rewrite-finish-step (first-p) - (let ((info (magit-read-rewrite-info))) - (or info - (error "No rewrite in progress")) - (let* ((pending (cdr (assq 'pending info))) - (first-unused - (let ((rpend (reverse pending))) - (while (and rpend (plist-get (cdr (car rpend)) 'used)) - (setq rpend (cdr rpend))) - (car rpend))) - (commit (car first-unused))) - (cond ((not first-unused) - (magit-rewrite-stop t)) - ((magit-apply-commit commit t (not first-p)) - (magit-rewrite-set-commit-property commit 'used t) - (magit-rewrite-finish-step nil)))))) - -;;; Updating, pull, and push - -(magit-define-command fetch (remote) - "Fetch from REMOTE." - (interactive (list (magit-read-remote))) - (apply 'magit-run-git-async "fetch" remote magit-custom-options)) - -(magit-define-command fetch-current () - "Run fetch for default remote. - -If there is no default remote, ask for one." - (interactive) - (magit-fetch (or (magit-get-current-remote) - (magit-read-remote)))) - -(magit-define-command remote-update () - "Update all remotes." - (interactive) - (apply 'magit-run-git-async "remote" "update" magit-custom-options)) - -(magit-define-command pull () - "Run git pull against the current remote." - (interactive) - (let* ((branch (magit-get-current-branch)) - (branch-remote (magit-get-remote branch)) - (config-branch (and branch (magit-get "branch" branch "merge"))) - (merge-branch (or (and config-branch (not current-prefix-arg)) - (magit-read-remote-branch - branch-remote (format "Pull from: "))))) - (when (and branch (not config-branch)) - (magit-set branch-remote "branch" branch "remote") - (magit-set (format "refs/heads/%s" merge-branch) - "branch" branch "merge")) - (apply 'magit-run-git-async "pull" "-v" magit-custom-options))) - -(eval-when-compile (require 'eshell)) - -(defun magit-parse-arguments (command) - (require 'eshell) - (with-temp-buffer - (insert command) - (mapcar 'eval (eshell-parse-arguments (point-min) (point-max))))) - -(defun magit-shell-command (command) - "Perform arbitrary shell COMMAND." - (interactive "sCommand: ") - (let ((args (magit-parse-arguments command)) - (magit-process-popup-time 0)) - (magit-run* args nil nil nil t))) - -(defvar magit-git-command-history nil) - -(defun magit-git-command (command) - "Perform arbitrary Git COMMAND. - -Similar to `magit-shell-command', but involves slightly less -typing and automatically refreshes the status buffer." - (interactive - (list (read-string "Run git like this: " nil 'magit-git-command-history))) - (require 'pcomplete) - (let ((args (magit-parse-arguments command)) - (magit-process-popup-time 0)) - (magit-with-refresh - (magit-run* (append (cons magit-git-executable - magit-git-standard-options) - args) - nil nil nil t)))) - -(magit-define-command push-tags () - "Push tags." - (interactive) - (magit-run-git-async "push" "--tags")) - -(magit-define-command push () - "Push the current branch to a remote repository. - -With no prefix argument, ask `magit-get-remote' what remote to -use for this branch. - -With a prefix arg \(e.g., \\[universal-argument] \\[magit-push]), \ -ask user instead. - -With \\[universal-argument] \\[universal-argument] as prefix, \ -also prompt user for the remote branch; -otherwise, try to use the branch..merge git-config(1) -option, falling back to something hairy if that is unset." - (interactive) - (let* ((branch (or (magit-get-current-branch) - (error "Don't push a detached head. That's gross"))) - (branch-remote (magit-get-remote branch)) - (push-remote (if (or current-prefix-arg - (not branch-remote)) - (magit-read-remote (format "Push %s to remote" - branch) - branch-remote) - branch-remote)) - (ref-branch (or (and (>= (prefix-numeric-value current-prefix-arg) 16) - (magit-read-remote-branch - push-remote (format "Push %s as branch" branch))) - (magit-get "branch" branch "merge")))) - (if (and (not ref-branch) - (eq magit-set-upstream-on-push 'refuse)) - (error "Not pushing since no upstream has been set.") - (let ((set-upstream-on-push (and (not ref-branch) - (or (eq magit-set-upstream-on-push 'dontask) - (and (eq magit-set-upstream-on-push t) - (yes-or-no-p "Set upstream while pushing? ")))))) - (if (and (not branch-remote) - (not current-prefix-arg)) - (magit-set push-remote "branch" branch "remote")) - (apply 'magit-run-git-async "push" "-v" push-remote - (if ref-branch - (format "%s:%s" branch ref-branch) - branch) - (if set-upstream-on-push - (cons "--set-upstream" magit-custom-options) - magit-custom-options)) - ;; Although git will automatically set up the remote, - ;; it doesn't set up the branch to merge (at least as of Git 1.6.6.1), - ;; so we have to do that manually. - (unless ref-branch - (magit-set (concat "refs/heads/" branch) "branch" branch "merge")))))) - -;;; Log edit mode - -(defvar magit-log-edit-buffer-name "*magit-edit-log*" - "Buffer name for composing commit messages.") - -(defvar magit-log-edit-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "C-c C-c") 'magit-log-edit-commit) - (define-key map (kbd "C-x #") 'magit-log-edit-commit) - (define-key map (kbd "C-c C-a") 'magit-log-edit-toggle-amending) - (define-key map (kbd "C-c C-s") 'magit-log-edit-toggle-signoff) - (define-key map (kbd "C-c C-t") 'magit-log-edit-toggle-author) - (define-key map (kbd "C-c C-e") 'magit-log-edit-toggle-allow-empty) - (define-key map (kbd "M-p") 'log-edit-previous-comment) - (define-key map (kbd "M-n") 'log-edit-next-comment) - (define-key map (kbd "C-c C-k") 'magit-log-edit-cancel-log-message) - (define-key map (kbd "C-c C-]") 'magit-log-edit-cancel-log-message) - (define-key map (kbd "C-x C-s") (lambda () - (interactive) - (message "Not saved. Use C-c C-c to finalize this commit message."))) - map)) - -(defvar magit-pre-log-edit-window-configuration nil) - -(define-derived-mode magit-log-edit-mode text-mode "Magit Log Edit" - ;; Recognize changelog-style paragraphs - (set (make-local-variable 'paragraph-start) - (concat paragraph-start "\\|*\\|("))) - -(defun magit-log-edit-cleanup () - (save-excursion - (goto-char (point-min)) - (goto-char (point-min)) - (if (re-search-forward "[ \t\n]*\\'" nil t) - (replace-match "\n" nil nil)))) - -(defun magit-log-edit-append (str) - (with-current-buffer (get-buffer-create magit-log-edit-buffer-name) - (goto-char (point-max)) - (insert str "\n"))) - -(defconst magit-log-header-end "-- End of Magit header --\n") - -(defun magit-log-edit-get-fields () - (let ((buf (get-buffer magit-log-edit-buffer-name)) - (result nil)) - (if buf - (with-current-buffer buf - (goto-char (point-min)) - (while (looking-at "^\\([A-Za-z0-9-_]+\\): *\\(.+\\)?$") - (setq result (acons (intern (downcase (match-string 1))) - (read (or (match-string 2) "nil")) - result)) - (forward-line)) - (if (not (looking-at (regexp-quote magit-log-header-end))) - (setq result nil)))) - (nreverse result))) - -(defun magit-log-edit-set-fields (fields) - (let ((buf (get-buffer-create magit-log-edit-buffer-name))) - (with-current-buffer buf - (goto-char (point-min)) - (if (search-forward-regexp (format "^\\([A-Za-z0-9-_]+:.*\n\\)*%s" - (regexp-quote magit-log-header-end)) - nil t) - (delete-region (match-beginning 0) (match-end 0))) - (goto-char (point-min)) - (when fields - (while fields - (insert (capitalize (symbol-name (caar fields))) ": " - (prin1-to-string (cdar fields)) "\n") - (setq fields (cdr fields))) - (insert magit-log-header-end))))) - -(defun magit-log-edit-set-field (name value) - (let* ((fields (magit-log-edit-get-fields)) - (cell (assq name fields))) - (cond (cell - (if value - (rplacd cell value) - (setq fields (delq cell fields)))) - (t - (if value - (setq fields (append fields (list (cons name value))))))) - (magit-log-edit-set-fields fields))) - -(defun magit-log-edit-get-field (name) - (cdr (assq name (magit-log-edit-get-fields)))) - -(defun magit-log-edit-toggle-field (name default) - "Toggle the log-edit field named NAME. -If it's currently unset, set it to DEFAULT (t or nil). - -Return nil if the field is toggled off, and non-nil if it's -toggled on. When it's toggled on for the first time, return -'first." - (let* ((fields (magit-log-edit-get-fields)) - (cell (assq name fields)) yesp) - (if cell - (progn - (setq yesp (equal (cdr cell) "yes")) - (rplacd cell (if yesp "no" "yes"))) - (setq fields (acons name (if default "yes" "no") fields)) - (setq yesp (if default 'first))) - (magit-log-edit-set-fields fields) - yesp)) - -(defun magit-log-edit-toggle-input (name default) - "Toggle the log-edit input named NAME. -If it's currently unset, set it to DEFAULT (a string). If it is -set remove it. - -Return nil if the input is toggled off, and its valud if it's -toggled on." - (let* ((fields (magit-log-edit-get-fields)) - (cell (assq name fields)) - result) - (if cell - (progn - (setq fields (assq-delete-all name fields) - result (cdr cell))) - (setq fields (acons name default fields))) - (magit-log-edit-set-fields fields) - result)) - -(defun magit-log-edit-setup-author-env (author) - "Set GIT_AUTHOR_* variables from AUTHOR spec. -If AUTHOR is nil, honor default values from -environment (potentially empty)." - (when author - ;; XXX - this is a bit strict, probably. - (or (string-match "\\(.*\\) <\\(.*\\)>\\(?:,\\s-*\\(.+\\)\\)?" author) - (error "Can't parse author string")) - ;; Shucks, setenv destroys the match data. - (let ((name (match-string 1 author)) - (email (match-string 2 author)) - (date (match-string 3 author))) - (make-local-variable 'process-environment) - (setenv "GIT_AUTHOR_NAME" name) - (setenv "GIT_AUTHOR_EMAIL" email) - (if date - (setenv "GIT_AUTHOR_DATE" date))))) - -(defun magit-log-edit-push-to-comment-ring (comment) - (when (or (ring-empty-p log-edit-comment-ring) - (not (equal comment (ring-ref log-edit-comment-ring 0)))) - (ring-insert log-edit-comment-ring comment))) - -(defun magit-log-edit-commit () - "Finish edits and create new commit object. -\('git commit ...')" - (interactive) - (let* ((fields (magit-log-edit-get-fields)) - (amend (equal (cdr (assq 'amend fields)) "yes")) - (allow-empty (equal (cdr (assq 'allow-empty fields)) "yes")) - (commit-all (equal (cdr (assq 'commit-all fields)) "yes")) - (sign-off-field (assq 'sign-off fields)) - (sign-off (if sign-off-field - (equal (cdr sign-off-field) "yes") - magit-commit-signoff)) - (tag-rev (cdr (assq 'tag-rev fields))) - (tag-name (cdr (assq 'tag-name fields))) - (author (cdr (assq 'author fields))) - (tag-options (cdr (assq 'tag-options fields)))) - - (unless (or (magit-anything-staged-p) - allow-empty - amend - tag-name - (file-exists-p (concat (magit-git-dir) "MERGE_HEAD")) - (and commit-all - (not (magit-everything-clean-p)))) - (error "Refusing to create empty commit. Maybe you want to amend (%s) or allow-empty (%s)?" - (key-description (car (where-is-internal - 'magit-log-edit-toggle-amending))) - (key-description (car (where-is-internal - 'magit-log-edit-toggle-allow-empty))))) - - (magit-log-edit-push-to-comment-ring (buffer-string)) - (magit-log-edit-setup-author-env author) - (magit-log-edit-set-fields nil) - (magit-log-edit-cleanup) - (if (= (buffer-size) 0) - (insert "(Empty description)\n")) - (let ((env process-environment) - (commit-buf (current-buffer))) - (with-current-buffer (magit-find-status-buffer default-directory) - (let ((process-environment env)) - (cond (tag-name - (apply #'magit-run-git-with-input commit-buf - "tag" (append tag-options (list tag-name "-a" "-F" "-" tag-rev)))) - (t - (apply #'magit-run-async-with-input commit-buf - magit-git-executable - (append magit-git-standard-options - '("commit") - magit-custom-options - '("-F" "-") - (if (and commit-all (not allow-empty)) '("--all") '()) - (if amend '("--amend") '()) - (if allow-empty '("--allow-empty")) - (if sign-off '("--signoff") '())))))))) - ;; shouldn't we kill that buffer altogether? - (erase-buffer) - (let ((magit-buf magit-buffer-internal)) - (bury-buffer) - (set-buffer magit-buf)) - (when (file-exists-p (concat (magit-git-dir) "MERGE_MSG")) - (delete-file (concat (magit-git-dir) "MERGE_MSG"))) - ;; potentially the local environment has been altered with settings that - ;; were specific to this commit. Let's revert it - (kill-local-variable 'process-environment) - (magit-update-vc-modeline default-directory) - (when magit-pre-log-edit-window-configuration - (set-window-configuration magit-pre-log-edit-window-configuration) - (setq magit-pre-log-edit-window-configuration nil)))) - -(defun magit-log-edit-cancel-log-message () - "Abort edits and erase commit message being composed." - (interactive) - (when (or (not magit-log-edit-confirm-cancellation) - (yes-or-no-p - "Really cancel editing the log (any changes will be lost)?")) - (erase-buffer) - (bury-buffer) - (when magit-pre-log-edit-window-configuration - (set-window-configuration magit-pre-log-edit-window-configuration) - (setq magit-pre-log-edit-window-configuration nil)))) - -(defun magit-log-edit-toggle-amending () - "Toggle whether this will be an amendment to the previous commit. -\(i.e., whether eventual commit does 'git commit --amend')" - (interactive) - (when (eq (magit-log-edit-toggle-field 'amend t) 'first) - (magit-log-edit-append - (magit-trim-line (magit-format-commit "HEAD" "%s%n%n%b"))))) - -(defun magit-log-edit-toggle-signoff () - "Toggle whether this commit will include a signoff. -\(i.e., whether eventual commit does 'git commit --signoff')" - (interactive) - (magit-log-edit-toggle-field 'sign-off (not magit-commit-signoff))) - -(defun magit-log-edit-toggle-author () - "Toggle whether this commit will include an author. -\(i.e., whether eventual commit is run with GIT_AUTHOR_NAME and -GIT_AUTHOR_EMAIL set)" - (interactive) - (magit-log-edit-toggle-input 'author (format "%s <%s>" - (or (magit-get "user" "name") "Author Name") - (or (magit-get "user" "email") "author@email")))) - -(defun magit-log-edit-toggle-allow-empty () - "Toggle whether this commit is allowed to be empty. -This means that the eventual commit does 'git commit --allow-empty'." - (interactive) - (magit-log-edit-toggle-field 'allow-empty t)) - -(defun magit-pop-to-log-edit (operation) - (let ((dir default-directory) - (magit-buf (current-buffer)) - (buf (get-buffer-create magit-log-edit-buffer-name))) - (setq magit-pre-log-edit-window-configuration - (current-window-configuration)) - (pop-to-buffer buf) - (setq default-directory dir) - (when (file-exists-p (concat (magit-git-dir) "MERGE_MSG")) - (insert-file-contents (concat (magit-git-dir) "MERGE_MSG"))) - (magit-log-edit-mode) - (make-local-variable 'magit-buffer-internal) - (setq magit-buffer-internal magit-buf) - (message "Type C-c C-c to %s (C-c C-k to cancel)." operation))) - -(defun magit-log-edit (&optional arg) - "Brings up a buffer to allow editing of commit messages. - -Giving a simple prefix arg will amend a previous commit, while -a double prefix arg will allow creating an empty one. - -If there is a rebase in progress, offer the user the option to -continue it. - -\\{magit-log-edit-mode-map}" - (interactive "P") - ;; If repository is dirty there is no point in trying to - ;; suggest to continue the rebase. Git will rebuke you and exit with - ;; error code, so suggest it only if theres absolutely nothing else - ;; to do and rebase is ongoing. - (if (and (magit-everything-clean-p) - (magit-rebase-info) - (y-or-n-p "Rebase in progress. Continue it? ")) - (magit-run-git-async "rebase" "--continue") - - ;; If there's nothing staged, set commit flag to `nil', thus - ;; avoiding unnescessary popping up of the log edit buffer in case - ;; when user chose to forgo commiting all unstaged changes - (let ((amend-p (= (prefix-numeric-value arg) 4)) - (empty-p (= (prefix-numeric-value arg) 16))) - (when (and magit-commit-all-when-nothing-staged - (not (magit-everything-clean-p)) - (not (magit-anything-staged-p))) - (cond ((eq magit-commit-all-when-nothing-staged 'ask-stage) - (when (y-or-n-p "Nothing staged. Stage everything now? ") - (magit-stage-all))) - ((not (magit-log-edit-get-field 'commit-all)) - (when (or (eq magit-commit-all-when-nothing-staged t) - (y-or-n-p - "Nothing staged. Commit all unstaged changes? ")) - (magit-log-edit-set-field 'commit-all "yes"))))) - (when amend-p - (magit-log-edit-toggle-amending)) - (when empty-p - (magit-log-edit-toggle-allow-empty)) - (let ((author-email (or (getenv "GIT_AUTHOR_EMAIL") "")) - (author-name (or (getenv "GIT_AUTHOR_NAME") "")) - (author-date (or (getenv "GIT_AUTHOR_DATE") ""))) - (if (not (string= author-email "")) - (magit-log-edit-set-field 'author (format "%s <%s>%s" - (if (string= "" author-name) author-email author-name) - author-email - (if (string= "" author-date) "" (format ", %s" author-date)))))) - (magit-pop-to-log-edit "commit")))) - -(defun magit-add-log () - (interactive) - (cond ((magit-rebase-info) - (if (y-or-n-p "Rebase in progress. Continue it? ") - (magit-run-git-async "rebase" "--continue"))) - (t - (let ((section (magit-current-section))) - (let ((fun (if (eq (magit-section-type section) 'hunk) - (save-window-excursion - (save-excursion - (magit-visit-item) - (add-log-current-defun))) - nil)) - (file (magit-diff-item-file - (cond ((eq (magit-section-type section) 'hunk) - (magit-hunk-item-diff section)) - ((eq (magit-section-type section) 'diff) - section) - (t - (error "No change at point")))))) - (magit-log-edit nil) - (goto-char (point-min)) - (cond ((not (search-forward-regexp - (format "^\\* %s" (regexp-quote file)) nil t)) - ;; No entry for file, create it. - (goto-char (point-max)) - (insert (format "\n* %s" file)) - (if fun - (insert (format " (%s)" fun))) - (insert ": ")) - (fun - ;; found entry for file, look for fun - (let ((limit (or (save-excursion - (and (search-forward-regexp "^\\* " - nil t) - (match-beginning 0))) - (point-max)))) - (cond ((search-forward-regexp (format "(.*\\<%s\\>.*):" - (regexp-quote fun)) - limit t) - ;; found it, goto end of current entry - (if (search-forward-regexp "^(" limit t) - (backward-char 2) - (goto-char limit))) - (t - ;; not found, insert new entry - (goto-char limit) - (if (bolp) - (open-line 1) - (newline)) - (insert (format "(%s): " fun)))))) - (t - ;; found entry for file, look for beginning it - (when (looking-at ":") - (forward-char 2))))))))) - -;;; Tags - -(magit-define-command tag (name rev) - "Create a new lightweight tag with the given NAME at REV. -\('git tag NAME')." - (interactive - (list - (read-string "Tag name: ") - (magit-read-rev "Place tag on: " (or (magit-default-rev) "HEAD")))) - (apply #'magit-run-git "tag" (append magit-custom-options (list name rev)))) - -(magit-define-command annotated-tag (name rev) - "Start composing an annotated tag with the given NAME. -Tag will point to the current 'HEAD'." - (interactive - (list - (read-string "Tag name: ") - (magit-read-rev "Place tag on: " (or (magit-default-rev) "HEAD")))) - (magit-log-edit-set-field 'tag-name name) - (magit-log-edit-set-field 'tag-rev rev) - (magit-log-edit-set-field 'tag-options magit-custom-options) - (magit-pop-to-log-edit "tag")) - -;;; Stashing - -(defun magit-wash-stash () - (if (search-forward-regexp "stash@{\\(.*?\\)}" (line-end-position) t) - (let ((stash (match-string-no-properties 0)) - (name (match-string-no-properties 1))) - (delete-region (match-beginning 0) (match-end 0)) - (goto-char (match-beginning 0)) - (fixup-whitespace) - (goto-char (line-beginning-position)) - (insert name) - (goto-char (line-beginning-position)) - (magit-with-section stash 'stash - (magit-set-section-info stash) - (forward-line))) - (forward-line)) - t) - -(defun magit-wash-stashes () - (let ((magit-old-top-section nil)) - (magit-wash-sequence #'magit-wash-stash))) - -(magit-define-inserter stashes () - (magit-git-section 'stashes - "Stashes:" 'magit-wash-stashes - "stash" "list")) - -(magit-define-command stash (description) - "Create new stash of working tree and staging area named DESCRIPTION. -Working tree and staging area revert to the current 'HEAD'. -With prefix argument, changes in staging area are kept. -\('git stash save [--keep-index] DESCRIPTION')" - (interactive "sStash description: ") - (apply 'magit-run-git `("stash" "save" ,@magit-custom-options "--" ,description))) - -(magit-define-command stash-snapshot () - "Create new stash of working tree and staging area; keep changes in place. -\('git stash save \"Snapshot...\"; git stash apply stash@{0}')" - (interactive) - (magit-with-refresh - (apply 'magit-run-git `("stash" "save" ,@magit-custom-options - ,(format-time-string "Snapshot taken at %Y-%m-%d %H:%M:%S" - (current-time)))) - (magit-run-git "stash" "apply" "stash@{0}"))) - -(defvar magit-currently-shown-stash nil) - -(define-derived-mode magit-stash-mode magit-mode "Magit Stash" - "Mode for looking at a git stash. - -\\{magit-stash-mode-map}" - :group 'magit) - -(defvar magit-stash-buffer-name "*magit-stash*" - "Buffer name for displaying a stash.") - -(defun magit-show-stash (stash &optional scroll) - (when (magit-section-p stash) - (setq stash (magit-section-info stash))) - (let ((dir default-directory) - (buf (get-buffer-create magit-stash-buffer-name)) - (stash-id (magit-git-string "rev-list" "-1" stash))) - (cond ((and (equal magit-currently-shown-stash stash-id) - (with-current-buffer buf - (> (length (buffer-string)) 1))) - (let ((win (get-buffer-window buf))) - (cond ((not win) - (display-buffer buf)) - (scroll - (with-selected-window win - (funcall scroll)))))) - (t - (setq magit-currently-shown-stash stash-id) - (display-buffer buf) - (with-current-buffer buf - (set-buffer buf) - (goto-char (point-min)) - (let* ((range (cons (concat stash "^2^") stash)) - (magit-current-diff-range range) - (args (magit-rev-range-to-git range))) - (magit-mode-init dir 'magit-diff-mode #'magit-refresh-diff-buffer - range args))))))) -;;; Commits - -(defun magit-commit-at-point (&optional nil-ok-p) - (let* ((section (magit-current-section)) - (commit (if (and section - (eq (magit-section-type section) 'commit)) - (magit-section-info section) - (get-text-property (point) 'revision)))) - (if nil-ok-p - commit - (or commit - (error "No commit at point"))))) - -(defun magit-apply-commit (commit &optional docommit noerase revert) - (let* ((parent-id (magit-choose-parent-id commit "cherry-pick")) - (success (magit-run* `(,magit-git-executable - ,@magit-git-standard-options - ,(if revert "revert" "cherry-pick") - ,@(if parent-id - (list "-m" (number-to-string parent-id))) - ,@(if (not docommit) (list "--no-commit")) - ,commit) - nil noerase))) - (when (and (not docommit) success) - (cond (revert - (magit-log-edit-append - (magit-format-commit commit "Reverting \"%s\""))) - (t - (magit-log-edit-append - (magit-format-commit commit "%s%n%n%b")) - (magit-log-edit-set-field - 'author - (magit-format-commit commit "%an <%ae>, %ai"))))) - success)) - -(defun magit-apply-item () - (interactive) - (magit-section-action (item info "apply") - ((pending commit) - (magit-apply-commit info) - (magit-rewrite-set-commit-property info 'used t)) - ((commit) - (magit-apply-commit info)) - ((unstaged *) - (error "Change is already in your working tree")) - ((staged *) - (error "Change is already in your working tree")) - ((hunk) - (magit-apply-hunk-item item)) - ((diff) - (magit-apply-diff-item item)) - ((stash) - (magit-run-git "stash" "apply" info)))) - -(defun magit-cherry-pick-item () - (interactive) - (magit-section-action (item info "cherry-pick") - ((pending commit) - (magit-apply-commit info t) - (magit-rewrite-set-commit-property info 'used t)) - ((commit) - (magit-apply-commit info t)) - ((stash) - (magit-run-git "stash" "pop" info)))) - -(defmacro magit-with-revert-confirmation (&rest body) - `(when (or (not magit-revert-item-confirm) - (yes-or-no-p "Really revert this item? ")) - ,@body)) - -(defun magit-revert-item () - (interactive) - (magit-section-action (item info "revert") - ((pending commit) - (magit-with-revert-confirmation - (magit-apply-commit info nil nil t) - (magit-rewrite-set-commit-property info 'used nil))) - ((commit) - (magit-with-revert-confirmation - (magit-apply-commit info nil nil t))) - ;; Reverting unstaged changes cannot be undone - ((unstaged *) - (magit-discard-item)) - ((hunk) - (magit-with-revert-confirmation - (magit-apply-hunk-item-reverse item))) - ((diff) - (magit-with-revert-confirmation - (magit-apply-diff-item item "--reverse"))))) - -(defun magit-log-show-more-entries (&optional arg) - "Grow the number of log entries shown. - -With no prefix optional ARG, show twice as many log entries. -With a numerical prefix ARG, add this number to the number of shown log entries. -With a non numeric prefix ARG, show all entries" - (interactive "P") - (make-local-variable 'magit-log-cutoff-length) - (cond - ((numberp arg) - (setq magit-log-cutoff-length (+ magit-log-cutoff-length arg))) - (arg - (setq magit-log-cutoff-length magit-log-infinite-length)) - (t (setq magit-log-cutoff-length (* magit-log-cutoff-length 2)))) - (let ((old-point (point))) - (magit-refresh) - (goto-char old-point))) - -(defun magit-refresh-log-buffer (range style args) - (magit-configure-have-graph) - (magit-configure-have-decorate) - (magit-configure-have-abbrev) - (setq magit-current-range range) - (magit-create-log-buffer-sections - (apply #'magit-git-section nil - (magit-rev-range-describe range "Commits") - (apply-partially 'magit-wash-log style) - `("log" - ,(format "--max-count=%s" magit-log-cutoff-length) - ,"--abbrev-commit" - ,(format "--abbrev=%s" magit-sha1-abbrev-length) - ,@(cond ((eq style 'long) (list "--stat" "-z")) - ((eq style 'oneline) (list "--pretty=oneline")) - (t nil)) - ,@(if magit-have-decorate (list "--decorate=full")) - ,@(if magit-have-graph (list "--graph")) - ,@args - "--")))) - -(define-derived-mode magit-log-mode magit-mode "Magit Log" - "Mode for looking at git log. - -\\{magit-log-mode-map}" - :group 'magit) - -(defvar magit-log-buffer-name "*magit-log*" - "Buffer name for display of log entries.") - -(magit-define-command log-ranged () - (interactive) - (magit-log t)) -(define-obsolete-function-alias 'magit-display-log-ranged 'magit-log-ranged) - -(magit-define-command log (&optional ask-for-range &rest extra-args) - (interactive) - (let* ((log-range (if ask-for-range - (magit-read-rev-range "Log" "HEAD") - "HEAD")) - (topdir (magit-get-top-dir default-directory)) - (args (nconc (list (magit-rev-range-to-git log-range)) - magit-custom-options - extra-args))) - (magit-buffer-switch magit-log-buffer-name) - (magit-mode-init topdir 'magit-log-mode #'magit-refresh-log-buffer log-range - 'oneline args))) - -(define-obsolete-function-alias 'magit-display-log 'magit-log) - -(magit-define-command log-long-ranged () - (interactive) - (magit-log-long t)) - -(magit-define-command log-long (&optional ranged) - (interactive) - (let* ((range (if ranged - (magit-read-rev-range "Long log" "HEAD") - "HEAD")) - (topdir (magit-get-top-dir default-directory)) - (args (append (list (magit-rev-range-to-git range)) - magit-custom-options))) - (magit-buffer-switch magit-log-buffer-name) - (magit-mode-init topdir 'magit-log-mode #'magit-refresh-log-buffer range - 'long args))) - -;;; Reflog - -(defvar magit-reflog-head nil - "The HEAD of the reflog in the current buffer. -This is only non-nil in reflog buffers.") -(make-variable-buffer-local 'magit-reflog-head) - -(defun magit-refresh-reflog-buffer (head args) - (setq magit-reflog-head head) - (magit-create-log-buffer-sections - (apply #'magit-git-section - 'reflog (format "Local history of head %s" head) 'magit-wash-log "log" - (append magit-git-log-options - (list - "--walk-reflogs" - (format "--max-count=%s" magit-log-cutoff-length) - args))))) - -(define-derived-mode magit-reflog-mode magit-log-mode "Magit Reflog" - "Mode for looking at git reflog. - -\\{magit-reflog-mode-map}" - :group 'magit) - -(magit-define-command reflog (&optional ask-for-range) - (interactive) - (let ((at (or (if ask-for-range - (magit-read-rev "Reflog of" (or (magit-guess-branch) "HEAD"))) - "HEAD"))) - (let* ((topdir (magit-get-top-dir default-directory)) - (args (magit-rev-to-git at))) - (magit-buffer-switch "*magit-reflog*") - (magit-mode-init topdir 'magit-reflog-mode - #'magit-refresh-reflog-buffer at args)))) - -(magit-define-command reflog-ranged () - (interactive) - (magit-reflog t)) - -;;; Diffing - -(defvar magit-ediff-buffers nil - "List of buffers that may be killed by `magit-ediff-restore'.") - -(defvar magit-ediff-windows nil - "The window configuration that will be restored when Ediff is finished.") - -(defun magit-ediff() - "View the current DIFF section in ediff." - (interactive) - (let ((diff (magit-current-section))) - (when (magit-section-hidden diff) - ;; Range is not set until the first time the diff is visible. - ;; This somewhat hackish code makes sure it's been visible at least once. - (magit-toggle-section) - (magit-toggle-section) - (setq diff (magit-current-section))) - (if (eq 'hunk (magit-section-type diff)) - (setq diff (magit-section-parent diff))) - (unless (eq 'diff (magit-section-type diff)) - (error "No diff at this location")) - (let* ((type (magit-diff-item-kind diff)) - (file1 (magit-diff-item-file diff)) - (file2 (magit-diff-item-file2 diff)) - (range (magit-diff-item-range diff))) - (cond - ((memq type '(new deleted typechange)) - (message "Why ediff a %s file?" type)) - ((and (eq type 'unmerged) - (eq (cdr range) 'working)) - (magit-interactive-resolve file1)) - ((consp (car range)) - (magit-ediff* (magit-show (caar range) file2) - (magit-show (cdar range) file2) - (magit-show (cdr range) file1))) - (t - (magit-ediff* (magit-show (car range) file2) - (magit-show (cdr range) file1))))))) - -(defun magit-ediff* (a b &optional c) - (setq magit-ediff-buffers (list a b c)) - (setq magit-ediff-windows (current-window-configuration)) - (add-hook 'ediff-quit-hook 'magit-ediff-restore 'append) - (if c - (ediff-buffers3 a b c) - (ediff-buffers a b))) - -(defun magit-ediff-restore() - "Kill any buffers in `magit-ediff-buffers' that are not visiting files and -restore the window state that was saved before ediff was called." - (dolist (buffer magit-ediff-buffers) - (if (and (null (buffer-file-name buffer)) - (buffer-live-p buffer)) - (kill-buffer buffer))) - (setq magit-ediff-buffers nil) - (set-window-configuration magit-ediff-windows) - (remove-hook 'ediff-quit-hook 'magit-ediff-restore)) - -(defun magit-refresh-diff-buffer (range args) - (let ((magit-current-diff-range (cond - ((stringp range) - (cons range 'working)) - ((null (cdr range)) - (cons (car range) 'working)) - (t - range)))) - (setq magit-current-range range) - (magit-create-buffer-sections - (magit-git-section 'diffbuf - (magit-rev-range-describe range "Changes") - 'magit-wash-diffs - "diff" (magit-diff-U-arg) args "--")))) - -(define-derived-mode magit-diff-mode magit-mode "Magit Diff" - "Mode for looking at a git diff. - -\\{magit-diff-mode-map}" - :group 'magit) - -(magit-define-command diff (range) - (interactive (list (magit-read-rev-range "Diff"))) - (if range - (let* ((dir default-directory) - (args (magit-rev-range-to-git range)) - (buf (get-buffer-create "*magit-diff*"))) - (display-buffer buf) - (with-current-buffer buf - (magit-mode-init dir 'magit-diff-mode #'magit-refresh-diff-buffer range args))))) - -(magit-define-command diff-working-tree (rev) - (interactive (list (magit-read-rev "Diff with" (magit-default-rev)))) - (magit-diff (or rev "HEAD"))) - -(defun magit-diff-with-mark () - (interactive) - (magit-diff (cons (magit-marked-commit) - (magit-commit-at-point)))) - -;;; Wazzup - -(defvar magit-wazzup-head nil - "The integration head for the current wazzup buffer. -This is only non-nil in wazzup buffers.") -(make-variable-buffer-local 'magit-wazzup-head) - -(defvar magit-wazzup-all-p nil - "Non-nil if the current wazzup buffer displays excluded branches. -This is only meaningful in wazzup buffers.") -(make-variable-buffer-local 'magit-wazzup-all-p) - -(defun magit-wazzup-toggle-ignore (branch edit) - (let ((ignore-file (concat (magit-git-dir) "info/wazzup-exclude"))) - (if edit - (setq branch (read-string "Branch to ignore for wazzup: " branch))) - (let ((ignored (magit-file-lines ignore-file))) - (cond ((member branch ignored) - (when (or (not edit) - (y-or-n-p "Branch %s is already ignored. Unignore? ")) - (setq ignored (delete branch ignored)))) - (t - (setq ignored (append ignored (list branch))))) - (magit-write-file-lines ignore-file ignored) - (magit-need-refresh)))) - -(defun magit-refresh-wazzup-buffer (head all) - (setq magit-wazzup-head head) - (setq magit-wazzup-all-p all) - (let ((branch-desc (or head "(detached) HEAD"))) - (unless head (setq head "HEAD")) - (magit-create-buffer-sections - (magit-with-section 'wazzupbuf nil - (insert (format "Wazzup, %s\n\n" branch-desc)) - (let* ((excluded (magit-file-lines (concat (magit-git-dir) "info/wazzup-exclude"))) - (all-branches (magit-list-interesting-refs)) - (branches (if all all-branches - (delq nil (mapcar - (lambda (b) - (and (not - (member (cdr b) excluded)) - b)) - all-branches)))) - (reported (make-hash-table :test #'equal))) - (dolist (branch branches) - (let* ((name (car branch)) - (ref (cdr branch)) - (hash (magit-rev-parse ref)) - (reported-branch (gethash hash reported))) - (unless (or (and reported-branch - (string= (file-name-nondirectory ref) - reported-branch)) - (not (magit-git-string "merge-base" head ref))) - (puthash hash (file-name-nondirectory ref) reported) - (let* ((n (length (magit-git-lines "log" "--pretty=oneline" - (concat head ".." ref)))) - (section - (let ((magit-section-hidden-default t)) - (magit-git-section - (cons ref 'wazzup) - (format "%s unmerged commits in %s%s" - n name - (if (member ref excluded) - " (normally ignored)" - "")) - 'magit-wash-log - "log" - (format "--max-count=%s" magit-log-cutoff-length) - "--abbrev-commit" - (format "--abbrev=%s" magit-sha1-abbrev-length) - "--graph" - "--pretty=oneline" - (format "%s..%s" head ref) - "--")))) - (magit-set-section-info ref section)))))))))) - -(define-derived-mode magit-wazzup-mode magit-mode "Magit Wazzup" - "Mode for looking at commits that could be merged from other branches. - -\\{magit-wazzup-mode-map}" - :group 'magit) - -(defun magit-wazzup (&optional all) - (interactive "P") - (let ((topdir (magit-get-top-dir default-directory)) - (current-branch (magit-get-current-branch))) - (magit-buffer-switch "*magit-wazzup*") - (magit-mode-init topdir 'magit-wazzup-mode - #'magit-refresh-wazzup-buffer - current-branch all))) - -(defun magit-filename (filename) - "Return the path of FILENAME relative to its git repository. - -If FILENAME is absolute, return a path relative to the git -repository containing it. Otherwise, return a path relative to -the current git repository." - (let ((topdir (expand-file-name - (magit-get-top-dir (or (file-name-directory filename) - default-directory)))) - (file (file-truename filename))) - (when (and (not (string= topdir "")) - ;; FILE must start with the git repository path - (zerop (string-match-p (concat "\\`" topdir) file))) - (substring file (length topdir))))) - -;; This variable is used to keep track of the current file in the -;; *magit-log* buffer when this one is dedicated to showing the log of -;; just 1 file. -(defvar magit-file-log-file nil) -(make-variable-buffer-local 'magit-file-log-file) - -(defun magit-refresh-file-log-buffer (file range style) - "Refresh the current file-log buffer by calling git. - -FILE is the path of the file whose log must be displayed. - -`magit-current-range' will be set to the value of RANGE. - -STYLE controls the display. It is either `'long', `'oneline', or something else. - " - (magit-configure-have-graph) - (magit-configure-have-decorate) - (magit-configure-have-abbrev) - (setq magit-current-range range) - (setq magit-file-log-file file) - (magit-create-log-buffer-sections - (apply #'magit-git-section nil - (magit-rev-range-describe range (format "Commits for file %s" file)) - (apply-partially 'magit-wash-log style) - `("log" - ,(format "--max-count=%s" magit-log-cutoff-length) - ,"--abbrev-commit" - ,(format "--abbrev=%s" magit-sha1-abbrev-length) - ,@(cond ((eq style 'long) (list "--stat" "-z")) - ((eq style 'oneline) (list "--pretty=oneline")) - (t nil)) - ,@(if magit-have-decorate (list "--decorate=full")) - ,@(if magit-have-graph (list "--graph")) - "--" - ,file)))) - -(defun magit-file-log (&optional all) - "Display the log for the currently visited file or another one. - -With a prefix argument or if no file is currently visited, ask -for the file whose log must be displayed." - (interactive "P") - (let ((topdir (magit-get-top-dir default-directory)) - (current-file (magit-filename - (if (or current-prefix-arg (not buffer-file-name)) - (magit-read-file-from-rev (magit-get-current-branch)) - buffer-file-name))) - (range "HEAD")) - (magit-buffer-switch "*magit-log*") - (magit-mode-init topdir 'magit-log-mode - #'magit-refresh-file-log-buffer - current-file range 'oneline))) - -(defun magit-show-file-revision () - "Open a new buffer showing the current file in the revision at point." - (interactive) - (flet ((magit-show-file-from-diff (item) - (switch-to-buffer-other-window - (magit-show (cdr (magit-diff-item-range item)) - (magit-diff-item-file item))))) - (magit-section-action (item info "show") - ((commit) - (let ((current-file (or magit-file-log-file - (magit-read-file-from-rev info)))) - (switch-to-buffer-other-window - (magit-show info current-file)))) - ((hunk) (magit-show-file-from-diff (magit-hunk-item-diff item))) - ((diff) (magit-show-file-from-diff item))))) - -;;; Miscellaneous - -(defun magit-ignore-modifiable-file (file edit) - "Prompt the user for the filename to be added to git ignore. -\\ -The minibuffer's future history (accessible with \\[next-history-element]) -contains predefined values (such as wildcards) that might -be of interest. -The history and default value are derived from the filename FILE. -If EDIT argument is negative, the prompt proposes wildcard by default. -" - (let* ((just-extension (concat "*." (file-name-extension file))) - (full-extension (concat (file-name-directory file) just-extension)) - (just-file (file-name-nondirectory file)) - ;; change the order in history depending on the negativity of - ;; EDIT. - (history (if (< (prefix-numeric-value edit) 0) - (list full-extension just-extension file just-file) - (list file full-extension just-extension just-file)))) - (read-string - (format "File to ignore [%s]: " (car history)) - nil nil history))) - -(defun magit-ignore-file (file edit local) - "Add FILE to the list of files to ignore. -\\ -If EDIT is non-`nil', prompt the user for the filename to -be added to git ignore. In this case, the minibuffer's -future history (accessible with \\[next-history-element]) contains predefined -values (such as wildcards) that might be of interest. - -If LOCAL is nil, the `.gitignore' file is updated. -Otherwise, it is `.git/info/exclude'." - (let* ((local-ignore-dir (concat (magit-git-dir) "info/")) - (ignore-file (if local - (concat local-ignore-dir "exclude") - ".gitignore"))) - (if edit - (setq file (magit-ignore-modifiable-file file edit))) - (if (and local (not (file-exists-p local-ignore-dir))) - (make-directory local-ignore-dir t)) - (with-temp-buffer - (when (file-exists-p ignore-file) - (insert-file-contents ignore-file)) - (goto-char (point-max)) - (unless (bolp) - (insert "\n")) - (insert file "\n") - (write-region nil nil ignore-file)) - (magit-need-refresh))) - -(defun magit-ignore-item () - "Add FILE to the `.gitignore' list of files to ignore. -\\ -With a prefix argument, prompt the user for the filename to -be added. In this case, the minibuffer's future history -\(accessible with \\[next-history-element]) contains predefined values (such as -wildcards) that might be of interest. If prefix argument is -negative, the prompt proposes wildcard by default." - (interactive) - (magit-section-action (item info "ignore") - ((untracked file) - (magit-ignore-file (concat "/" info) current-prefix-arg nil)) - ((wazzup) - (magit-wazzup-toggle-ignore info current-prefix-arg)))) - -(defun magit-ignore-item-locally () - "Add FILE to the `.git/info/exclude' list of files to ignore. -\\ -With a prefix argument, prompt the user for the filename to -be added. In this case, the minibuffer's future history -(accessible with \\[next-history-element]) contains predefined values (such as -wildcards) that might be of interest. If prefix argument is -negative, the prompt proposes wildcard by default." - (interactive) - (magit-section-action (item info "ignore") - ((untracked file) - (magit-ignore-file (concat "/" info) current-prefix-arg t)))) - -(defun magit-discard-diff (diff stagedp) - (let ((kind (magit-diff-item-kind diff)) - (file (magit-diff-item-file diff))) - (cond ((eq kind 'deleted) - (when (yes-or-no-p (format "Resurrect %s? " file)) - (magit-run-git "reset" "-q" "--" file) - (magit-run-git "checkout" "--" file))) - ((eq kind 'new) - (if (yes-or-no-p (format "Delete %s? " file)) - (magit-run-git "rm" "-f" "--" file))) - (t - (if (yes-or-no-p (format "Discard changes to %s? " file)) - (if stagedp - (magit-run-git "checkout" "HEAD" "--" file) - (magit-run-git "checkout" "--" file))))))) - -(defun magit-discard-item () - (interactive) - (magit-section-action (item info "discard") - ((untracked file) - (when (yes-or-no-p (format "Delete %s? " info)) - (if (and (file-directory-p info) - (not (file-symlink-p info))) - (magit-delete-directory info 'recursive) - (delete-file info)) - (magit-refresh-buffer))) - ((untracked) - (if (yes-or-no-p "Delete all untracked files and directories? ") - (magit-run-git "clean" "-df"))) - ((unstaged diff hunk) - (when (yes-or-no-p (if (magit-use-region-p) - "Discard changes in region? " - "Discard hunk? ")) - (magit-apply-hunk-item-reverse item))) - ((staged diff hunk) - (if (magit-file-uptodate-p (magit-diff-item-file - (magit-hunk-item-diff item))) - (when (yes-or-no-p (if (magit-use-region-p) - "Discard changes in region? " - "Discard hunk? ")) - (magit-apply-hunk-item-reverse item "--index")) - (error "Can't discard this hunk. Please unstage it first"))) - ((unstaged diff) - (magit-discard-diff item nil)) - ((staged diff) - (if (magit-file-uptodate-p (magit-diff-item-file item)) - (magit-discard-diff item t) - (error "Can't discard staged changes to this file. Please unstage it first"))) - ((diff diff) - (save-excursion - (magit-goto-parent-section) - (magit-discard-item))) - ((diff diff hunk) - (save-excursion - (magit-goto-parent-section) - (magit-goto-parent-section) - (magit-discard-item))) - ((hunk) - (error "Can't discard this hunk")) - ((diff) - (error "Can't discard this diff")) - ((stash) - (when (yes-or-no-p "Discard stash? ") - (magit-run-git "stash" "drop" info))) - ((branch) - (when (yes-or-no-p (if current-prefix-arg - "Force delete branch?" - "Delete branch? ")) - (magit-delete-branch info current-prefix-arg))) - ((remote) - (when (yes-or-no-p "Remove remote? ") - (magit-remove-remote info))))) - -(defun magit-move-item () - (interactive) - (magit-section-action (item info "move") - ((branch) - (call-interactively 'magit-move-branch)) - ((remote) - (call-interactively 'magit-rename-remote)))) - -(defmacro magit-visiting-file-item (&rest body) - `(let ((marker (save-window-excursion - (magit-visit-file-item) - (set-marker (make-marker) (point))))) - (save-excursion - (with-current-buffer (marker-buffer marker) - (goto-char marker) - ,@body)))) - -(defun magit-add-change-log-entry-no-option (&optional other-window) - "Add a change log entry for current change. -With a prefix argument, edit in other window. -The name of the change log file is set by variable change-log-default-name." - (interactive "P") - (if other-window - (magit-visiting-file-item (add-change-log-entry-other-window)) - (magit-visiting-file-item (add-change-log-entry)))) - -(defun magit-add-change-log-entry-other-window () - (interactive) - (magit-visiting-file-item (call-interactively 'add-change-log-entry-other-window))) - -(eval-after-load 'dired-x - '(defun magit-dired-jump (&optional other-window) - "Visit current item. -With a prefix argument, visit in other window." - (interactive "P") - (require 'dired-x) - (magit-section-action (item info "dired-jump") - ((untracked file) - (dired-jump other-window (file-truename info))) - ((diff) - (dired-jump other-window (file-truename (magit-diff-item-file item)))) - ((hunk) - (dired-jump other-window - (file-truename (magit-diff-item-file - (magit-hunk-item-diff item)))))))) - -(defun magit-visit-file-item (&optional other-window) - "Visit current file associated with item. -With a prefix argument, visit in other window." - (interactive "P") - (magit-section-action (item info "visit-file") - ((untracked file) - (funcall - (if other-window 'find-file-other-window 'find-file) - info)) - ((diff) - (let ((file (magit-diff-item-file item))) - (cond ((not (file-exists-p file)) - (error "Can't visit deleted file: %s" file)) - ((file-directory-p file) - (magit-status file)) - (t - (funcall - (if other-window 'find-file-other-window 'find-file) - file))))) - ((hunk) - (let ((file (magit-diff-item-file (magit-hunk-item-diff item))) - (line (magit-hunk-item-target-line item))) - (if (not (file-exists-p file)) - (error "Can't visit deleted file: %s" file)) - (funcall - (if other-window 'find-file-other-window 'find-file) - file) - (goto-char (point-min)) - (forward-line (1- line)))))) - -(defun magit-visit-item (&optional other-window) - "Visit current item. -With a prefix argument, visit in other window." - (interactive "P") - (magit-section-action (item info "visit") - ((untracked file) - (call-interactively 'magit-visit-file-item)) - ((diff) - (call-interactively 'magit-visit-file-item)) - ((hunk) - (call-interactively 'magit-visit-file-item)) - ((commit) - (magit-show-commit info nil nil 'select)) - ((stash) - (magit-show-stash info) - (pop-to-buffer magit-stash-buffer-name)) - ((branch) - (magit-checkout info)) - ((longer) - (magit-log-show-more-entries ())))) - -(defun magit-show-item-or-scroll-up () - (interactive) - (magit-section-action (item info) - ((commit) - (magit-show-commit info #'scroll-up)) - ((stash) - (magit-show-stash info #'scroll-up)) - (t - (scroll-up)))) - -(defun magit-show-item-or-scroll-down () - (interactive) - (magit-section-action (item info) - ((commit) - (magit-show-commit info #'scroll-down)) - ((stash) - (magit-show-stash info #'scroll-down)) - (t - (scroll-down)))) - -(defun magit-mark-item (&optional unmark) - (interactive "P") - (if unmark - (magit-set-marked-commit nil) - (magit-section-action (item info "mark") - ((commit) - (magit-set-marked-commit (if (eq magit-marked-commit info) - nil - info)))))) - -(defun magit-describe-item () - (interactive) - (let ((section (magit-current-section))) - (message "Section: %s %s-%s %S %S %S" - (magit-section-type section) - (magit-section-beginning section) - (magit-section-end section) - (magit-section-title section) - (magit-section-info section) - (magit-section-context-type section)))) - -(defun magit-copy-item-as-kill () - "Copy sha1 of commit at point into kill ring." - (interactive) - (magit-section-action (item info "copy") - ((commit) - (kill-new info) - (message "%s" info)))) - -(eval-when-compile (require 'server)) - -(defun magit-server-running-p () - "Test whether server is running (works with < 23 as well). - -Return values: - nil the server is definitely not running. - t the server seems to be running. - something else we cannot determine whether it's running without using - commands which may have to wait for a long time." - (require 'server) - (if (functionp 'server-running-p) - (server-running-p) - (condition-case nil - (if server-use-tcp - (with-temp-buffer - (insert-file-contents-literally (expand-file-name server-name server-auth-dir)) - (or (and (looking-at "127\\.0\\.0\\.1:[0-9]+ \\([0-9]+\\)") - (assq 'comm - (process-attributes - (string-to-number (match-string 1)))) - t) - :other)) - (delete-process - (make-network-process - :name "server-client-test" :family 'local :server nil :noquery t - :service (expand-file-name server-name server-socket-dir))) - t) - (file-error nil)))) - -(defun magit-interactive-rebase () - "Start a git rebase -i session, old school-style." - (interactive) - (unless (magit-server-running-p) - (server-start)) - (let* ((section (get-text-property (point) 'magit-section)) - (commit (and (member 'commit (magit-section-context-type section)) - (magit-section-info section))) - (old-editor (getenv "GIT_EDITOR"))) - (setenv "GIT_EDITOR" (concat (locate-file "emacsclient" exec-path) - " -s " server-name)) - (unwind-protect - (magit-run-git-async "rebase" "-i" - (or (and commit (concat commit "^")) - (magit-read-rev "Interactively rebase to" (magit-guess-branch)))) - (if old-editor - (setenv "GIT_EDITOR" old-editor))))) - -(define-derived-mode magit-branch-manager-mode magit-mode "Magit Branch" - "Magit Branches") - -(defun magit-quit-window (&optional kill-buffer) - "Bury the buffer and delete its window. With a prefix argument, kill the -buffer instead." - (interactive "P") - (quit-window kill-buffer (selected-window))) - -(defun magit--branch-name-at-point () - "Get the branch name in the line at point." - (let ((branch (magit-section-info (magit-current-section)))) - (or branch (error "No branch at point")))) - -(defun magit--branches-for-remote-repo (remote) - "Return a list of remote branch names for REMOTE. -These are the branch names with the remote name stripped." - (remq nil - (mapcar (lambda (line) - (save-match-data - (if (and (not (string-match-p " -> " line)) - (string-match (concat "^ +" remote "/\\([^ $]+\\)") - line)) - (match-string 1 line)))) - (magit-git-lines "branch" "-r")))) - -(defvar magit-branches-buffer-name "*magit-branches*") - -(defun magit--is-branch-at-point-remote () - "Return non-nil if the branch at point is a remote tracking branch" - (magit-remote-part-of-branch (magit--branch-name-at-point))) - -(defun magit-remote-part-of-branch (branch) - (when (string-match-p "^\\(?:refs/\\)?remotes\\/" branch) - (loop for remote in (magit-git-lines "remote") - when (string-match-p (format "^\\(?:refs/\\)?remotes\\/%s\\/" (regexp-quote remote)) branch) return remote))) - -(defun magit-branch-no-remote (branch) - (let ((remote (magit-remote-part-of-branch branch))) - (if remote - (progn - ;; This has to match if remote is non-nil - (assert (string-match (format "^\\(?:refs/\\)?remotes\\/%s\\/\\(.*\\)" (regexp-quote remote)) branch) - 'show-args "Unexpected string-match failure: %s %s") - (match-string 1 branch)) - branch))) - -(defun magit-wash-branch-line (&optional remote-name) - (looking-at (concat - "^\\([ *] \\)" ; 1: current branch marker - "\\(.+?\\) +" ; 2: branch name - - "\\(?:" - - "\\([0-9a-fA-F]+\\)" ; 3: sha1 - " " - "\\(?:\\[" - "\\([^:\n]+?\\)" ; 4: tracking (non-greedy + to avoid matching \n) - "\\(?:: \\)?" - "\\(?:ahead \\([0-9]+\\)\\)?" ; 5: ahead - "\\(?:, \\)?" - "\\(?:behind \\([0-9]+\\)\\)?" ; 6: behind - "\\] \\)?" - "\\(?:.*\\)" ; message - - "\\|" ; or - - "-> " ; the pointer to - "\\(.+\\)" ; 7: a ref - - "\\)\n")) - - (let* ((current-string (match-string 1)) - (branch (match-string 2)) - (sha1 (match-string 3)) - (tracking (match-string 4)) - (ahead (match-string 5)) - (behind (match-string 6)) - (other-ref (match-string 7)) - (current (string-match-p "^\\*" current-string))) - - ; the current line is deleted before being reconstructed - (delete-region (point) - (line-beginning-position 2)) - - (magit-with-section branch 'branch - (magit-set-section-info branch) - (insert-before-markers - ; sha1 - (propertize (or sha1 - (make-string magit-sha1-abbrev-length ? )) - 'face 'magit-log-sha1) - " " - ; current marker - (if current - "# " - " ") - ; branch name - (apply 'propertize (magit-branch-no-remote branch) - (if current - '(face magit-branch))) - ; other ref that this branch is pointing to - (if other-ref - (concat " -> " (substring other-ref (+ 1 (length remote-name)))) - "") - ; tracking information - (if (and tracking - (equal (magit-remote-branch-for branch t) - (concat "refs/remotes/" tracking))) - (concat " [" - ; getting rid of the tracking branch name if it is the same as the branch name - (let* ((tracking-remote (magit-get "branch" branch "remote")) - (tracking-branch (substring tracking (+ 1 (length tracking-remote))))) - (propertize (if (string= branch tracking-branch) - (concat "@ " tracking-remote) - (concat tracking-branch " @ " tracking-remote)) - 'face 'magit-log-head-label-remote)) - ; ahead/behind information - (if (or ahead - behind) - ": " - "") - (if ahead - (concat "ahead " - (propertize ahead - 'face (if current - 'magit-branch)) - (if behind - ", " - "")) - "") - (if behind - (concat "behind " - (propertize behind - 'face 'magit-log-head-label-remote)) - "") - "]") - "") - "\n")))) - -(defun magit-wash-remote-branches-group (group) - (let* ((remote-name (first group)) - (url (magit-get "remote" remote-name "url")) - (push-url (magit-get "remote" remote-name "pushurl")) - (urls (concat url (if push-url - (concat ", "push-url) - ""))) - (marker (second group))) - - (magit-with-section (concat "remote:" remote-name) 'remote - (magit-set-section-info remote-name) - (insert-before-markers (propertize (format "%s (%s):" remote-name urls) 'face 'magit-section-title) "\n") - (magit-wash-branches-between-point-and-marker marker remote-name)) - (insert-before-markers "\n"))) - -(defun magit-wash-branches-between-point-and-marker (marker &optional remote-name) - (save-restriction - (narrow-to-region (point) marker) - (magit-wash-sequence - (if remote-name - (apply-partially 'magit-wash-branch-line remote-name) - #'magit-wash-branch-line)))) - -(defun magit-wash-branches () - ; get the names of the remotes - (let* ((remotes (magit-git-lines "remote")) - ; get the location of remotes in the buffer - (markers - (append (mapcar (lambda (remote) - (save-excursion - (when (search-forward-regexp - (concat "^ remotes\\/" remote) nil t) - (beginning-of-line) - (point-marker)))) - remotes) - (list (save-excursion - (goto-char (point-max)) - (point-marker))))) - ; list of remote elements to display in the buffer - (remote-groups (loop for remote in remotes - for end-markers on (cdr markers) - for marker = (loop for x in end-markers thereis x) - collect (list remote marker)))) - - ; actual displaying of information - (magit-with-section "local" nil - (insert-before-markers (propertize "Local:" 'face 'magit-section-title) "\n") - (magit-set-section-info ".") - (magit-wash-branches-between-point-and-marker - (loop for x in markers thereis x))) - - (insert-before-markers "\n") - - (mapc 'magit-wash-remote-branches-group remote-groups) - - ; make sure markers point to nil so that they can be garbage collected - (mapc (lambda (marker) - (when marker - (set-marker marker nil))) - markers))) - -(defun magit-refresh-branch-manager () - (magit-create-buffer-sections - (magit-git-section "branches" nil 'magit-wash-branches - "branch" - "-vva" - (format "--abbrev=%s" magit-sha1-abbrev-length)))) - -(magit-define-command branch-manager () - (interactive) - (let ((topdir (magit-get-top-dir default-directory))) - (magit-buffer-switch magit-branches-buffer-name) - (magit-mode-init topdir 'magit-branch-manager-mode #'magit-refresh-branch-manager))) - -(defun magit-change-what-branch-tracks () - "Change which remote branch the current branch tracks." - (interactive) - (if (magit--is-branch-at-point-remote) - (error "Cannot modify a remote branch")) - (let* ((local-branch (magit--branch-name-at-point)) - (new-tracked (magit-read-rev "Change tracked branch to" - nil - (lambda (ref) - (not (string-match-p "refs/remotes/" - ref))))) - new-remote new-branch) - (unless (string= (or new-tracked "") "") - (cond (;; Match refs that are unknown in the local repository if - ;; `magit-remote-ref-format' is set to - ;; `name-then-remote'. Can be useful if you want to - ;; create a new branch in a remote repository. - (string-match "^\\([^ ]+\\) +(\\(.+\\))$" ; 1: branch name; 2: remote name - new-tracked) - (setq new-remote (match-string 2 new-tracked) - new-branch (concat "refs/heads/" (match-string 1 new-tracked)))) - ((string-match "^\\(?:refs/remotes/\\)?\\([^/]+\\)/\\(.+\\)" ; 1: remote name; 2: branch name - new-tracked) - (setq new-remote (match-string 1 new-tracked) - new-branch (concat "refs/heads/" (match-string 2 new-tracked)))) - (t (error "Cannot parse the remote and branch name")))) - (magit-set new-remote "branch" local-branch "remote") - (magit-set new-branch "branch" local-branch "merge") - (magit-branch-manager) - (if (string= (magit-get-current-branch) local-branch) - (magit-refresh-buffer (magit-find-status-buffer default-directory))))) - -(defvar magit-ediff-file) - -(defun magit-interactive-resolve (file) - (require 'ediff) - (let ((merge-status (magit-git-string "ls-files" "-u" "--" file)) - (base-buffer (generate-new-buffer (concat file ".base"))) - (our-buffer (generate-new-buffer (concat file ".current"))) - (their-buffer (generate-new-buffer (concat file ".merged"))) - (windows (current-window-configuration))) - (if (null merge-status) - (error "Cannot resolve %s" file)) - (with-current-buffer base-buffer - (if (string-match "^[0-9]+ [0-9a-f]+ 1" merge-status) - (insert (magit-git-output `("cat-file" "blob" ,(concat ":1:" file)))))) - (with-current-buffer our-buffer - (if (string-match "^[0-9]+ [0-9a-f]+ 2" merge-status) - (insert (magit-git-output `("cat-file" "blob" ,(concat ":2:" file))))) - (let ((buffer-file-name file)) - (normal-mode))) - (with-current-buffer their-buffer - (if (string-match "^[0-9]+ [0-9a-f]+ 3" merge-status) - (insert (magit-git-output `("cat-file" "blob" ,(concat ":3:" file))))) - (let ((buffer-file-name file)) - (normal-mode))) - ;; We have now created the 3 buffer with ours, theirs and the ancestor files - (with-current-buffer (ediff-merge-buffers-with-ancestor our-buffer their-buffer base-buffer) - (make-local-variable 'magit-ediff-file) - (setq magit-ediff-file file) - (make-local-variable 'magit-ediff-windows) - (setq magit-ediff-windows windows) - (make-local-variable 'ediff-quit-hook) - (add-hook 'ediff-quit-hook - (lambda () - (let ((buffer-A ediff-buffer-A) - (buffer-B ediff-buffer-B) - (buffer-C ediff-buffer-C) - (buffer-Ancestor ediff-ancestor-buffer) - (file magit-ediff-file) - (file-buffer) - (windows magit-ediff-windows)) - (ediff-cleanup-mess) - (find-file file) - (setq file-buffer (current-buffer)) - (erase-buffer) - (insert-buffer-substring buffer-C) - (kill-buffer buffer-A) - (kill-buffer buffer-B) - (kill-buffer buffer-C) - (when (bufferp buffer-Ancestor) (kill-buffer buffer-Ancestor)) - (set-window-configuration windows) - (magit-save-some-buffers - "Conflict resolution finished; you may save the buffer" - (lambda () (eq (current-buffer) file-buffer))))))))) - -(defun magit-interactive-resolve-item () - (interactive) - (magit-section-action (item info "resolv") - ((diff) - (magit-interactive-resolve (cadr info))))) - -(defun magit-submodule-update (&optional init) - "Update the submodule of the current git repository - -With a prefix arg, do a submodule update --init" - (interactive "P") - (let ((default-directory (magit-get-top-dir default-directory))) - (apply #'magit-run-git-async "submodule" "update" (if init '("--init") ())))) - -(defun magit-submodule-update-init () - "Update and init the submodule of the current git repository." - (interactive) - (magit-submodule-update t)) - -(defun magit-submodule-init () - "Initialize the submodules" - (interactive) - (let ((default-directory (magit-get-top-dir default-directory))) - (magit-run-git-async "submodule" "init"))) - -(defun magit-submodule-sync () - "Synchronizes submodules' remote URL configuration" - (interactive) - (let ((default-directory (magit-get-top-dir default-directory))) - (magit-run-git-async "submodule" "sync"))) - -(defun magit-run-git-gui () - "Run `git gui' for the current git repository" - (interactive) - (let* ((default-directory (magit-get-top-dir default-directory))) - (magit-start-process "Git Gui" nil magit-git-executable "gui"))) - -(defun magit-run-gitk () - "Run `gitk --all' for the current git repository" - (interactive) - (let ((default-directory (magit-get-top-dir default-directory))) - (cond - ((eq system-type 'windows-nt) - ;; Gitk is a shell script, and Windows doesn't know how to - ;; "execute" it. The Windows version of Git comes with an - ;; implementation of "sh" and everything else it needs, but - ;; Windows users might not have added the directory where it's - ;; installed to their path - (let ((git-bin-dir (file-name-directory magit-gitk-executable)) - (exec-path exec-path) - (process-environment process-environment)) - (when git-bin-dir - ;; Adding it onto the end so that anything the user - ;; specified will get tried first. Emacs looks in - ;; exec-path; PATH is the environment variable inherited by - ;; the process. I need to change both. - (setq exec-path (append exec-path (list git-bin-dir))) - (push (format "PATH=%s;%s" - (getenv "PATH") - (replace-regexp-in-string "/" "\\\\" git-bin-dir)) - process-environment)) - (magit-start-process "Gitk" nil "sh" magit-gitk-executable "--all"))) - (t - (magit-start-process "Gitk" nil magit-gitk-executable "--all"))))) - -(defun magit-load-config-extensions () - "Try to load magit extensions that are defined at git config -layer. This can be added to `magit-mode-hook' for example" - (dolist (ext (magit-get-all "magit.extension")) - (let ((sym (intern (format "magit-%s-mode" ext)))) - (when (and (fboundp sym) - (not (eq sym 'magit-wip-save-mode))) - (funcall sym 1))))) - -(provide 'magit) - -;; rest of magit core -(require 'magit-key-mode) -(require 'magit-bisect) - -;;; magit.el ends here diff --git a/elpa/magit-1.2.1/magit.info b/elpa/magit-1.2.1/magit.info deleted file mode 100644 index 087ebe6..0000000 --- a/elpa/magit-1.2.1/magit.info +++ /dev/null @@ -1,1362 +0,0 @@ -This is magit.info, produced by makeinfo version 4.13 from magit.texi. - -INFO-DIR-SECTION Emacs -START-INFO-DIR-ENTRY -* Magit: (magit). Using Git from Emacs with Magit. -END-INFO-DIR-ENTRY - - Copyright (C) 2008, 2009, 2010, 2011 Magit contributors. (See the -header of magit.el for the lengthy list of Magit contributors.) - - Permission is granted to copy, distribute and/or modify this - document under the terms of the GNU Free Documentation License, - Version 1.2 or any later version published by the Free Software - Foundation; with no Invariant Sections, with no Front-Cover Texts, - and with no Back-Cover Texts. - - -File: magit.info, Node: Top, Next: Introduction, Up: (dir) - -Magit User Manual -***************** - -Magit is an interface to the version control system Git, implemented as -an extension to Emacs. Magit supports GNU Emacs version 22 or later. -It may work with other emacsen, but Magit developers do not intend to -investigate and fix bugs that only appear in unsupported versions. -Patches to fix bugs in other emacsen or volunteers to maintain -compatibility are still welcome. - -* Menu: - -* Introduction:: -* Acknowledgments:: -* Sections:: -* Status:: -* Untracked files:: -* Staging and Committing:: -* History:: -* Reflogs:: -* Commit Buffer:: -* Diffing:: -* Tagging:: -* Resetting:: -* Stashing:: -* Branching:: -* The Branch Manager:: -* Wazzup:: -* Merging:: -* Rebasing:: -* Interactive Rebasing:: -* Rewriting:: -* Pushing and Pulling:: -* Bisecting:: -* Submodules:: -* Using Magit Extensions:: -* Using Git Directly:: -* Customization:: -* Frequently Asked Questions:: - - -File: magit.info, Node: Introduction, Next: Acknowledgments, Prev: Top, Up: Top - -1 Introduction -************** - -With Magit, you can inspect and modify your Git repositories with -Emacs. You can review and commit the changes you have made to the -tracked files, for example, and you can browse the history of past -changes. There is support for cherry picking, reverting, merging, -rebasing, and other common Git operations. - - Magit is not a complete interface to Git; it just aims to make the -most common Git operations convenient. Thus, Magit will likely not -save you from learning Git itself. - - This manual provides a tour of all Magit features. It does not give -an introduction to version control in general, or to Git in particular. - - The main entry point to Magit is `M-x magit-status', which will put -you in Magit's status buffer. You will be using it frequently, so it -is probably a good idea to bind `magit-status' to a key of your choice. - - In addition to the status buffer, Magit will also create buffers that -show lists of commits, buffers with diffs, and other kinds of buffers. -All these buffers are in `magit-mode' and have the same key bindings. -Not all commands make sense in all contexts, but a given key will -always do the same thing in all Magit buffers. - - Naturally, Magit runs the `git' command to do most of the work. The -`*magit-process*' buffer contains the transcript of the most recent -command. You can switch to it with `$'. - - -File: magit.info, Node: Acknowledgments, Next: Sections, Prev: Introduction, Up: Top - -2 Acknowledgments -***************** - -Marius Vollmer started the whole project. Thanks ! - - From day one of the first Magit announcement, John Wiegley has -contributed numerous fixes, UI improvements, and new features. Thanks! - - Linh Dang and Christian Neukirchen also contributed from day one. -Thanks! - - Phil Hagelberg joined a few days later. Thanks! - - Alex Ott contributed support for git svn. Thanks! - - Marcin Bachry contributed bug fixes and support for decorated logs. -Thanks! - - Alexey Voinov fixed bugs. Thanks! - - RĂ©mi Vanicat helped with Tramp support. Thanks! - - -File: magit.info, Node: Sections, Next: Status, Prev: Acknowledgments, Up: Top - -3 Sections -********** - -All Magit buffers are structured into nested 'sections'. These -sections can be hidden and shown individually. When a section is -hidden, only its first line is shown and all its children are -completely invisible. - - The most fine-grained way to control the visibility of sections is -the `TAB' key. It will to toggle the current section (the section that -contains point) between being hidden and being shown. - - Typing `S-TAB' toggles the visibility of the children of the current -section. When all of them are shown, they will all be hidden. -Otherwise, when some or all are hidden, they will all be shown. - - The digit keys `1', `2', `3', and `4' control the visibility of -sections based on levels. Hitting `2', for example, will show sections -on levels one and two, and will hide sections on level 3. However, -only sections that are a parent or child of the current section are -affected. - - For example, when the current section is on level 3 and you hit `1', -the grand-parent of the current section (which is on level one) will be -shown, and the parent of the current section (level 2) will be hidden. -The visibility of no other section will be changed. - - This sounds a bit complicated, but you'll figure it out. - - Using `M-1', `M-2', `M-3', and `M-4' is similar to the unmodified -digits, but now all sections on the respective level are affected, -regardless of whether or not they are related to the current section. - - For example, `M-1' will only show the first lines of the top-level -sections and will hide everything else. Typing `M-4' on the other hand -will show everything. - - Because of the way the status buffer is set up, some changes to -section visibility are more common than others. Files are on level 2 -and diff hunks are on level 4. Thus, you can type `2' to collapse the -diff of the current file, and `M-2' to collapse all files. This -returns the status buffer to its default setup and is a quick way to -unclutter it after drilling down into the modified files. - - Because `2' and `M-2' are so common in the status buffer, they are -bound to additional, more mnemonic keys: `M-h' (hide) and `M-H' (hide -all). Likewise `4' and `M-4' are also available as `M-s' (show) and -`M-S' (show all). - - In other buffers than the status buffer, `M-h', `M-H', `M-s', and -`M-S' might work on different levels than on 2 and 4, but they keep -their general meaning: `M-H' hides all detail, and `M-S' shows -everything. - - -File: magit.info, Node: Status, Next: Untracked files, Prev: Sections, Up: Top - -4 Status -******** - -Running `M-x magit-status' displays the main interface of Magit, the -status buffer. You can have multiple status buffers active at the same -time, each associated with its own Git repository. - - When invoking `M-x magit-status' from within a Git repository, it -will switch to the status buffer of that repository. Otherwise, it -will prompt for a directory. With a prefix argument, it will always -prompt. - - You can set `magit-repo-dirs' to customize how `magit-status' asks -for the repository to work on. When `magit-repo-dirs' is nil, -`magit-status' will simply ask for a directory. - - If you specify a directory that is not a Git repository, `M-x -magit-status' will offer to initialize it as one. - - When `magit-repo-dirs' is not nil, it is treated as a list of -directory names, and `magit-status' will find all Git repositories in -those directories and offer them for completion. (Magit will only look -`magit-repo-dirs-depth' levels deep, however.) - - With two prefix arguments, `magit-status' will always prompt for a -raw directory. - - Thus, you would normally set `magit-repo-dirs' to the places where -you keep most of your Git repositories and switch between them with -`C-u M-x magit-status'. If you want to go to a repository outside of -your normal working areas, or if you want to create a new repository, -you would use `C-u C-u M-x magit-status'. - - You need to explicitly refresh the status buffer when you have made -changes to the repository from outside of Emacs. You can type `g' in -the status buffer itself, or just use `M-x magit-status' instead of -`C-x b' when switching to it. You also need to refresh the status -buffer in this way after saving a file in Emacs. - - The header at the top of the status buffer shows a short summary of -the repository state: where it is located, which branch is checked out, -etc. Below the header are a number of sections that show details about -the working tree and the staging area. You can hide and show them as -described in the previous section. - - The first section shows _Untracked files_, if there are any. See -*note Untracked files:: for more details. - - The next two sections show your local changes. They are explained -fully in the next chapter, *note Staging and Committing::. - - If the current branch is associated with a remote tracking branch, -the status buffer shows the differences between the current branch and -the tracking branch. See *note Pushing and Pulling:: for more -information. - - During a history rewriting session, the status buffer shows the -_Pending changes_ and _Pending commits_ sections. See *note -Rewriting:: for more details. - - -File: magit.info, Node: Untracked files, Next: Staging and Committing, Prev: Status, Up: Top - -5 Untracked files -***************** - -Untracked files are shown in the _Untracked files_ section. - - You can add an untracked file to the staging area with `s'. If -point is on the _Untracked files_ section title when you hit `s', all -untracked files are staged. - - Typing `C-u S' anywhere will also stage all untracked files, -together with all changes to the tracked files. - - You can instruct Git to ignore them by typing `i'. This will add -the filename to the `.gitignore' file. Typing `C-u i' will ask you for -the name of the file to ignore. This is useful to ignore whole -directories, for example. In this case, the minibuffer's future history -(accessible with `M-n') contains predefined values (such as wildcards) -that might be of interest. If prefix argument is negative (for example -after typing `C-- i'), the prompt proposes wildcard by default. The -`I' command is similar to `i' but will add the file to -`.git/info/exclude' instead. - - To delete an untracked file forever, use `k'. If point is on the -_Untracked files_ section title when you hit `k', all untracked files -are deleted. - - -File: magit.info, Node: Staging and Committing, Next: History, Prev: Untracked files, Up: Top - -6 Staging and Committing -************************ - -Comitting with Git is a two step process: first you add the changes you -want to commit to a 'staging area', and then you commit them to the -repository. This allows you to only commit a subset of your local -changes. - - Magit allows you to ignore the staging area if you wish. As long as -your staging area is unused, Magit will show your uncomitted changes in -a section named _Changes_. - - When the staging area is in use, Magit uses two sections: _Unstaged -changes_ and _Staged changes_. The _Staged changes_ section shows the -changes that will be included in the next commit, while the _Unstaged -changes_ section shows the changes that will be left out. - - To move an unstaged hunk into the staging area, move point into the -hunk and type `s'. Likewise, to unstage a hunk, move point into it and -type `u'. If point is in a diff header when you type `s' or `u', all -hunks belonging to that diff are moved at the same time. - - If the region is active when you type `s' or `u', only the changes -in the region are staged or unstaged. (This works line by line: if the -beginning of a line is in the region it is included in the changes, -otherwise it is not.) - - To change the size of the hunks, you can type `+' or `-' to increase -and decrease, respectively. Typing `0' will reset the hunk size to the -default. - - Typing `C-u s' will ask you for a name of a file to be staged, for -example to stage files that are hidden. - - To move all hunks of all diffs into the staging area in one go, type -`S'. To unstage everything, type `U'. - - Typing `C-u S' will stage all untracked files in addition to the -changes to tracked files. - - You can discard uncommitted changes by moving point into a hunk and -typing `k'. The changes to discard are selected as with `s' and `u'. - - Before committing, you should write a short description of the -changes. - - Type `c' to pop up a buffer where you can write your change -description. Once you are happy with the description, type `C-c C-c' -in that buffer to perform the commit. - - If you want to write changes in a `ChangeLog' file, you can use `C-x -4 a' on a diff hunk. - - Typing `c' when the staging area is unused is a special situation. -Normally, the next commit would be empty, but you can configure Magit -to do something more useful by customizing the -`magit-commit-all-when-nothing-staged' variable. One choice is to -instruct the subsequent `C-c C-c' to commit all changes. Another -choice is stage everything at the time of hitting `c'. - - You can type `C-c C-a' in the buffer with the change description to -toggle a flag that determines whether the next commit will _amend_ the -current commit in HEAD. - - Typing `C-c C-s' will toggle the `--signoff' option. The default is -determined by the `magit-commit-signoff' customization variable. - - Typing `C-c C-e' will toggle the `--allow-empty' option. This -allows you to make commits that serve as notes, without including any -changes. - - Typing `C-c C-t' will toggle the option to specify the name and -email address for the commit's author. The default is determined by -the `user.name' and `user.email' git configuration settings. - - If you change your mind and don't want to go ahead with your commit -while you are in the `*magit-log-edit*' buffer, you can just switch to -another buffer, continue editing there, staging and unstaging things -until you are happy, and then return to the `*magit-log-edit*' buffer, -maybe via `C-x b', or by hitting `c' again in a Magit buffer. - - If you want to erase the `*magit-log-edit*' buffer and bury it, you -can hit `C-c C-k' in it. - - Typing `C' will also pop up the change description buffer, but in -addition, it will try to insert a ChangeLog-style entry for the change -that point is in. - - -File: magit.info, Node: History, Next: Reflogs, Prev: Staging and Committing, Up: Top - -7 History -********* - -To show the repository history of your current head, type `l l'. A new -buffer will be shown that displays the history in a terse form. The -first paragraph of each commit message is displayed, next to a -representation of the relationships between commits. - - To show the repository history between two branches or between any -two points of the history, type `l r l'. You will be prompted to enter -references for starting point and ending point of the history range; you -can use auto-completion to specify them. A typical use case for ranged -history log display would be `l r l master RET new-feature RET' that -will display commits on the new-feature branch that are not in master; -these commits can then be inspected and cherry-picked, for example. - - More thorough filtering can be done by supplying `l' with one or -more suffix arguments, as displayed in its popup. `=g' ('Grep') for -example, limits the output to commits of which the log message matches -a specific string/regex. - - Typing `l L' (or `l C-u L') will show the log in a more verbose form. - - Magit will show only `magit-log-cutoff-length' entries. `e' will -show twice as many entries. `C-u e' will show all entries, and given a -numeric prefix argument, `e' will add this number of entries. - - You can move point to a commit and then cause various things to -happen with it. (The following commands work in any list of commits, -such as the one shown in the _Unpushed commits_ section.) - - Typing `RET' will pop up more information about the current commit -and move point into the new buffer. *Note Commit Buffer::. Typing -`SPC' and `DEL' will also show the information, but will scroll the new -buffer up or down (respectively) when typed again. - - Typing `a' will apply the current commit to your current branch. -This is useful when you are browsing the history of some other branch -and you want to `cherry-pick' some changes from it. A typical -situation is applying selected bug fixes from the development version -of a program to a release branch. The cherry-picked changes will not -be committed automatically; you need to do that explicitly. - - Typing `A' will cherry-pick the current commit and will also commit -the changes automatically when there have not been any conflicts. - - Typing `v' will revert the current commit. Thus, it will apply the -changes made by that commit in reverse. This is obviously useful to -cleanly undo changes that turned out to be wrong. As with `a', you -need to commit the changes explicitly. - - Typing `C-w' will copy the sha1 of the current commit into the kill -ring. - - Typing `=' will show the differences from the current commit to the -"marked" commit. - - You can mark the current commit by typing `.'. When the current -commit is already marked, typing `.' will unmark it. To unmark the -marked commit no matter where point is, use `C-u .'. - - Some commands, such as `=', will use the current commit and the -marked commit as implicit arguments. Other commands will offer the -marked commit as a default when prompting for their arguments. - - -File: magit.info, Node: Reflogs, Next: Commit Buffer, Prev: History, Up: Top - -8 Reflogs -********* - -You can use `l h' and `l H' to browse your _reflog_, the local history -of changes made to your repository heads. Typing `H' will ask for a -head, while `l h' will show the reflog of `HEAD'. - - The resulting buffer is just like the buffer produced by `l l' and -`l L' that shows the commit history. - - -File: magit.info, Node: Commit Buffer, Next: Diffing, Prev: Reflogs, Up: Top - -9 Commit Buffer -*************** - -When you view a commit (perhaps by selecting it in the log buffer, -*note History::), the "commit buffer" is displayed, showing you -information about the commit and letting you interact with it. - - By placing your cursor within the diff or hunk and typing `a', you -can apply the same patch to your working copy. This is useful when you -want to copy a change from another branch, but don't necessarily want -to cherry-pick the whole commit. - - By typing `v' you can apply the patch in reverse, removing all the -lines that were added and adding all the lines that were removed. This -is a convenient way to remove a change after determining that it -introduced a bug. - - If the commit message refers to any other commits in the repository -by their unique hash, the hash will be highlighted and you will be able -to visit the referenced commit either by clicking on it or by moving -your cursor onto it and pressing `RET'. - - The commit buffer maintains a history of the commits it has shown. -After visiting a referenced commit you can type `C-c C-b' to get back -to where you came from. To go forward in the history, type `C-c C-f'. -There are also `[back]' and `[forward]' buttons at the bottom of the -buffer. - - -File: magit.info, Node: Diffing, Next: Tagging, Prev: Commit Buffer, Up: Top - -10 Diffing -********** - -Magit typically shows diffs in the "unified" format. - - In any buffer that shows a diff, you can type `e' anywhere within -the diff to show the two versions of the file in Ediff. If the diff is -of a file in the status buffer that needs to be merged, you will be -able to use Ediff as an interactive merge tool. Otherwise, Ediff will -simply show the two versions of the file. - - To show the changes from your working tree to another revision, type -`d'. To show the changes between two arbitrary revisions, type `D'. - - You can use `a' within the diff output to apply the changes to your -working tree. As usual when point is in a diff header for a file, all -changes for that file are applied, and when it is in a hunk, only that -hunk is. When the region is active, the applied changes are restricted -to that region. - - Typing `v' will apply the selected changes in reverse. - - -File: magit.info, Node: Tagging, Next: Resetting, Prev: Diffing, Up: Top - -11 Tagging -********** - -Typing `t t' will make a lighweight tag. Typing `t a' will make an -annotated tag. It will put you in the normal `*magit-log-edit' buffer -for writing commit messages, but typing `C-c C-c' in it will make the -tag instead. This is controlled by the `Tag' field that will be added -to the `*magit-log-edit*' buffer. You can edit it, if you like. - - -File: magit.info, Node: Resetting, Next: Stashing, Prev: Tagging, Up: Top - -12 Resetting -************ - -Once you have added a commit to your local repository, you can not -change that commit anymore in any way. But you can reset your current -head to an earlier commit and start over. - - If you have published your history already, rewriting it in this way -can be confusing and should be avoided. However, rewriting your local -history is fine and it is often cleaner to fix mistakes this way than -by reverting commits (with `v', for example). - - Typing `x' will ask for a revision and reset your current head to -it. No changes will be made to your working tree and staging area. -Thus, the _Staged changes_ section in the status buffer will show the -changes that you have removed from your commit history. You can commit -the changes again as if you had just made them, thus rewriting history. - - Typing `x' while point is in a line that describes a commit will -offer this commit as the default revision to reset to. Thus, you can -move point to one of the commits in the _Unpushed commits_ section and -hit `x RET' to reset your current head to it. - - Type `X' to reset your working tree and staging area to the most -recently committed state. This will discard your local modifications, -so be careful. - - You can give a prefix to `x' if you want to reset both the current -head and your working tree to a given commit. This is the same as -first using an unprefixed `x' to reset only the head, and then using -`X'. - - -File: magit.info, Node: Stashing, Next: Branching, Prev: Resetting, Up: Top - -13 Stashing -*********** - -You can create a new stash with `z z'. Your stashes will be listed in -the status buffer, and you can apply them with `a' and pop them with -`A'. To drop a stash, use `k'. - - With a prefix argument, both `a' and `A' will attempt to reinstate -the index as well as the working tree from the stash. - - Typing `z -k z' will create a stash just like `z z', but will leave -the changes in your working tree and index. This makes it easier to, -for example, test multiple variations of the same change. - - If you just want to make quick snapshots in between edits, you can -use `z s', which automatically enters a timestamp as description, and -keeps your working tree and index intact by default. - - You can visit and show stashes in the usual way: Typing `SPC' and -`DEL' will pop up a buffer with the description of the stash and scroll -it, typing `RET' will move point into that buffer. Using `C-u RET' will -move point into that buffer in other window. - - -File: magit.info, Node: Branching, Next: The Branch Manager, Prev: Stashing, Up: Top - -14 Branching -************ - -The current branch is indicated in the header of the status buffer. -You can switch to a different branch by typing `b b'. This will -immediately checkout the branch into your working copy, so you -shouldn't have any local modifications when switching branches. - - If you try to switch to a remote branch, Magit will offer to create a -local tracking branch for it instead. This way, you can easily start -working on new branches that have appeared in a remote repository. - - Typing `b b' while point is at a commit description will offer that -commit as the default to switch to. This will result in a detached -head. - - Typing `b m' will let you rename a branch. Unless a branch with the -same name already exists, obviously... - - To create a new branch and switch to it immediately, type `b n'. - - To delete a branch, type `b d'. If you're currently on that branch, -Magit will offer to switch to the 'master' branch. - - Deleting a branch is only possible if it's already fully merged into -HEAD or its upstream branch. Unless you type `b D', that is. Here be -dragons... - - Typing `b v' will list the local and remote branches in a new buffer -called `*magit-branches*' from which you can work with them. See *note -The Branch Manager:: for more details. - - -File: magit.info, Node: The Branch Manager, Next: Wazzup, Prev: Branching, Up: Top - -15 The Branch Manager -********************* - -The Branch Manager is a separate buffer called `*magit-branches*' with -its own local key map. The buffer contains both local and remote -branches. The current local branch is marked by a "*" in front of the -name. - - To check out a branch, move your cursor to the desired branch and -press `RET'. - - Typing `k' will delete the branch in the current line, and `C-u k' -deletes it even if it hasn't been merged into the current local branch. -Deleting works for both local and remote branches. - - By typing `T' on a local branch, you can change which remote branch -it's set to track. - - -File: magit.info, Node: Wazzup, Next: Merging, Prev: The Branch Manager, Up: Top - -16 Wazzup -********* - -Typing `w' will show a summary of how your other branches relate to the -current branch. - - For each branch, you will get a section that lists the commits in -that branch that are not in the current branch. The sections are -initially collapsed; you need to explicitly open them with `TAB' (or -similar) to show the lists of commits. - - When point is on a _N unmerged commits in ..._ title, the -corresponding branch will be offered as the default for a merge. - - Hitting `i' on a branch title will ignore this branch in the wazzup -view. You can use `C-u w' to show all branches, including the ignored -ones. Hitting `i' on an already ignored branch in that view will -unignore it. - - -File: magit.info, Node: Merging, Next: Rebasing, Prev: Wazzup, Up: Top - -17 Merging -********** - -Magit offers two ways to merge branches: manual and automatic. A -manual merge will apply all changes to your working tree and staging -area, but will not commit them, while an automatic merge will go ahead -and commit them immediately. - - Type `m m' to initiate merge. - - After initiating a merge, the header of the status buffer might -remind you that the next commit will be a merge commit (with more than -one parent). If you want to abort a manual merge, just do a hard reset -to HEAD with `X'. - - Merges can fail if the two branches you want to merge introduce -conflicting changes. In that case, the automatic merge stops before the -commit, essentially falling back to a manual merge. You need to resolve -the conflicts for example with `e' and stage the resolved files, for -example with `S'. - - You can not stage individual hunks one by one as you resolve them, -you can only stage whole files once all conflicts in them have been -resolved. - - -File: magit.info, Node: Rebasing, Next: Interactive Rebasing, Prev: Merging, Up: Top - -18 Rebasing -*********** - -Typing `R' in the status buffer will initiate a rebase or, if one is -already in progress, ask you how to continue. - - When a rebase is stopped in the middle because of a conflict, the -header of the status buffer will indicate how far along you are in the -series of commits that are being replayed. When that happens, you -should resolve the conflicts and stage everything and hit `R c' to -continue the rebase. Alternatively, hitting `c' or `C' while in the -middle of a rebase will also ask you whether to continue the rebase. - - Of course, you can initiate a rebase in any number of ways, by -configuring `git pull' to rebase instead of merge, for example. Such a -rebase can be finished with `R' as well. - - -File: magit.info, Node: Interactive Rebasing, Next: Rewriting, Prev: Rebasing, Up: Top - -19 Interactive Rebasing -*********************** - -Typing `E' in the status buffer will initiate an interactive rebase. -This is equivalent to running `git rebase --interactive' at the command -line. The `git-rebase-todo' file will be opened in an Emacs buffer for -you to edit. This file is opened using `emacsclient', so just edit this -file as you normally would, then call the `server-edit' function -(typically bound to `C-x #') to tell Emacs you are finished editing, -and the rebase will proceed as usual. - - If you have loaded `rebase-mode.el' (which is included in the Magit -distribution), the `git-rebase-todo' buffer will be in `rebase-mode'. -This mode disables normal text editing but instead provides single-key -commands (shown in the buffer) to perform all the edits that you would -normally do manually, including changing the operation to be performed -each commit ("pick", "squash", etc.), deleting (commenting out) commits -from the list, and reordering commits. You can finish editing the -buffer and proceed with the rebase by pressing `C-c C-c', which is -bound to `server-edit' in this mode, and you can abort the rebase with -`C-c C-k', just like when editing a commit message in Magit. - - -File: magit.info, Node: Rewriting, Next: Pushing and Pulling, Prev: Interactive Rebasing, Up: Top - -20 Rewriting -************ - -As hinted at earlier, you can rewrite your commit history. For -example, you can reset the current head to an earlier commit with `x'. -This leaves the working tree unchanged, and the status buffer will show -all the changes that have been made since that new value of the current -head. You can commit these changes again, possibly splitting them into -multiple commits as you go along. - - Amending your last commit is a common special case of rewriting -history like this. - - Another common way to rewrite history is to reset the head to an -earlier commit, and then to cherry pick the previous commits in a -different order. You could pick them from the reflog, for example. - - Magit has several commands that can simplify the book keeping -associated with rewriting. These commands all start with the `r' -prefix key. - - Typing `r b' will start a rewrite operation. You will be prompted -for a _base_ commit. This commit and all subsequent commits up until -the current head are then put in a list of _Pending commits_, after -which the current head will be reset to the _parent_ of the base -commit. This can be configured to behave like `git rebase', i.e. -exclude the selected base commit from the rewrite operation, with the -`magit-rewrite-inclusive' variable. - - You would then typically use `a' and `A' to cherry pick commits from -the list of pending commits in the desired order, until all have been -applied. Magit shows which commits have been applied by changing their -marker from `*' to `.'. - - Using `A' will immediately commit the commit (as usual). If you -want to combine multiple previous commits into a single new one, use -`a' to apply them all to your working tree, and then commit them -together. - - Magit has no explicit support for rewriting merge commits. It will -happily include merge commits in the list of pending commits, but there -is no way of replaying them automatically. You have to redo the merge -explicitly. - - You can also use `v' to revert a commit when you have changed your -mind. This will change the `.' mark back to `*'. - - Once you are done with the rewrite, type `r s' to remove the book -keeping information from the status buffer. - - If you rather wish to start over, type `r a'. This will abort the -rewriting, resetting the current head back to the value it had before -the rewrite was started with `r b'. - - Typing `r f' will _finish_ the rewrite: it will apply all unused -commits one after the other, as if you would us `A' with all of them. - - You can change the `*' and `.' marks of a pending commit explicitly -with `r *' and `r .'. - - In addition to a list of pending commits, the status buffer will show -the _Pending changes_. This section shows the diff between the -original head and the current head. You can use it to review the -changes that you still need to rewrite, and you can apply hunks from -it, like from any other diff. - - -File: magit.info, Node: Pushing and Pulling, Next: Bisecting, Prev: Rewriting, Up: Top - -21 Pushing and Pulling -********************** - -Magit will run `git push' when you type `P P'. If you give a prefix -argument to `P P', you will be prompted for the repository to push to. -When no default remote repository has been configured yet for the -current branch, you will be prompted as well. Typing `P P' will only -push the current branch to the remote. In other words, it will run -`git push '. The branch will be created in the remote -if it doesn't exist already. The local branch will be configured so -that it pulls from the new remote branch. If you give a double prefix -argument to `P P', you will be prompted in addition for the target -branch to push to. In other words, it will run `git push -:'. - - Typing `f f' will run `git fetch'. It will prompt for the name of -the remote to update if there is no default one. Typing `f o' will -always prompt for the remote. Typing `F F' will run `git pull'. When -you don't have a default branch configured to be pulled into the -current one, you will be asked for it. - - If there is a default remote repository for the current branch, Magit -will show that repository in the status buffer header. - - In this case, the status buffer will also have a _Unpushed commits_ -section that shows the commits on your current head that are not in the -branch named `/'. This section works just like the -history buffer: you can see details about a commit with `RET', compare -two of them with `.' and `=', and you can reset your current head to -one of them with `x', for example. If you want to push the changes then -type `P P'. - - When the remote branch has changes that are not in the current -branch, Magit shows them in a section called _Unpulled changes_. Typing -`F F' will fetch and merge them into the current branch. - - -File: magit.info, Node: Submodules, Next: Using Magit Extensions, Prev: Bisecting, Up: Top - -22 Submodules -************* - -`M u' - Update the submodules, with a prefix argument it will initializing. - -`M i' - Initialize the submodules. - -`M b' - Update and initialize the submodules in one go. - -`M s' - Synchronizes submodules' remote URL configuration setting to the - value specified in .gitmodules. - - -File: magit.info, Node: Bisecting, Next: Submodules, Prev: Pushing and Pulling, Up: Top - -23 Bisecting -************ - -Magit supports bisecting by showing how many revisions and steps are -left to be tested in the status buffer. You can control the bisect -session from both the status and from log buffers with the `B' key menu. - - Typing `B s' will start a bisect session. You will be prompted for -a revision that is known to be bad (defaults to _HEAD_) and for a -revision that is known to be good (defaults to the revision at point if -there is one). git will select a revision for you to test, and Magit -will update its status buffer accordingly. - - You can tell git that the current revision is good with `B g', that -it is bad with `B b' or that git should skip it with `B k'. You can -also tell git to go into full automatic mode by giving it the name of a -script to run for each revision to test with `B u'. - - The current status can be shown as a log with `B l'. It contains the -revisions that have already been tested and your decisions about their -state. - - The revisions left to test can be visualized in gitk with `B v'. - - When you're finished bisecting you have to reset the session with `B -r'. - - -File: magit.info, Node: Using Magit Extensions, Next: Using Git Directly, Prev: Submodules, Up: Top - -24 Magit Extensions -******************* - -* Menu: - -* Activating extensions:: -* Interfacing with Subversion:: -* Interfacing with Topgit:: -* Interfacing with StGit:: -* Developing Extensions:: - - -File: magit.info, Node: Activating extensions, Next: Interfacing with Subversion, Up: Using Magit Extensions - -24.1 Activating extensions -========================== - -Magit comes with a couple of shipped extensions that allow interaction -with `git-svn', `topgit' and `stgit'. See following sections for -specific details on how to use them. - - Extensions can be activated globally or on a per-repository basis. -Since those extensions are implemented as minor modes, one can use for -example `M-x magit-topgit-mode' to toggle the `topgit' extension, -making the corresponding section and commands (un)available. - - In order to do that automatically (and for every repository), one can -use for example: - - (add-hook 'magit-mode-hook 'turn-on-magit-topgit) - - Magit also allows configuring different extensions, based on the git -repository configuration. - - (add-hook 'magit-mode-hook 'magit-load-config-extensions) - - This will read git configuration variables and activate the relevant -extensions. - - For example, after running the following commands, the `topgit' -extension will be loaded for every repository, while the `svn' one will -be loaded only for the current one. - - $ git config --global --add magit.extension topgit - $ git config --add magit.extension svn - - Note the `--add' flag, which means that each extension gets its own -line in the `config' file. - - -File: magit.info, Node: Interfacing with Subversion, Next: Interfacing with Topgit, Prev: Activating extensions, Up: Using Magit Extensions - -24.2 Interfacing with Subversion -================================ - -Typing `N r' runs `git svn rebase', typing `N c' runs `git svn dcommit' -and typing `N f' runs `git svn fetch'. - - `N s' will prompt you for a (numeric, Subversion) revision and then -search for a corresponding Git sha1 for the commit. This is limited to -the path of the remote Subversion repository. With a prefix (`C-u N s' -the user will also be prompted for a branch to search in. - - -File: magit.info, Node: Interfacing with Topgit, Next: Interfacing with StGit, Prev: Interfacing with Subversion, Up: Using Magit Extensions - -24.3 Interfacing with Topgit -============================ - -Topgit (http://repo.or.cz/r/topgit.git) is a patch queue manager that -aims at being close as possible to raw Git, which makes it easy to use -with Magit. In particular, it does not require to use a different set of -commands for "commit", "update",… operations. - - `magit-topgit.el' provides basic integration with Magit, mostly by -providing a "Topics" section. - - Topgit branches can be created the regular way, by using a "t/" -prefix by convention. So, creating a "t/foo" branch will actually -populate the "Topics" section with one more branch after committing -`.topdeps' and `.topmsg'. - - Also, the way we pull (see *note Pushing and Pulling::) such a -branch is slightly different, since it requires updating the various -dependencies of that branch. This should be mostly transparent, except -in case of conflicts. - - -File: magit.info, Node: Interfacing with StGit, Next: Developing Extensions, Prev: Interfacing with Topgit, Up: Using Magit Extensions - -24.4 Interfacing with StGit -=========================== - -StGit (http://www.procode.org/stgit) is a Python application providing -similar functionality to Quilt (i.e. pushing/popping patches to/from a -stack) on top of Git. These operations are performed using Git commands -and the patches are stored as Git commit objects, allowing easy merging -of the StGit patches into other repositories using standard Git -functionality. - - `magit-stgit.el' provides basic integration with Magit, mostly by -providing a "Series" section, whose patches can be seen as regular -commits through the "visit" action. - - You can change the current patch in a series with the "apply" action, -as well as you can delete them using the "discard" action. - - Additionally, the `magit-stgit-refresh' and `magit-stgit-rebase' -commands let you perform the respective StGit operations. - - -File: magit.info, Node: Developing Extensions, Prev: Interfacing with StGit, Up: Using Magit Extensions - -24.5 Developing Extensions -========================== - -Magit provides a generic mechanism to allow cooperation with Git-related -systems, such as foreign VCS, patch systems,… - - In particular it allows to: - - * Define sections to display specific informations about the current - state of the repository, and place them relatively to existing - sections. - - `magit-define-inserter' automagically defines two hooks called - `magit-before-insert-SECTION-hook' and - `magit-after-insert-SECTION-hook' that allow to generate and place - more sections. - - In the following example, we use the builtin "stashes" section to - place our own "foo" one. - - (magit-define-inserter foo () - (magit-git-section 'foo - "Foo:" 'foo-wash-function - "foo" "arg1" "arg2")) - (add-hook 'magit-after-insert-stashes-hook 'magit-insert-foo) - - * Define new types of objects in those sections. - - The function `foo-wash-function' defined above post-processes each - line of the output of the "git foo arg1 arg2" command, and is able - to associate a type to certain lines. - - A simple implementation could be: - - (defun foo-wash-function () - (let ((foo (buffer-substring (line-beginning-position) (line-end-position)))) - (goto-char (line-beginning-position)) - (magit-with-section foo 'foo - (magit-set-section-info foo) - (forward-line)))) - - In this case, every line of the command output is transformed into - an object of type `'foo'. - - * Alter behavior of generic commands to dispatch them correctly to - the relevant system, optionally making use of the newly defined - types. - - (magit-add-action (item info "discard") - ((foo) - (do-something-meaningful-for-discarding-a-foo))) - - This will alter the behavior of `k', when applied to those objects. - - * Plug a different logic into basic commands, to reflect the - presence of the extension. - - `magit-define-command' automagically defines a - `magit-CMD-command-hook' that can contain a list of functions to - call before the actual core code. Execution stops after the first - hook that returns a non-nil value. This leaves room for extension - logic. - - (add-hook 'magit-create-branch-command-hook 'foo-create-branch) - - The function `foo-create-branch' will be called each time an - attempt is made to create a branch, and can, for example, react to - a certain name convention. - - * Define new commands and associated menu. - - This part is not really specific to extensions, except that menus - take place in the "Extensions" submenu. - - - It is suggested that Magit extensions authors stick to the -convention of making extensions minor modes. This has many advantages, -including the fact that users are able to toggle extensions, and that -it's easy to configure a specific set of extensions for a given -repository. - - Shipped extensions can serve as an example of how to develop new -extensions. - - Basically a `foo' extension should provide a `magit-foo-mode' minor -mode, as well as a `turn-on-magit-foo' function. The main task of the -minor mode is to register/unregister the various hooks that the -extension requires. The registered actions on the other hand can be -left alone and activated globally, since they can be run only on -displayed items, which won't happen when the minor mode is off. - - Don't forget to call `magit-refresh' when the minor mode is toggled -interactively, so that the relevant sections can be shown or hidden. - - -File: magit.info, Node: Using Git Directly, Next: Customization, Prev: Using Magit Extensions, Up: Top - -25 Using Git Directly -********************* - -For situations when Magit doesn't do everything you need, you can run -raw Git commands using `:'. This will prompt for a Git command, run -it, and refresh the status buffer. The output can be viewed by typing -`$'. - - -File: magit.info, Node: Customization, Next: Frequently Asked Questions, Prev: Using Git Directly, Up: Top - -26 Customization -**************** - -The following variables can be used to adapt Magit to your workflow: - -`magit-git-executable' - The name of the Git executable. - -`magit-git-standard-options' - Standard options when running Git. - -`magit-repo-dirs' - Directories containing Git repositories. - - Magit will look into these directories for Git repositories and - offer them as choices for `magit-status'. - -`magit-repo-dirs-depth' - The maximum depth to look for Git repos. - - When looking for a Git repository below the directories in - `magit-repo-dirs', Magit will only descend this many levels deep. - -`magit-save-some-buffers' - Non-nil means that `magit-status' will save modified buffers - before running. Setting this to `t' will ask which buffers to - save, setting it to `'dontask' will save all modified buffers - without asking. - -`magit-save-some-buffers-predicate' - Specifies a predicate function on `magit-save-some-buffers' to - determine which unsaved buffers should be prompted for saving. - -`magit-commit-all-when-nothing-staged' - Determines what `magit-log-edit' does when nothing is staged. - Setting this to `nil' will make it do nothing, setting it to `t' - will arrange things so that the actual commit command will use the - `--all' option, setting it to `'ask' will first ask for - confirmation whether to do this, and setting it to `'ask-stage' - will cause all changes to be staged, after a confirmation. - -`magit-commit-signoff' - When performing `git commit' adds `--signoff'. - -`magit-log-cutoff-length' - The maximum number of commits to show in the `log' and `whazzup' - buffers. - -`magit-log-infinite-length' - Number of log used to show as maximum for - `magit-log-cutoff-length'. - -`magit-log-auto-more' - Insert more log entries automatically when moving past the last - entry. - - Only considered when moving past the last entry with - `magit-goto-next-section'. - -`magit-process-popup-time' - Popup the process buffer if a command takes longer than this many - seconds. - -`magit-revert-item-confirm' - Require acknowledgment before reverting an item. - -`magit-log-edit-confirm-cancellation' - Require acknowledgment before canceling the log edit buffer. - -`magit-remote-ref-format' - What format to use for autocompleting refs, in pariticular for - remotes. - - Autocompletion is used by functions like `magit-checkout', - `magit-interactive-rebase' and others which offer branch name - completion. - - The value `'name-then-remote' means remotes will be of the form - `name (remote)', while the value `'remote-slash-name' means that - they'll be of the form `remote/name'. I.e. something that's listed - as `remotes/upstream/next' by `git branch -l -a' will be - `upstream/next'. - -`magit-process-connection-type' - Connection type used for the git process. - - `nil' mean pipe, it is usually faster and more efficient, and work - on cygwin. `t' mean pty, it enable magit to prompt for passphrase - when needed. - -`magit-completing-read-function' - Function to be called when requesting input from the user. - -`magit-create-branch-behaviour' - Where magit will create a new branch if not supplied a branchname - or ref. - - The value `'at-head' means a new branch will be created at the tip - of your current branch, while the value `'at-point' means magit - will try to find a valid reference at point... - -`magit-status-buffer-switch-function' - Function for `magit-status' to use for switching to the status - buffer. - - The function is given one argument, the status buffer. - -`magit-rewrite-inclusive' - Whether magit includes the selected base commit in a rewrite - operation. - - `t' means both the selected commit as well as any subsequent - commits will be rewritten. This is magit's default behaviour, - equivalent to `git rebase -i ${REV~1}' - - A'---B'---C'---D' - ^ - - `nil' means the selected commit will be literally used as `base', - so only subsequent commits will be rewritten. This is consistent - with git-rebase, equivalent to `git rebase -i ${REV}', yet more - cumbersome to use from the status buffer. - - A---B'---C'---D' - ^ - -`magit-topgit-executable' - The name of the TopGit executable. - -`magit-topgit-branch-prefix' - Convention prefix for topic branch creation. - - - -File: magit.info, Node: Frequently Asked Questions, Prev: Customization, Up: Top - -27 Frequently Asked Questions -***************************** - -* Menu: - -* FAQ - Changes:: -* FAQ 1 - Troubleshooting:: -* FAQ 2 - Display issues:: - - -File: magit.info, Node: FAQ - Changes, Next: FAQ 1 - Troubleshooting, Up: Frequently Asked Questions - -27.1 Changes -============ - - * v1.1: Changed the way extensions work. Previously, they were - enabled unconditionally once the library was loaded. Now they are - minor modes that need to be activated explicitly (potentially on a - per-repository basis). See *note Activating extensions::. - - - -File: magit.info, Node: FAQ 1 - Troubleshooting, Next: FAQ 2 - Display issues, Prev: FAQ - Changes, Up: Frequently Asked Questions - -27.2 Troubleshooting -==================== - -* Menu: - -* FAQ 1-1:: How do I get raw error messages from git? - - -File: magit.info, Node: FAQ 1-1, Up: FAQ 1 - Troubleshooting - -27.2.1 Question 1.1 -------------------- - -How do I get raw error messages from git? - -Answer -...... - -If a command goes wrong, you can hit `$' to access the git process -buffer. There, the entire trace for the latest operation is available. - - -File: magit.info, Node: FAQ 2 - Display issues, Prev: FAQ 1 - Troubleshooting, Up: Frequently Asked Questions - -27.3 Display issues -=================== - -* Menu: - -* FAQ 2-1:: How do I fix international characters display? - - -File: magit.info, Node: FAQ 2-1, Up: FAQ 2 - Display issues - -27.3.1 Question 2.1 -------------------- - -How do I fix international characters display? - -Answer -...... - -Please make sure your Magit buffer uses a compatible coding system. In -the particular case of file names, git itself quotes them by default. -You can disable this with one of the following approaches: - - $ git config core.quotepath false - - or - - (setq magit-git-standard-options (append magit-git-standard-options - '("-c" "core.quotepath=false"))) - - The latter might not work in old versions of git. - - - -Tag Table: -Node: Top640 -Node: Introduction1593 -Node: Acknowledgments3065 -Node: Sections3745 -Node: Status6295 -Node: Untracked files9034 -Node: Staging and Committing10238 -Node: History14136 -Node: Reflogs17316 -Node: Commit Buffer17720 -Node: Diffing19046 -Node: Tagging20033 -Node: Resetting20482 -Node: Stashing22006 -Node: Branching23064 -Node: The Branch Manager24442 -Node: Wazzup25158 -Node: Merging25949 -Node: Rebasing26999 -Node: Interactive Rebasing27825 -Node: Rewriting29117 -Node: Pushing and Pulling32142 -Node: Submodules34069 -Node: Bisecting34489 -Node: Using Magit Extensions35704 -Node: Activating extensions36001 -Node: Interfacing with Subversion37385 -Node: Interfacing with Topgit37983 -Node: Interfacing with StGit39011 -Node: Developing Extensions40009 -Node: Using Git Directly43787 -Node: Customization44158 -Node: Frequently Asked Questions48702 -Node: FAQ - Changes48933 -Node: FAQ 1 - Troubleshooting49341 -Node: FAQ 1-149589 -Node: FAQ 2 - Display issues49893 -Node: FAQ 2-150122 - -End Tag Table - - -Local Variables: -coding: utf-8 -End: diff --git a/elpa/magit-1.2.1/rebase-mode.el b/elpa/magit-1.2.1/rebase-mode.el deleted file mode 100644 index 1ccfb54..0000000 --- a/elpa/magit-1.2.1/rebase-mode.el +++ /dev/null @@ -1,322 +0,0 @@ -;;; rebase-mode -- edit git rebase files. - -;; Copyright (C) 2010 Phil Jackson -;; Copyright (C) 2011 Peter J Weisberg -;; -;; 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 . - -;;; Commentary: - -;; Allows the editing of a git rebase file (which you might get when -;; using 'git rebase -i' or hitting 'E' in Magit). Assumes editing is -;; happening in a server. - -;;; Code: - -(require 'server) - -(defgroup rebase-mode nil - "Customize Rebase Mode" - :group 'faces) - -(defface rebase-mode-killed-action-face - '((((class color)) - :inherit font-lock-comment-face - :strike-through t)) - "Action lines in the rebase TODO list that have been commented out." - :group 'rebase-mode) - -(defface rebase-mode-description-face - '((t :inherit font-lock-comment-face)) - "Face for one-line commit descriptions" - :group 'rebase-mode) - -(defconst rebase-mode-action-line-re - (rx - line-start - (? "#") - (group - (| - (any "presf") - "pick" - "reword" - "edit" - "squash" - "fixup")) - (char space) - (group - (** 4 40 hex-digit)) ;sha1 - (char space) - (group - (* not-newline))) - "Regexp that matches an action line in a rebase buffer.") - -(defconst rebase-mode-exec-line-re - (rx - line-start - (? "#") - (group - (| "x" - "exec")) - (char space) - (group - (* not-newline))) - "Regexp that matches an exec line in a rebase buffer.") - -(defconst rebase-mode-dead-line-re - (rx-to-string `(and line-start - (char ?#) - (or (regexp ,(substring rebase-mode-action-line-re 1)) - (regexp ,(substring rebase-mode-exec-line-re 1)))) t) - "Regexp that matches a commented-out exec or action line in a rebase buffer.") - -(defvar rebase-mode-font-lock-keywords - (list - (list rebase-mode-action-line-re - '(1 font-lock-keyword-face) - '(2 font-lock-builtin-face) - '(3 'rebase-mode-description-face)) - (list rebase-mode-exec-line-re - '(1 font-lock-keyword-face)) - (list (rx line-start (char "#") (* not-newline)) 0 font-lock-comment-face) - (list rebase-mode-dead-line-re 0 ''rebase-mode-killed-action-face t)) - "Font lock keywords for `rebase-mode'.") - -(defvar key-to-action-map - '(("c" . "pick") - ("r" . "reword") - ("e" . "edit") - ("s" . "squash") - ("f" . "fixup")) - "Mapping from key to action.") - -(defvar rebase-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "q") 'server-edit) - (define-key map (kbd "C-c C-c") 'server-edit) - - (define-key map (kbd "a") 'rebase-mode-abort) - (define-key map (kbd "C-c C-k") 'rebase-mode-abort) - - (define-key map (kbd "M-p") 'rebase-mode-move-line-up) - (define-key map (kbd "M-n") 'rebase-mode-move-line-down) - (define-key map (kbd "k") 'rebase-mode-kill-line) - (define-key map (kbd "x") 'rebase-mode-exec) - - (define-key map (kbd "n") 'forward-line) - (define-key map (kbd "p") '(lambda(n) - (interactive "p") - (forward-line (* n -1)))) - (define-key map [remap undo] 'rebase-mode-undo) - map) - "Keymap for rebase-mode. Note this will be added to by the -top-level code which defines the edit functions.") - -(require 'easymenu) -(easy-menu-define rebase-mode-menu rebase-mode-map - "Rebase-mode menu" - '("Rebase" - ["Pick" rebase-mode-pick t] - ["Reword" rebase-mode-reword t] - ["Edit" rebase-mode-edit t] - ["Squash" rebase-mode-squash t] - ["Fixup" rebase-mode-fixup t] - ["Kill" rebase-mode-kill-line t] - ["Move Down" rebase-mode-move-line-down t] - ["Move Up" rebase-mode-move-line-up t] - ["Execute" rebase-mode-exec t] - "---" - ["Abort" rebase-mode-abort t] - ["Done" server-edit t])) - -;; create the functions which edit the action lines themselves (based -;; on `key-to-action-map' above) -(mapc (lambda (key-action) - (let ((fun-name (intern (concat "rebase-mode-" (cdr key-action))))) - ;; define the function - (eval `(defun ,fun-name () - (interactive) - (rebase-mode-edit-line ,(cdr key-action)))) - - ;; bind the function in `rebase-mode-map' - (define-key rebase-mode-map (car key-action) fun-name))) - key-to-action-map) - -(defun rebase-mode-edit-line (change-to) - "Change the keyword at the start of the current action line to -that of CHANGE-TO." - (when (rebase-mode-looking-at-action) - (let ((buffer-read-only nil) - (start (point))) - (goto-char (point-at-bol)) - (delete-region (point) (progn (forward-word 1) (point))) - (insert change-to) - (goto-char start)))) - -(defun rebase-mode-looking-at-action () - "Return non-nil if looking at an action line." - (save-excursion - (goto-char (point-at-bol)) - (looking-at rebase-mode-action-line-re))) - -(defun rebase-mode-looking-at-action-or-exec () - "Return non-nil if looking at an action line or exec line." - (save-excursion - (goto-char (point-at-bol)) - (or (looking-at rebase-mode-action-line-re) - (looking-at rebase-mode-exec-line-re)))) - -(defun rebase-mode-looking-at-exec () - "Return non-nil if cursor is on an exec line." - (string-match rebase-mode-exec-line-re (thing-at-point 'line))) - -(defun rebase-mode-looking-at-killed-exec () - "Return non-nil if looking at an exec line that has been commented out" - (let ((line (thing-at-point 'line))) - (and (eq (aref line 0) ?#) - (string-match rebase-mode-exec-line-re line)))) - -(defun rebase-mode-move-line-up () - "Move the current action line up." - (interactive) - (when (rebase-mode-looking-at-action-or-exec) - (let ((buffer-read-only nil) - (col (current-column))) - (transpose-lines 1) - (forward-line -2) - (move-to-column col)))) - -(defun rebase-mode-move-line-down () - "Assuming the next line is also an action line, move the current line down." - (interactive) - ;; if we're on an action and the next line is also an action - (when (and (rebase-mode-looking-at-action-or-exec) - (save-excursion - (forward-line) - (rebase-mode-looking-at-action-or-exec))) - (let ((buffer-read-only nil) - (col (current-column))) - (forward-line 1) - (transpose-lines 1) - (forward-line -1) - (move-to-column col)))) - -(defun rebase-mode-abort () - "Abort this rebase (by emptying the buffer, saving and closing -server connection)." - (interactive) - (when (or (not (buffer-modified-p)) - (y-or-n-p "Abort this rebase? ")) - (let ((buffer-read-only nil)) - (delete-region (point-min) (point-max)) - (save-buffer) - (server-edit)))) - -(defun rebase-mode-kill-line () - "Kill the current action line." - (interactive) - (when (and (not (eq (char-after (point-at-bol)) ?#)) - (rebase-mode-looking-at-action-or-exec)) - (beginning-of-line) - (let ((buffer-read-only nil)) - (insert "#")) - (forward-line))) - -(defun rebase-mode-exec (edit) - "Prompt the user for a shell command to be executed, and add it to -the todo list. - -If the cursor is on a commented-out exec line, uncomment the -current line instead of prompting. - -When the prefix argument EDIT is non-nil and the cursor is on an -exec line, edit that line instead of inserting a new one. If the -exec line was commented out, also uncomment it." - (interactive "P") - (cond - ((and edit (rebase-mode-looking-at-exec)) - (let ((new-line (rebase-mode-read-exec-line - (match-string-no-properties 2 (thing-at-point 'line)))) - (inhibit-read-only t)) - (delete-region (point-at-bol) (point-at-eol)) - (if (not (equal "" new-line)) - (insert "exec " new-line) - (delete-char -1) - (forward-line)) - (move-beginning-of-line nil))) - ((rebase-mode-looking-at-killed-exec) - (save-excursion - (beginning-of-line) - (let ((buffer-read-only nil)) - (delete-char 1)))) - (t - (let ((inhibit-read-only t) - (line (rebase-mode-read-exec-line))) - (unless (equal "" line) - (move-end-of-line nil) - (newline) - (insert (concat "exec " line)))) - (move-beginning-of-line nil)))) - -(defun rebase-mode-read-exec-line (&optional initial-line) - (read-shell-command "Execute: " initial-line)) - -(defun rebase-mode-undo (&optional arg) - "A thin wrapper around `undo', which allows undoing in -read-only buffers." - (interactive "P") - (let ((inhibit-read-only t)) - (undo arg))) - -;;;###autoload -(define-derived-mode rebase-mode special-mode "Rebase" - "Major mode for editing of a Git rebase file. - -Rebase files are generated when you run 'git rebase -i' or run -`magit-interactive-rebase'. They describe how Git should perform -the rebase. See the documentation for git-rebase (e.g., by -running 'man git-rebase' at the command line) for details." - (setq font-lock-defaults '(rebase-mode-font-lock-keywords t t))) - -(defun rebase-mode-show-keybindings () - "Modify the \"Commands:\" section of the comment Git generates -at the bottom of the file so that in place of the one-letter -abbreviation for the command, it shows the command's keybinding. -By default, this is the same except for the \"pick\" command." - (save-excursion - (goto-char (point-min)) - (while (search-forward-regexp "^# \\(.\\), \\([[:alpha:]]+\\) = " nil t) - (let ((start (match-beginning 1)) - (end (match-end 1)) - (command (intern (concat "rebase-mode-" (match-string 2))))) - (when (fboundp command) - (let ((overlay (make-overlay start end))) - (overlay-put overlay - 'display - (key-description (where-is-internal command nil t))))))))) - -(add-hook 'rebase-mode-hook 'rebase-mode-show-keybindings t) - -(defun rebase-mode-disable-before-save-hook () - (set (make-local-variable 'before-save-hook) nil)) - -(add-hook 'rebase-mode-hook 'rebase-mode-disable-before-save-hook) - -;;;###autoload -(add-to-list 'auto-mode-alist - '("git-rebase-todo" . rebase-mode)) - -(provide 'rebase-mode) - -;;; rebase-mode.el ends here diff --git a/elpa/magit-1.4.1/AUTHORS.md b/elpa/magit-1.4.1/AUTHORS.md new file mode 100644 index 0000000..36e4ffe --- /dev/null +++ b/elpa/magit-1.4.1/AUTHORS.md @@ -0,0 +1,184 @@ +Authors +======= + +Also see https://github.com/magit/magit/graphs/contributors. +Names below are sorted alphabetically. + +Author +------ + +- Marius Vollmer + +Maintainer +---------- + +- Jonas Bernoulli + +Retired Maintainers +------------------- + +- Nicolas Dudebout +- Peter J. Weisberg +- Phil Jackson +- RĂ©mi Vanicat +- Yann Hodique + +Contributors +------------ + +- aaa707 +- Aaron Culich +- Abdo Roig-Maranges +- acple +- Adam Spiers +- Ævar ArnfjörĂ° Bjarmason +- Alan Falloon +- Alexey Voinov +- Alex Ott +- Andreas Fuchs +- Andreas Liljeqvist +- Andreas Rottmann +- Andrei ChiÈ›u +- Andrew Kirkpatrick +- Andrew Schwartzmeyer +- Andrey Smirnov +- Bastian Beischer +- Ben Walton +- Bradley Wright +- Brandon W Maister +- Brian Warner +- Bryan Shell +- Chris Bernard +- Chris Done +- Chris Moore +- Chris Ring +- Christian Dietrich +- Christian Kluge +- Christopher Monsanto +- Cornelius Mika +- Craig Andera +- Dale Hagglund +- Damien Cassou +- Daniel Brockman +- Daniel Farina +- Daniel Hackney +- Dan LaManna +- David Abrahams +- David Hull +- David Wallin +- Dennis Paskorz +- Divye Kapoor +- Dominique Quatravaux +- Eli Barzilay +- Eric Davis +- Eric Schulte +- Evgkeni Sampelnikof +- Felix Geller +- Feng Li +- Geoff Shannon +- George Kadianakis +- Graham Clark +- Greg A. Woods +- Greg Sexton +- Hannu Koivisto +- Hans-Peter Deifel +- Ian Eure +- Jan Tatarik +- Jasper St. Pierre +- Jeff Bellegarde +- Jeff Dairiki +- Jesse Alama +- John Wiegley +- Jonas Bernoulli +- Jonathan Roes +- Jordan Greenberg +- Julien Danjou +- Justin Caratzas +- Kimberly Wolk +- Kyle Meyer +- Laurent Laffont +- Leandro Facchinetti +- Lele Gaifax +- Leo Liu +- Leonardo Etcheverry +- LluĂ­s Vilanova +- Loic Dachary +- LuĂ­s Borges de Oliveira +- Luke Amdor +- Manuel VĂ¡zquez Acosta +- Marcel Wolf +- Marc Herbert +- Marcin Bachry +- Marco Craveiro +- Marian Schubert +- Marius Vollmer +- Mark Hepburn +- Matus Goljer +- Miles Bader +- Mitchel Humpherys +- Moritz Bunkus +- Nathan Weizenbaum +- Nguyá»…n Tuấn Anh +- Nic Ferier +- Nick Alcock +- Nick Alexander +- Nick Dimiduk +- Nicolas Dudebout +- Nicolas Richard +- Noam Postavsky +- Ole Arndt +- Ă“scar Fuentes +- Paul Stadig +- Pavel Holejsovsky +- Pekka Pessi +- Peter J. Weisberg +- Philippe Vaucher +- Philipp Haselwarter +- Philip Weaver +- Phil Jackson +- Pieter Praet +- Prathamesh Sonpatki +- rabio +- Rafael Laboissiere +- Raimon Grau +- Ramkumar Ramachandra +- Remco van 't Veer +- RĂ©mi Vanicat +- RenĂ© Stadler +- Robert Boone +- Robin Green +- Roger Crew +- Romain Francoise +- Ron Parker +- Roy Crihfield +- RĂ¼diger Sonderfeld +- RĂ¼diger Sonderfeld +- Ryan C. Thompson +- Samuel Bronson +- Sanjoy Das +- Sean Bryant +- Sebastian Wiesner +- SĂ©bastien Gross +- Seong-Kook Shin +- Sergey Pashinin +- Sergey Vinokurov +- Servilio Afre Puentes +- Å tÄ›pĂ¡n NÄ›mec +- Steven Chow +- Steven Thomas +- Steve Purcell +- Suhail Shergill +- Takafumi Arakaki +- Teruki Shigitani +- Thierry Volpiatto +- Thomas Frössman +- Thomas Jost +- Thomas Riccardi +- Tibor Simko +- Timo Juhani Lindfors +- Ting-Yu Lin +- Tom Feist +- Wilfred Hughes +- Win Treese +- Yann Hodique +- York Zhao diff --git a/elpa/magit-1.2.1/dir b/elpa/magit-1.4.1/dir similarity index 88% rename from elpa/magit-1.2.1/dir rename to elpa/magit-1.4.1/dir index 5fec543..d389e6e 100644 --- a/elpa/magit-1.2.1/dir +++ b/elpa/magit-1.4.1/dir @@ -15,4 +15,4 @@ File: dir, Node: Top This is the top of the INFO tree * Menu: Emacs -* Magit: (magit). Using Git from Emacs with Magit. +* Magit (1.4.0): (magit). Using Git from Emacs with Magit. (1.4.0) diff --git a/elpa/magit-1.4.1/magit-autoloads.el b/elpa/magit-1.4.1/magit-autoloads.el new file mode 100644 index 0000000..cd1c0a4 --- /dev/null +++ b/elpa/magit-1.4.1/magit-autoloads.el @@ -0,0 +1,579 @@ +;;; magit-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (or (file-name-directory #$) (car load-path))) + +;;;### (autoloads nil "magit" "magit.el" (21831 16623 612188 923000)) +;;; Generated autoloads from magit.el + +(autoload 'magit-git-command "magit" "\ +Execute a Git subcommand asynchronously, displaying the output. +With a prefix argument run Git in the root of the current +repository. Non-interactively run Git in DIRECTORY with ARGS. + +\(fn ARGS DIRECTORY)" t nil) + +(autoload 'magit-show-commit "magit" "\ +Show information about COMMIT. + +\(fn COMMIT &optional NOSELECT)" t nil) + +(autoload 'magit-status "magit" "\ +Open a Magit status buffer for the Git repository containing DIR. +If DIR is not within a Git repository, offer to create a Git +repository in DIR. + +Interactively, a prefix argument means to ask the user which Git +repository to use even if `default-directory' is under Git +control. Two prefix arguments means to ignore `magit-repo-dirs' +when asking for user input. + +Depending on option `magit-status-buffer-switch-function' the +status buffer is shown in another window (the default) or the +current window. Non-interactively optional SWITCH-FUNCTION +can be used to override this. + +\(fn DIR &optional SWITCH-FUNCTION)" t nil) + +(autoload 'magit-stage-all "magit" "\ +Add all remaining changes in tracked files to staging area. +With a prefix argument, add remaining untracked files as well. +\('git add [-u] .'). + +\(fn &optional INCLUDING-UNTRACKED)" t nil) + +(autoload 'magit-unstage-all "magit" "\ +Remove all changes from staging area. +\('git reset --mixed HEAD'). + +\(fn)" t nil) + +(autoload 'magit-dired-jump "magit" "\ +Visit current item in dired. +With a prefix argument, visit in other window. + +\(fn &optional OTHER-WINDOW)" t nil) + +(autoload 'magit-show "magit" "\ +Display and select a buffer containing FILE as stored in REV. + +Insert the contents of FILE as stored in the revision REV into a +buffer. Then select the buffer using `pop-to-buffer' or with a +prefix argument using `switch-to-buffer'. Non-interactivity use +SWITCH-FUNCTION to switch to the buffer, if that is nil simply +return the buffer, without displaying it. + +\(fn REV FILE &optional SWITCH-FUNCTION)" t nil) + +(autoload 'magit-merge "magit" "\ +Merge REVISION into the current 'HEAD', leaving changes uncommitted. +With a prefix argument, skip editing the log message and commit. +\('git merge [--no-commit] REVISION'). + +\(fn REVISION &optional DO-COMMIT)" t nil) + +(autoload 'magit-merge-abort "magit" "\ +Abort the current merge operation. + +\(fn)" t nil) + +(autoload 'magit-checkout "magit" "\ +Switch 'HEAD' to REVISION and update working tree. +Fails if working tree or staging area contain uncommitted changes. +If REVISION is a remote branch, offer to create a local branch. +\('git checkout [-b] REVISION'). + +\(fn REVISION)" t nil) + +(autoload 'magit-create-branch "magit" "\ +Switch 'HEAD' to new BRANCH at revision PARENT and update working tree. +Fails if working tree or staging area contain uncommitted changes. +\('git checkout -b BRANCH REVISION'). + +\(fn BRANCH PARENT)" t nil) + +(autoload 'magit-delete-branch "magit" "\ +Delete the BRANCH. +If the branch is the current one, offers to switch to `master' first. +With prefix, forces the removal even if it hasn't been merged. +Works with local or remote branches. +\('git branch [-d|-D] BRANCH' or 'git push :refs/heads/BRANCH'). + +\(fn BRANCH &optional FORCE)" t nil) + +(autoload 'magit-rename-branch "magit" "\ +Rename branch OLD to NEW. +With prefix, forces the rename even if NEW already exists. +\('git branch [-m|-M] OLD NEW'). + +\(fn OLD NEW &optional FORCE)" t nil) + +(autoload 'magit-add-remote "magit" "\ +Add the REMOTE and fetch it. +\('git remote add REMOTE URL'). + +\(fn REMOTE URL)" t nil) + +(autoload 'magit-remove-remote "magit" "\ +Delete the REMOTE. +\('git remote rm REMOTE'). + +\(fn REMOTE)" t nil) + +(autoload 'magit-rename-remote "magit" "\ +Rename remote OLD to NEW. +\('git remote rename OLD NEW'). + +\(fn OLD NEW)" t nil) + +(autoload 'magit-interactive-rebase "magit" "\ +Start a git rebase -i session, old school-style. + +\(fn COMMIT)" t nil) + +(autoload 'magit-reset-head "magit" "\ +Switch 'HEAD' to REVISION, keeping prior working tree and staging area. +Any differences from REVISION become new changes to be committed. +With prefix argument, all uncommitted changes in working tree +and staging area are lost. +\('git reset [--soft|--hard] REVISION'). + +\(fn REVISION &optional HARD)" t nil) + +(autoload 'magit-reset-head-hard "magit" "\ +Switch 'HEAD' to REVISION, losing all changes. +Uncomitted changes in both working tree and staging area are lost. +\('git reset --hard REVISION'). + +\(fn REVISION)" t nil) + +(autoload 'magit-reset-working-tree "magit" "\ +Revert working tree and clear changes from staging area. +\('git reset --hard HEAD'). + +With a prefix arg, also remove untracked files. +With two prefix args, remove ignored files as well. + +\(fn &optional ARG)" t nil) + +(autoload 'magit-fetch "magit" "\ +Fetch from REMOTE. + +\(fn REMOTE)" t nil) + +(autoload 'magit-fetch-current "magit" "\ +Run fetch for default remote. + +If there is no default remote, ask for one. + +\(fn)" t nil) + +(autoload 'magit-remote-update "magit" "\ +Update all remotes. + +\(fn)" t nil) + +(autoload 'magit-pull "magit" "\ +Run git pull. + +If there is no default remote, the user is prompted for one and +its values is saved with git config. If there is no default +merge branch, the user is prompted for one and its values is +saved with git config. With a prefix argument, the default +remote is not used and the user is prompted for a remote. With +two prefix arguments, the default merge branch is not used and +the user is prompted for a merge branch. Values entered by the +user because of prefix arguments are not saved with git config. + +\(fn)" t nil) + +(autoload 'magit-push-tags "magit" "\ +Push tags to a remote repository. + +Push tags to the current branch's remote. If that isn't set push +to \"origin\" or if that remote doesn't exit but only a single +remote is defined use that. Otherwise or with a prefix argument +ask the user what remote to use. + +\(fn)" t nil) + +(autoload 'magit-push "magit" "\ +Push the current branch to a remote repository. + +This command runs the `magit-push-remote' hook. By default that +means running `magit-push-dwim'. So unless you have customized +the hook this command behaves like this: + +With a single prefix argument ask the user what branch to push +to. With two or more prefix arguments also ask the user what +remote to push to. Otherwise use the remote and branch as +configured using the Git variables `branch..remote' and +`branch..merge'. If the former is undefined ask the user. +If the latter is undefined push without specifing the remote +branch explicitly. + +Also see option `magit-set-upstream-on-push'. + +\(fn)" t nil) + +(autoload 'magit-commit "magit" "\ +Create a new commit on HEAD. +With a prefix argument amend to the commit at HEAD instead. +\('git commit [--amend]'). + +\(fn &optional AMENDP)" t nil) + +(autoload 'magit-commit-amend "magit" "\ +Amend the last commit. +\('git commit --amend'). + +\(fn)" t nil) + +(autoload 'magit-commit-extend "magit" "\ +Amend the last commit, without editing the message. +With a prefix argument do change the committer date, otherwise +don't. The option `magit-commit-extend-override-date' can be +used to inverse the meaning of the prefix argument. +\('git commit --no-edit --amend [--keep-date]'). + +\(fn &optional OVERRIDE-DATE)" t nil) + +(autoload 'magit-commit-reword "magit" "\ +Reword the last commit, ignoring staged changes. + +With a prefix argument do change the committer date, otherwise +don't. The option `magit-commit-rewrite-override-date' can be +used to inverse the meaning of the prefix argument. + +Non-interactively respect the optional OVERRIDE-DATE argument +and ignore the option. + +\('git commit --only --amend'). + +\(fn &optional OVERRIDE-DATE)" t nil) + +(autoload 'magit-commit-fixup "magit" "\ +Create a fixup commit. +With a prefix argument the user is always queried for the commit +to be fixed. Otherwise the current or marked commit may be used +depending on the value of option `magit-commit-squash-commit'. +\('git commit [--no-edit] --fixup=COMMIT'). + +\(fn &optional COMMIT)" t nil) + +(autoload 'magit-commit-squash "magit" "\ +Create a squash commit. +With a prefix argument the user is always queried for the commit +to be fixed. Otherwise the current or marked commit may be used +depending on the value of option `magit-commit-squash-commit'. +\('git commit [--no-edit] --fixup=COMMIT'). + +\(fn &optional COMMIT FIXUP)" t nil) + +(autoload 'magit-tag "magit" "\ +Create a new tag with the given NAME at REV. +With a prefix argument annotate the tag. +\('git tag [--annotate] NAME REV'). + +\(fn NAME REV &optional ANNOTATE)" t nil) + +(autoload 'magit-delete-tag "magit" "\ +Delete the tag with the given NAME. +\('git tag -d NAME'). + +\(fn NAME)" t nil) + +(autoload 'magit-stash "magit" "\ +Create new stash of working tree and staging area named DESCRIPTION. +Working tree and staging area revert to the current 'HEAD'. +With prefix argument, changes in staging area are kept. +\('git stash save [--keep-index] DESCRIPTION') + +\(fn DESCRIPTION)" t nil) + +(autoload 'magit-stash-snapshot "magit" "\ +Create new stash of working tree and staging area; keep changes in place. +\('git stash save \"Snapshot...\"; git stash apply stash@{0}') + +\(fn)" t nil) + +(autoload 'magit-submodule-update "magit" "\ +Update the submodule of the current git repository. +With a prefix arg, do a submodule update --init. + +\(fn &optional INIT)" t nil) + +(autoload 'magit-submodule-update-init "magit" "\ +Update and init the submodule of the current git repository. + +\(fn)" t nil) + +(autoload 'magit-submodule-init "magit" "\ +Initialize the submodules. + +\(fn)" t nil) + +(autoload 'magit-submodule-sync "magit" "\ +Synchronizes submodule's remote URL configuration. + +\(fn)" t nil) + +(autoload 'magit-bisect-start "magit" "\ +Start a bisect session. + +Bisecting a bug means to find the commit that introduced it. +This command starts such a bisect session by asking for a know +good and a bad commit. To move the session forward use the +other actions from the bisect popup (\\\\[magit-key-mode-popup-bisecting]). + +\(fn BAD GOOD)" t nil) + +(autoload 'magit-bisect-reset "magit" "\ +After bisecting cleanup bisection state and return to original HEAD. + +\(fn)" t nil) + +(autoload 'magit-bisect-good "magit" "\ +While bisecting, mark the current commit as good. +Use this after you have asserted that the commit does not contain +the bug in question. + +\(fn)" t nil) + +(autoload 'magit-bisect-bad "magit" "\ +While bisecting, mark the current commit as bad. +Use this after you have asserted that the commit does contain the +bug in question. + +\(fn)" t nil) + +(autoload 'magit-bisect-skip "magit" "\ +While bisecting, skip the current commit. +Use this if for some reason the current commit is not a good one +to test. This command lets Git choose a different one. + +\(fn)" t nil) + +(autoload 'magit-bisect-run "magit" "\ +Bisect automatically by running commands after each step. + +\(fn CMDLINE)" t nil) + +(autoload 'magit-log "magit" "\ + + +\(fn &optional RANGE)" t nil) + +(autoload 'magit-log-ranged "magit" "\ + + +\(fn RANGE)" t nil) + +(autoload 'magit-log-long "magit" "\ + + +\(fn &optional RANGE)" t nil) + +(autoload 'magit-log-long-ranged "magit" "\ + + +\(fn RANGE)" t nil) + +(autoload 'magit-file-log "magit" "\ +Display the log for the currently visited file or another one. +With a prefix argument show the log graph. + +\(fn FILE &optional USE-GRAPH)" t nil) + +(autoload 'magit-reflog "magit" "\ +Display the reflog of the current branch. +With a prefix argument another branch can be chosen. + +\(fn REF)" t nil) + +(autoload 'magit-reflog-head "magit" "\ +Display the HEAD reflog. + +\(fn)" t nil) + +(autoload 'magit-cherry "magit" "\ +Show commits in a branch that are not merged in the upstream branch. + +\(fn HEAD UPSTREAM)" t nil) + +(autoload 'magit-save-index "magit" "\ +Add the content of current file as if it was the index. + +\(fn)" t nil) + +(autoload 'magit-interactive-resolve "magit" "\ +Resolve a merge conflict using Ediff. + +\(fn FILE)" t nil) + +(autoload 'magit-diff "magit" "\ +Show differences between two commits. +RANGE should be a range (A..B or A...B) but can also be a single +commit. If one side of the range is omitted, then it defaults +to HEAD. If just a commit is given, then changes in the working +tree relative to that commit are shown. + +\(fn RANGE &optional WORKING ARGS)" t nil) + +(autoload 'magit-diff-working-tree "magit" "\ +Show differences between a commit and the current working tree. + +\(fn REV)" t nil) + +(autoload 'magit-diff-staged "magit" "\ +Show differences between the index and the HEAD commit. + +\(fn)" t nil) + +(autoload 'magit-diff-unstaged "magit" "\ +Show differences between the current working tree and index. + +\(fn)" t nil) + +(autoload 'magit-diff-stash "magit" "\ +Show changes in a stash. +A Stash consist of more than just one commit. This command uses +a special diff range so that the stashed changes actually were a +single commit. + +\(fn STASH &optional NOSELECT)" t nil) + +(autoload 'magit-wazzup "magit" "\ +Show a list of branches in a dedicated buffer. +Unlike in the buffer created by `magit-branch-manager' each +branch can be expanded to show a list of commits not merged +into the selected branch. + +\(fn BRANCH)" t nil) + +(autoload 'magit-branch-manager "magit" "\ +Show a list of branches in a dedicated buffer. + +\(fn)" t nil) + +(autoload 'magit-init "magit" "\ +Create or reinitialize a Git repository. +Read directory name and initialize it as new Git repository. + +If the directory is below an existing repository, then the user +has to confirm that a new one should be created inside; or when +the directory is the root of the existing repository, whether +it should be reinitialized. + +Non-interactively DIRECTORY is always (re-)initialized. + +\(fn DIRECTORY)" t nil) + +(autoload 'magit-add-change-log-entry "magit" "\ +Find change log file and add date entry and item for current change. +This differs from `add-change-log-entry' (which see) in that +it acts on the current hunk in a Magit buffer instead of on +a position in a file-visiting buffer. + +\(fn &optional WHOAMI FILE-NAME OTHER-WINDOW)" t nil) + +(autoload 'magit-add-change-log-entry-other-window "magit" "\ +Find change log file in other window and add entry and item. +This differs from `add-change-log-entry-other-window' (which see) +in that it acts on the current hunk in a Magit buffer instead of +on a position in a file-visiting buffer. + +\(fn &optional WHOAMI FILE-NAME)" t nil) + +(autoload 'magit-run-git-gui "magit" "\ +Run `git gui' for the current git repository. + +\(fn)" t nil) + +(autoload 'magit-run-git-gui-blame "magit" "\ +Run `git gui blame' on the given FILENAME and COMMIT. +Interactively run it for the current file and the HEAD, with a +prefix or when the current file cannot be determined let the user +choose. When the current buffer is visiting FILENAME instruct +blame to center around the line point is on. + +\(fn COMMIT FILENAME &optional LINENUM)" t nil) + +(autoload 'magit-run-gitk "magit" "\ +Run Gitk for the current git repository. +Without a prefix argument run `gitk --all', with +a prefix argument run gitk without any arguments. + +\(fn ARG)" t nil) + +;;;*** + +;;;### (autoloads nil "magit-blame" "magit-blame.el" (21831 16623 +;;;;;; 579188 925000)) +;;; Generated autoloads from magit-blame.el + +(autoload 'magit-blame-mode "magit-blame" "\ +Display blame information inline. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads nil "magit-key-mode" "magit-key-mode.el" (21831 +;;;;;; 16623 594188 924000)) +;;; Generated autoloads from magit-key-mode.el + +(defvar magit-key-mode-groups '((dispatch (actions ("b" "Branching" magit-key-mode-popup-branching) ("B" "Bisecting" magit-key-mode-popup-bisecting) ("c" "Committing" magit-key-mode-popup-committing) ("d" "Diff worktree" magit-diff-working-tree) ("D" "Diff" magit-diff) ("f" "Fetching" magit-key-mode-popup-fetching) ("F" "Pulling" magit-key-mode-popup-pulling) ("g" "Refresh Buffers" magit-refresh-all) ("l" "Logging" magit-key-mode-popup-logging) ("m" "Merging" magit-key-mode-popup-merging) ("M" "Remoting" magit-key-mode-popup-remoting) ("P" "Pushing" magit-key-mode-popup-pushing) ("o" "Submoduling" magit-key-mode-popup-submodule) ("r" "Rewriting" magit-key-mode-popup-rewriting) ("R" "Rebasing" magit-rebase-step) ("s" "Show Status" magit-status) ("S" "Stage all" magit-stage-all) ("t" "Tagging" magit-key-mode-popup-tagging) ("U" "Unstage all" magit-unstage-all) ("v" "Show Commit" magit-show-commit) ("V" "Show File" magit-show) ("w" "Wazzup" magit-wazzup) ("X" "Reset worktree" magit-reset-working-tree) ("y" "Cherry" magit-cherry) ("z" "Stashing" magit-key-mode-popup-stashing) ("!" "Running" magit-key-mode-popup-running) ("$" "Show Process" magit-process))) (logging (man-page "git-log") (actions ("l" "Short" magit-log) ("L" "Long" magit-log-long) ("h" "Head Reflog" magit-reflog-head) ("f" "File log" magit-file-log) ("rl" "Ranged short" magit-log-ranged) ("rL" "Ranged long" magit-log-long-ranged) ("rh" "Reflog" magit-reflog)) (switches ("-m" "Only merge commits" "--merges") ("-s" "No merge commits" "--no-merges") ("-do" "Date Order" "--date-order") ("-f" "First parent" "--first-parent") ("-i" "Case insensitive patterns" "-i") ("-pr" "Pickaxe regex" "--pickaxe-regex") ("-g" "Show Graph" "--graph") ("-n" "Name only" "--name-only") ("-am" "All match" "--all-match") ("-al" "All" "--all")) (arguments ("=r" "Relative" "--relative=" read-directory-name) ("=c" "Committer" "--committer=" read-from-minibuffer) ("=>" "Since" "--since=" read-from-minibuffer) ("=<" "Before" "--before=" read-from-minibuffer) ("=a" "Author" "--author=" read-from-minibuffer) ("=g" "Grep messages" "--grep=" read-from-minibuffer) ("=G" "Grep patches" "-G" read-from-minibuffer) ("=L" "Trace evolution of line range [long log only]" "-L" magit-read-file-trace) ("=s" "Pickaxe search" "-S" read-from-minibuffer) ("=b" "Branches" "--branches=" read-from-minibuffer) ("=R" "Remotes" "--remotes=" read-from-minibuffer))) (running (actions ("!" "Git Subcommand (from root)" magit-git-command-topdir) (":" "Git Subcommand (from pwd)" magit-git-command) ("g" "Git Gui" magit-run-git-gui) ("k" "Gitk" magit-run-gitk))) (fetching (man-page "git-fetch") (actions ("f" "Current" magit-fetch-current) ("a" "All" magit-remote-update) ("o" "Other" magit-fetch)) (switches ("-p" "Prune" "--prune"))) (pushing (man-page "git-push") (actions ("P" "Push" magit-push) ("t" "Push tags" magit-push-tags)) (switches ("-f" "Force" "--force") ("-d" "Dry run" "-n") ("-u" "Set upstream" "-u"))) (pulling (man-page "git-pull") (actions ("F" "Pull" magit-pull)) (switches ("-f" "Force" "--force") ("-r" "Rebase" "--rebase"))) (branching (man-page "git-branch") (actions ("v" "Branch manager" magit-branch-manager) ("b" "Checkout" magit-checkout) ("c" "Create" magit-create-branch) ("r" "Rename" magit-rename-branch) ("k" "Delete" magit-delete-branch)) (switches ("-t" "Set upstream configuration" "--track") ("-m" "Merged to HEAD" "--merged") ("-M" "Merged to master" "--merged=master") ("-n" "Not merged to HEAD" "--no-merged") ("-N" "Not merged to master" "--no-merged=master")) (arguments ("=c" "Contains" "--contains=" magit-read-rev-with-default) ("=m" "Merged" "--merged=" magit-read-rev-with-default) ("=n" "Not merged" "--no-merged=" magit-read-rev-with-default))) (remoting (man-page "git-remote") (actions ("v" "Remote manager" magit-branch-manager) ("a" "Add" magit-add-remote) ("r" "Rename" magit-rename-remote) ("k" "Remove" magit-remove-remote))) (tagging (man-page "git-tag") (actions ("t" "Create" magit-tag) ("k" "Delete" magit-delete-tag)) (switches ("-a" "Annotate" "--annotate") ("-f" "Force" "--force") ("-s" "Sign" "--sign"))) (stashing (man-page "git-stash") (actions ("v" "View" magit-diff-stash) ("z" "Save" magit-stash) ("s" "Snapshot" magit-stash-snapshot) ("a" "Apply" magit-stash-apply) ("p" "Pop" magit-stash-pop) ("k" "Drop" magit-stash-drop)) (switches ("-k" "Keep index" "--keep-index") ("-u" "Include untracked files" "--include-untracked") ("-a" "Include all files" "--all"))) (committing (man-page "git-commit") (actions ("c" "Commit" magit-commit) ("a" "Amend" magit-commit-amend) ("e" "Extend" magit-commit-extend) ("r" "Reword" magit-commit-reword) ("f" "Fixup" magit-commit-fixup) ("s" "Squash" magit-commit-squash)) (switches ("-a" "Stage all modified and deleted files" "--all") ("-e" "Allow empty commit" "--allow-empty") ("-v" "Show diff of changes to be committed" "--verbose") ("-n" "Bypass git hooks" "--no-verify") ("-s" "Add Signed-off-by line" "--signoff") ("-R" "Claim authorship and reset author date" "--reset-author")) (arguments ("=A" "Override the author" "--author=" read-from-minibuffer) ("=S" "Sign using gpg" "--gpg-sign=" magit-read-gpg-secret-key))) (merging (man-page "git-merge") (actions ("m" "Merge" magit-merge) ("A" "Abort" magit-merge-abort)) (switches ("-ff" "Fast-forward only" "--ff-only") ("-nf" "No fast-forward" "--no-ff") ("-sq" "Squash" "--squash")) (arguments ("-st" "Strategy" "--strategy=" read-from-minibuffer))) (rewriting (actions ("b" "Begin" magit-rewrite-start) ("s" "Stop" magit-rewrite-stop) ("a" "Abort" magit-rewrite-abort) ("f" "Finish" magit-rewrite-finish) ("d" "Diff pending" magit-rewrite-diff-pending) ("*" "Set unused" magit-rewrite-set-unused) ("." "Set used" magit-rewrite-set-used))) (apply-mailbox (man-page "git-am") (actions ("J" "Apply Mailbox" magit-apply-mailbox)) (switches ("-s" "add a Signed-off-by line to the commit message" "--signoff") ("-3" "allow fall back on 3way merging if needed" "--3way") ("-k" "pass -k flag to git-mailinfo" "--keep") ("-c" "strip everything before a scissors line" "--scissors") ("-p" "pass it through git-apply" "-p") ("-r" "override error message when patch failure occurs" "--resolvemsg") ("-d" "lie about committer date" "--committer-date-is-author-date") ("-D" "use current timestamp for author date" "--ignore-date") ("-b" "pass -b flag to git-mailinfo" "--keep-non-patch")) (arguments ("=p" "format the patch(es) are in" "--patch-format=" read-from-minibuffer))) (submodule (man-page "git-submodule") (actions ("u" "Update" magit-submodule-update) ("b" "Both update and init" magit-submodule-update-init) ("i" "Init" magit-submodule-init) ("s" "Sync" magit-submodule-sync))) (bisecting (man-page "git-bisect") (actions ("b" "Bad" magit-bisect-bad) ("g" "Good" magit-bisect-good) ("k" "Skip" magit-bisect-skip) ("r" "Reset" magit-bisect-reset) ("s" "Start" magit-bisect-start) ("u" "Run" magit-bisect-run))) (diff-options (actions ("s" "Set" magit-set-diff-options) ("d" "Set default" magit-set-default-diff-options) ("c" "Save default" magit-save-default-diff-options) ("r" "Reset to default" magit-reset-diff-options) ("h" "Toggle Hunk Refinement" magit-diff-toggle-refine-hunk)) (switches ("-m" "Show smallest possible diff" "--minimal") ("-p" "Use patience diff algorithm" "--patience") ("-h" "Use histogram diff algorithm" "--histogram") ("-b" "Ignore whitespace changes" "--ignore-space-change") ("-w" "Ignore all whitespace" "--ignore-all-space") ("-W" "Show surrounding functions" "--function-context")))) "\ +Holds the key, help, function mapping for the log-mode. +If you modify this make sure you reset `magit-key-mode-keymaps' +to nil.") + (mapc (lambda (g) (eval `(autoload ',(intern (concat "magit-key-mode-popup-" (symbol-name (car g)))) "magit-key-mode" ,(concat "Key menu for " (symbol-name (car g))) t))) magit-key-mode-groups) + +;;;*** + +;;;### (autoloads nil "magit-wip" "magit-wip.el" (21831 16623 587188 +;;;;;; 925000)) +;;; Generated autoloads from magit-wip.el + +(autoload 'magit-wip-save-mode "magit-wip" "\ +Magit support for committing to a work-in-progress ref. + +When this minor mode is turned on and a file is saved inside a +writable git repository then it is also committed to a special +work-in-progress ref. + +\(fn &optional ARG)" t nil) + +(defvar global-magit-wip-save-mode nil "\ +Non-nil if Global-Magit-Wip-Save mode is enabled. +See the command `global-magit-wip-save-mode' for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `global-magit-wip-save-mode'.") + +(custom-autoload 'global-magit-wip-save-mode "magit-wip" nil) + +(autoload 'global-magit-wip-save-mode "magit-wip" "\ +Toggle Magit-Wip-Save mode in all buffers. +With prefix ARG, enable Global-Magit-Wip-Save mode if ARG is positive; +otherwise, disable it. If called from Lisp, enable the mode if +ARG is omitted or nil. + +Magit-Wip-Save mode is enabled in all buffers where +`turn-on-magit-wip-save' would do it. +See `magit-wip-save-mode' for more information on Magit-Wip-Save mode. + +\(fn &optional ARG)" t nil) + +;;;*** + +;;;### (autoloads nil nil ("magit-pkg.el") (21831 16623 655620 175000)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; magit-autoloads.el ends here diff --git a/elpa/magit-1.2.1/magit-blame.el b/elpa/magit-1.4.1/magit-blame.el similarity index 70% rename from elpa/magit-1.2.1/magit-blame.el rename to elpa/magit-1.4.1/magit-blame.el index 8518dcb..550df5a 100644 --- a/elpa/magit-1.2.1/magit-blame.el +++ b/elpa/magit-1.4.1/magit-blame.el @@ -1,15 +1,16 @@ -;;; magit-blame.el --- blame support for magit +;;; magit-blame.el --- blame support for Magit -;; Copyright (C) 2012 RĂ¼diger Sonderfeld -;; Copyright (C) 2012 Yann Hodique -;; Copyright (C) 2011 byplayer -;; Copyright (C) 2010 Alexander Prusov -;; Copyright (C) 2009 Tim Moore -;; Copyright (C) 2008 Linh Dang -;; Copyright (C) 2008 Marius Vollmer +;; Copyright (C) 2012-2015 The Magit Project Developers +;; +;; For a full list of contributors, see the AUTHORS.md file +;; at the top-level directory of this distribution and at +;; https://raw.github.com/magit/magit/master/AUTHORS.md ;; Author: Yann Hodique -;; Keywords: +;; Package: magit + +;; Contains code from Egg (Emacs Got Git) , +;; released under the GNU General Public License version 3 or later. ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by @@ -26,21 +27,38 @@ ;;; Commentary: -;; This code has been backported from Egg (Magit fork) to Magit +;; Control git-blame from Magit. +;; This code has been backported from Egg (Magit fork) to Magit. ;;; Code: -(eval-when-compile (require 'cl)) +(eval-when-compile (require 'cl-lib)) (require 'magit) +(require 'easymenu) + +;;; Options + +(defgroup magit-blame nil + "Git-blame support for Magit." + :group 'magit-extensions) + +(defcustom magit-blame-ignore-whitespace t + "Ignore whitespace when determining blame information." + :group 'magit-blame + :type 'boolean) + +(defcustom magit-time-format-string "%Y-%m-%dT%T%z" + "How to format time in magit-blame header." + :group 'magit-blame + :type 'string) (defface magit-blame-header - '((t :inherit magit-header)) + '((t :inherit magit-section-title)) "Face for blame header." :group 'magit-faces) (defface magit-blame-sha1 - '((t :inherit (magit-log-sha1 - magit-blame-header))) + '((t :inherit (magit-log-sha1 magit-blame-header))) "Face for blame sha1." :group 'magit-faces) @@ -59,8 +77,10 @@ "Face for blame tag line." :group 'magit-faces) -(defconst magit-blame-map - (let ((map (make-sparse-keymap "Magit:Blame"))) +;;; Keymaps + +(defvar magit-blame-map + (let ((map (make-sparse-keymap))) (define-key map (kbd "l") 'magit-blame-locate-commit) (define-key map (kbd "RET") 'magit-blame-locate-commit) (define-key map (kbd "q") 'magit-blame-mode) @@ -69,8 +89,18 @@ map) "Keymap for an annotated section.\\{magit-blame-map}") -(defvar magit-blame-buffer-read-only) -(make-variable-buffer-local 'magit-blame-buffer-read-only) +(easy-menu-define magit-blame-mode-menu magit-blame-map + "Magit blame menu" + '("Blame" + ["Locate Commit" magit-blame-locate-commit t] + ["Next" magit-blame-next-chunk t] + ["Previous" magit-blame-previous-chunk t] + "---" + ["Quit" magit-blame-mode t])) + +;;; Mode + +(defvar-local magit-blame-buffer-read-only nil) ;;;###autoload (define-minor-mode magit-blame-mode @@ -78,20 +108,20 @@ :keymap magit-blame-map :lighter " blame" (unless (buffer-file-name) - (error "Current buffer has no associated file!")) + (user-error "Current buffer has no associated file!")) (when (and (buffer-modified-p) (y-or-n-p (format "save %s first? " (buffer-file-name)))) (save-buffer)) - (if magit-blame-mode - (progn - (setq magit-blame-buffer-read-only buffer-read-only) - (magit-blame-file-on (current-buffer)) - (set-buffer-modified-p nil) - (setq buffer-read-only t)) - (magit-blame-file-off (current-buffer)) - (set-buffer-modified-p nil) - (setq buffer-read-only magit-blame-buffer-read-only))) + (cond (magit-blame-mode + (setq magit-blame-buffer-read-only buffer-read-only) + (magit-blame-file-on (current-buffer)) + (set-buffer-modified-p nil) + (setq buffer-read-only t)) + (t + (magit-blame-file-off (current-buffer)) + (set-buffer-modified-p nil) + (setq buffer-read-only magit-blame-buffer-read-only)))) (defun magit-blame-file-off (buffer) (save-excursion @@ -99,8 +129,8 @@ (with-current-buffer buffer (widen) (mapc (lambda (ov) - (if (overlay-get ov :blame) - (delete-overlay ov))) + (when (overlay-get ov :blame) + (delete-overlay ov))) (overlays-in (point-min) (point-max))))))) (defun magit-blame-file-on (buffer) @@ -109,78 +139,47 @@ (with-current-buffer buffer (save-restriction (with-temp-buffer - (magit-git-insert (list "blame" "--porcelain" "--" - (file-name-nondirectory - (buffer-file-name buffer)))) + (apply 'magit-git-insert "blame" "--porcelain" + `(,@(and magit-blame-ignore-whitespace (list "-w")) "--" + ,(file-name-nondirectory (buffer-file-name buffer)))) (magit-blame-parse buffer (current-buffer))))))) +;;; Commands + (defun magit-blame-locate-commit (pos) "Jump to a commit in the branch history from an annotated blame section." (interactive "d") (let ((overlays (overlays-at pos)) sha1) (dolist (ov overlays) - (if (overlay-get ov :blame) - (setq sha1 (plist-get (nth 3 (overlay-get ov :blame)) :sha1)))) - (if sha1 - (magit-show-commit sha1)))) + (when (overlay-get ov :blame) + (setq sha1 (plist-get (nth 3 (overlay-get ov :blame)) :sha1)))) + (when sha1 + (magit-show-commit sha1)))) -(defun magit-find-next-overlay-change (BEG END PROP) - "Return the next position after BEG where an overlay matching a -property PROP starts or ends. If there are no matching overlay -boundaries from BEG to END, the return value is nil." - (save-excursion - (goto-char BEG) - (catch 'found - (flet ((overlay-change (pos) - (if (< BEG END) (next-overlay-change pos) - (previous-overlay-change pos))) - (within-bounds-p (pos) - (if (< BEG END) (< pos END) - (> pos END)))) - (let ((ov-pos BEG)) - ;; iterate through overlay changes from BEG to END - (while (within-bounds-p ov-pos) - (let* ((next-ov-pos (overlay-change ov-pos)) - ;; search for an overlay with a PROP property - (next-ov - (let ((overlays (overlays-at next-ov-pos))) - (while (and overlays - (not (overlay-get (car overlays) PROP))) - (setq overlays (cdr overlays))) - (car overlays)))) - (if next-ov - ;; found the next overlay with prop PROP at next-ov-pos - (throw 'found next-ov-pos) - ;; no matching overlay found, keep looking - (setq ov-pos next-ov-pos))))))))) - -(defun magit-blame-next-chunk (pos) +(defun magit-blame-next-chunk () "Go to the next blame chunk." - (interactive "d") - (let ((next-chunk-pos (magit-find-next-overlay-change pos (point-max) :blame))) - (when next-chunk-pos - (goto-char next-chunk-pos)))) + (interactive) + (let ((next (next-single-property-change (point) :blame))) + (when next + (goto-char next)))) -(defun magit-blame-previous-chunk (pos) +(defun magit-blame-previous-chunk () "Go to the previous blame chunk." - (interactive "d") - (let ((prev-chunk-pos (magit-find-next-overlay-change pos (point-min) :blame))) - (when prev-chunk-pos - (goto-char prev-chunk-pos)))) + (interactive) + (let ((prev (previous-single-property-change (point) :blame))) + (when prev + (goto-char prev)))) -(defcustom magit-time-format-string "%Y-%m-%dT%T%z" - "How to format time in magit-blame header." - :group 'magit - :type 'string) +;;; Parse (defun magit-blame-decode-time (unixtime &optional tz) "Decode UNIXTIME into (HIGH LOW) format. The second argument TZ can be used to add the timezone in (-)HHMM format to UNIXTIME. UNIXTIME should be either a number -containing seconds since epoch or Emacs's (HIGH LOW -. IGNORED) format." +containing seconds since epoch or Emacs's (HIGH LOW . IGNORED) +format." (when (numberp tz) (unless (numberp unixtime) (setq unixtime (float-time unixtime))) @@ -221,7 +220,9 @@ officially supported at the moment." (with-current-buffer blame-buf (goto-char (point-min)) ;; search for a ful commit info - (while (re-search-forward "^\\([0-9a-f]\\{40\\}\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\)$" nil t) + (while (re-search-forward + "^\\([0-9a-f]\\{40\\}\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\)$" + nil t) (setq commit (match-string-no-properties 1) old-line (string-to-number (match-string-no-properties 2)) @@ -300,4 +301,7 @@ officially supported at the moment." (overlay-put ov 'before-string blame)))))) (provide 'magit-blame) +;; Local Variables: +;; indent-tabs-mode: nil +;; End: ;;; magit-blame.el ends here diff --git a/elpa/magit-1.4.1/magit-key-mode.el b/elpa/magit-1.4.1/magit-key-mode.el new file mode 100644 index 0000000..7dd7dc2 --- /dev/null +++ b/elpa/magit-1.4.1/magit-key-mode.el @@ -0,0 +1,735 @@ +;;; magit-key-mode.el --- interactively tune git invocation + +;; Copyright (C) 2010-2015 The Magit Project Developers +;; +;; For a full list of contributors, see the AUTHORS.md file +;; at the top-level directory of this distribution and at +;; https://raw.github.com/magit/magit/master/AUTHORS.md + +;; Author: Phil Jackson +;; Package: magit + +;; 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 . + +;;; Commentary: + +;; This library implements `magit-key-mode' which is used throughout +;; Magit to let the user interactively select the command, switches +;; and options to call Git with. It can be though of as a way to +;; provide "postfix" arguments. + +;;; Code: + +(require 'magit) + +(eval-when-compile (require 'cl-lib)) + +(defvar magit-key-mode-keymaps) +(defvar magit-key-mode-last-buffer) +(defvar magit-pre-key-mode-window-conf) + +;;; Options + +(defcustom magit-key-mode-show-usage t + "Whether to show usage information when entering a popup." + :group 'magit + :type 'boolean) + +;;; Faces + +(defface magit-key-mode-header-face + '((t :inherit font-lock-keyword-face)) + "Face for key mode header lines." + :group 'magit-faces) + +(defface magit-key-mode-button-face + '((t :inherit font-lock-builtin-face)) + "Face for key mode buttons." + :group 'magit-faces) + +(defface magit-key-mode-switch-face + '((t :inherit font-lock-warning-face)) + "Face for key mode switches." + :group 'magit-faces) + +(defface magit-key-mode-args-face + '((t :inherit widget-field)) + "Face for key mode switch arguments." + :group 'magit-faces) + +;;; Keygroups +;;;###autoload +(defvar magit-key-mode-groups + '((dispatch + (actions + ("b" "Branching" magit-key-mode-popup-branching) + ("B" "Bisecting" magit-key-mode-popup-bisecting) + ("c" "Committing" magit-key-mode-popup-committing) + ("d" "Diff worktree" magit-diff-working-tree) + ("D" "Diff" magit-diff) + ("f" "Fetching" magit-key-mode-popup-fetching) + ("F" "Pulling" magit-key-mode-popup-pulling) + ("g" "Refresh Buffers" magit-refresh-all) + ("l" "Logging" magit-key-mode-popup-logging) + ("m" "Merging" magit-key-mode-popup-merging) + ("M" "Remoting" magit-key-mode-popup-remoting) + ("P" "Pushing" magit-key-mode-popup-pushing) + ("o" "Submoduling" magit-key-mode-popup-submodule) + ("r" "Rewriting" magit-key-mode-popup-rewriting) + ("R" "Rebasing" magit-rebase-step) + ("s" "Show Status" magit-status) + ("S" "Stage all" magit-stage-all) + ("t" "Tagging" magit-key-mode-popup-tagging) + ("U" "Unstage all" magit-unstage-all) + ("v" "Show Commit" magit-show-commit) + ("V" "Show File" magit-show) + ("w" "Wazzup" magit-wazzup) + ("X" "Reset worktree" magit-reset-working-tree) + ("y" "Cherry" magit-cherry) + ("z" "Stashing" magit-key-mode-popup-stashing) + ("!" "Running" magit-key-mode-popup-running) + ("$" "Show Process" magit-process))) + + (logging + (man-page "git-log") + (actions + ("l" "Short" magit-log) + ("L" "Long" magit-log-long) + ("h" "Head Reflog" magit-reflog-head) + ("f" "File log" magit-file-log) + ("rl" "Ranged short" magit-log-ranged) + ("rL" "Ranged long" magit-log-long-ranged) + ("rh" "Reflog" magit-reflog)) + (switches + ("-m" "Only merge commits" "--merges") + ("-s" "No merge commits" "--no-merges") + ("-do" "Date Order" "--date-order") + ("-f" "First parent" "--first-parent") + ("-i" "Case insensitive patterns" "-i") + ("-pr" "Pickaxe regex" "--pickaxe-regex") + ("-g" "Show Graph" "--graph") + ("-n" "Name only" "--name-only") + ("-am" "All match" "--all-match") + ("-al" "All" "--all")) + (arguments + ("=r" "Relative" "--relative=" read-directory-name) + ("=c" "Committer" "--committer=" read-from-minibuffer) + ("=>" "Since" "--since=" read-from-minibuffer) + ("=<" "Before" "--before=" read-from-minibuffer) + ("=a" "Author" "--author=" read-from-minibuffer) + ("=g" "Grep messages" "--grep=" read-from-minibuffer) + ("=G" "Grep patches" "-G" read-from-minibuffer) + ("=L" "Trace evolution of line range [long log only]" + "-L" magit-read-file-trace) + ("=s" "Pickaxe search" "-S" read-from-minibuffer) + ("=b" "Branches" "--branches=" read-from-minibuffer) + ("=R" "Remotes" "--remotes=" read-from-minibuffer))) + + (running + (actions + ("!" "Git Subcommand (from root)" magit-git-command-topdir) + (":" "Git Subcommand (from pwd)" magit-git-command) + ("g" "Git Gui" magit-run-git-gui) + ("k" "Gitk" magit-run-gitk))) + + (fetching + (man-page "git-fetch") + (actions + ("f" "Current" magit-fetch-current) + ("a" "All" magit-remote-update) + ("o" "Other" magit-fetch)) + (switches + ("-p" "Prune" "--prune"))) + + (pushing + (man-page "git-push") + (actions + ("P" "Push" magit-push) + ("t" "Push tags" magit-push-tags)) + (switches + ("-f" "Force" "--force") + ("-d" "Dry run" "-n") + ("-u" "Set upstream" "-u"))) + + (pulling + (man-page "git-pull") + (actions + ("F" "Pull" magit-pull)) + (switches + ("-f" "Force" "--force") + ("-r" "Rebase" "--rebase"))) + + (branching + (man-page "git-branch") + (actions + ("v" "Branch manager" magit-branch-manager) + ("b" "Checkout" magit-checkout) + ("c" "Create" magit-create-branch) + ("r" "Rename" magit-rename-branch) + ("k" "Delete" magit-delete-branch)) + (switches + ("-t" "Set upstream configuration" "--track") + ("-m" "Merged to HEAD" "--merged") + ("-M" "Merged to master" "--merged=master") + ("-n" "Not merged to HEAD" "--no-merged") + ("-N" "Not merged to master" "--no-merged=master")) + (arguments + ("=c" "Contains" "--contains=" magit-read-rev-with-default) + ("=m" "Merged" "--merged=" magit-read-rev-with-default) + ("=n" "Not merged" "--no-merged=" magit-read-rev-with-default))) + + (remoting + (man-page "git-remote") + (actions + ("v" "Remote manager" magit-branch-manager) + ("a" "Add" magit-add-remote) + ("r" "Rename" magit-rename-remote) + ("k" "Remove" magit-remove-remote))) + + (tagging + (man-page "git-tag") + (actions + ("t" "Create" magit-tag) + ("k" "Delete" magit-delete-tag)) + (switches + ("-a" "Annotate" "--annotate") + ("-f" "Force" "--force") + ("-s" "Sign" "--sign"))) + + (stashing + (man-page "git-stash") + (actions + ("v" "View" magit-diff-stash) + ("z" "Save" magit-stash) + ("s" "Snapshot" magit-stash-snapshot) + ("a" "Apply" magit-stash-apply) + ("p" "Pop" magit-stash-pop) + ("k" "Drop" magit-stash-drop)) + (switches + ("-k" "Keep index" "--keep-index") + ("-u" "Include untracked files" "--include-untracked") + ("-a" "Include all files" "--all"))) + + (committing + (man-page "git-commit") + (actions + ("c" "Commit" magit-commit) + ("a" "Amend" magit-commit-amend) + ("e" "Extend" magit-commit-extend) + ("r" "Reword" magit-commit-reword) + ("f" "Fixup" magit-commit-fixup) + ("s" "Squash" magit-commit-squash)) + (switches + ("-a" "Stage all modified and deleted files" "--all") + ("-e" "Allow empty commit" "--allow-empty") + ("-v" "Show diff of changes to be committed" "--verbose") + ("-n" "Bypass git hooks" "--no-verify") + ("-s" "Add Signed-off-by line" "--signoff") + ("-R" "Claim authorship and reset author date" "--reset-author")) + (arguments + ("=A" "Override the author" "--author=" read-from-minibuffer) + ("=S" "Sign using gpg" "--gpg-sign=" magit-read-gpg-secret-key))) + + (merging + (man-page "git-merge") + (actions + ("m" "Merge" magit-merge) + ("A" "Abort" magit-merge-abort)) + (switches + ("-ff" "Fast-forward only" "--ff-only") + ("-nf" "No fast-forward" "--no-ff") + ("-sq" "Squash" "--squash")) + (arguments + ("-st" "Strategy" "--strategy=" read-from-minibuffer))) + + (rewriting + (actions + ("b" "Begin" magit-rewrite-start) + ("s" "Stop" magit-rewrite-stop) + ("a" "Abort" magit-rewrite-abort) + ("f" "Finish" magit-rewrite-finish) + ("d" "Diff pending" magit-rewrite-diff-pending) + ("*" "Set unused" magit-rewrite-set-unused) + ("." "Set used" magit-rewrite-set-used))) + + (apply-mailbox + (man-page "git-am") + (actions + ("J" "Apply Mailbox" magit-apply-mailbox)) + (switches + ("-s" "add a Signed-off-by line to the commit message" "--signoff") + ("-3" "allow fall back on 3way merging if needed" "--3way") + ("-k" "pass -k flag to git-mailinfo" "--keep") + ("-c" "strip everything before a scissors line" "--scissors") + ("-p" "pass it through git-apply" "-p") + ("-r" "override error message when patch failure occurs" "--resolvemsg") + ("-d" "lie about committer date" "--committer-date-is-author-date") + ("-D" "use current timestamp for author date" "--ignore-date") + ("-b" "pass -b flag to git-mailinfo" "--keep-non-patch")) + (arguments + ("=p" "format the patch(es) are in" "--patch-format=" read-from-minibuffer))) + + (submodule + (man-page "git-submodule") + (actions + ("u" "Update" magit-submodule-update) + ("b" "Both update and init" magit-submodule-update-init) + ("i" "Init" magit-submodule-init) + ("s" "Sync" magit-submodule-sync))) + + (bisecting + (man-page "git-bisect") + (actions + ("b" "Bad" magit-bisect-bad) + ("g" "Good" magit-bisect-good) + ("k" "Skip" magit-bisect-skip) + ("r" "Reset" magit-bisect-reset) + ("s" "Start" magit-bisect-start) + ("u" "Run" magit-bisect-run))) + + (diff-options + (actions + ("s" "Set" magit-set-diff-options) + ("d" "Set default" magit-set-default-diff-options) + ("c" "Save default" magit-save-default-diff-options) + ("r" "Reset to default" magit-reset-diff-options) + ("h" "Toggle Hunk Refinement" magit-diff-toggle-refine-hunk)) + (switches + ("-m" "Show smallest possible diff" "--minimal") + ("-p" "Use patience diff algorithm" "--patience") + ("-h" "Use histogram diff algorithm" "--histogram") + ("-b" "Ignore whitespace changes" "--ignore-space-change") + ("-w" "Ignore all whitespace" "--ignore-all-space") + ("-W" "Show surrounding functions" "--function-context")) + )) + "Holds the key, help, function mapping for the log-mode. +If you modify this make sure you reset `magit-key-mode-keymaps' +to nil.") + +(defun magit-key-mode-delete-group (group) + "Delete a group from `magit-key-mode-keymaps'." + (let ((items (assoc group magit-key-mode-groups))) + (when items + ;; reset the cache + (setq magit-key-mode-keymaps nil) + ;; delete the whole group + (setq magit-key-mode-groups + (delq items magit-key-mode-groups)) + ;; unbind the defun + (magit-key-mode-de-generate group)) + magit-key-mode-groups)) + +(defun magit-key-mode-add-group (group) + "Add a new group to `magit-key-mode-keymaps'. +If there already is a group of that name then this will +completely remove it and put in its place an empty one of the +same name." + (when (assoc group magit-key-mode-groups) + (magit-key-mode-delete-group group)) + (setq magit-key-mode-groups + (cons (list group (list 'actions) (list 'switches) (list 'arguments)) + magit-key-mode-groups))) + +(defun magit-key-mode-key-defined-p (for-group key) + "Return t if KEY is defined as any option within FOR-GROUP. +The option may be a switch, argument or action." + (catch 'result + (let ((options (magit-key-mode-options-for-group for-group))) + (dolist (type '(actions switches arguments)) + (when (assoc key (assoc type options)) + (throw 'result t)))))) + +(defun magit-key-mode-update-group (for-group thing &rest args) + "Abstraction for setting values in `magit-key-mode-keymaps'." + (let* ((options (magit-key-mode-options-for-group for-group)) + (things (assoc thing options)) + (key (car args))) + (if (cdr things) + (if (magit-key-mode-key-defined-p for-group key) + (error "%s is already defined in the %s group." key for-group) + (setcdr (cdr things) (cons args (cddr things)))) + (setcdr things (list args))) + (setq magit-key-mode-keymaps nil) + things)) + +(defun magit-key-mode-insert-argument (for-group key desc arg read-func) + "Add a new binding KEY in FOR-GROUP which will use READ-FUNC +to receive input to apply to argument ARG git is run. DESC should +be a brief description of the binding." + (magit-key-mode-update-group for-group 'arguments key desc arg read-func)) + +(defun magit-key-mode-insert-switch (for-group key desc switch) + "Add a new binding KEY in FOR-GROUP which will add SWITCH to git's +command line when it runs. DESC should be a brief description of +the binding." + (magit-key-mode-update-group for-group 'switches key desc switch)) + +(defun magit-key-mode-insert-action (for-group key desc func) + "Add a new binding KEY in FOR-GROUP which will run command FUNC. +DESC should be a brief description of the binding." + (magit-key-mode-update-group for-group 'actions key desc func)) + +(defun magit-key-mode-options-for-group (for-group) + "Retrieve the options for the group FOR-GROUP. +This includes switches, commands and arguments." + (or (cdr (assoc for-group magit-key-mode-groups)) + (error "Unknown group '%s'" for-group))) + +;;; Commands + +(defun magit-key-mode-help (for-group) + "Provide help for a key within FOR-GROUP. +The user is prompted for the key." + (let* ((opts (magit-key-mode-options-for-group for-group)) + (man-page (cadr (assoc 'man-page opts))) + (seq (read-key-sequence + (format "Enter command prefix%s: " + (if man-page + (format ", `?' for man `%s'" man-page) + "")))) + (actions (cdr (assoc 'actions opts)))) + (cond + ;; if it is an action popup the help for the to-be-run function + ((assoc seq actions) (describe-function (nth 2 (assoc seq actions)))) + ;; if there is "?" show a man page if there is one + ((equal seq "?") + (if man-page + (man man-page) + (error "No man page associated with `%s'" for-group))) + (t (error "No help associated with `%s'" seq))))) + +(defun magit-key-mode-exec-at-point () + "Run action/args/option at point." + (interactive) + (let ((key (or (get-text-property (point) 'key-group-executor) + (error "Nothing at point to do.")))) + (call-interactively (lookup-key (current-local-map) key)))) + +(defun magit-key-mode-jump-to-next-exec () + "Jump to the next action/args/option point." + (interactive) + (let* ((oldp (point)) + (old (get-text-property oldp 'key-group-executor)) + (p (if (= oldp (point-max)) (point-min) (1+ oldp)))) + (while (let ((new (get-text-property p 'key-group-executor))) + (and (not (= p oldp)) (or (not new) (eq new old)))) + (setq p (if (= p (point-max)) (point-min) (1+ p)))) + (goto-char p) + (skip-chars-forward " "))) + +;;; Keymaps + +(defvar magit-key-mode-keymaps nil + "This will be filled lazily with proper keymaps. +These keymaps are created using `define-key' as they're requested.") + +(defun magit-key-mode-build-keymap (for-group) + "Construct a normal looking keymap for the key mode to use. +Put it in `magit-key-mode-keymaps' for fast lookup." + (let* ((options (magit-key-mode-options-for-group for-group)) + (actions (cdr (assoc 'actions options))) + (switches (cdr (assoc 'switches options))) + (arguments (cdr (assoc 'arguments options))) + (map (make-sparse-keymap))) + (suppress-keymap map 'nodigits) + ;; ret dwim + (define-key map (kbd "RET") 'magit-key-mode-exec-at-point) + ;; tab jumps to the next "button" + (define-key map (kbd "TAB") 'magit-key-mode-jump-to-next-exec) + + ;; all maps should `quit' with `C-g' or `q' + (define-key map (kbd "C-g") `(lambda () + (interactive) + (magit-key-mode-command nil))) + (define-key map (kbd "q") `(lambda () + (interactive) + (magit-key-mode-command nil))) + ;; run help + (define-key map (kbd "?") `(lambda () + (interactive) + (magit-key-mode-help ',for-group))) + + (let ((defkey (lambda (k action) + (when (and (lookup-key map (car k)) + (not (numberp (lookup-key map (car k))))) + (message "Warning: overriding binding for `%s' in %S" + (car k) for-group) + (ding) + (sit-for 2)) + (define-key map (car k) + `(lambda () (interactive) ,action))))) + (dolist (k actions) + (funcall defkey k `(magit-key-mode-command ',(nth 2 k)))) + (dolist (k switches) + (funcall defkey k `(magit-key-mode-toggle-option ',for-group ,(nth 2 k)))) + (dolist (k arguments) + (funcall defkey k `(magit-key-mode-add-argument + ',for-group ,(nth 2 k) ',(nth 3 k))))) + + (push (cons for-group map) magit-key-mode-keymaps) + map)) + +;;; Toggling and Running + +(defvar magit-key-mode-prefix nil + "Prefix argument to the command that brought up the key-mode window. +For internal use. Used by the command that's eventually invoked.") + +(defvar magit-key-mode-current-args nil + "A hash-table of current argument set. +These will eventually make it to the git command-line.") + +(defvar magit-key-mode-current-options nil + "Current option set. +These will eventually make it to the git command-line.") + +(defvar magit-custom-options nil + "List of custom options to pass to Git. +Do not customize this (used in the `magit-key-mode' implementation).") + +(defun magit-key-mode-command (func) + (let ((current-prefix-arg (or current-prefix-arg magit-key-mode-prefix)) + (magit-custom-options magit-key-mode-current-options)) + (maphash (lambda (k v) + (push (concat k v) magit-custom-options)) + magit-key-mode-current-args) + (set-window-configuration magit-pre-key-mode-window-conf) + (kill-buffer magit-key-mode-last-buffer) + (when func + (setq this-command func) + (call-interactively this-command)))) + +(defun magit-key-mode-add-argument (for-group arg-name input-func) + (let ((input (funcall input-func (concat arg-name ": ")))) + (puthash arg-name input magit-key-mode-current-args) + (magit-key-mode-redraw for-group))) + +(defun magit-key-mode-toggle-option (for-group option-name) + "Toggles the appearance of OPTION-NAME in `magit-key-mode-current-options'." + (if (member option-name magit-key-mode-current-options) + (setq magit-key-mode-current-options + (delete option-name magit-key-mode-current-options)) + (add-to-list 'magit-key-mode-current-options option-name)) + (magit-key-mode-redraw for-group)) + +;;; Mode + +(defvar magit-key-mode-buf-name "*magit-key: %s*" + "Format string to create the name of the magit-key buffer.") + +(defvar magit-key-mode-last-buffer nil + "Store the last magit-key buffer used.") + +(defvar magit-pre-key-mode-window-conf nil + "Will hold the pre-menu configuration of magit.") + +(defun magit-key-mode (for-group &optional original-opts) + "Mode for magit key selection. +All commands, switches and options can be toggled/actioned with +the key combination highlighted before the description." + (interactive) + ;; save the window config to restore it as was (no need to make this + ;; buffer local) + (setq magit-pre-key-mode-window-conf + (current-window-configuration)) + ;; setup the mode, draw the buffer + (let ((buf (get-buffer-create (format magit-key-mode-buf-name + (symbol-name for-group))))) + (setq magit-key-mode-last-buffer buf) + (split-window-vertically) + (other-window 1) + (switch-to-buffer buf) + (kill-all-local-variables) + (set (make-local-variable 'scroll-margin) 0) + (set (make-local-variable + 'magit-key-mode-current-options) + original-opts) + (set (make-local-variable + 'magit-key-mode-current-args) + (make-hash-table)) + (set (make-local-variable 'magit-key-mode-prefix) current-prefix-arg) + (magit-key-mode-redraw for-group)) + (when magit-key-mode-show-usage + (message (concat "Type a prefix key to toggle it. " + "Run 'actions' with their prefixes. " + "'?' for more help.")))) + +(defun magit-key-mode-get-key-map (for-group) + "Get or build the keymap for FOR-GROUP." + (or (cdr (assoc for-group magit-key-mode-keymaps)) + (magit-key-mode-build-keymap for-group))) + +(defun magit-key-mode-redraw (for-group) + "(re)draw the magit key buffer." + (let ((buffer-read-only nil) + (current-exec (get-text-property (point) 'key-group-executor)) + (new-exec-pos) + (old-point (point)) + (is-first (zerop (buffer-size))) + (actions-p nil)) + (erase-buffer) + (make-local-variable 'font-lock-defaults) + (use-local-map (magit-key-mode-get-key-map for-group)) + (setq actions-p (magit-key-mode-draw for-group)) + (delete-trailing-whitespace) + (setq mode-name "magit-key-mode" major-mode 'magit-key-mode) + (when current-exec + (setq new-exec-pos + (cdr (assoc current-exec + (magit-key-mode-build-exec-point-alist))))) + (cond ((and is-first actions-p) + (goto-char actions-p) + (magit-key-mode-jump-to-next-exec)) + (new-exec-pos + (goto-char new-exec-pos) + (skip-chars-forward " ")) + (t + (goto-char old-point)))) + (setq buffer-read-only t) + (fit-window-to-buffer)) + +(defun magit-key-mode-build-exec-point-alist () + (save-excursion + (goto-char (point-min)) + (let* ((exec (get-text-property (point) 'key-group-executor)) + (exec-alist (and exec `((,exec . ,(point)))))) + (cl-do nil ((eobp) (nreverse exec-alist)) + (when (not (eq exec (get-text-property (point) 'key-group-executor))) + (setq exec (get-text-property (point) 'key-group-executor)) + (when exec (push (cons exec (point)) exec-alist))) + (forward-char))))) + +;;; Draw Buffer + +(defun magit-key-mode-draw-header (header) + "Draw a header with the correct face." + (insert (propertize header 'face 'magit-key-mode-header-face) "\n")) + +(defvar magit-key-mode-args-in-cols nil + "When true, draw arguments in columns as with switches and options.") + +(defun magit-key-mode-draw-args (args) + "Draw the args part of the menu." + (magit-key-mode-draw-buttons + "Args" + args + (lambda (x) + (format "(%s) %s" + (nth 2 x) + (propertize (gethash (nth 2 x) magit-key-mode-current-args "") + 'face 'magit-key-mode-args-face))) + (not magit-key-mode-args-in-cols))) + +(defun magit-key-mode-draw-switches (switches) + "Draw the switches part of the menu." + (magit-key-mode-draw-buttons + "Switches" + switches + (lambda (x) + (format "(%s)" (let ((s (nth 2 x))) + (if (member s magit-key-mode-current-options) + (propertize s 'face 'magit-key-mode-switch-face) + s)))))) + +(defun magit-key-mode-draw-actions (actions) + "Draw the actions part of the menu." + (magit-key-mode-draw-buttons "Actions" actions nil)) + +(defun magit-key-mode-draw-buttons (section xs maker + &optional one-col-each) + (when xs + (magit-key-mode-draw-header section) + (magit-key-mode-draw-in-cols + (mapcar (lambda (x) + (let* ((head (propertize (car x) 'face 'magit-key-mode-button-face)) + (desc (nth 1 x)) + (more (and maker (funcall maker x))) + (text (format " %s: %s%s%s" + head desc (if more " " "") (or more "")))) + (propertize text 'key-group-executor (car x)))) + xs) + one-col-each))) + +(defun magit-key-mode-draw-in-cols (strings one-col-each) + "Given a list of strings, print in columns (using `insert'). +If ONE-COL-EACH is true then don't columify, but rather, draw +each item on one line." + (let ((longest-act (apply 'max (mapcar 'length strings)))) + (while strings + (let ((str (car strings))) + (let ((padding (make-string (- (+ longest-act 3) (length str)) ? ))) + (insert str) + (if (or one-col-each + (and (> (+ (length padding) ; + (current-column) + longest-act) + (window-width)) + (cdr strings))) + (insert "\n") + (insert padding)))) + (setq strings (cdr strings)))) + (insert "\n")) + +(defun magit-key-mode-draw (for-group) + "Draw actions, switches and parameters. +Return the point before the actions part, if any, nil otherwise." + (let* ((options (magit-key-mode-options-for-group for-group)) + (switches (cdr (assoc 'switches options))) + (arguments (cdr (assoc 'arguments options))) + (actions (cdr (assoc 'actions options))) + (p nil)) + (magit-key-mode-draw-switches switches) + (magit-key-mode-draw-args arguments) + (when actions (setq p (point-marker))) + (magit-key-mode-draw-actions actions) + (insert "\n") + p)) + +;;; Generate Groups + +(defun magit-key-mode-de-generate (group) + "Unbind the function for GROUP." + (fmakunbound + (intern (concat "magit-key-mode-popup-" (symbol-name group))))) + +(defun magit-key-mode-generate (group) + "Generate the key-group menu for GROUP." + (let ((opts (magit-key-mode-options-for-group group))) + (eval + `(defun ,(intern (concat "magit-key-mode-popup-" (symbol-name group))) nil + ,(concat "Key menu for " (symbol-name group)) + (interactive) + (magit-key-mode + (quote ,group) + ;; As a tempory kludge it is okay to do this here. + ,(cl-case group + (logging + '(list "--graph")) + (diff-options + '(when (local-variable-p 'magit-diff-options) + magit-diff-options)))))))) + +;; create the interactive functions for the key mode popups (which are +;; applied in the top-level key maps) +(mapc (lambda (g) + (magit-key-mode-generate (car g))) + magit-key-mode-groups) + +;;;###autoload (mapc (lambda (g) (eval `(autoload ',(intern (concat "magit-key-mode-popup-" (symbol-name (car g)))) "magit-key-mode" ,(concat "Key menu for " (symbol-name (car g))) t))) magit-key-mode-groups) + +(provide 'magit-key-mode) +;; Local Variables: +;; indent-tabs-mode: nil +;; End: +;;; magit-key-mode.el ends here diff --git a/elpa/magit-1.4.1/magit-pkg.el b/elpa/magit-1.4.1/magit-pkg.el new file mode 100644 index 0000000..47ed9ff --- /dev/null +++ b/elpa/magit-1.4.1/magit-pkg.el @@ -0,0 +1,5 @@ +(define-package "magit" "1.4.1" + "Control Git from Emacs." + '((cl-lib "0.5") + (git-commit-mode "1.0.0") + (git-rebase-mode "1.0.0"))) diff --git a/elpa/magit-1.4.1/magit-wip.el b/elpa/magit-1.4.1/magit-wip.el new file mode 100644 index 0000000..ccb71b1 --- /dev/null +++ b/elpa/magit-1.4.1/magit-wip.el @@ -0,0 +1,143 @@ +;;; magit-wip.el --- git-wip plug-in for Magit + +;; Copyright (C) 2012-2015 The Magit Project Developers +;; +;; For a full list of contributors, see the AUTHORS.md file +;; at the top-level directory of this distribution and at +;; https://raw.github.com/magit/magit/master/AUTHORS.md + +;; Author: Jonas Bernoulli +;; Keywords: vc tools +;; Package: magit + +;; 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 . + +;;; Commentary: + +;; This plug-in provides support for special work-in-progress refs. + +;; This requires the third-party git command "git wip" which is available +;; from https://github.com/bartman/git-wip. + +;; To enable `magit-wip-save-mode' enable `global-magit-wip-save-mode' +;; and use the Magit extension mechanism to select the repositories in +;; which you want to use a work-in-progress ref. +;; +;; (global-magit-wip-save-mode 1) +;; +;; $ git config --add magit.extension wip-save # or +;; $ git config --global --add magit.extension wip-save + +;; Note that `global-magit-wip-save-mode' is the only mode that uses the +;; extension mechanism for file-visiting buffers all other global modes +;; making use of it to turn on local modes in Magit buffers. + +;;; Code: + +(require 'magit) +(require 'format-spec) + +(defun magit-wip-mode (&rest ignore) + (message "magit-wip-mode is obsolete and doesn't do anything")) +(make-obsolete 'magit-wip-mode "This mode is a noop now" "1.4.0") + +;;; Options + +(defgroup magit-wip nil + "Git-Wip support for Magit." + :group 'magit-extensions) + +(defcustom magit-wip-commit-message "WIP %r" + "Commit message for git-wip commits. + +The following `format'-like specs are supported: +%f the full name of the file being saved +%g the root of the git repository +%r the name of the file being saved, + relative to the repository root." + :group 'magit-wip + :type 'string) + +(defcustom magit-wip-echo-area-message "Wrote %f (wip)" + "Message shown in the echo area after creating a git-wip commit. + +The following `format'-like specs are supported: +%f the full name of the file being saved +%g the root of the git repository +%r the name of the file being saved, + relative to the repository root." + :group 'magit-wip + :type '(choice (const :tag "No message" nil) string)) + +(defvar magit-wip-save-mode-lighter " Wip") + +;;; Mode + +;;;###autoload +(define-minor-mode magit-wip-save-mode + "Magit support for committing to a work-in-progress ref. + +When this minor mode is turned on and a file is saved inside a +writable git repository then it is also committed to a special +work-in-progress ref." + :lighter magit-wip-save-mode-lighter + (if magit-wip-save-mode + (add-hook 'after-save-hook 'magit-wip-save t t) + (remove-hook 'after-save-hook 'magit-wip-save t))) + +;;;###autoload +(define-globalized-minor-mode global-magit-wip-save-mode + magit-wip-save-mode turn-on-magit-wip-save + :group 'magit-wip) + +(defun turn-on-magit-wip-save () + "Conditionally turn on magit-wip-save-mode. + +Turn on magit-wip-save-mode if the buffer is a file in a git +repository where wip-save is enabled in git config. + +You can activate it with git config magit.extension wip-save." + (when (and (buffer-file-name) + (magit-get-top-dir) + (magit-git-true "rev-parse" "--is-inside-work-tree") + (member "wip-save" (magit-get-all "magit.extension"))) + (if (magit-git-success "wip" "-h") + (magit-wip-save-mode 1) + (message "Git command 'git wip' cannot be found")))) + +(defun magit-wip-save () + (let* ((filename (expand-file-name (file-truename (buffer-file-name)))) + (filedir (file-name-directory filename)) + (toplevel (magit-get-top-dir filedir)) + (blobname (file-relative-name filename toplevel)) + (spec `((?f . ,filename) + (?r . ,blobname) + (?g . ,toplevel)))) + (when (and toplevel (file-writable-p toplevel) + (not (member blobname + (let ((default-directory filedir)) + (magit-git-lines + "ls-files" "--other" "--ignored" + "--exclude-standard" "--full-name"))))) + (magit-run-git "wip" "save" + (format-spec magit-wip-commit-message spec) + "--editor" "--" filename) + (when magit-wip-echo-area-message + (message (format-spec magit-wip-echo-area-message spec)))))) + +(provide 'magit-wip) +;; Local Variables: +;; indent-tabs-mode: nil +;; End: +;;; magit-wip.el ends here diff --git a/elpa/magit-1.4.1/magit.el b/elpa/magit-1.4.1/magit.el new file mode 100644 index 0000000..769d402 --- /dev/null +++ b/elpa/magit-1.4.1/magit.el @@ -0,0 +1,7838 @@ +;;; magit.el --- control Git from Emacs + +;; Copyright (C) 2008-2015 The Magit Project Developers +;; +;; For a full list of contributors, see the AUTHORS.md file +;; at the top-level directory of this distribution and at +;; https://raw.github.com/magit/magit/master/AUTHORS.md + +;; Author: Marius Vollmer +;; Maintainer: Jonas Bernoulli +;; Former-Maintainers: +;; Nicolas Dudebout +;; Peter J. Weisberg +;; Phil Jackson +;; RĂ©mi Vanicat +;; Yann Hodique + +;; Keywords: vc tools +;; Package: magit +;; Package-Requires: ((cl-lib "0.5") (git-commit-mode "1.0.0") (git-rebase-mode "1.0.0")) + +;; Magit requires at least GNU Emacs 23.2 and Git 1.7.2.5. +;; These are the versions shipped by Debian oldstable (6.0, Squeeze). + +;; Contains code from GNU Emacs , +;; released under the GNU General Public License version 3 or later. + +;; 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 . + +;;; Commentary: + +;; Invoking the magit-status function will show a buffer with the +;; status of the current git repository and its working tree. That +;; buffer offers key bindings for manipulating the status in simple +;; ways. +;; +;; The status buffer mainly shows the difference between the working +;; tree and the index, and the difference between the index and the +;; current HEAD. You can add individual hunks from the working tree +;; to the index, and you can commit the index. +;; +;; See the Magit User Manual for more information. + +;;; Code: + +(defvar magit-version 'undefined + "The version of Magit that you're using. +Use the function by the same name instead of this variable.") +;; The value is set at the end of this file, using the +;; function `magit-version' which is also defined there. + +;;;; Dependencies + +(when (version< emacs-version "23.2") + (error "Magit requires at least GNU Emacs 23.2")) + +(require 'git-commit-mode) +(require 'git-rebase-mode) + +(require 'ansi-color) +(require 'autorevert) +(require 'cl-lib) +(require 'diff-mode) +(require 'easymenu) +(require 'epa) +(require 'format-spec) +(require 'grep) +(require 'help-mode) +(require 'ring) +(require 'server) +(require 'tramp) +(require 'view) + +(eval-when-compile + (require 'dired) + (require 'dired-x) + (require 'ediff) + (require 'eshell) + (require 'ido) + (require 'package nil t) + (require 'view)) + +;;;; Declarations + +(if (featurep 'vc-git) + (defalias 'magit-grep 'vc-git-grep) + (defalias 'magit-grep 'lgrep)) + +(declare-function dired-jump 'dired-x) +(declare-function dired-uncache 'dired) +(declare-function ediff-cleanup-mess 'ediff) +(declare-function eshell-parse-arguments 'eshell) +(declare-function ido-completing-read 'ido) +(declare-function package-desc-vers 'package) +(declare-function package-desc-version 'package) +(declare-function package-version-join 'package) +(declare-function view-mode 'view) + +(defvar git-commit-previous-winconf) +(defvar magit-commit-buffer-name) +(defvar magit-custom-options) +(defvar magit-log-buffer-name) +(defvar magit-marked-commit) +(defvar magit-process-buffer-name) +(defvar magit-reflog-buffer-name) +(defvar magit-refresh-args) +(defvar magit-stash-buffer-name) +(defvar magit-status-buffer-name) +(defvar magit-this-process) +(defvar package-alist) + +;;;; Compatibility + +(eval-and-compile + + ;; Added in Emacs 24.3 + (unless (fboundp 'user-error) + (defalias 'user-error 'error)) + + ;; Added in Emacs 24.3 (mirrors/emacs@b335efc3). + (unless (fboundp 'setq-local) + (defmacro setq-local (var val) + "Set variable VAR to value VAL in current buffer." + (list 'set (list 'make-local-variable (list 'quote var)) val))) + + ;; Added in Emacs 24.3 (mirrors/emacs@b335efc3). + (unless (fboundp 'defvar-local) + (defmacro defvar-local (var val &optional docstring) + "Define VAR as a buffer-local variable with default value VAL. +Like `defvar' but additionally marks the variable as being automatically +buffer-local wherever it is set." + (declare (debug defvar) (doc-string 3)) + (list 'progn (list 'defvar var val docstring) + (list 'make-variable-buffer-local (list 'quote var))))) + + ;; Added in Emacs 24.1 + (unless (fboundp 'run-hook-wrapped) + (defun run-hook-wrapped-1 (hook fns wrap-function &rest args) + (cl-loop for fn in fns + if (and (eq fn t) + (local-variable-p hook) + (default-boundp hook) + (apply 'run-hook-wrapped-1 nil + (default-value hook) wrap-function args)) + return it + else if (and (functionp fn) (apply wrap-function fn args)) + return it)) + + (defun run-hook-wrapped (hook wrap-function &rest args) + "Run HOOK, passing each function through WRAP-FUNCTION. +I.e. instead of calling each function FUN directly with arguments ARGS, +it calls WRAP-FUNCTION with arguments FUN and ARGS. +As soon as a call to WRAP-FUNCTION returns non-nil, `run-hook-wrapped' +aborts and returns that value." + (when (boundp hook) + (let ((fns (symbol-value hook))) + (apply 'run-hook-wrapped-1 hook + (if (functionp fns) (list fns) fns) + wrap-function args))))) + ) + + +;;; Settings +;;;; Custom Groups + +(defgroup magit nil + "Controlling Git from Emacs." + :group 'tools) + +(defgroup magit-process nil + "Git and other external processes used by Magit." + :group 'magit) + +(defgroup magit-modes nil + "Modes provided by Magit." + :group 'magit) + +(defgroup magit-status nil + "Inspect and manipulate Git repositories." + :group 'magit-modes) + +(defgroup magit-diff nil + "Inspect and manipulate Git diffs." + :group 'magit-modes) + +(defgroup magit-commit nil + "Inspect and manipulate Git commits." + :group 'magit-modes) + +(defgroup magit-log nil + "Inspect and manipulate Git history." + :group 'magit-modes) + +(defgroup magit-extensions nil + "Extensions to Magit." + :group 'magit) + +(defgroup magit-faces nil + "Faces used by Magit." + :group 'magit + :group 'faces) + +(when (featurep 'gitattributes-mode) + (custom-add-to-group 'magit-modes 'gitattributes-mode 'custom-group)) + +(when (featurep 'git-commit-mode) + (custom-add-to-group 'magit-modes 'git-commit 'custom-group) + (custom-add-to-group 'magit-faces 'git-commit-faces 'custom-group)) + +(when (featurep 'git-rebase-mode) + (custom-add-to-group 'magit-modes 'git-rebase 'custom-group) + (custom-add-to-group 'magit-faces 'git-rebase-faces 'custom-group)) + +(custom-add-to-group 'magit 'vc-follow-symlinks 'custom-variable) + +;;;; Custom Options +;;;;; Processes + +(defcustom magit-git-executable + (or (and (eq system-type 'windows-nt) + ;; On Windows asking for "git" from $PATH might also return + ;; a "git.exe" or "git.cmd". Using "bin/git.exe" directly + ;; is faster than using one of the wrappers "cmd/git.exe" + ;; or "cmd/git.cmd". The wrappers are likely to come + ;; earlier on $PATH, and so we have to exlicitly use + ;; the former. + (let ((exe (executable-find "git.exe"))) + (when exe + (let ((alt (directory-file-name (file-name-directory exe)))) + (if (and (equal (file-name-nondirectory alt) "cmd") + (setq alt (expand-file-name + (convert-standard-filename "bin/git.exe") + (file-name-directory alt))) + (file-executable-p alt)) + alt + exe))))) + ;; When the only cost is finding the executable, then it it + ;; better not to cache the full path. It might not be installed + ;; in the same location on machines whose repositories are + ;; accessed using Tramp. + "git") + "The Git executable used by Magit." + :group 'magit-process + :type 'string) + +(defcustom magit-git-standard-options + '("--no-pager" "-c" "core.preloadindex=true") + "Standard options when running Git. +Be careful what you add here, especially if you are using +tramp to connect to servers with ancient Git versions." + :group 'magit-process + :type '(repeat string)) + +(defcustom magit-gitk-executable + (or (and (eq system-type 'windows-nt) + (let ((exe (expand-file-name + "gitk" (file-name-nondirectory magit-git-executable)))) + (and (file-executable-p exe) exe))) + (executable-find "gitk") "gitk") + "The Gitk executable." + :group 'magit-process + :set-after '(magit-git-executable) + :type 'string) + +(defun magit-locate-emacsclient () + "Search for a suitable Emacsclient executable." + (let ((path (cl-copy-list exec-path)) fixup client) + (when invocation-directory + (setq path (cons (directory-file-name invocation-directory) path)) + (when (eq system-type 'darwin) + (setq fixup (expand-file-name "bin" invocation-directory)) + (when (file-directory-p fixup) + (push fixup path)) + (when (string-match "^Emacs-\\(powerpc\\|i386\\|x86_64\\)-\\(.+\\)" + invocation-name) + (setq fixup (expand-file-name + (format "bin-%s-%s" + (match-string 1 invocation-name) + (match-string 2 invocation-name)) + invocation-directory)) + (when (file-directory-p fixup) + (push fixup path))) + (when (string-match-p "Cellar" invocation-directory) + (setq fixup (expand-file-name "../../../bin" invocation-directory)) + (when (file-directory-p fixup) + (push fixup path)))) + (setq path (delete-dups path))) + (setq client (magit-locate-emacsclient-1 path 3)) + (if client + (shell-quote-argument client) + (display-warning 'magit (format "\ +Cannot determine a suitable Emacsclient + +Determining an Emacsclient executable suitable for the +current Emacs instance failed. For more information +please see https://github.com/magit/magit/wiki/Emacsclient.")) + nil))) + +(defun magit-take (n l) ; until we get to use `-take' from dash + (let (r) (dotimes (_ n) (and l (push (pop l) r))) (nreverse r))) + +(defun magit-locate-emacsclient-1 (path depth) + (let* ((version-lst (magit-take depth (split-string emacs-version "\\."))) + (version-reg (concat "^" (mapconcat #'identity version-lst "\\.")))) + (or (locate-file-internal + "emacsclient" path + (cl-mapcan + (lambda (v) (cl-mapcar (lambda (e) (concat v e)) exec-suffixes)) + (nconc (cl-mapcon (lambda (v) + (setq v (mapconcat #'identity (reverse v) ".")) + (list v (concat "-" v))) + (reverse version-lst)) + (list ""))) + (lambda (exec) + (ignore-errors + (string-match-p version-reg (magit-emacsclient-version exec))))) + (and (> depth 1) + (magit-locate-emacsclient-1 path (1- depth)))))) + +(defun magit-emacsclient-version (exec) + (cadr (split-string (car (process-lines exec "--version"))))) + +(defcustom magit-emacsclient-executable (magit-locate-emacsclient) + "The Emacsclient executable. +If the default is nil, or commiting or rebasing is somehow broken, +please see https://github.com/magit/magit/wiki/Emacsclient." + :package-version '(magit . "1.4.0") + :group 'magit-process + :type '(choice (string :tag "Executable") + (const :tag "Don't use Emacsclient" nil))) + +(defcustom magit-process-connection-type (not (eq system-type 'cygwin)) + "Connection type used for the git process. + +If nil, use pipes: this is usually more efficient, and works on Cygwin. +If t, use ptys: this enables magit to prompt for passphrases when needed." + :group 'magit-process + :type '(choice (const :tag "pipe" nil) + (const :tag "pty" t))) + +(defcustom magit-process-popup-time -1 + "Popup the process buffer if a command takes longer than this many seconds." + :group 'magit-process + :type '(choice (const :tag "Never" -1) + (const :tag "Immediately" 0) + (integer :tag "After this many seconds"))) + +(defcustom magit-process-log-max 32 + "Maximum number of sections to keep in a process log buffer. +When adding a new section would go beyond the limit set here, +then the older half of the sections are remove. Sections that +belong to processes that are still running are never removed." + :package-version '(magit . "1.4.0") + :group 'magit-process + :type 'integer) + +(defcustom magit-process-quote-curly-braces + (and (eq system-type 'windows-nt) + (let ((case-fold-search t)) + (string-match-p "cygwin" magit-git-executable)) + t) + "Whether curly braces should be quoted when calling git. +This may be necessary when using Windows. On all other system +types this must always be nil. + +We are not certain when quoting is needed, but it appears it is +needed when using Cygwin Git but not when using stand-alone Git. +The default value is set based on that assumptions. If this +turns out to be wrong you can customize this option but please +also comment on issue #816." + :package-version '(magit . "1.4.0") + :group 'magit-process + :set-after '(magit-git-executable) + :type 'boolean) + +(defcustom magit-process-yes-or-no-prompt-regexp + " [\[(]\\([Yy]\\(?:es\\)?\\)[/|]\\([Nn]o?\\)[\])] ?[?:] ?$" + "Regexp matching Yes-or-No prompts of git and its subprocesses." + :package-version '(magit . "1.4.0") + :group 'magit-process + :type 'regexp) + +(defcustom magit-process-password-prompt-regexps + '("^\\(Enter \\)?[Pp]assphrase\\( for \\(RSA \\)?key '.*'\\)?: ?$" + "^\\(Enter \\)?[Pp]assword\\( for '.*'\\)?: ?$" + "^.*'s password: ?$" + "^Yubikey for .*: ?$") + "List of regexps matching password prompts of git and its subprocesses." + :package-version '(magit . "1.4.0") + :group 'magit-process + :type '(repeat (regexp))) + +(defcustom magit-process-username-prompt-regexps + '("^Username for '.*': ?$") + "List of regexps matching username prompts of git and its subprocesses." + :package-version '(magit . "1.4.0") + :group 'magit-process + :type '(repeat (regexp))) + +(defconst magit-server-window-type + '(choice + (const :tag "Use selected window" + :match (lambda (widget value) + (not (functionp value))) + nil) + (function-item :tag "Display in new frame" switch-to-buffer-other-frame) + (function-item :tag "Use pop-to-buffer" pop-to-buffer) + (function :tag "Other function"))) + +(defcustom magit-server-window-for-commit 'pop-to-buffer + "Function used to select a window for displaying commit message buffers. +It should take one argument (a buffer) and display and select it. +A common value is `pop-to-buffer'. It can also be nil in which +case the selected window is used." + :package-version '(magit . "1.4.0") + :group 'magit-process + :type magit-server-window-type) + +(defcustom magit-server-window-for-rebase server-window + "Function used to select a window for displaying interactive rebase buffers. +It should take one argument (a buffer) and display and select it. +A common value is `pop-to-buffer'. It can also be nil in which +case the selected window is used." + :package-version '(magit . "1.4.0") + :group 'magit-process + :set-after '(server-window) + :type magit-server-window-type) + +;;;;; Staging + +(defcustom magit-stage-all-confirm t + "Whether to require confirmation before staging all changes. +This reduces the risk of accidentally losing the index. If +nothing at all is staged yet, then always stage without requiring +confirmation, because it can be undone without the risk of losing +a carefully crafted index." + :package-version '(magit . "1.4.0") + :group 'magit + :type 'boolean) + +(defcustom magit-unstage-all-confirm t + "Whether to require confirmation before unstaging all changes. +This reduces the risk of accidentally losing of the index. If +there are no staged changes at all, then always unstage without +confirmation, because it can be undone without the risk of losing +a carefully crafted index." + :package-version '(magit . "1.4.0") + :group 'magit + :type 'boolean) + +(defcustom magit-revert-item-confirm t + "Whether to require confirmation before reverting hunks. +If you disable this, consider enabling `magit-revert-backup' +instead." + :group 'magit + :type 'boolean) + +(defcustom magit-revert-backup nil + "Whether to backup a hunk before reverting it. +The hunk is stored in \".git/magit/reverted.diff\" and can be +applied using `magit-revert-undo'. Older hunks are available +in the same directory as numbered backup files and have to be +applied manually. Only individual hunks are backed up; when +a complete file is reverted (which requires confirmation) no +backup is created." + :package-version '(magit . "1.4.0") + :group 'magit + :type 'boolean) + +(defcustom magit-save-some-buffers t + "Whether certain commands save modified buffers before running. + +nil don't save buffers. +t ask which buffers to save. +`dontask' save all buffers without asking." + :group 'magit + :type '(choice (const :tag "Never" nil) + (const :tag "Ask" t) + (const :tag "Save without asking" dontask))) + +(defcustom magit-save-some-buffers-predicate + 'magit-save-buffers-predicate-tree-only + "A predicate function to decide whether to save a buffer. + +Used by function `magit-save-some-buffers' when the variable of +the same name is non-nil." + :group 'magit + :type '(radio (function-item magit-save-buffers-predicate-tree-only) + (function-item magit-save-buffers-predicate-all) + (function :tag "Other"))) + +(defcustom magit-rewrite-inclusive t + "Whether magit includes the selected base commit in a rewrite operation. + +t means both the selected commit as well as any subsequent +commits will be rewritten. This is magit's default behaviour, +equivalent to 'git rebase -i ${REV}~1' + + A'---B'---C'---D' + ^ + +nil means the selected commit will be literally used as 'base', +so only subsequent commits will be rewritten. This is consistent +with git-rebase, equivalent to 'git rebase -i ${REV}', yet more +cumbersome to use from the status buffer. + + A---B'---C'---D' + ^" + :group 'magit + :type '(choice (const :tag "Always" t) + (const :tag "Never" nil) + (const :tag "Ask" ask))) + +;;;;; Highlighting + +(defun magit-set-variable-and-refresh (symbol value) + "Set SYMBOL to VALUE and call `magit-refresh-all'." + (set-default symbol value) + ;; If magit isn't fully loaded yet no buffer that might + ;; need refreshing can exist and we can take a shortcut. + ;; We also don't want everything to repeatedly refresh + ;; when evaluating this file. + (when (and (featurep 'magit) (not buffer-file-name)) + (magit-refresh-all))) + +(defcustom magit-highlight-whitespace t + "Specify where to highlight whitespace errors. +See `magit-highlight-trailing-whitespace', +`magit-highlight-indentation'. The symbol t means in all diffs, +`status' means only in the status buffer, and nil means nowhere." + :group 'magit + :set 'magit-set-variable-and-refresh + :type '(choice (const :tag "Always" t) + (const :tag "Never" nil) + (const :tag "In status buffer" status))) + +(defcustom magit-highlight-trailing-whitespace t + "Whether to highlight whitespace at the end of a line in diffs. +Used only when `magit-highlight-whitespace' is non-nil." + :group 'magit + :set 'magit-set-variable-and-refresh + :type 'boolean) + +(defcustom magit-highlight-indentation nil + "Highlight the \"wrong\" indentation style. +Used only when `magit-highlight-whitespace' is non-nil. + +The value is a list of cons cells. The car is a regular +expression, and the cdr is the value that applies to repositories +whose directory matches the regular expression. If more than one +item matches, then the *last* item in the list applies. So, the +default value should come first in the list. + +If the value is `tabs', highlight indentation with tabs. If the +value is an integer, highlight indentation with at least that +many spaces. Otherwise, highlight neither." + :group 'magit + :set 'magit-set-variable-and-refresh + :type `(repeat (cons (string :tag "Directory regexp") + (choice (const :tag "Tabs" tabs) + (integer :tag "Spaces" :value ,tab-width) + (const :tag "Neither" nil))))) ;^FIXME + +(defcustom magit-item-highlight-face 'magit-item-highlight + "The face used to highlight the current section. + +By default the highlighting of the current section is done using +the background color specified by face `magit-item-highlight'. + +If you don't want to use the background to do the highlighting, +this *might* by as easy as customizing that face. However if you +are using a theme, which in turn sets the background color of +that face then, due to limitations in face inheritance when using +themes, you might be forced to use another face. + +Unfortunately it is only possible to override a face attribute, +set by a theme, but not to drop it entirely. This means that one +has to explicitly use the `default' background color, to make it +appear *as if* the background wasn't used. + +One reason you might want to *not* use the background, is that +doing so forces the use of overlays for parts of diffs and for +refnames. Using overlays potentially degrades performance when +generating large diffs. Also see option `magit-use-overlays'." + :package-version '(magit . "1.4.0") + :group 'magit + :group 'magit-faces + :type '(choice (const magit-item-highlight) + (const bold) + (face :tag "Other face") + (const :tag "Don't highlight" nil))) + +(defcustom magit-use-overlays + (not (eq magit-item-highlight-face 'bold)) + "Whether to use overlays to highlight various diff components. + +This has to be non-nil if the current section is highlighted by +changing the background color. Otherwise background colors that +hold semantic meaning, like that of the added and removed lines +in diffs, as well as section headings, would be shadowed by the +highlighting. + +To select the face used for highlighting customize the option +`magit-item-highlight-face'. If you set that to `bold' or some +other face that does not use the background then you can set this +option to nil. Doing so could potentially improve performance +when generating large diffs." + :package-version '(magit . "1.4.0") + :group 'magit + :group 'magit-faces + :set-after '(magit-item-highlight-face) + :type 'boolean) + +(define-obsolete-variable-alias 'magit-diff-use-overlays + 'magit-use-overlays "1.4.0") + +;;;;; Completion + +(defcustom magit-completing-read-function 'magit-builtin-completing-read + "Function to be called when requesting input from the user." + :group 'magit + :type '(radio (function-item magit-ido-completing-read) + (function-item magit-builtin-completing-read) + (function :tag "Other"))) + +(defcustom magit-remote-ref-format 'remote-slash-branch + "How to format refs when autocompleting, in particular for remotes. + +Autocompletion is used by functions like `magit-checkout', +`magit-interactive-rebase' and others which offer branch name +completion. + +`remote-slash-branch' Format refs as \"remote/branch\". +`branch-then-remote' Format refs as \"branch (remote)\"." + :package-version '(magit . "1.4.0") + :group 'magit + :type '(choice (const :tag "branch (remote)" branch-then-remote) + (const :tag "remote/branch" remote-slash-branch))) + +(defcustom magit-repo-dirs nil + "Directories containing Git repositories. +Magit will look into these directories for Git repositories and +offer them as choices for `magit-status'." + :group 'magit + :type '(repeat directory)) + +(defcustom magit-repo-dirs-depth 3 + "The maximum depth to look for Git repos. +When looking for a Git repository below the directories in +`magit-repo-dirs', Magit will only descend this many levels +deep." + :group 'magit + :type 'integer) + +;;;;; Modes +;;;;;; Common + +(defcustom magit-mode-hook nil + "Hook run when entering a Magit mode derived mode." + :options '(magit-load-config-extensions) + :group 'magit-modes + :type 'hook) + +(defcustom magit-show-xref-buttons '(magit-diff-mode magit-commit-mode) + "List of modes whose buffers should contain history buttons. +Currently only `magit-diff-mode' and `magit-commit-mode' are +supported." + :package-version '(magit . "1.4.0") + :group 'magit-modes + :type '(repeat (choice (const magit-diff-mode) + (const magit-commit-mode)))) + +(defcustom magit-show-child-count nil + "Whether to append the number of childen to section headings." + :package-version '(magit . "1.4.0") + :group 'magit-modes + :type 'boolean) + +(defvar magit-status-line-align-to 9) + +(defcustom magit-restore-window-configuration nil + "Whether quitting a Magit buffer restores previous window configuration. + +Function `magit-mode-display-buffer' is used to display and +select Magit buffers. Unless the buffer was already displayed in +a window of the selected frame it also stores the previous window +configuration. If this option is non-nil that configuration will +later be restored by `magit-mode-quit-window', provided the +buffer has not since been displayed in another frame. + +This works best when only two windows are usually displayed in a +frame. If this isn't the case setting this to t might often lead +to undesirable behaviour. Also quitting a Magit buffer while +another Magit buffer that was created earlier is still displayed +will cause that buffer to be hidden, which might or might not be +what you want." + :package-version '(magit . "1.4.0") + :group 'magit-modes + :type 'boolean) + +(defcustom magit-refs-namespaces + '(("^\\(HEAD\\)$" magit-log-head-label-head nil) + ("^refs/tags/\\(.+\\)" magit-log-head-label-tags nil) + ("^refs/heads/\\(.+\\)" magit-log-head-label-local nil) + ("^refs/remotes/\\(.+\\)" magit-log-head-label-remote nil) + ("^refs/bisect/\\(bad\\)" magit-log-head-label-bisect-bad nil) + ("^refs/bisect/\\(skip.*\\)" magit-log-head-label-bisect-skip nil) + ("^refs/bisect/\\(good.*\\)" magit-log-head-label-bisect-good nil) + ("^refs/wip/\\(.+\\)" magit-log-head-label-wip nil) + ("^refs/patches/\\(.+\\)" magit-log-head-label-patches nil) + ("^\\(bad\\):" magit-log-head-label-bisect-bad nil) + ("^\\(skip\\):" magit-log-head-label-bisect-skip nil) + ("^\\(good\\):" magit-log-head-label-bisect-good nil) + ("\\(.+\\)" magit-log-head-label-default nil)) + "How different refs should be formatted for display. + +Each entry controls how a certain type of ref is displayed, and +has the form (REGEXP FACE FORMATTER). REGEXP is a regular +expression used to match full refs. The first entry whose REGEXP +matches the reference is used. The first regexp submatch becomes +the \"label\" that represents the ref and is propertized with +font FONT. If FORMATTER is non-nil it should be a function that +takes two arguments, the full ref and the face. It is supposed +to return a propertized label that represents the ref. + +Currently this variable is only used in logs and the branch +manager but it will be used in more places in the future." + :package-version '(magit . "1.4.0") + :group 'magit-modes + :type '(repeat + (list regexp + face + (choice (const :tag "first submatch is label" nil) + (function :tag "format using function"))))) + +;;;;;; Status + +(defcustom magit-status-mode-hook nil + "Hook run when the `magit-status' buffer is created." + :group 'magit-status + :type 'hook) + +(defcustom magit-status-sections-hook + '(magit-insert-status-local-line + magit-insert-status-remote-line + magit-insert-status-head-line + magit-insert-status-tags-line + magit-insert-status-merge-line + magit-insert-status-rebase-lines + magit-insert-empty-line + magit-insert-rebase-sequence + magit-insert-bisect-output + magit-insert-bisect-rest + magit-insert-bisect-log + magit-insert-stashes + magit-insert-untracked-files + magit-insert-pending-commits + magit-insert-unstaged-changes + magit-insert-staged-changes + magit-insert-unpulled-commits + magit-insert-unpushed-commits) + "Hook run to insert sections into the status buffer. + +This option allows reordering the sections and adding sections +that are by default displayed in other Magit buffers. Doing the +latter is currently not recommended because not all functions +that insert sections have been adapted yet. Only inserters that +take no argument can be used and some functions exist that begin +with the `magit-insert-' prefix but do not insert a section. + +Note that there are already plans to improve this and to add +similar hooks for other Magit modes." + :package-version '(magit . "1.4.0") + :group 'magit-status + :type 'hook) + +(defcustom magit-status-buffer-switch-function 'pop-to-buffer + "Function for `magit-status' to use for switching to the status buffer. + +The function is given one argument, the status buffer." + :group 'magit-status + :type '(radio (function-item switch-to-buffer) + (function-item pop-to-buffer) + (function :tag "Other"))) + +(defcustom magit-status-show-sequence-help t + "Whether to show instructions on how to proceed a stopped action. +When this is non-nil and a commit failed to apply during a merge +or rebase, then show instructions on how to continue." + :package-version '(magit . "1.4.0") + :group 'magit-status + :type 'boolean) + +(defcustom magit-status-tags-line-subject 'head + "Whether tag or head is the subject on tags line in status buffer. + +This controls how the words \"ahead\" and \"behind\" are used on +the tags line in the status buffer. The tags line does not +actually display complete sentences, but when thinking about when +to use which term, it helps imagining it did. This option +controls whether the tag names should be considered the subjects +or objects in these sentences. + +`tag' The previous tag is *behind* HEAD by N commits. + The next tag is *ahead* of HEAD by N commits. +`head' HEAD is *ahead* of the previous tag by N commits. + HEAD is *behind* the next tag by N commits. + +If the value is `tag' the commit counts are fontified; otherwise +they are not (due to semantic considerations)." + :package-version '(magit . "1.4.0") + :group 'magit-status + :type '(choice (const :tag "tags are the subjects" tag) + (const :tag "head is the subject" head))) + +;;;;;; Diff + +(defun magit-set-default-diff-options (symbol value) + "Set the default for `magit-diff-options' based on popup value. +Also set the local value in all Magit buffers and refresh them. +\n(fn)" ; The arguments are an internal implementation detail. + (interactive (list 'magit-diff-options magit-custom-options)) + (set-default symbol value) + (when (and (featurep 'magit) (not buffer-file-name)) + (dolist (buffer (buffer-list)) + (when (derived-mode-p 'magit-mode) + (with-current-buffer buffer + (with-no-warnings + (setq-local magit-diff-options value)) + (magit-mode-refresh-buffer)))))) + +(defcustom magit-diff-options nil + "Git options used to display diffs. + +For more information about the options see man:git-diff. +This variable can be conveniently set in Magit buffers +using `magit-key-mode-popup-diff-options' (bound to \ +\\\\[magit-key-mode-popup-diff-options]). + +Please note that not all of these options are supported by older +versions of Git, which could become a problem if you use tramp to +access repositories on a system with such a version. If you see +whitespace where you would have expected a diff, this likely is +the cause, and the only (currently) workaround is to not make the +problematic option a member of the default value." + :package-version '(magit . "1.4.0") + :group 'magit-diff + :set 'magit-set-default-diff-options + :type '(set :greedy t + (const :tag + "--minimal Show smallest possible diff" + "--minimal") + (const :tag + "--patience Use patience diff algorithm" + "--patience") + (const :tag + "--histogram Use histogram diff algorithm" + "--histogram") + (const :tag + "--ignore-space-change Ignore whitespace changes" + "--ignore-space-change") + (const :tag + "--ignore-all-space Ignore all whitespace" + "--ignore-all-space") + (const :tag + "--function-context Show surrounding functions" + "--function-context"))) + +(put 'magit-diff-options 'permanent-local t) + +(defcustom magit-show-diffstat t + "Whether to show diffstat in diff and commit buffers." + :package-version '(magit . "1.4.0") + :group 'magit-diff + :group 'magit-commit + :type 'boolean) + +(defcustom magit-diff-refine-hunk nil + "Show fine (word-granularity) differences within diff hunks. + +There are three possible settings: + +nil never show fine differences +t show fine differences for the selected diff hunk only +`all' show fine differences for all displayed diff hunks" + :group 'magit-diff + :type '(choice (const :tag "Never" nil) + (const :tag "Selected only" t) + (const :tag "All" all)) + :set 'magit-set-variable-and-refresh) + +;;;;;; Commit + +(defcustom magit-commit-ask-to-stage t + "Whether to ask to stage everything when committing and nothing is staged." + :package-version '(magit . "1.4.0") + :group 'magit-commit + :type 'boolean) + +(defcustom magit-commit-extend-override-date nil + "Whether using `magit-commit-extend' changes the committer date." + :package-version '(magit . "1.4.0") + :group 'magit-commit + :type 'boolean) + +(defcustom magit-commit-reword-override-date nil + "Whether using `magit-commit-reword' changes the committer date." + :package-version '(magit . "1.4.0") + :group 'magit-commit + :type 'boolean) + +(defcustom magit-commit-squash-commit nil + "Whether to target the marked or current commit when squashing. + +When this is nil then the command `magit-commit-fixup' and +`magit-commit-squash' always require that the user explicitly +selects a commit. This is also the case when these commands are +used with a prefix argument, in which case this option is ignored. + +Otherwise this controls which commit to target, either the +current or marked commit. Or if both can be used, which should +be preferred." + :package-version '(magit . "1.4.0") + :group 'magit-commit + :type + '(choice + (const :tag "Always prompt" nil) + (const :tag "Prefer current commit, else use marked" current-or-marked) + (const :tag "Prefer marked commit, else use current" marked-or-current) + (const :tag "Use current commit, if any" current) + (const :tag "Use marked commit, if any" marked))) + +(defcustom magit-expand-staged-on-commit nil + "Whether to expand staged changes when creating a commit. +When this is non-nil and the current buffer is the status buffer +expand the section containing staged changes. If this is `full' +always expand all subsections; if it is t subsections that were +previously hidden remain hidden. + +In the event that expanding very large patches takes a long time +\\\\[keyboard-quit] can be used to abort that step. +This is especially useful when you would normally not look at the +changes, e.g. because you are committing some binary files." + :package-version '(magit . "1.4.0") + :group 'magit-commit + :type '(choice (const :tag "Expand all subsections" full) + (const :tag "Expand top section" t) + (const :tag "Don't expand" nil))) + +;;;;;; Log + +(defcustom magit-log-auto-more nil + "Insert more log entries automatically when moving past the last entry. + +Only considered when moving past the last entry with +`magit-goto-*-section' commands." + :group 'magit-log + :type 'boolean) + +(defcustom magit-log-cutoff-length 100 + "The maximum number of commits to show in the log and whazzup buffers." + :group 'magit-log + :type 'integer) + +(defcustom magit-log-infinite-length 99999 + "Number of log used to show as maximum for `magit-log-cutoff-length'." + :group 'magit-log + :type 'integer) + +(defcustom magit-log-format-graph-function nil + "Function used to format graphs in log buffers. +The function is called with one argument, the propertized graph +of a single line in as a string. It has to return the formatted +string. This option can also be nil, in which case the graph is +inserted as is." + :package-version '(magit . "1.4.0") + :group 'magit-log + :type '(choice (const :tag "insert as is" nil) + (function-item magit-log-format-unicode-graph) + function)) + +(defcustom magit-log-format-unicode-graph-alist + '((?/ . ?╱) (?| . ?│) (?\\ . ?╲) (?* . ?â—†) (?o . ?â—‡)) + "Alist used by `magit-log-format-unicode-graph' to translate chars." + :package-version '(magit . "1.4.0") + :group 'magit-log + :type '(repeat (cons :format "%v\n" + (character :format "replace %v ") + (character :format "with %v")))) + +(defcustom magit-log-show-gpg-status nil + "Display signature verification information as part of the log." + :package-version '(magit . "1.4.0") + :group 'magit-log + :type 'boolean) + +(defcustom magit-log-show-margin t + "Whether to use a margin when showing `oneline' logs. +When non-nil the author name and date are displayed in the margin +of the log buffer if that contains a `oneline' log. This can be +toggled temporarily using the command `magit-log-toggle-margin'." + :package-version '(magit . "1.4.0") + :group 'magit-log + :type 'boolean) + +(put 'magit-log-show-margin 'permanent-local t) + +(defcustom magit-log-margin-spec '(25 nil magit-duration-spec) + "How to format the margin for `oneline' logs. + +When the log buffer contains a `oneline' log, then it optionally +uses the right margin to display the author name and author date. +This is also supported in the reflog buffer. + +Logs that are shown together with other non-log information (e.g. +in the status buffer) are never accompanied by a margin. The +same applies to `long' logs, in this case because that would be +redundant. + +This option controls how that margin is formatted, the other +option affecting this is `magit-log-show-margin'; if that is nil +then no margin is displayed at all. To toggle this temporarily +use the command `magit-log-show-margin'. + +The value has the form (WIDTH CHARACTERP DURATION-SPEC). The +width of the margin is controlled using WIDTH, an integer. When +CHARACTERP is non-nil time units are shown as single characters, +otherwise the full name of the unit is displayed. DURATION-SPEC +has to be a variable, its value controls which time units are +used, how many seconds they contain, and what their names are." + :package-version '(magit . "1.4.0") + :group 'magit-log + :type '(list (integer :tag "Margin width") + (choice :tag "Time unit style" + (const :tag "Character" t) + (const :tag "Word" nil)) + (variable :tag "Duration spec variable"))) + +(defcustom magit-duration-spec + `((?Y "year" "years" ,(round (* 60 60 24 365.2425))) + (?M "month" "months" ,(round (* 60 60 24 30.436875))) + (?w "week" "weeks" ,(* 60 60 24 7)) + (?d "day" "days" ,(* 60 60 24)) + (?h "hour" "hours" ,(* 60 60)) + (?m "minute" "minutes" 60) + (?s "second" "seconds" 1)) + "Units used to display durations in a human format. +The value is a list of time units, beginning with the longest. +Each element has the form ((CHAR UNIT UNITS SECONDS)..). UNIT +is the time unit, UNITS is the plural of that unit. CHAR is a +character that can be used as abbreviation and must be unique +amoung all elements. SECONDS is the number of seconds in one +UNIT. Also see option `magit-log-margin-spec'." + :package-version '(magit . "1.4.0") + :group 'magit-log + :type '(repeat (list (character :tag "Unit character") + (string :tag "Unit singular string") + (string :tag "Unit plural string") + (integer :tag "Seconds in unit")))) + +(defcustom magit-ellipsis #x2026 ; "horizontal ellipsis" + "Character appended to abreviated text. +Currently this is used only in the log margin, but might later +be used elsewhere too. Filenames that were abbreviated by Git +are left as-is." + :package-version '(magit . "1.4.0") + :group 'magit-log + :type 'character) + +;;;;;; Others + +(defcustom magit-auto-revert-mode-lighter " MRev" + "String to display when Magit-Auto-Revert mode is active." + :group 'magit-modes) + +(define-minor-mode magit-auto-revert-mode + "Toggle global Magit-Auto-Revert mode. +With prefix ARG, enable Magit-Auto-Revert mode if ARG is positive; +otherwise, disable it. If called from Lisp, enable the mode if +ARG is omitted or nil. + +Magit-Auto-Revert mode is a global minor mode that, after Magit +has run a Git command, reverts buffers associated with files that +have changed on disk and are tracked in the current Git repository." + :group 'magit-modes + :lighter magit-auto-revert-mode-lighter + :global t + :init-value t) + +(defcustom magit-merge-warn-dirty-worktree t + "Whether to issue a warning when attempting to start a merge in a dirty worktree." + :package-version '(magit . "1.4.0") + :group 'magit-modes + :type 'boolean) + +(defcustom magit-push-hook '(magit-push-dwim) + "Hook run by `magit-push' to actually do the work. +See `magit-push' and `magit-push-dwim' for more information." + :package-version '(magit . "1.4.0") + :group 'magit-modes + :type 'hook) + +(defcustom magit-set-upstream-on-push nil + "Whether `magit-push' may set upstream when pushing a branch. +This only applies if the branch does not have an upstream set yet. + +nil don't use --set-upstream. +t ask if --set-upstream should be used. +`dontask' always use --set-upstream. +`refuse' refuse to push unless a remote branch has already been set." + :group 'magit-modes + :type '(choice (const :tag "Never" nil) + (const :tag "Ask" t) + (const :tag "Ask if not set" askifnotset) + (const :tag "Refuse" refuse) + (const :tag "Always" dontask))) + +(defcustom magit-wazzup-sections-hook + '(magit-insert-wazzup-head-line + magit-insert-empty-line + magit-insert-wazzup-branches) + "Hook run to insert sections into the wazzup buffer." + :package-version '(magit . "1.4.0") + :group 'magit-modes + :type 'hook) + +(defcustom magit-cherry-sections-hook + '(magit-insert-cherry-head-line + magit-insert-cherry-upstream-line + magit-insert-cherry-help-lines + magit-insert-empty-line + magit-insert-cherry-commits) + "Hook run to insert sections into the cherry buffer." + :package-version '(magit . "1.4.0") + :group 'magit-modes + :type 'hook) + +;;;; Custom Faces + +(defface magit-section-title + '((t :inherit header-line)) + "Face for section titles." + :group 'magit-faces) + +(defface magit-branch + '((((class color) (background light)) + :background "Grey85" + :foreground "LightSkyBlue4") + (((class color) (background dark)) + :background "Grey13" + :foreground "LightSkyBlue1")) + "Face for branches." + :group 'magit-faces) + +(defface magit-tag + '((((class color) (background light)) + :background "LemonChiffon1" + :foreground "goldenrod4") + (((class color) (background dark)) + :background "LemonChiffon1" + :foreground "goldenrod4")) + "Face for tags." + :group 'magit-faces) + +(defface magit-diff-file-header + '((t :inherit diff-file-header)) + "Face for diff file header lines." + :group 'magit-faces) + +(defface magit-diff-hunk-header + '((t :inherit diff-hunk-header)) + "Face for diff hunk header lines." + :group 'magit-faces) + +(defface magit-diff-add + '((t :inherit diff-added)) + "Face for lines in a diff that have been added." + :group 'magit-faces) + +(defface magit-diff-del + '((t :inherit diff-removed)) + "Face for lines in a diff that have been deleted." + :group 'magit-faces) + +(defface magit-diff-none + '((t :inherit diff-context)) + "Face for lines in a diff that are unchanged." + :group 'magit-faces) + +(defface magit-diff-merge-current + '((t :inherit font-lock-preprocessor-face)) + "Face for merge conflict marker 'current' line." + :group 'magit-faces) + +(defface magit-diff-merge-separator + '((t :inherit font-lock-preprocessor-face)) + "Face for merge conflict marker seperator." + :group 'magit-faces) + +(defface magit-diff-merge-diff3-separator + '((t :inherit font-lock-preprocessor-face)) + "Face for merge conflict marker seperator." + :group 'magit-faces) + +(defface magit-diff-merge-proposed + '((t :inherit font-lock-preprocessor-face)) + "Face for merge conflict marker 'proposed' line." + :group 'magit-faces) + +(defface magit-log-graph + '((((class color) (background light)) + :foreground "grey11") + (((class color) (background dark)) + :foreground "grey80")) + "Face for the graph element of the log output." + :group 'magit-faces) + +(defface magit-log-sha1 + '((((class color) (background light)) + :foreground "firebrick") + (((class color) (background dark)) + :foreground "tomato")) + "Face for the sha1 element of the log output." + :group 'magit-faces) + +(defface magit-log-author + '((((class color) (background light)) + :foreground "firebrick") + (((class color) (background dark)) + :foreground "tomato")) + "Face for the author element of the log output." + :group 'magit-faces) + +(defface magit-log-date + '((t)) + "Face for the date element of the log output." + :group 'magit-faces) + +(defface magit-log-message + '((t)) + "Face for the message element of the log output." + :group 'magit-faces) + +(defface magit-cherry-unmatched + '((t :foreground "cyan")) + "Face for unmatched cherry commits.") + +(defface magit-cherry-equivalent + '((t :foreground "magenta")) + "Face for equivalent cherry commits.") + +(defface magit-item-highlight + '((t :inherit secondary-selection)) + "Face for highlighting the current item." + :group 'magit-faces) + +(defface magit-item-mark + '((t :inherit highlight)) + "Face for highlighting marked item." + :group 'magit-faces) + +(defface magit-log-head-label-bisect-good + '((((class color) (background light)) + :box t + :background "light green" + :foreground "dark olive green") + (((class color) (background dark)) + :box t + :background "light green" + :foreground "dark olive green")) + "Face for good bisect refs." + :group 'magit-faces) + +(defface magit-log-head-label-bisect-skip + '((((class color) (background light)) + :box t + :background "light goldenrod" + :foreground "dark goldenrod") + (((class color) (background dark)) + :box t + :background "light goldenrod" + :foreground "dark goldenrod")) + "Face for skipped bisect refs." + :group 'magit-faces) + +(defface magit-log-head-label-bisect-bad + '((((class color) (background light)) + :box t + :background "IndianRed1" + :foreground "IndianRed4") + (((class color) (background dark)) + :box t + :background "IndianRed1" + :foreground "IndianRed4")) + "Face for bad bisect refs." + :group 'magit-faces) + +(defface magit-log-head-label-remote + '((((class color) (background light)) + :box t + :background "Grey85" + :foreground "OliveDrab4") + (((class color) (background dark)) + :box t + :background "Grey11" + :foreground "DarkSeaGreen2")) + "Face for remote branch head labels shown in log buffer." + :group 'magit-faces) + +(defface magit-log-head-label-tags + '((((class color) (background light)) + :box t + :background "LemonChiffon1" + :foreground "goldenrod4") + (((class color) (background dark)) + :box t + :background "LemonChiffon1" + :foreground "goldenrod4")) + "Face for tag labels shown in log buffer." + :group 'magit-faces) + +(defface magit-log-head-label-patches + '((((class color) (background light)) + :box t + :background "IndianRed1" + :foreground "IndianRed4") + (((class color) (background dark)) + :box t + :background "IndianRed1" + :foreground "IndianRed4")) + "Face for Stacked Git patches." + :group 'magit-faces) + +(defface magit-whitespace-warning-face + '((t :inherit trailing-whitespace)) + "Face for highlighting whitespace errors in Magit diffs." + :group 'magit-faces) + +(defface magit-log-head-label-local + '((((class color) (background light)) + :box t + :background "Grey85" + :foreground "LightSkyBlue4") + (((class color) (background dark)) + :box t + :background "Grey13" + :foreground "LightSkyBlue1")) + "Face for local branch head labels shown in log buffer." + :group 'magit-faces) + +(defface magit-log-head-label-head + '((((class color) (background light)) + :box t + :background "Grey70" + :foreground "Black") + (((class color) (background dark)) + :box t + :background "Grey20" + :foreground "White")) + "Face for working branch head labels shown in log buffer." + :group 'magit-faces) + +(defface magit-log-head-label-default + '((((class color) (background light)) + :box t + :background "Grey50") + (((class color) (background dark)) + :box t + :background "Grey50")) + "Face for unknown ref labels shown in log buffer." + :group 'magit-faces) + +(defface magit-log-head-label-wip + '((((class color) (background light)) + :box t + :background "Grey95" + :foreground "LightSkyBlue3") + (((class color) (background dark)) + :box t + :background "Grey07" + :foreground "LightSkyBlue4")) + "Face for git-wip labels shown in log buffer." + :group 'magit-faces) + +(defface magit-signature-good + '((t :foreground "green")) + "Face for good signatures." + :group 'magit-faces) + +(defface magit-signature-bad + '((t :foreground "red")) + "Face for bad signatures." + :group 'magit-faces) + +(defface magit-signature-untrusted + '((t :foreground "cyan")) + "Face for good untrusted signatures." + :group 'magit-faces) + +(defface magit-signature-none + '((t :inherit magit-log-message)) + "Face for unsigned commits." + :group 'magit-faces) + + +(defface magit-log-reflog-label-commit + '((((class color) (background light)) + :box t + :background "LemonChiffon1" + :foreground "goldenrod4") + (((class color) (background dark)) + :box t + :background "LemonChiffon1" + :foreground "goldenrod4")) + "Face for reflog subject labels shown in reflog buffer." + :group 'magit-faces) + +(defface magit-log-reflog-label-amend + '((t :inherit magit-log-reflog-label-commit)) + "Face for reflog subject labels shown in reflog buffer." + :group 'magit-faces) + +(defface magit-log-reflog-label-merge + '((t :inherit magit-log-reflog-label-commit)) + "Face for reflog subject labels shown in reflog buffer." + :group 'magit-faces) + +(defface magit-log-reflog-label-checkout + '((((class color) (background light)) + :box t + :background "Grey85" + :foreground "LightSkyBlue4") + (((class color) (background dark)) + :box t + :background "Grey13" + :foreground "LightSkyBlue1")) + "Face for reflog subject labels shown in reflog buffer." + :group 'magit-faces) + +(defface magit-log-reflog-label-reset + '((((class color) (background light)) + :box t + :background "IndianRed1" + :foreground "IndianRed4") + (((class color) (background dark)) + :box t + :background "IndianRed1" + :foreground "IndianRed4")) + "Face for reflog subject labels shown in reflog buffer." + :group 'magit-faces) + +(defface magit-log-reflog-label-rebase + '((((class color) (background light)) + :box t + :background "Grey85" + :foreground "OliveDrab4") + (((class color) (background dark)) + :box t + :background "Grey11" + :foreground "DarkSeaGreen2")) + "Face for reflog subject labels shown in reflog buffer." + :group 'magit-faces) + +(defface magit-log-reflog-label-cherry-pick +'((((class color) (background light)) + :box t + :background "light green" + :foreground "dark olive green") + (((class color) (background dark)) + :box t + :background "light green" + :foreground "dark olive green")) + "Face for reflog subject labels shown in reflog buffer." + :group 'magit-faces) + +(defface magit-log-reflog-label-remote + '((((class color) (background light)) + :box t + :background "Grey50") + (((class color) (background dark)) + :box t + :background "Grey50")) + "Face for reflog subject labels shown in reflog buffer." + :group 'magit-faces) + +(defface magit-log-reflog-label-other + '((((class color) (background light)) + :box t + :background "Grey50") + (((class color) (background dark)) + :box t + :background "Grey50")) + "Face for reflog subject labels shown in reflog buffer." + :group 'magit-faces) + +(defface magit-process-ok + '((t :inherit magit-section-title + :foreground "green")) + "Face for zero exit-status." + :group 'magit-faces) + +(defface magit-process-ng + '((t :inherit magit-section-title + :foreground "red")) + "Face for non-zero exit-status." + :group 'magit-faces) + +;;;; Keymaps + +;; Not an option to avoid advertising it. +(defvar magit-rigid-key-bindings nil + "Use rigid key bindings instead of thematic key popups. +If you enable this a lot of functionality is lost. You most +likely don't want that. This variable only has an effect if +set before loading libary `magit'.") + +(when (boundp 'git-commit-mode-map) + (define-key git-commit-mode-map (kbd "C-c C-d") 'magit-diff-staged)) + +(defvar magit-mode-map + (let ((map (make-keymap))) + (suppress-keymap map t) + (define-key map (kbd "n") 'magit-goto-next-section) + (define-key map (kbd "p") 'magit-goto-previous-section) + (define-key map (kbd "^") 'magit-goto-parent-section) + (define-key map (kbd "M-n") 'magit-goto-next-sibling-section) + (define-key map (kbd "M-p") 'magit-goto-previous-sibling-section) + (define-key map (kbd "TAB") 'magit-toggle-section) + (define-key map (kbd "") 'magit-expand-collapse-section) + (define-key map (kbd "1") 'magit-show-level-1) + (define-key map (kbd "2") 'magit-show-level-2) + (define-key map (kbd "3") 'magit-show-level-3) + (define-key map (kbd "4") 'magit-show-level-4) + (define-key map (kbd "M-1") 'magit-show-level-1-all) + (define-key map (kbd "M-2") 'magit-show-level-2-all) + (define-key map (kbd "M-3") 'magit-show-level-3-all) + (define-key map (kbd "M-4") 'magit-show-level-4-all) + (define-key map (kbd "M-h") 'magit-show-only-files) + (define-key map (kbd "M-H") 'magit-show-only-files-all) + (define-key map (kbd "M-s") 'magit-show-level-4) + (define-key map (kbd "M-S") 'magit-show-level-4-all) + (define-key map (kbd "g") 'magit-refresh) + (define-key map (kbd "G") 'magit-refresh-all) + (define-key map (kbd "?") 'magit-key-mode-popup-dispatch) + (define-key map (kbd ":") 'magit-git-command) + (define-key map (kbd "C-x 4 a") 'magit-add-change-log-entry-other-window) + (define-key map (kbd "L") 'magit-add-change-log-entry) + (define-key map (kbd "RET") 'magit-visit-item) + (define-key map (kbd "C-") 'magit-dired-jump) + (define-key map (kbd "SPC") 'magit-show-item-or-scroll-up) + (define-key map (kbd "DEL") 'magit-show-item-or-scroll-down) + (define-key map (kbd "C-w") 'magit-copy-item-as-kill) + (cond (magit-rigid-key-bindings + (define-key map (kbd "c") 'magit-commit) + (define-key map (kbd "m") 'magit-merge) + (define-key map (kbd "b") 'magit-checkout) + (define-key map (kbd "M") 'magit-branch-manager) + (define-key map (kbd "r") 'undefined) + (define-key map (kbd "f") 'magit-fetch-current) + (define-key map (kbd "F") 'magit-pull) + (define-key map (kbd "J") 'magit-apply-mailbox) + (define-key map (kbd "!") 'magit-git-command-topdir) + (define-key map (kbd "P") 'magit-push) + (define-key map (kbd "t") 'magit-tag) + (define-key map (kbd "l") 'magit-log) + (define-key map (kbd "o") 'magit-submodule-update) + (define-key map (kbd "B") 'undefined) + (define-key map (kbd "z") 'magit-stash)) + (t + (define-key map (kbd "c") 'magit-key-mode-popup-committing) + (define-key map (kbd "m") 'magit-key-mode-popup-merging) + (define-key map (kbd "b") 'magit-key-mode-popup-branching) + (define-key map (kbd "M") 'magit-key-mode-popup-remoting) + (define-key map (kbd "r") 'magit-key-mode-popup-rewriting) + (define-key map (kbd "f") 'magit-key-mode-popup-fetching) + (define-key map (kbd "F") 'magit-key-mode-popup-pulling) + (define-key map (kbd "J") 'magit-key-mode-popup-apply-mailbox) + (define-key map (kbd "!") 'magit-key-mode-popup-running) + (define-key map (kbd "P") 'magit-key-mode-popup-pushing) + (define-key map (kbd "t") 'magit-key-mode-popup-tagging) + (define-key map (kbd "l") 'magit-key-mode-popup-logging) + (define-key map (kbd "o") 'magit-key-mode-popup-submodule) + (define-key map (kbd "B") 'magit-key-mode-popup-bisecting) + (define-key map (kbd "z") 'magit-key-mode-popup-stashing))) + (define-key map (kbd "$") 'magit-process) + (define-key map (kbd "E") 'magit-interactive-rebase) + (define-key map (kbd "R") 'magit-rebase-step) + (define-key map (kbd "e") 'magit-ediff) + (define-key map (kbd "w") 'magit-wazzup) + (define-key map (kbd "y") 'magit-cherry) + (define-key map (kbd "q") 'magit-mode-quit-window) + (define-key map (kbd "x") 'magit-reset-head) + (define-key map (kbd "v") 'magit-revert-item) + (define-key map (kbd "a") 'magit-apply-item) + (define-key map (kbd "A") 'magit-cherry-pick-item) + (define-key map (kbd "d") 'magit-diff-working-tree) + (define-key map (kbd "D") 'magit-diff) + (define-key map (kbd "-") 'magit-diff-smaller-hunks) + (define-key map (kbd "+") 'magit-diff-larger-hunks) + (define-key map (kbd "0") 'magit-diff-default-hunks) + (define-key map (kbd "h") 'magit-key-mode-popup-diff-options) + (define-key map (kbd "H") 'magit-diff-toggle-refine-hunk) + (define-key map (kbd "S") 'magit-stage-all) + (define-key map (kbd "U") 'magit-unstage-all) + (define-key map (kbd "X") 'magit-reset-working-tree) + (define-key map (kbd "C-c C-c") 'magit-key-mode-popup-dispatch) + (define-key map (kbd "C-c C-e") 'magit-key-mode-popup-dispatch) + map) + "Parent keymap for all keymaps of modes derived from `magit-mode'.") + +(defvar magit-commit-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map magit-mode-map) + (define-key map (kbd "C-c C-b") 'magit-go-backward) + (define-key map (kbd "C-c C-f") 'magit-go-forward) + (define-key map (kbd "SPC") 'scroll-up) + (define-key map (kbd "DEL") 'scroll-down) + (define-key map (kbd "j") 'magit-jump-to-diffstats) + map) + "Keymap for `magit-commit-mode'.") + +(defvar magit-status-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map magit-mode-map) + (define-key map (kbd "s") 'magit-stage-item) + (define-key map (kbd "u") 'magit-unstage-item) + (define-key map (kbd "i") 'magit-ignore-item) + (define-key map (kbd "I") 'magit-ignore-item-locally) + (define-key map (kbd "j") 'magit-section-jump-map) + (define-key map (kbd ".") 'magit-mark-item) + (define-key map (kbd "=") 'magit-diff-with-mark) + (define-key map (kbd "k") 'magit-discard-item) + (define-key map (kbd "C") 'magit-commit-add-log) + map) + "Keymap for `magit-status-mode'.") + +(eval-after-load 'dired-x + '(define-key magit-status-mode-map [remap dired-jump] 'magit-dired-jump)) + +(defvar magit-log-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map magit-mode-map) + (define-key map (kbd ".") 'magit-mark-item) + (define-key map (kbd "=") 'magit-diff-with-mark) + (define-key map (kbd "e") 'magit-log-show-more-entries) + (define-key map (kbd "h") 'magit-log-toggle-margin) + map) + "Keymap for `magit-log-mode'.") + +(defvar magit-cherry-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map magit-mode-map) + map) + "Keymap for `magit-cherry-mode'.") + +(defvar magit-reflog-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map magit-log-mode-map) + map) + "Keymap for `magit-reflog-mode'.") + +(defvar magit-diff-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map magit-mode-map) + (define-key map (kbd "C-c C-b") 'magit-go-backward) + (define-key map (kbd "C-c C-f") 'magit-go-forward) + (define-key map (kbd "SPC") 'scroll-up) + (define-key map (kbd "DEL") 'scroll-down) + (define-key map (kbd "j") 'magit-jump-to-diffstats) + map) + "Keymap for `magit-diff-mode'.") + +(defvar magit-wazzup-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map magit-mode-map) + (define-key map (kbd ".") 'magit-mark-item) + (define-key map (kbd "=") 'magit-diff-with-mark) + (define-key map (kbd "i") 'magit-ignore-item) + map) + "Keymap for `magit-wazzup-mode'.") + +(defvar magit-branch-manager-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map magit-mode-map) + (define-key map (kbd "c") 'magit-create-branch) + (define-key map (kbd "a") 'magit-add-remote) + (define-key map (kbd "r") 'magit-rename-item) + (define-key map (kbd "k") 'magit-discard-item) + (define-key map (kbd "T") 'magit-change-what-branch-tracks) + map) + "Keymap for `magit-branch-manager-mode'.") + +(defvar magit-process-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map magit-mode-map) + map) + "Keymap for `magit-process-mode'.") + +(defvar magit-section-jump-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "z") 'magit-jump-to-stashes) + (define-key map (kbd "n") 'magit-jump-to-untracked) + (define-key map (kbd "u") 'magit-jump-to-unstaged) + (define-key map (kbd "s") 'magit-jump-to-staged) + (define-key map (kbd "f") 'magit-jump-to-unpulled) + (define-key map (kbd "p") 'magit-jump-to-unpushed) + (define-key map (kbd "r") 'magit-jump-to-pending) + map) + "Submap for jumping to sections in `magit-status-mode'.") +(fset 'magit-section-jump-map magit-section-jump-map) + +(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-item t] + ["Stage all" magit-stage-all t] + ["Unstage" magit-unstage-item t] + ["Unstage all" magit-unstage-all t] + ["Commit" magit-key-mode-popup-committing 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" + ["Short Log" magit-log t] + ["Long Log" magit-log-long t] + ["Reflog" magit-reflog t] + ["Extended..." magit-key-mode-popup-logging t]) + "---" + ["Cherry pick" magit-cherry-pick-item t] + ["Apply" magit-apply-item t] + ["Revert" magit-revert-item t] + "---" + ["Ignore" magit-ignore-item t] + ["Ignore locally" magit-ignore-item-locally t] + ["Discard" magit-discard-item t] + ["Reset head" magit-reset-head t] + ["Reset working tree" magit-reset-working-tree t] + ["Stash" magit-stash t] + ["Snapshot" magit-stash-snapshot t] + "---" + ["Branch..." magit-checkout t] + ["Merge" magit-merge t] + ["Interactive resolve" magit-interactive-resolve t] + ["Rebase" magit-rebase-step t] + ("Rewrite" + ["Start" magit-rewrite-start t] + ["Stop" magit-rewrite-stop t] + ["Finish" magit-rewrite-finish t] + ["Abort" magit-rewrite-abort t] + ["Set used" magit-rewrite-set-used t] + ["Set unused" magit-rewrite-set-unused t]) + "---" + ["Push" magit-push t] + ["Pull" magit-pull t] + ["Remote update" magit-remote-update t] + ("Submodule" + ["Submodule update" magit-submodule-update t] + ["Submodule update and init" magit-submodule-update-init t] + ["Submodule init" magit-submodule-init t] + ["Submodule sync" magit-submodule-sync t]) + "---" + ("Extensions") + "---" + ["Display Git output" magit-process t] + ["Quit Magit" magit-mode-quit-window t])) + + +;;; Utilities (1) +;;;; Minibuffer Input + +(defun magit-ido-completing-read + (prompt choices &optional predicate require-match initial-input hist def) + "ido-based completing-read almost-replacement." + (require 'ido) + (let ((reply (ido-completing-read + prompt + (if (consp (car choices)) + (mapcar #'car choices) + choices) + predicate require-match initial-input hist def))) + (or (and (consp (car choices)) + (cdr (assoc reply choices))) + reply))) + +(defun magit-builtin-completing-read + (prompt choices &optional predicate require-match initial-input hist def) + "Magit wrapper for standard `completing-read' function." + (let ((reply (completing-read + (if (and def (> (length prompt) 2) + (string-equal ": " (substring prompt -2))) + (format "%s (default %s): " (substring prompt 0 -2) def) + prompt) + choices predicate require-match initial-input hist def))) + (if (string= reply "") + (if require-match + (user-error "Nothing selected") + nil) + reply))) + +(defun magit-completing-read + (prompt collection &optional predicate require-match initial-input hist def) + "Call function in `magit-completing-read-function' to read user input. + +Read `completing-read' documentation for the meaning of the argument." + (funcall magit-completing-read-function + (concat prompt ": ") collection predicate + require-match initial-input hist def)) + +(defvar magit-gpg-secret-key-hist nil) + +(defun magit-read-gpg-secret-key (prompt) + (let ((keys (mapcar + (lambda (key) + (list (epg-sub-key-id (car (epg-key-sub-key-list key))) + (let ((id-obj (car (epg-key-user-id-list key))) + (id-str nil)) + (when id-obj + (setq id-str (epg-user-id-string id-obj)) + (if (stringp id-str) + id-str + (epg-decode-dn id-obj)))))) + (epg-list-keys (epg-make-context epa-protocol) nil t)))) + (magit-completing-read prompt keys nil nil nil 'magit-gpg-secret-key-hist + (car (or magit-gpg-secret-key-hist keys))))) + +;;;; Various Utilities + +(defmacro magit-bind-match-strings (varlist &rest body) + (declare (indent 1)) + (let ((i 0)) + `(let ,(mapcar (lambda (var) + (list var (list 'match-string (cl-incf i)))) + varlist) + ,@body))) + +(defun magit-file-line (file) + "Return the first line of FILE as a string." + (when (file-regular-p file) + (with-temp-buffer + (insert-file-contents file) + (buffer-substring-no-properties (point-min) + (line-end-position))))) + +(defun magit-file-lines (file &optional keep-empty-lines) + "Return a list of strings containing one element per line in FILE. +Unless optional argument KEEP-EMPTY-LINES is t, trim all empty lines." + (when (file-regular-p file) + (with-temp-buffer + (insert-file-contents file) + (split-string (buffer-string) "\n" (not keep-empty-lines))))) + +(defvar-local magit-file-name () + "Name of file the buffer shows a different version of.") + +(defun magit-buffer-file-name (&optional relative) + (let* ((topdir (magit-get-top-dir)) + (filename (or buffer-file-name + (when (buffer-base-buffer) + (with-current-buffer (buffer-base-buffer) + buffer-file-name)) + (when magit-file-name + (expand-file-name magit-file-name topdir))))) + (when filename + (setq filename (file-truename filename)) + (if relative + (file-relative-name filename topdir) + filename)))) + +(defun magit-format-duration (duration spec width) + (cl-destructuring-bind (char unit units weight) + (car spec) + (let ((cnt (round (/ duration weight 1.0)))) + (if (or (not (cdr spec)) + (>= (/ duration weight) 1)) + (if (= width 1) + (format "%3i%c" cnt char) + (format (format "%%3i %%-%is" width) cnt + (if (= cnt 1) unit units))) + (magit-format-duration duration (cdr spec) width))))) + +(defun magit-flatten-onelevel (list) + (cl-mapcan (lambda (elt) + (cond ((consp elt) (copy-sequence elt)) + (elt (list elt)))) + list)) + +(defun magit-insert (string face &rest args) + (if magit-use-overlays + (let ((start (point))) + (insert string) + (let ((ov (make-overlay start (point) nil t))) + (overlay-put ov 'face face) + ;; (overlay-put ov 'priority 10) + (overlay-put ov 'evaporate t))) + (insert (propertize string 'face face))) + (apply #'insert args)) + +(defun magit-put-face-property (start end face) + (if magit-use-overlays + (let ((ov (make-overlay start end nil t))) + (overlay-put ov 'face face) + ;; (overlay-put ov 'priority 10) + (overlay-put ov 'evaporate t)) + (put-text-property start end 'face face))) + +;;;; Buffer Margins + +(defun magit-set-buffer-margin (width enable) + (let ((window (get-buffer-window))) + (when window + (with-selected-window window + (set-window-margins nil (car (window-margins)) (if enable width 0)) + (let ((fn (apply-partially + (lambda (width) + (let ((window (get-buffer-window))) + (when window + (with-selected-window window + (set-window-margins nil (car (window-margins)) + width))))) + width))) + (if enable + (add-hook 'window-configuration-change-hook fn nil t) + (remove-hook 'window-configuration-change-hook fn t))))))) + +(defun magit-make-margin-overlay (&rest strings) + (let ((o (make-overlay (point) (line-end-position) nil t))) + (overlay-put o 'evaporate t) + (overlay-put o 'before-string + (propertize "o" 'display + (list '(margin right-margin) + (apply #'concat strings)))))) + +(defvar-local magit-log-margin-timeunit-width nil) + +(defun magit-log-margin-set-timeunit-width () + (cl-destructuring-bind (width characterp duration-spec) + magit-log-margin-spec + (setq magit-log-margin-timeunit-width + (if characterp + 1 + (apply 'max (mapcar (lambda (e) + (max (length (nth 1 e)) + (length (nth 2 e)))) + (symbol-value duration-spec))))))) + +;;;; Emacsclient Support + +(defmacro magit-with-emacsclient (server-window &rest body) + "Arrange for Git to use Emacsclient as \"the git editor\". + +Git processes that use \"the editor\" have to be asynchronous. +The use of this macro ensures that such processes inside BODY use +Emacsclient as \"the editor\" by setting the environment variable +$GIT_EDITOR accordingly around calls to Git and starting the +server if necessary." + (declare (indent 1)) + `(let* ((process-environment process-environment) + (magit-process-popup-time -1)) + ;; Make sure the client is usable. + (magit-assert-emacsclient "use `magit-with-emacsclient'") + ;; Make sure server-use-tcp's value is valid. + (unless (featurep 'make-network-process '(:family local)) + (setq server-use-tcp t)) + ;; Make sure the server is running. + (unless server-process + (when (server-running-p server-name) + (setq server-name (format "server%s" (emacs-pid))) + (when (server-running-p server-name) + (server-force-delete server-name))) + (server-start)) + ;; Tell Git to use the client. + (setenv "GIT_EDITOR" + (concat magit-emacsclient-executable + ;; Tell the client where the server file is. + (and (not server-use-tcp) + (concat " --socket-name=" + (expand-file-name server-name + server-socket-dir))))) + (when server-use-tcp + (setenv "EMACS_SERVER_FILE" + (expand-file-name server-name server-auth-dir))) + ;; As last resort fallback to a new Emacs instance. + (setenv "ALTERNATE_EDITOR" + (expand-file-name invocation-name invocation-directory)) + ;; Git has to be called asynchronously in BODY or we create a + ;; dead lock. By the time Emacsclient is called the dynamic + ;; binding is no longer in effect and our primitives don't + ;; support callbacks. Temporarily set the default value and + ;; restore the old value using a timer. + (let ((window ,server-window)) + (unless (equal window server-window) + (run-at-time "1 sec" nil + (apply-partially (lambda (value) + (setq server-window value)) + server-window)) + (setq-default server-window window))) + ,@body)) + +(defun magit-use-emacsclient-p () + (and magit-emacsclient-executable + (not (tramp-tramp-file-p default-directory)))) + +(defun magit-assert-emacsclient (action) + (unless magit-emacsclient-executable + (user-error "Cannot %s when `magit-emacsclient-executable' is nil" action)) + (when (tramp-tramp-file-p default-directory) + (user-error "Cannot %s when accessing repository using tramp" action))) + +;;;; Git Config + +(defun magit-get (&rest keys) + "Return the value of Git config entry specified by KEYS." + (magit-git-string "config" (mapconcat 'identity keys "."))) + +(defun magit-get-all (&rest keys) + "Return all values of the Git config entry specified by KEYS." + (magit-git-lines "config" "--get-all" (mapconcat 'identity keys "."))) + +(defun magit-get-boolean (&rest keys) + "Return the boolean value of Git config entry specified by KEYS." + (magit-git-true "config" "--bool" (mapconcat 'identity keys "."))) + +(defun magit-set (val &rest keys) + "Set Git config settings specified by KEYS to VAL." + (if val + (magit-git-string "config" (mapconcat 'identity keys ".") val) + (magit-git-string "config" "--unset" (mapconcat 'identity keys ".")))) + +;;;; Git Low-Level + +(defun magit-git-repo-p (dir) + (file-exists-p (expand-file-name ".git" dir))) + +(defun magit-git-dir (&optional path) + "Return absolute path to the GIT_DIR for the current repository. +If optional PATH is non-nil it has to be a path relative to the +GIT_DIR and its absolute path is returned" + (let ((gitdir (magit-git-string "rev-parse" "--git-dir"))) + (when gitdir + (setq gitdir (file-name-as-directory + (magit-expand-git-file-name gitdir))) + (if path + (expand-file-name (convert-standard-filename path) gitdir) + gitdir)))) + +(defun magit-no-commit-p () + "Return non-nil if there is no commit in the current git repository." + (not (magit-git-string "rev-list" "-1" "HEAD"))) + +(defun magit-get-top-dir (&optional directory) + "Return the top directory for the current repository. + +Determine the repository which contains `default-directory' in +either its work tree or git control directory and return its top +directory. If there is no top directory, because the repository +is bare, return the control directory instead. + +If optional DIRECTORY is non-nil then return the top directory of +the repository that contains that instead. DIRECTORY has to be +an existing directory." + (setq directory (if directory + (file-name-as-directory + (expand-file-name directory)) + default-directory)) + (unless (file-directory-p directory) + (error "%s isn't an existing directory" directory)) + (let* ((default-directory directory) + (top (magit-git-string "rev-parse" "--show-toplevel"))) + (if top + (file-name-as-directory (magit-expand-git-file-name top)) + (let ((gitdir (magit-git-dir))) + (when gitdir + (if (magit-bare-repo-p) + gitdir + (file-name-directory (directory-file-name gitdir)))))))) + +(defun magit-expand-git-file-name (filename) + (when (tramp-tramp-file-p default-directory) + (setq filename (file-relative-name filename + (with-parsed-tramp-file-name + default-directory nil + localname)))) + (expand-file-name filename)) + +(defun magit-file-relative-name (file) + "Return the path of FILE relative to the repository root. +If FILE isn't inside a Git repository then return nil." + (setq file (file-truename file)) + (let ((topdir (magit-get-top-dir (file-name-directory file)))) + (and topdir (substring file (length topdir))))) + +(defun magit-bare-repo-p () + "Return t if the current repository is bare." + (magit-git-true "rev-parse" "--is-bare-repository")) + +(defun magit-get-ref (ref) + (magit-git-string "symbolic-ref" "-q" ref)) + +(defun magit-get-current-branch () + (let ((head (magit-get-ref "HEAD"))) + (when (and head (string-match "^refs/heads/" head)) + (substring head 11)))) + +(defun magit-get-remote/branch (&optional branch verify) + "Return the remote-tracking branch of BRANCH used for pulling. +Return a string of the form \"REMOTE/BRANCH\". + +If optional BRANCH is nil return the remote-tracking branch of +the current branch. If optional VERIFY is non-nil verify that +the remote branch exists; else return nil." + (save-match-data + (let (remote remote-branch remote/branch) + (and (or branch (setq branch (magit-get-current-branch))) + (setq remote (magit-get "branch" branch "remote")) + (setq remote-branch (magit-get "branch" branch "merge")) + (string-match "^refs/heads/\\(.+\\)" remote-branch) + (setq remote/branch + (concat remote "/" (match-string 1 remote-branch))) + (or (not verify) + (magit-git-success "rev-parse" "--verify" remote/branch)) + remote/branch)))) + +(defun magit-get-tracked-branch (&optional branch qualified pretty) + "Return the name of the tracking branch the local branch name BRANCH. + +If optional QUALIFIED is non-nil return the full branch path, +otherwise try to shorten it to a name (which may fail). If +optional PRETTY is non-nil additionally format the branch name +according to option `magit-remote-ref-format'." + (unless branch + (setq branch (magit-get-current-branch))) + (when branch + (let ((remote (magit-get "branch" branch "remote")) + (merge (magit-get "branch" branch "merge"))) + (when (and (not merge) + (not (equal remote "."))) + (setq merge branch)) + (when (and remote merge) + (if (string= remote ".") + (cond (qualified merge) + ((string-match "^refs/heads/" merge) + (substring merge 11)) + ((string-match "^refs/" merge) + merge)) + (let* ((fetch (mapcar (lambda (f) (split-string f "[+:]" t)) + (magit-get-all "remote" remote "fetch"))) + (match (cadr (assoc merge fetch)))) + (unless match + (let* ((prefix (nreverse (split-string merge "/"))) + (unique (list (car prefix)))) + (setq prefix (cdr prefix)) + (setq fetch + (cl-mapcan + (lambda (f) + (cl-destructuring-bind (from to) f + (setq from (nreverse (split-string from "/"))) + (when (equal (car from) "*") + (list (list (cdr from) to))))) + fetch)) + (while (and prefix (not match)) + (if (setq match (cadr (assoc prefix fetch))) + (setq match (concat (substring match 0 -1) + (mapconcat 'identity unique "/"))) + (push (car prefix) unique) + (setq prefix (cdr prefix)))))) + (cond ((not match) nil) + (qualified match) + ((string-match "^refs/remotes/" match) + (if pretty + (magit-format-ref match) + (substring match 13))) + (t match)))))))) + +(defun magit-get-previous-branch () + "Return the refname of the previously checked out branch. +Return nil if the previously checked out branch no longer exists." + (magit-name-rev (magit-git-string "rev-parse" "--verify" "@{-1}"))) + +(defun magit-get-current-tag (&optional with-distance-p) + "Return the closest tag reachable from \"HEAD\". + +If optional WITH-DISTANCE-P is non-nil then return (TAG COMMITS), +if it is `dirty' return (TAG COMMIT DIRTY). COMMITS is the number +of commits in \"HEAD\" but not in TAG and DIRTY is t if there are +uncommitted changes, nil otherwise." + (let ((tag (magit-git-string "describe" "--long" "--tags" + (and (eq with-distance-p 'dirty) "--dirty")))) + (save-match-data + (when tag + (string-match + "\\(.+\\)-\\(?:0[0-9]*\\|\\([0-9]+\\)\\)-g[0-9a-z]+\\(-dirty\\)?$" tag) + (if with-distance-p + (list (match-string 1 tag) + (string-to-number (or (match-string 2 tag) "0")) + (and (match-string 3 tag) t)) + (match-string 1 tag)))))) + +(defun magit-get-next-tag (&optional with-distance-p) + "Return the closest tag from which \"HEAD\" is reachable. + +If no such tag can be found or if the distance is 0 (in which +case it is the current tag, not the next) return nil instead. + +If optional WITH-DISTANCE-P is non-nil then return (TAG COMMITS) +where COMMITS is the number of commits in TAG but not in \"HEAD\"." + (let ((rev (magit-git-string "describe" "--contains" "HEAD"))) + (save-match-data + (when (and rev (string-match "^[^^~]+" rev)) + (let ((tag (match-string 0 rev))) + (unless (equal tag (magit-get-current-tag)) + (if with-distance-p + (list tag (car (magit-rev-diff-count tag "HEAD"))) + tag))))))) + +(defun magit-get-remote (branch) + "Return the name of the remote for BRANCH. +If branch is nil or it has no remote, but a remote named +\"origin\" exists, return that. Otherwise, return nil." + (let ((remote (or (and branch (magit-get "branch" branch "remote")) + (and (magit-get "remote" "origin" "url") "origin")))) + (unless (string= remote "") + remote))) + +(defun magit-get-current-remote () + "Return the name of the remote for the current branch. +If there is no current branch, or no remote for that branch, +but a remote named \"origin\" is configured, return that. +Otherwise, return nil." + (magit-get-remote (magit-get-current-branch))) + +(defun magit-ref-exists-p (ref) + (magit-git-success "show-ref" "--verify" ref)) + +(defun magit-rev-parse (&rest args) + "Execute `git rev-parse ARGS', returning first line of output. +If there is no output return nil." + (apply #'magit-git-string "rev-parse" args)) + +(defun magit-ref-ambiguous-p (ref) + "Return whether or not REF is ambiguous." + ;; An ambiguous ref does not cause `git rev-parse --abbrev-ref' + ;; to exits with a non-zero status. But there is nothing on + ;; stdout in that case. + (not (magit-git-string "rev-parse" "--abbrev-ref" ref))) + +(defun magit-rev-diff-count (a b) + "Return the commits in A but not B and vice versa. +Return a list of two integers: (A>B B>A)." + (mapcar 'string-to-number + (split-string (magit-git-string "rev-list" + "--count" "--left-right" + (concat a "..." b)) + "\t"))) + +(defun magit-name-rev (rev &optional no-trim) + "Return a human-readable name for REV. +Unlike `git name-rev', this will remove \"tags/\" and \"remotes/\" +prefixes if that can be done unambiguously (unless optional arg +NO-TRIM is non-nil). In addition, it will filter out revs +involving HEAD." + (when rev + (let ((name (magit-git-string "name-rev" "--no-undefined" "--name-only" rev))) + ;; There doesn't seem to be a way of filtering HEAD out from name-rev, + ;; so we have to do it manually. + ;; HEAD-based names are too transient to allow. + (when (and (stringp name) + (string-match "^\\(.*\\" name)) + (setq name (magit-rev-parse rev))))) + (setq rev (or name rev)) + (when (string-match "^\\(?:tags\\|remotes\\)/\\(.*\\)" rev) + (let ((plain-name (match-string 1 rev))) + (unless (or no-trim (magit-ref-ambiguous-p plain-name)) + (setq rev plain-name)))) + rev))) + +(defun magit-file-uptodate-p (file) + (magit-git-success "diff" "--quiet" "--" file)) + +(defun magit-anything-staged-p () + (magit-git-failure "diff" "--quiet" "--cached")) + +(defun magit-anything-unstaged-p () + (magit-git-failure "diff" "--quiet")) + +(defun magit-anything-modified-p () + (or (magit-anything-staged-p) + (magit-anything-unstaged-p))) + +(defun magit-commit-parents (commit) + (cdr (split-string (magit-git-string "rev-list" "-1" "--parents" commit)))) + +(defun magit-assert-one-parent (commit command) + (when (> (length (magit-commit-parents commit)) 1) + (user-error "Cannot %s a merge commit" command))) + +(defun magit-decode-git-path (path) + (if (eq (aref path 0) ?\") + (string-as-multibyte (read path)) + path)) + +(defun magit-abbrev-length () + (string-to-number (or (magit-get "core.abbrev") "7"))) + +(defun magit-abbrev-arg () + (format "--abbrev=%d" (magit-abbrev-length))) + +;;;; Git Revisions + +(defvar magit-uninteresting-refs + '("^refs/stash$" + "^refs/remotes/[^/]+/HEAD$" + "^refs/remotes/[^/]+/top-bases$" + "^refs/top-bases$")) + +(cl-defun magit-list-interesting-refs (&optional uninteresting + (refs nil srefs)) + (cl-loop for ref in (if srefs + refs + (mapcar (lambda (l) + (cadr (split-string l " "))) + (magit-git-lines "show-ref"))) + with label + unless (or (cl-loop for i in + (cl-typecase uninteresting + (null magit-uninteresting-refs) + (list uninteresting) + (string (cons (format "^refs/heads/%s$" + uninteresting) + magit-uninteresting-refs))) + thereis (string-match i ref)) + (not (setq label (magit-format-ref ref)))) + collect (cons label ref))) + +(defun magit-format-ref (ref) + (cond ((string-match "refs/heads/\\(.*\\)" ref) + (match-string 1 ref)) + ((string-match "refs/tags/\\(.*\\)" ref) + (format (if (eq magit-remote-ref-format 'branch-then-remote) + "%s (tag)" + "%s") + (match-string 1 ref))) + ((string-match "refs/remotes/\\([^/]+\\)/\\(.+\\)" ref) + (if (eq magit-remote-ref-format 'branch-then-remote) + (format "%s (%s)" + (match-string 2 ref) + (match-string 1 ref)) + (substring ref 13))) + (t ref))) + +(defvar magit-read-file-hist nil) + +(defun magit-read-file-from-rev (revision &optional default) + (unless revision + (setq revision "HEAD")) + (let ((default-directory (magit-get-top-dir))) + (magit-completing-read + (format "Retrieve file from %s" revision) + (magit-git-lines "ls-tree" "-r" "-t" "--name-only" revision) + nil 'require-match + nil 'magit-read-file-hist + (or default (magit-buffer-file-name t))))) + +(defun magit-read-file-trace (ignored) + (let ((file (magit-read-file-from-rev "HEAD")) + (trace (read-string "Trace: "))) + (if (string-match + "^\\(/.+/\\|:[^:]+\\|[0-9]+,[-+]?[0-9]+\\)\\(:\\)?$" trace) + (concat trace (or (match-string 2 trace) ":") file) + (user-error "Trace is invalid, see man git-log")))) + +(defvar magit-read-rev-history nil + "The history of inputs to `magit-read-rev' and `magit-read-tag'.") + +(defun magit-read-tag (prompt &optional require-match) + (magit-completing-read prompt (magit-git-lines "tag") nil + require-match nil 'magit-read-rev-history)) + +(defun magit-read-rev (prompt &optional default uninteresting noselection) + (let* ((interesting-refs + (mapcar (lambda (elt) + (setcdr elt (replace-regexp-in-string + "^refs/heads/" "" (cdr elt))) + elt) + (magit-list-interesting-refs uninteresting))) + (reply (magit-completing-read prompt interesting-refs nil nil nil + 'magit-read-rev-history default)) + (rev (or (cdr (assoc reply interesting-refs)) reply))) + (when (equal rev ".") + (setq rev magit-marked-commit)) + (unless (or rev noselection) + (user-error "No rev selected")) + rev)) + +(defun magit-read-rev-with-default (prompt) + (magit-read-rev prompt + (let ((branch (or (magit-guess-branch) "HEAD"))) + (when branch + (if (string-match "^refs/\\(.*\\)" branch) + (match-string 1 branch) + branch))))) + +(defun magit-read-rev-range (op &optional def-beg def-end) + (let ((beg (magit-read-rev (format "%s range or start" op) def-beg))) + (save-match-data + (if (string-match "^\\(.+\\)\\.\\.\\(.+\\)$" beg) + (match-string 0 beg) + (let ((end (magit-read-rev (format "%s end" op) def-end nil t))) + (if end (concat beg ".." end) beg)))))) + +(defun magit-read-stash (prompt) + (let ((n (read-number prompt 0)) + (l (1- (length (magit-git-lines "stash" "list"))))) + (if (> n l) + (user-error "No stash older than stash@{%i}" l) + (format "stash@{%i}" n)))) + +(defun magit-read-remote (prompt &optional default require-match) + (magit-completing-read prompt (magit-git-lines "remote") + nil require-match nil nil + (or default (magit-guess-remote)))) + +(defun magit-read-remote-branch (prompt remote &optional default) + (let ((branch (magit-completing-read + prompt + (cl-mapcan + (lambda (b) + (and (not (string-match " -> " b)) + (string-match (format "^ *%s/\\(.*\\)$" + (regexp-quote remote)) b) + (list (match-string 1 b)))) + (magit-git-lines "branch" "-r")) + nil nil nil nil default))) + (unless (string= branch "") + branch))) + +(defun magit-format-ref-label (ref) + (cl-destructuring-bind (re face fn) + (cl-find-if (lambda (ns) + (string-match (car ns) ref)) + magit-refs-namespaces) + (if fn + (funcall fn ref face) + (propertize (or (match-string 1 ref) ref) 'face face)))) + +(defun magit-format-ref-labels (string) + (save-match-data + (mapconcat 'magit-format-ref-label + (mapcar 'cdr + (magit-list-interesting-refs + nil (split-string string "\\(tag: \\|[(), ]\\)" t))) + " "))) + +(defun magit-insert-ref-labels (string) + (save-match-data + (dolist (ref (split-string string "\\(tag: \\|[(), ]\\)" t) " ") + (cl-destructuring-bind (re face fn) + (cl-find-if (lambda (elt) (string-match (car elt) ref)) + magit-refs-namespaces) + (if fn + (let ((text (funcall fn ref face))) + (magit-insert text (get-text-property 1 'face text) ?\s)) + (magit-insert (or (match-string 1 ref) ref) face ?\s)))))) + +(defun magit-format-rev-summary (rev) + (let ((s (magit-git-string "log" "-1" + (concat "--pretty=format:%h %s") rev))) + (when s + (string-match " " s) + (put-text-property 0 (match-beginning 0) 'face 'magit-log-sha1 s) + s))) + +;;; Magit Api +;;;; Section Api +;;;;; Section Core + +(cl-defstruct magit-section + type info + beginning content-beginning end + hidden needs-refresh-on-show highlight + diff-status diff-file2 diff-range + process + parent children) + +(defvar-local magit-root-section nil + "The root section in the current buffer. +All other sections are descendants of this section. The value +of this variable is set by `magit-with-section' and you should +never modify it.") +(put 'magit-root-section 'permanent-local t) + +;;;;; Section Creation + +(defvar magit-with-section--parent nil + "For use by `magit-with-section' only.") + +(defvar magit-with-section--oldroot nil + "For use by `magit-with-section' only.") + +(defmacro magit-with-section (arglist &rest body) + "\n\n(fn (NAME TYPE &optional INFO HEADING NOHIGHLIGHT COLLAPSE) &rest ARGS)" + (declare (indent 1) (debug ((form form &optional form form form) body))) + (let ((s (car arglist))) + `(let ((,s (make-magit-section + :type ',(nth 1 arglist) + :info ,(nth 2 arglist) + :highlight (not ,(nth 4 arglist)) + :beginning (point-marker) + :content-beginning (point-marker) + :parent magit-with-section--parent))) + (setf (magit-section-hidden ,s) + (let ((old (and magit-with-section--oldroot + (magit-find-section (magit-section-path ,s) + magit-with-section--oldroot)))) + (if old + (magit-section-hidden old) + ,(nth 5 arglist)))) + (let ((magit-with-section--parent ,s) + (magit-with-section--oldroot + (or magit-with-section--oldroot + (unless magit-with-section--parent + (prog1 magit-root-section + (setq magit-root-section ,s)))))) + ,@body) + (when ,s + (set-marker-insertion-type (magit-section-content-beginning ,s) t) + (let ((heading ,(nth 3 arglist))) + (when heading + (save-excursion + (goto-char (magit-section-beginning ,s)) + (insert + (if (string-match-p "\n$" heading) + (substring heading 0 -1) + (propertize + (let (c) + (if (and magit-show-child-count + (string-match-p ":$" heading) + (> (setq c (length (magit-section-children ,s))) 0)) + (format "%s (%s):" (substring heading 0 -1) c) + heading)) + 'face 'magit-section-title))) + (insert "\n")))) + (set-marker-insertion-type (magit-section-beginning ,s) t) + (goto-char (max (point) ; smaller if there is no content + (magit-section-content-beginning ,s))) + (setf (magit-section-end ,s) (point-marker)) + (save-excursion + (goto-char (magit-section-beginning ,s)) + (let ((end (magit-section-end ,s))) + (while (< (point) end) + (let ((next (or (next-single-property-change + (point) 'magit-section) + end))) + (unless (get-text-property (point) 'magit-section) + (put-text-property (point) next 'magit-section ,s)) + (goto-char next))))) + (if (eq ,s magit-root-section) + (magit-section-set-hidden magit-root-section nil) + (setf (magit-section-children (magit-section-parent ,s)) + (nconc (magit-section-children (magit-section-parent ,s)) + (list ,s))))) + ,s))) + +(defmacro magit-cmd-insert-section (arglist washer program &rest args) + "\n\n(fn (TYPE &optional HEADING) WASHER PROGRAM &rest ARGS)" + (declare (indent 2)) + `(magit-with-section (section ,(car arglist) + ',(car arglist) + ,(cadr arglist) t) + (apply #'process-file ,program nil (list t nil) nil + (magit-flatten-onelevel (list ,@args))) + (unless (eq (char-before) ?\n) + (insert "\n")) + (save-restriction + (narrow-to-region (magit-section-content-beginning section) (point)) + (goto-char (point-min)) + (funcall ,washer) + (goto-char (point-max))) + (let ((parent (magit-section-parent section)) + (head-beg (magit-section-beginning section)) + (body-beg (magit-section-content-beginning section))) + (if (= (point) body-beg) + (if (not parent) + (insert "(empty)\n") + (delete-region head-beg body-beg) + (setq section nil)) + (insert "\n"))))) + +(defmacro magit-git-insert-section (arglist washer &rest args) + "\n\n(fn (TYPE &optional HEADING) WASHER &rest ARGS)" + (declare (indent 2)) + `(magit-cmd-insert-section ,arglist + ,washer + magit-git-executable + magit-git-standard-options ,@args)) + +(defmacro magit-insert-line-section (arglist line) + "\n\n(fn (TYPE &optional INFO) line)" + (declare (indent 1)) + (let ((l (cl-gensym "line"))) + `(let ((,l (concat ,line "\n"))) + (when (string-match "^\\([^:]+\\):\\( \\)" ,l) + (setq ,l (replace-match + (make-string (max 1 (- magit-status-line-align-to + (length (match-string 1 ,l)))) + ?\s) + t t ,l 2))) + (magit-with-section (section ,(car arglist) ',(car arglist) ,l t) + (setf (magit-section-info section) ,(cadr arglist)))))) + +;;;;; Section Searching + +(defun magit-find-section (path top) + "Find the section at the path PATH in subsection of section TOP." + (if (null path) + top + (let ((secs (magit-section-children top))) + (while (and secs (not (equal (car path) + (magit-section-info (car secs))))) + (setq secs (cdr secs))) + (when (car secs) + (magit-find-section (cdr path) (car secs)))))) + +(defun magit-section-path (section) + "Return the path of SECTION." + (let ((parent (magit-section-parent section))) + (when parent + (append (magit-section-path parent) + (list (magit-section-info section)))))) + +(defun magit-find-section-after (pos) + "Find the first section that begins after POS." + (magit-find-section-after* pos (list magit-root-section))) + +(defun magit-find-section-after* (pos secs) + "Find the first section that begins after POS in the list SECS +\(including children of sections in SECS)." + (while (and secs + (<= (magit-section-beginning (car secs)) pos)) + (setq secs (if (magit-section-hidden (car secs)) + (cdr secs) + (append (magit-section-children (car secs)) + (cdr secs))))) + (car secs)) + +(defun magit-find-section-before (pos) + "Return the last section that begins before POS." + (let ((section (magit-find-section-at pos))) + (cl-do* ((current (or (magit-section-parent section) + section) + next) + (next (unless (magit-section-hidden current) + (magit-find-section-before* + pos (magit-section-children current))) + (unless (magit-section-hidden current) + (magit-find-section-before* + pos (magit-section-children current))))) + ((null next) current)))) + +(defun magit-find-section-before* (pos secs) + "Find the last section that begins before POS in the list SECS." + (let ((prev nil)) + (while (and secs + (< (magit-section-beginning (car secs)) pos)) + (setq prev (car secs)) + (setq secs (cdr secs))) + prev)) + +(defun magit-current-section () + "Return the Magit section at point." + (magit-find-section-at (point))) + +(defun magit-find-section-at (pos) + "Return the Magit section at POS." + (or (get-text-property pos 'magit-section) + magit-root-section)) + +;;;;; Section Jumping + +(defun magit-goto-next-section () + "Go to the next section." + (interactive) + (let ((next (magit-find-section-after (point)))) + (if next + (magit-goto-section next) + (message "No next section")))) + +(defun magit-goto-previous-section () + "Go to the previous section." + (interactive) + (if (eq (point) 1) + (message "No previous section") + (magit-goto-section (magit-find-section-before (point))))) + +(defun magit-goto-parent-section () + "Go to the parent section." + (interactive) + (let ((parent (magit-section-parent (magit-current-section)))) + (when parent + (goto-char (magit-section-beginning parent))))) + +(defun magit-goto-next-sibling-section () + "Go to the next sibling section." + (interactive) + (let* ((section (magit-current-section)) + (parent (magit-section-parent section)) + (next (and parent (magit-find-section-after* + (1- (magit-section-end section)) + (magit-section-children parent))))) + (if next + (magit-goto-section next) + (magit-goto-next-section)))) + +(defun magit-goto-previous-sibling-section () + "Go to the previous sibling section." + (interactive) + (let* ((section (magit-current-section)) + (parent (magit-section-parent section)) + (prev (and parent (magit-find-section-before* + (magit-section-beginning section) + (magit-section-children parent))))) + (if prev + (magit-goto-section prev) + (magit-goto-previous-section)))) + +(defun magit-goto-section (section) + (goto-char (magit-section-beginning section)) + (cond + ((and magit-log-auto-more + (eq (magit-section-type section) 'longer)) + (magit-log-show-more-entries) + (forward-line -1) + (magit-goto-next-section)) + ((and (eq (magit-section-type section) 'commit) + (derived-mode-p 'magit-log-mode) + (or (eq (car magit-refresh-args) 'oneline) + (get-buffer-window magit-commit-buffer-name))) + (magit-show-commit (magit-section-info section) t)))) + +(defun magit-goto-section-at-path (path) + "Go to the section described by PATH." + (let ((sec (magit-find-section path magit-root-section))) + (if sec + (goto-char (magit-section-beginning sec)) + (message "No such section")))) + +(defmacro magit-define-section-jumper (sym title) + "Define an interactive function to go to section SYM. +TITLE is the displayed title of the section." + (let ((fun (intern (format "magit-jump-to-%s" sym)))) + `(progn + (defun ,fun (&optional expand) ,(format "\ +Jump to section '%s'. +With a prefix argument also expand it." title) + (interactive "P") + (if (magit-goto-section-at-path '(,sym)) + (when expand + (with-local-quit + (if (eq magit-expand-staged-on-commit 'full) + (magit-show-level 4 nil) + (magit-expand-section))) + (recenter 0)) + (message ,(format "Section '%s' wasn't found" title)))) + (put ',fun 'definition-name ',sym)))) + +(magit-define-section-jumper stashes "Stashes") +(magit-define-section-jumper untracked "Untracked files") +(magit-define-section-jumper unstaged "Unstaged changes") +(magit-define-section-jumper staged "Staged changes") +(magit-define-section-jumper unpulled "Unpulled commits") +(magit-define-section-jumper unpushed "Unpushed commits") +(magit-define-section-jumper diffstats "Diffstats") + +;;;;; Section Hooks + +(defun magit-add-section-hook (hook function &optional at append local) + "Add to the value of section hook HOOK the function FUNCTION. + +Add FUNCTION at the beginning of the hook list unless optional +APPEND is non-nil, in which case FUNCTION is added at the end. +If FUNCTION already is a member then move it to the new location. + +If optional AT is non-nil and a member of the hook list, then add +FUNCTION next to that instead. Add before or after AT depending +on APPEND. If only FUNCTION is a member of the list, then leave +it where ever it already is. + +If optional LOCAL is non-nil, then modify the hook's buffer-local +value rather than its global value. This makes the hook local by +copying the default value. That copy is then modified. + +HOOK should be a symbol. If HOOK is void, it is first set to nil. +HOOK's value must not be a single hook function. FUNCTION should +be a function that takes no arguments and inserts one or multiple +sections at point, moving point forward. FUNCTION may choose not +to insert its section(s), when doing so would not make sense. It +should not be abused for other side-effects. To remove FUNCTION +again use `remove-hook'." + (or (boundp hook) (set hook nil)) + (or (default-boundp hook) (set-default hook nil)) + (let ((value (if local + (if (local-variable-p hook) + (symbol-value hook) + (unless (local-variable-if-set-p hook) + (make-local-variable hook)) + (copy-sequence (default-value hook))) + (default-value hook)))) + (if at + (when (setq at (member at value)) + (setq value (delq function value)) + (if append + (push function (cdr at)) + (push (car at) (cdr at)) + (setcar at function))) + (setq value (delq function value))) + (unless (member function value) + (setq value (if append + (append value (list function)) + (cons function value)))) + (if local + (set hook value) + (set-default hook value)))) + +;;;;; Section Utilities + +(defun magit-map-sections (function section) + "Apply FUNCTION to SECTION and recursively its subsections." + (funcall function section) + (mapc (apply-partially 'magit-map-sections function) + (magit-section-children section))) + +(defun magit-wash-sequence (function) + "Repeatedly call FUNCTION until it returns nil or eob is reached. +FUNCTION has to move point forward or return nil." + (while (and (not (eobp)) (funcall function)))) + +(defun magit-section-parent-info (section) + (setq section (magit-section-parent section)) + (when section (magit-section-info section))) + +(defun magit-section-siblings (section &optional direction) + (let ((parent (magit-section-parent section))) + (when parent + (let ((siblings (magit-section-children parent))) + (cl-ecase direction + (prev (member section (reverse siblings))) + (next (member section siblings)) + (nil siblings)))))) + +(defun magit-section-region-siblings (&optional key) + (let ((beg (magit-find-section-at (region-beginning))) + (end (magit-find-section-at (region-end)))) + (if (eq beg end) + (list (if key (funcall key beg) beg)) + (goto-char (region-end)) + (when (bolp) + (setq end (magit-find-section-at (1- (point))))) + (while (> (length (magit-section-path beg)) + (length (magit-section-path end))) + (setq beg (magit-section-parent beg))) + (while (> (length (magit-section-path end)) + (length (magit-section-path beg))) + (setq end (magit-section-parent end))) + (let* ((parent (magit-section-parent beg)) + (siblings (magit-section-children parent))) + (if (eq parent (magit-section-parent end)) + (mapcar (or key #'identity) + (cl-intersection (memq beg siblings) + (memq end (reverse siblings)))) + (user-error "Ambitious cross-section region")))))) + +(defun magit-diff-section-for-diffstat (section) + (let ((file (magit-section-info section))) + (cl-find-if (lambda (s) + (and (eq (magit-section-type s) 'diff) + (string-equal (magit-section-info s) file))) + (magit-section-children magit-root-section)))) + +;;;;; Section Visibility + +(defun magit-section-set-hidden (section hidden) + "Hide SECTION if HIDDEN is not nil, show it otherwise." + (setf (magit-section-hidden section) hidden) + (if (and (not hidden) + (magit-section-needs-refresh-on-show section)) + (magit-refresh) + (let ((inhibit-read-only t) + (beg (save-excursion + (goto-char (magit-section-beginning section)) + (forward-line) + (point))) + (end (magit-section-end section))) + (when (< beg end) + (put-text-property beg end 'invisible hidden))) + (unless hidden + (dolist (c (magit-section-children section)) + (magit-section-set-hidden c (magit-section-hidden c)))))) + +(defun magit-section-any-hidden (section) + "Return true if SECTION or any of its children is hidden." + (or (magit-section-hidden section) + (let ((kids (magit-section-children section))) + (while (and kids (not (magit-section-any-hidden (car kids)))) + (setq kids (cdr kids))) + kids))) + +(defun magit-section-collapse (section) + "Show SECTION and hide all its children." + (dolist (c (magit-section-children section)) + (setf (magit-section-hidden c) t)) + (magit-section-set-hidden section nil)) + +(defun magit-section-expand (section) + "Show SECTION and all its children." + (dolist (c (magit-section-children section)) + (setf (magit-section-hidden c) nil)) + (magit-section-set-hidden section nil)) + +(defun magit-section-expand-all-aux (section) + "Show recursively all SECTION's children." + (dolist (c (magit-section-children section)) + (setf (magit-section-hidden c) nil) + (magit-section-expand-all-aux c))) + +(defun magit-section-expand-all (section) + "Show SECTION and all its children." + (magit-section-expand-all-aux section) + (magit-section-set-hidden section nil)) + +(defun magit-section-hideshow (flag-or-func) + "Show or hide current section depending on FLAG-OR-FUNC. + +If FLAG-OR-FUNC is a function, it will be ran on current section. +IF FLAG-OR-FUNC is a boolean, the section will be hidden if it is +true, shown otherwise." + (let ((section (magit-current-section))) + (when (magit-section-parent section) + (goto-char (magit-section-beginning section)) + (if (functionp flag-or-func) + (funcall flag-or-func section) + (magit-section-set-hidden section flag-or-func))))) + +(defun magit-show-section () + "Show current section." + (interactive) + (magit-section-hideshow nil)) + +(defun magit-hide-section () + "Hide current section." + (interactive) + (magit-section-hideshow t)) + +(defun magit-collapse-section () + "Hide all subsection of current section." + (interactive) + (magit-section-hideshow #'magit-section-collapse)) + +(defun magit-expand-section () + "Show all subsection of current section." + (interactive) + (magit-section-hideshow #'magit-section-expand)) + +(defun magit-toggle-file-section () + "Like `magit-toggle-section' but toggle at file granularity." + (interactive) + (when (eq (magit-section-type (magit-current-section)) 'hunk) + (magit-goto-parent-section)) + (magit-toggle-section)) + +(defun magit-toggle-section () + "Toggle hidden status of current section." + (interactive) + (magit-section-hideshow + (lambda (s) + (magit-section-set-hidden s (not (magit-section-hidden s)))))) + +(defun magit-expand-collapse-section () + "Toggle hidden status of subsections of current section." + (interactive) + (magit-section-hideshow + (lambda (s) + (cond ((magit-section-any-hidden s) + (magit-section-expand-all s)) + (t + (magit-section-collapse s)))))) + +(defun magit-cycle-section () + "Cycle between expanded, hidden and collapsed state for current section. + +Hidden: only the first line of the section is shown +Collapsed: only the first line of the subsection is shown +Expanded: everything is shown." + (interactive) + (magit-section-hideshow + (lambda (s) + (cond ((magit-section-hidden s) + (magit-section-collapse s)) + ((with-no-warnings + (cl-notany #'magit-section-hidden (magit-section-children s))) + (magit-section-set-hidden s t)) + (t + (magit-section-expand s)))))) + +(defun magit-section-lineage (section) + "Return list of parent, grand-parents... for SECTION." + (when section + (cons section (magit-section-lineage (magit-section-parent section))))) + +(defun magit-section-show-level (section level threshold path) + (magit-section-set-hidden section (>= level threshold)) + (when (and (< level threshold) + (not (magit-no-commit-p))) + (if path + (magit-section-show-level (car path) (1+ level) threshold (cdr path)) + (dolist (c (magit-section-children section)) + (magit-section-show-level c (1+ level) threshold nil))))) + +(defun magit-show-level (level all) + "Show section whose level is less than LEVEL, hide the others. +If ALL is non nil, do this in all sections, otherwise do it only +on ancestors and descendants of current section." + (if all + (magit-section-show-level magit-root-section 0 level nil) + (let ((path (reverse (magit-section-lineage (magit-current-section))))) + (magit-section-show-level (car path) 0 level (cdr path))))) + +(defun magit-show-only-files () + "Show section that are files, but not their subsection. + +Do this in on ancestors and descendants of current section." + (interactive) + (if (derived-mode-p 'magit-status-mode) + (call-interactively 'magit-show-level-2) + (call-interactively 'magit-show-level-1))) + +(defun magit-show-only-files-all () + "Show section that are files, but not their subsection. +Do this for all sections" + (interactive) + (if (derived-mode-p 'magit-status-mode) + (call-interactively 'magit-show-level-2-all) + (call-interactively 'magit-show-level-1-all))) + +(defmacro magit-define-level-shower-1 (level all) + "Define an interactive function to show function of level LEVEL. + +If ALL is non nil, this function will affect all section, +otherwise it will affect only ancestors and descendants of +current section." + (let ((fun (intern (format "magit-show-level-%s%s" + level (if all "-all" "")))) + (doc (format "Show sections on level %s." level))) + `(defun ,fun () + ,doc + (interactive) + (magit-show-level ,level ,all)))) + +(defmacro magit-define-level-shower (level) + "Define two interactive function to show function of level LEVEL. +One for all, one for current lineage." + `(progn + (magit-define-level-shower-1 ,level nil) + (magit-define-level-shower-1 ,level t))) + +(magit-define-level-shower 1) +(magit-define-level-shower 2) +(magit-define-level-shower 3) +(magit-define-level-shower 4) + +;;;;; Section Highlighting + +(defvar-local magit-highlighted-section nil) +(defvar-local magit-highlight-overlay nil) + +(defun magit-highlight-section () + "Highlight current section. +If its HIGHLIGHT slot is nil, then don't highlight it." + (let ((section (magit-current-section)) + (refinep (lambda () + (and magit-highlighted-section + (eq magit-diff-refine-hunk t) + (eq (magit-section-type magit-highlighted-section) + 'hunk))))) + (unless (eq section magit-highlighted-section) + (when (funcall refinep) + (magit-diff-unrefine-hunk magit-highlighted-section)) + (setq magit-highlighted-section section) + (unless magit-highlight-overlay + (overlay-put (setq magit-highlight-overlay (make-overlay 1 1)) + 'face magit-item-highlight-face)) + (cond ((and section (magit-section-highlight section)) + (when (funcall refinep) + (magit-diff-refine-hunk section)) + (move-overlay magit-highlight-overlay + (magit-section-beginning section) + (magit-section-end section) + (current-buffer))) + (t + (delete-overlay magit-highlight-overlay)))))) + +;;;;; Section Actions + +(defun magit-section-context-type (section) + (cons (magit-section-type section) + (let ((parent (magit-section-parent section))) + (when parent + (magit-section-context-type parent))))) + +(defun magit-section-match-1 (l1 l2) + (or (null l1) + (if (eq (car l1) '*) + (or (magit-section-match-1 (cdr l1) l2) + (and l2 + (magit-section-match-1 l1 (cdr l2)))) + (and l2 + (equal (car l1) (car l2)) + (magit-section-match-1 (cdr l1) (cdr l2)))))) + +(defun magit-section-match (condition &optional section) + (unless section + (setq section (magit-current-section))) + (cond ((eq condition t) t) + ((not section) nil) + ((listp condition) + (cl-find t condition :test + (lambda (_ condition) + (magit-section-match condition section)))) + (t + (magit-section-match-1 (if (symbolp condition) + (list condition) + (append condition nil)) + (magit-section-context-type section))))) + +(defmacro magit-section-case (slots &rest clauses) + (declare (indent 1)) + `(let* ((it (magit-current-section)) + ,@(mapcar + (lambda (slot) + `(,slot + (and it (,(intern (format "magit-section-%s" slot)) it)))) + slots)) + (cond ,@(mapcar (lambda (clause) + `((magit-section-match ',(car clause) it) + ,@(cdr clause))) + clauses)))) + +(defconst magit-section-action-success + (make-symbol "magit-section-action-success")) + +(defmacro magit-section-action (opname slots &rest clauses) + (declare (indent 2) (debug (sexp &rest (sexp body)))) + (let ((value (cl-gensym "value"))) + `(let ((,value + (or (run-hook-wrapped + ',(intern (format "magit-%s-hook" opname)) + (lambda (fn section) + (when (magit-section-match + (or (get fn 'magit-section-action-context) + (error "%s undefined for %s" + 'magit-section-action-context fn)) + section) + (funcall fn (magit-section-info section)))) + (magit-current-section)) + (magit-section-case ,slots + ,@clauses + (t (user-error + (if (magit-current-section) + ,(format "Cannot %s this section" opname) + ,(format "Nothing to %s here" opname)))))))) + (unless (eq ,value magit-section-action-success) + ,value)))) + +;;;; Process Api +;;;;; Process Commands + +(defun magit-process () + "Display Magit process buffer." + (interactive) + (let ((buf (magit-process-buffer))) + (if (buffer-live-p buf) + (pop-to-buffer buf) + (user-error "Process buffer doesn't exist")))) + +(defun magit-process-kill () + "Kill the process at point." + (interactive) + (magit-section-case (info) + (process (if (eq (process-status info) 'run) + (when (yes-or-no-p "Kill this process? ") + (kill-process info)) + (user-error "Process isn't running"))))) + +(defvar magit-git-command-history nil) + +;;;###autoload +(defun magit-git-command (args directory) + "Execute a Git subcommand asynchronously, displaying the output. +With a prefix argument run Git in the root of the current +repository. Non-interactively run Git in DIRECTORY with ARGS." + (interactive (magit-git-command-read-args)) + (require 'eshell) + (magit-mode-display-buffer (magit-process-buffer nil t) + 'magit-process-mode 'pop-to-buffer) + (goto-char (point-max)) + (let ((default-directory directory)) + (magit-run-git-async + (with-temp-buffer + (insert args) + (mapcar 'eval (eshell-parse-arguments (point-min) + (point-max))))))) + +(defun magit-git-command-topdir (args directory) + "Execute a Git subcommand asynchronously, displaying the output. +Run Git in the root of the current repository. +\n(fn)" ; arguments are for internal use + (interactive (magit-git-command-read-args t)) + (magit-git-command args directory)) + +(defun magit-git-command-read-args (&optional root) + (let ((dir (if (or root current-prefix-arg) + (or (magit-get-top-dir) + (user-error "Not inside a Git repository")) + default-directory))) + (list (read-string (format "Git subcommand (in %s): " + (abbreviate-file-name dir)) + nil 'magit-git-command-history) + dir))) + +;;;;; Process Mode + +(define-derived-mode magit-process-mode magit-mode "Magit Process" + "Mode for looking at git process output.") + +(defvar magit-process-buffer-name "*magit-process*" + "Name of buffer where output of processes is put.") + +(defun magit-process-buffer (&optional topdir create) + (or (magit-mode-get-buffer magit-process-buffer-name + 'magit-process-mode topdir) + (with-current-buffer (magit-mode-get-buffer-create + magit-process-buffer-name + 'magit-process-mode topdir) + (magit-process-mode) + (let* ((inhibit-read-only t) + (s (magit-with-section (section processbuf nil nil t) + (insert "\n")))) + (set-marker-insertion-type (magit-section-beginning s) nil) + (set-marker-insertion-type (magit-section-content-beginning s) nil) + (current-buffer))))) + +;;;;; Synchronous Processes + +(defun magit-git-exit-code (&rest args) + "Execute Git with ARGS, returning its exit code." + (apply #'process-file magit-git-executable nil nil nil + (append magit-git-standard-options + (magit-flatten-onelevel args)))) + +(defun magit-git-success (&rest args) + "Execute Git with ARGS, returning t if its exit code is 0." + (= (apply #'magit-git-exit-code args) 0)) + +(defun magit-git-failure (&rest args) + "Execute Git with ARGS, returning t if its exit code is 1." + (= (apply #'magit-git-exit-code args) 1)) + +(defun magit-git-string (&rest args) + "Execute Git with ARGS, returning the first line of its output. +If there is no output return nil. If the output begins with a +newline return an empty string." + (with-temp-buffer + (apply #'process-file magit-git-executable nil (list t nil) nil + (append magit-git-standard-options + (magit-flatten-onelevel args))) + (unless (= (point-min) (point-max)) + (goto-char (point-min)) + (buffer-substring-no-properties + (line-beginning-position) + (line-end-position))))) + +(defun magit-git-true (&rest args) + "Execute Git with ARGS, returning t if it prints \"true\". +Return t if the first (and usually only) output line is the +string \"true\", otherwise return nil." + (equal (apply #'magit-git-string args) "true")) + +(defun magit-git-false (&rest args) + "Execute Git with ARGS, returning t if it prints \"false\". +Return t if the first (and usually only) output line is the +string \"false\", otherwise return nil." + (equal (apply #'magit-git-string args) "false")) + +(defun magit-git-insert (&rest args) + "Execute Git with ARGS, inserting its output at point." + (apply #'process-file magit-git-executable nil (list t nil) nil + (append magit-git-standard-options + (magit-flatten-onelevel args)))) + +(defun magit-git-lines (&rest args) + "Execute Git with ARGS, returning its output as a list of lines. +Empty lines anywhere in the output are omitted." + (with-temp-buffer + (apply #'process-file magit-git-executable nil (list t nil) nil + (append magit-git-standard-options + (magit-flatten-onelevel args))) + (split-string (buffer-string) "\n" 'omit-nulls))) + +(defun magit-run-git (&rest args) + "Call Git synchronously in a separate process, and refresh. + +The arguments ARGS specify command line arguments. The first +level of ARGS is flattened, so each member of ARGS has to be a +string or a list of strings. + +Option `magit-git-executable' specifies which Git executable is +used. The arguments in option `magit-git-standard-options' are +prepended to ARGS. + +After Git returns, the current buffer (if it is a Magit buffer) +as well as the current repository's status buffer are refreshed. +Unmodified buffers visiting files that are tracked in the current +repository are reverted if `magit-auto-revert-mode' is active. + +Process output goes into a new section in a buffer specified by +variable `magit-process-buffer-name'." + (apply #'magit-call-git (magit-process-quote-arguments args)) + (magit-refresh)) + +(defun magit-call-git (&rest args) + "Call Git synchronously in a separate process. + +The arguments ARGS specify command line arguments. The first +level of ARGS is flattened, so each member of ARGS has to be a +string or a list of strings. + +Option `magit-git-executable' specifies which Git executable is +used. The arguments in option `magit-git-standard-options' are +prepended to ARGS. + +Process output goes into a new section in a buffer specified by +variable `magit-process-buffer-name'." + (apply #'magit-call-process magit-git-executable + (append magit-git-standard-options args))) + +(defun magit-call-process (program &rest args) + "Call PROGRAM synchronously in a separate process. + +The arguments ARGS specify command line arguments. The first +level of ARGS is flattened, so each member of ARGS has to be a +string or a list of strings. + +Process output goes into a new section in a buffer specified by +variable `magit-process-buffer-name'." + (setq args (magit-flatten-onelevel args)) + (cl-destructuring-bind (process-buf . section) + (magit-process-setup program args) + (magit-process-finish + (let ((inhibit-read-only t)) + (apply #'process-file program nil process-buf nil args)) + process-buf (current-buffer) default-directory section))) + +(defun magit-run-git-with-input (input &rest args) + "Call Git in a separate process. + +The first argument, INPUT, has to be a buffer or the name of an +existing buffer. The content of that buffer is used as the +process' standard input. + +The remaining arguments, ARGS, specify command line arguments. +The first level of ARGS is flattened, so each member of ARGS has +to be a string or a list of strings. + +Option `magit-git-executable' specifies which Git executable is +used. The arguments in option `magit-git-standard-options' are +prepended to ARGS. + +After Git returns, the current buffer (if it is a Magit buffer) +as well as the current repository's status buffer are refreshed. +Unmodified buffers visiting files that are tracked in the current +repository are reverted if `magit-auto-revert-mode' is active. + +This function actually starts a asynchronous process, but it then +waits for that process to return." + (apply #'magit-start-git input args) + (magit-process-wait) + (magit-refresh)) + +(defun magit-run-git-with-logfile (file &rest args) + "Call Git in a separate process and log its output. +And log the output to FILE. This function might have a +short halflive. See `magit-run-git' for more information." + (apply #'magit-start-git nil args) + (process-put magit-this-process 'logfile file) + (set-process-filter magit-this-process 'magit-process-logfile-filter) + (magit-process-wait) + (magit-refresh)) + +;;;;; Asynchronous Processes + +(defvar magit-this-process nil) + +(defun magit-run-git-async (&rest args) + "Start Git, prepare for refresh, and return the process object. + +If optional argument INPUT is non-nil, it has to be a buffer or +the name of an existing buffer. The content of that buffer is +used as the process' standard input. + +The remaining arguments, ARGS, specify command line arguments. +The first level of ARGS is flattened, so each member of ARGS has +to be a string or a list of strings. + +Display the command line arguments in the echo area. + +After Git returns some buffers are refreshed: the buffer that was +current when `magit-start-process' was called (if it is a Magit +buffer and still alive), as well as the respective Magit status +buffer. Unmodified buffers visiting files that are tracked in +the current repository are reverted if `magit-auto-revert-mode' +is active. + +See `magit-start-process' for more information." + (message "Running %s %s" magit-git-executable + (mapconcat 'identity (magit-flatten-onelevel args) " ")) + (apply #'magit-start-git nil args)) + +(defun magit-start-git (&optional input &rest args) + "Start Git, prepare for refresh, and return the process object. + +If optional argument INPUT is non-nil, it has to be a buffer or +the name of an existing buffer. The buffer content becomes the +processes standard input. + +The remaining arguments, ARGS, specify command line arguments. +The first level of ARGS is flattened, so each member of ARGS has +to be a string or a list of strings. + +After Git returns some buffers are refreshed: the buffer that was +current when `magit-start-process' was called (if it is a Magit +buffer and still alive), as well as the respective Magit status +buffer. Unmodified buffers visiting files that are tracked in +the current repository are reverted if `magit-auto-revert-mode' +is active. + +See `magit-start-process' for more information." + (apply #'magit-start-process magit-git-executable input + (append magit-git-standard-options + (magit-process-quote-arguments args)))) + +(defun magit-start-process (program &optional input &rest args) + "Start PROGRAM, prepare for refresh, and return the process object. + +If optional argument INPUT is non-nil, it has to be a buffer or +the name of an existing buffer. The buffer content becomes the +processes standard input. + +The remaining arguments, ARGS, specify command line arguments. +The first level of ARGS is flattened, so each member of ARGS has +to be a string or a list of strings. + +The process is started using `start-file-process' and then setup +to use the sentinel `magit-process-sentinel' and the filter +`magit-process-filter'. Information required by these functions +is stored in the process object. When this function returns the +process has not started to run yet so it is possible to override +the sentinel and filter. + +After the process returns, `magit-process-sentinel' refreshes the +buffer that was current when `magit-start-process' was called (if +it is a Magit buffer and still alive), as well as the respective +Magit status buffer. Unmodified buffers visiting files that are +tracked in the current repository are reverted if +`magit-auto-revert-mode' is active." + (setq args (magit-flatten-onelevel args)) + (cl-destructuring-bind (process-buf . section) + (magit-process-setup program args) + (let* ((process-connection-type + ;; Don't use a pty, because it would set icrnl + ;; which would modify the input (issue #20). + (and (not input) magit-process-connection-type)) + (process (apply 'start-file-process + (file-name-nondirectory program) + process-buf program args))) + (set-process-sentinel process #'magit-process-sentinel) + (set-process-filter process #'magit-process-filter) + (set-process-buffer process process-buf) + (process-put process 'section section) + (process-put process 'command-buf (current-buffer)) + (process-put process 'default-dir default-directory) + (setf (magit-section-process section) process) + (with-current-buffer process-buf + (set-marker (process-mark process) (point))) + (when input + (with-current-buffer input + (process-send-region process (point-min) (point-max)) + (process-send-eof process))) + (setq magit-this-process process) + (setf (magit-section-info section) process) + (magit-process-display-buffer process) + process))) + +;;;;; Process Internals + +(defun magit-process-setup (program args) + (magit-process-set-mode-line program args) + (let ((buf (magit-process-buffer))) + (if buf + (magit-process-truncate-log buf) + (setq buf (magit-process-buffer nil t))) + (with-current-buffer buf + (goto-char (1- (point-max))) + (let* ((inhibit-read-only t) + (magit-with-section--parent magit-root-section) + ;; Kids, don't do this ^^^^ at home. + (s (magit-with-section + (section process nil + (mapconcat 'identity (cons program args) " ")) + (insert "\n")))) + (set-marker-insertion-type (magit-section-content-beginning s) nil) + (insert "\n") + (backward-char 2) + (cons (current-buffer) s))))) + +(defun magit-process-truncate-log (buffer) + (with-current-buffer buffer + (let* ((head nil) + (tail (magit-section-children magit-root-section)) + (count (length tail))) + (when (> (1+ count) magit-process-log-max) + (while (and (cdr tail) + (> count (/ magit-process-log-max 2))) + (let* ((inhibit-read-only t) + (section (car tail)) + (process (magit-section-process section))) + (cond ((not process)) + ((memq (process-status process) '(exit signal)) + (delete-region (magit-section-beginning section) + (1+ (magit-section-end section))) + (cl-decf count)) + (t + (push section head)))) + (pop tail)) + (setf (magit-section-children magit-root-section) + (nconc (reverse head) tail)))))) + +(defun magit-process-sentinel (process event) + "Default sentinel used by `magit-start-process'." + (when (memq (process-status process) '(exit signal)) + (setq event (substring event 0 -1)) + (magit-process-unset-mode-line) + (when (string-match "^finished" event) + (message (concat (capitalize (process-name process)) " finished"))) + (magit-process-finish process) + (when (eq process magit-this-process) + (setq magit-this-process nil)) + (magit-refresh (and (buffer-live-p (process-get process 'command-buf)) + (process-get process 'command-buf))))) + +(defun magit-process-filter (proc string) + "Default filter used by `magit-start-process'." + (with-current-buffer (process-buffer proc) + (let ((inhibit-read-only t)) + (magit-process-yes-or-no-prompt proc string) + (magit-process-username-prompt proc string) + (magit-process-password-prompt proc string) + (goto-char (process-mark proc)) + (setq string (propertize string 'invisible + (magit-section-hidden + (process-get proc 'section)))) + ;; Find last ^M in string. If one was found, ignore everything + ;; before it and delete the current line. + (let ((ret-pos (length string))) + (while (and (>= (setq ret-pos (1- ret-pos)) 0) + (/= ?\r (aref string ret-pos)))) + (cond ((>= ret-pos 0) + (goto-char (line-beginning-position)) + (delete-region (point) (line-end-position)) + (insert-and-inherit (substring string (+ ret-pos 1)))) + (t + (insert-and-inherit string)))) + (set-marker (process-mark proc) (point))))) + +(defun magit-process-logfile-filter (process string) + "Special filter used by `magit-run-git-with-logfile'." + (magit-process-filter process string) + (let ((file (process-get process 'logfile))) + (with-temp-file file + (when (file-exists-p file) + (insert-file-contents file) + (goto-char (point-max))) + (insert string) + (write-region (point-min) (point-max) file)))) + +(defun magit-process-yes-or-no-prompt (proc string) + "Forward yes-or-no prompts to the user." + (let ((beg (string-match magit-process-yes-or-no-prompt-regexp string)) + (max-mini-window-height 30)) + (when beg + (process-send-string + proc + (downcase + (concat (match-string (if (yes-or-no-p (substring string 0 beg)) 1 2) + string) + "\n")))))) + +(defun magit-process-password-prompt (proc string) + "Forward password prompts to the user." + (let ((prompt (magit-process-match-prompt + magit-process-password-prompt-regexps string))) + (when prompt + (process-send-string proc (concat (read-passwd prompt) "\n"))))) + +(defun magit-process-username-prompt (proc string) + "Forward username prompts to the user." + (let ((prompt (magit-process-match-prompt + magit-process-username-prompt-regexps string))) + (when prompt + (process-send-string proc + (concat (read-string prompt nil nil + (user-login-name)) + "\n"))))) + +(defun magit-process-match-prompt (prompts string) + (when (cl-find-if (lambda (regex) + (string-match regex string)) + prompts) + (let ((prompt (match-string 0 string))) + (cond ((string-match ": $" prompt) prompt) + ((string-match ":$" prompt) (concat prompt " ")) + (t (concat prompt ": ")))))) + +(defun magit-process-wait () + (while (and magit-this-process + (eq (process-status magit-this-process) 'run)) + (sit-for 0.1 t))) + +(defun magit-process-set-mode-line (program args) + (when (equal program magit-git-executable) + (setq args (nthcdr (1+ (length magit-git-standard-options)) args))) + (magit-map-magit-buffers + (apply-partially (lambda (s) + (setq mode-line-process s)) + (concat " " program + (and args (concat " " (car args))))))) + +(defun magit-process-unset-mode-line () + (magit-map-magit-buffers (lambda () (setq mode-line-process nil)))) + +(defvar magit-process-error-message-re + (concat "^\\(?:error\\|fatal\\|git\\): \\(.*\\)" paragraph-separate)) + +(defun magit-process-finish (arg &optional process-buf command-buf + default-dir section) + (unless (integerp arg) + (setq process-buf (process-buffer arg) + command-buf (process-get arg 'command-buf) + default-dir (process-get arg 'default-dir) + section (process-get arg 'section) + arg (process-exit-status arg))) + (when (featurep 'dired) + (dired-uncache default-dir)) + (when (buffer-live-p process-buf) + (with-current-buffer process-buf + (let ((inhibit-read-only t) + (mark (magit-section-beginning section))) + (set-marker-insertion-type mark nil) + (goto-char mark) + (insert (propertize (format "%3s " arg) + 'magit-section section + 'face (if (= arg 0) + 'magit-process-ok + 'magit-process-ng)))))) + (unless (= arg 0) + (message ; `error' would prevent refresh + "%s ... [%s buffer %s for details]" + (or (and (buffer-live-p process-buf) + (with-current-buffer process-buf + (save-excursion + (goto-char (magit-section-end section)) + (when (re-search-backward + magit-process-error-message-re + (magit-section-content-beginning section) + t) + (match-string 1))))) + "Git failed") + (let ((key (and (buffer-live-p command-buf) + (with-current-buffer command-buf + (car (where-is-internal + 'magit-process-display-buffer)))))) + (if key (format "Hit %s to see" (key-description key)) "See")) + (buffer-name process-buf))) + arg) + +(defun magit-process-display-buffer (process) + (when (process-live-p process) + (let ((buf (process-buffer process))) + (cond ((not (buffer-live-p buf))) + ((= magit-process-popup-time 0) + (pop-to-buffer buf)) + ((> magit-process-popup-time 0) + (run-with-timer magit-process-popup-time nil + (lambda (p) + (when (eq (process-status p) 'run) + (let ((buf (process-buffer p))) + (when (buffer-live-p buf) + (pop-to-buffer buf))))) + process)))))) + +(defun magit-process-quote-arguments (args) + "Quote each argument in list ARGS as an argument to Git. +Except when `magit-process-quote-curly-braces' is non-nil ARGS is +returned unchanged. This is required to works around strangeness +of the Windows \"Powershell\"." + (if magit-process-quote-curly-braces + (mapcar (apply-partially 'replace-regexp-in-string + "{\\([0-9]+\\)}" "\\\\{\\1\\\\}") + (magit-flatten-onelevel args)) + args)) + +;;;; Mode Api +;;;;; Mode Foundation + +(define-derived-mode magit-mode special-mode "Magit" + "Parent major mode from which Magit major modes inherit. + +Please see the manual for a complete description of Magit. + +\\{magit-mode-map}" + (buffer-disable-undo) + (setq truncate-lines t) + (add-hook 'pre-command-hook #'magit-remember-point nil t) + (add-hook 'post-command-hook #'magit-correct-point-after-command t t) + (add-hook 'post-command-hook #'magit-highlight-section t t) + ;; Emacs' normal method of showing trailing whitespace gives weird + ;; results when `magit-whitespace-warning-face' is different from + ;; `trailing-whitespace'. + (when (and magit-highlight-whitespace + magit-highlight-trailing-whitespace) + (setq show-trailing-whitespace nil))) + +(defvar-local magit-refresh-function nil) +(put 'magit-refresh-function 'permanent-local t) + +(defvar-local magit-refresh-args nil) +(put 'magit-refresh-args 'permanent-local t) + +(defmacro magit-mode-setup + (buffer switch-func mode refresh-func &rest refresh-args) + "Display and select BUFFER, turn on MODE, and refresh a first time. +Display BUFFER using `magit-mode-display-buffer', then turn on +MODE in BUFFER, set the local value of `magit-refresh-function' +to REFRESH-FUNC and that of `magit-refresh-args' to REFRESH-ARGS +and finally \"refresh\" a first time. All arguments are +evaluated before switching to BUFFER." + (let ((mode-symb (cl-gensym "mode-symb")) + (toplevel (cl-gensym "toplevel")) + (init-args (cl-gensym "init-args")) + (buf-symb (cl-gensym "buf-symb"))) + `(let* ((,mode-symb ,mode) + (,toplevel (magit-get-top-dir)) + (,init-args (list ,mode-symb ,refresh-func ,@refresh-args)) + (,buf-symb (magit-mode-display-buffer + ,buffer ,mode-symb ,switch-func))) + (if ,toplevel + (with-current-buffer ,buf-symb + (apply #'magit-mode-init ,toplevel ,init-args)) + (user-error "Not inside a Git repository"))))) + +(defun magit-mode-init (dir mode refresh-func &rest refresh-args) + "Turn on MODE and refresh in the current buffer. +Turn on MODE, set the local value of `magit-refresh-function' to +REFRESH-FUNC and that of `magit-refresh-args' to REFRESH-ARGS and +finally \"refresh\" a first time. + +Also see `magit-mode-setup', a more convenient variant." + (cl-case mode + (magit-commit-mode + (magit-setup-xref (cons #'magit-show-commit refresh-args)) + (goto-char (point-min))) + (magit-diff-mode + (magit-setup-xref (cons #'magit-diff refresh-args)) + (goto-char (point-min)))) + (setq default-directory dir + magit-refresh-function refresh-func + magit-refresh-args refresh-args) + (funcall mode) + (magit-mode-refresh-buffer)) + +(defvar-local magit-previous-window-configuration nil) +(put 'magit-previous-window-configuration 'permanent-local t) + +(defun magit-mode-display-buffer (buffer mode &optional switch-function) + "Display BUFFER in some window and select it. +BUFFER may be a buffer or a string, the name of a buffer. Return +the buffer. + +Unless BUFFER is already displayed in the selected frame store the +previous window configuration as a buffer local value, so that it +can later be restored by `magit-mode-quit-window'. + +Then display and select BUFFER using SWITCH-FUNCTION. If that is +nil either use `pop-to-buffer' if the current buffer's major mode +derives from Magit mode; or else use `switch-to-buffer'. + +This is only intended for buffers whose major modes derive from +Magit mode." + (cond ((stringp buffer) + (setq buffer (magit-mode-get-buffer-create buffer mode))) + ((not (bufferp buffer)) + (signal 'wrong-type-argument (list 'bufferp nil)))) + (unless (get-buffer-window buffer (selected-frame)) + (with-current-buffer (get-buffer-create buffer) + (setq magit-previous-window-configuration + (current-window-configuration)))) + (funcall (or switch-function + (if (derived-mode-p 'magit-mode) + 'switch-to-buffer + 'pop-to-buffer)) + buffer) + buffer) + +(defun magit-mode-get-buffer (format mode &optional topdir create) + (if (not (string-match-p "%[Tt]" format)) + (funcall (if create #'get-buffer-create #'get-buffer) format) + (unless topdir + (setq topdir (magit-get-top-dir))) + (let ((name (format-spec + format `((?T . ,topdir) + (?t . ,(file-name-nondirectory + (directory-file-name topdir))))))) + (or (cl-find-if + (lambda (buf) + (with-current-buffer buf + (and (or (not mode) (eq major-mode mode)) + (equal (expand-file-name default-directory) topdir) + (string-match-p (format "^%s\\(?:<[0-9]+>\\)?$" + (regexp-quote name)) + (buffer-name))))) + (buffer-list)) + (and create (generate-new-buffer name)))))) + +(defun magit-mode-get-buffer-create (format mode &optional topdir) + (magit-mode-get-buffer format mode topdir t)) + +(cl-defun magit-mode-refresh-buffer (&optional (buffer (current-buffer))) + (with-current-buffer buffer + (when magit-refresh-function + (let* ((old-line (line-number-at-pos)) + (old-point (point)) + (old-section (magit-current-section)) + (old-path (and old-section + (magit-section-path (magit-current-section))))) + (beginning-of-line) + (let ((inhibit-read-only t) + (section-line (and old-section + (count-lines + (magit-section-beginning old-section) + (point)))) + (line-char (- old-point (point)))) + (erase-buffer) + (apply magit-refresh-function + magit-refresh-args) + (let ((s (and old-path (magit-find-section old-path magit-root-section)))) + (cond (s + (goto-char (magit-section-beginning s)) + (forward-line section-line) + (forward-char line-char)) + (t + (save-restriction + (widen) + (goto-char (point-min)) + (forward-line (1- old-line))))))) + (magit-highlight-section) + (magit-refresh-marked-commits-in-buffer))))) + +(defun magit-mode-quit-window (&optional kill-buffer) + "Bury the current buffer and delete its window. +With a prefix argument, kill the buffer instead. + +If `magit-restore-window-configuration' is non-nil and the last +configuration stored by `magit-mode-display-buffer' originates +from the selected frame then restore it after burrying/killing +the buffer. Finally reset the window configuration to nil." + (interactive "P") + (let ((winconf magit-previous-window-configuration) + (buffer (current-buffer)) + (frame (selected-frame))) + (quit-window kill-buffer (selected-window)) + (when winconf + (when (and magit-restore-window-configuration + (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))))) + (run-hook-with-args 'magit-mode-quit-window-hook buffer))) + +;;;;; Mode Utilities + +(defun magit-map-magit-buffers (func &optional dir) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (when (and (derived-mode-p 'magit-mode) + (or (null dir) + (equal default-directory dir))) + (funcall func))))) + +;;;;; (section kludges) + +(defvar-local magit-last-point nil) +(put 'magit-last-point 'permanent-local t) + +(defun magit-remember-point () + (setq magit-last-point (point))) + +(defun magit-invisible-region-end (pos) + (while (and (not (= pos (point-max))) (invisible-p pos)) + (setq pos (next-char-property-change pos))) + pos) + +(defun magit-invisible-region-start (pos) + (while (and (not (= pos (point-min))) (invisible-p pos)) + (setq pos (1- (previous-char-property-change pos)))) + pos) + +(defun magit-correct-point-after-command () + "Move point outside of invisible regions. + +Emacs often leaves point in invisible regions, it seems. To fix +this, we move point ourselves and never let Emacs do its own +adjustments. + +When point has to be moved out of an invisible region, it can be +moved to its end or its beginning. We usually move it to its +end, except when that would move point back to where it was +before the last command." + (when (invisible-p (point)) + (let ((end (magit-invisible-region-end (point)))) + (goto-char (if (= end magit-last-point) + (magit-invisible-region-start (point)) + end)))) + (setq disable-point-adjustment t)) + +;;;;; 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-xref-insert-buttons () + (when (and (or (eq magit-show-xref-buttons t) + (apply 'derived-mode-p magit-show-xref-buttons)) + (or help-xref-stack help-xref-forward-stack)) + (insert "\n") + (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-with-section (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-item-highlight-face + 'help-echo (purecopy "mouse-2, RET: go back to previous history entry")) + +(define-button-type 'magit-xref-forward + :supertype 'help-forward + 'mouse-face magit-item-highlight-face + 'help-echo (purecopy "mouse-2, RET: go back to next history entry")) + +(defun magit-setup-xref (item) + (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) + (let ((tail (nthcdr 10 help-xref-stack))) + (if tail (setcdr tail nil)))) + (setq help-xref-stack-item item)) + +;;;;; Refresh Machinery + +(defun magit-refresh (&optional buffer) + "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. +If the global `magit-auto-revert-mode' is turned on, then +also revert all unmodified buffers that visit files being +tracked in the current repository." + (interactive (list (current-buffer))) + (unless buffer + (setq buffer (current-buffer))) + (with-current-buffer buffer + (when (derived-mode-p 'magit-mode) + (magit-mode-refresh-buffer buffer)) + (let (status) + (when (and (not (eq major-mode 'magit-status-mode)) + (setq status (magit-mode-get-buffer + magit-status-buffer-name + 'magit-status-mode))) + (magit-mode-refresh-buffer status)))) + (when magit-auto-revert-mode + (magit-revert-buffers))) + +(defun magit-refresh-all () + "Refresh all buffers belonging to the current repository. + +Refresh all Magit buffers belonging to the current repository. +If the global `magit-auto-revert-mode' is turned on, then also +revert all unmodified buffers that visit files being tracked in +the current repository." + (interactive) + (magit-map-magit-buffers #'magit-mode-refresh-buffer default-directory) + (magit-revert-buffers)) + +(defun magit-revert-buffers () + (let ((topdir (magit-get-top-dir))) + (when topdir + (let ((gitdir (magit-git-dir)) + (tracked (magit-git-lines "ls-tree" "-r" "--name-only" "HEAD"))) + (dolist (buf (buffer-list)) + (with-current-buffer buf + (let ((file (buffer-file-name))) + (and file (string-prefix-p topdir file) + (not (string-prefix-p gitdir file)) + (member (file-relative-name file topdir) tracked) + (let ((auto-revert-mode t)) + (auto-revert-handler) + (run-hooks 'magit-revert-buffer-hook)))))))))) + +;;; (misplaced) +;;;; Diff Options + +(defvar magit-diff-context-lines 3) + +(defun magit-diff-U-arg () + (format "-U%d" magit-diff-context-lines)) + +(defun magit-diff-smaller-hunks (&optional count) + "Decrease the context for diff hunks by COUNT." + (interactive "p") + (setq magit-diff-context-lines (max 0 (- magit-diff-context-lines count))) + (magit-refresh)) + +(defun magit-diff-larger-hunks (&optional count) + "Increase the context for diff hunks by COUNT." + (interactive "p") + (setq magit-diff-context-lines (+ magit-diff-context-lines count)) + (magit-refresh)) + +(defun magit-diff-default-hunks () + "Reset context for diff hunks to the default size." + (interactive) + (setq magit-diff-context-lines 3) + (magit-refresh)) + +(defun magit-set-diff-options () + "Set local `magit-diff-options' based on popup state. +And refresh the current Magit buffer." + (interactive) + (setq-local magit-diff-options magit-custom-options) + (magit-refresh)) + +;; `magit-set-default-diff-options' is defined in "Options"/"Setters". + +(defun magit-save-default-diff-options () + "Set and save the default for `magit-diff-options' based on popup value. +Also set the local value in all Magit buffers and refresh them." + (interactive) + (customize-save-variable 'magit-diff-options magit-custom-options)) + +(defun magit-reset-diff-options () + "Reset local `magit-diff-options' to default value. +And refresh the current Magit buffer." + (interactive) + (setq-local magit-diff-options (default-value 'magit-diff-options)) + (magit-refresh)) + +;;;; Raw Diff Washing + +(defun magit-insert-diff (section file status) + (let ((beg (point))) + (apply 'magit-git-insert "-c" "diff.submodule=short" "diff" + `(,(magit-diff-U-arg) ,@magit-diff-options "--" ,file)) + (unless (eq (char-before) ?\n) + (insert "\n")) + (save-restriction + (narrow-to-region beg (point)) + (goto-char beg) + (magit-wash-diff-section section) + (goto-char (point-max))))) + +(defun magit-wash-raw-diffs (&optional staged) + (let (previous) + (magit-wash-sequence + (lambda () + (setq previous (magit-wash-raw-diff previous staged)))))) + +(defun magit-wash-raw-diff (previous staged) + (when (looking-at + ":\\([0-7]+\\) \\([0-7]+\\) [0-9a-f]+ [0-9a-f]+ \\(.\\)[0-9]*\t\\([^\t\n]+\\)$") + (let ((file (magit-decode-git-path (match-string-no-properties 4))) + (status (cl-ecase (string-to-char (match-string-no-properties 3)) + (?A 'new) + (?C 'copy) + (?D 'deleted) + (?M 'modified) + (?T 'typechange) + (?U 'unmerged) + (?X 'unknown)))) + (delete-region (point) (1+ (line-end-position))) + (unless (or ;; Unmerged files get two entries; we ignore the second. + (equal file previous) + ;; Ignore staged, unmerged files. + (and staged (eq status 'unmerged))) + (magit-with-section (section diff file nil nil + (not (derived-mode-p + 'magit-diff-mode + 'magit-commit-mode))) + (if (not (magit-section-hidden section)) + (magit-insert-diff section file status) + (setf (magit-section-diff-status section) status) + (setf (magit-section-needs-refresh-on-show section) t) + (magit-insert-diff-title status file nil)))) + file))) + +;;; Modes (1) +;;;; Commit Mode +;;;;; Commit Core + +(define-derived-mode magit-commit-mode magit-mode "Magit" + "Mode for looking at a git commit. + +\\Type `\\[magit-visit-item]` to visit the changed file, \ +`\\[magit-toggle-section]` to hide or show a hunk, +`\\[magit-diff-larger-hunks]` and `\\[magit-diff-smaller-hunks]` to change the \ +size of the hunks. +Type `\\[magit-apply-item]` to apply a change to your worktree and \ +`\\[magit-revert-item]` to reverse it. + +\\{magit-commit-mode-map} +Unless shadowed by the mode specific bindings above, bindings +from the parent keymap `magit-mode-map' are also available." + :group 'magit) + +(defvar magit-commit-buffer-name "*magit-commit*" + "Name of buffer used to display a commit.") + +;;;###autoload +(defun magit-show-commit (commit &optional noselect) + "Show information about COMMIT." + (interactive (list (magit-read-rev-with-default + "Show commit (hash or ref)"))) + (when (magit-git-failure "cat-file" "commit" commit) + (user-error "%s is not a commit" commit)) + (magit-mode-setup magit-commit-buffer-name + (if noselect 'display-buffer 'pop-to-buffer) + #'magit-commit-mode + #'magit-refresh-commit-buffer + commit)) + +(defun magit-show-item-or-scroll-up () + "Update commit or status buffer for item at point. + +Either show the commit or stash at point in another buffer, +or if that buffer is already displayed in the current frame +and contains information about that commit or stash, then +instead scroll the buffer up. If there is no commit or +stash at point, then prompt for a commit." + (interactive) + (magit-show-item-or-scroll 'scroll-up)) + +(defun magit-show-item-or-scroll-down () + "Update commit or status buffer for item at point. + +Either show the commit or stash at point in another buffer, +or if that buffer is already displayed in the current frame +and contains information about that commit or stash, then +instead scroll the buffer down. If there is no commit or +stash at point, then prompt for a commit." + (interactive) + (magit-show-item-or-scroll 'scroll-down)) + +(defun magit-show-item-or-scroll (fn) + (let (rev cmd buf win) + (magit-section-case (info) + (commit (setq rev info + cmd 'magit-show-commit + buf magit-commit-buffer-name)) + (stash (setq rev info + cmd 'magit-diff-stash + buf magit-stash-buffer-name))) + (if rev + (if (and (setq buf (get-buffer buf)) + (setq win (get-buffer-window buf)) + (with-current-buffer buf + (equal rev (car magit-refresh-args)))) + (with-selected-window win + (condition-case err + (funcall fn) + (error + (goto-char (cl-case fn + (scroll-up (point-min)) + (scroll-down (point-max))))))) + (funcall cmd rev t)) + (call-interactively 'magit-show-commit)))) + +(defun magit-refresh-commit-buffer (commit) + (magit-git-insert-section (commitbuf nil) + #'magit-wash-commit + "log" "-1" "--decorate=full" + "--pretty=medium" (magit-diff-U-arg) + "--cc" "-p" (and magit-show-diffstat "--stat") + magit-diff-options commit)) + +;;;;; Commit Washing + +(defun magit-wash-commit () + (looking-at "^commit \\([a-z0-9]+\\)\\(?: \\(.+\\)\\)?$") + (let ((rev (match-string 1)) + (refs (match-string 2))) + (delete-region (point) (1+ (line-end-position))) + (magit-with-section + (section headers 'headers + (concat (propertize rev 'face 'magit-log-sha1) + (and refs (concat " "(magit-format-ref-labels refs))) + "\n")) + (while (re-search-forward "^\\([a-z]+\\): +\\(.+\\)$" nil t) + (when (string-match-p (match-string 1) "Merge") + (let ((revs (match-string 2))) + (delete-region (match-beginning 2) (match-end 2)) + (dolist (rev (split-string revs)) + (magit-insert-commit-button rev) + (insert ?\s))))) + (forward-line))) + (forward-line) + (let ((bound (save-excursion + (when (re-search-forward "^diff" nil t) + (copy-marker (match-beginning 0))))) + (summary (buffer-substring-no-properties + (point) (line-end-position)))) + (delete-region (point) (1+ (line-end-position))) + (magit-with-section (section message 'message (concat summary "\n")) + (cond ((re-search-forward "^---" bound t) + (goto-char (match-beginning 0)) + (delete-region (match-beginning 0) (match-end 0))) + ((re-search-forward "^.[^ ]" bound t) + (goto-char (1- (match-beginning 0))))))) + (forward-line) + (when magit-show-diffstat + (magit-wash-diffstats)) + (forward-line) + (magit-wash-diffs)) + +(defun magit-insert-commit-button (hash) + (magit-with-section (section commit hash) + (insert-text-button hash + 'help-echo "Visit commit" + 'action (lambda (button) + (save-excursion + (goto-char button) + (magit-visit-item))) + 'follow-link t + 'mouse-face magit-item-highlight-face + 'face 'magit-log-sha1))) + +;;;; Status Mode + +(define-derived-mode magit-status-mode magit-mode "Magit" + "Mode for looking at git status. + +\\Type `\\[magit-stage-item]` to stage (add) an item, \ +`\\[magit-unstage-item]` to unstage it. +Type `\\[magit-key-mode-popup-committing]` to have a popup to commit, type \ +`\\[magit-key-mode-popup-dispatch]` to see others +available popup. +Type `\\[magit-visit-item]` to visit something, and \ +`\\[magit-toggle-section]` to show or hide section. + +More information can be found in Info node `(magit)Status' + +Other key binding: +\\{magit-status-mode-map}" + :group 'magit) + +(defvar magit-status-buffer-name "*magit: %t*" + "Name of buffer used to display a repository's status.") + +;;;###autoload +(defun magit-status (dir &optional switch-function) + "Open a Magit status buffer for the Git repository containing DIR. +If DIR is not within a Git repository, offer to create a Git +repository in DIR. + +Interactively, a prefix argument means to ask the user which Git +repository to use even if `default-directory' is under Git +control. Two prefix arguments means to ignore `magit-repo-dirs' +when asking for user input. + +Depending on option `magit-status-buffer-switch-function' the +status buffer is shown in another window (the default) or the +current window. Non-interactively optional SWITCH-FUNCTION +can be used to override this." + (interactive (list (if current-prefix-arg + (magit-read-top-dir + (> (prefix-numeric-value current-prefix-arg) + 4)) + (or (magit-get-top-dir) + (magit-read-top-dir nil))))) + (magit-save-some-buffers) + (let ((topdir (magit-get-top-dir dir))) + (when (or topdir + (and (yes-or-no-p + (format "There is no Git repository in %s. Create one? " + dir)) + (progn + (magit-init dir) + (setq topdir (magit-get-top-dir dir))))) + (let ((default-directory topdir)) + (magit-mode-setup magit-status-buffer-name + (or switch-function + magit-status-buffer-switch-function) + #'magit-status-mode + #'magit-refresh-status))))) + +(defalias 'magit-status-internal 'magit-status) ; forward compatibility + +(defun magit-refresh-status () + (magit-git-exit-code "update-index" "--refresh") + (magit-with-section (section status 'status nil t) + (run-hooks 'magit-status-sections-hook)) + (run-hooks 'magit-refresh-status-hook)) + +;;; Sections +;;;; Real Sections + +(defun magit-insert-stashes () + ;; #1427 Set log.date to work around an issue in Git <1.7.10.3. + (let ((stashes (magit-git-lines "-c" "log.date=default" "stash" "list"))) + (when stashes + (magit-with-section (section stashes 'stashes "Stashes:" t) + (dolist (stash stashes) + (string-match "^\\(stash@{\\([0-9]+\\)}\\): \\(.+\\)$" stash) + (let ((stash (match-string 1 stash)) + (number (match-string 2 stash)) + (message (match-string 3 stash))) + (magit-with-section (section stash stash) + (insert number ": " message "\n")))) + (insert "\n"))))) + +(defun magit-insert-untracked-files () + (magit-with-section (section untracked 'untracked "Untracked files:" t) + (let ((files (cl-mapcan + (lambda (f) + (when (eq (aref f 0) ??) (list f))) + (magit-git-lines + "status" "--porcelain")))) + (if (not files) + (setq section nil) + (dolist (file files) + (setq file (magit-decode-git-path (substring file 3))) + (magit-with-section (section file file) + (insert "\t" file "\n"))) + (insert "\n"))))) + +(defun magit-insert-pending-commits () + (let* ((info (magit-read-rewrite-info)) + (pending (cdr (assq 'pending info)))) + (when pending + (magit-with-section (section pending 'pending "Pending commits:" t) + (dolist (p pending) + (let* ((commit (car p)) + (properties (cdr p)) + (used (plist-get properties 'used))) + (magit-with-section (section commit commit) + (insert (magit-git-string + "log" "-1" + (if used + "--pretty=format:. %s" + "--pretty=format:* %s") + commit "--") + "\n"))))) + (insert "\n")))) + +(defun magit-insert-unstaged-changes () + (let ((magit-current-diff-range (cons 'index 'working)) + (magit-diff-options (copy-sequence magit-diff-options))) + (magit-git-insert-section (unstaged "Unstaged changes:") + #'magit-wash-raw-diffs + "diff-files"))) + +(defun magit-insert-staged-changes () + (let ((no-commit (not (magit-git-success "log" "-1" "HEAD")))) + (when (or no-commit (magit-anything-staged-p)) + (let ((magit-current-diff-range (cons "HEAD" 'index)) + (base (if no-commit + (magit-git-string "mktree") + "HEAD")) + (magit-diff-options (append '("--cached") magit-diff-options))) + (magit-git-insert-section (staged "Staged changes:") + (apply-partially #'magit-wash-raw-diffs t) + "diff-index" "--cached" base))))) + +(defun magit-insert-unpulled-or-recent-commits () + (let ((tracked (magit-get-tracked-branch nil t))) + (if (and tracked + (not (equal (magit-git-string "rev-parse" "HEAD") + (magit-git-string "rev-parse" tracked)))) + (magit-insert-unpulled-commits) + (magit-git-insert-section (recent "Recent commits:") + (apply-partially 'magit-wash-log 'unique) + "log" "--format=format:%h %s" "-n" "10")))) + +(defun magit-insert-unpulled-commits () + (let ((tracked (magit-get-tracked-branch nil t))) + (when tracked + (magit-git-insert-section (unpulled "Unpulled commits:") + (apply-partially 'magit-wash-log 'unique) + "log" "--format=format:%h %s" (concat "HEAD.." tracked))))) + +(defun magit-insert-unpushed-commits () + (let ((tracked (magit-get-tracked-branch nil t))) + (when tracked + (magit-git-insert-section (unpushed "Unpushed commits:") + (apply-partially 'magit-wash-log 'unique) + "log" "--format=format:%h %s" (concat tracked "..HEAD"))))) + +(defun magit-insert-unpulled-cherries () + (let ((tracked (magit-get-tracked-branch nil t))) + (when tracked + (magit-git-insert-section (unpulled "Unpulled commits:") + (apply-partially 'magit-wash-log 'cherry) + "cherry" "-v" (magit-abbrev-arg) (magit-get-current-branch) tracked)))) + +(defun magit-insert-unpushed-cherries () + (let ((tracked (magit-get-tracked-branch nil t))) + (when tracked + (magit-git-insert-section (unpushed "Unpushed commits:") + (apply-partially 'magit-wash-log 'cherry) + "cherry" "-v" (magit-abbrev-arg) tracked)))) + +;;;; Line Sections + +(defun magit-insert-empty-line () + (insert "\n")) + +(defun magit-insert-status-local-line () + (let ((branch (or (magit-get-current-branch) "(detached)"))) + (magit-insert-line-section (branch branch) + (concat "Local: " + (propertize branch 'face 'magit-branch) + " " (abbreviate-file-name default-directory))))) + +(defun magit-insert-status-remote-line () + (let* ((branch (magit-get-current-branch)) + (tracked (magit-get-tracked-branch branch))) + (when tracked + (magit-insert-line-section (branch tracked) + (concat "Remote: " + (and (magit-get-boolean "branch" branch "rebase") "onto ") + (magit-format-tracked-line tracked branch)))))) + +(defun magit-format-tracked-line (tracked branch) + (when tracked + (setq tracked (propertize tracked 'face 'magit-branch)) + (let ((remote (magit-get "branch" branch "remote"))) + (concat (if (string= "." remote) + (concat "branch " tracked) + (when (string-match (concat "^" remote) tracked) + (setq tracked (substring tracked (1+ (length remote))))) + (concat tracked " @ " remote + " (" (magit-get "remote" remote "url") ")")))))) + +(defun magit-insert-status-head-line () + (let ((hash (magit-git-string "rev-parse" "--verify" "HEAD"))) + (if hash + (magit-insert-line-section (commit hash) + (concat "Head: " (magit-format-rev-summary "HEAD"))) + (magit-insert-line-section (no-commit) + "Head: nothing committed yet")))) + +(defun magit-insert-status-tags-line () + (let* ((current-tag (magit-get-current-tag t)) + (next-tag (magit-get-next-tag t)) + (both-tags (and current-tag next-tag t)) + (tag-subject (eq magit-status-tags-line-subject 'tag))) + (when (or current-tag next-tag) + (magit-insert-line-section (line) + (concat + (if both-tags "Tags: " "Tag: ") + (and current-tag (apply 'magit-format-status-tag-sentence + tag-subject current-tag)) + (and both-tags ", ") + (and next-tag (apply 'magit-format-status-tag-sentence + (not tag-subject) next-tag))))))) + +(defun magit-format-status-tag-sentence (behindp tag cnt &rest ignored) + (concat (propertize tag 'face 'magit-tag) + (and (> cnt 0) + (concat (if (eq magit-status-tags-line-subject 'tag) + (concat " (" (propertize (format "%s" cnt) + 'face 'magit-branch)) + (format " (%i" cnt)) + " " (if behindp "behind" "ahead") ")")))) + +;;;; Progress Sections + +(defun magit-insert-status-merge-line () + (let ((heads (magit-file-lines (magit-git-dir "MERGE_HEAD")))) + (when heads + (magit-insert-line-section (line) + (concat + "Merging: " + (mapconcat 'identity (mapcar 'magit-name-rev heads) ", ") + (and magit-status-show-sequence-help + "; Resolve conflicts, or press \"m A\" to Abort")))))) + +(defun magit-insert-status-rebase-lines () + (let ((rebase (magit-rebase-info))) + (when rebase + (magit-insert-line-section (line) + (concat (if (nth 4 rebase) "Applying" "Rebasing") + (apply 'format ": onto %s (%s of %s)" rebase) + (and magit-status-show-sequence-help + "; Press \"R\" to Abort, Skip, or Continue"))) + (when (and (null (nth 4 rebase)) (nth 3 rebase)) + (magit-insert-line-section (line) + (concat "Stopped: " + (magit-format-rev-summary (nth 3 rebase)))))))) + +(defun magit-insert-rebase-sequence () + (let ((f (magit-git-dir "rebase-merge/git-rebase-todo"))) + (when (file-exists-p f) + (magit-with-section (section rebase-todo 'rebase-todo "Rebasing:" t) + (cl-loop + for line in (magit-file-lines f) + when (string-match + "^\\(pick\\|reword\\|edit\\|squash\\|fixup\\) \\([^ ]+\\) \\(.*\\)$" + line) + do (let ((cmd (match-string 1 line)) + (hash (match-string 2 line)) + (msg (match-string 3 line))) + (magit-with-section (section commit hash) + (insert cmd " ") + (insert (propertize + (magit-git-string "rev-parse" "--short" hash) + 'face 'magit-log-sha1)) + (insert " " msg "\n")))) + (insert "\n"))))) + +(defun magit-insert-bisect-output () + (when (magit-bisecting-p) + (let ((lines + (or (magit-file-lines (magit-git-dir "BISECT_CMD_OUTPUT")) + (list "Bisecting: (no saved bisect output)" + "It appears you have invoked `git bisect' from a shell." + "There is nothing wrong with that, we just cannot display" + "anything useful here. Consult the shell output instead."))) + (done-re "^[a-z0-9]\\{40\\} is the first bad commit$")) + (magit-with-section + (section bisect-output 'bisect-output + (propertize + (or (and (string-match done-re (car lines)) (pop lines)) + (cl-find-if (apply-partially 'string-match done-re) + lines) + (pop lines)) + 'face 'magit-section-title) + t t) + (dolist (line lines) + (insert line "\n")))) + (insert "\n"))) + +(defun magit-insert-bisect-rest () + (when (magit-bisecting-p) + (magit-git-insert-section (bisect-view "Bisect Rest:") + (apply-partially 'magit-wash-log 'bisect-vis) + "bisect" "visualize" "git" "log" + "--pretty=format:%h%d %s" "--decorate=full"))) + +(defun magit-insert-bisect-log () + (when (magit-bisecting-p) + (magit-git-insert-section (bisect-log "Bisect Log:") + #'magit-wash-bisect-log + "bisect" "log"))) + +(defun magit-wash-bisect-log () + (let (beg) + (while (progn (setq beg (point-marker)) + (re-search-forward "^\\(git bisect [^\n]+\n\\)" nil t)) + (let ((heading (match-string-no-properties 1))) + (delete-region (match-beginning 0) (match-end 0)) + (save-restriction + (narrow-to-region beg (point)) + (goto-char (point-min)) + (magit-with-section (section bisect-log 'bisect-log heading nil t) + (magit-wash-sequence + (apply-partially 'magit-wash-log-line 'bisect-log + (magit-abbrev-length))))))) + (when (re-search-forward + "# first bad commit: \\[\\([a-z0-9]\\{40\\}\\)\\] [^\n]+\n" nil t) + (let ((hash (match-string-no-properties 1))) + (delete-region (match-beginning 0) (match-end 0)) + (magit-with-section + (section 'bisect-log 'bisect-log + (concat hash " is the first bad commit\n"))))))) + +(defun magit-bisecting-p () + (file-exists-p (magit-git-dir "BISECT_LOG"))) + +;;; Utilities (2) +;;;; Save Buffers + +(defvar magit-default-directory nil) + +(defun magit-save-some-buffers (&optional msg pred topdir) + "Save some buffers if variable `magit-save-some-buffers' is non-nil. +If variable `magit-save-some-buffers' is set to `dontask' then +don't ask the user before saving the buffers, just go ahead and +do it. + +Optional argument MSG is displayed in the minibuffer if variable +`magit-save-some-buffers' is nil. + +Optional second argument PRED determines which buffers are considered: +If PRED is nil, all the file-visiting buffers are considered. +If PRED is t, then certain non-file buffers will also be considered. +If PRED is a zero-argument function, it indicates for each buffer whether +to consider it or not when called with that buffer current." + (interactive) + (let ((predicate-function (or pred magit-save-some-buffers-predicate)) + (magit-default-directory (or topdir default-directory))) + (if magit-save-some-buffers + (save-some-buffers + (eq magit-save-some-buffers 'dontask) + predicate-function) + (when msg + (message msg))))) + +(defun magit-save-buffers-predicate-all () + "Prompt to save all buffers with unsaved changes." + t) + +(defun magit-save-buffers-predicate-tree-only () + "Only prompt to save buffers which are within the current git project. +As determined by the directory passed to `magit-status'." + (and buffer-file-name + (let ((topdir (magit-get-top-dir magit-default-directory))) + (and topdir + (equal (file-remote-p topdir) (file-remote-p buffer-file-name)) + ;; ^ Avoid needlessly connecting to unrelated tramp remotes. + (string= topdir (magit-get-top-dir + (file-name-directory buffer-file-name))))))) + +;;; Porcelain +;;;; Apply +;;;;; Apply Commands +;;;;;; Apply + +(defun magit-apply-item () + "Apply the item at point to the current working tree." + (interactive) + (magit-section-action apply (info) + (([* unstaged] [* staged]) + (user-error "Change is already in your working tree")) + (hunk (magit-apply-hunk-item it)) + (diff (magit-apply-diff-item it)) + (stash (magit-stash-apply info)) + (commit (magit-apply-commit info)))) + +;;;;;; Stage + +(defun magit-stage-item (&optional file) + "Add the item at point to the staging area. +With a prefix argument, prompt for a file to be staged instead." + (interactive + (when current-prefix-arg + (list (file-relative-name (read-file-name "File to stage: " nil nil t) + (magit-get-top-dir))))) + (if file + (magit-run-git "add" file) + (magit-section-action stage (info) + ([file untracked] + (magit-run-git + (cond + ((use-region-p) + (cons "add" (magit-section-region-siblings #'magit-section-info))) + ((and (string-match-p "/$" info) + (file-exists-p (expand-file-name ".git" info))) + (let ((repo (read-string + "Add submodule tracking remote repo (empty to abort): " + (let ((default-directory + (file-name-as-directory + (expand-file-name info default-directory)))) + (magit-get "remote.origin.url"))))) + (if (equal repo "") + (user-error "Abort") + (list "submodule" "add" repo (substring info 0 -1))))) + (t + (list "add" info))))) + (untracked + (magit-run-git "add" "--" (magit-git-lines "ls-files" "--other" + "--exclude-standard"))) + ([hunk diff unstaged] + (magit-apply-hunk-item it "--cached")) + ([diff unstaged] + (magit-run-git "add" "-u" + (if (use-region-p) + (magit-section-region-siblings #'magit-section-info) + info))) + (unstaged + (magit-stage-all)) + ([* staged] + (user-error "Already staged")) + (hunk (user-error "Can't stage this hunk")) + (diff (user-error "Can't stage this diff"))))) + +;;;###autoload +(defun magit-stage-all (&optional including-untracked) + "Add all remaining changes in tracked files to staging area. +With a prefix argument, add remaining untracked files as well. +\('git add [-u] .')." + (interactive "P") + (when (or (not magit-stage-all-confirm) + (not (magit-anything-staged-p)) + (yes-or-no-p "Stage all changes? ")) + (if including-untracked + (magit-run-git "add" ".") + (magit-run-git "add" "-u" ".")))) + +;;;;;; Unstage + +(defun magit-unstage-item () + "Remove the item at point from the staging area." + (interactive) + (magit-section-action unstage (info) + ([hunk diff staged] + (magit-apply-hunk-item it "--reverse" "--cached")) + ([diff staged] + (when (eq info 'unmerged) + (user-error "Can't unstage an unmerged file. Resolve it first")) + (let ((files (if (use-region-p) + (magit-section-region-siblings #'magit-section-info) + (list info)))) + (if (magit-no-commit-p) + (magit-run-git "rm" "--cached" "--" files) + (magit-run-git "reset" "-q" "HEAD" "--" files)))) + (staged + (magit-unstage-all)) + ([* unstaged] + (user-error "Already unstaged")) + (hunk (user-error "Can't unstage this hunk")) + (diff (user-error "Can't unstage this diff")))) + +;;;###autoload +(defun magit-unstage-all () + "Remove all changes from staging area. +\('git reset --mixed HEAD')." + (interactive) + (when (or (not magit-unstage-all-confirm) + (and (not (magit-anything-unstaged-p)) + (not (magit-git-lines "ls-files" "--others" "-t" + "--exclude-standard"))) + (yes-or-no-p "Unstage all changes? ")) + (magit-run-git "reset" "HEAD" "--"))) + +;;;;;; Discard + +(defun magit-discard-item () + "Remove the change introduced by the item at point." + (interactive) + (magit-section-action discard (info parent-info) + ([file untracked] + (when (yes-or-no-p (format "Delete %s? " info)) + (if (and (file-directory-p info) + (not (file-symlink-p info))) + (delete-directory info 'recursive) + (delete-file info)) + (magit-refresh))) + (untracked + (when (yes-or-no-p "Delete all untracked files and directories? ") + (magit-run-git "clean" "-df"))) + ([hunk diff unstaged] + (when (yes-or-no-p (if (use-region-p) + "Discard changes in region? " + "Discard hunk? ")) + (magit-apply-hunk-item it "--reverse"))) + ([hunk diff staged] + (if (magit-file-uptodate-p parent-info) + (when (yes-or-no-p (if (use-region-p) + "Discard changes in region? " + "Discard hunk? ")) + (magit-apply-hunk-item it "--reverse" "--index")) + (user-error "Can't discard this hunk. Please unstage it first"))) + ([diff unstaged] + (magit-discard-diff it nil)) + ([diff staged] + (if (magit-file-uptodate-p (magit-section-info it)) + (magit-discard-diff it t) + (user-error "Can't discard staged changes to this file. \ +Please unstage it first"))) + (hunk (user-error "Can't discard this hunk")) + (diff (user-error "Can't discard this diff")) + (stash (when (yes-or-no-p "Discard stash? ") + (magit-stash-drop info))) + (branch (when (yes-or-no-p + (if current-prefix-arg + (concat "Force delete branch [" info "]? ") + (concat "Delete branch [" info "]? "))) + (magit-delete-branch info current-prefix-arg))) + (remote (when (yes-or-no-p "Remove remote? ") + (magit-remove-remote info))))) + +;;;;;; Revert + +(defun magit-revert-item () + "Revert the item at point. +The change introduced by the item is reversed in the current +working tree." + (interactive) + (magit-section-action revert (info) + ([* unstaged] (magit-discard-item)) + (commit (when (or (not magit-revert-item-confirm) + (yes-or-no-p "Revert this commit? ")) + (magit-revert-commit info))) + (diff (when (or (not magit-revert-item-confirm) + (yes-or-no-p "Revert this diff? ")) + (magit-apply-diff-item it "--reverse"))) + (hunk (when (or (not magit-revert-item-confirm) + (yes-or-no-p "Revert this hunk? ")) + (magit-apply-hunk-item it "--reverse"))))) + +(defun magit-revert-commit (commit) + (magit-assert-one-parent commit "revert") + (magit-run-git "revert" "--no-commit" commit)) + +(defconst magit-revert-backup-file "magit/reverted.diff") + +(defun magit-revert-undo () + "Re-apply the previously reverted hunk. +Also see option `magit-revert-backup'." + (interactive) + (let ((file (magit-git-dir magit-revert-backup-file))) + (if (file-readable-p file) + (magit-run-git "apply" file) + (user-error "No backups exist")) + (magit-refresh))) + +;;;;; Apply Core + +(defun magit-discard-diff (diff stagedp) + (let ((file (magit-section-info diff))) + (cl-case (magit-section-diff-status diff) + (deleted + (when (yes-or-no-p (format "Resurrect %s? " file)) + (when stagedp + (magit-run-git "reset" "-q" "--" file)) + (magit-run-git "checkout" "--" file))) + (new + (when (yes-or-no-p (format "Delete %s? " file)) + (magit-run-git "rm" "-f" "--" file))) + (t + (when (yes-or-no-p (format "Discard changes to %s? " file)) + (if stagedp + (magit-run-git "checkout" "HEAD" "--" file) + (magit-run-git "checkout" "--" file))))))) + +(defun magit-apply-commit (commit) + (magit-assert-one-parent commit "cherry-pick") + (magit-run-git "cherry-pick" "--no-commit" commit)) + +(defun magit-apply-diff-item (diff &rest args) + (when (zerop magit-diff-context-lines) + (setq args (cons "--unidiff-zero" args))) + (let ((buf (generate-new-buffer " *magit-input*"))) + (unwind-protect + (progn (magit-insert-diff-item-patch diff buf) + (magit-run-git-with-input + buf "apply" args "--ignore-space-change" "-")) + (kill-buffer buf)))) + +(defun magit-apply-hunk-item (hunk &rest args) + "Apply single hunk or part of a hunk to the index or working file. + +This function is the core of magit's stage, unstage, apply, and +revert operations. HUNK (or the portion of it selected by the +region) will be applied to either the index, if \"--cached\" is a +member of ARGS, or to the working file otherwise." + (when (string-match "^diff --cc" (magit-section-parent-info hunk)) + (user-error (concat "Cannot un-/stage individual resolution hunks. " + "Please stage the whole file."))) + (let ((use-region (use-region-p))) + (when (zerop magit-diff-context-lines) + (setq args (cons "--unidiff-zero" args)) + (when use-region + (user-error (concat "Not enough context to partially apply hunk. " + "Use `+' to increase context.")))) + (let ((buf (generate-new-buffer " *magit-input*"))) + (unwind-protect + (progn (if use-region + (magit-insert-hunk-item-region-patch + hunk (member "--reverse" args) + (region-beginning) (region-end) buf) + (magit-insert-hunk-item-patch hunk buf)) + (magit-revert-backup buf args) + (magit-run-git-with-input + buf "apply" args "--ignore-space-change" "-")) + (kill-buffer buf))))) + +(defun magit-insert-diff-item-patch (diff buf) + (magit-insert-region (magit-section-content-beginning diff) + (magit-section-end diff) + buf)) + +(defun magit-insert-hunk-item-patch (hunk buf) + (magit-diff-item-insert-header (magit-section-parent hunk) buf) + (magit-insert-region (magit-section-beginning hunk) + (magit-section-end hunk) + buf)) + +(defun magit-insert-hunk-item-region-patch (hunk reverse beg end buf) + (magit-diff-item-insert-header (magit-section-parent hunk) buf) + (save-excursion + (goto-char (magit-section-beginning hunk)) + (magit-insert-current-line buf) + (forward-line) + (let ((copy-op (if reverse "+" "-"))) + (while (< (point) (magit-section-end hunk)) + (cond ((and (<= beg (point)) (< (point) end)) + (magit-insert-current-line buf)) + ((looking-at " ") + (magit-insert-current-line buf)) + ((looking-at copy-op) + (let ((text (buffer-substring-no-properties + (+ (point) 1) (line-beginning-position 2)))) + (with-current-buffer buf + (insert " " text))))) + (forward-line)))) + (with-current-buffer buf + (diff-fixup-modifs (point-min) (point-max)))) + +(defun magit-diff-item-insert-header (diff buf) + (magit-insert-region (magit-section-content-beginning diff) + (if (magit-section-children diff) + (magit-section-beginning + (car (magit-section-children diff))) + (magit-section-end diff)) + buf)) + +(defun magit-insert-region (beg end buf) + (let ((text (buffer-substring-no-properties beg end))) + (with-current-buffer buf + (insert text)))) + +(defun magit-insert-current-line (buf) + (let ((text (buffer-substring-no-properties + (line-beginning-position) (line-beginning-position 2)))) + (with-current-buffer buf + (insert text)))) + +(defun magit-revert-backup (buffer args) + (when (and magit-revert-backup (member "--reverse" args)) + (with-current-buffer buffer + (let ((buffer-file-name (magit-git-dir magit-revert-backup-file)) + (make-backup-files t) + (backup-directory-alist nil) + (version-control t) + (kept-old-versions 0) + (kept-new-versions 10)) + (make-directory (file-name-directory buffer-file-name) t) + (save-buffer 16))))) + +;;;; Visit + +(defun magit-visit-item (&optional other-window) + "Visit current item. +With a prefix argument, visit in other window." + (interactive "P") + (magit-section-action visit (info parent-info) + ((diff diffstat [file untracked]) + (magit-visit-file-item info other-window)) + (hunk (magit-visit-file-item parent-info other-window + (magit-hunk-item-target-line it) + (current-column))) + (commit (magit-show-commit info)) + (stash (magit-diff-stash info)) + (branch (magit-checkout info)))) + +(defun magit-visit-file-item (file &optional other-window line column) + (unless file + (user-error "Can't get pathname for this file")) + (unless (file-exists-p file) + (user-error "Can't visit deleted file: %s" file)) + (if (file-directory-p file) + (progn + (setq file (file-name-as-directory (expand-file-name file))) + (if (equal (magit-get-top-dir (file-name-directory file)) + (magit-get-top-dir)) + (magit-dired-jump other-window) + (magit-status file (if other-window + 'pop-to-buffer + 'switch-to-buffer)))) + (if other-window + (find-file-other-window file) + (find-file file)) + (when line + (goto-char (point-min)) + (forward-line (1- line)) + (when (> column 0) + (move-to-column (1- column)))))) + +(defun magit-hunk-item-target-line (hunk) + (save-excursion + (beginning-of-line) + (let ((line (line-number-at-pos))) + (goto-char (magit-section-beginning hunk)) + (unless (looking-at "@@+ .* \\+\\([0-9]+\\)\\(,[0-9]+\\)? @@+") + (user-error "Hunk header not found")) + (let ((target (string-to-number (match-string 1)))) + (forward-line) + (while (< (line-number-at-pos) line) + ;; XXX - deal with combined diffs + (unless (looking-at "-") + (setq target (+ target 1))) + (forward-line)) + target)))) + +;;;###autoload +(defun magit-dired-jump (&optional other-window) + "Visit current item in dired. +With a prefix argument, visit in other window." + (interactive "P") + (require 'dired-x) + (dired-jump other-window + (file-truename + (magit-section-action dired-jump (info parent-info) + ([file untracked] info) + ((diff diffstat) info) + (hunk parent-info) + (t default-directory))))) + +(defvar-local magit-file-log-file nil) +(defvar-local magit-show-current-version nil) + +;;;###autoload +(defun magit-show (rev file &optional switch-function) + "Display and select a buffer containing FILE as stored in REV. + +Insert the contents of FILE as stored in the revision REV into a +buffer. Then select the buffer using `pop-to-buffer' or with a +prefix argument using `switch-to-buffer'. Non-interactivity use +SWITCH-FUNCTION to switch to the buffer, if that is nil simply +return the buffer, without displaying it." + ;; REV may also be one of the symbols `index' or `working' but + ;; that is only intended for use by `magit-ediff'. + (interactive + (let (rev file section) + (magit-section-case (info parent) + (commit (setq file magit-file-log-file rev info)) + (hunk (setq section parent)) + (diff (setq section it))) + (if section + (setq rev (car (magit-diff-range section)) + file (magit-section-info section)) + (unless rev + (setq rev (magit-get-current-branch)))) + (setq rev (magit-read-rev "Retrieve file from revision" rev) + file (cl-case rev + (working (read-file-name "Find file: ")) + (index (magit-read-file-from-rev "HEAD" file)) + (t (magit-read-file-from-rev rev file)))) + (list rev file (if current-prefix-arg + 'switch-to-buffer + 'pop-to-buffer)))) + (let (buffer) + (if (eq rev 'working) + (setq buffer (find-file-noselect file)) + (let ((name (format "%s.%s" file + (if (symbolp rev) + (format "@{%s}" rev) + (replace-regexp-in-string "/" ":" rev))))) + (setq buffer (get-buffer name)) + (when buffer + (with-current-buffer buffer + (if (and (equal file magit-file-name) + (equal rev magit-show-current-version)) + (let ((inhibit-read-only t)) + (erase-buffer)) + (setq buffer nil)))) + (with-current-buffer + (or buffer (setq buffer (create-file-buffer name))) + (setq buffer-read-only t) + (with-silent-modifications + (if (eq rev 'index) + (let ((temp (car (split-string + (magit-git-string "checkout-index" + "--temp" file) + "\t"))) + (inhibit-read-only t)) + (insert-file-contents temp nil nil nil t) + (delete-file temp)) + (magit-git-insert "cat-file" "-p" (concat rev ":" file)))) + (let ((buffer-file-name (expand-file-name file (magit-get-top-dir)))) + (normal-mode t)) + (setq magit-file-name file) + (setq magit-show-current-version rev) + (goto-char (point-min))))) + (when switch-function + (with-current-buffer buffer + (funcall switch-function (current-buffer)))) + buffer)) + +;;;; Act +;;;;; Merging + +;;;###autoload +(defun magit-merge (revision &optional do-commit) + "Merge REVISION into the current 'HEAD', leaving changes uncommitted. +With a prefix argument, skip editing the log message and commit. +\('git merge [--no-commit] REVISION')." + (interactive (list (magit-read-rev "Merge" + (or (magit-guess-branch) + (magit-get-previous-branch))) + current-prefix-arg)) + (when (or (not (magit-anything-modified-p)) + (not magit-merge-warn-dirty-worktree) + (yes-or-no-p + "Running merge in a dirty worktree could cause data loss. Continue?")) + (magit-run-git "merge" revision magit-custom-options + (unless do-commit "--no-commit")) + (when (file-exists-p ".git/MERGE_MSG") + (let ((magit-custom-options nil)) + (magit-commit))))) + +;;;###autoload +(defun magit-merge-abort () + "Abort the current merge operation." + (interactive) + (if (file-exists-p (magit-git-dir "MERGE_HEAD")) + (when (yes-or-no-p "Abort merge? ") + (magit-run-git-async "merge" "--abort")) + (user-error "No merge in progress"))) + +;;;;; Branching + +;;;###autoload +(defun magit-checkout (revision) + "Switch 'HEAD' to REVISION and update working tree. +Fails if working tree or staging area contain uncommitted changes. +If REVISION is a remote branch, offer to create a local branch. +\('git checkout [-b] REVISION')." + (interactive + (list (let ((current-branch (magit-get-current-branch)) + (default (or (magit-guess-branch) + (magit-get-previous-branch)))) + (magit-read-rev (format "Switch from '%s' to" current-branch) + (unless (string= current-branch default) + default) + current-branch)))) + (magit-save-some-buffers) + (or (and (string-match "^\\(?:refs/\\)?remotes/\\([^/]+\\)/\\(.+\\)" revision) + (let ((remote (match-string 1 revision)) + (branch (match-string 2 revision))) + (and (yes-or-no-p (format "Create local branch for %s? " branch)) + (let ((local (read-string + (format "Call local branch (%s): " branch) + nil nil branch))) + (if (magit-ref-exists-p (concat "refs/heads/" local)) + (user-error "'%s' already exists" local) + (magit-run-git "checkout" "-b" local revision) + t))))) + (magit-run-git "checkout" revision))) + +;;;###autoload +(defun magit-create-branch (branch parent) + "Switch 'HEAD' to new BRANCH at revision PARENT and update working tree. +Fails if working tree or staging area contain uncommitted changes. +\('git checkout -b BRANCH REVISION')." + (interactive + (list (read-string "Create branch: ") + (magit-read-rev "Parent" (or (magit-guess-branch) + (magit-get-current-branch))))) + (cond ((run-hook-with-args-until-success + 'magit-create-branch-hook branch parent)) + ((and branch (not (string= branch ""))) + (magit-save-some-buffers) + (magit-run-git "checkout" magit-custom-options + "-b" branch parent)))) + +;;;###autoload +(defun magit-delete-branch (branch &optional force) + "Delete the BRANCH. +If the branch is the current one, offers to switch to `master' first. +With prefix, forces the removal even if it hasn't been merged. +Works with local or remote branches. +\('git branch [-d|-D] BRANCH' or 'git push :refs/heads/BRANCH')." + (interactive (list (magit-read-rev "Branch to delete" + (or (magit-guess-branch) + (magit-get-previous-branch))) + current-prefix-arg)) + (if (string-match "^\\(?:refs/\\)?remotes/\\([^/]+\\)/\\(.+\\)" branch) + (magit-run-git-async "push" + (match-string 1 branch) + (concat ":" (match-string 2 branch))) + (let* ((current (magit-get-current-branch)) + (is-current (string= branch current)) + (is-master (string= branch "master")) + (args (list "branch" + (if force "-D" "-d") + branch))) + (cond + ((and is-current is-master) + (message "Cannot delete master branch while it's checked out.")) + (is-current + (if (and (magit-ref-exists-p "refs/heads/master") + (y-or-n-p "Cannot delete current branch. Switch to master first? ")) + (progn + (magit-checkout "master") + (magit-run-git args)) + (message "The current branch was not deleted."))) + (t + (magit-run-git args)))))) + +;;;###autoload +(defun magit-rename-branch (old new &optional force) + "Rename branch OLD to NEW. +With prefix, forces the rename even if NEW already exists. +\('git branch [-m|-M] OLD NEW')." + (interactive + (let* ((old (magit-read-rev-with-default "Old name")) + (new (read-string "New name: " old))) + (list old new current-prefix-arg))) + (if (or (null new) (string= new "") + (string= old new)) + (message "Cannot rename branch \"%s\" to \"%s\"." old new) + (magit-run-git "branch" (if force "-M" "-m") old new))) + +(defun magit-guess-branch () + "Return a branch name depending on the context of cursor. +If no branch is found near the cursor return nil." + (magit-section-case (info parent-info) + (branch info) + ([commit wazzup] parent-info) + ([commit ] (magit-name-rev info)) + ([ wazzup] info))) + +;;;;; Remoting + +;;;###autoload +(defun magit-add-remote (remote url) + "Add the REMOTE and fetch it. +\('git remote add REMOTE URL')." + (interactive (list (read-string "Remote name: ") + (read-string "Remote url: "))) + (magit-run-git-async "remote" "add" "-f" remote url)) + +;;;###autoload +(defun magit-remove-remote (remote) + "Delete the REMOTE. +\('git remote rm REMOTE')." + (interactive (list (magit-read-remote "Delete remote"))) + (magit-run-git "remote" "rm" remote)) + +;;;###autoload +(defun magit-rename-remote (old new) + "Rename remote OLD to NEW. +\('git remote rename OLD NEW')." + (interactive + (let* ((old (magit-read-remote "Old name")) + (new (read-string "New name: " old))) + (list old new))) + (if (or (null old) (string= old "") + (null new) (string= new "") + (string= old new)) + (message "Cannot rename remote \"%s\" to \"%s\"." old new) + (magit-run-git "remote" "rename" old new))) + +(defun magit-guess-remote () + (magit-section-case (info parent-info) + (remote info) + (branch parent-info) + (t (if (string= info ".") info (magit-get-current-remote))))) + +;;;;; Rebase + +(defun magit-rebase-info () + "Return a list indicating the state of an in-progress rebase. + +The returned list has the form (ONTO DONE TOTAL STOPPED AM). +ONTO is the commit being rebased onto. +DONE and TOTAL are integers with obvious meanings. +STOPPED is the SHA-1 of the commit at which rebase stopped. +AM is non-nil if the current rebase is actually a git-am. + +Return nil if there is no rebase in progress." + (let ((m (magit-git-dir "rebase-merge")) + (a (magit-git-dir "rebase-apply"))) + (cond + ((file-directory-p m) ; interactive + (list + (magit-name-rev (magit-file-line (expand-file-name "onto" m))) + (length (magit-file-lines (expand-file-name "done" m))) + (cl-loop for line in (magit-file-lines + (expand-file-name "git-rebase-todo.backup" m)) + count (string-match "^[^#\n]" line)) + (magit-file-line (expand-file-name "stopped-sha" m)) + nil)) + + ((file-regular-p (expand-file-name "onto" a)) ; non-interactive + (list + (magit-name-rev (magit-file-line (expand-file-name "onto" a))) + (1- (string-to-number (magit-file-line (expand-file-name "next" a)))) + (string-to-number (magit-file-line (expand-file-name "last" a))) + (let ((patch-header (magit-file-line + (car (directory-files a t "^[0-9]\\{4\\}$"))))) + (when (string-match "^From \\([a-z0-9]\\{40\\}\\) " patch-header) + (match-string 1 patch-header))) + nil)) + + ((file-regular-p (expand-file-name "applying" a)) ; am + (list + (magit-name-rev "HEAD") + (1- (string-to-number (magit-file-line (expand-file-name "next" a)))) + (string-to-number (magit-file-line (expand-file-name "last" a))) + (let ((patch-header (magit-file-line + (car (directory-files a t "^[0-9]\\{4\\}$"))))) + (when (string-match "^From \\([a-z0-9]\\{40\\}\\) " patch-header) + (match-string 1 patch-header))) + t))))) + +(defun magit-rebase-step () + "Initiate or continue a rebase." + (interactive) + (let ((rebase (magit-rebase-info))) + (if rebase + (let ((cursor-in-echo-area t) + (message-log-max nil) + (am (nth 4 rebase))) + (message "%s in progress. [A]bort, [S]kip, or [C]ontinue? " + (if am "Apply mailbox" "Rebase")) + (cl-case (read-event) + ((?A ?a) (magit-run-git-async (if am "am" "rebase") "--abort")) + ((?S ?s) (magit-run-git-async (if am "am" "rebase") "--skip")) + ((?C ?c) (magit-with-emacsclient magit-server-window-for-commit + (magit-run-git-async (if am "am" "rebase") "--continue"))))) + (let* ((branch (magit-get-current-branch)) + (rev (magit-read-rev + "Rebase to" + (magit-get-tracked-branch branch) + branch))) + (magit-run-git "rebase" rev))))) + +;;;###autoload +(defun magit-interactive-rebase (commit) + "Start a git rebase -i session, old school-style." + (interactive (let ((commit (magit-section-case (info) (commit info)))) + (list (if commit + (concat commit "^") + (magit-read-rev "Interactively rebase to" + (magit-guess-branch)))))) + (magit-assert-emacsclient "rebase interactively") + (magit-with-emacsclient magit-server-window-for-rebase + (magit-run-git-async "rebase" "-i" commit))) + +;;;;; AM + +(defun magit-apply-mailbox (&optional file-or-dir) + "Apply a series of patches from a mailbox." + (interactive "fmbox or Maildir file or directory: ") + (magit-with-emacsclient magit-server-window-for-rebase + (magit-run-git-async "am" file-or-dir))) + +;;;;; Reset + +;;;###autoload +(defun magit-reset-head (revision &optional hard) + "Switch 'HEAD' to REVISION, keeping prior working tree and staging area. +Any differences from REVISION become new changes to be committed. +With prefix argument, all uncommitted changes in working tree +and staging area are lost. +\('git reset [--soft|--hard] REVISION')." + (interactive (list (magit-read-rev (format "%s head to" + (if current-prefix-arg + "Hard reset" + "Reset")) + (or (magit-guess-branch) "HEAD")) + current-prefix-arg)) + (magit-run-git "reset" (if hard "--hard" "--soft") revision "--")) + +;;;###autoload +(defun magit-reset-head-hard (revision) + "Switch 'HEAD' to REVISION, losing all changes. +Uncomitted changes in both working tree and staging area are lost. +\('git reset --hard REVISION')." + (interactive (list (magit-read-rev (format "Hard reset head to") + (or (magit-guess-branch) "HEAD")))) + (magit-reset-head revision t)) + +;;;###autoload +(defun magit-reset-working-tree (&optional arg) + "Revert working tree and clear changes from staging area. +\('git reset --hard HEAD'). + +With a prefix arg, also remove untracked files. +With two prefix args, remove ignored files as well." + (interactive "p") + (let ((include-untracked (>= arg 4)) + (include-ignored (>= arg 16))) + (when (yes-or-no-p (format "Discard all uncommitted changes%s%s? " + (if include-untracked + ", untracked files" + "") + (if include-ignored + ", ignored files" + ""))) + (magit-reset-head-hard "HEAD") + (when include-untracked + (magit-run-git "clean" "-fd" (if include-ignored "-x" "")))))) + +;;;;; Rewriting + +(defun magit-read-rewrite-info () + (when (file-exists-p (magit-git-dir "magit-rewrite-info")) + (with-temp-buffer + (insert-file-contents (magit-git-dir "magit-rewrite-info")) + (goto-char (point-min)) + (read (current-buffer))))) + +(defun magit-write-rewrite-info (info) + (with-temp-file (magit-git-dir "magit-rewrite-info") + (prin1 info (current-buffer)) + (princ "\n" (current-buffer)))) + +(defun magit-rewrite-set-commit-property (commit prop value) + (let* ((info (magit-read-rewrite-info)) + (pending (cdr (assq 'pending info))) + (p (assoc commit pending))) + (when p + (setf (cdr p) (plist-put (cdr p) prop value)) + (magit-write-rewrite-info info) + (magit-refresh)) + t)) + +(add-hook 'magit-apply-hook 'magit-rewrite-apply) +(put 'magit-rewrite-apply 'magit-section-action-context [commit pending]) +(defun magit-rewrite-apply (commit) + (magit-apply-commit commit) + (magit-rewrite-set-commit-property commit 'used t)) + +(add-hook 'magit-cherry-pick-hook 'magit-rewrite-pick) +(put 'magit-rewrite-pick 'magit-section-action-context [commit pending]) +(defun magit-rewrite-pick (commit) + (magit-cherry-pick-commit commit) + (magit-rewrite-set-commit-property commit 'used t)) + +(add-hook 'magit-revert-hook 'magit-rewrite-revert) +(put 'magit-rewrite-revert 'magit-section-action-context [commit pending]) +(defun magit-rewrite-revert (commit) + (when (or (not magit-revert-item-confirm) + (yes-or-no-p "Revert this commit? ")) + (magit-revert-commit commit) + (magit-rewrite-set-commit-property commit 'used nil))) + +(defun magit-rewrite-set-used () + (interactive) + (magit-section-case (info) + ([commit pending] + (magit-rewrite-set-commit-property info 'used t) + (magit-refresh)))) + +(defun magit-rewrite-set-unused () + (interactive) + (magit-section-case (info) + ([commit pending] + (magit-rewrite-set-commit-property info 'used nil) + (magit-refresh)))) + +(defun magit-rewrite-start (from &optional onto) + (interactive (list (magit-read-rev-with-default "Rewrite from"))) + (when (magit-anything-modified-p) + (user-error "You have uncommitted changes")) + (or (not (magit-read-rewrite-info)) + (user-error "Rewrite in progress")) + (let* ((orig (magit-rev-parse "HEAD")) + (base (if (or (eq magit-rewrite-inclusive t) + (and (eq magit-rewrite-inclusive 'ask) + (y-or-n-p "Include selected revision in rewrite? "))) + (or (car (magit-commit-parents from)) + (user-error "Can't rewrite a parentless commit")) + from)) + (pending (magit-git-lines "rev-list" (concat base "..")))) + (magit-write-rewrite-info `((orig ,orig) + (pending ,@(mapcar #'list pending)))) + (magit-run-git "reset" "--hard" base "--"))) + +(defun magit-rewrite-stop (&optional noconfirm) + (interactive) + (let* ((info (magit-read-rewrite-info))) + (or info + (user-error "No rewrite in progress")) + (when (or noconfirm + (yes-or-no-p "Stop rewrite? ")) + (magit-write-rewrite-info nil) + (magit-refresh)))) + +(defun magit-rewrite-abort () + (interactive) + (let* ((info (magit-read-rewrite-info)) + (orig (cadr (assq 'orig info)))) + (or info + (user-error "No rewrite in progress")) + (when (magit-anything-modified-p) + (user-error "You have uncommitted changes")) + (when (yes-or-no-p "Abort rewrite? ") + (magit-write-rewrite-info nil) + (magit-run-git "reset" "--hard" orig "--")))) + +(defun magit-rewrite-finish () + (interactive) + (magit-rewrite-finish-step) + (magit-refresh)) + +(defun magit-rewrite-finish-step () + (let ((info (magit-read-rewrite-info))) + (or info + (user-error "No rewrite in progress")) + (let* ((pending (cdr (assq 'pending info))) + (first-unused + (let ((rpend (reverse pending))) + (while (and rpend (plist-get (cdr (car rpend)) 'used)) + (setq rpend (cdr rpend))) + (car rpend))) + (commit (car first-unused))) + (cond ((not first-unused) + (magit-rewrite-stop t)) + ((magit-git-success "cherry-pick" commit) + (magit-rewrite-set-commit-property commit 'used t) + (magit-rewrite-finish-step)) + (t + (magit-refresh) + (error "Could not apply %s" commit)))))) + +(defun magit-rewrite-diff-pending () + (interactive) + (let* ((info (magit-read-rewrite-info)) + (orig (cadr (assq 'orig info)))) + (if orig + (magit-diff orig nil "-R") + (user-error "No rewrite in progress")))) + +(defun magit-rewrite-diff-pending-transition () + (interactive) + (message "Please remove magit-insert-pending-changes from your magit-status-sections-hook, or move to magit-rewrite-diff-pending")) + +(define-obsolete-function-alias + 'magit-insert-pending-changes 'magit-rewrite-diff-pending-transition + "382351845e" + "https://github.com/magit/magit/commit/382351845eca2425713f640f9bb55756c9ddf723") + +;;;;; Fetching + +;;;###autoload +(defun magit-fetch (remote) + "Fetch from REMOTE." + (interactive (list (magit-read-remote "Fetch remote"))) + (magit-run-git-async "fetch" remote magit-custom-options)) + +;;;###autoload +(defun magit-fetch-current () + "Run fetch for default remote. + +If there is no default remote, ask for one." + (interactive) + (magit-fetch (or (magit-get-current-remote) + (magit-read-remote "Fetch remote")))) + +;;;###autoload +(defun magit-remote-update () + "Update all remotes." + (interactive) + (or (run-hook-with-args-until-success 'magit-remote-update-hook) + (magit-run-git-async "remote" "update" magit-custom-options))) + +;;;;; Pulling + +;;;###autoload +(defun magit-pull () + "Run git pull. + +If there is no default remote, the user is prompted for one and +its values is saved with git config. If there is no default +merge branch, the user is prompted for one and its values is +saved with git config. With a prefix argument, the default +remote is not used and the user is prompted for a remote. With +two prefix arguments, the default merge branch is not used and +the user is prompted for a merge branch. Values entered by the +user because of prefix arguments are not saved with git config." + (interactive) + (or (run-hook-with-args-until-success 'magit-pull-hook) + (let* ((branch (magit-get-current-branch)) + (branch-remote (magit-get-remote branch)) + (branch-merge (magit-get "branch" branch "merge")) + (branch-merge-name (and branch-merge + (save-match-data + (string-match "^refs/heads/\\(.+\\)" branch-merge) + (match-string 1 branch-merge)))) + (choose-remote (>= (prefix-numeric-value current-prefix-arg) 4)) + (choose-branch (>= (prefix-numeric-value current-prefix-arg) 16)) + (remote-needed (or choose-remote + (not branch-remote))) + (branch-needed (or choose-branch + (not branch-merge-name))) + (chosen-branch-remote + (if remote-needed + (magit-read-remote "Pull from remote" branch-remote) + branch-remote)) + (chosen-branch-merge-name + (if branch-needed + (magit-read-remote-branch (format "Pull branch from remote %s" + chosen-branch-remote) + chosen-branch-remote) + branch-merge-name))) + (when (and (not branch-remote) + (not choose-remote)) + (magit-set chosen-branch-remote "branch" branch "remote")) + (when (and (not branch-merge-name) + (not choose-branch)) + (magit-set (format "%s" chosen-branch-merge-name) + "branch" branch "merge")) + (magit-run-git-async + "pull" magit-custom-options + (and choose-remote chosen-branch-remote) + (and (or choose-remote choose-branch) + (list (format "refs/heads/%s:refs/remotes/%s/%s" + chosen-branch-merge-name + chosen-branch-remote + chosen-branch-merge-name))))))) + +;;;;; Pushing + +;;;###autoload +(defun magit-push-tags () + "Push tags to a remote repository. + +Push tags to the current branch's remote. If that isn't set push +to \"origin\" or if that remote doesn't exit but only a single +remote is defined use that. Otherwise or with a prefix argument +ask the user what remote to use." + (interactive) + (let* ((branch (magit-get-current-branch)) + (remotes (magit-git-lines "remote")) + (remote (or (and branch (magit-get-remote branch)) + (car (member "origin" remotes)) + (and (= (length remotes) 1) + (car remotes))))) + (when (or current-prefix-arg (not remote)) + (setq remote (magit-read-remote "Push to remote"))) + (magit-run-git-async "push" remote "--tags" magit-custom-options))) + +;;;###autoload +(defun magit-push () + "Push the current branch to a remote repository. + +This command runs the `magit-push-remote' hook. By default that +means running `magit-push-dwim'. So unless you have customized +the hook this command behaves like this: + +With a single prefix argument ask the user what branch to push +to. With two or more prefix arguments also ask the user what +remote to push to. Otherwise use the remote and branch as +configured using the Git variables `branch..remote' and +`branch..merge'. If the former is undefined ask the user. +If the latter is undefined push without specifing the remote +branch explicitly. + +Also see option `magit-set-upstream-on-push'." + (interactive) + (run-hook-with-args-until-success 'magit-push-hook current-prefix-arg)) + +(defun magit-push-dwim (arg) + "Push the current branch to a remote repository. + +With a single prefix argument ask the user what remote to push +to. With two or more prefix arguments also ask the user the +name of the remote branch to push to. + +Otherwise use the remote and branch as configured using the +Git variables `branch..remote' and `branch..merge'. +If the former is undefined ask the user. If the latter is +undefined push without specifing the remote branch explicitly. + +Also see option `magit-set-upstream-on-push'." + (interactive "P") + (let* ((branch (or (magit-get-current-branch) + (user-error "Don't push a detached head. That's gross"))) + (auto-remote (magit-get-remote branch)) + (used-remote (if (or arg (not auto-remote)) + (magit-read-remote + (format "Push %s to remote" branch) auto-remote) + auto-remote)) + (auto-branch (and (equal used-remote auto-remote) + (magit-get "branch" branch "merge"))) + (used-branch (if (>= (prefix-numeric-value arg) 16) + (magit-read-remote-branch + (format "Push %s as branch" branch) + used-remote auto-branch) + auto-branch))) + (cond ;; Pushing to what's already configured. + ((and auto-branch + (equal auto-branch used-branch) + (equal auto-remote used-remote))) + ;; Setting upstream because of magit-custom-options. + ((member "-u" magit-custom-options)) + ;; Two prefix arguments; ignore magit-set-upstream-on-push. + ((>= (prefix-numeric-value arg) 16) + (and (yes-or-no-p "Set upstream while pushing? ") + (setq magit-custom-options + (cons "-u" magit-custom-options)))) + ;; Else honor magit-set-upstream-on-push. + ((eq magit-set-upstream-on-push 'refuse) + (user-error "Not pushing since no upstream has been set.")) + ((or (eq magit-set-upstream-on-push 'dontask) + (and (eq magit-set-upstream-on-push t) + (yes-or-no-p "Set upstream while pushing? "))) + (setq magit-custom-options (cons "-u" magit-custom-options)))) + (magit-run-git-async + "push" "-v" used-remote + (if used-branch (format "%s:%s" branch used-branch) branch) + magit-custom-options))) + +;;;;; Committing + +;;;###autoload +(defun magit-commit (&optional amendp) + "Create a new commit on HEAD. +With a prefix argument amend to the commit at HEAD instead. +\('git commit [--amend]')." + (interactive "P") + (let ((args magit-custom-options)) + (when amendp + (setq args (cons "--amend" args))) + (when (setq args (magit-commit-assert args)) + (magit-commit-maybe-expand) + (magit-commit-internal "commit" args)))) + +;;;###autoload +(defun magit-commit-amend () + "Amend the last commit. +\('git commit --amend')." + (interactive) + (magit-commit-maybe-expand) + (magit-commit-internal "commit" (cons "--amend" magit-custom-options))) + +;;;###autoload +(defun magit-commit-extend (&optional override-date) + "Amend the last commit, without editing the message. +With a prefix argument do change the committer date, otherwise +don't. The option `magit-commit-extend-override-date' can be +used to inverse the meaning of the prefix argument. +\('git commit --no-edit --amend [--keep-date]')." + (interactive (list (if current-prefix-arg + (not magit-commit-reword-override-date) + magit-commit-reword-override-date))) + (magit-commit-maybe-expand) + (let ((process-environment process-environment)) + (unless override-date + (setenv "GIT_COMMITTER_DATE" + (magit-git-string "log" "-1" "--format:format=%cd"))) + (magit-commit-internal "commit" (nconc (list "--no-edit" "--amend") + magit-custom-options)))) + +;;;###autoload +(defun magit-commit-reword (&optional override-date) + "Reword the last commit, ignoring staged changes. + +With a prefix argument do change the committer date, otherwise +don't. The option `magit-commit-rewrite-override-date' can be +used to inverse the meaning of the prefix argument. + +Non-interactively respect the optional OVERRIDE-DATE argument +and ignore the option. + +\('git commit --only --amend')." + (interactive (list (if current-prefix-arg + (not magit-commit-reword-override-date) + magit-commit-reword-override-date))) + (let ((process-environment process-environment)) + (unless override-date + (setenv "GIT_COMMITTER_DATE" + (magit-git-string "log" "-1" "--format:format=%cd"))) + (magit-commit-internal "commit" (nconc (list "--only" "--amend") + magit-custom-options)))) + +(defvar-local magit-commit-squash-args nil) +(defvar-local magit-commit-squash-fixup nil) + +(defvar magit-commit-unmark-after-squash t) + +;;;###autoload +(defun magit-commit-fixup (&optional commit) + "Create a fixup commit. +With a prefix argument the user is always queried for the commit +to be fixed. Otherwise the current or marked commit may be used +depending on the value of option `magit-commit-squash-commit'. +\('git commit [--no-edit] --fixup=COMMIT')." + (interactive (list (magit-commit-squash-commit))) + (magit-commit-squash commit t)) + +;;;###autoload +(defun magit-commit-squash (&optional commit fixup) + "Create a squash commit. +With a prefix argument the user is always queried for the commit +to be fixed. Otherwise the current or marked commit may be used +depending on the value of option `magit-commit-squash-commit'. +\('git commit [--no-edit] --fixup=COMMIT')." + (interactive (list (magit-commit-squash-commit))) + (let ((args magit-custom-options)) + (cond + ((not commit) + (magit-commit-assert args) + (magit-log) + (setq magit-commit-squash-args args + magit-commit-squash-fixup fixup) + (add-hook 'magit-mark-commit-hook 'magit-commit-squash-marked t t) + (add-hook 'magit-mode-quit-window-hook 'magit-commit-squash-abort t t) + (message "Select commit using \".\", or abort using \"q\"")) + ((setq args (magit-commit-assert args)) + (when (eq args t) (setq args nil)) + (magit-commit-internal + "commit" + (nconc (list "--no-edit" + (concat (if fixup "--fixup=" "--squash=") commit)) + args)))))) + +(defun magit-commit-squash-commit () + (unless (or current-prefix-arg + (eq magit-commit-squash-commit nil)) + (let ((current (magit-section-case (info) (commit info)))) + (cl-ecase magit-commit-squash-commit + (current-or-marked (or current magit-marked-commit)) + (marked-or-current (or magit-marked-commit current)) + (current current) + (marked magit-marked-commit))))) + +(defun magit-commit-squash-marked () + (when magit-marked-commit + (magit-commit-squash magit-marked-commit magit-commit-squash-fixup)) + (when magit-commit-unmark-after-squash + (setq magit-marked-commit nil)) + (kill-local-variable 'magit-commit-squash-fixup) + (remove-hook 'magit-mark-commit-hook 'magit-commit-squash-marked t) + (remove-hook 'magit-mode-quit-window-hook 'magit-commit-squash-abort t) + (magit-mode-quit-window)) + +(defun magit-commit-squash-abort (buffer) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (remove-hook 'magit-mark-commit-hook 'magit-commit-squash-marked t) + (remove-hook 'magit-mode-quit-window-hook 'magit-commit-squash-abort t)))) + +(defun magit-commit-assert (args) + (cond + ((or (magit-anything-staged-p) + (member "--allow-empty" args) + (member "--all" args) + (member "--amend" args)) + (or args (list "--"))) + ((and (magit-rebase-info) + (y-or-n-p "Nothing staged. Continue in-progress rebase? ")) + (magit-run-git-async "rebase" "--continue") + nil) + (magit-commit-ask-to-stage + (magit-commit-maybe-expand t) + (when (y-or-n-p "Nothing staged. Stage and commit everything? ") + (magit-run-git "add" "-u" ".") + (or args (list "--")))) + (t + (user-error "Nothing staged. Set --allow-empty, --all, or --amend in popup")))) + +(defun magit-commit-maybe-expand (&optional unstaged) + (when (and magit-expand-staged-on-commit + (derived-mode-p 'magit-status-mode)) + (if unstaged + (magit-jump-to-unstaged t) + (magit-jump-to-staged t)))) + +(defun magit-commit-internal (subcmd args) + (setq git-commit-previous-winconf (current-window-configuration)) + (if (magit-use-emacsclient-p) + (magit-with-emacsclient magit-server-window-for-commit + (magit-run-git-async subcmd args)) + (let ((topdir (magit-get-top-dir)) + (editmsg (magit-git-dir (if (equal subcmd "tag") + "TAG_EDITMSG" + "COMMIT_EDITMSG")))) + (when (and (member "--amend" args) + (not (file-exists-p editmsg))) + (with-temp-file editmsg + (magit-git-insert "log" "-1" "--format=format:%B" "HEAD"))) + (with-current-buffer (find-file-noselect editmsg) + (funcall (if (functionp magit-server-window-for-commit) + magit-server-window-for-commit + 'switch-to-buffer) + (current-buffer)) + (add-hook 'git-commit-commit-hook + (apply-partially + (lambda (default-directory editmsg args) + (magit-run-git args) + (ignore-errors (delete-file editmsg))) + topdir editmsg + `(,subcmd + ,"--cleanup=strip" + ,(concat "--file=" (file-relative-name + (buffer-file-name) + topdir)) + ,@args)) + nil t))))) + +(defun magit-commit-add-log () + "Add a template for the current hunk to the commit message buffer." + (interactive) + (let* ((section (magit-current-section)) + (fun (if (eq (magit-section-type section) 'hunk) + (save-window-excursion + (save-excursion + (magit-visit-item) + (add-log-current-defun))) + nil)) + (file (magit-section-info + (cl-case (magit-section-type section) + (hunk (magit-section-parent section)) + (diff section) + (t (user-error "No change at point"))))) + (locate-buffer (lambda () + (cl-find-if + (lambda (buf) + (with-current-buffer buf + (derived-mode-p 'git-commit-mode))) + (append (buffer-list (selected-frame)) + (buffer-list))))) + (buffer (funcall locate-buffer))) + (unless buffer + (unless (magit-commit-assert nil) + (user-error "Abort")) + (magit-commit) + (while (not (setq buffer (funcall locate-buffer))) + (sit-for 0.01))) + (pop-to-buffer buffer) + (goto-char (point-min)) + (cond ((not (re-search-forward (format "^\\* %s" (regexp-quote file)) + nil t)) + ;; No entry for file, create it. + (goto-char (point-max)) + (forward-comment -1000) + (unless (or (bobp) (looking-back "\\(\\*[^\n]+\\|\n\\)")) + (insert "\n")) + (insert (format "\n* %s" file)) + (when fun + (insert (format " (%s)" fun))) + (insert ": ")) + (fun + ;; found entry for file, look for fun + (let ((limit (save-excursion + (or (and (re-search-forward "^\\* " nil t) + (match-beginning 0)) + (progn (goto-char (point-max)) + (forward-comment -1000) + (point)))))) + (cond ((re-search-forward + (format "(.*\\_<%s\\_>.*):" (regexp-quote fun)) + limit t) + ;; found it, goto end of current entry + (if (re-search-forward "^(" limit t) + (backward-char 2) + (goto-char limit))) + (t + ;; not found, insert new entry + (goto-char limit) + (if (bolp) + (open-line 1) + (newline)) + (insert (format "(%s): " fun)))))) + (t + ;; found entry for file, look for beginning it + (when (looking-at ":") + (forward-char 2)))))) + +;;;;; Tagging + +;;;###autoload +(defun magit-tag (name rev &optional annotate) + "Create a new tag with the given NAME at REV. +With a prefix argument annotate the tag. +\('git tag [--annotate] NAME REV')." + (interactive (list (magit-read-tag "Tag name") + (magit-read-rev "Place tag on" + (or (magit-guess-branch) "HEAD")) + current-prefix-arg)) + (let ((args (append magit-custom-options (list name rev)))) + (if (or (member "--sign" args) + (member "--annotate" args) + (and annotate (setq args (cons "--annotate" args)))) + (magit-commit-internal "tag" args) + (magit-run-git "tag" args)))) + +;;;###autoload +(defun magit-delete-tag (name) + "Delete the tag with the given NAME. +\('git tag -d NAME')." + (interactive (list (magit-read-tag "Delete Tag" t))) + (magit-run-git "tag" "-d" magit-custom-options name)) + +;;;;; Stashing + +(defvar magit-read-stash-history nil + "The history of inputs to `magit-stash'.") + +;;;###autoload +(defun magit-stash (description) + "Create new stash of working tree and staging area named DESCRIPTION. +Working tree and staging area revert to the current 'HEAD'. +With prefix argument, changes in staging area are kept. +\('git stash save [--keep-index] DESCRIPTION')" + (interactive (list (read-string "Stash description: " nil + 'magit-read-stash-history))) + (magit-run-git-async "stash" "save" magit-custom-options "--" description)) + +;;;###autoload +(defun magit-stash-snapshot () + "Create new stash of working tree and staging area; keep changes in place. +\('git stash save \"Snapshot...\"; git stash apply stash@{0}')" + (interactive) + (magit-call-git "stash" "save" magit-custom-options + (format-time-string + "Snapshot taken at %Y-%m-%d %H:%M:%S" + (current-time))) + (magit-run-git "stash" "apply" "stash@{0}")) + +(defun magit-stash-apply (stash) + "Apply a stash on top of the current working tree state. +\('git stash apply stash@{N}')" + (interactive (list (magit-read-stash "Apply stash (number): "))) + (magit-run-git "stash" "apply" stash)) + +(defun magit-stash-pop (stash) + "Apply a stash on top of working tree state and remove from stash list. +\('git stash pop stash@{N}')" + (interactive (list (magit-read-stash "Pop stash (number): "))) + (magit-run-git "stash" "pop" stash)) + +(defun magit-stash-drop (stash) + "Remove a stash from the stash list. +\('git stash drop stash@{N}')" + (interactive (list (magit-read-stash "Drop stash (number): "))) + (magit-run-git "stash" "drop" stash)) + +;;;;; Cherry-Pick + +(defun magit-cherry-pick-item () + "Cherry-pick them item at point." + (interactive) + (magit-section-action cherry-pick (info) + (commit (magit-cherry-pick-commit info)) + (stash (magit-stash-pop info)))) + +(defun magit-cherry-pick-commit (commit) + (magit-assert-one-parent commit "cherry-pick") + (magit-run-git "cherry-pick" commit)) + +;;;;; Submoduling + +;;;###autoload +(defun magit-submodule-update (&optional init) + "Update the submodule of the current git repository. +With a prefix arg, do a submodule update --init." + (interactive "P") + (let ((default-directory (magit-get-top-dir))) + (magit-run-git-async "submodule" "update" (and init "--init")))) + +;;;###autoload +(defun magit-submodule-update-init () + "Update and init the submodule of the current git repository." + (interactive) + (magit-submodule-update t)) + +;;;###autoload +(defun magit-submodule-init () + "Initialize the submodules." + (interactive) + (let ((default-directory (magit-get-top-dir))) + (magit-run-git-async "submodule" "init"))) + +;;;###autoload +(defun magit-submodule-sync () + "Synchronizes submodule's remote URL configuration." + (interactive) + (let ((default-directory (magit-get-top-dir))) + (magit-run-git-async "submodule" "sync"))) + +;;;;; Bisecting + +;;;###autoload +(defun magit-bisect-start (bad good) + "Start a bisect session. + +Bisecting a bug means to find the commit that introduced it. +This command starts such a bisect session by asking for a know +good and a bad commit. To move the session forward use the +other actions from the bisect popup (\ +\\\\[magit-key-mode-popup-bisecting])." + (interactive + (if (magit-bisecting-p) + (user-error "Already bisecting") + (list (magit-read-rev "Start bisect with known bad revision" "HEAD") + (magit-read-rev "Good revision" (magit-guess-branch))))) + (magit-run-git-bisect "start" (list bad good) t)) + +;;;###autoload +(defun magit-bisect-reset () + "After bisecting cleanup bisection state and return to original HEAD." + (interactive) + (when (yes-or-no-p "Reset bisect?") + (magit-run-git "bisect" "reset") + (ignore-errors (delete-file (magit-git-dir "BISECT_CMD_OUTPUT"))))) + +;;;###autoload +(defun magit-bisect-good () + "While bisecting, mark the current commit as good. +Use this after you have asserted that the commit does not contain +the bug in question." + (interactive) + (magit-run-git-bisect "good")) + +;;;###autoload +(defun magit-bisect-bad () + "While bisecting, mark the current commit as bad. +Use this after you have asserted that the commit does contain the +bug in question." + (interactive) + (magit-run-git-bisect "bad")) + +;;;###autoload +(defun magit-bisect-skip () + "While bisecting, skip the current commit. +Use this if for some reason the current commit is not a good one +to test. This command lets Git choose a different one." + (interactive) + (magit-run-git-bisect "skip")) + +;;;###autoload +(defun magit-bisect-run (cmdline) + "Bisect automatically by running commands after each step." + (interactive (list (read-shell-command "Bisect shell command: "))) + (magit-run-git-bisect "run" (list cmdline))) + +(defun magit-run-git-bisect (subcommand &optional args no-assert) + (unless (or no-assert (magit-bisecting-p)) + (user-error "Not bisecting")) + (let ((file (magit-git-dir "BISECT_CMD_OUTPUT")) + (default-directory (magit-get-top-dir))) + (ignore-errors (delete-file file)) + (magit-run-git-with-logfile file "bisect" subcommand args) + (magit-process-wait) + (magit-refresh))) + +;;;;; Logging + +;;;###autoload +(defun magit-log (&optional range) + (interactive) + (magit-mode-setup magit-log-buffer-name nil + #'magit-log-mode + #'magit-refresh-log-buffer + 'oneline (or range "HEAD") magit-custom-options)) + +;;;###autoload +(defun magit-log-ranged (range) + (interactive (list (magit-read-rev-range "Log" "HEAD"))) + (magit-log range)) + +;;;###autoload +(defun magit-log-long (&optional range) + (interactive) + (magit-mode-setup magit-log-buffer-name nil + #'magit-log-mode + #'magit-refresh-log-buffer + 'long (or range "HEAD") magit-custom-options)) + +;;;###autoload +(defun magit-log-long-ranged (range) + (interactive (list (magit-read-rev-range "Long Log" "HEAD"))) + (magit-log-long range)) + +;;;###autoload +(defun magit-file-log (file &optional use-graph) + "Display the log for the currently visited file or another one. +With a prefix argument show the log graph." + (interactive + (list (magit-read-file-from-rev (magit-get-current-branch) + (magit-buffer-file-name t)) + current-prefix-arg)) + (magit-mode-setup magit-log-buffer-name nil + #'magit-log-mode + #'magit-refresh-log-buffer + 'oneline "HEAD" + `(,@(and use-graph (list "--graph")) + ,@magit-custom-options + "--follow") + file)) + +;;;###autoload +(defun magit-reflog (ref) + "Display the reflog of the current branch. +With a prefix argument another branch can be chosen." + (interactive (let ((branch (magit-get-current-branch))) + (if (and branch (not current-prefix-arg)) + (list branch) + (list (magit-read-rev "Reflog of" branch))))) + (magit-mode-setup magit-reflog-buffer-name nil + #'magit-reflog-mode + #'magit-refresh-reflog-buffer ref)) + +;;;###autoload +(defun magit-reflog-head () + "Display the HEAD reflog." + (interactive) + (magit-reflog "HEAD")) + +;;; Modes (2) +;;;; Log Mode +;;;;; Log Core + +(define-derived-mode magit-log-mode magit-mode "Magit Log" + "Mode for looking at git log. + +\\Type `\\[magit-visit-item]` to visit a commit, and \ +`\\[magit-show-item-or-scroll-up]` to just show it. +Type `\\[magit-log-show-more-entries]` to show more commits, \ +and `\\[magit-refresh]` to refresh the log. +Type `\\[magit-diff-working-tree]` to see the diff between current commit and your working tree, +Type `\\[magit-diff]` to see diff between any two version +Type `\\[magit-apply-item]` to apply the change of the current commit to your wortree, +and `\\[magit-cherry-pick-item]` to apply and commit the result. +Type `\\[magit-revert-item]` to revert a commit, and `\\[magit-reset-head]` reset your current head to a commit, + +More information can be found in Info node `(magit)History' + +Other key binding: +\\{magit-log-mode-map}" + :group 'magit) + +(defvar magit-log-buffer-name "*magit-log*" + "Name of buffer used to display log entries.") + +(defun magit-refresh-log-buffer (style range args &optional file) + (magit-set-buffer-margin (car magit-log-margin-spec) + (and magit-log-show-margin + (eq (car magit-refresh-args) 'oneline))) + (magit-log-margin-set-timeunit-width) + (setq magit-file-log-file file) + (when (consp range) + (setq range (concat (car range) ".." (cdr range)))) + (magit-git-insert-section + (logbuf (concat "Commits" + (and file (concat " for file " file)) + (and range (concat " in " range)))) + (apply-partially 'magit-wash-log style 'color t) + "log" + (format "--max-count=%d" magit-log-cutoff-length) + "--decorate=full" "--color" + (cl-case style + (long (if magit-log-show-gpg-status + (list "--stat" "--show-signature") + "--stat")) + (oneline (concat "--pretty=format:%h%d " + (and magit-log-show-gpg-status "%G?") + "[%an][%at]%s"))) + args range "--" file) + (save-excursion + (goto-char (point-min)) + (magit-format-log-margin))) + +;;;;; Log Washing + +(defconst magit-log-oneline-re + (concat "^" + "\\(?4:\\(?: *[-_/|\\*o.] *\\)+ *\\)?" ; graph + "\\(?:" + "\\(?1:[0-9a-fA-F]+\\) " ; sha1 + "\\(?:\\(?3:([^()]+)\\) \\)?" ; refs + "\\(?7:[BGUN]\\)?" ; gpg + "\\[\\(?5:[^]]*\\)\\]" ; author + "\\[\\(?6:[^]]*\\)\\]" ; date + "\\(?2:.*\\)" ; msg + "\\)?$")) + +(defconst magit-log-long-re + (concat "^" + "\\(?4:\\(?:[-_/|\\*o.] *\\)+ *\\)?" ; graph + "\\(?:" + "\\(?:commit \\(?1:[0-9a-fA-F]+\\)" ; sha1 + "\\(?: \\(?3:([^()]+)\\)\\)?\\)" ; refs + "\\|" + "\\(?2:.+\\)\\)$")) ; "msg" + +(defconst magit-log-unique-re + (concat "^" + "\\(?1:[0-9a-fA-F]+\\) " ; sha1 + "\\(?2:.*\\)$")) ; msg + +(defconst magit-log-cherry-re + (concat "^" + "\\(?8:[-+]\\) " ; cherry + "\\(?1:[0-9a-fA-F]+\\) " ; sha1 + "\\(?2:.*\\)$")) ; msg + +(defconst magit-log-bisect-vis-re + (concat "^" + "\\(?1:[0-9a-fA-F]+\\) " ; sha1 + "\\(?:\\(?3:([^()]+)\\) \\)?" ; refs + "\\(?2:.+\\)$")) ; msg + +(defconst magit-log-bisect-log-re + (concat "^# " + "\\(?3:bad:\\|skip:\\|good:\\) " ; "refs" + "\\[\\(?1:[^]]+\\)\\] " ; sha1 + "\\(?2:.+\\)$")) ; msg + +(defconst magit-log-reflog-re + (concat "^" + "\\(?1:[^ ]+\\) " ; sha1 + "\\[\\(?5:[^]]*\\)\\] " ; author + "\\(?6:[^ ]*\\) " ; date + "[^@]+@{\\(?9:[^}]+\\)} " ; refsel + "\\(?10:merge\\|[^:]+\\)?:? ?" ; refsub + "\\(?2:.+\\)?$")) ; msg + +(defconst magit-reflog-subject-re + (concat "\\([^ ]+\\) ?" ; command (1) + "\\(\\(?: ?-[^ ]+\\)+\\)?" ; option (2) + "\\(?: ?(\\([^)]+\\))\\)?")) ; type (3) + +(defvar magit-log-count nil) + +(defun magit-wash-log (style &optional color longer) + (when color + (let ((ansi-color-apply-face-function + (lambda (beg end face) + (when face + (put-text-property beg end 'font-lock-face face))))) + (ansi-color-apply-on-region (point-min) (point-max)))) + (when (eq style 'cherry) + (reverse-region (point-min) (point-max))) + (let ((magit-log-count 0)) + (magit-wash-sequence (apply-partially 'magit-wash-log-line style + (magit-abbrev-length))) + (when (and longer + (= magit-log-count magit-log-cutoff-length)) + (magit-with-section (section longer 'longer) + (insert-text-button "type \"e\" to show more history" + 'action (lambda (button) + (magit-log-show-more-entries)) + 'follow-link t + 'mouse-face magit-item-highlight-face))))) + +(defun magit-wash-log-line (style abbrev) + (looking-at (cl-ecase style + (oneline magit-log-oneline-re) + (long magit-log-long-re) + (unique magit-log-unique-re) + (cherry magit-log-cherry-re) + (reflog magit-log-reflog-re) + (bisect-vis magit-log-bisect-vis-re) + (bisect-log magit-log-bisect-log-re))) + (magit-bind-match-strings + (hash msg refs graph author date gpg cherry refsel refsub) + (delete-region (point) (point-at-eol)) + (when cherry + (magit-insert cherry (if (string= cherry "-") + 'magit-cherry-equivalent + 'magit-cherry-unmatched) ?\s)) + (unless (eq style 'long) + (when (eq style 'bisect-log) + (setq hash (magit-git-string "rev-parse" "--short" hash))) + (if hash + (insert (propertize hash 'face 'magit-log-sha1) ?\s) + (insert (make-string (1+ abbrev) ? )))) + (when graph + (if magit-log-format-graph-function + (insert (funcall magit-log-format-graph-function graph)) + (insert graph))) + (when (and hash (eq style 'long)) + (magit-insert (if refs hash (magit-rev-parse hash)) 'magit-log-sha1 ?\s)) + (when refs + (magit-insert-ref-labels refs)) + (when refsub + (insert (format "%-2s " refsel)) + (insert (magit-log-format-reflog refsub))) + (when msg + (magit-insert msg (cl-case (and gpg (aref gpg 0)) + (?G 'magit-signature-good) + (?B 'magit-signature-bad) + (?U 'magit-signature-untrusted) + (?N 'magit-signature-none) + (t 'magit-log-message)))) + (goto-char (line-beginning-position)) + (magit-format-log-margin author date) + (if hash + (magit-with-section (section commit hash) + (when (derived-mode-p 'magit-log-mode) + (cl-incf magit-log-count)) + (forward-line) + (when (eq style 'long) + (magit-wash-sequence + (lambda () + (looking-at magit-log-long-re) + (when (match-string 2) + (magit-wash-log-line 'long abbrev)))))) + (forward-line))) + t) + +(defun magit-log-format-unicode-graph (string) + "Translate ascii characters to unicode characters. +Whether that actually is an improvment depends on the unicode +support of the font in use. The translation is done using the +alist in `magit-log-format-unicode-graph-alist'." + (replace-regexp-in-string + "[/|\\*o ]" + (lambda (str) + (propertize + (string (or (cdr (assq (aref str 0) + magit-log-format-unicode-graph-alist)) + (aref str 0))) + 'face (get-text-property 0 'face str))) + string)) + +(defun magit-format-log-margin (&optional author date) + (when magit-log-show-margin + (cl-destructuring-bind (width characterp duration-spec) + magit-log-margin-spec + (if author + (magit-make-margin-overlay + (propertize (truncate-string-to-width + author (- width 1 3 (if characterp 0 1) + magit-log-margin-timeunit-width 1) + nil ?\s (make-string 1 magit-ellipsis)) + 'face 'magit-log-author) + " " + (propertize (magit-format-duration + (abs (truncate (- (float-time) + (string-to-number date)))) + (symbol-value duration-spec) + magit-log-margin-timeunit-width) + 'face 'magit-log-date) + (propertize " " 'face 'fringe)) + (magit-make-margin-overlay + (propertize (make-string (1- width) ?\s) 'face 'default) + (propertize " " 'face 'fringe)))))) + +;;;;; Log Commands + +(defun magit-log-toggle-margin () + "Show or hide the log margin. +This command can only be used inside log buffers (usually +*magit-log*) and only if that displays a `oneline' log. +Also see option `magit-log-show-margin'." + (interactive) + (unless (derived-mode-p 'magit-log-mode) + (user-error "The log margin cannot be used outside of log buffers")) + (when (eq (car magit-refresh-args) 'long) + (user-error "The log margin cannot be used with verbose logs")) + (if magit-log-show-margin + (magit-set-buffer-margin (car magit-log-margin-spec) + (not (cdr (window-margins)))) + (setq-local magit-log-show-margin t) + (magit-refresh))) + +(defun magit-log-show-more-entries (&optional arg) + "Grow the number of log entries shown. + +With no prefix optional ARG, show twice as many log entries. +With a numerical prefix ARG, add this number to the number of shown log entries. +With a non numeric prefix ARG, show all entries" + (interactive "P") + (setq-local magit-log-cutoff-length + (cond ((numberp arg) (+ magit-log-cutoff-length arg)) + (arg magit-log-infinite-length) + (t (* magit-log-cutoff-length 2)))) + (let ((old-point (point))) + (magit-refresh) + (goto-char old-point))) + +;;;; Cherry Mode + +(define-derived-mode magit-cherry-mode magit-mode "Magit Cherry" + "Mode for looking at commits not merged upstream. + +\\Type `\\[magit-toggle-section]` to show or hide \ +section, `\\[magit-visit-item]` to visit an item and \ +`\\[magit-show-item-or-scroll-up]` to show it. +Type `\\[magit-diff-working-tree]` to display change with your working tree, \ +when `\\[magit-diff]` to display change +between any two commit. +Type `\\[magit-cherry-pick-item]` to cherry-pick a commit, and \ +`\\[magit-apply-item]` to apply its change to your +working tree, without committing, and `\\[magit-key-mode-popup-merging]` to \ +merge. +`\\[magit-refresh]` will refresh current buffer. + + +Other key binding: +\\{magit-cherry-mode-map}") + +(defvar magit-cherry-buffer-name "*magit-cherry*" + "Name of buffer used to display commits not merged upstream.") + +;;;###autoload +(defun magit-cherry (head upstream) + "Show commits in a branch that are not merged in the upstream branch." + (interactive + (let ((head (magit-read-rev "Cherry head" (magit-get-current-branch)))) + (list head (magit-read-rev "Cherry upstream" + (magit-get-tracked-branch head nil t))))) + (magit-mode-setup magit-cherry-buffer-name nil + #'magit-cherry-mode + #'magit-refresh-cherry-buffer upstream head)) + +(defun magit-refresh-cherry-buffer (upstream head) + (magit-with-section (section cherry 'cherry nil t) + (run-hooks 'magit-cherry-sections-hook))) + +(defun magit-insert-cherry-head-line () + (magit-insert-line-section (line) + (concat "Head: " + (propertize (cadr magit-refresh-args) 'face 'magit-branch) " " + (abbreviate-file-name default-directory)))) + +(defun magit-insert-cherry-upstream-line () + (magit-insert-line-section (line) + (concat "Upstream: " + (propertize (car magit-refresh-args) 'face 'magit-branch)))) + +(defun magit-insert-cherry-help-lines () + (when (derived-mode-p 'magit-cherry-mode) + (insert "\n") + (magit-insert-line-section (line) + (concat (propertize "-" 'face 'magit-cherry-equivalent) + " equivalent exists in both refs")) + (magit-insert-line-section (line) + (concat (propertize "+" 'face 'magit-cherry-unmatched) + " unmatched commit tree")))) + +(defun magit-insert-cherry-commits () + (magit-git-insert-section (cherries "Cherry commits:") + (apply-partially 'magit-wash-log 'cherry) + "cherry" "-v" (magit-abbrev-arg) magit-refresh-args)) + +;;;; Reflog Mode + +(defvar magit-reflog-buffer-name "*magit-reflog*" + "Name of buffer used to display reflog entries.") + +(define-derived-mode magit-reflog-mode magit-log-mode "Magit Reflog" + "Mode for looking at git reflog. + +\\Type `\\[magit-visit-item]` to visit a commit, and \ +`\\[magit-show-item-or-scroll-up]` to just show it. +Type `\\[magit-diff-working-tree]` to see the diff between current commit and \ +your working tree, +Type `\\[magit-diff]` to see the between any two version. +Type `\\[magit-reset-head]` to reset your head to the current commit, and \ +`\\[magit-apply-item]` to apply its change +to your working tree and `\\[magit-cherry-pick-item]` to cherry pick it. + +More information can be found in Info node `(magit)Reflogs' + +Other key binding: +\\{magit-reflog-mode-map}" + :group 'magit) + +(defun magit-refresh-reflog-buffer (ref) + (magit-log-margin-set-timeunit-width) + (magit-git-insert-section + (reflogbuf (format "Local history of branch %s" ref)) + (apply-partially 'magit-wash-log 'reflog t) + "reflog" "show" "--format=format:%h [%an] %ct %gd %gs" + (format "--max-count=%d" magit-log-cutoff-length) ref)) + +(defvar magit-reflog-labels + '(("commit" . magit-log-reflog-label-commit) + ("amend" . magit-log-reflog-label-amend) + ("merge" . magit-log-reflog-label-merge) + ("checkout" . magit-log-reflog-label-checkout) + ("branch" . magit-log-reflog-label-checkout) + ("reset" . magit-log-reflog-label-reset) + ("rebase" . magit-log-reflog-label-rebase) + ("cherry-pick" . magit-log-reflog-label-cherry-pick) + ("initial" . magit-log-reflog-label-commit) + ("pull" . magit-log-reflog-label-remote) + ("clone" . magit-log-reflog-label-remote))) + +(defun magit-log-format-reflog (subject) + (let* ((match (string-match magit-reflog-subject-re subject)) + (command (and match (match-string 1 subject))) + (option (and match (match-string 2 subject))) + (type (and match (match-string 3 subject))) + (label (if (string= command "commit") + (or type command) + command)) + (text (if (string= command "commit") + label + (mapconcat #'identity + (delq nil (list command option type)) + " ")))) + (format "%-16s " + (propertize text 'face + (or (cdr (assoc label magit-reflog-labels)) + 'magit-log-reflog-label-other))))) + +;;;; Ediff Support + +(defvar magit-ediff-buffers nil + "List of buffers that may be killed by `magit-ediff-restore'.") + +(defvar magit-ediff-windows nil + "The window configuration that will be restored when Ediff is finished.") + +(defun magit-ediff () + "View the current DIFF section in ediff." + (interactive) + (let ((diff (magit-current-section))) + (when (eq (magit-section-type (magit-current-section)) 'diffstat) + (setq diff (magit-diff-section-for-diffstat diff))) + (when (magit-section-hidden diff) + ;; Range is not set until the first time the diff is visible. + ;; This somewhat hackish code makes sure it's been visible at + ;; least once. + (magit-toggle-section) + (magit-toggle-section) + (setq diff (magit-current-section))) + (when (eq 'hunk (magit-section-type diff)) + (setq diff (magit-section-parent diff))) + (unless (eq 'diff (magit-section-type diff)) + (user-error "No diff at this location")) + (let* ((status (magit-section-diff-status diff)) + (file1 (magit-section-info diff)) + (file2 (magit-section-diff-file2 diff)) + (range (magit-diff-range diff))) + (cond + ((memq status '(new deleted typechange)) + (message "Why ediff a %s file?" status)) + ((and (eq status 'unmerged) + (eq (cdr range) 'working)) + (magit-interactive-resolve file1)) + ((consp (car range)) + (magit-ediff-buffers3 (magit-show (caar range) file2) + (magit-show (cdar range) file2) + (magit-show (cdr range) file1))) + (t + (magit-ediff-buffers (magit-show (car range) file2) + (magit-show (cdr range) file1))))))) + +(defun magit-ediff-buffers (a b) + (setq magit-ediff-buffers (list a b)) + (setq magit-ediff-windows (current-window-configuration)) + (ediff-buffers a b '(magit-ediff-add-cleanup))) + +(defun magit-ediff-buffers3 (a b c) + (setq magit-ediff-buffers (list a b c)) + (setq magit-ediff-windows (current-window-configuration)) + (ediff-buffers3 a b c '(magit-ediff-add-cleanup))) + +(defun magit-diff-range (diff) + (if (eq major-mode 'magit-commit-mode) + (let ((revs (split-string + (magit-git-string "rev-list" "-1" "--parents" + (car (last magit-refresh-args)))))) + (when (= (length revs) 2) + (cons (cadr revs) (car revs)))) + (magit-section-diff-range diff))) + +(defun magit-ediff-add-cleanup () + (make-local-variable 'magit-ediff-buffers) + (setq-default magit-ediff-buffers ()) + + (make-local-variable 'magit-ediff-windows) + (setq-default magit-ediff-windows ()) + + (add-hook 'ediff-cleanup-hook 'magit-ediff-restore 'append 'local)) + +(defun magit-ediff-restore () + "Kill any buffers in `magit-ediff-buffers' that are not visiting files and +restore the window state that was saved before ediff was called." + (dolist (buffer magit-ediff-buffers) + (when (and (null (buffer-file-name buffer)) + (buffer-live-p buffer)) + (with-current-buffer buffer + (when (and (eq magit-show-current-version 'index) + (buffer-modified-p)) + (magit-save-index))) + (kill-buffer buffer))) + (let ((buf (current-buffer))) + (set-window-configuration magit-ediff-windows) + (set-buffer buf))) + +;;;###autoload +(defun magit-save-index () + "Add the content of current file as if it was the index." + (interactive) + (unless (eq magit-show-current-version 'index) + (user-error "Current buffer doesn't visit the index version of a file")) + (when (y-or-n-p (format "Stage current version of %s? " magit-file-name)) + (let ((buf (current-buffer)) + (name (magit-git-dir "magit-add-index"))) + (with-temp-file name + (insert-buffer-substring buf)) + (let ((hash (magit-git-string "hash-object" "-t" "blob" "-w" + (concat "--path=" magit-file-name) + "--" name)) + (perm (substring (magit-git-string "ls-files" "-s" + magit-file-name) + 0 6))) + (magit-run-git "update-index" "--cacheinfo" + perm hash magit-file-name))))) + +;;;###autoload +(defun magit-interactive-resolve (file) + "Resolve a merge conflict using Ediff." + (interactive (list (magit-section-case (info) (diff (cadr info))))) + (require 'ediff) + (let ((merge-status (magit-git-lines "ls-files" "-u" "--" file)) + (base-buffer) + (our-buffer (generate-new-buffer (concat file ".current"))) + (their-buffer (generate-new-buffer (concat file ".merged"))) + (merger-buffer) + (windows (current-window-configuration))) + (unless merge-status + (user-error "Cannot resolve %s" file)) + (when (string-match "^[0-9]+ [0-9a-f]+ 1" (car merge-status)) + (pop merge-status) + (setq base-buffer (generate-new-buffer (concat file ".base"))) + (with-current-buffer base-buffer + (magit-git-insert "cat-file" "blob" (concat ":1:" file)))) + ;; If the second or third version do not exit, we use an empty buffer for the deleted file + (with-current-buffer our-buffer + (when (string-match "^[0-9]+ [0-9a-f]+ 2" (car merge-status)) + (pop merge-status) + (magit-git-insert "cat-file" "blob" (concat ":2:" file))) + (let ((buffer-file-name file)) + (normal-mode t))) + (with-current-buffer their-buffer + (when (string-match "^[0-9]+ [0-9a-f]+ 3" (car merge-status)) + (magit-git-insert "cat-file" "blob" (concat ":3:" file))) + (let ((buffer-file-name file)) + (normal-mode t))) + ;; We have now created the 3 buffer with ours, theirs and the ancestor files + (if base-buffer + (setq merger-buffer (ediff-merge-buffers-with-ancestor + our-buffer their-buffer base-buffer nil nil file)) + (setq merger-buffer (ediff-merge-buffers our-buffer their-buffer nil nil file))) + (with-current-buffer merger-buffer + (setq ediff-show-clashes-only t) + (setq-local magit-ediff-windows windows) + (make-local-variable 'ediff-quit-hook) + (add-hook 'ediff-quit-hook + (lambda () + (let ((buffer-A ediff-buffer-A) + (buffer-B ediff-buffer-B) + (buffer-C ediff-buffer-C) + (buffer-Ancestor ediff-ancestor-buffer) + (windows magit-ediff-windows)) + (ediff-cleanup-mess) + (kill-buffer buffer-A) + (kill-buffer buffer-B) + (when (bufferp buffer-Ancestor) + (kill-buffer buffer-Ancestor)) + (set-window-configuration windows))))))) + +;;;; Diff Mode +;;;;; Diff Core + +(define-derived-mode magit-diff-mode magit-mode "Magit Diff" + "Mode for looking at a git diff. + +\\Type `\\[magit-visit-item]` to visit the changed file, \ +`\\[magit-toggle-section]` to hide or show a hunk, +`\\[magit-diff-larger-hunks]` and `\\[magit-diff-smaller-hunks]` to change \ +the size of the hunks. +Type `\\[magit-apply-item]` to apply a change to your worktree and \ +`\\[magit-revert-item]` to reverse it. +You can also use `\\[magit-ediff]` to see the current change with ediff. + +More information can be found in Info node `(magit)Diffing' + +\\{magit-diff-mode-map}" + :group 'magit) + +(defvar magit-diff-buffer-name "*magit-diff*" + "Name of buffer used to display a diff.") + +(defvar magit-stash-buffer-name "*magit-stash*" + "Name of buffer used to display a stash.") + +;;;;; Diff Entry Commands + +;;;###autoload +(defun magit-diff (range &optional working args) + "Show differences between two commits. +RANGE should be a range (A..B or A...B) but can also be a single +commit. If one side of the range is omitted, then it defaults +to HEAD. If just a commit is given, then changes in the working +tree relative to that commit are shown." + (interactive (list (magit-read-rev-range "Diff"))) + (magit-mode-setup magit-diff-buffer-name + #'pop-to-buffer + #'magit-diff-mode + #'magit-refresh-diff-buffer range working args)) + +;;;###autoload +(defun magit-diff-working-tree (rev) + "Show differences between a commit and the current working tree." + (interactive (list (magit-read-rev-with-default "Diff working tree with"))) + (magit-diff (or rev "HEAD") t)) + +;;;###autoload +(defun magit-diff-staged () + "Show differences between the index and the HEAD commit." + (interactive) + (magit-diff nil nil (list "--cached"))) + +;;;###autoload +(defun magit-diff-unstaged () + "Show differences between the current working tree and index." + (interactive) + (magit-diff nil)) + +;;;###autoload +(defun magit-diff-stash (stash &optional noselect) + "Show changes in a stash. +A Stash consist of more than just one commit. This command uses +a special diff range so that the stashed changes actually were a +single commit." + (interactive (list (magit-read-stash "Show stash (number): "))) + (magit-mode-setup magit-commit-buffer-name + (if noselect 'display-buffer 'pop-to-buffer) + #'magit-diff-mode + #'magit-refresh-diff-buffer + (concat stash "^2^.." stash))) + +(defun magit-diff-with-mark (range) + "Show difference between the marked commit and the one at point. +If there is no commit at point, then prompt for one." + (interactive + (let* ((marked (or magit-marked-commit (user-error "No commit marked"))) + (current (magit-get-current-branch)) + (is-current (string= (magit-name-rev marked) current)) + (commit (or (magit-guess-branch) + (magit-read-rev + (format "Diff marked commit %s with" marked) + (unless is-current current) + current)))) + (list (concat marked ".." commit)))) + (magit-diff range)) + +(defun magit-refresh-diff-buffer (range &optional working args) + (let ((magit-current-diff-range + (cond (working (cons range 'working)) + ((null range) nil) + ((consp range) + (prog1 range + (setq range (concat (car range) ".." (cdr range))))) + ((string-match "^\\([^.]+\\)\\.\\.\\([^.]\\)$" range) + (cons (match-string 1 range) + (match-string 2 range)))))) + (magit-git-insert-section + (diffbuf (cond (working + (format "Changes from %s to working tree" range)) + ((not range) + (if (member "--cached" args) + "Staged changes" + "Unstaged changes")) + (t + (format "Changes in %s" range)))) + #'magit-wash-diffs + "diff" (magit-diff-U-arg) + (and magit-show-diffstat "--patch-with-stat") + range args "--"))) + +;;;;; Diff Washing + +(defconst magit-diff-statline-re + (concat "^ ?" + "\\(.*\\)" ; file + "\\( +| +\\)" ; separator + "\\([0-9]+\\|Bin\\(?: +[0-9]+ -> [0-9]+ bytes\\)?$\\) ?" + "\\(\\+*\\)" ; add + "\\(-*\\)$")) ; del + +(defvar magit-current-diff-range nil + "Used internally when setting up magit diff sections.") + +(defvar-local magit-diffstat-cached-sections nil) +(put 'magit-diffstat-cached-sections 'permanent-local t) + +(defun magit-wash-diffs () + (magit-wash-diffstats) + (when (re-search-forward "^diff" nil t) + (goto-char (line-beginning-position)) + (magit-wash-sequence #'magit-wash-diff)) + (goto-char (point-max)) + (magit-xref-insert-buttons)) + +(defun magit-wash-diffstats () + (let ((beg (point))) + (when (re-search-forward "^ ?\\([0-9]+ +files? change[^\n]*\n\\)" nil t) + (let ((heading (match-string-no-properties 1))) + (delete-region (match-beginning 0) (match-end 0)) + (goto-char beg) + (magit-with-section (section diffstats 'diffstats heading) + (magit-wash-sequence #'magit-wash-diffstat))) + (setq magit-diffstat-cached-sections + (nreverse magit-diffstat-cached-sections))))) + +(defun magit-wash-diffstat () + (when (looking-at magit-diff-statline-re) + (magit-bind-match-strings (file sep cnt add del) + (delete-region (point) (1+ (line-end-position))) + (magit-with-section (section diffstat 'diffstat) + (insert " " file sep cnt " ") + (when add (insert (propertize add 'face 'magit-diff-add))) + (when del (insert (propertize del 'face 'magit-diff-del))) + (insert "\n") + (push section magit-diffstat-cached-sections))))) + +(defun magit-wash-diff () + (magit-with-section (section diff (buffer-substring-no-properties + (line-beginning-position) + (line-end-position))) + (setq section (magit-wash-diff-section section)))) + +(defun magit-wash-diff-section (section) + (cond ((re-search-forward "^\\* Unmerged path \\(.*\\)" nil t) + (forward-line 0) + (let ((file (magit-decode-git-path (match-string-no-properties 1)))) + (delete-region (point) (line-end-position)) + (insert "\tUnmerged " file "\n") + (setf (magit-section-diff-status section) 'unmerged) + (setf (magit-section-info section) file) + section)) + ((re-search-forward "^diff" nil t) + (forward-line 0) + (let ((file (cond + ((looking-at "^diff --git \\(\".*\"\\) \\(\".*\"\\)$") + (substring (magit-decode-git-path + (match-string-no-properties 2)) 2)) + ((looking-at "^diff --git ./\\(.*\\) ./\\(.*\\)$") + (match-string-no-properties 2)) + ((looking-at "^diff --cc +\\(.*\\)$") + (match-string-no-properties 1)))) + (end (save-excursion + (forward-line) ;; skip over "diff" line + (if (re-search-forward "^diff\\|^@@" nil t) + (goto-char (match-beginning 0)) + (goto-char (point-max))) + (point-marker)))) + (when magit-diffstat-cached-sections + (setf (magit-section-info (pop magit-diffstat-cached-sections)) + file)) + (let ((status (cond + ((looking-at "^diff --cc") + 'unmerged) + ((save-excursion + (re-search-forward "^new file" end t)) + 'new) + ((save-excursion + (re-search-forward "^deleted" end t)) + (setf (magit-section-hidden section) t) + 'deleted) + ((save-excursion + (re-search-forward "^rename" end t)) + 'renamed) + (t + 'modified))) + (file2 (cond + ((save-excursion + (re-search-forward "^rename from \\(.*\\)" + end t)) + (match-string-no-properties 1))))) + (setf (magit-section-diff-status section) status) + (setf (magit-section-info section) file) + (setf (magit-section-diff-file2 section) (or file2 file)) + (setf (magit-section-diff-range section) magit-current-diff-range) + (magit-insert-diff-title status file file2) + (when (re-search-forward + "\\(--- \\(.*\\)\n\\+\\+\\+ \\(.*\\)\n\\)" nil t) + (magit-put-face-property (match-beginning 1) (match-end 1) + 'magit-diff-hunk-header) + (magit-put-face-property (match-beginning 2) (match-end 2) + 'magit-diff-file-header) + (magit-put-face-property (match-beginning 3) (match-end 3) + 'magit-diff-file-header)) + (goto-char end) + (magit-wash-sequence #'magit-wash-hunk))) + section))) + +(defun magit-insert-diff-title (status file file2) + (insert (format "\t%-10s " (capitalize (symbol-name status))) + file + (if (eq status 'renamed) (format " (from %s)" file2) "") + "\n")) + +(defun magit-wash-hunk () + (when (looking-at "^@@\\(@\\)?.+") + (let ((merging (match-beginning 1))) + (magit-with-section (section hunk (match-string 0)) + (magit-put-face-property (point) (line-end-position) + 'magit-diff-hunk-header) + (forward-line) + (while (not (or (eobp) (looking-at "^diff\\|^@@"))) + (magit-put-face-property + (point) (line-end-position) + (cond + ((looking-at "^\\+\\+<<<<<<<") 'magit-diff-merge-current) + ((looking-at "^\\+\\+=======") 'magit-diff-merge-separator) + ((looking-at "^\\+\\+|||||||") 'magit-diff-merge-diff3-separator) + ((looking-at "^\\+\\+>>>>>>>") 'magit-diff-merge-proposed) + ((looking-at (if merging "^\\(\\+\\| \\+\\)" "^\\+")) + (magit-diff-highlight-whitespace merging) + 'magit-diff-add) + ((looking-at (if merging "^\\(-\\| \\-\\)" "^-")) + (magit-diff-highlight-whitespace merging) + 'magit-diff-del) + (t + 'magit-diff-none))) + (forward-line)) + (when (eq magit-diff-refine-hunk 'all) + (magit-diff-refine-hunk section)))) + t)) + +(defun magit-diff-highlight-whitespace (merging) + (when (and magit-highlight-whitespace + (or (derived-mode-p 'magit-status-mode) + (not (eq magit-highlight-whitespace 'status)))) + (let ((prefix (if merging "^[-\\+\s]\\{2\\}" "^[-\\+]")) + (indent + (if (local-variable-p 'magit-highlight-indentation) + magit-highlight-indentation + (setq-local + magit-highlight-indentation + (cdr (cl-find-if (lambda (pair) + (string-match-p (car pair) default-directory)) + (default-value 'magit-highlight-indentation) + :from-end t)))))) + (when (and magit-highlight-trailing-whitespace + (looking-at (concat prefix ".*?\\([ \t]+\\)$"))) + (magit-put-face-property (match-beginning 1) (match-end 1) + 'magit-whitespace-warning-face)) + (when (or (and (eq indent 'tabs) + (looking-at (concat prefix "\\( *\t[ \t]*\\)"))) + (and (integerp indent) + (looking-at (format "%s\\([ \t]* \\{%s,\\}[ \t]*\\)" + prefix indent)))) + (magit-put-face-property (match-beginning 1) (match-end 1) + 'magit-whitespace-warning-face))))) + +;;;;; Diff Mode Commands + +(defun magit-diff-toggle-refine-hunk (&optional other) + "Turn diff-hunk refining on or off. + +If hunk refining is currently on, then hunk refining is turned off. +If hunk refining is off, then hunk refining is turned on, in +`selected' mode (only the currently selected hunk is refined). + +With a prefix argument, the \"third choice\" is used instead: +If hunk refining is currently on, then refining is kept on, but +the refining mode (`selected' or `all') is switched. +If hunk refining is off, then hunk refining is turned on, in +`all' mode (all hunks refined). + +Customize variable `magit-diff-refine-hunk' to change the default mode." + (interactive "P") + (let ((hunk (and magit-highlighted-section + (eq (magit-section-type magit-highlighted-section) 'hunk) + magit-highlighted-section)) + (old magit-diff-refine-hunk)) + (setq-local magit-diff-refine-hunk + (if other + (if (eq old 'all) t 'all) + (not old))) + (cond ((or (eq old 'all) + (eq magit-diff-refine-hunk 'all)) + (magit-refresh)) + ((not hunk)) + (magit-diff-refine-hunk + (magit-diff-refine-hunk hunk)) + (t + (magit-diff-unrefine-hunk hunk))) + (message "magit-diff-refine-hunk: %s" magit-diff-refine-hunk))) + +(defun magit-diff-refine-hunk (hunk) + (save-excursion + (goto-char (magit-section-beginning hunk)) + ;; `diff-refine-hunk' does not handle combined diffs. + (unless (looking-at "@@@") + (diff-refine-hunk)))) + +(defun magit-diff-unrefine-hunk (hunk) + (remove-overlays (magit-section-beginning hunk) + (magit-section-end hunk) + 'diff-mode 'fine)) + +;;;; Wazzup Mode + +(define-derived-mode magit-wazzup-mode magit-mode "Magit Wazzup" + "Mode for looking at git commits not merged into current HEAD. + +\\Type `\\[magit-toggle-section]` to show or hide \ +section, `\\[magit-visit-item]` to visit an item \ +`\\[magit-show-item-or-scroll-up]` to show it. +Type `\\[magit-diff-working-tree]` to display change with your working tree, \ +and `\\[magit-diff]` to display change +between any two commit. +Type `\\[magit-cherry-pick-item]` to cherry-pick a commit, and \ +`\\[magit-apply-item]` to apply its change to your +working tree, without committing, and `\\[magit-key-mode-popup-merging]` \ +to merge those change. +Type `\\[magit-refresh]` to refresh current buffer. + +More information can be found in Info node `(magit)Wazzup' + +\\{magit-wazzup-mode-map}" + :group 'magit) + +(defvar magit-wazzup-buffer-name "*magit-wazzup*" + "Name of buffer used to display commits not merged into current HEAD.") + +;;;###autoload +(defun magit-wazzup (branch) + "Show a list of branches in a dedicated buffer. +Unlike in the buffer created by `magit-branch-manager' each +branch can be expanded to show a list of commits not merged +into the selected branch." + (interactive + (let ((branch (magit-get-current-branch))) + (list (if current-prefix-arg + (magit-read-rev "Wazzup branch" branch) + branch)))) + (magit-mode-setup magit-wazzup-buffer-name nil + #'magit-wazzup-mode + #'magit-refresh-wazzup-buffer branch)) + +(defun magit-refresh-wazzup-buffer (head) + (magit-with-section (section wazzupbuf 'wazzupbuf nil t) + (run-hooks 'magit-wazzup-sections-hook))) + +(defun magit-insert-wazzup-head-line () + (magit-insert-line-section (line) + (concat "Head: " + (propertize (car magit-refresh-args) 'face 'magit-branch) " " + (abbreviate-file-name default-directory)))) + +(defun magit-insert-wazzup-branches () + (dolist (upstream (magit-git-lines "show-ref")) + (setq upstream (cadr (split-string upstream " "))) + (when (and (not (string-match-p "HEAD$" upstream)) + (string-match-p "^refs/\\(heads\\|remotes\\)/" upstream)) + (magit-insert-wazzup-commits upstream (car magit-refresh-args))))) + +(defun magit-insert-wazzup-commits (upstream head) + (let ((count (string-to-number + (magit-git-string "rev-list" "--count" "--right-only" + (concat head "..." upstream))))) + (when (> count 0) + (magit-with-section + (section wazzup upstream + (format "%3s %s\n" count (magit-format-ref-label upstream)) + nil t) + (cond + ((magit-section-hidden section) + (setf (magit-section-hidden section) t) + (setf (magit-section-needs-refresh-on-show section) t)) + (t + (let ((beg (point))) + (magit-git-insert "cherry" "-v" "--abbrev" head upstream) + (save-restriction + (narrow-to-region beg (point)) + (goto-char (point-min)) + (magit-wash-log 'cherry))))))))) + +;;;; Branch Manager Mode +;;;;; (core) + +(define-derived-mode magit-branch-manager-mode magit-mode "Magit Branch" + "Mode for looking at git branches. + +\\Type `\\[magit-visit-item]` to checkout a branch, `\\[magit-reset-head]' to reset current branch, +you can also merge the branch with `\\[magit-key-mode-popup-merging]` + +Type `\\[magit-discard-item]' to delete a branch, or `\\[universal-argument] \\[magit-discard-item]' to force the deletion. +Type `\\[magit-rename-item]' to Rename a branch. + +More information can be found in Info node `(magit)The branch list' + +\\{magit-branch-manager-mode-map} +Unless shadowed by the mode specific bindings above, bindings +from the parent keymap `magit-mode-map' are also available.") + +(defvar magit-branches-buffer-name "*magit-branches*" + "Name of buffer used to display and manage branches.") + +;;;###autoload +(defun magit-branch-manager () + "Show a list of branches in a dedicated buffer." + (interactive) + (if (magit-get-top-dir) ; Kludge for #1215 + (magit-mode-setup magit-branches-buffer-name nil + #'magit-branch-manager-mode + #'magit-refresh-branch-manager) + (user-error "There is no Git repository here"))) + +(defun magit-refresh-branch-manager () + (magit-git-insert-section (branchbuf nil) + #'magit-wash-branches + "branch" "-vva" magit-custom-options)) + +;;;;; Branch List Washing + +(defconst magit-wash-branch-line-re + (concat "^\\([ *] \\)" ; 1: current branch marker + "\\(.+?\\) +" ; 2: branch name + "\\(?:" + "\\([0-9a-fA-F]+\\)" ; 3: sha1 + " " + "\\(?:\\[" + "\\([^:\n]+?\\)" ; 4: tracking + "\\(?:: \\)?" + "\\(?:ahead \\([0-9]+\\)\\)?" ; 5: ahead + "\\(?:, \\)?" + "\\(?:behind \\([0-9]+\\)\\)?" ; 6: behind + "\\] \\)?" + "\\(?:.*\\)" ; message + "\\|" ; or + "-> " ; the pointer to + "\\(.+\\)" ; 7: a ref + "\\)\n")) + +(defun magit-wash-branch-line (&optional remote-name) + (when (looking-at magit-wash-branch-line-re) + ;; ^ Kludge for #1162. v Don't reindent for now. + (let* ((marker (match-string 1)) + (branch (match-string 2)) + (sha1 (match-string 3)) + (tracking (match-string 4)) + (ahead (match-string 5)) + (behind (match-string 6)) + (other-ref (match-string 7)) + (branch-face (and (equal marker "* ") 'magit-branch))) + (delete-region (point) (line-beginning-position 2)) + (magit-with-section (section branch branch) + (insert (propertize (or sha1 (make-string 7 ? )) + 'face 'magit-log-sha1) + " " marker + (propertize (if (string-match-p "^remotes/" branch) + (substring branch 8) + branch) + 'face branch-face)) + (when other-ref + (insert " -> " (substring other-ref (+ 1 (length remote-name))))) + (when (and tracking + (equal (magit-get-tracked-branch branch t) + (concat "refs/remotes/" tracking))) + (insert " [") + ;; getting rid of the tracking branch name if it is + ;; the same as the branch name + (let* ((remote (magit-get "branch" branch "remote")) + (merge (substring tracking (+ 1 (length remote))))) + (insert (propertize (if (string= branch merge) + (concat "@ " remote) + (concat merge " @ " remote)) + 'face 'magit-log-head-label-remote))) + (when (or ahead behind) + (insert ":") + (and ahead (insert "ahead " (propertize ahead 'face branch-face))) + (and ahead behind (insert ", ")) + (and behind (insert "behind " + (propertize behind 'face + 'magit-log-head-label-remote)))) + (insert "]")) + (insert "\n"))))) + +(defun magit-wash-remote-branches-group (group) + (let* ((remote (car group)) + (url (magit-get "remote" remote "url")) + (push-url (magit-get "remote" remote "pushurl")) + (urls (concat url (and push-url (concat ", " push-url)))) + (marker (cadr group))) + (magit-with-section + (section remote remote (format "%s (%s):" remote urls) t) + (magit-wash-branches-between-point-and-marker marker remote) + (insert "\n")))) + +(defun magit-wash-branches-between-point-and-marker (marker &optional remote-name) + (save-restriction + (narrow-to-region (point) marker) + (magit-wash-sequence + (apply-partially 'magit-wash-branch-line remote-name)))) + +(defun magit-wash-branches () + ;; get the names of the remotes + (let* ((remotes (magit-git-lines "remote")) + ;; get the location of remotes in the buffer + (markers + (append (mapcar (lambda (remote) + (save-excursion + (when (re-search-forward + (format "^ remotes/%s/" remote) nil t) + (beginning-of-line) + (point-marker)))) + remotes) + (list (save-excursion + (goto-char (point-max)) + (point-marker))))) + ;; list of remote elements to display in the buffer + (remote-groups + (cl-loop for remote in remotes + for end-markers on (cdr markers) + for marker = (cl-loop for x in end-markers thereis x) + collect (list remote marker)))) + ;; actual displaying of information + (magit-with-section (section local "." "Local:" t) + (magit-wash-branches-between-point-and-marker + (cl-loop for x in markers thereis x)) + (insert "\n")) + (mapc 'magit-wash-remote-branches-group remote-groups) + ;; make sure markers point to nil so that they can be garbage collected + (mapc (lambda (marker) + (when marker + (set-marker marker nil))) + markers))) + +;;;;; (commands) + +(defun magit-rename-item () + "Rename the item at point." + (interactive) + (magit-section-action rename () + (branch (call-interactively 'magit-rename-branch)) + (remote (call-interactively 'magit-rename-remote)))) + +(defun magit-change-what-branch-tracks () + "Change which remote branch the current branch tracks." + (interactive) + (let* ((branch (magit-guess-branch)) + (track (magit-read-rev "Track branch")) + (track- + (cond ((string-match "^\\([^ ]+\\) +(\\(.+\\))$" track) + (cons (match-string 2 track) + (concat "refs/heads/" (match-string 1 track)))) + ((string-match "^\\(?:refs/remotes/\\)?\\([^/]+\\)/\\(.+\\)" + track) + (cons (match-string 1 track) + (concat "refs/heads/" (match-string 2 track)))) + (t + (user-error "Cannot parse the remote and branch name"))))) + (magit-set (car track-) "branch" branch "remote") + (magit-set (cdr track-) "branch" branch "merge") + (magit-refresh))) + +;;; Miscellaneous +;;;; Miscellaneous Commands + +;;;###autoload +(defun magit-init (directory) + "Create or reinitialize a Git repository. +Read directory name and initialize it as new Git repository. + +If the directory is below an existing repository, then the user +has to confirm that a new one should be created inside; or when +the directory is the root of the existing repository, whether +it should be reinitialized. + +Non-interactively DIRECTORY is always (re-)initialized." + (interactive + (let* ((dir (file-name-as-directory + (expand-file-name + (read-directory-name "Create repository in: ")))) + (top (magit-get-top-dir dir))) + (if (and top + (not (yes-or-no-p + (if (string-equal top dir) + (format "Reinitialize existing repository %s? " dir) + (format "%s is a repository. Create another in %s? " + top dir))))) + (user-error "Abort") + (list dir)))) + (magit-run-git "init" (expand-file-name directory))) + +(defun magit-copy-item-as-kill () + "Copy sha1 of commit at point into kill ring." + (interactive) + (magit-section-action copy (info) + ((branch commit file diff) + (kill-new info) + (message "%s" info)))) + +(defun magit-ignore-item (edit &optional local) + "Ignore the item at point. +With a prefix argument edit the ignore string." + (interactive "P") + (magit-section-action ignore (info) + ([file untracked] + (magit-ignore-file (concat "/" info) edit local) + (magit-refresh)) + (diff + (when (yes-or-no-p (format "%s is tracked. Untrack and ignore? " info)) + (magit-ignore-file (concat "/" info) edit local) + (magit-run-git "rm" "--cached" info))))) + +(defun magit-ignore-item-locally (edit) + "Ignore the item at point locally only. +With a prefix argument edit the ignore string." + (interactive "P") + (magit-ignore-item edit t)) + +(defun magit-ignore-file (file &optional edit local) + "Add FILE to the list of files to ignore. +If EDIT is non-nil, prompt the user for the string to be ignored +instead of using FILE. The changes are written to .gitignore +except if LOCAL is non-nil in which case they are written to +.git/info/exclude." + (let* ((local-ignore-dir (magit-git-dir "info/")) + (ignore-file (if local + (concat local-ignore-dir "exclude") + ".gitignore"))) + (when edit + (setq file (magit-ignore-edit-string file))) + (when (and local (not (file-exists-p local-ignore-dir))) + (make-directory local-ignore-dir t)) + (with-temp-buffer + (when (file-exists-p ignore-file) + (insert-file-contents ignore-file)) + (goto-char (point-max)) + (unless (bolp) + (insert "\n")) + (insert file "\n") + (write-region nil nil ignore-file)))) + +(defun magit-ignore-edit-string (file) + "Prompt the user for the string to be ignored. +A list of predefined values with wildcards is derived from the +filename FILE." + (let* ((extension (concat "*." (file-name-extension file))) + (extension-in-dir (concat (file-name-directory file) extension)) + (filename (file-name-nondirectory file)) + (completions (list extension extension-in-dir filename file))) + (magit-completing-read "File/pattern to ignore" + completions nil nil nil nil file))) + +;;;; Commit Mark + +(defvar magit-marked-commit nil) + +(defvar-local magit-mark-overlay nil) +(put 'magit-mark-overlay 'permanent-local t) + +(defun magit-mark-item (&optional unmark) + "Mark the commit at point. +Some commands act on the marked commit by default or use it as +default when prompting for a commit." + (interactive "P") + (if unmark + (setq magit-marked-commit nil) + (magit-section-action mark (info) + (commit (setq magit-marked-commit + (if (equal magit-marked-commit info) nil info))))) + (magit-refresh-marked-commits) + (run-hooks 'magit-mark-commit-hook)) + +(defun magit-refresh-marked-commits () + (magit-map-magit-buffers #'magit-refresh-marked-commits-in-buffer)) + +(defun magit-refresh-marked-commits-in-buffer () + (unless magit-mark-overlay + (setq magit-mark-overlay (make-overlay 1 1)) + (overlay-put magit-mark-overlay 'face 'magit-item-mark)) + (delete-overlay magit-mark-overlay) + (magit-map-sections + (lambda (section) + (when (and (eq (magit-section-type section) 'commit) + (equal (magit-section-info section) + magit-marked-commit)) + (move-overlay magit-mark-overlay + (magit-section-beginning section) + (magit-section-end section) + (current-buffer)))) + magit-root-section)) + +;;;; ChangeLog + +;;;###autoload +(defun magit-add-change-log-entry (&optional whoami file-name other-window) + "Find change log file and add date entry and item for current change. +This differs from `add-change-log-entry' (which see) in that +it acts on the current hunk in a Magit buffer instead of on +a position in a file-visiting buffer." + (interactive (list current-prefix-arg + (prompt-for-change-log-name))) + (let (buf pos) + (save-window-excursion + (magit-visit-item) + (setq buf (current-buffer) + pos (point))) + (save-excursion + (with-current-buffer buf + (goto-char pos) + (add-change-log-entry whoami file-name other-window))))) + +;;;###autoload +(defun magit-add-change-log-entry-other-window (&optional whoami file-name) + "Find change log file in other window and add entry and item. +This differs from `add-change-log-entry-other-window' (which see) +in that it acts on the current hunk in a Magit buffer instead of +on a position in a file-visiting buffer." + (interactive (and current-prefix-arg + (list current-prefix-arg + (prompt-for-change-log-name)))) + (magit-add-change-log-entry whoami file-name t)) + +;;;; Read Repository + +(defun magit-read-top-dir (dir) + "Ask the user for a Git repository. +The choices offered by auto-completion will be the repositories +under `magit-repo-dirs'. If `magit-repo-dirs' is nil or DIR is +non-nil, then autocompletion will offer directory names." + (if (and (not dir) magit-repo-dirs) + (let* ((repos (magit-list-repos magit-repo-dirs)) + (reply (magit-completing-read "Git repository" repos))) + (file-name-as-directory + (or (cdr (assoc reply repos)) + (if (file-directory-p reply) + (expand-file-name reply) + (user-error "Not a repository or a directory: %s" reply))))) + (file-name-as-directory + (read-directory-name "Git repository: " + (or (magit-get-top-dir) default-directory))))) + +(defun magit-list-repos (dirs) + (magit-list-repos-remove-conflicts + (cl-loop for dir in dirs + append (cl-loop for repo in + (magit-list-repos* dir magit-repo-dirs-depth) + collect (cons (file-name-nondirectory repo) repo))))) + +(defun magit-list-repos* (dir depth) + "Return a list of repos found in DIR, recursing up to DEPTH levels deep." + (if (file-readable-p (expand-file-name ".git" dir)) + (list (expand-file-name dir)) + (and (> depth 0) + (file-accessible-directory-p dir) + (not (member (file-name-nondirectory dir) + '(".." "."))) + (cl-loop for entry in (directory-files dir t nil t) + append (magit-list-repos* entry (1- depth)))))) + +(defun magit-list-repos-remove-conflicts (alist) + (let ((dict (make-hash-table :test 'equal)) + (alist (delete-dups alist)) + (result nil)) + (dolist (a alist) + (puthash (car a) (cons (cdr a) (gethash (car a) dict)) + dict)) + (maphash + (lambda (key value) + (if (= (length value) 1) + (push (cons key (car value)) result) + (let ((sub (magit-list-repos-remove-conflicts + (mapcar + (lambda (entry) + (let ((dir (directory-file-name + (substring entry 0 (- (length key)))))) + (cons (concat (file-name-nondirectory dir) "/" key) + entry))) + value)))) + (setq result (append result sub))))) + dict) + result)) + +;;;; External Tools + +;;;###autoload +(defun magit-run-git-gui () + "Run `git gui' for the current git repository." + (interactive) + (let* ((default-directory (magit-get-top-dir))) + (call-process magit-git-executable nil 0 nil "gui"))) + +;;;###autoload +(defun magit-run-git-gui-blame (commit filename &optional linenum) + "Run `git gui blame' on the given FILENAME and COMMIT. +Interactively run it for the current file and the HEAD, with a +prefix or when the current file cannot be determined let the user +choose. When the current buffer is visiting FILENAME instruct +blame to center around the line point is on." + (interactive + (let (revision filename) + (when (or current-prefix-arg + (not (setq revision "HEAD" + filename (magit-buffer-file-name t)))) + (setq revision (magit-read-rev "Retrieve from revision" "HEAD") + filename (magit-read-file-from-rev revision))) + (list revision filename + (and (equal filename + (ignore-errors + (magit-file-relative-name (buffer-file-name)))) + (line-number-at-pos))))) + (let ((default-directory (magit-get-top-dir))) + (apply #'call-process magit-git-executable nil 0 nil "gui" "blame" + `(,@(and linenum (list (format "--line=%d" linenum))) + ,commit + ,filename)))) + +;;;###autoload +(defun magit-run-gitk (arg) + "Run Gitk for the current git repository. +Without a prefix argument run `gitk --all', with +a prefix argument run gitk without any arguments." + (interactive "P") + (apply #'call-process magit-gitk-executable nil 0 nil + (if arg nil (list "--all")))) + +;;;; Maintenance Tools + +(defun magit-describe-item () + "Show information about the section at point. +This command is intended for debugging purposes." + (interactive) + (let* ((section (magit-current-section)) + (head-beg (magit-section-beginning section)) + (body-beg (magit-section-content-beginning section))) + (message "Section: %s %s%s-%s %S %S" + (magit-section-type section) + (marker-position (magit-section-beginning section)) + (if (and body-beg (not (= body-beg head-beg)) + (< body-beg (magit-section-end section))) + (format "-%s" (marker-position body-beg)) + "") + (marker-position (magit-section-end section)) + (magit-section-info section) + (magit-section-context-type section)))) + +;;;; Magit Extensions + +(defun magit-load-config-extensions () + "Try to load magit extensions that are defined at git config layer. +This can be added to `magit-mode-hook' for example" + (dolist (ext (magit-get-all "magit.extension")) + (let ((sym (intern (format "magit-%s-mode" ext)))) + (when (and (fboundp sym) + (not (eq sym 'magit-wip-save-mode))) + (funcall sym 1))))) + +;;; magit.el ends soon + +(defconst magit-font-lock-keywords + (eval-when-compile + `((,(concat "(\\(" (regexp-opt + '("magit-define-level-shower" + "magit-define-section-jumper")) + "\\)\\>[ \t'\(]*\\(\\sw+\\)?") + (1 font-lock-keyword-face) + (2 font-lock-function-name-face nil t)) + (,(concat "(" (regexp-opt + '("magit-with-section" + "magit-cmd-insert-section" + "magit-git-insert-section" + "magit-insert-line-section" + "magit-section-action" + "magit-section-case" + "magit-add-action-clauses" + "magit-bind-match-strings" + "magit-visiting-file-item" + "magit-tests--with-temp-dir" + "magit-tests--with-temp-repo" + "magit-tests--with-temp-clone") t) + "\\>") + . 1))) + "Magit expressions to highlight in Emacs-Lisp mode. +To highlight Magit expressions add something like this to your +init file: + + (require 'magit) + (font-lock-add-keywords 'emacs-lisp-mode + magit-font-lock-keywords)") + +(defun magit-version (&optional noerror) + "The version of Magit that you're using.\n\n\(fn)" + (interactive) + (let ((toplib (or load-file-name buffer-file-name))) + (unless (and toplib + (equal (file-name-nondirectory toplib) "magit.el")) + (setq toplib (locate-library "magit.el"))) + (when toplib + (let* ((dir (file-name-directory toplib)) + (static (expand-file-name "magit-version.el" dir)) + (gitdir (expand-file-name ".git" dir))) + (cond ((file-exists-p gitdir) + (setq magit-version + (let ((default-directory dir)) + (magit-git-string "describe" "--tags" "--dirty"))) + (ignore-errors (delete-file static))) + ((file-exists-p static) + (load-file static)) + ((featurep 'package) + (setq magit-version + (or (ignore-errors ; < 24.3.50 + (package-version-join + (package-desc-vers + (cdr (assq 'magit package-alist))))) + (ignore-errors ; >= 24.3.50 + (package-version-join + (package-desc-version + (cadr (assq 'magit package-alist))))))))))) + (if (stringp magit-version) + (when (called-interactively-p 'any) + (message "magit-%s" magit-version)) + (if noerror + (progn (setq magit-version 'error) + (message "Cannot determine Magit's version")) + (user-error "Cannot determine Magit's version"))) + magit-version)) + +(defvar magit-last-seen-setup-instructions "0") + +(defun magit-maybe-show-setup-instructions () + (when (version< magit-last-seen-setup-instructions "1.4.0") + (require 'warnings) + (display-warning :warning "for magit-1.4.0 + +You have just updated to version 1.4.0 of Magit, and have to +make a choice. + +Before running Git, Magit by default reverts all unmodified +buffers which visit files tracked in the current repository. +This can potentially lead to dataloss so you might want to +disable this by adding the following line to your init file: + + (setq magit-auto-revert-mode nil) + +The risk is not as high as it might seem. If snapshots on Melpa +and Melpa-Stable had this enabled for a long time, so if you did +not experience any dataloss in the past, then you should probably +keep this enabled. + +Keeping this mode enabled is only problematic if you, for +example, use `git reset --hard REV' or `magit-reset-head-hard', +and expect Emacs to preserve the old state of some file in a +buffer. If you turn of this mode then file-visiting buffers and +Magit buffer will no longer by in sync, which can be confusing +and complicates many operations. Also note that it is possible +to undo a buffer revert using `C-x u' (`undo'). + +Then you also have to add the following line to your init file +to prevent this message from being shown again when you restart +Emacs: + + (setq magit-last-seen-setup-instructions \"1.4.0\") + +You might also want to read the release notes: +https://raw.githubusercontent.com/magit/magit/next/Documentation/RelNotes/1.4.0.txt")) + (when (featurep 'magit-log-edit) + (display-warning :error "magit-log-edit has to be removed + +Magit is no longer compatible with the library `magit-log-edit', +which was used in earlier releases. Please remove it, so that +Magit can use the successor `git-commit-mode' without the +obsolete library getting in the way. Then restart Emacs. + +You might also want to read: +https://github.com/magit/magit/wiki/Emacsclient"))) + +(add-hook 'after-init-hook #'magit-maybe-show-setup-instructions) + +(provide 'magit) + +(cl-eval-when (load eval) + (magit-version t) + (when after-init-time + (magit-maybe-show-setup-instructions))) + +(require 'magit-key-mode) + +;; Local Variables: +;; coding: utf-8 +;; indent-tabs-mode: nil +;; End: +;;; magit.el ends here diff --git a/elpa/magit-1.4.1/magit.info b/elpa/magit-1.4.1/magit.info new file mode 100644 index 0000000..46be711 --- /dev/null +++ b/elpa/magit-1.4.1/magit.info @@ -0,0 +1,1596 @@ +This is magit.info, produced by makeinfo version 4.13 from magit.texi. + +Magit is an interface to the version control system Git, implemented as +an Emacs package. + + Unlike Emacs's native Version Control package which strives to +provide a unified interface to various version control systems, Magit +only supports Git and can therefor better take advantage of its native +features. + + You are looking at the manual for the `1.4.0' release. + + Magit supports GNU Emacs 23.2 or later; 24.1 or later is recommended. +Magit supports Git 1.7.2.5 or later; 1.8.2 or later is recommended. + + When something breaks please see the curated list of known issues +(https://github.com/magit/magit/wiki/Known-Issues) and the FAQ +(https://github.com/magit/magit/wiki/FAQ). If that doesn't help check +the list of all open issues issues +(https://github.com/magit/magit/issues). + + If everything else fails please open a new issue or ask for help on +the mailing list +(https://groups.google.com/forum/?fromgroups#!forum/magit). + + Copyright (C) 2008-2015 The Magit Project Developers + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation License, + Version 1.2 or any later version published by the Free Software + Foundation; with no Invariant Sections, with no Front-Cover Texts, + and with no Back-Cover Texts. A copy of the license is included + in the section entitled "GNU Free Documentation License". + +INFO-DIR-SECTION Emacs +START-INFO-DIR-ENTRY +* Magit (1.4.0): (magit). Using Git from Emacs with Magit. (1.4.0) +END-INFO-DIR-ENTRY + + +File: magit.info, Node: Top, Next: Introduction, Up: (dir) + +Magit User Manual (1.4.0) +************************* + +Magit is an interface to the version control system Git, implemented as +an Emacs package. + + Unlike Emacs's native Version Control package which strives to +provide a unified interface to various version control systems, Magit +only supports Git and can therefor better take advantage of its native +features. + + You are looking at the manual for the `1.4.0' release. + + Magit supports GNU Emacs 23.2 or later; 24.1 or later is recommended. +Magit supports Git 1.7.2.5 or later; 1.8.2 or later is recommended. + + When something breaks please see the curated list of known issues +(https://github.com/magit/magit/wiki/Known-Issues) and the FAQ +(https://github.com/magit/magit/wiki/FAQ). If that doesn't help check +the list of all open issues issues +(https://github.com/magit/magit/issues). + + If everything else fails please open a new issue or ask for help on +the mailing list +(https://groups.google.com/forum/?fromgroups#!forum/magit). + + Copyright (C) 2008-2015 The Magit Project Developers + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation License, + Version 1.2 or any later version published by the Free Software + Foundation; with no Invariant Sections, with no Front-Cover Texts, + and with no Back-Cover Texts. A copy of the license is included + in the section entitled "GNU Free Documentation License". + +* Menu: + +* Introduction:: +* Acknowledgments:: +* Sections:: +* Status:: +* Untracked files:: +* Staging and Committing:: +* History:: +* Reflogs:: +* Commit Buffer:: +* Diffing:: +* Tagging:: +* Resetting:: +* Stashing:: +* Branches and Remotes:: +* Wazzup:: +* Merging:: +* Rebasing:: +* Interactive Rebasing:: +* Rewriting:: +* Pushing and Pulling:: +* Submodules:: +* Bisecting:: +* Finding commits not merged upstream:: +* Using Magit Extensions:: +* Using Git Directly:: +* GNU Free Documentation License:: + + +File: magit.info, Node: Introduction, Next: Acknowledgments, Prev: Top, Up: Top + +1 Introduction +************** + +With Magit, you can inspect and modify your Git repositories with +Emacs. You can review and commit the changes you have made to the +tracked files, for example, and you can browse the history of past +changes. There is support for cherry picking, reverting, merging, +rebasing, and other common Git operations. + + Magit is not a complete interface to Git; it just aims to make the +most common Git operations convenient. Thus, Magit will likely not +save you from learning Git itself. + + This manual provides a tour of many Magit features. It isn't an +introduction to version control in general, or to Git in particular. + + The main entry point to Magit is `M-x magit-status', which puts you +in Magit's status buffer. You will be using it frequently, so it is +probably a good idea to globally bind `magit-status' to a key of your +choice. + + In addition to the status buffer, Magit will also create buffers that +show lists of commits, buffers with diffs, and other kinds of buffers. +All these buffers are in a mode derived from `magit-mode' and have the +similar key bindings. Not all commands make sense in all contexts, but +a given key will do the same thing in different Magit buffers. + + Naturally, Magit runs the `git' command to do most of the work. The +`*magit-process*' buffer contains the transcript of the most recent +command. You can switch to it with `$'. + + +File: magit.info, Node: Acknowledgments, Next: Sections, Prev: Introduction, Up: Top + +2 Acknowledgments +***************** + +Our thank goes to all current and past contributors, Marius Vollmer who +started the project, and all retired and current maintainers, Phil +Jackson, Peter J. Weisberg, RĂ©mi Vanicat, Nicolas Dudebout, Yann +Hodique, and Jonas Bernoulli. + + For a full list of contributors, see the AUTHORS.md file at the +top-level directory of this distribution or at AUTHORS.md +(https://github.com/magit/magit/tree/master/AUTHORS.md). + + +File: magit.info, Node: Sections, Next: Status, Prev: Acknowledgments, Up: Top + +3 Sections +********** + +All Magit buffers are structured into nested 'sections'. These +sections can be hidden and shown individually. When a section is +hidden, only its first line is shown and all its children are +completely invisible. + + The most fine-grained way to control the visibility of sections is +the `TAB' key. It will to toggle the current section (the section that +contains point) between being hidden and being shown. + + Typing `S-TAB' toggles the visibility of the children of the current +section. When all of them are shown, they will all be hidden. +Otherwise, when some or all are hidden, they will all be shown. + + The digit keys `1', `2', `3', and `4' control the visibility of +sections based on levels. Hitting `2', for example, will show sections +on levels one and two, and will hide sections on level 3. However, +only sections that are a parent or child of the current section are +affected. + + For example, when the current section is on level 3 and you hit `1', +the grand-parent of the current section (which is on level one) will be +shown, and the parent of the current section (level 2) will be hidden. +The visibility of no other section will be changed. + + This sounds a bit complicated, but you'll figure it out. + + Using `M-1', `M-2', `M-3', and `M-4' is similar to the unmodified +digits, but now all sections on the respective level are affected, +regardless of whether or not they are related to the current section. + + For example, `M-1' will only show the first lines of the top-level +sections and will hide everything else. Typing `M-4' on the other hand +will show everything. + + Because of the way the status buffer is set up, some changes to +section visibility are more common than others. Files are on level 2 +and diff hunks are on level 4. Thus, you can type `2' to collapse the +diff of the current file, and `M-2' to collapse all files. This +returns the status buffer to its default setup and is a quick way to +unclutter it after drilling down into the modified files. + + Because `2' and `M-2' are so common in the status buffer, they are +bound to additional, more mnemonic keys: `M-h' (hide) and `M-H' (hide +all). Likewise `4' and `M-4' are also available as `M-s' (show) and +`M-S' (show all). + + In other buffers than the status buffer, `M-h', `M-H', `M-s', and +`M-S' might work on different levels than on 2 and 4, but they keep +their general meaning: `M-H' hides all detail, and `M-S' shows +everything. + + +File: magit.info, Node: Status, Next: Untracked files, Prev: Sections, Up: Top + +4 Status +******** + +Running `M-x magit-status' displays the main interface of Magit, the +status buffer. You can have multiple status buffers active at the same +time, each associated with its own Git repository. + + When invoking `M-x magit-status' from within a Git repository, it +will switch to the status buffer of that repository. Otherwise, it +will prompt for a directory. With a prefix argument, it will always +prompt. + + You can set `magit-repo-dirs' to customize how `magit-status' asks +for the repository to work on. When `magit-repo-dirs' is nil, +`magit-status' will simply ask for a directory. + + If you specify a directory that is not a Git repository, `M-x +magit-status' will offer to initialize it as one. + + When `magit-repo-dirs' is not nil, it is treated as a list of +directory names, and `magit-status' will find all Git repositories in +those directories and offer them for completion. (Magit will only look +`magit-repo-dirs-depth' levels deep, however.) + + With two prefix arguments, `magit-status' will always prompt for a +raw directory. + + Thus, you would normally set `magit-repo-dirs' to the places where +you keep most of your Git repositories and switch between them with +`C-u M-x magit-status'. If you want to go to a repository outside of +your normal working areas, or if you want to create a new repository, +you would use `C-u C-u M-x magit-status'. + + You need to explicitly refresh the status buffer when you have made +changes to the repository from outside of Emacs. You can type `g' in +the status buffer itself, or just use `M-x magit-status' instead of +`C-x b' when switching to it. You also need to refresh the status +buffer in this way after saving a file in Emacs. + + The header at the top of the status buffer shows a short summary of +the repository state: where it is located, which branch is checked out, +etc. Below the header are a number of sections that show details about +the working tree and the staging area. You can hide and show them as +described in the previous section. + + The first section shows _Untracked files_, if there are any. See +*note Untracked files:: for more details. + + The next two sections show your local changes. They are explained +fully in the next chapter, *note Staging and Committing::. + + If the current branch is associated with a remote tracking branch, +the status buffer shows the differences between the current branch and +the tracking branch. See *note Pushing and Pulling:: for more +information. + + During a history rewriting session, the status buffer shows the +_Pending changes_ and _Pending commits_ sections. See *note +Rewriting:: for more details. + + +File: magit.info, Node: Untracked files, Next: Staging and Committing, Prev: Status, Up: Top + +5 Untracked files +***************** + +Untracked files are shown in the _Untracked files_ section. + + You can add an untracked file to the staging area with `s'. If +point is on the _Untracked files_ section title when you hit `s', all +untracked files are staged. + + Typing `C-u S' anywhere will also stage all untracked files, +together with all changes to the tracked files. + + You can instruct Git to ignore them by typing `i'. This will add +the filename to the `.gitignore' file. Typing `C-u i' will ask you for +the name of the file to ignore. This is useful to ignore whole +directories, for example. In this case, the minibuffer's future history +(accessible with `M-n') contains predefined values (such as wildcards) +that might be of interest. If prefix argument is negative (for example +after typing `C-- i'), the prompt proposes wildcard by default. The +`I' command is similar to `i' but will add the file to +`.git/info/exclude' instead. + + To delete an untracked file forever, use `k'. If point is on the +_Untracked files_ section title when you hit `k', all untracked files +are deleted. + + +File: magit.info, Node: Staging and Committing, Next: History, Prev: Untracked files, Up: Top + +6 Staging and Committing +************************ + +Committing with Git is a two step process: first you add the changes +you want to commit to a 'staging area' or 'index', and then you commit +them to the repository. This allows you to only commit a subset of the +changes in the working tree. If you are not familiar with this concept +yet, then you should change that as soon as possible using one of the +fine Git tutorials. If you don't, then Git and by extension Magit will +seem rather strange. + + Magit shows uncommitted changes in two sections, depending on whether +the changes have been staged yet. The _Staged changes_ section shows +the changes that will be included in the next commit, while the +_Unstaged changes_ section shows the changes that will be left out. + + To move an unstaged hunk into the staging area, move point into the +hunk and type `s'. Likewise, to unstage a hunk, move point into it and +type `u'. If point is in a diff header when you type `s' or `u', all +hunks belonging to that diff are moved at the same time. + + Currently it is only possible to stage from the status buffer. +Staging and unstaging from diff buffers that show unstaged and staged +changes is not possible yet. + + If the region is active when you type `s' or `u', only the changes +in the region are staged or unstaged. (This works line by line: if the +beginning of a line is in the region it is included in the changes, +otherwise it is not.) + + To change the size of the hunks, you can type `+' or `-' to increase +and decrease, respectively. Typing `0' will reset the hunk size to the +default. + + Typing `C-u s' will ask you for a name of a file to be staged, for +example to stage files that are hidden. + + To move all hunks of all diffs into the staging area in one go, type +`S'. To unstage everything, type `U'. + + Typing `C-u S' will stage all untracked files in addition to the +changes to tracked files. + + You can discard uncommitted changes by moving point into a hunk and +typing `k'. The changes to discard are selected as with `s' and `u'. + + Before committing, you should write a short description of the +changes. + + Type `c c' to pop up a buffer where you can write your change +description. Once you are happy with the description, type `C-c C-c' +in that buffer to perform the commit. + + If you want to write changes in a `ChangeLog' file, you can use `C-x +4 a' on a diff hunk. + + Typing `c c' when the staging area is unused is a special situation. +Normally, the next commit would be empty, but you can configure Magit +to do something more useful by customizing the +`magit-commit-all-when-nothing-staged' variable. One choice is to +instruct the subsequent `C-c C-c' to commit all changes. Another +choice is stage everything at the time of hitting `c c'. + + Typing `M-n' or `M-p' will cycle through the +`log-edit-comment-ring', which will have your previous log messages. +This is particularly useful if you have a hook that occasionally causes +git to refuse your commit. + + To abort a commit use `C-c C-k'. The commit message is saved and +can later be retrieved in the commit message buffer using `M-n' and +`M-p'. + + Typing `C' will also pop up the change description buffer, but in +addition, it will try to insert a ChangeLog-style entry for the change +that point is in. + + +File: magit.info, Node: History, Next: Reflogs, Prev: Staging and Committing, Up: Top + +7 History +********* + +To show the repository history of your current head, type `l l'. A new +buffer will be shown that displays the history in a terse form. The +first paragraph of each commit message is displayed, next to a +representation of the relationships between commits. + + To show the repository history between two branches or between any +two points of the history, type `l r l'. You will be prompted to enter +references for starting point and ending point of the history range; you +can use auto-completion to specify them. A typical use case for ranged +history log display would be `l r l master RET new-feature RET' that +will display commits on the new-feature branch that are not in master; +these commits can then be inspected and cherry-picked, for example. + + More thorough filtering can be done by supplying `l' with one or +more suffix arguments, as displayed in its popup. `=g' ('Grep') for +example, limits the output to commits of which the log message matches +a specific string/regex. + + Typing `l L' (or `l C-u L') will show the log in a more verbose form. + + Magit will show only `magit-log-cutoff-length' entries. `e' will +show twice as many entries. `C-u e' will show all entries, and given a +numeric prefix argument, `e' will add this number of entries. + + You can move point to a commit and then cause various things to +happen with it. (The following commands work in any list of commits, +such as the one shown in the _Unpushed commits_ section.) + + Typing `RET' will pop up more information about the current commit +and move point into the new buffer. *Note Commit Buffer::. Typing +`SPC' and `DEL' will also show the information, but will scroll the new +buffer up or down (respectively) when typed again. + + Typing `a' will apply the current commit to your current branch. +This is useful when you are browsing the history of some other branch +and you want to `cherry-pick' some changes from it. A typical +situation is applying selected bug fixes from the development version +of a program to a release branch. The cherry-picked changes will not +be committed automatically; you need to do that explicitly. + + Typing `A' will cherry-pick the current commit and will also commit +the changes automatically when there have not been any conflicts. + + Typing `v' will revert the current commit. Thus, it will apply the +changes made by that commit in reverse. This is obviously useful to +cleanly undo changes that turned out to be wrong. As with `a', you +need to commit the changes explicitly. + + Typing `C-w' will copy the sha1 of the current commit into the kill +ring. + + Typing `=' will show the differences from the current commit to the +"marked" commit. + + You can mark the current commit by typing `.'. When the current +commit is already marked, typing `.' will unmark it. To unmark the +marked commit no matter where point is, use `C-u .'. + + Some commands, such as `=', will use the current commit and the +marked commit as implicit arguments. Other commands will offer the +marked commit as a default when prompting for their arguments. + + +File: magit.info, Node: Reflogs, Next: Commit Buffer, Prev: History, Up: Top + +8 Reflogs +********* + +You can use `l h' and `l H' to browse your _reflog_, the local history +of changes made to your repository heads. Typing `H' will ask for a +head, while `l h' will show the reflog of `HEAD'. + + The resulting buffer is just like the buffer produced by `l l' and +`l L' that shows the commit history. + + +File: magit.info, Node: Commit Buffer, Next: Diffing, Prev: Reflogs, Up: Top + +9 Commit Buffer +*************** + +When you view a commit (perhaps by selecting it in the log buffer, +*note History::), the "commit buffer" is displayed, showing you +information about the commit and letting you interact with it. + + By placing your cursor within the diff or hunk and typing `a', you +can apply the same patch to your working copy. This is useful when you +want to copy a change from another branch, but don't necessarily want +to cherry-pick the whole commit. + + By typing `v' you can apply the patch in reverse, removing all the +lines that were added and adding all the lines that were removed. This +is a convenient way to remove a change after determining that it +introduced a bug. + + If the commit message refers to any other commits in the repository +by their unique hash, the hash will be highlighted and you will be able +to visit the referenced commit either by clicking on it or by moving +your cursor onto it and pressing `RET'. + + The commit buffer maintains a history of the commits it has shown. +After visiting a referenced commit you can type `C-c C-b' to get back +to where you came from. To go forward in the history, type `C-c C-f'. +There are also `[back]' and `[forward]' buttons at the bottom of the +buffer. + + +File: magit.info, Node: Diffing, Next: Tagging, Prev: Commit Buffer, Up: Top + +10 Diffing +********** + +Magit typically shows diffs in the "unified" format. + + In any buffer that shows a diff, you can type `e' anywhere within +the diff to show the two versions of the file in Ediff. If the diff is +of a file in the status buffer that needs to be merged, you will be +able to use Ediff as an interactive merge tool. Otherwise, Ediff will +simply show the two versions of the file. + + To show the changes from your working tree to another revision, type +`d'. To show the changes between two arbitrary revisions, type `D'. + + You can use `a' within the diff output to apply the changes to your +working tree. As usual when point is in a diff header for a file, all +changes for that file are applied, and when it is in a hunk, only that +hunk is. When the region is active, the applied changes are restricted +to that region. + + Typing `v' will apply the selected changes in reverse. + + +File: magit.info, Node: Tagging, Next: Resetting, Prev: Diffing, Up: Top + +11 Tagging +********** + +Typing `t t' will make a lightweight tag. Typing `t a' will make an +annotated tag. It will put you in the normal `*magit-log-edit' buffer +for writing commit messages, but typing `C-c C-c' in it will make the +tag instead. This is controlled by the `Tag' field that will be added +to the `*magit-log-edit*' buffer. You can edit it, if you like. + + +File: magit.info, Node: Resetting, Next: Stashing, Prev: Tagging, Up: Top + +12 Resetting +************ + +Once you have added a commit to your local repository, you can not +change that commit anymore in any way. But you can reset your current +head to an earlier commit and start over. + + If you have published your history already, rewriting it in this way +can be confusing and should be avoided. However, rewriting your local +history is fine and it is often cleaner to fix mistakes this way than +by reverting commits (with `v', for example). + + Typing `x' will ask for a revision and reset your current head to +it. No changes will be made to your working tree and staging area. +Thus, the _Staged changes_ section in the status buffer will show the +changes that you have removed from your commit history. You can commit +the changes again as if you had just made them, thus rewriting history. + + Typing `x' while point is in a line that describes a commit will +offer this commit as the default revision to reset to. Thus, you can +move point to one of the commits in the _Unpushed commits_ section and +hit `x RET' to reset your current head to it. + + Type `X' to reset your working tree and staging area to the most +recently committed state. This will discard your local modifications, +so be careful. + + You can give a prefix to `x' if you want to reset both the current +head and your working tree to a given commit. This is the same as +first using an unprefixed `x' to reset only the head, and then using +`X'. + + +File: magit.info, Node: Stashing, Next: Branches and Remotes, Prev: Resetting, Up: Top + +13 Stashing +*********** + +You can create a new stash with `z z'. Your stashes will be listed in +the status buffer, and you can apply them with `a' and pop them with +`A'. To drop a stash, use `k'. + + With a prefix argument, both `a' and `A' will attempt to reinstate +the index as well as the working tree from the stash. + + Typing `z -k z' will create a stash just like `z z', but will leave +the changes in your working tree and index. This makes it easier to, +for example, test multiple variations of the same change. + + If you just want to make quick snapshots in between edits, you can +use `z s', which automatically enters a timestamp as description, and +keeps your working tree and index intact by default. + + You can visit and show stashes in the usual way: Typing `SPC' and +`DEL' will pop up a buffer with the description of the stash and scroll +it, typing `RET' will move point into that buffer. Using `C-u RET' +will move point into that buffer in other window. + + +File: magit.info, Node: Branches and Remotes, Next: Wazzup, Prev: Stashing, Up: Top + +14 Branches and Remotes +*********************** + +The current branch is indicated in the header of the status buffer. If +this branch is tracking a remote branch, the latter is also indicated. + + Branches and remotes can be manipulated directly with a popup menu or +through the branch manager. Using the popup menu allows you to quickly +make changes from any magit buffer. The branch manager is a separate +buffer called `*magit-branches*'. It displays information about +branches and remotes and offers a local key map for shorter key +bindings. The two interaction methods are described in more details +below. + +* Menu: + +* Branches Popup:: +* Remotes Popup:: +* Branches in the Branch Manager:: +* Remotes in the Branch Manager:: + + +File: magit.info, Node: Branches Popup, Next: Remotes Popup, Up: Branches and Remotes + +14.1 Branches Popup +=================== + +Typing `b' will display a popup menu to manipulate branches. + + You can switch to a different branch by typing `b b'. This will +immediately checkout the branch into your working copy, so you +shouldn't have any local modifications when switching branches. + + If you try to switch to a remote branch, Magit will offer to create a +local tracking branch for it instead. This way, you can easily start +working on new branches that have appeared in a remote repository. + + Typing `b b' while point is at a commit description will offer that +commit as the default to switch to. This will result in a detached +head. + + To create a new branch and switch to it immediately, type `b c'. + + To delete a branch, type `b k'. If you're currently on that branch, +Magit will offer to switch to the 'master' branch. + + Typing `b r' will let you rename a branch. Unless a branch with +the same name already exists, obviously... + + Deleting a branch is only possible if it's already fully merged into +HEAD or its upstream branch. Unless you type `b C-u k', that is. Here +be dragons... + + Typing `b v' will launch the branch manager. + + +File: magit.info, Node: Remotes Popup, Next: Branches in the Branch Manager, Prev: Branches Popup, Up: Branches and Remotes + +14.2 Remotes Popup +================== + +Typing `M' will display a popup menu to manipulate remotes. + + To add a new remote, type `M a'. + + To delete a remote type `M k'. + + Typing `M r' will let you rename a remote. + + +File: magit.info, Node: Branches in the Branch Manager, Next: Remotes in the Branch Manager, Prev: Remotes Popup, Up: Branches and Remotes + +14.3 Branches in the Branch Manager +=================================== + +In the branch manager, each branch is displayed on a separate line. The +current local branch is marked by a "*" in front of the name. Remote +branches are grouped by the remote they come from. + + If a local branch tracks a remote branch some extra information is +printed on the branch line. The format is the following: " +[ : ahead , behind ]". "" +is omitted if it is identical to "". "ahead" and "behind" +information are only displayed if necessary. + + To check out a branch, move your cursor to the desired branch and +press `RET'. + + Typing `c' will create a new branch. + + Typing `k' will delete the branch in the current line, and `C-u k' +deletes it even if it hasn't been merged into the current local branch. +Deleting works for both local and remote branches. + + Typing `r' on a branch will rename it. + + Typing `T' on a local branch, changes which remote branch it tracks. + + +File: magit.info, Node: Remotes in the Branch Manager, Prev: Branches in the Branch Manager, Up: Branches and Remotes + +14.4 Remotes in the Branch Manager +================================== + +In the branch manager, each remote is displayed on a separate line. The +format is the following " (, )". "" +is omitted if it is not set. The associated branches are listed under +this line. + + Typing `a' will add a new remote. + + Typing `k' will delete the remote in the current line. + + Typing `r' on a remote will rename it. + + +File: magit.info, Node: Wazzup, Next: Merging, Prev: Branches and Remotes, Up: Top + +15 Wazzup +********* + +Typing `w' will show a summary of how your other branches relate to the +current branch. + + For each branch, you will get a section that lists the commits in +that branch that are not in the current branch. The sections are +initially collapsed; you need to explicitly open them with `TAB' (or +similar) to show the lists of commits. + + When point is on a _N unmerged commits in ..._ title, the +corresponding branch will be offered as the default for a merge. + + Hitting `i' on a branch title will ignore this branch in the wazzup +view. You can use `C-u w' to show all branches, including the ignored +ones. Hitting `i' on an already ignored branch in that view will +unignore it. + + +File: magit.info, Node: Merging, Next: Rebasing, Prev: Wazzup, Up: Top + +16 Merging +********** + +Magit offers two ways to merge branches: manual and automatic. A +manual merge will apply all changes to your working tree and staging +area, but will not commit them, while an automatic merge will go ahead +and commit them immediately. + + Type `m m' to initiate merge. + + After initiating a merge, the header of the status buffer might +remind you that the next commit will be a merge commit (with more than +one parent). If you want to abort a manual merge, just do a hard reset +to HEAD with `X'. + + Merges can fail if the two branches you want to merge introduce +conflicting changes. In that case, the automatic merge stops before the +commit, essentially falling back to a manual merge. You need to resolve +the conflicts for example with `e' and stage the resolved files, for +example with `S'. + + You can not stage individual hunks one by one as you resolve them, +you can only stage whole files once all conflicts in them have been +resolved. + + +File: magit.info, Node: Rebasing, Next: Interactive Rebasing, Prev: Merging, Up: Top + +17 Rebasing +*********** + +Typing `R' in the status buffer will initiate a rebase or, if one is +already in progress, ask you how to continue. + + When a rebase is stopped in the middle because of a conflict, the +header of the status buffer will indicate how far along you are in the +series of commits that are being replayed. When that happens, you +should resolve the conflicts and stage everything and hit `R c' to +continue the rebase. Alternatively, hitting `c' or `C' while in the +middle of a rebase will also ask you whether to continue the rebase. + + Of course, you can initiate a rebase in any number of ways, by +configuring `git pull' to rebase instead of merge, for example. Such a +rebase can be finished with `R' as well. + + +File: magit.info, Node: Interactive Rebasing, Next: Rewriting, Prev: Rebasing, Up: Top + +18 Interactive Rebasing +*********************** + +Typing `E' in the status buffer will initiate an interactive rebase. +This is equivalent to running `git rebase --interactive' at the command +line. The `git-rebase-todo' file will be opened in an Emacs buffer for +you to edit. This file is opened using `emacsclient', so just edit +this file as you normally would, then call the `server-edit' function +(typically bound to `C-x #') to tell Emacs you are finished editing, +and the rebase will proceed as usual. + + If you have loaded `rebase-mode.el' (which is included in the Magit +distribution), the `git-rebase-todo' buffer will be in `rebase-mode'. +This mode disables normal text editing but instead provides single-key +commands (shown in the buffer) to perform all the edits that you would +normally do manually, including changing the operation to be performed +each commit ("pick", "squash", etc.), deleting (commenting out) commits +from the list, and reordering commits. You can finish editing the +buffer and proceed with the rebase by pressing `C-c C-c', which is +bound to `server-edit' in this mode, and you can abort the rebase with +`C-c C-k', just like when editing a commit message in Magit. + + +File: magit.info, Node: Rewriting, Next: Pushing and Pulling, Prev: Interactive Rebasing, Up: Top + +19 Rewriting +************ + +As hinted at earlier, you can rewrite your commit history. For +example, you can reset the current head to an earlier commit with `x'. +This leaves the working tree unchanged, and the status buffer will show +all the changes that have been made since that new value of the current +head. You can commit these changes again, possibly splitting them into +multiple commits as you go along. + + Amending your last commit is a common special case of rewriting +history like this. + + Another common way to rewrite history is to reset the head to an +earlier commit, and then to cherry pick the previous commits in a +different order. You could pick them from the reflog, for example. + + Magit has several commands that can simplify the book keeping +associated with rewriting. These commands all start with the `r' +prefix key. + + (Unless you already do so, we recommend that you don't use the +functionality described here. It is semi-deprecated and will be +removed once its unique features have been ported to the `git rebase +--interactive' workflow. Even now the latter is almost always the +better option.) + + Typing `r b' will start a rewrite operation. You will be prompted +for a _base_ commit. This commit and all subsequent commits up until +the current head are then put in a list of _Pending commits_, after +which the current head will be reset to the _parent_ of the base +commit. This can be configured to behave like `git rebase', i.e. +exclude the selected base commit from the rewrite operation, with the +`magit-rewrite-inclusive' variable. + + You would then typically use `a' and `A' to cherry pick commits from +the list of pending commits in the desired order, until all have been +applied. Magit shows which commits have been applied by changing their +marker from `*' to `.'. + + Using `A' will immediately commit the commit (as usual). If you +want to combine multiple previous commits into a single new one, use +`a' to apply them all to your working tree, and then commit them +together. + + Magit has no explicit support for rewriting merge commits. It will +happily include merge commits in the list of pending commits, but there +is no way of replaying them automatically. You have to redo the merge +explicitly. + + You can also use `v' to revert a commit when you have changed your +mind. This will change the `.' mark back to `*'. + + Once you are done with the rewrite, type `r s' to remove the book +keeping information from the status buffer. + + If you rather wish to start over, type `r a'. This will abort the +rewriting, resetting the current head back to the value it had before +the rewrite was started with `r b'. + + Typing `r f' will _finish_ the rewrite: it will apply all unused +commits one after the other, as if you would use `A' with all of them. + + You can change the `*' and `.' marks of a pending commit explicitly +with `r *' and `r .'. + + In addition to a list of pending commits, the status buffer will show +the _Pending changes_. This section shows the diff between the +original head and the current head. You can use it to review the +changes that you still need to rewrite, and you can apply hunks from +it, like from any other diff. + + +File: magit.info, Node: Pushing and Pulling, Next: Submodules, Prev: Rewriting, Up: Top + +20 Pushing and Pulling +********************** + +Magit will run `git push' when you type `P P'. If you give a prefix +argument to `P P', you will be prompted for the repository to push to. +When no default remote repository has been configured yet for the +current branch, you will be prompted as well. Typing `P P' will only +push the current branch to the remote. In other words, it will run +`git push '. The branch will be created in the remote +if it doesn't exist already. The local branch will be configured so +that it pulls from the new remote branch. If you give a double prefix +argument to `P P', you will be prompted in addition for the target +branch to push to. In other words, it will run `git push +:'. + + Typing `f f' will run `git fetch'. It will prompt for the name of +the remote to update if there is no default one. Typing `f o' will +always prompt for the remote. Typing `F F' will run `git pull'. When +you don't have a default branch configured to be pulled into the +current one, you will be asked for it. + + If there is a default remote repository for the current branch, Magit +will show that repository in the status buffer header. + + In this case, the status buffer will also have a _Unpushed commits_ +section that shows the commits on your current head that are not in the +branch named `/'. This section works just like the +history buffer: you can see details about a commit with `RET', compare +two of them with `.' and `=', and you can reset your current head to +one of them with `x', for example. If you want to push the changes +then type `P P'. + + When the remote branch has changes that are not in the current +branch, Magit shows them in a section called _Unpulled changes_. Typing +`F F' will fetch and merge them into the current branch. + + +File: magit.info, Node: Submodules, Next: Bisecting, Prev: Pushing and Pulling, Up: Top + +21 Submodules +************* + +`o u' + Update the submodules, with a prefix argument it will also + initialize them. + +`o i' + Initialize the submodules. + +`o b' + Update and initialize the submodules in one go (same as C-u o u). + +`o s' + Synchronizes submodules' remote URL configuration setting to the + value specified in .gitmodules. + + +File: magit.info, Node: Bisecting, Next: Finding commits not merged upstream, Prev: Submodules, Up: Top + +22 Bisecting +************ + +Magit supports bisecting by showing how many revisions and steps are +left to be tested in the status buffer. You can control the bisect +session from both the status and from log buffers with the `B' key menu. + + Typing `B s' will start a bisect session. You will be prompted for +a revision that is known to be bad (defaults to _HEAD_) and for a +revision that is known to be good (defaults to the revision at point if +there is one). git will select a revision for you to test, and Magit +will update its status buffer accordingly. + + You can tell git that the current revision is good with `B g', that +it is bad with `B b' or that git should skip it with `B k'. You can +also tell git to go into full automatic mode by giving it the name of a +script to run for each revision to test with `B u'. + + The current status can be shown as a log with `B l'. It contains +the revisions that have already been tested and your decisions about +their state. + + The revisions left to test can be visualized in gitk with `B v'. + + When you're finished bisecting you have to reset the session with `B +r'. + + +File: magit.info, Node: Finding commits not merged upstream, Next: Using Magit Extensions, Prev: Bisecting, Up: Top + +23 Finding commits not merged upstream +************************************** + +One of the comforts of git is that it can tell you which commits have +been merged upstream but not locally and vice versa. Git's sub-command +for this is `cherry' (not to be confused with `cherry-pick'). Magit +has support for this by invoking `magit-cherry' which is bound to `y' +by default. + + Magit will then ask you first for the upstream revision (which +defaults to the currently tracked remote branch if any) and the head +revision (which defaults to the current branch) to use in the +comparison. You will then see a new buffer in which all commits are +listed with a directional marker, their revision and the commit +message's first line. The directional marker is either `+' indicating +a commit that's present in upstream but not in head or `-' which +indicates a commit present in head but not in upstream. + + From this list you can use the usual key bindings for cherry-picking +individual commits (`a' for cherry-picking without committing and `A' +for the same plus the automatic commit). The buffer is refreshed +automatically after each cherry-pick. + + +File: magit.info, Node: Using Magit Extensions, Next: Using Git Directly, Prev: Finding commits not merged upstream, Up: Top + +24 Magit Extensions +******************* + +* Menu: + +* Activating extensions:: +* Interfacing with Subversion:: +* Interfacing with Topgit:: +* Interfacing with StGit:: + + +File: magit.info, Node: Activating extensions, Next: Interfacing with Subversion, Up: Using Magit Extensions + +24.1 Activating extensions +========================== + +Magit comes with a couple of shipped extensions that allow interaction +with `git-svn', `topgit' and `stgit'. See following sections for +specific details on how to use them. + + Extensions can be activated globally or on a per-repository basis. +Since those extensions are implemented as minor modes, one can use for +example `M-x magit-topgit-mode' to toggle the `topgit' extension, +making the corresponding section and commands (un)available. + + In order to do that automatically (and for every repository), one can +use for example: + + (add-hook 'magit-mode-hook 'turn-on-magit-topgit) + + Magit also allows configuring different extensions, based on the git +repository configuration. + + (add-hook 'magit-mode-hook 'magit-load-config-extensions) + + This will read git configuration variables and activate the relevant +extensions. + + For example, after running the following commands, the `topgit' +extension will be loaded for every repository, while the `svn' one will +be loaded only for the current one. + + $ git config --global --add magit.extension topgit + $ git config --add magit.extension svn + + Note the `--add' flag, which means that each extension gets its own +line in the `config' file. + + +File: magit.info, Node: Interfacing with Subversion, Next: Interfacing with Topgit, Prev: Activating extensions, Up: Using Magit Extensions + +24.2 Interfacing with Subversion +================================ + +Typing `N r' runs `git svn rebase', typing `N c' runs `git svn dcommit' +and typing `N f' runs `git svn fetch'. + + `N s' will prompt you for a (numeric, Subversion) revision and then +search for a corresponding Git sha1 for the commit. This is limited to +the path of the remote Subversion repository. With a prefix (`C-u N s' +the user will also be prompted for a branch to search in. + + +File: magit.info, Node: Interfacing with Topgit, Next: Interfacing with StGit, Prev: Interfacing with Subversion, Up: Using Magit Extensions + +24.3 Interfacing with Topgit +============================ + +Topgit (http://repo.or.cz/r/topgit.git) is a patch queue manager that +aims at being close as possible to raw Git, which makes it easy to use +with Magit. In particular, it does not require to use a different set +of commands for "commit", "update", and other operations. + + `magit-topgit.el' provides basic integration with Magit, mostly by +providing a "Topics" section. + + Topgit branches can be created the regular way, by using a "t/" +prefix by convention. So, creating a "t/foo" branch will actually +populate the "Topics" section with one more branch after committing +`.topdeps' and `.topmsg'. + + Also, the way we pull (see *note Pushing and Pulling::) such a +branch is slightly different, since it requires updating the various +dependencies of that branch. This should be mostly transparent, except +in case of conflicts. + + +File: magit.info, Node: Interfacing with StGit, Prev: Interfacing with Topgit, Up: Using Magit Extensions + +24.4 Interfacing with StGit +=========================== + +StGit (http://www.procode.org/stgit) is a Python application providing +similar functionality to Quilt (i.e. pushing/popping patches to/from a +stack) on top of Git. These operations are performed using Git +commands and the patches are stored as Git commit objects, allowing +easy merging of the StGit patches into other repositories using +standard Git functionality. + + `magit-stgit.el' provides basic integration with Magit, mostly by +providing a "Series" section, whose patches can be seen as regular +commits through the "visit" action. + + You can change the current patch in a series with the "apply" action, +as well as you can delete them using the "discard" action. + + Additionally, the `magit-stgit-refresh' and `magit-stgit-rebase' +commands let you perform the respective StGit operations. + + +File: magit.info, Node: Using Git Directly, Next: GNU Free Documentation License, Prev: Using Magit Extensions, Up: Top + +25 Using Git Directly +********************* + +For situations when Magit doesn't do everything you need, you can run +raw Git commands using `:'. This will prompt for a Git command, run +it, and refresh the status buffer. The output can be viewed by typing +`$'. + + +File: magit.info, Node: GNU Free Documentation License, Prev: Using Git Directly, Up: Top + +Appendix A GNU Free Documentation License +***************************************** + + Version 1.2, November 2002 + + Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + 0. PREAMBLE + + The purpose of this License is to make a manual, textbook, or other + functional and useful document "free" in the sense of freedom: to + assure everyone the effective freedom to copy and redistribute it, + with or without modifying it, either commercially or + noncommercially. Secondarily, this License preserves for the + author and publisher a way to get credit for their work, while not + being considered responsible for modifications made by others. + + This License is a kind of "copyleft", which means that derivative + works of the document must themselves be free in the same sense. + It complements the GNU General Public License, which is a copyleft + license designed for free software. + + We have designed this License in order to use it for manuals for + free software, because free software needs free documentation: a + free program should come with manuals providing the same freedoms + that the software does. But this License is not limited to + software manuals; it can be used for any textual work, regardless + of subject matter or whether it is published as a printed book. + We recommend this License principally for works whose purpose is + instruction or reference. + + 1. APPLICABILITY AND DEFINITIONS + + This License applies to any manual or other work, in any medium, + that contains a notice placed by the copyright holder saying it + can be distributed under the terms of this License. Such a notice + grants a world-wide, royalty-free license, unlimited in duration, + to use that work under the conditions stated herein. The + "Document", below, refers to any such manual or work. Any member + of the public is a licensee, and is addressed as "you". You + accept the license if you copy, modify or distribute the work in a + way requiring permission under copyright law. + + A "Modified Version" of the Document means any work containing the + Document or a portion of it, either copied verbatim, or with + modifications and/or translated into another language. + + A "Secondary Section" is a named appendix or a front-matter section + of the Document that deals exclusively with the relationship of the + publishers or authors of the Document to the Document's overall + subject (or to related matters) and contains nothing that could + fall directly within that overall subject. (Thus, if the Document + is in part a textbook of mathematics, a Secondary Section may not + explain any mathematics.) The relationship could be a matter of + historical connection with the subject or with related matters, or + of legal, commercial, philosophical, ethical or political position + regarding them. + + The "Invariant Sections" are certain Secondary Sections whose + titles are designated, as being those of Invariant Sections, in + the notice that says that the Document is released under this + License. If a section does not fit the above definition of + Secondary then it is not allowed to be designated as Invariant. + The Document may contain zero Invariant Sections. If the Document + does not identify any Invariant Sections then there are none. + + The "Cover Texts" are certain short passages of text that are + listed, as Front-Cover Texts or Back-Cover Texts, in the notice + that says that the Document is released under this License. A + Front-Cover Text may be at most 5 words, and a Back-Cover Text may + be at most 25 words. + + A "Transparent" copy of the Document means a machine-readable copy, + represented in a format whose specification is available to the + general public, that is suitable for revising the document + straightforwardly with generic text editors or (for images + composed of pixels) generic paint programs or (for drawings) some + widely available drawing editor, and that is suitable for input to + text formatters or for automatic translation to a variety of + formats suitable for input to text formatters. A copy made in an + otherwise Transparent file format whose markup, or absence of + markup, has been arranged to thwart or discourage subsequent + modification by readers is not Transparent. An image format is + not Transparent if used for any substantial amount of text. A + copy that is not "Transparent" is called "Opaque". + + Examples of suitable formats for Transparent copies include plain + ASCII without markup, Texinfo input format, LaTeX input format, + SGML or XML using a publicly available DTD, and + standard-conforming simple HTML, PostScript or PDF designed for + human modification. Examples of transparent image formats include + PNG, XCF and JPG. Opaque formats include proprietary formats that + can be read and edited only by proprietary word processors, SGML or + XML for which the DTD and/or processing tools are not generally + available, and the machine-generated HTML, PostScript or PDF + produced by some word processors for output purposes only. + + The "Title Page" means, for a printed book, the title page itself, + plus such following pages as are needed to hold, legibly, the + material this License requires to appear in the title page. For + works in formats which do not have any title page as such, "Title + Page" means the text near the most prominent appearance of the + work's title, preceding the beginning of the body of the text. + + A section "Entitled XYZ" means a named subunit of the Document + whose title either is precisely XYZ or contains XYZ in parentheses + following text that translates XYZ in another language. (Here XYZ + stands for a specific section name mentioned below, such as + "Acknowledgements", "Dedications", "Endorsements", or "History".) + To "Preserve the Title" of such a section when you modify the + Document means that it remains a section "Entitled XYZ" according + to this definition. + + The Document may include Warranty Disclaimers next to the notice + which states that this License applies to the Document. These + Warranty Disclaimers are considered to be included by reference in + this License, but only as regards disclaiming warranties: any other + implication that these Warranty Disclaimers may have is void and + has no effect on the meaning of this License. + + 2. VERBATIM COPYING + + You may copy and distribute the Document in any medium, either + commercially or noncommercially, provided that this License, the + copyright notices, and the license notice saying this License + applies to the Document are reproduced in all copies, and that you + add no other conditions whatsoever to those of this License. You + may not use technical measures to obstruct or control the reading + or further copying of the copies you make or distribute. However, + you may accept compensation in exchange for copies. If you + distribute a large enough number of copies you must also follow + the conditions in section 3. + + You may also lend copies, under the same conditions stated above, + and you may publicly display copies. + + 3. COPYING IN QUANTITY + + If you publish printed copies (or copies in media that commonly + have printed covers) of the Document, numbering more than 100, and + the Document's license notice requires Cover Texts, you must + enclose the copies in covers that carry, clearly and legibly, all + these Cover Texts: Front-Cover Texts on the front cover, and + Back-Cover Texts on the back cover. Both covers must also clearly + and legibly identify you as the publisher of these copies. The + front cover must present the full title with all words of the + title equally prominent and visible. You may add other material + on the covers in addition. Copying with changes limited to the + covers, as long as they preserve the title of the Document and + satisfy these conditions, can be treated as verbatim copying in + other respects. + + If the required texts for either cover are too voluminous to fit + legibly, you should put the first ones listed (as many as fit + reasonably) on the actual cover, and continue the rest onto + adjacent pages. + + If you publish or distribute Opaque copies of the Document + numbering more than 100, you must either include a + machine-readable Transparent copy along with each Opaque copy, or + state in or with each Opaque copy a computer-network location from + which the general network-using public has access to download + using public-standard network protocols a complete Transparent + copy of the Document, free of added material. If you use the + latter option, you must take reasonably prudent steps, when you + begin distribution of Opaque copies in quantity, to ensure that + this Transparent copy will remain thus accessible at the stated + location until at least one year after the last time you + distribute an Opaque copy (directly or through your agents or + retailers) of that edition to the public. + + It is requested, but not required, that you contact the authors of + the Document well before redistributing any large number of + copies, to give them a chance to provide you with an updated + version of the Document. + + 4. MODIFICATIONS + + You may copy and distribute a Modified Version of the Document + under the conditions of sections 2 and 3 above, provided that you + release the Modified Version under precisely this License, with + the Modified Version filling the role of the Document, thus + licensing distribution and modification of the Modified Version to + whoever possesses a copy of it. In addition, you must do these + things in the Modified Version: + + A. Use in the Title Page (and on the covers, if any) a title + distinct from that of the Document, and from those of + previous versions (which should, if there were any, be listed + in the History section of the Document). You may use the + same title as a previous version if the original publisher of + that version gives permission. + + B. List on the Title Page, as authors, one or more persons or + entities responsible for authorship of the modifications in + the Modified Version, together with at least five of the + principal authors of the Document (all of its principal + authors, if it has fewer than five), unless they release you + from this requirement. + + C. State on the Title page the name of the publisher of the + Modified Version, as the publisher. + + D. Preserve all the copyright notices of the Document. + + E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. + + F. Include, immediately after the copyright notices, a license + notice giving the public permission to use the Modified + Version under the terms of this License, in the form shown in + the Addendum below. + + G. Preserve in that license notice the full lists of Invariant + Sections and required Cover Texts given in the Document's + license notice. + + H. Include an unaltered copy of this License. + + I. Preserve the section Entitled "History", Preserve its Title, + and add to it an item stating at least the title, year, new + authors, and publisher of the Modified Version as given on + the Title Page. If there is no section Entitled "History" in + the Document, create one stating the title, year, authors, + and publisher of the Document as given on its Title Page, + then add an item describing the Modified Version as stated in + the previous sentence. + + J. Preserve the network location, if any, given in the Document + for public access to a Transparent copy of the Document, and + likewise the network locations given in the Document for + previous versions it was based on. These may be placed in + the "History" section. You may omit a network location for a + work that was published at least four years before the + Document itself, or if the original publisher of the version + it refers to gives permission. + + K. For any section Entitled "Acknowledgements" or "Dedications", + Preserve the Title of the section, and preserve in the + section all the substance and tone of each of the contributor + acknowledgements and/or dedications given therein. + + L. Preserve all the Invariant Sections of the Document, + unaltered in their text and in their titles. Section numbers + or the equivalent are not considered part of the section + titles. + + M. Delete any section Entitled "Endorsements". Such a section + may not be included in the Modified Version. + + N. Do not retitle any existing section to be Entitled + "Endorsements" or to conflict in title with any Invariant + Section. + + O. Preserve any Warranty Disclaimers. + + If the Modified Version includes new front-matter sections or + appendices that qualify as Secondary Sections and contain no + material copied from the Document, you may at your option + designate some or all of these sections as invariant. To do this, + add their titles to the list of Invariant Sections in the Modified + Version's license notice. These titles must be distinct from any + other section titles. + + You may add a section Entitled "Endorsements", provided it contains + nothing but endorsements of your Modified Version by various + parties--for example, statements of peer review or that the text + has been approved by an organization as the authoritative + definition of a standard. + + You may add a passage of up to five words as a Front-Cover Text, + and a passage of up to 25 words as a Back-Cover Text, to the end + of the list of Cover Texts in the Modified Version. Only one + passage of Front-Cover Text and one of Back-Cover Text may be + added by (or through arrangements made by) any one entity. If the + Document already includes a cover text for the same cover, + previously added by you or by arrangement made by the same entity + you are acting on behalf of, you may not add another; but you may + replace the old one, on explicit permission from the previous + publisher that added the old one. + + The author(s) and publisher(s) of the Document do not by this + License give permission to use their names for publicity for or to + assert or imply endorsement of any Modified Version. + + 5. COMBINING DOCUMENTS + + You may combine the Document with other documents released under + this License, under the terms defined in section 4 above for + modified versions, provided that you include in the combination + all of the Invariant Sections of all of the original documents, + unmodified, and list them all as Invariant Sections of your + combined work in its license notice, and that you preserve all + their Warranty Disclaimers. + + The combined work need only contain one copy of this License, and + multiple identical Invariant Sections may be replaced with a single + copy. If there are multiple Invariant Sections with the same name + but different contents, make the title of each such section unique + by adding at the end of it, in parentheses, the name of the + original author or publisher of that section if known, or else a + unique number. Make the same adjustment to the section titles in + the list of Invariant Sections in the license notice of the + combined work. + + In the combination, you must combine any sections Entitled + "History" in the various original documents, forming one section + Entitled "History"; likewise combine any sections Entitled + "Acknowledgements", and any sections Entitled "Dedications". You + must delete all sections Entitled "Endorsements." + + 6. COLLECTIONS OF DOCUMENTS + + You may make a collection consisting of the Document and other + documents released under this License, and replace the individual + copies of this License in the various documents with a single copy + that is included in the collection, provided that you follow the + rules of this License for verbatim copying of each of the + documents in all other respects. + + You may extract a single document from such a collection, and + distribute it individually under this License, provided you insert + a copy of this License into the extracted document, and follow + this License in all other respects regarding verbatim copying of + that document. + + 7. AGGREGATION WITH INDEPENDENT WORKS + + A compilation of the Document or its derivatives with other + separate and independent documents or works, in or on a volume of + a storage or distribution medium, is called an "aggregate" if the + copyright resulting from the compilation is not used to limit the + legal rights of the compilation's users beyond what the individual + works permit. When the Document is included in an aggregate, this + License does not apply to the other works in the aggregate which + are not themselves derivative works of the Document. + + If the Cover Text requirement of section 3 is applicable to these + copies of the Document, then if the Document is less than one half + of the entire aggregate, the Document's Cover Texts may be placed + on covers that bracket the Document within the aggregate, or the + electronic equivalent of covers if the Document is in electronic + form. Otherwise they must appear on printed covers that bracket + the whole aggregate. + + 8. TRANSLATION + + Translation is considered a kind of modification, so you may + distribute translations of the Document under the terms of section + 4. Replacing Invariant Sections with translations requires special + permission from their copyright holders, but you may include + translations of some or all Invariant Sections in addition to the + original versions of these Invariant Sections. You may include a + translation of this License, and all the license notices in the + Document, and any Warranty Disclaimers, provided that you also + include the original English version of this License and the + original versions of those notices and disclaimers. In case of a + disagreement between the translation and the original version of + this License or a notice or disclaimer, the original version will + prevail. + + If a section in the Document is Entitled "Acknowledgements", + "Dedications", or "History", the requirement (section 4) to + Preserve its Title (section 1) will typically require changing the + actual title. + + 9. TERMINATION + + You may not copy, modify, sublicense, or distribute the Document + except as expressly provided for under this License. Any other + attempt to copy, modify, sublicense or distribute the Document is + void, and will automatically terminate your rights under this + License. However, parties who have received copies, or rights, + from you under this License will not have their licenses + terminated so long as such parties remain in full compliance. + + 10. FUTURE REVISIONS OF THIS LICENSE + + The Free Software Foundation may publish new, revised versions of + the GNU Free Documentation License from time to time. Such new + versions will be similar in spirit to the present version, but may + differ in detail to address new problems or concerns. See + `http://www.gnu.org/copyleft/'. + + Each version of the License is given a distinguishing version + number. If the Document specifies that a particular numbered + version of this License "or any later version" applies to it, you + have the option of following the terms and conditions either of + that specified version or of any later version that has been + published (not as a draft) by the Free Software Foundation. If + the Document does not specify a version number of this License, + you may choose any version ever published (not as a draft) by the + Free Software Foundation. + +ADDENDUM: How to use this License for your documents +==================================================== + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and license +notices just after the title page: + + Copyright (C) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.2 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover + Texts. A copy of the license is included in the section entitled ``GNU + Free Documentation License''. + + If you have Invariant Sections, Front-Cover Texts and Back-Cover +Texts, replace the "with...Texts." line with this: + + with the Invariant Sections being LIST THEIR TITLES, with + the Front-Cover Texts being LIST, and with the Back-Cover Texts + being LIST. + + If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + + If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, to +permit their use in free software. + + + +Tag Table: +Node: Top1609 +Node: Introduction3622 +Node: Acknowledgments5115 +Node: Sections5663 +Node: Status8213 +Node: Untracked files10952 +Node: Staging and Committing12157 +Node: History15562 +Node: Reflogs18744 +Node: Commit Buffer19148 +Node: Diffing20474 +Node: Tagging21461 +Node: Resetting21911 +Node: Stashing23435 +Node: Branches and Remotes24506 +Node: Branches Popup25327 +Node: Remotes Popup26589 +Node: Branches in the Branch Manager26940 +Node: Remotes in the Branch Manager28112 +Node: Wazzup28673 +Node: Merging29466 +Node: Rebasing30516 +Node: Interactive Rebasing31342 +Node: Rewriting32637 +Node: Pushing and Pulling35947 +Node: Submodules37877 +Node: Bisecting38325 +Node: Finding commits not merged upstream39560 +Node: Using Magit Extensions40826 +Node: Activating extensions41122 +Node: Interfacing with Subversion42507 +Node: Interfacing with Topgit43107 +Node: Interfacing with StGit44145 +Node: Using Git Directly45114 +Node: GNU Free Documentation License45502 + +End Tag Table + + +Local Variables: +coding: utf-8 +End: