| @ -1,18 +0,0 @@ | |||
| This is the file .../info/dir, which contains the | |||
| topmost node of the Info hierarchy, called (dir)Top. | |||
| The first time you invoke Info you start off looking at this node. | |||
| File: dir, Node: Top This is the top of the INFO tree | |||
| This (the Directory node) gives a menu of major topics. | |||
| Typing "q" exits, "?" lists all Info commands, "d" returns here, | |||
| "h" gives a primer for first-timers, | |||
| "mEmacs<Return>" visits the Emacs manual, etc. | |||
| In Emacs, you can click mouse button 2 on a menu item or cross reference | |||
| to select it. | |||
| * Menu: | |||
| Emacs | |||
| * Magit: (magit). Using Git from Emacs with Magit. | |||
| @ -1,167 +0,0 @@ | |||
| ;;; magit-autoloads.el --- automatically extracted autoloads | |||
| ;; | |||
| ;;; Code: | |||
| (add-to-list 'load-path (or (file-name-directory #$) (car load-path))) | |||
| ;;;### (autoloads nil "magit" "../../../../.emacs.d/elpa/magit-1.2.1/magit.el" | |||
| ;;;;;; "99a76f87e1f4d97ede141ae69ef58d75") | |||
| ;;; Generated autoloads from ../../../../.emacs.d/elpa/magit-1.2.1/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 nil "magit-blame" "../../../../.emacs.d/elpa/magit-1.2.1/magit-blame.el" | |||
| ;;;;;; "df3b98696a2827704979850c7f9e037d") | |||
| ;;; Generated autoloads from ../../../../.emacs.d/elpa/magit-1.2.1/magit-blame.el | |||
| (autoload 'magit-blame-mode "magit-blame" "\ | |||
| Display blame information inline. | |||
| \(fn &optional ARG)" t nil) | |||
| ;;;*** | |||
| ;;;### (autoloads nil "magit-stgit" "../../../../.emacs.d/elpa/magit-1.2.1/magit-stgit.el" | |||
| ;;;;;; "3a799c21b480259ac5942c12153a0e2f") | |||
| ;;; Generated autoloads from ../../../../.emacs.d/elpa/magit-1.2.1/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 nil "magit-svn" "../../../../.emacs.d/elpa/magit-1.2.1/magit-svn.el" | |||
| ;;;;;; "1165865405f67b53f4b888c4b4a07ed4") | |||
| ;;; Generated autoloads from ../../../../.emacs.d/elpa/magit-1.2.1/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 nil "magit-topgit" "../../../../.emacs.d/elpa/magit-1.2.1/magit-topgit.el" | |||
| ;;;;;; "4ab21c607308ffc9dd96dba3f5d06e85") | |||
| ;;; Generated autoloads from ../../../../.emacs.d/elpa/magit-1.2.1/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 nil "magit-wip" "../../../../.emacs.d/elpa/magit-1.2.1/magit-wip.el" | |||
| ;;;;;; "ffe9e1c421911a9366218c10f341fa52") | |||
| ;;; Generated autoloads from ../../../../.emacs.d/elpa/magit-1.2.1/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 nil "rebase-mode" "../../../../.emacs.d/elpa/magit-1.2.1/rebase-mode.el" | |||
| ;;;;;; "475429652819edec7004bbe0b89f98dc") | |||
| ;;; Generated autoloads from ../../../../.emacs.d/elpa/magit-1.2.1/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 ("../../../../.emacs.d/elpa/magit-1.2.1/magit-autoloads.el" | |||
| ;;;;;; "../../../../.emacs.d/elpa/magit-1.2.1/magit-bisect.el" "../../../../.emacs.d/elpa/magit-1.2.1/magit-blame.el" | |||
| ;;;;;; "../../../../.emacs.d/elpa/magit-1.2.1/magit-key-mode.el" | |||
| ;;;;;; "../../../../.emacs.d/elpa/magit-1.2.1/magit-pkg.el" "../../../../.emacs.d/elpa/magit-1.2.1/magit-stgit.el" | |||
| ;;;;;; "../../../../.emacs.d/elpa/magit-1.2.1/magit-svn.el" "../../../../.emacs.d/elpa/magit-1.2.1/magit-topgit.el" | |||
| ;;;;;; "../../../../.emacs.d/elpa/magit-1.2.1/magit-wip.el" "../../../../.emacs.d/elpa/magit-1.2.1/magit.el" | |||
| ;;;;;; "../../../../.emacs.d/elpa/magit-1.2.1/rebase-mode.el") (21570 | |||
| ;;;;;; 22947 221714 0)) | |||
| ;;;*** | |||
| ;; Local Variables: | |||
| ;; version-control: never | |||
| ;; no-byte-compile: t | |||
| ;; no-update-autoloads: t | |||
| ;; End: | |||
| ;;; magit-autoloads.el ends here | |||
| @ -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) | |||
| @ -1,303 +0,0 @@ | |||
| ;;; 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 | |||
| ;; Author: Yann Hodique <yann.hodique@gmail.com> | |||
| ;; Keywords: | |||
| ;; Magit is free software; you can redistribute it and/or modify it | |||
| ;; under the terms of the GNU General Public License as published by | |||
| ;; the Free Software Foundation; either version 3, or (at your option) | |||
| ;; any later version. | |||
| ;; | |||
| ;; Magit is distributed in the hope that it will be useful, but WITHOUT | |||
| ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |||
| ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public | |||
| ;; License for more details. | |||
| ;; | |||
| ;; You should have received a copy of the GNU General Public License | |||
| ;; along with Magit. If not, see <http://www.gnu.org/licenses/>. | |||
| ;;; Commentary: | |||
| ;; This code has been backported from Egg (Magit fork) to Magit | |||
| ;;; Code: | |||
| (eval-when-compile (require 'cl)) | |||
| (require 'magit) | |||
| (defface magit-blame-header | |||
| '((t :inherit magit-header)) | |||
| "Face for blame header." | |||
| :group 'magit-faces) | |||
| (defface magit-blame-sha1 | |||
| '((t :inherit (magit-log-sha1 | |||
| magit-blame-header))) | |||
| "Face for blame sha1." | |||
| :group 'magit-faces) | |||
| (defface magit-blame-culprit | |||
| '((t :inherit magit-blame-header)) | |||
| "Face for blame culprit." | |||
| :group 'magit-faces) | |||
| (defface magit-blame-time | |||
| '((t :inherit magit-blame-header)) | |||
| "Face for blame time." | |||
| :group 'magit-faces) | |||
| (defface magit-blame-subject | |||
| '((t :inherit (magit-log-message magit-blame-header))) | |||
| "Face for blame tag line." | |||
| :group 'magit-faces) | |||
| (defconst magit-blame-map | |||
| (let ((map (make-sparse-keymap "Magit:Blame"))) | |||
| (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) | |||
| (define-key map (kbd "n") 'magit-blame-next-chunk) | |||
| (define-key map (kbd "p") 'magit-blame-previous-chunk) | |||
| map) | |||
| "Keymap for an annotated section.\\{magit-blame-map}") | |||
| (defvar magit-blame-buffer-read-only) | |||
| (make-variable-buffer-local 'magit-blame-buffer-read-only) | |||
| ;;;###autoload | |||
| (define-minor-mode magit-blame-mode | |||
| "Display blame information inline." | |||
| :keymap magit-blame-map | |||
| :lighter " blame" | |||
| (unless (buffer-file-name) | |||
| (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))) | |||
| (defun magit-blame-file-off (buffer) | |||
| (save-excursion | |||
| (save-restriction | |||
| (with-current-buffer buffer | |||
| (widen) | |||
| (mapc (lambda (ov) | |||
| (if (overlay-get ov :blame) | |||
| (delete-overlay ov))) | |||
| (overlays-in (point-min) (point-max))))))) | |||
| (defun magit-blame-file-on (buffer) | |||
| (magit-blame-file-off buffer) | |||
| (save-excursion | |||
| (with-current-buffer buffer | |||
| (save-restriction | |||
| (with-temp-buffer | |||
| (magit-git-insert (list "blame" "--porcelain" "--" | |||
| (file-name-nondirectory | |||
| (buffer-file-name buffer)))) | |||
| (magit-blame-parse buffer (current-buffer))))))) | |||
| (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)))) | |||
| (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) | |||
| "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)))) | |||
| (defun magit-blame-previous-chunk (pos) | |||
| "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)))) | |||
| (defcustom magit-time-format-string "%Y-%m-%dT%T%z" | |||
| "How to format time in magit-blame header." | |||
| :group 'magit | |||
| :type 'string) | |||
| (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." | |||
| (when (numberp tz) | |||
| (unless (numberp unixtime) | |||
| (setq unixtime (float-time unixtime))) | |||
| (let* ((ptz (abs tz)) | |||
| (min (+ (* (/ ptz 100) 60) | |||
| (mod ptz 100)))) | |||
| (setq unixtime (+ (* (if (< tz 0) (- min) min) 60) unixtime)))) | |||
| (when (numberp unixtime) | |||
| (setq unixtime (seconds-to-time unixtime))) | |||
| unixtime) | |||
| (defun magit-blame-format-time-string (format &optional unixtime tz) | |||
| "Use FORMAT to format the time UNIXTIME, or now if omitted. | |||
| UNIXTIME is specified as a number containing seconds since epoch | |||
| or Emacs's (HIGH LOW . IGNORED) format. The optional argument TZ | |||
| can be used to set the time zone. If TZ is a number it is | |||
| treated as a (-)HHMM offset to Universal Time. If TZ is not | |||
| a number and non-nil the time is printed in UTC. If TZ is nil | |||
| the local zime zone is used. The format of the function is | |||
| similar to `format-time-string' except for %Z which is not | |||
| officially supported at the moment." | |||
| (unless unixtime | |||
| (setq unixtime (current-time))) | |||
| (when (numberp tz) ;; TODO add support for %Z | |||
| (setq format (replace-regexp-in-string "%z" (format "%+05d" tz) format))) | |||
| (format-time-string format (magit-blame-decode-time unixtime tz) tz)) | |||
| (defun magit-blame-parse (target-buf blame-buf) | |||
| "Parse blame-info in buffer BLAME-BUF and decorate TARGET-BUF buffer." | |||
| (save-match-data | |||
| (let ((blank (propertize " " 'face 'magit-blame-header)) | |||
| (nl (propertize "\n" 'face 'magit-blame-header)) | |||
| (commit-hash (make-hash-table :test 'equal :size 577)) | |||
| commit commit-info old-line new-line num old-file subject author | |||
| author-time author-timezone info ov beg end blame) | |||
| (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) | |||
| (setq commit (match-string-no-properties 1) | |||
| old-line (string-to-number | |||
| (match-string-no-properties 2)) | |||
| new-line (string-to-number | |||
| (match-string-no-properties 3)) | |||
| num (string-to-number | |||
| (match-string-no-properties 4))) | |||
| ;; was this commit already seen (and stored in the hash)? | |||
| (setq commit-info (gethash commit commit-hash)) | |||
| ;; Nope, this is the 1st time, the full commit-info follow. | |||
| (unless commit-info | |||
| (re-search-forward "^author \\(.+\\)$") | |||
| (setq author (match-string-no-properties 1)) | |||
| (re-search-forward "^author-time \\(.+\\)$") | |||
| (setq author-time (string-to-number | |||
| (match-string-no-properties 1))) | |||
| (re-search-forward "^author-tz \\(.+\\)$") | |||
| (setq author-timezone (string-to-number | |||
| (match-string-no-properties 1))) | |||
| (re-search-forward "^summary \\(.+\\)$") | |||
| (setq subject (match-string-no-properties 1)) | |||
| (re-search-forward "^filename \\(.+\\)$") | |||
| (setq old-file (match-string-no-properties 1)) | |||
| (setq commit-info (list :sha1 commit :author author | |||
| :author-time author-time | |||
| :author-timezone author-timezone | |||
| :subject subject :file old-file)) | |||
| ;; save it in the hash | |||
| (puthash commit commit-info commit-hash)) | |||
| ;; add the current blame-block into the list INFO. | |||
| (setq info (cons (list old-line new-line num commit-info) | |||
| info)))) | |||
| ;; now do from beginning | |||
| (setq info (nreverse info)) | |||
| (with-current-buffer target-buf | |||
| ;; for every blame chunk | |||
| (dolist (chunk info) | |||
| (setq commit-info (nth 3 chunk) | |||
| old-line (nth 0 chunk) | |||
| new-line (nth 1 chunk) | |||
| num (nth 2 chunk) | |||
| commit (plist-get commit-info :sha1) | |||
| author (plist-get commit-info :author) | |||
| author-time (plist-get commit-info :author-time) | |||
| author-timezone (plist-get commit-info :author-timezone) | |||
| subject (plist-get commit-info :subject)) | |||
| (goto-char (point-min)) | |||
| (forward-line (1- new-line)) | |||
| (setq beg (line-beginning-position) | |||
| end (save-excursion | |||
| (forward-line num) | |||
| (line-beginning-position))) | |||
| ;; mark the blame chunk | |||
| (put-text-property beg end :blame chunk) | |||
| ;; make an overlay with blame info as 'before-string | |||
| ;; on the current chunk. | |||
| (setq ov (make-overlay beg end)) | |||
| (overlay-put ov :blame chunk) | |||
| (setq blame (concat | |||
| (propertize (substring-no-properties commit 0 8) | |||
| 'face 'magit-blame-sha1) | |||
| blank | |||
| (propertize (format "%-20s" author) | |||
| 'face 'magit-blame-culprit) | |||
| blank | |||
| (propertize (magit-blame-format-time-string | |||
| magit-time-format-string | |||
| author-time author-timezone) | |||
| 'face 'magit-blame-time) | |||
| blank | |||
| (propertize subject 'face 'magit-blame-subject) | |||
| blank nl)) | |||
| (overlay-put ov 'before-string blame)))))) | |||
| (provide 'magit-blame) | |||
| ;;; magit-blame.el ends here | |||
| @ -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) | |||
| @ -1 +0,0 @@ | |||
| (define-package "magit" "1.2.1" "Control Git from Emacs.") | |||
| @ -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 <http://www.gnu.org/licenses/>. | |||
| ;;; 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 | |||
| @ -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 <http://www.gnu.org/licenses/>. | |||
| ;;; 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 | |||
| @ -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 <http://www.gnu.org/licenses/>. | |||
| ;;; 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 | |||
| @ -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 <jonas@bernoul.li> | |||
| ;; Magit is free software; you can redistribute it and/or modify it | |||
| ;; under the terms of the GNU General Public License as published by | |||
| ;; the Free Software Foundation; either version 3, or (at your option) | |||
| ;; any later version. | |||
| ;; | |||
| ;; Magit is distributed in the hope that it will be useful, but WITHOUT | |||
| ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |||
| ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public | |||
| ;; License for more details. | |||
| ;; | |||
| ;; You should have received a copy of the GNU General Public License | |||
| ;; along with Magit. If not, see <http://www.gnu.org/licenses/>. | |||
| ;;; Commentary: | |||
| ;; This 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 | |||
| @ -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 <http://www.gnu.org/licenses/>. | |||
| ;;; 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 | |||