Skip to content

Instantly share code, notes, and snippets.

@dhaley
Created March 21, 2014 17:41
Show Gist options
  • Save dhaley/9691569 to your computer and use it in GitHub Desktop.
Save dhaley/9691569 to your computer and use it in GitHub Desktop.
helm-swoop-info error
Debugger entered--Lisp error: (wrong-type-argument number-or-marker-p nil)
1-(nil)
(forward-line (1- $line))
helm-swoop--goto-line(nil)
(progn (helm-swoop--goto-line $num) (save-current-buffer (set-buffer helm-swoop-target-buffer) (delete-overlay helm-swoop-line-overlay) (helm-swoop--target-line-overlay-move)) (helm-swoop--recenter))
(progn (select-window (car save-selected-window--state) (quote norecord)) (progn (helm-swoop--goto-line $num) (save-current-buffer (set-buffer helm-swoop-target-buffer) (delete-overlay helm-swoop-line-overlay) (helm-swoop--target-line-overlay-move)) (helm-swoop--recenter)))
(unwind-protect (progn (select-window (car save-selected-window--state) (quote norecord)) (progn (helm-swoop--goto-line $num) (save-current-buffer (set-buffer helm-swoop-target-buffer) (delete-overlay helm-swoop-line-overlay) (helm-swoop--target-line-overlay-move)) (helm-swoop--recenter))) (internal--after-with-selected-window save-selected-window--state))
(save-current-buffer (unwind-protect (progn (select-window (car save-selected-window--state) (quote norecord)) (progn (helm-swoop--goto-line $num) (save-current-buffer (set-buffer helm-swoop-target-buffer) (delete-overlay helm-swoop-line-overlay) (helm-swoop--target-line-overlay-move)) (helm-swoop--recenter))) (internal--after-with-selected-window save-selected-window--state)))
(let ((save-selected-window--state (internal--before-with-selected-window helm-swoop-synchronizing-window))) (save-current-buffer (unwind-protect (progn (select-window (car save-selected-window--state) (quote norecord)) (progn (helm-swoop--goto-line $num) (save-current-buffer (set-buffer helm-swoop-target-buffer) (delete-overlay helm-swoop-line-overlay) (helm-swoop--target-line-overlay-move)) (helm-swoop--recenter))) (internal--after-with-selected-window save-selected-window--state))))
(let* (($key (helm-swoop--get-string-at-line)) ($num (if (string-match "^[0-9]+" $key) (progn (string-to-number (match-string 0 $key)))))) (let ((save-selected-window--state (internal--before-with-selected-window helm-swoop-synchronizing-window))) (save-current-buffer (unwind-protect (progn (select-window (car save-selected-window--state) (quote norecord)) (progn (helm-swoop--goto-line $num) (save-current-buffer (set-buffer helm-swoop-target-buffer) (delete-overlay helm-swoop-line-overlay) (helm-swoop--target-line-overlay-move)) (helm-swoop--recenter))) (internal--after-with-selected-window save-selected-window--state)))) (setq helm-swoop-last-line-info (cons helm-swoop-target-buffer $num)))
(progn (select-window (car save-selected-window--state) (quote norecord)) (let* (($key (helm-swoop--get-string-at-line)) ($num (if (string-match "^[0-9]+" $key) (progn (string-to-number (match-string 0 $key)))))) (let ((save-selected-window--state (internal--before-with-selected-window helm-swoop-synchronizing-window))) (save-current-buffer (unwind-protect (progn (select-window (car save-selected-window--state) (quote norecord)) (progn (helm-swoop--goto-line $num) (save-current-buffer ... ... ...) (helm-swoop--recenter))) (internal--after-with-selected-window save-selected-window--state)))) (setq helm-swoop-last-line-info (cons helm-swoop-target-buffer $num))))
(unwind-protect (progn (select-window (car save-selected-window--state) (quote norecord)) (let* (($key (helm-swoop--get-string-at-line)) ($num (if (string-match "^[0-9]+" $key) (progn (string-to-number ...))))) (let ((save-selected-window--state (internal--before-with-selected-window helm-swoop-synchronizing-window))) (save-current-buffer (unwind-protect (progn (select-window ... ...) (progn ... ... ...)) (internal--after-with-selected-window save-selected-window--state)))) (setq helm-swoop-last-line-info (cons helm-swoop-target-buffer $num)))) (internal--after-with-selected-window save-selected-window--state))
(save-current-buffer (unwind-protect (progn (select-window (car save-selected-window--state) (quote norecord)) (let* (($key (helm-swoop--get-string-at-line)) ($num (if (string-match "^[0-9]+" $key) (progn ...)))) (let ((save-selected-window--state (internal--before-with-selected-window helm-swoop-synchronizing-window))) (save-current-buffer (unwind-protect (progn ... ...) (internal--after-with-selected-window save-selected-window--state)))) (setq helm-swoop-last-line-info (cons helm-swoop-target-buffer $num)))) (internal--after-with-selected-window save-selected-window--state)))
(let ((save-selected-window--state (internal--before-with-selected-window (helm-window)))) (save-current-buffer (unwind-protect (progn (select-window (car save-selected-window--state) (quote norecord)) (let* (($key (helm-swoop--get-string-at-line)) ($num (if ... ...))) (let ((save-selected-window--state ...)) (save-current-buffer (unwind-protect ... ...))) (setq helm-swoop-last-line-info (cons helm-swoop-target-buffer $num)))) (internal--after-with-selected-window save-selected-window--state))))
helm-swoop--move-line-action()
helm-next-line(1)
call-interactively(helm-next-line nil nil)
read-from-minibuffer("Swoop: " #("git-gutter+-refresh" 0 19 (fontified t face whitespace-line)) (keymap (C-M-left . paren-backward-sexp) (C-M-right . paren-forward-sexp) (94 . helm-swoop-caret-match) (menu-bar keymap (help-menu keymap (describe keymap (describe-mode . helm-help)))) (help keymap (109 . helm-help)) (f1 keymap (109 . helm-help)) (8 keymap (109 . helm-help) (104 . undefined) (8 . undefined) (4 . helm-debug-output)) (20 . helm-toggle-resplit-and-swap-windows) (C-tab . undefined) (triple-mouse-3 . ignore) (double-mouse-3 . ignore) (mouse-3 . ignore) (drag-mouse-3 . ignore) (down-mouse-3 . ignore) (triple-mouse-2 . ignore) (double-mouse-2 . ignore) (mouse-2 . ignore) (drag-mouse-2 . ignore) (down-mouse-2 . ignore) (triple-mouse-1 . ignore) (double-mouse-1 . ignore) (mouse-1 . ignore) (drag-mouse-1 . ignore) (down-mouse-1 . ignore) (67108897 . helm-toggle-suspend-update) (3 keymap (21 . helm-force-update) (6 . helm-follow-mode) (11 . helm-kill-selection-and-quit) (25 . helm-yank-selection) (4 . helm-delete-current-selection) (45 . helm-swap-windows)) (67108987 . helm-enlarge-window) (67108989 . helm-narrow-window) (19 . undefined) (18 . undefined) (23 . helm-yank-text-at-point) (24 keymap (2 . helm-resume-list-buffers-after-quit) (98 . helm-resume-previous-session-after-quit) (6 . helm-quit-and-find-file)) (11 . helm-delete-minibuffer-contents) (67108896 . helm-toggle-visible-mark) (0 . helm-toggle-visible-mark) (C-M-up . helm-scroll-other-window-down) (C-M-down . helm-scroll-other-window) (M-prior . helm-scroll-other-window-down) (M-next . helm-scroll-other-window) (12 . helm-recenter-top-bottom-other-window) (15 . helm-next-source) (10 . helm-select-3rd-action) (5 . helm-select-2nd-action-or-end-of-line) (26 . helm-execute-persistent-action) (9 . helm-select-action) (13 . helm-exit-minibuffer) (left . helm-previous-source) (right . helm-next-source) (7 . helm-keyboard-quit) ...) nil nil nil t)
helm-read-pattern-maybe("Swoop: " #("git-gutter+-refresh" 0 19 (fontified t face whitespace-line)) "^368 " nil nil nil nil)
#[0 "\312\211\211\211\305\206\n(()*+,\313\314-\"\315\316\317\320\321\322!\323\"\324\325%DC\216\326\303\301\307\300$\210\327(!\210\330\331!\210\315\332DC\216\333\302\301\304\303\306\307\310\205P\3109\205P\310&\210*\210)?\205r\334\335\316\317\336\321\322\311!\337\"\340\325%\"\210\341\342\335\"\210\343 \330\344\345\346\347\"P!\210-\207" [((name . "git-gutter+.el") (init lambda nil (unless helm-swoop-cache (with-current-buffer (helm-candidate-buffer (quote local)) (insert "1 ;;; git-gutter+.el --- Manage Git hunks straight from the buffer\n\n3 ;; Copyright (C) 2013 by Syohei YOSHIDA and contributors\n\n5 ;; Author: Syohei YOSHIDA <syohex@gmail.com> and contributors\n6 ;; URL: https://github.com/nonsequitur/git-gutter-plus\n7 ;; Version: 0.1\n\n9 ;; This program is free software; you can redistribute it and/or modify\n10 ;; it under the terms of the GNU General Public License as published by\n11 ;; the Free Software Foundation, either version 3 of the License, or\n12 ;; (at your option) any later version.\n\n14 ;; This program is distributed in the hope that it will be useful,\n15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of\n16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n17 ;; GNU General Public License for more details.\n\n19 ;; You should have received a copy of the GNU General Public License\n20 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n22 ;; Package-Requires: ((git-commit-mode \"0.14\"))\n\n24 ;;; Commentary:\n25 ;;\n26 ;; View, stage and revert Git changes straight from the buffer.\n\n28 ;;; Code:\n\n30 (eval-when-compile\n31 (require 'cl))\n\n33 (require 'tramp)\n34 (require 'log-edit)\n35 (require 'git-commit-mode)\n\n37 (defgroup git-gutter+ nil\n38 \"Manage Git hunks straight from the buffer\"\n39 :prefix \"git-gutter+-\"\n40 :group 'vc)\n\n42 (defcustom git-gutter+-window-width nil\n43 \"Character width of the gutter margin. Set this variable if the automatically\n44 calculated width looks wrong. (This can happen with some special characters.)\"\n45 :type 'integer\n46 :group 'git-gutter+)\n\n48 (defcustom git-gutter+-git-executable \"git\"\n49 \"The path of the Git executable.\"\n50 :type 'string\n51 :group 'git-gutter+)\n\n53 (defcustom git-gutter+-diff-options nil\n54 \"List of strings containing extra arguments to 'git diff'\"\n55 :type 'list\n56 :group 'git-gutter+)\n\n58 (defcustom git-gutter+-separator-sign nil\n59 \"Separator sign\"\n60 :type 'string\n61 :group 'git-gutter+)\n\n63 (defcustom git-gutter+-modified-sign \"=\"\n64 \"Modified sign\"\n65 :type 'string\n66 :group 'git-gutter+)\n\n68 (defcustom git-gutter+-added-sign \"+\"\n69 \"Added sign\"\n70 :type 'string\n71 :group 'git-gutter+)\n\n73 (defcustom git-gutter+-deleted-sign \"-\"\n74 \"Deleted sign\"\n75 :type 'string\n76 :group 'git-gutter+)\n\n78 (defcustom git-gutter+-unchanged-sign nil\n79 \"Unchanged sign\"\n80 :type 'string\n81 :group 'git-gutter+)\n\n83 (defcustom git-gutter+-hide-gutter nil\n84 \"Hide gutter if there are no changes\"\n85 :type 'boolean\n86 :group 'git-gutter+)\n\n88 (defcustom git-gutter+-lighter \" GitGutter\"\n89 \"Minor mode lighter in mode-line\"\n90 :type 'string\n91 :group 'git-gutter+)\n\n93 (defface git-gutter+-separator\n94 '((t (:foreground \"cyan\" :weight bold)))\n95 \"Face of the separator\"\n96 :group 'git-gutter+)\n\n98 (defface git-gutter+-modified\n99 '((t (:foreground \"magenta\" :weight bold)))\n100 \"Face for modified lines\"\n101 :group 'git-gutter+)\n\n103 (defface git-gutter+-added\n104 '((t (:foreground \"green\" :weight bold)))\n105 \"Face for added lines\"\n106 :group 'git-gutter+)\n\n108 (defface git-gutter+-deleted\n109 '((t (:foreground \"red\" :weight bold)))\n110 \"Face for deleted lines\"\n111 :group 'git-gutter+)\n\n113 (defface git-gutter+-unchanged\n114 '((t (:background \"yellow\")))\n115 \"Face for unchanged lines\"\n116 :group 'git-gutter+)\n\n118 (defcustom git-gutter+-disabled-modes nil\n119 \"A list of modes for which `global-git-gutter+-mode' should be disabled.\"\n120 :type '(repeat symbol)\n121 :group 'git-gutter+)\n\n123 (defvar git-gutter+-mode-map\n124 (make-sparse-keymap))\n\n126 (defvar git-gutter+-view-diff-function nil\n127 \"Function to call for displaying diffs\")\n\n129 (defvar git-gutter+-clear-function nil\n130 \"Function to call for clearing the diff display\")\n\n132 (defvar git-gutter+-window-config-change-function nil\n133 \"Function to call when the buffer's local window configuration has changed\")\n\n135 (defvar git-gutter+-diffinfos nil)\n136 (defvar git-gutter+-diff-header nil)\n137 (make-variable-buffer-local 'git-gutter+-diffinfos)\n138 (make-variable-buffer-local 'git-gutter+-diff-header)\n\n140 (defvar git-gutter+-popup-buffer \"*git-gutter+-diff*\")\n141 (defvar git-gutter+-buffers-to-reenable nil)\n\n143 (defconst git-gutter+-hunk-header-regex\n144 ;; The same as diff-hunk-header-re-unified\n145 \"^@@ -\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? \\\\+\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? @@\")\n\n147 (defalias 'git-gutter+-popup-hunk 'git-gutter+-show-hunk)\n148 (defalias 'git-gutter+-revert-hunk 'git-gutter+-revert-hunks)\n\n150 (defmacro git-gutter+-awhen (test &rest body)\n151 \"Anaphoric when.\"\n152 (declare (indent 1))\n153 `(let ((it ,test))\n154 (when it ,@body)))\n\n156 (defun git-gutter+-enable-default-display-mode ()\n157 (setq git-gutter+-view-diff-function 'git-gutter+-view-diff-infos\n158 git-gutter+-clear-function 'git-gutter+-clear-diff-infos\n159 git-gutter+-window-config-change-function 'git-gutter+-show-gutter))\n\n161 (unless git-gutter+-view-diff-function\n162 (git-gutter+-enable-default-display-mode))\n\n164 (defun git-gutter+-call-git (args &optional file)\n165 (if (and file (file-remote-p file))\n166 (apply #'process-file git-gutter+-git-executable nil t nil args)\n167 (apply #'call-process git-gutter+-git-executable nil t nil args)))\n\n169 (defun git-gutter+-in-git-repository-p (file)\n170 (with-temp-buffer\n171 (let ((args '(\"rev-parse\" \"--is-inside-work-tree\")))\n172 (when (zerop (git-gutter+-call-git args file))\n173 (goto-char (point-min))\n174 (string= \"true\" (buffer-substring-no-properties\n175 (point) (line-end-position)))))))\n\n177 (defun git-gutter+-root-directory (file)\n178 (with-temp-buffer\n179 (let* ((args '(\"rev-parse\" \"--show-toplevel\"))\n180 (ret (git-gutter+-call-git args file)))\n181 (when (zerop ret)\n182 (goto-char (point-min))\n183 (let ((root (buffer-substring-no-properties (point) (line-end-position))))\n184 (unless (string= root \"\")\n185 (file-name-as-directory root)))))))\n\n187 (defsubst git-gutter+-diff-args (file)\n188 (delq nil (list \"--no-pager\" \"diff\" \"--no-color\" \"--no-ext-diff\" \"-U0\"\n189 git-gutter+-diff-options file)))\n\n191 (defun git-gutter+-diff (curfile)\n192 (let ((args (git-gutter+-diff-args curfile))\n193 (file (buffer-file-name))) ;; for tramp\n194 (with-temp-buffer\n195 (when (zerop (git-gutter+-call-git args file))\n196 (goto-char (point-min))\n197 (let ((diff-header (git-gutter+-get-diff-header))\n198 (diffinfos (git-gutter+-get-diffinfos)))\n199 (list diff-header diffinfos))))))\n\n201 (defun git-gutter+-get-diff-header ()\n202 (save-excursion\n203 (if (re-search-forward git-gutter+-hunk-header-regex nil t)\n204 (buffer-substring (point-min) (match-beginning 0)))))\n\n206 (defsubst git-gutter+-make-diffinfo (type content start end)\n207 (list :type type :content content :start-line start :end-line end))\n\n209 (defun git-gutter+-get-diffinfos ()\n210 (loop while (re-search-forward git-gutter+-hunk-header-regex nil t)\n211 ;; Hunk header format:\n212 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n213 for del-len = (string-to-number (or (match-string 2) \"1\"))\n214 for add-line = (string-to-number (match-string 3))\n215 for add-len = (string-to-number (or (match-string 4) \"1\"))\n216 for type = (cond ((zerop del-len) 'added)\n217 ((zerop add-len) 'deleted)\n218 (t 'modified))\n219 for start-line = (if (eq type 'deleted)\n220 (1+ add-line)\n221 add-line)\n222 for end-line = (if (eq type 'deleted)\n223 start-line\n224 (1- (+ add-line add-len)))\n225 for content = (git-gutter+-diff-content)\n226 collect\n227 (git-gutter+-make-diffinfo type content start-line end-line)))\n\n229 (defun git-gutter+-diff-content ()\n230 (save-excursion\n231 (goto-char (line-beginning-position)) ; Move to beginning of hunk header\n232 (let ((hunk-start (point)))\n233 ;; Move to end of hunk\n234 (forward-line 1)\n235 (if (re-search-forward \"^@@\" nil t)\n236 (backward-char 3) ;; exclude \"\\n@@\"\n237 (goto-char (1- (point-max)))) ; Skip trailing newline\n238 (buffer-substring hunk-start (point)))))\n\n240 (defun git-gutter+-line-to-pos (line)\n241 (save-excursion\n242 (goto-char (point-min))\n243 (forward-line (1- line))\n244 (point)))\n\n246 (defun git-gutter+-before-string (sign)\n247 (let* ((sep-sign git-gutter+-separator-sign)\n248 (sep (when sep-sign\n249 (propertize sep-sign 'face 'git-gutter+-separator)))\n250 (gutter-sep (concat sign sep)))\n251 (propertize \" \" 'display `((margin left-margin) ,gutter-sep))))\n\n253 (defsubst git-gutter+-select-face (type)\n254 (case type\n255 (added 'git-gutter+-added)\n256 (modified 'git-gutter+-modified)\n257 (deleted 'git-gutter+-deleted)))\n\n259 (defsubst git-gutter+-select-sign (type)\n260 (case type\n261 (added git-gutter+-added-sign)\n262 (modified git-gutter+-modified-sign)\n263 (deleted git-gutter+-deleted-sign)))\n\n265 (defun git-gutter+-propertized-sign (type)\n266 (let ((sign (git-gutter+-select-sign type))\n267 (face (git-gutter+-select-face type)))\n268 (propertize sign 'face face)))\n\n270 (defun git-gutter+-view-region (sign start-line end-line)\n271 (let ((beg (git-gutter+-line-to-pos start-line)))\n272 (goto-char beg)\n273 (while (and (<= (line-number-at-pos) end-line) (not (eobp)))\n274 (git-gutter+-view-at-pos sign (point))\n275 (forward-line 1))))\n\n277 (defun git-gutter+-view-at-pos (sign pos)\n278 (let ((ov (make-overlay pos pos)))\n279 (overlay-put ov 'before-string (git-gutter+-before-string sign))\n280 (overlay-put ov 'git-gutter+ t)))\n\n282 (defun git-gutter+-view-diff-info (diffinfo)\n283 (let* ((start-line (plist-get diffinfo :start-line))\n284 (end-line (plist-get diffinfo :end-line))\n285 (type (plist-get diffinfo :type))\n286 (sign (git-gutter+-propertized-sign type)))\n287 (case type\n288 ((modified added) (git-gutter+-view-region sign start-line end-line))\n289 (deleted (git-gutter+-view-at-pos\n290 sign (git-gutter+-line-to-pos start-line))))))\n\n292 (defun git-gutter+-sign-width (sign)\n293 (loop for s across sign\n294 sum (char-width s)))\n\n296 (defun git-gutter+-longest-sign-width ()\n297 (let ((signs (list git-gutter+-modified-sign\n298 git-gutter+-added-sign\n299 git-gutter+-deleted-sign)))\n300 (when git-gutter+-unchanged-sign\n301 (add-to-list 'signs git-gutter+-unchanged-sign))\n302 (+ (apply 'max (mapcar 'git-gutter+-sign-width signs))\n303 (git-gutter+-sign-width git-gutter+-separator-sign))))\n\n305 (defun git-gutter+-view-for-unchanged ()\n306 (save-excursion\n307 (let ((sign (if git-gutter+-unchanged-sign\n308 (propertize git-gutter+-unchanged-sign\n309 'face 'git-gutter+-unchanged)\n310 \" \")))\n311 (goto-char (point-min))\n312 (while (not (eobp))\n313 (git-gutter+-view-at-pos sign (point))\n314 (forward-line 1)))))\n\n316 (defun git-gutter+-set-window-margin (width)\n317 (let ((curwin (get-buffer-window)))\n318 (set-window-margins curwin width (cdr (window-margins curwin)))))\n\n320 (defsubst git-gutter+-file-buffer-p ()\n321 (and (buffer-file-name)\n322 default-directory\n323 (file-directory-p default-directory)))\n\n325 ;;;###autoload\n326 (define-minor-mode git-gutter+-mode\n327 \"Git-Gutter mode\"\n328 :group 'git-gutter+\n329 :init-value nil\n330 :global nil\n331 :lighter git-gutter+-lighter\n332 (if git-gutter+-mode\n333 (if (and (git-gutter+-file-buffer-p)\n334 (git-gutter+-in-git-repository-p (buffer-file-name)))\n335 (progn\n336 (git-gutter+-add-local-hooks)\n337 (git-gutter+-refresh))\n338 (if (called-interactively-p 'any)\n339 (message \"No Git repo for current buffer\"))\n340 (git-gutter+-mode -1))\n341 (git-gutter+-remove-local-hooks)\n342 (git-gutter+-clear)))\n\n344 (defun git-gutter+-add-local-hooks ()\n345 (add-hook 'after-save-hook 'git-gutter+-refresh nil t)\n346 ;; Turn off `git-gutter+-mode' while reverting to prevent any redundant calls to\n347 ;; `git-gutter+-refresh'.\n348 (add-hook 'before-revert-hook 'git-gutter+-turn-off nil t)\n349 (add-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change nil t)\n350 (if git-gutter+-window-config-change-function\n351 (add-hook 'window-configuration-change-hook\n352 git-gutter+-window-config-change-function nil t)))\n\n354 (defun git-gutter+-remove-local-hooks ()\n355 (remove-hook 'after-save-hook 'git-gutter+-refresh t)\n356 (remove-hook 'before-revert-hook 'git-gutter+-turn-off t)\n357 (remove-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change t)\n358 (if git-gutter+-window-config-change-function\n359 (remove-hook 'window-configuration-change-hook\n360 git-gutter+-window-config-change-function t)))\n\n362 (defmacro git-gutter+-in-all-buffers (&rest body)\n363 `(dolist (buf (buffer-list))\n364 (with-current-buffer buf\n365 ,@body)))\n\n367 ;; When `define-globalized-minor-mode' is used to define `global-git-gutter+-mode',\n368 ;; `git-gutter+-mode' and thus `git-gutter+-refresh' get run twice when a new file\n369 ;; is opened. (First for `fundamental-mode', then for the file-specific mode.)\n370 ;; The following definition of `global-git-gutter+-mode' avoids any redundant calls to\n371 ;; `git-gutter+-refresh'.\n\n373 ;;;###autoload\n374 (define-minor-mode global-git-gutter+-mode ()\n375 \"Global Git-Gutter mode\"\n376 :group 'git-gutter+\n377 :init-value nil\n378 :global t\n379 (if global-git-gutter+-mode\n380 (progn\n381 (add-hook 'find-file-hook 'git-gutter+-turn-on)\n382 (add-hook 'after-revert-hook 'git-gutter+-turn-on)\n383 (add-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n384 (git-gutter+-in-all-buffers (git-gutter+-turn-on)))\n385 (remove-hook 'find-file-hook 'git-gutter+-turn-on)\n386 (remove-hook 'after-revert-hook 'git-gutter+-turn-on)\n387 (remove-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n388 (git-gutter+-in-all-buffers (git-gutter+-turn-off))))\n\n390 (defun git-gutter+-turn-on ()\n391 (when (and (buffer-file-name)\n392 (not (memq major-mode git-gutter+-disabled-modes))\n393 (not git-gutter+-mode))\n394 (git-gutter+-mode t)))\n\n396 (defun git-gutter+-turn-off ()\n397 (if git-gutter+-mode (git-gutter+-mode -1)))\n\n399 (defun git-gutter+-reenable-after-major-mode-change ()\n400 (if global-git-gutter+-mode\n401 (add-to-list 'git-gutter+-buffers-to-reenable (current-buffer))))\n\n403 (defun git-gutter+-reenable-buffers ()\n404 (dolist (buf git-gutter+-buffers-to-reenable)\n405 (with-current-buffer buf\n406 (git-gutter+-turn-on)))\n407 (setq git-gutter+-buffers-to-reenable nil))\n\n409 (defsubst git-gutter+-show-gutter-p (diffinfos)\n410 (if git-gutter+-hide-gutter\n411 (or diffinfos git-gutter+-unchanged-sign)\n412 (or global-git-gutter+-mode git-gutter+-unchanged-sign diffinfos)))\n\n414 (defun git-gutter+-show-gutter (&optional diffinfos)\n415 (when (git-gutter+-show-gutter-p (or diffinfos git-gutter+-diffinfos))\n416 (let ((win-width (or git-gutter+-window-width\n417 (git-gutter+-longest-sign-width))))\n418 (git-gutter+-set-window-margin win-width))))\n\n420 (defun git-gutter+-view-diff-infos (diffinfos)\n421 (when (or git-gutter+-unchanged-sign\n422 git-gutter+-separator-sign)\n423 (git-gutter+-view-for-unchanged))\n424 (when diffinfos\n425 (save-excursion\n426 (mapc 'git-gutter+-view-diff-info diffinfos)))\n427 (git-gutter+-show-gutter diffinfos))\n\n429 (defsubst git-gutter+-reset-window-margin-p ()\n430 (or git-gutter+-hide-gutter\n431 (not global-git-gutter+-mode)))\n\n433 (defun git-gutter+-clear-diff-infos ()\n434 (when (git-gutter+-reset-window-margin-p)\n435 (git-gutter+-set-window-margin 0))\n436 (remove-overlays (point-min) (point-max) 'git-gutter+ t))\n\n438 (defun git-gutter+-process-diff (curfile)\n439 (destructuring-bind\n440 (diff-header diffinfos) (git-gutter+-diff curfile)\n441 (setq git-gutter+-diff-header diff-header\n442 git-gutter+-diffinfos diffinfos)\n443 (save-restriction\n444 (widen)\n445 (funcall git-gutter+-view-diff-function diffinfos))))\n\n447 (defun git-gutter+-search-near-diff-index (diffinfos is-reverse)\n448 (loop with current-line = (line-number-at-pos)\n449 with cmp-fn = (if is-reverse '> '<)\n450 for diffinfo in (if is-reverse (reverse diffinfos) diffinfos)\n451 for index = 0 then (1+ index)\n452 for start-line = (plist-get diffinfo :start-line)\n453 when (funcall cmp-fn current-line start-line)\n454 return (if is-reverse\n455 (1- (- (length diffinfos) index))\n456 index)))\n\n458 (defun git-gutter+-diffinfo-at-point ()\n459 (save-restriction\n460 (widen)\n461 (loop with current-line = (line-number-at-pos)\n462 for diffinfo in git-gutter+-diffinfos\n463 for start = (plist-get diffinfo :start-line)\n464 for end = (or (plist-get diffinfo :end-line) (1+ start))\n465 when (and (>= current-line start) (<= current-line end))\n466 return diffinfo)))\n\n468 (defun git-gutter+-collect-deleted-line (str)\n469 (with-temp-buffer\n470 (insert str)\n471 (goto-char (point-min))\n472 (loop while (re-search-forward \"^-\\\\(.*?\\\\)$\" nil t)\n473 collect (match-string 1) into deleted-lines\n474 finally return deleted-lines)))\n\n476 (defun git-gutter+-delete-added-lines (start-line end-line)\n477 (forward-line (1- start-line))\n478 (let ((start-point (point)))\n479 (forward-line (1+ (- end-line start-line)))\n480 (delete-region start-point (point))))\n\n482 (defun git-gutter+-insert-deleted-lines (content)\n483 (dolist (line (git-gutter+-collect-deleted-line content))\n484 (insert (concat line \"\\n\"))))\n\n486 (defun git-gutter+-do-revert-hunk (diffinfo)\n487 (save-excursion\n488 (save-restriction\n489 (widen)\n490 (goto-char (point-min))\n491 (let ((start-line (plist-get diffinfo :start-line))\n492 (end-line (plist-get diffinfo :end-line))\n493 (content (plist-get diffinfo :content)))\n494 (case (plist-get diffinfo :type)\n495 (added (git-gutter+-delete-added-lines start-line end-line))\n496 (deleted (forward-line (1- start-line))\n497 (git-gutter+-insert-deleted-lines content))\n498 (modified (git-gutter+-delete-added-lines start-line end-line)\n499 (git-gutter+-insert-deleted-lines content)))))))\n\n501 (defun git-gutter+-revert-hunks ()\n502 \"Revert hunk at point. If region is active, revert all hunks within the region.\"\n503 (interactive)\n504 (let* ((diffinfos (git-gutter+-selected-diffinfos))\n505 (one-diffinfo-p (= 1 (length diffinfos))))\n506 (save-window-excursion\n507 (if one-diffinfo-p (git-gutter+-show-hunk (car diffinfos)))\n508 (when (and diffinfos\n509 (yes-or-no-p (if one-diffinfo-p\n510 \"Revert hunk?\"\n511 (format \"Revert %d hunks?\" (length diffinfos)))))\n512 ;; Revert diffinfos in reverse so that earlier hunks don't invalidate the\n513 ;; line number information of the later hunks.\n514 (dolist (diffinfo (nreverse diffinfos))\n515 (git-gutter+-do-revert-hunk diffinfo))\n516 (save-buffer))\n517 (if one-diffinfo-p\n518 (git-gutter+-awhen (get-buffer git-gutter+-popup-buffer)\n519 (kill-buffer it))))))\n\n521 (defun git-gutter+-show-hunk (&optional diffinfo)\n522 \"Show hunk at point in another window\"\n523 (interactive)\n524 (git-gutter+-awhen (or diffinfo\n525 (git-gutter+-diffinfo-at-point))\n526 (save-selected-window\n527 (with-current-buffer (get-buffer-create git-gutter+-popup-buffer)\n528 (setq buffer-read-only nil)\n529 (erase-buffer)\n530 (insert (plist-get it :content))\n531 (insert \"\\n\")\n532 (goto-char (point-min))\n533 (diff-mode)\n534 (view-mode)\n535 (pop-to-buffer (current-buffer))))))\n\n537 (defun git-gutter+-next-hunk (arg)\n538 \"Move to next diff hunk\"\n539 (interactive \"p\")\n540 (if (not git-gutter+-diffinfos)\n541 (message \"No changes in buffer\")\n542 (save-restriction\n543 (widen)\n544 (let* ((is-reverse (< arg 0))\n545 (diffinfos git-gutter+-diffinfos)\n546 (len (length diffinfos))\n547 (index (git-gutter+-search-near-diff-index diffinfos is-reverse))\n548 (real-index (if index\n549 (let ((next (if is-reverse (1+ index) (1- index))))\n550 (mod (+ arg next) len))\n551 (if is-reverse (1- (length diffinfos)) 0)))\n552 (diffinfo (nth real-index diffinfos)))\n553 (goto-char (point-min))\n554 (forward-line (1- (plist-get diffinfo :start-line)))\n555 (when (buffer-live-p (get-buffer git-gutter+-popup-buffer))\n556 (save-window-excursion\n557 (git-gutter+-show-hunk)))))))\n\n559 (defun git-gutter+-previous-hunk (arg)\n560 \"Move to previous diff hunk\"\n561 (interactive \"p\")\n562 (git-gutter+-next-hunk (- arg)))\n\n564 (defun git-gutter+-remote-default-directory (dir file)\n565 (let* ((vec (tramp-dissect-file-name file))\n566 (method (aref vec 0))\n567 (user (aref vec 1))\n568 (host (aref vec 2)))\n569 (format \"/%s:%s%s:%s\" method (if user (concat user \"@\") \"\") host dir)))\n\n571 (defun git-gutter+-remote-file-path (dir file)\n572 (let ((file (aref (tramp-dissect-file-name file) 3)))\n573 (replace-regexp-in-string (concat \"\\\\`\" dir) \"\" file)))\n\n575 (defun git-gutter+-local-file-path (file)\n576 (if (eq system-type 'windows-nt)\n577 ;; Cygwin can't handle Windows absolute paths\n578 (file-relative-name file default-directory)\n579 file))\n\n581 (defun git-gutter+-refresh ()\n582 (git-gutter+-clear)\n583 (let ((file (buffer-file-name)))\n584 (when (and file (file-exists-p file))\n585 (if (file-remote-p file)\n586 (let* ((repo-root (git-gutter+-root-directory file))\n587 (default-directory (git-gutter+-remote-default-directory repo-root file)))\n588 (git-gutter+-process-diff (git-gutter+-remote-file-path repo-root file)))\n589 (git-gutter+-process-diff (git-gutter+-local-file-path file))))))\n\n591 (defun git-gutter+-clear ()\n592 (save-restriction\n593 (widen)\n594 (funcall git-gutter+-clear-function))\n595 (setq git-gutter+-diffinfos nil))\n\n\n598 ;;; Staging\n\n600 (defun git-gutter+-stage-hunks ()\n601 \"Stage hunk at point. If region is active, stage all hunk lines within the region.\"\n602 (interactive)\n603 (let* ((line-range (if (use-region-p)\n604 (cons (line-number-at-pos (region-beginning))\n605 (line-number-at-pos (region-end)))))\n606 (diffinfos (git-gutter+-selected-diffinfos line-range)))\n607 (when diffinfos\n608 (let ((error-msg (git-gutter+-stage-diffinfos diffinfos line-range)))\n609 (if error-msg\n610 (message \"Error staging hunks:\\n%s\" error-msg))\n611 (git-gutter+-refresh)))))\n\n613 (defun git-gutter+-selected-diffinfos (&optional line-range)\n614 (unless line-range\n615 (setq line-range (if (use-region-p)\n616 (cons (line-number-at-pos (region-beginning))\n617 (line-number-at-pos (region-end))))))\n618 (if line-range\n619 (git-gutter+-diffinfos-between-lines line-range)\n620 (git-gutter+-awhen (git-gutter+-diffinfo-at-point)\n621 (list it))))\n\n623 (defsubst git-gutter+-diffinfo-between-lines-p (diffinfo start-line end-line)\n624 (let ((diff-start (plist-get diffinfo :start-line))\n625 (diff-end (plist-get diffinfo :end-line)))\n626 (and (<= start-line diff-end)\n627 (<= diff-start end-line))))\n\n629 (defun git-gutter+-diffinfos-between-lines (line-range)\n630 (save-restriction\n631 (widen)\n632 (let ((start-line (car line-range))\n633 (end-line (cdr line-range)))\n634 (delq nil\n635 (mapcar (lambda (diffinfo)\n636 (if (git-gutter+-diffinfo-between-lines-p\n637 diffinfo start-line end-line)\n638 diffinfo))\n639 git-gutter+-diffinfos)))))\n\n641 (defun git-gutter+-stage-diffinfos (diffinfos line-range)\n642 (let ((header git-gutter+-diff-header))\n643 (with-temp-buffer\n644 (insert header)\n645 ;; Insert hunks in reverse so that earlier hunks don't invalidate the line\n646 ;; number information of the later hunks.\n647 (dolist (diffinfo (nreverse diffinfos))\n648 (git-gutter+-insert-diffinfo diffinfo line-range)\n649 (goto-char (point-max)))\n650 (git-gutter+-call-git-on-current-buffer\n651 '(\"apply\" \"--unidiff-zero\" \"--cached\" \"-\")))))\n\n653 (defun git-gutter+-insert-diffinfo (diffinfo line-range)\n654 (let ((content (plist-get diffinfo :content))\n655 (type (plist-get diffinfo :type)))\n656 (if (not line-range)\n657 (git-gutter+-insert-hunk content type)\n658 (let ((diff-start-line (plist-get diffinfo :start-line))\n659 (diff-end-line (plist-get diffinfo :end-line))\n660 (start-line (car line-range))\n661 (end-line (cdr line-range)))\n662 (git-gutter+-insert-hunk content type\n663 (1+ (- start-line diff-start-line))\n664 (1+ (- end-line diff-start-line)))))))\n\n666 (defun git-gutter+-call-git-on-current-buffer (args)\n667 \"Sends the current buffer contents to Git and replaces them with Git's output.\n\n669 RETURNS nil if Git ran successfully. Returns an error description otherwise.\"\n670 (unless (zerop (apply #'call-process-region (point-min) (point-max)\n671 git-gutter+-git-executable t t nil args))\n672 (buffer-string)))\n\n674 (defsubst git-gutter+-read-hunk-header (hunk)\n675 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n676 (string-match git-gutter+-hunk-header-regex hunk)\n677 (list (string-to-number (match-string 1 hunk))\n678 (string-to-number (or (match-string 2 hunk) \"1\"))\n679 (string-to-number (match-string 3 hunk))\n680 (string-to-number (or (match-string 4 hunk) \"1\"))))\n\n682 (defun git-gutter+-insert-hunk (hunk type &optional start end)\n683 \"If START and END are provided, only insert addition (+) lines between\n684 START and END (inclusive). START and END are both line numbers starting with 1.\"\n685 (destructuring-bind\n686 (del-line del-len add-line add-len) (git-gutter+-read-hunk-header hunk)\n687 (let* ((start (max 1 (or start 1)))\n688 (end (min add-len (or end add-len)))\n689 (insert-all-p (or (eq type :deleted)\n690 (and (= start 1) (= end add-len))))\n691 (num-lines-selected (if insert-all-p\n692 add-len\n693 (1+ (- end start)))))\n694 ;; When the user selected the last lines of a hunk with type `modified' (but\n695 ;; not the complete hunk), then don't insert any deletion (-) lines from that\n696 ;; hunk.\n697 (if (and (eq type 'modified)\n698 (> start 1) (= end add-len))\n699 (setq type 'modified-trailing))\n\n701 (save-excursion\n702 (insert hunk \"\\n\"))\n\n704 (git-gutter+-delete-hunk-header)\n\n706 (if (not insert-all-p)\n707 (git-gutter+-modify-hunk type num-lines-selected del-len start))\n\n709 (let ((hunk-header (git-gutter+-make-hunk-header type num-lines-selected\n710 del-line del-len add-line)))\n711 (insert hunk-header \"\\n\")))))\n\n713 (defun git-gutter+-delete-hunk-header ()\n714 (let ((hunk-start (point)))\n715 (forward-line 1)\n716 (delete-region hunk-start (point))))\n\n718 (defun git-gutter+-modify-hunk (type num-lines-selected del-len start)\n719 \"Remove all addition (+) lines from hunk that aren't selected.\n720 If TYPE is not `modified', also remove all deletion (-) lines.\"\n721 (let ((first-line-selected (+ del-len (1- start)))\n722 selected-lines)\n723 (save-excursion\n724 (forward-line first-line-selected)\n725 (let ((selection-start (point)))\n726 (forward-line num-lines-selected)\n727 (setq selected-lines (buffer-substring selection-start (point)))))\n728 (save-excursion\n729 (if (eq type 'modified) (forward-line del-len)) ; skip over deletion (-) lines\n730 (delete-region (point) (point-max))\n731 (insert selected-lines))))\n\n733 (defun git-gutter+-make-hunk-header (type num-lines-selected del-line del-len add-line)\n734 (let ((add-len num-lines-selected))\n735 (case type\n736 (added (setq add-line (1+ del-line)))\n737 (modified-trailing (setq add-line (+ del-line del-len)\n738 del-line (1- add-line)\n739 del-len 0))\n740 (t (setq add-line del-line)))\n741 (format \"@@ -%d,%d +%d,%d @@\"\n742 del-line del-len\n743 add-line add-len)))\n\n\n746 ;;; Committing\n747 ;; This section draws heavily from old Magit source code.\n\n749 (defvar git-gutter+-pre-commit-window-config nil)\n750 (defvar git-gutter+-commit-origin-buffer nil\n751 \"Buffer that started the commit\")\n\n753 (defconst git-gutter+-commit-buffer-name \"*Commit Message*\")\n754 (defconst git-gutter+-staged-changes-buffer-name \"*Staged Changes*\")\n\n756 ;;;###autoload\n757 (defun git-gutter+-commit ()\n758 \"Commit staged changes. If nothing is staged, ask to stage the current buffer.\"\n759 (interactive)\n\n761 (when (and (not (git-gutter+-anything-staged-p))\n762 git-gutter+-diffinfos\n763 (y-or-n-p \"Nothing staged. Stage current buffer? \"))\n764 (git-gutter+-stage-whole-buffer))\n\n766 (let ((file (buffer-file-name))\n767 (dir default-directory))\n768 (git-gutter+-save-window-config-if-needed)\n769 (setq git-gutter+-commit-origin-buffer (current-buffer))\n770 (git-gutter+-open-commit-edit-buffer dir)\n771 (git-gutter+-show-staged-changes file dir)))\n\n773 (defun git-gutter+-stage-and-commit ()\n774 (interactive)\n775 (git-gutter+-stage-hunks)\n776 (git-gutter+-commit))\n\n778 (defun git-gutter+-save-window-config-if-needed ()\n779 ;; Only save the window config if the temporary buffers that get popped-up by\n780 ;; git-gutter+ are not already visible.\n781 ;; In this way, `git-gutter+-commit' can be called twice in a row without\n782 ;; losing the original window config.\n783 (when (not (and git-gutter+-pre-commit-window-config\n784 (get-buffer-window git-gutter+-commit-buffer-name)\n785 (get-buffer-window git-gutter+-staged-changes-buffer-name)))\n786 (setq git-gutter+-pre-commit-window-config (current-window-configuration))))\n\n788 (defun git-gutter+-open-commit-edit-buffer (dir)\n789 \"Opens a buffer for composing the commit message\"\n790 (pop-to-buffer (get-buffer-create git-gutter+-commit-buffer-name))\n791 (setq default-directory dir)\n792 (git-gutter+-commit-mode)\n793 (message \"Type C-c C-c to commit (C-c C-k to cancel).\"))\n\n795 (defsubst git-gutter+-pop-to-staged-changes-buffer ()\n796 (let* ((buf (get-buffer-create git-gutter+-staged-changes-buffer-name))\n797 (window (get-buffer-window buf)))\n798 (if window\n799 ;; Buffer is already visible\n800 (select-window window)\n801 (if (<= (length (window-list)) 2)\n802 (split-window))\n803 (pop-to-buffer buf))))\n\n805 (defun git-gutter+-show-staged-changes (file dir)\n806 (save-selected-window\n807 (git-gutter+-pop-to-staged-changes-buffer)\n808 (setq buffer-read-only nil)\n809 (erase-buffer)\n810 (let ((default-directory dir))\n811 (git-gutter+-call-git '(\"diff\" \"--staged\") file))\n812 (goto-char (point-min))\n813 (diff-mode)\n814 (view-mode)))\n\n816 (defsubst git-gutter+-abort-commit-when-no-changes (allow-empty amend)\n817 (unless (or amend\n818 allow-empty\n819 (git-gutter+-anything-staged-p))\n820 (error\n821 \"Refusing to create empty commit. Maybe you want to amend (%s) or allow-empty (%s)?\"\n822 (key-description (car (where-is-internal\n823 'git-gutter+-commit-toggle-amending)))\n824 (key-description (car (where-is-internal\n825 'git-gutter+-commit-toggle-allow-empty))))))\n\n827 (defsubst git-gutter+-buffer-is-whitespace ()\n828 (save-excursion\n829 (goto-char (point-min))\n830 (looking-at-p \"[ \\t\\n]*\\\\'\")))\n\n832 (defun git-gutter+-publish-commit ()\n833 \"Publish commit\"\n834 (interactive)\n835 (let* ((fields (git-gutter+-commit-get-fields))\n836 (amend (equal \"yes\" (git-gutter+-commit-get-field 'amend fields)))\n837 (allow-empty (equal \"yes\" (git-gutter+-commit-get-field 'allow-empty fields)))\n838 (author (git-gutter+-commit-get-field 'author fields))\n839 (date (git-gutter+-commit-get-field 'date fields)))\n\n841 (git-gutter+-abort-commit-when-no-changes allow-empty amend)\n\n843 (git-gutter+-push-to-comment-ring (buffer-string))\n\n845 (git-gutter+-commit-set-fields nil) ; Delete message header\n\n847 (when (git-gutter+-buffer-is-whitespace)\n848 (erase-buffer)\n849 (insert \"(Empty description)\"))\n\n851 (let ((error-msg (git-gutter+-call-git-on-current-buffer\n852 (append '(\"--no-pager\" \"commit\" \"-F\" \"-\")\n853 (if amend '(\"--amend\"))\n854 (if allow-empty '(\"--allow-empty\"))\n855 (if author (list (concat \"--author=\" author)))\n856 (if date (list (concat \"--date=\" date)))))))\n857 (if error-msg\n858 (progn\n859 (message \"Commit error:\\n%s\" error-msg)\n860 (erase-buffer)\n861 (insert (ring-ref log-edit-comment-ring 0))) ; Reinsert commit message\n862 (message \"Commit successful.\")\n863 (git-gutter+-close-commit-edit-buffer)\n864 (git-gutter+-update-vc-modeline)))))\n\n866 (defun git-gutter+-close-commit-edit-buffer ()\n867 \"Abort edits and discard commit message being composed.\"\n868 (interactive)\n869 (kill-buffer)\n870 (set-window-configuration git-gutter+-pre-commit-window-config))\n\n872 (defun git-gutter+-update-vc-modeline ()\n873 (when (buffer-live-p git-gutter+-commit-origin-buffer)\n874 (with-current-buffer git-gutter+-commit-origin-buffer\n875 ;; Updating the modeline has no effect if the buffer still has\n876 ;; changes - it will remain in the 'modified' state. So skip it then.\n877 (unless git-gutter+-diffinfos\n878 (ignore-errors (vc-find-file-hook))))))\n\n880 (defun git-gutter+-stage-whole-buffer ()\n881 (save-excursion\n882 (mark-whole-buffer)\n883 (git-gutter+-stage-hunks)))\n\n885 (defun git-gutter+-anything-staged-p ()\n886 \"Return t if the current repo has staged changes\"\n887 (not (zerop (git-gutter+-call-git '(\"diff\" \"--quiet\" \"--cached\")))))\n\n889 (defun git-gutter+-commit-toggle-amending ()\n890 \"Toggle whether this will be an amendment to the previous commit.\n891 \\(i.e., whether commit is run via 'git commit --amend')\"\n892 (interactive)\n893 ;; Remove the newline that 'git-commit-mode' adds to a new commit\n894 ;; message buffer by default. This prevents an ugly visual\n895 ;; gap between the commit message header and the previous commit\n896 ;; message.\n897 (when (git-gutter+-buffer-is-whitespace)\n898 (erase-buffer))\n\n900 (let ((amend-was-already-set (git-gutter+-commit-get-field 'amend)))\n901 (git-gutter+-commit-toggle-field 'amend t)\n902 (unless amend-was-already-set\n903 ;; Insert previous commit message\n904 (goto-char (point-max))\n905 (unless (zerop (current-column))\n906 (insert \"\\n\"))\n907 (insert (git-gutter+-get-last-commit-msg)\n908 \"\\n\"))))\n\n910 (defun git-gutter+-commit-toggle-allow-empty ()\n911 \"Toggle whether this commit is allowed to be empty.\n912 \\(i.e., whether commit is run via 'git commit --allow-empty')\"\n913 (interactive)\n914 (git-gutter+-commit-toggle-field 'allow-empty t))\n\n916 (defun git-gutter+-format-author (author email)\n917 (format \"%s <%s>\" author email))\n\n919 (defun git-gutter+-commit-toggle-author ()\n920 \"Toggle whether this commit should have a user-defined author.\"\n921 (interactive)\n922 (git-gutter+-commit-toggle-input\n923 'author (git-gutter+-format-author\n924 (or (git-gutter+-get-cfg \"user\" \"name\") \"Author Name\")\n925 (or (git-gutter+-get-cfg \"user\" \"email\") \"author@email\"))))\n\n927 (defun git-gutter+-commit-toggle-date ()\n928 \"Toggle whether this commit should have a user-defined date.\"\n929 (interactive)\n930 (git-gutter+-commit-toggle-input 'date\n931 ;; ISO 8601\n932 (format-time-string \"%Y-%m-%dT%T%z\" (current-time))))\n\n934 (defun git-gutter+-push-to-comment-ring (comment)\n935 (when (or (ring-empty-p log-edit-comment-ring)\n936 (not (equal comment (ring-ref log-edit-comment-ring 0))))\n937 (ring-insert log-edit-comment-ring comment)))\n\n939 (defun git-gutter+-get-last-commit-msg ()\n940 (git-gutter+-git-output '(\"log\" \"--max-count=1\" \"--pretty=format:%s%n%n%b\" \"HEAD\")))\n\n942 (defun git-gutter+-get-cfg (&rest keys)\n943 (git-gutter+-git-output (list \"config\" (mapconcat 'identity keys \".\"))))\n\n945 (defun git-gutter+-git-output (args)\n946 (with-temp-buffer\n947 (git-gutter+-call-git args)\n948 ;; Delete trailing newlines\n949 (goto-char (point-min))\n950 (if (re-search-forward \"\\n+\\\\'\" nil t)\n951 (replace-match \"\"))\n952 (buffer-string)))\n\n\n955 ;;; Commit message header\n\n957 (defconst git-gutter+-commit-header-end \"-- End of commit options header --\\n\")\n\n959 (defun git-gutter+-commit-get-field (name &optional fields)\n960 (cdr (assq name (or fields (git-gutter+-commit-get-fields)))))\n\n962 (defun git-gutter+-commit-set-field (name value)\n963 (let* ((fields (git-gutter+-commit-get-fields))\n964 (cell (assq name fields)))\n965 (cond (cell\n966 (if value\n967 (rplacd cell value)\n968 (setq fields (delq cell fields))))\n969 (t\n970 (if value\n971 (setq fields (append fields (list (cons name value)))))))\n972 (git-gutter+-commit-set-fields fields)))\n\n974 (defun git-gutter+-commit-toggle-field (name default)\n975 \"Toggle the commit header field named NAME.\n976 If it's currently unset, set it to DEFAULT (t or nil).\"\n977 (let* ((fields (git-gutter+-commit-get-fields))\n978 (cell (assq name fields)))\n979 (if cell\n980 (rplacd cell (if (equal (cdr cell) \"yes\") \"no\" \"yes\"))\n981 (setq fields (acons name (if default \"yes\" \"no\") fields)))\n982 (git-gutter+-commit-set-fields fields)))\n\n984 (defun git-gutter+-commit-toggle-input (name default)\n985 \"Toggle the commit header input named NAME.\n986 If it's currently unset, set it to DEFAULT (a string). If it is\n987 set remove it.\"\n988 (let* ((fields (git-gutter+-commit-get-fields))\n989 (cell (assq name fields)))\n990 (if cell\n991 (setq fields (assq-delete-all name fields))\n992 (setq fields (acons name default fields)))\n993 (git-gutter+-commit-set-fields fields)))\n\n995 (defun git-gutter+-commit-get-fields ()\n996 (let (result)\n997 (goto-char (point-min))\n998 (while (looking-at \"^\\\\([A-Za-z0-9-_]+\\\\): *\\\\(.+\\\\)?$\")\n999 (let ((name (intern (downcase (match-string 1))))\n1000 (value (read (or (match-string 2) \"nil\"))))\n1001 (push (cons name value) result))\n1002 (forward-line))\n1003 (if (looking-at (regexp-quote git-gutter+-commit-header-end))\n1004 (nreverse result))))\n\n1006 (defun git-gutter+-commit-set-fields (fields)\n1007 (goto-char (point-min))\n1008 ;; Delete commit header\n1009 (if (search-forward-regexp (format \"^\\\\(?:[A-Za-z0-9-_]+:.*\\n\\\\)*%s\"\n1010 (regexp-quote git-gutter+-commit-header-end))\n1011 nil t)\n1012 (delete-region (match-beginning 0) (match-end 0)))\n1013 (goto-char (point-min))\n1014 (when fields\n1015 (dolist (field fields)\n1016 (insert (capitalize (symbol-name (car field))) \": \"\n1017 (prin1-to-string (cdr field)) \"\\n\"))\n1018 (insert git-gutter+-commit-header-end)))\n\n\n1021 ;;; git-gutter+-commit-mode\n1022 ;; Like git-commit-mode, but adds keybindings to git-gutter+ commands and\n1023 ;; highlighting support for the commit message header.\n\n1025 (define-derived-mode git-gutter+-commit-mode git-commit-mode \"Git-Gutter-Commit\"\n1026 (setq font-lock-defaults (list (git-gutter+-commit-font-lock-keywords) t)))\n\n1028 (setq git-gutter+-commit-mode-map\n1029 (let ((map (copy-keymap git-commit-mode-map)))\n1030 (define-key map (kbd \"C-c C-c\") 'git-gutter+-publish-commit)\n1031 (define-key map (kbd \"C-c C-k\") 'git-gutter+-close-commit-edit-buffer)\n1032 (define-key map (kbd \"C-c C-a\") 'git-gutter+-commit-toggle-amending)\n1033 (define-key map (kbd \"C-c C-e\") 'git-gutter+-commit-toggle-allow-empty)\n1034 (define-key map (kbd \"C-c C-u\") 'git-gutter+-commit-toggle-author)\n1035 (define-key map (kbd \"C-c C-d\") 'git-gutter+-commit-toggle-date)\n1036 (define-key map (kbd \"C-c C-b\") 'git-commit-ack)\n1037 (define-key map (kbd \"M-p\") 'log-edit-previous-comment)\n1038 (define-key map (kbd \"M-n\") 'log-edit-next-comment)\n1039 map))\n\n1041 (defface git-gutter+-commit-header-face\n1042 '((t :inherit font-lock-comment-face))\n1043 \"Highlights the commit message header\"\n1044 :group 'git-gutter+-faces)\n\n1046 (defconst git-gutter+-commit-header-regex\n1047 (concat \"\\\\(?:.\\\\|\\n\\\\)*?\" (regexp-quote git-gutter+-commit-header-end)))\n\n1049 (defconst git-gutter+-skip-commit-header-regex\n1050 (concat \"\\\\`\\\\(?:\" git-gutter+-commit-header-regex \"\\\\)?\"))\n\n1052 ;; Modify git-commit-summary-regexp to ignore the commit header\n1053 (defadvice git-commit-summary-regexp\n1054 (after ignore-git-gutter+-commit-header activate compile)\n1055 (if (eq major-mode 'git-gutter+-commit-mode)\n1056 (setq ad-return-value\n1057 (concat git-gutter+-skip-commit-header-regex\n1058 (substring ; Remove leading \"\\\\`\"\n1059 ad-return-value 2)))))\n\n1061 (defun git-gutter+-commit-font-lock-keywords ()\n1062 \"Like `git-commit-mode-font-lock-keywords' but with commit header highlighting\"\n1063 `((,(concat \"\\\\`\" git-gutter+-commit-header-regex) . 'git-gutter+-commit-header-face)\n1064 ,@(git-commit-mode-font-lock-keywords)))\n\n\n1067 ;;; Magit synchronization\n1068 ;; Force Magit to refresh git-gutter+ when updating the VC mode line.\n\n1070 (defvar git-gutter+-orig-vc-find-file-hook)\n\n1072 (defvar git-gutter+-vc-find-file-hook-with-refresh\n1073 (lambda ()\n1074 (funcall git-gutter+-orig-vc-find-file-hook)\n1075 (if git-gutter+-mode (git-gutter+-refresh))))\n\n1077 (defadvice magit-update-vc-modeline (around refresh-git-gutter+ compile activate)\n1078 ;; `magit-update-vc-modeline' calls `vc-find-file-hook' (a function!) on each\n1079 ;; buffer in the repo. Temporarily rebind it to `vc-find-file-hook-with-refresh',\n1080 ;; which calls git-gutter+-refresh after updating the VC mode line.\n1081 ;;\n1082 ;; Using `flet' would have been much simpler, but it's deprecated since 24.3.\n1083 (setq git-gutter+-orig-vc-find-file-hook (symbol-function 'vc-find-file-hook))\n1084 (fset 'vc-find-file-hook git-gutter+-vc-find-file-hook-with-refresh)\n1085 (unwind-protect\n1086 ad-do-it\n1087 (fset 'vc-find-file-hook git-gutter+-orig-vc-find-file-hook)))\n\n1089 (provide 'git-gutter+)\n\n1091 ;;; git-gutter+.el ends here\n")) (setq helm-swoop-cache t))) (candidates-in-buffer) (get-line . buffer-substring-no-properties) (keymap keymap (C-M-left . backward-sexp) (C-M-right . forward-sexp) (27 keymap (105 . helm-multi-swoop-all-from-helm-swoop)) (3 keymap (5 . helm-swoop-edit)) keymap (C-M-left . paren-backward-sexp) (C-M-right . paren-forward-sexp) (94 . helm-swoop-caret-match) (menu-bar keymap (help-menu keymap (describe keymap (describe-mode . helm-help)))) (help keymap (109 . helm-help)) (f1 keymap (109 . helm-help)) (8 keymap (109 . helm-help) (104 . undefined) (8 . undefined) (4 . helm-debug-output)) (20 . helm-toggle-resplit-and-swap-windows) (C-tab . undefined) (triple-mouse-3 . ignore) (double-mouse-3 . ignore) (mouse-3 . ignore) (drag-mouse-3 . ignore) (down-mouse-3 . ignore) (triple-mouse-2 . ignore) (double-mouse-2 . ignore) (mouse-2 . ignore) (drag-mouse-2 . ignore) (down-mouse-2 . ignore) (triple-mouse-1 . ignore) (double-mouse-1 . ignore) (mouse-1 . ignore) (drag-mouse-1 . ignore) (down-mouse-1 . ignore) (67108897 . helm-toggle-suspend-update) (3 keymap (21 . helm-force-update) (6 . helm-follow-mode) (11 . helm-kill-selection-and-quit) (25 . helm-yank-selection) (4 . helm-delete-current-selection) (45 . helm-swap-windows)) (67108987 . helm-enlarge-window) (67108989 . helm-narrow-window) (19 . undefined) (18 . undefined) (23 . helm-yank-text-at-point) (24 keymap (2 . helm-resume-list-buffers-after-quit) (98 . helm-resume-previous-session-after-quit) (6 . helm-quit-and-find-file)) (11 . helm-delete-minibuffer-contents) (67108896 . helm-toggle-visible-mark) (0 . helm-toggle-visible-mark) (C-M-up . helm-scroll-other-window-down) (C-M-down . helm-scroll-other-window) (M-prior . helm-scroll-other-window-down) (M-next . helm-scroll-other-window) (12 . helm-recenter-top-bottom-other-window) (15 . helm-next-source) (10 . helm-select-3rd-action) (5 . helm-select-2nd-action-or-end-of-line) ...) (header-line . "[C-c C-e] Edit mode, [M-i] apply all buffers") (action lambda ($line) (helm-swoop--goto-line (when (string-match "^[0-9]+" $line) (string-to-number (match-string 0 $line)))) (when (re-search-forward (mapconcat (quote identity) (split-string helm-pattern " ") "\\|") nil t) (goto-char (match-beginning 0))) (helm-swoop--recenter)) (migemo)) #("git-gutter+-refresh" 0 19 (fontified t face whitespace-line)) "Swoop: " nil "^368 " "*Helm Swoop*" nil nil nil nil nil mapcar #[257 "\211JB\207" [] 3 "\n\n(fn V)"] funcall make-byte-code 0 "\300\301\211:\203@\262\211A\262@\262\211L\210A\262\202\266\302\303!\207" vconcat vector [nil helm-log "restore variables"] 5 "\n\n(fn)" helm-initialize helm-display-buffer helm-log "show prompt" #[0 "\300 \207" [helm-cleanup] 1 "\n\n(fn)"] helm-read-pattern-maybe defalias helm-hook51420 "\302\303DC\216\300\211)\207" [overriding-local-map funcall #[0 "\300\301\302\"\207" [remove-hook helm-cleanup-hook helm-hook51420] 3 "\n\n(fn)"]] 2 add-hook helm-cleanup-hook helm-execute-selection-action "[End session] " make-string 41 45 helm-buffer helm-quit helm-in-persistent-action helm-current-source helm-source-name helm-restored-variables] 9 "\n\n(fn)"]()
funcall(#[0 "\312\211\211\211\305\206\n(()*+,\313\314-\"\315\316\317\320\321\322!\323\"\324\325%DC\216\326\303\301\307\300$\210\327(!\210\330\331!\210\315\332DC\216\333\302\301\304\303\306\307\310\205P\3109\205P\310&\210*\210)?\205r\334\335\316\317\336\321\322\311!\337\"\340\325%\"\210\341\342\335\"\210\343 \330\344\345\346\347\"P!\210-\207" [((name . "git-gutter+.el") (init lambda nil (unless helm-swoop-cache (with-current-buffer (helm-candidate-buffer (quote local)) (insert "1 ;;; git-gutter+.el --- Manage Git hunks straight from the buffer\n\n3 ;; Copyright (C) 2013 by Syohei YOSHIDA and contributors\n\n5 ;; Author: Syohei YOSHIDA <syohex@gmail.com> and contributors\n6 ;; URL: https://github.com/nonsequitur/git-gutter-plus\n7 ;; Version: 0.1\n\n9 ;; This program is free software; you can redistribute it and/or modify\n10 ;; it under the terms of the GNU General Public License as published by\n11 ;; the Free Software Foundation, either version 3 of the License, or\n12 ;; (at your option) any later version.\n\n14 ;; This program is distributed in the hope that it will be useful,\n15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of\n16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n17 ;; GNU General Public License for more details.\n\n19 ;; You should have received a copy of the GNU General Public License\n20 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n22 ;; Package-Requires: ((git-commit-mode \"0.14\"))\n\n24 ;;; Commentary:\n25 ;;\n26 ;; View, stage and revert Git changes straight from the buffer.\n\n28 ;;; Code:\n\n30 (eval-when-compile\n31 (require 'cl))\n\n33 (require 'tramp)\n34 (require 'log-edit)\n35 (require 'git-commit-mode)\n\n37 (defgroup git-gutter+ nil\n38 \"Manage Git hunks straight from the buffer\"\n39 :prefix \"git-gutter+-\"\n40 :group 'vc)\n\n42 (defcustom git-gutter+-window-width nil\n43 \"Character width of the gutter margin. Set this variable if the automatically\n44 calculated width looks wrong. (This can happen with some special characters.)\"\n45 :type 'integer\n46 :group 'git-gutter+)\n\n48 (defcustom git-gutter+-git-executable \"git\"\n49 \"The path of the Git executable.\"\n50 :type 'string\n51 :group 'git-gutter+)\n\n53 (defcustom git-gutter+-diff-options nil\n54 \"List of strings containing extra arguments to 'git diff'\"\n55 :type 'list\n56 :group 'git-gutter+)\n\n58 (defcustom git-gutter+-separator-sign nil\n59 \"Separator sign\"\n60 :type 'string\n61 :group 'git-gutter+)\n\n63 (defcustom git-gutter+-modified-sign \"=\"\n64 \"Modified sign\"\n65 :type 'string\n66 :group 'git-gutter+)\n\n68 (defcustom git-gutter+-added-sign \"+\"\n69 \"Added sign\"\n70 :type 'string\n71 :group 'git-gutter+)\n\n73 (defcustom git-gutter+-deleted-sign \"-\"\n74 \"Deleted sign\"\n75 :type 'string\n76 :group 'git-gutter+)\n\n78 (defcustom git-gutter+-unchanged-sign nil\n79 \"Unchanged sign\"\n80 :type 'string\n81 :group 'git-gutter+)\n\n83 (defcustom git-gutter+-hide-gutter nil\n84 \"Hide gutter if there are no changes\"\n85 :type 'boolean\n86 :group 'git-gutter+)\n\n88 (defcustom git-gutter+-lighter \" GitGutter\"\n89 \"Minor mode lighter in mode-line\"\n90 :type 'string\n91 :group 'git-gutter+)\n\n93 (defface git-gutter+-separator\n94 '((t (:foreground \"cyan\" :weight bold)))\n95 \"Face of the separator\"\n96 :group 'git-gutter+)\n\n98 (defface git-gutter+-modified\n99 '((t (:foreground \"magenta\" :weight bold)))\n100 \"Face for modified lines\"\n101 :group 'git-gutter+)\n\n103 (defface git-gutter+-added\n104 '((t (:foreground \"green\" :weight bold)))\n105 \"Face for added lines\"\n106 :group 'git-gutter+)\n\n108 (defface git-gutter+-deleted\n109 '((t (:foreground \"red\" :weight bold)))\n110 \"Face for deleted lines\"\n111 :group 'git-gutter+)\n\n113 (defface git-gutter+-unchanged\n114 '((t (:background \"yellow\")))\n115 \"Face for unchanged lines\"\n116 :group 'git-gutter+)\n\n118 (defcustom git-gutter+-disabled-modes nil\n119 \"A list of modes for which `global-git-gutter+-mode' should be disabled.\"\n120 :type '(repeat symbol)\n121 :group 'git-gutter+)\n\n123 (defvar git-gutter+-mode-map\n124 (make-sparse-keymap))\n\n126 (defvar git-gutter+-view-diff-function nil\n127 \"Function to call for displaying diffs\")\n\n129 (defvar git-gutter+-clear-function nil\n130 \"Function to call for clearing the diff display\")\n\n132 (defvar git-gutter+-window-config-change-function nil\n133 \"Function to call when the buffer's local window configuration has changed\")\n\n135 (defvar git-gutter+-diffinfos nil)\n136 (defvar git-gutter+-diff-header nil)\n137 (make-variable-buffer-local 'git-gutter+-diffinfos)\n138 (make-variable-buffer-local 'git-gutter+-diff-header)\n\n140 (defvar git-gutter+-popup-buffer \"*git-gutter+-diff*\")\n141 (defvar git-gutter+-buffers-to-reenable nil)\n\n143 (defconst git-gutter+-hunk-header-regex\n144 ;; The same as diff-hunk-header-re-unified\n145 \"^@@ -\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? \\\\+\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? @@\")\n\n147 (defalias 'git-gutter+-popup-hunk 'git-gutter+-show-hunk)\n148 (defalias 'git-gutter+-revert-hunk 'git-gutter+-revert-hunks)\n\n150 (defmacro git-gutter+-awhen (test &rest body)\n151 \"Anaphoric when.\"\n152 (declare (indent 1))\n153 `(let ((it ,test))\n154 (when it ,@body)))\n\n156 (defun git-gutter+-enable-default-display-mode ()\n157 (setq git-gutter+-view-diff-function 'git-gutter+-view-diff-infos\n158 git-gutter+-clear-function 'git-gutter+-clear-diff-infos\n159 git-gutter+-window-config-change-function 'git-gutter+-show-gutter))\n\n161 (unless git-gutter+-view-diff-function\n162 (git-gutter+-enable-default-display-mode))\n\n164 (defun git-gutter+-call-git (args &optional file)\n165 (if (and file (file-remote-p file))\n166 (apply #'process-file git-gutter+-git-executable nil t nil args)\n167 (apply #'call-process git-gutter+-git-executable nil t nil args)))\n\n169 (defun git-gutter+-in-git-repository-p (file)\n170 (with-temp-buffer\n171 (let ((args '(\"rev-parse\" \"--is-inside-work-tree\")))\n172 (when (zerop (git-gutter+-call-git args file))\n173 (goto-char (point-min))\n174 (string= \"true\" (buffer-substring-no-properties\n175 (point) (line-end-position)))))))\n\n177 (defun git-gutter+-root-directory (file)\n178 (with-temp-buffer\n179 (let* ((args '(\"rev-parse\" \"--show-toplevel\"))\n180 (ret (git-gutter+-call-git args file)))\n181 (when (zerop ret)\n182 (goto-char (point-min))\n183 (let ((root (buffer-substring-no-properties (point) (line-end-position))))\n184 (unless (string= root \"\")\n185 (file-name-as-directory root)))))))\n\n187 (defsubst git-gutter+-diff-args (file)\n188 (delq nil (list \"--no-pager\" \"diff\" \"--no-color\" \"--no-ext-diff\" \"-U0\"\n189 git-gutter+-diff-options file)))\n\n191 (defun git-gutter+-diff (curfile)\n192 (let ((args (git-gutter+-diff-args curfile))\n193 (file (buffer-file-name))) ;; for tramp\n194 (with-temp-buffer\n195 (when (zerop (git-gutter+-call-git args file))\n196 (goto-char (point-min))\n197 (let ((diff-header (git-gutter+-get-diff-header))\n198 (diffinfos (git-gutter+-get-diffinfos)))\n199 (list diff-header diffinfos))))))\n\n201 (defun git-gutter+-get-diff-header ()\n202 (save-excursion\n203 (if (re-search-forward git-gutter+-hunk-header-regex nil t)\n204 (buffer-substring (point-min) (match-beginning 0)))))\n\n206 (defsubst git-gutter+-make-diffinfo (type content start end)\n207 (list :type type :content content :start-line start :end-line end))\n\n209 (defun git-gutter+-get-diffinfos ()\n210 (loop while (re-search-forward git-gutter+-hunk-header-regex nil t)\n211 ;; Hunk header format:\n212 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n213 for del-len = (string-to-number (or (match-string 2) \"1\"))\n214 for add-line = (string-to-number (match-string 3))\n215 for add-len = (string-to-number (or (match-string 4) \"1\"))\n216 for type = (cond ((zerop del-len) 'added)\n217 ((zerop add-len) 'deleted)\n218 (t 'modified))\n219 for start-line = (if (eq type 'deleted)\n220 (1+ add-line)\n221 add-line)\n222 for end-line = (if (eq type 'deleted)\n223 start-line\n224 (1- (+ add-line add-len)))\n225 for content = (git-gutter+-diff-content)\n226 collect\n227 (git-gutter+-make-diffinfo type content start-line end-line)))\n\n229 (defun git-gutter+-diff-content ()\n230 (save-excursion\n231 (goto-char (line-beginning-position)) ; Move to beginning of hunk header\n232 (let ((hunk-start (point)))\n233 ;; Move to end of hunk\n234 (forward-line 1)\n235 (if (re-search-forward \"^@@\" nil t)\n236 (backward-char 3) ;; exclude \"\\n@@\"\n237 (goto-char (1- (point-max)))) ; Skip trailing newline\n238 (buffer-substring hunk-start (point)))))\n\n240 (defun git-gutter+-line-to-pos (line)\n241 (save-excursion\n242 (goto-char (point-min))\n243 (forward-line (1- line))\n244 (point)))\n\n246 (defun git-gutter+-before-string (sign)\n247 (let* ((sep-sign git-gutter+-separator-sign)\n248 (sep (when sep-sign\n249 (propertize sep-sign 'face 'git-gutter+-separator)))\n250 (gutter-sep (concat sign sep)))\n251 (propertize \" \" 'display `((margin left-margin) ,gutter-sep))))\n\n253 (defsubst git-gutter+-select-face (type)\n254 (case type\n255 (added 'git-gutter+-added)\n256 (modified 'git-gutter+-modified)\n257 (deleted 'git-gutter+-deleted)))\n\n259 (defsubst git-gutter+-select-sign (type)\n260 (case type\n261 (added git-gutter+-added-sign)\n262 (modified git-gutter+-modified-sign)\n263 (deleted git-gutter+-deleted-sign)))\n\n265 (defun git-gutter+-propertized-sign (type)\n266 (let ((sign (git-gutter+-select-sign type))\n267 (face (git-gutter+-select-face type)))\n268 (propertize sign 'face face)))\n\n270 (defun git-gutter+-view-region (sign start-line end-line)\n271 (let ((beg (git-gutter+-line-to-pos start-line)))\n272 (goto-char beg)\n273 (while (and (<= (line-number-at-pos) end-line) (not (eobp)))\n274 (git-gutter+-view-at-pos sign (point))\n275 (forward-line 1))))\n\n277 (defun git-gutter+-view-at-pos (sign pos)\n278 (let ((ov (make-overlay pos pos)))\n279 (overlay-put ov 'before-string (git-gutter+-before-string sign))\n280 (overlay-put ov 'git-gutter+ t)))\n\n282 (defun git-gutter+-view-diff-info (diffinfo)\n283 (let* ((start-line (plist-get diffinfo :start-line))\n284 (end-line (plist-get diffinfo :end-line))\n285 (type (plist-get diffinfo :type))\n286 (sign (git-gutter+-propertized-sign type)))\n287 (case type\n288 ((modified added) (git-gutter+-view-region sign start-line end-line))\n289 (deleted (git-gutter+-view-at-pos\n290 sign (git-gutter+-line-to-pos start-line))))))\n\n292 (defun git-gutter+-sign-width (sign)\n293 (loop for s across sign\n294 sum (char-width s)))\n\n296 (defun git-gutter+-longest-sign-width ()\n297 (let ((signs (list git-gutter+-modified-sign\n298 git-gutter+-added-sign\n299 git-gutter+-deleted-sign)))\n300 (when git-gutter+-unchanged-sign\n301 (add-to-list 'signs git-gutter+-unchanged-sign))\n302 (+ (apply 'max (mapcar 'git-gutter+-sign-width signs))\n303 (git-gutter+-sign-width git-gutter+-separator-sign))))\n\n305 (defun git-gutter+-view-for-unchanged ()\n306 (save-excursion\n307 (let ((sign (if git-gutter+-unchanged-sign\n308 (propertize git-gutter+-unchanged-sign\n309 'face 'git-gutter+-unchanged)\n310 \" \")))\n311 (goto-char (point-min))\n312 (while (not (eobp))\n313 (git-gutter+-view-at-pos sign (point))\n314 (forward-line 1)))))\n\n316 (defun git-gutter+-set-window-margin (width)\n317 (let ((curwin (get-buffer-window)))\n318 (set-window-margins curwin width (cdr (window-margins curwin)))))\n\n320 (defsubst git-gutter+-file-buffer-p ()\n321 (and (buffer-file-name)\n322 default-directory\n323 (file-directory-p default-directory)))\n\n325 ;;;###autoload\n326 (define-minor-mode git-gutter+-mode\n327 \"Git-Gutter mode\"\n328 :group 'git-gutter+\n329 :init-value nil\n330 :global nil\n331 :lighter git-gutter+-lighter\n332 (if git-gutter+-mode\n333 (if (and (git-gutter+-file-buffer-p)\n334 (git-gutter+-in-git-repository-p (buffer-file-name)))\n335 (progn\n336 (git-gutter+-add-local-hooks)\n337 (git-gutter+-refresh))\n338 (if (called-interactively-p 'any)\n339 (message \"No Git repo for current buffer\"))\n340 (git-gutter+-mode -1))\n341 (git-gutter+-remove-local-hooks)\n342 (git-gutter+-clear)))\n\n344 (defun git-gutter+-add-local-hooks ()\n345 (add-hook 'after-save-hook 'git-gutter+-refresh nil t)\n346 ;; Turn off `git-gutter+-mode' while reverting to prevent any redundant calls to\n347 ;; `git-gutter+-refresh'.\n348 (add-hook 'before-revert-hook 'git-gutter+-turn-off nil t)\n349 (add-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change nil t)\n350 (if git-gutter+-window-config-change-function\n351 (add-hook 'window-configuration-change-hook\n352 git-gutter+-window-config-change-function nil t)))\n\n354 (defun git-gutter+-remove-local-hooks ()\n355 (remove-hook 'after-save-hook 'git-gutter+-refresh t)\n356 (remove-hook 'before-revert-hook 'git-gutter+-turn-off t)\n357 (remove-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change t)\n358 (if git-gutter+-window-config-change-function\n359 (remove-hook 'window-configuration-change-hook\n360 git-gutter+-window-config-change-function t)))\n\n362 (defmacro git-gutter+-in-all-buffers (&rest body)\n363 `(dolist (buf (buffer-list))\n364 (with-current-buffer buf\n365 ,@body)))\n\n367 ;; When `define-globalized-minor-mode' is used to define `global-git-gutter+-mode',\n368 ;; `git-gutter+-mode' and thus `git-gutter+-refresh' get run twice when a new file\n369 ;; is opened. (First for `fundamental-mode', then for the file-specific mode.)\n370 ;; The following definition of `global-git-gutter+-mode' avoids any redundant calls to\n371 ;; `git-gutter+-refresh'.\n\n373 ;;;###autoload\n374 (define-minor-mode global-git-gutter+-mode ()\n375 \"Global Git-Gutter mode\"\n376 :group 'git-gutter+\n377 :init-value nil\n378 :global t\n379 (if global-git-gutter+-mode\n380 (progn\n381 (add-hook 'find-file-hook 'git-gutter+-turn-on)\n382 (add-hook 'after-revert-hook 'git-gutter+-turn-on)\n383 (add-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n384 (git-gutter+-in-all-buffers (git-gutter+-turn-on)))\n385 (remove-hook 'find-file-hook 'git-gutter+-turn-on)\n386 (remove-hook 'after-revert-hook 'git-gutter+-turn-on)\n387 (remove-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n388 (git-gutter+-in-all-buffers (git-gutter+-turn-off))))\n\n390 (defun git-gutter+-turn-on ()\n391 (when (and (buffer-file-name)\n392 (not (memq major-mode git-gutter+-disabled-modes))\n393 (not git-gutter+-mode))\n394 (git-gutter+-mode t)))\n\n396 (defun git-gutter+-turn-off ()\n397 (if git-gutter+-mode (git-gutter+-mode -1)))\n\n399 (defun git-gutter+-reenable-after-major-mode-change ()\n400 (if global-git-gutter+-mode\n401 (add-to-list 'git-gutter+-buffers-to-reenable (current-buffer))))\n\n403 (defun git-gutter+-reenable-buffers ()\n404 (dolist (buf git-gutter+-buffers-to-reenable)\n405 (with-current-buffer buf\n406 (git-gutter+-turn-on)))\n407 (setq git-gutter+-buffers-to-reenable nil))\n\n409 (defsubst git-gutter+-show-gutter-p (diffinfos)\n410 (if git-gutter+-hide-gutter\n411 (or diffinfos git-gutter+-unchanged-sign)\n412 (or global-git-gutter+-mode git-gutter+-unchanged-sign diffinfos)))\n\n414 (defun git-gutter+-show-gutter (&optional diffinfos)\n415 (when (git-gutter+-show-gutter-p (or diffinfos git-gutter+-diffinfos))\n416 (let ((win-width (or git-gutter+-window-width\n417 (git-gutter+-longest-sign-width))))\n418 (git-gutter+-set-window-margin win-width))))\n\n420 (defun git-gutter+-view-diff-infos (diffinfos)\n421 (when (or git-gutter+-unchanged-sign\n422 git-gutter+-separator-sign)\n423 (git-gutter+-view-for-unchanged))\n424 (when diffinfos\n425 (save-excursion\n426 (mapc 'git-gutter+-view-diff-info diffinfos)))\n427 (git-gutter+-show-gutter diffinfos))\n\n429 (defsubst git-gutter+-reset-window-margin-p ()\n430 (or git-gutter+-hide-gutter\n431 (not global-git-gutter+-mode)))\n\n433 (defun git-gutter+-clear-diff-infos ()\n434 (when (git-gutter+-reset-window-margin-p)\n435 (git-gutter+-set-window-margin 0))\n436 (remove-overlays (point-min) (point-max) 'git-gutter+ t))\n\n438 (defun git-gutter+-process-diff (curfile)\n439 (destructuring-bind\n440 (diff-header diffinfos) (git-gutter+-diff curfile)\n441 (setq git-gutter+-diff-header diff-header\n442 git-gutter+-diffinfos diffinfos)\n443 (save-restriction\n444 (widen)\n445 (funcall git-gutter+-view-diff-function diffinfos))))\n\n447 (defun git-gutter+-search-near-diff-index (diffinfos is-reverse)\n448 (loop with current-line = (line-number-at-pos)\n449 with cmp-fn = (if is-reverse '> '<)\n450 for diffinfo in (if is-reverse (reverse diffinfos) diffinfos)\n451 for index = 0 then (1+ index)\n452 for start-line = (plist-get diffinfo :start-line)\n453 when (funcall cmp-fn current-line start-line)\n454 return (if is-reverse\n455 (1- (- (length diffinfos) index))\n456 index)))\n\n458 (defun git-gutter+-diffinfo-at-point ()\n459 (save-restriction\n460 (widen)\n461 (loop with current-line = (line-number-at-pos)\n462 for diffinfo in git-gutter+-diffinfos\n463 for start = (plist-get diffinfo :start-line)\n464 for end = (or (plist-get diffinfo :end-line) (1+ start))\n465 when (and (>= current-line start) (<= current-line end))\n466 return diffinfo)))\n\n468 (defun git-gutter+-collect-deleted-line (str)\n469 (with-temp-buffer\n470 (insert str)\n471 (goto-char (point-min))\n472 (loop while (re-search-forward \"^-\\\\(.*?\\\\)$\" nil t)\n473 collect (match-string 1) into deleted-lines\n474 finally return deleted-lines)))\n\n476 (defun git-gutter+-delete-added-lines (start-line end-line)\n477 (forward-line (1- start-line))\n478 (let ((start-point (point)))\n479 (forward-line (1+ (- end-line start-line)))\n480 (delete-region start-point (point))))\n\n482 (defun git-gutter+-insert-deleted-lines (content)\n483 (dolist (line (git-gutter+-collect-deleted-line content))\n484 (insert (concat line \"\\n\"))))\n\n486 (defun git-gutter+-do-revert-hunk (diffinfo)\n487 (save-excursion\n488 (save-restriction\n489 (widen)\n490 (goto-char (point-min))\n491 (let ((start-line (plist-get diffinfo :start-line))\n492 (end-line (plist-get diffinfo :end-line))\n493 (content (plist-get diffinfo :content)))\n494 (case (plist-get diffinfo :type)\n495 (added (git-gutter+-delete-added-lines start-line end-line))\n496 (deleted (forward-line (1- start-line))\n497 (git-gutter+-insert-deleted-lines content))\n498 (modified (git-gutter+-delete-added-lines start-line end-line)\n499 (git-gutter+-insert-deleted-lines content)))))))\n\n501 (defun git-gutter+-revert-hunks ()\n502 \"Revert hunk at point. If region is active, revert all hunks within the region.\"\n503 (interactive)\n504 (let* ((diffinfos (git-gutter+-selected-diffinfos))\n505 (one-diffinfo-p (= 1 (length diffinfos))))\n506 (save-window-excursion\n507 (if one-diffinfo-p (git-gutter+-show-hunk (car diffinfos)))\n508 (when (and diffinfos\n509 (yes-or-no-p (if one-diffinfo-p\n510 \"Revert hunk?\"\n511 (format \"Revert %d hunks?\" (length diffinfos)))))\n512 ;; Revert diffinfos in reverse so that earlier hunks don't invalidate the\n513 ;; line number information of the later hunks.\n514 (dolist (diffinfo (nreverse diffinfos))\n515 (git-gutter+-do-revert-hunk diffinfo))\n516 (save-buffer))\n517 (if one-diffinfo-p\n518 (git-gutter+-awhen (get-buffer git-gutter+-popup-buffer)\n519 (kill-buffer it))))))\n\n521 (defun git-gutter+-show-hunk (&optional diffinfo)\n522 \"Show hunk at point in another window\"\n523 (interactive)\n524 (git-gutter+-awhen (or diffinfo\n525 (git-gutter+-diffinfo-at-point))\n526 (save-selected-window\n527 (with-current-buffer (get-buffer-create git-gutter+-popup-buffer)\n528 (setq buffer-read-only nil)\n529 (erase-buffer)\n530 (insert (plist-get it :content))\n531 (insert \"\\n\")\n532 (goto-char (point-min))\n533 (diff-mode)\n534 (view-mode)\n535 (pop-to-buffer (current-buffer))))))\n\n537 (defun git-gutter+-next-hunk (arg)\n538 \"Move to next diff hunk\"\n539 (interactive \"p\")\n540 (if (not git-gutter+-diffinfos)\n541 (message \"No changes in buffer\")\n542 (save-restriction\n543 (widen)\n544 (let* ((is-reverse (< arg 0))\n545 (diffinfos git-gutter+-diffinfos)\n546 (len (length diffinfos))\n547 (index (git-gutter+-search-near-diff-index diffinfos is-reverse))\n548 (real-index (if index\n549 (let ((next (if is-reverse (1+ index) (1- index))))\n550 (mod (+ arg next) len))\n551 (if is-reverse (1- (length diffinfos)) 0)))\n552 (diffinfo (nth real-index diffinfos)))\n553 (goto-char (point-min))\n554 (forward-line (1- (plist-get diffinfo :start-line)))\n555 (when (buffer-live-p (get-buffer git-gutter+-popup-buffer))\n556 (save-window-excursion\n557 (git-gutter+-show-hunk)))))))\n\n559 (defun git-gutter+-previous-hunk (arg)\n560 \"Move to previous diff hunk\"\n561 (interactive \"p\")\n562 (git-gutter+-next-hunk (- arg)))\n\n564 (defun git-gutter+-remote-default-directory (dir file)\n565 (let* ((vec (tramp-dissect-file-name file))\n566 (method (aref vec 0))\n567 (user (aref vec 1))\n568 (host (aref vec 2)))\n569 (format \"/%s:%s%s:%s\" method (if user (concat user \"@\") \"\") host dir)))\n\n571 (defun git-gutter+-remote-file-path (dir file)\n572 (let ((file (aref (tramp-dissect-file-name file) 3)))\n573 (replace-regexp-in-string (concat \"\\\\`\" dir) \"\" file)))\n\n575 (defun git-gutter+-local-file-path (file)\n576 (if (eq system-type 'windows-nt)\n577 ;; Cygwin can't handle Windows absolute paths\n578 (file-relative-name file default-directory)\n579 file))\n\n581 (defun git-gutter+-refresh ()\n582 (git-gutter+-clear)\n583 (let ((file (buffer-file-name)))\n584 (when (and file (file-exists-p file))\n585 (if (file-remote-p file)\n586 (let* ((repo-root (git-gutter+-root-directory file))\n587 (default-directory (git-gutter+-remote-default-directory repo-root file)))\n588 (git-gutter+-process-diff (git-gutter+-remote-file-path repo-root file)))\n589 (git-gutter+-process-diff (git-gutter+-local-file-path file))))))\n\n591 (defun git-gutter+-clear ()\n592 (save-restriction\n593 (widen)\n594 (funcall git-gutter+-clear-function))\n595 (setq git-gutter+-diffinfos nil))\n\n\n598 ;;; Staging\n\n600 (defun git-gutter+-stage-hunks ()\n601 \"Stage hunk at point. If region is active, stage all hunk lines within the region.\"\n602 (interactive)\n603 (let* ((line-range (if (use-region-p)\n604 (cons (line-number-at-pos (region-beginning))\n605 (line-number-at-pos (region-end)))))\n606 (diffinfos (git-gutter+-selected-diffinfos line-range)))\n607 (when diffinfos\n608 (let ((error-msg (git-gutter+-stage-diffinfos diffinfos line-range)))\n609 (if error-msg\n610 (message \"Error staging hunks:\\n%s\" error-msg))\n611 (git-gutter+-refresh)))))\n\n613 (defun git-gutter+-selected-diffinfos (&optional line-range)\n614 (unless line-range\n615 (setq line-range (if (use-region-p)\n616 (cons (line-number-at-pos (region-beginning))\n617 (line-number-at-pos (region-end))))))\n618 (if line-range\n619 (git-gutter+-diffinfos-between-lines line-range)\n620 (git-gutter+-awhen (git-gutter+-diffinfo-at-point)\n621 (list it))))\n\n623 (defsubst git-gutter+-diffinfo-between-lines-p (diffinfo start-line end-line)\n624 (let ((diff-start (plist-get diffinfo :start-line))\n625 (diff-end (plist-get diffinfo :end-line)))\n626 (and (<= start-line diff-end)\n627 (<= diff-start end-line))))\n\n629 (defun git-gutter+-diffinfos-between-lines (line-range)\n630 (save-restriction\n631 (widen)\n632 (let ((start-line (car line-range))\n633 (end-line (cdr line-range)))\n634 (delq nil\n635 (mapcar (lambda (diffinfo)\n636 (if (git-gutter+-diffinfo-between-lines-p\n637 diffinfo start-line end-line)\n638 diffinfo))\n639 git-gutter+-diffinfos)))))\n\n641 (defun git-gutter+-stage-diffinfos (diffinfos line-range)\n642 (let ((header git-gutter+-diff-header))\n643 (with-temp-buffer\n644 (insert header)\n645 ;; Insert hunks in reverse so that earlier hunks don't invalidate the line\n646 ;; number information of the later hunks.\n647 (dolist (diffinfo (nreverse diffinfos))\n648 (git-gutter+-insert-diffinfo diffinfo line-range)\n649 (goto-char (point-max)))\n650 (git-gutter+-call-git-on-current-buffer\n651 '(\"apply\" \"--unidiff-zero\" \"--cached\" \"-\")))))\n\n653 (defun git-gutter+-insert-diffinfo (diffinfo line-range)\n654 (let ((content (plist-get diffinfo :content))\n655 (type (plist-get diffinfo :type)))\n656 (if (not line-range)\n657 (git-gutter+-insert-hunk content type)\n658 (let ((diff-start-line (plist-get diffinfo :start-line))\n659 (diff-end-line (plist-get diffinfo :end-line))\n660 (start-line (car line-range))\n661 (end-line (cdr line-range)))\n662 (git-gutter+-insert-hunk content type\n663 (1+ (- start-line diff-start-line))\n664 (1+ (- end-line diff-start-line)))))))\n\n666 (defun git-gutter+-call-git-on-current-buffer (args)\n667 \"Sends the current buffer contents to Git and replaces them with Git's output.\n\n669 RETURNS nil if Git ran successfully. Returns an error description otherwise.\"\n670 (unless (zerop (apply #'call-process-region (point-min) (point-max)\n671 git-gutter+-git-executable t t nil args))\n672 (buffer-string)))\n\n674 (defsubst git-gutter+-read-hunk-header (hunk)\n675 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n676 (string-match git-gutter+-hunk-header-regex hunk)\n677 (list (string-to-number (match-string 1 hunk))\n678 (string-to-number (or (match-string 2 hunk) \"1\"))\n679 (string-to-number (match-string 3 hunk))\n680 (string-to-number (or (match-string 4 hunk) \"1\"))))\n\n682 (defun git-gutter+-insert-hunk (hunk type &optional start end)\n683 \"If START and END are provided, only insert addition (+) lines between\n684 START and END (inclusive). START and END are both line numbers starting with 1.\"\n685 (destructuring-bind\n686 (del-line del-len add-line add-len) (git-gutter+-read-hunk-header hunk)\n687 (let* ((start (max 1 (or start 1)))\n688 (end (min add-len (or end add-len)))\n689 (insert-all-p (or (eq type :deleted)\n690 (and (= start 1) (= end add-len))))\n691 (num-lines-selected (if insert-all-p\n692 add-len\n693 (1+ (- end start)))))\n694 ;; When the user selected the last lines of a hunk with type `modified' (but\n695 ;; not the complete hunk), then don't insert any deletion (-) lines from that\n696 ;; hunk.\n697 (if (and (eq type 'modified)\n698 (> start 1) (= end add-len))\n699 (setq type 'modified-trailing))\n\n701 (save-excursion\n702 (insert hunk \"\\n\"))\n\n704 (git-gutter+-delete-hunk-header)\n\n706 (if (not insert-all-p)\n707 (git-gutter+-modify-hunk type num-lines-selected del-len start))\n\n709 (let ((hunk-header (git-gutter+-make-hunk-header type num-lines-selected\n710 del-line del-len add-line)))\n711 (insert hunk-header \"\\n\")))))\n\n713 (defun git-gutter+-delete-hunk-header ()\n714 (let ((hunk-start (point)))\n715 (forward-line 1)\n716 (delete-region hunk-start (point))))\n\n718 (defun git-gutter+-modify-hunk (type num-lines-selected del-len start)\n719 \"Remove all addition (+) lines from hunk that aren't selected.\n720 If TYPE is not `modified', also remove all deletion (-) lines.\"\n721 (let ((first-line-selected (+ del-len (1- start)))\n722 selected-lines)\n723 (save-excursion\n724 (forward-line first-line-selected)\n725 (let ((selection-start (point)))\n726 (forward-line num-lines-selected)\n727 (setq selected-lines (buffer-substring selection-start (point)))))\n728 (save-excursion\n729 (if (eq type 'modified) (forward-line del-len)) ; skip over deletion (-) lines\n730 (delete-region (point) (point-max))\n731 (insert selected-lines))))\n\n733 (defun git-gutter+-make-hunk-header (type num-lines-selected del-line del-len add-line)\n734 (let ((add-len num-lines-selected))\n735 (case type\n736 (added (setq add-line (1+ del-line)))\n737 (modified-trailing (setq add-line (+ del-line del-len)\n738 del-line (1- add-line)\n739 del-len 0))\n740 (t (setq add-line del-line)))\n741 (format \"@@ -%d,%d +%d,%d @@\"\n742 del-line del-len\n743 add-line add-len)))\n\n\n746 ;;; Committing\n747 ;; This section draws heavily from old Magit source code.\n\n749 (defvar git-gutter+-pre-commit-window-config nil)\n750 (defvar git-gutter+-commit-origin-buffer nil\n751 \"Buffer that started the commit\")\n\n753 (defconst git-gutter+-commit-buffer-name \"*Commit Message*\")\n754 (defconst git-gutter+-staged-changes-buffer-name \"*Staged Changes*\")\n\n756 ;;;###autoload\n757 (defun git-gutter+-commit ()\n758 \"Commit staged changes. If nothing is staged, ask to stage the current buffer.\"\n759 (interactive)\n\n761 (when (and (not (git-gutter+-anything-staged-p))\n762 git-gutter+-diffinfos\n763 (y-or-n-p \"Nothing staged. Stage current buffer? \"))\n764 (git-gutter+-stage-whole-buffer))\n\n766 (let ((file (buffer-file-name))\n767 (dir default-directory))\n768 (git-gutter+-save-window-config-if-needed)\n769 (setq git-gutter+-commit-origin-buffer (current-buffer))\n770 (git-gutter+-open-commit-edit-buffer dir)\n771 (git-gutter+-show-staged-changes file dir)))\n\n773 (defun git-gutter+-stage-and-commit ()\n774 (interactive)\n775 (git-gutter+-stage-hunks)\n776 (git-gutter+-commit))\n\n778 (defun git-gutter+-save-window-config-if-needed ()\n779 ;; Only save the window config if the temporary buffers that get popped-up by\n780 ;; git-gutter+ are not already visible.\n781 ;; In this way, `git-gutter+-commit' can be called twice in a row without\n782 ;; losing the original window config.\n783 (when (not (and git-gutter+-pre-commit-window-config\n784 (get-buffer-window git-gutter+-commit-buffer-name)\n785 (get-buffer-window git-gutter+-staged-changes-buffer-name)))\n786 (setq git-gutter+-pre-commit-window-config (current-window-configuration))))\n\n788 (defun git-gutter+-open-commit-edit-buffer (dir)\n789 \"Opens a buffer for composing the commit message\"\n790 (pop-to-buffer (get-buffer-create git-gutter+-commit-buffer-name))\n791 (setq default-directory dir)\n792 (git-gutter+-commit-mode)\n793 (message \"Type C-c C-c to commit (C-c C-k to cancel).\"))\n\n795 (defsubst git-gutter+-pop-to-staged-changes-buffer ()\n796 (let* ((buf (get-buffer-create git-gutter+-staged-changes-buffer-name))\n797 (window (get-buffer-window buf)))\n798 (if window\n799 ;; Buffer is already visible\n800 (select-window window)\n801 (if (<= (length (window-list)) 2)\n802 (split-window))\n803 (pop-to-buffer buf))))\n\n805 (defun git-gutter+-show-staged-changes (file dir)\n806 (save-selected-window\n807 (git-gutter+-pop-to-staged-changes-buffer)\n808 (setq buffer-read-only nil)\n809 (erase-buffer)\n810 (let ((default-directory dir))\n811 (git-gutter+-call-git '(\"diff\" \"--staged\") file))\n812 (goto-char (point-min))\n813 (diff-mode)\n814 (view-mode)))\n\n816 (defsubst git-gutter+-abort-commit-when-no-changes (allow-empty amend)\n817 (unless (or amend\n818 allow-empty\n819 (git-gutter+-anything-staged-p))\n820 (error\n821 \"Refusing to create empty commit. Maybe you want to amend (%s) or allow-empty (%s)?\"\n822 (key-description (car (where-is-internal\n823 'git-gutter+-commit-toggle-amending)))\n824 (key-description (car (where-is-internal\n825 'git-gutter+-commit-toggle-allow-empty))))))\n\n827 (defsubst git-gutter+-buffer-is-whitespace ()\n828 (save-excursion\n829 (goto-char (point-min))\n830 (looking-at-p \"[ \\t\\n]*\\\\'\")))\n\n832 (defun git-gutter+-publish-commit ()\n833 \"Publish commit\"\n834 (interactive)\n835 (let* ((fields (git-gutter+-commit-get-fields))\n836 (amend (equal \"yes\" (git-gutter+-commit-get-field 'amend fields)))\n837 (allow-empty (equal \"yes\" (git-gutter+-commit-get-field 'allow-empty fields)))\n838 (author (git-gutter+-commit-get-field 'author fields))\n839 (date (git-gutter+-commit-get-field 'date fields)))\n\n841 (git-gutter+-abort-commit-when-no-changes allow-empty amend)\n\n843 (git-gutter+-push-to-comment-ring (buffer-string))\n\n845 (git-gutter+-commit-set-fields nil) ; Delete message header\n\n847 (when (git-gutter+-buffer-is-whitespace)\n848 (erase-buffer)\n849 (insert \"(Empty description)\"))\n\n851 (let ((error-msg (git-gutter+-call-git-on-current-buffer\n852 (append '(\"--no-pager\" \"commit\" \"-F\" \"-\")\n853 (if amend '(\"--amend\"))\n854 (if allow-empty '(\"--allow-empty\"))\n855 (if author (list (concat \"--author=\" author)))\n856 (if date (list (concat \"--date=\" date)))))))\n857 (if error-msg\n858 (progn\n859 (message \"Commit error:\\n%s\" error-msg)\n860 (erase-buffer)\n861 (insert (ring-ref log-edit-comment-ring 0))) ; Reinsert commit message\n862 (message \"Commit successful.\")\n863 (git-gutter+-close-commit-edit-buffer)\n864 (git-gutter+-update-vc-modeline)))))\n\n866 (defun git-gutter+-close-commit-edit-buffer ()\n867 \"Abort edits and discard commit message being composed.\"\n868 (interactive)\n869 (kill-buffer)\n870 (set-window-configuration git-gutter+-pre-commit-window-config))\n\n872 (defun git-gutter+-update-vc-modeline ()\n873 (when (buffer-live-p git-gutter+-commit-origin-buffer)\n874 (with-current-buffer git-gutter+-commit-origin-buffer\n875 ;; Updating the modeline has no effect if the buffer still has\n876 ;; changes - it will remain in the 'modified' state. So skip it then.\n877 (unless git-gutter+-diffinfos\n878 (ignore-errors (vc-find-file-hook))))))\n\n880 (defun git-gutter+-stage-whole-buffer ()\n881 (save-excursion\n882 (mark-whole-buffer)\n883 (git-gutter+-stage-hunks)))\n\n885 (defun git-gutter+-anything-staged-p ()\n886 \"Return t if the current repo has staged changes\"\n887 (not (zerop (git-gutter+-call-git '(\"diff\" \"--quiet\" \"--cached\")))))\n\n889 (defun git-gutter+-commit-toggle-amending ()\n890 \"Toggle whether this will be an amendment to the previous commit.\n891 \\(i.e., whether commit is run via 'git commit --amend')\"\n892 (interactive)\n893 ;; Remove the newline that 'git-commit-mode' adds to a new commit\n894 ;; message buffer by default. This prevents an ugly visual\n895 ;; gap between the commit message header and the previous commit\n896 ;; message.\n897 (when (git-gutter+-buffer-is-whitespace)\n898 (erase-buffer))\n\n900 (let ((amend-was-already-set (git-gutter+-commit-get-field 'amend)))\n901 (git-gutter+-commit-toggle-field 'amend t)\n902 (unless amend-was-already-set\n903 ;; Insert previous commit message\n904 (goto-char (point-max))\n905 (unless (zerop (current-column))\n906 (insert \"\\n\"))\n907 (insert (git-gutter+-get-last-commit-msg)\n908 \"\\n\"))))\n\n910 (defun git-gutter+-commit-toggle-allow-empty ()\n911 \"Toggle whether this commit is allowed to be empty.\n912 \\(i.e., whether commit is run via 'git commit --allow-empty')\"\n913 (interactive)\n914 (git-gutter+-commit-toggle-field 'allow-empty t))\n\n916 (defun git-gutter+-format-author (author email)\n917 (format \"%s <%s>\" author email))\n\n919 (defun git-gutter+-commit-toggle-author ()\n920 \"Toggle whether this commit should have a user-defined author.\"\n921 (interactive)\n922 (git-gutter+-commit-toggle-input\n923 'author (git-gutter+-format-author\n924 (or (git-gutter+-get-cfg \"user\" \"name\") \"Author Name\")\n925 (or (git-gutter+-get-cfg \"user\" \"email\") \"author@email\"))))\n\n927 (defun git-gutter+-commit-toggle-date ()\n928 \"Toggle whether this commit should have a user-defined date.\"\n929 (interactive)\n930 (git-gutter+-commit-toggle-input 'date\n931 ;; ISO 8601\n932 (format-time-string \"%Y-%m-%dT%T%z\" (current-time))))\n\n934 (defun git-gutter+-push-to-comment-ring (comment)\n935 (when (or (ring-empty-p log-edit-comment-ring)\n936 (not (equal comment (ring-ref log-edit-comment-ring 0))))\n937 (ring-insert log-edit-comment-ring comment)))\n\n939 (defun git-gutter+-get-last-commit-msg ()\n940 (git-gutter+-git-output '(\"log\" \"--max-count=1\" \"--pretty=format:%s%n%n%b\" \"HEAD\")))\n\n942 (defun git-gutter+-get-cfg (&rest keys)\n943 (git-gutter+-git-output (list \"config\" (mapconcat 'identity keys \".\"))))\n\n945 (defun git-gutter+-git-output (args)\n946 (with-temp-buffer\n947 (git-gutter+-call-git args)\n948 ;; Delete trailing newlines\n949 (goto-char (point-min))\n950 (if (re-search-forward \"\\n+\\\\'\" nil t)\n951 (replace-match \"\"))\n952 (buffer-string)))\n\n\n955 ;;; Commit message header\n\n957 (defconst git-gutter+-commit-header-end \"-- End of commit options header --\\n\")\n\n959 (defun git-gutter+-commit-get-field (name &optional fields)\n960 (cdr (assq name (or fields (git-gutter+-commit-get-fields)))))\n\n962 (defun git-gutter+-commit-set-field (name value)\n963 (let* ((fields (git-gutter+-commit-get-fields))\n964 (cell (assq name fields)))\n965 (cond (cell\n966 (if value\n967 (rplacd cell value)\n968 (setq fields (delq cell fields))))\n969 (t\n970 (if value\n971 (setq fields (append fields (list (cons name value)))))))\n972 (git-gutter+-commit-set-fields fields)))\n\n974 (defun git-gutter+-commit-toggle-field (name default)\n975 \"Toggle the commit header field named NAME.\n976 If it's currently unset, set it to DEFAULT (t or nil).\"\n977 (let* ((fields (git-gutter+-commit-get-fields))\n978 (cell (assq name fields)))\n979 (if cell\n980 (rplacd cell (if (equal (cdr cell) \"yes\") \"no\" \"yes\"))\n981 (setq fields (acons name (if default \"yes\" \"no\") fields)))\n982 (git-gutter+-commit-set-fields fields)))\n\n984 (defun git-gutter+-commit-toggle-input (name default)\n985 \"Toggle the commit header input named NAME.\n986 If it's currently unset, set it to DEFAULT (a string). If it is\n987 set remove it.\"\n988 (let* ((fields (git-gutter+-commit-get-fields))\n989 (cell (assq name fields)))\n990 (if cell\n991 (setq fields (assq-delete-all name fields))\n992 (setq fields (acons name default fields)))\n993 (git-gutter+-commit-set-fields fields)))\n\n995 (defun git-gutter+-commit-get-fields ()\n996 (let (result)\n997 (goto-char (point-min))\n998 (while (looking-at \"^\\\\([A-Za-z0-9-_]+\\\\): *\\\\(.+\\\\)?$\")\n999 (let ((name (intern (downcase (match-string 1))))\n1000 (value (read (or (match-string 2) \"nil\"))))\n1001 (push (cons name value) result))\n1002 (forward-line))\n1003 (if (looking-at (regexp-quote git-gutter+-commit-header-end))\n1004 (nreverse result))))\n\n1006 (defun git-gutter+-commit-set-fields (fields)\n1007 (goto-char (point-min))\n1008 ;; Delete commit header\n1009 (if (search-forward-regexp (format \"^\\\\(?:[A-Za-z0-9-_]+:.*\\n\\\\)*%s\"\n1010 (regexp-quote git-gutter+-commit-header-end))\n1011 nil t)\n1012 (delete-region (match-beginning 0) (match-end 0)))\n1013 (goto-char (point-min))\n1014 (when fields\n1015 (dolist (field fields)\n1016 (insert (capitalize (symbol-name (car field))) \": \"\n1017 (prin1-to-string (cdr field)) \"\\n\"))\n1018 (insert git-gutter+-commit-header-end)))\n\n\n1021 ;;; git-gutter+-commit-mode\n1022 ;; Like git-commit-mode, but adds keybindings to git-gutter+ commands and\n1023 ;; highlighting support for the commit message header.\n\n1025 (define-derived-mode git-gutter+-commit-mode git-commit-mode \"Git-Gutter-Commit\"\n1026 (setq font-lock-defaults (list (git-gutter+-commit-font-lock-keywords) t)))\n\n1028 (setq git-gutter+-commit-mode-map\n1029 (let ((map (copy-keymap git-commit-mode-map)))\n1030 (define-key map (kbd \"C-c C-c\") 'git-gutter+-publish-commit)\n1031 (define-key map (kbd \"C-c C-k\") 'git-gutter+-close-commit-edit-buffer)\n1032 (define-key map (kbd \"C-c C-a\") 'git-gutter+-commit-toggle-amending)\n1033 (define-key map (kbd \"C-c C-e\") 'git-gutter+-commit-toggle-allow-empty)\n1034 (define-key map (kbd \"C-c C-u\") 'git-gutter+-commit-toggle-author)\n1035 (define-key map (kbd \"C-c C-d\") 'git-gutter+-commit-toggle-date)\n1036 (define-key map (kbd \"C-c C-b\") 'git-commit-ack)\n1037 (define-key map (kbd \"M-p\") 'log-edit-previous-comment)\n1038 (define-key map (kbd \"M-n\") 'log-edit-next-comment)\n1039 map))\n\n1041 (defface git-gutter+-commit-header-face\n1042 '((t :inherit font-lock-comment-face))\n1043 \"Highlights the commit message header\"\n1044 :group 'git-gutter+-faces)\n\n1046 (defconst git-gutter+-commit-header-regex\n1047 (concat \"\\\\(?:.\\\\|\\n\\\\)*?\" (regexp-quote git-gutter+-commit-header-end)))\n\n1049 (defconst git-gutter+-skip-commit-header-regex\n1050 (concat \"\\\\`\\\\(?:\" git-gutter+-commit-header-regex \"\\\\)?\"))\n\n1052 ;; Modify git-commit-summary-regexp to ignore the commit header\n1053 (defadvice git-commit-summary-regexp\n1054 (after ignore-git-gutter+-commit-header activate compile)\n1055 (if (eq major-mode 'git-gutter+-commit-mode)\n1056 (setq ad-return-value\n1057 (concat git-gutter+-skip-commit-header-regex\n1058 (substring ; Remove leading \"\\\\`\"\n1059 ad-return-value 2)))))\n\n1061 (defun git-gutter+-commit-font-lock-keywords ()\n1062 \"Like `git-commit-mode-font-lock-keywords' but with commit header highlighting\"\n1063 `((,(concat \"\\\\`\" git-gutter+-commit-header-regex) . 'git-gutter+-commit-header-face)\n1064 ,@(git-commit-mode-font-lock-keywords)))\n\n\n1067 ;;; Magit synchronization\n1068 ;; Force Magit to refresh git-gutter+ when updating the VC mode line.\n\n1070 (defvar git-gutter+-orig-vc-find-file-hook)\n\n1072 (defvar git-gutter+-vc-find-file-hook-with-refresh\n1073 (lambda ()\n1074 (funcall git-gutter+-orig-vc-find-file-hook)\n1075 (if git-gutter+-mode (git-gutter+-refresh))))\n\n1077 (defadvice magit-update-vc-modeline (around refresh-git-gutter+ compile activate)\n1078 ;; `magit-update-vc-modeline' calls `vc-find-file-hook' (a function!) on each\n1079 ;; buffer in the repo. Temporarily rebind it to `vc-find-file-hook-with-refresh',\n1080 ;; which calls git-gutter+-refresh after updating the VC mode line.\n1081 ;;\n1082 ;; Using `flet' would have been much simpler, but it's deprecated since 24.3.\n1083 (setq git-gutter+-orig-vc-find-file-hook (symbol-function 'vc-find-file-hook))\n1084 (fset 'vc-find-file-hook git-gutter+-vc-find-file-hook-with-refresh)\n1085 (unwind-protect\n1086 ad-do-it\n1087 (fset 'vc-find-file-hook git-gutter+-orig-vc-find-file-hook)))\n\n1089 (provide 'git-gutter+)\n\n1091 ;;; git-gutter+.el ends here\n")) (setq helm-swoop-cache t))) (candidates-in-buffer) (get-line . buffer-substring-no-properties) (keymap keymap (C-M-left . backward-sexp) (C-M-right . forward-sexp) (27 keymap (105 . helm-multi-swoop-all-from-helm-swoop)) (3 keymap (5 . helm-swoop-edit)) keymap (C-M-left . paren-backward-sexp) (C-M-right . paren-forward-sexp) (94 . helm-swoop-caret-match) (menu-bar keymap (help-menu keymap (describe keymap (describe-mode . helm-help)))) (help keymap (109 . helm-help)) (f1 keymap (109 . helm-help)) (8 keymap (109 . helm-help) (104 . undefined) (8 . undefined) (4 . helm-debug-output)) (20 . helm-toggle-resplit-and-swap-windows) (C-tab . undefined) (triple-mouse-3 . ignore) (double-mouse-3 . ignore) (mouse-3 . ignore) (drag-mouse-3 . ignore) (down-mouse-3 . ignore) (triple-mouse-2 . ignore) (double-mouse-2 . ignore) (mouse-2 . ignore) (drag-mouse-2 . ignore) (down-mouse-2 . ignore) (triple-mouse-1 . ignore) (double-mouse-1 . ignore) (mouse-1 . ignore) (drag-mouse-1 . ignore) (down-mouse-1 . ignore) (67108897 . helm-toggle-suspend-update) (3 keymap (21 . helm-force-update) (6 . helm-follow-mode) (11 . helm-kill-selection-and-quit) (25 . helm-yank-selection) (4 . helm-delete-current-selection) (45 . helm-swap-windows)) (67108987 . helm-enlarge-window) (67108989 . helm-narrow-window) (19 . undefined) (18 . undefined) (23 . helm-yank-text-at-point) (24 keymap (2 . helm-resume-list-buffers-after-quit) (98 . helm-resume-previous-session-after-quit) (6 . helm-quit-and-find-file)) (11 . helm-delete-minibuffer-contents) (67108896 . helm-toggle-visible-mark) (0 . helm-toggle-visible-mark) (C-M-up . helm-scroll-other-window-down) (C-M-down . helm-scroll-other-window) (M-prior . helm-scroll-other-window-down) (M-next . helm-scroll-other-window) (12 . helm-recenter-top-bottom-other-window) (15 . helm-next-source) (10 . helm-select-3rd-action) (5 . helm-select-2nd-action-or-end-of-line) ...) (header-line . "[C-c C-e] Edit mode, [M-i] apply all buffers") (action lambda ($line) (helm-swoop--goto-line (when (string-match "^[0-9]+" $line) (string-to-number (match-string 0 $line)))) (when (re-search-forward (mapconcat (quote identity) (split-string helm-pattern " ") "\\|") nil t) (goto-char (match-beginning 0))) (helm-swoop--recenter)) (migemo)) #("git-gutter+-refresh" 0 19 (fontified t face whitespace-line)) "Swoop: " nil "^368 " "*Helm Swoop*" nil nil nil nil nil mapcar #[257 "\211JB\207" [] 3 "\n\n(fn V)"] funcall make-byte-code 0 "\300\301\211:\203@\262\211A\262@\262\211L\210A\262\202\266\302\303!\207" vconcat vector [nil helm-log "restore variables"] 5 "\n\n(fn)" helm-initialize helm-display-buffer helm-log "show prompt" #[0 "\300 \207" [helm-cleanup] 1 "\n\n(fn)"] helm-read-pattern-maybe defalias helm-hook51420 "\302\303DC\216\300\211)\207" [overriding-local-map funcall #[0 "\300\301\302\"\207" [remove-hook helm-cleanup-hook helm-hook51420] 3 "\n\n(fn)"]] 2 add-hook helm-cleanup-hook helm-execute-selection-action "[End session] " make-string 41 45 helm-buffer helm-quit helm-in-persistent-action helm-current-source helm-source-name helm-restored-variables] 9 "\n\n(fn)"])
#[0 "\311\312\313\314\315\"P!\210\"\316\211#\206:\317\300!\320\316\320:\2038@\262$>\211\262?\211\262\2038A\262\202\266\203#%\320\262&\320\262\203Q\321\322!\210\323\324\325\326\327\330 \"\331\"\332\333%DC\216\334\323\324\325\335\327\330\300\301\302\303\304\305\306\307\310&\n\336\"\337\333%D\340\323\341\334EDC\217,\207" [((name . "git-gutter+.el") (init lambda nil (unless helm-swoop-cache (with-current-buffer (helm-candidate-buffer (quote local)) (insert "1 ;;; git-gutter+.el --- Manage Git hunks straight from the buffer\n\n3 ;; Copyright (C) 2013 by Syohei YOSHIDA and contributors\n\n5 ;; Author: Syohei YOSHIDA <syohex@gmail.com> and contributors\n6 ;; URL: https://github.com/nonsequitur/git-gutter-plus\n7 ;; Version: 0.1\n\n9 ;; This program is free software; you can redistribute it and/or modify\n10 ;; it under the terms of the GNU General Public License as published by\n11 ;; the Free Software Foundation, either version 3 of the License, or\n12 ;; (at your option) any later version.\n\n14 ;; This program is distributed in the hope that it will be useful,\n15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of\n16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n17 ;; GNU General Public License for more details.\n\n19 ;; You should have received a copy of the GNU General Public License\n20 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n22 ;; Package-Requires: ((git-commit-mode \"0.14\"))\n\n24 ;;; Commentary:\n25 ;;\n26 ;; View, stage and revert Git changes straight from the buffer.\n\n28 ;;; Code:\n\n30 (eval-when-compile\n31 (require 'cl))\n\n33 (require 'tramp)\n34 (require 'log-edit)\n35 (require 'git-commit-mode)\n\n37 (defgroup git-gutter+ nil\n38 \"Manage Git hunks straight from the buffer\"\n39 :prefix \"git-gutter+-\"\n40 :group 'vc)\n\n42 (defcustom git-gutter+-window-width nil\n43 \"Character width of the gutter margin. Set this variable if the automatically\n44 calculated width looks wrong. (This can happen with some special characters.)\"\n45 :type 'integer\n46 :group 'git-gutter+)\n\n48 (defcustom git-gutter+-git-executable \"git\"\n49 \"The path of the Git executable.\"\n50 :type 'string\n51 :group 'git-gutter+)\n\n53 (defcustom git-gutter+-diff-options nil\n54 \"List of strings containing extra arguments to 'git diff'\"\n55 :type 'list\n56 :group 'git-gutter+)\n\n58 (defcustom git-gutter+-separator-sign nil\n59 \"Separator sign\"\n60 :type 'string\n61 :group 'git-gutter+)\n\n63 (defcustom git-gutter+-modified-sign \"=\"\n64 \"Modified sign\"\n65 :type 'string\n66 :group 'git-gutter+)\n\n68 (defcustom git-gutter+-added-sign \"+\"\n69 \"Added sign\"\n70 :type 'string\n71 :group 'git-gutter+)\n\n73 (defcustom git-gutter+-deleted-sign \"-\"\n74 \"Deleted sign\"\n75 :type 'string\n76 :group 'git-gutter+)\n\n78 (defcustom git-gutter+-unchanged-sign nil\n79 \"Unchanged sign\"\n80 :type 'string\n81 :group 'git-gutter+)\n\n83 (defcustom git-gutter+-hide-gutter nil\n84 \"Hide gutter if there are no changes\"\n85 :type 'boolean\n86 :group 'git-gutter+)\n\n88 (defcustom git-gutter+-lighter \" GitGutter\"\n89 \"Minor mode lighter in mode-line\"\n90 :type 'string\n91 :group 'git-gutter+)\n\n93 (defface git-gutter+-separator\n94 '((t (:foreground \"cyan\" :weight bold)))\n95 \"Face of the separator\"\n96 :group 'git-gutter+)\n\n98 (defface git-gutter+-modified\n99 '((t (:foreground \"magenta\" :weight bold)))\n100 \"Face for modified lines\"\n101 :group 'git-gutter+)\n\n103 (defface git-gutter+-added\n104 '((t (:foreground \"green\" :weight bold)))\n105 \"Face for added lines\"\n106 :group 'git-gutter+)\n\n108 (defface git-gutter+-deleted\n109 '((t (:foreground \"red\" :weight bold)))\n110 \"Face for deleted lines\"\n111 :group 'git-gutter+)\n\n113 (defface git-gutter+-unchanged\n114 '((t (:background \"yellow\")))\n115 \"Face for unchanged lines\"\n116 :group 'git-gutter+)\n\n118 (defcustom git-gutter+-disabled-modes nil\n119 \"A list of modes for which `global-git-gutter+-mode' should be disabled.\"\n120 :type '(repeat symbol)\n121 :group 'git-gutter+)\n\n123 (defvar git-gutter+-mode-map\n124 (make-sparse-keymap))\n\n126 (defvar git-gutter+-view-diff-function nil\n127 \"Function to call for displaying diffs\")\n\n129 (defvar git-gutter+-clear-function nil\n130 \"Function to call for clearing the diff display\")\n\n132 (defvar git-gutter+-window-config-change-function nil\n133 \"Function to call when the buffer's local window configuration has changed\")\n\n135 (defvar git-gutter+-diffinfos nil)\n136 (defvar git-gutter+-diff-header nil)\n137 (make-variable-buffer-local 'git-gutter+-diffinfos)\n138 (make-variable-buffer-local 'git-gutter+-diff-header)\n\n140 (defvar git-gutter+-popup-buffer \"*git-gutter+-diff*\")\n141 (defvar git-gutter+-buffers-to-reenable nil)\n\n143 (defconst git-gutter+-hunk-header-regex\n144 ;; The same as diff-hunk-header-re-unified\n145 \"^@@ -\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? \\\\+\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? @@\")\n\n147 (defalias 'git-gutter+-popup-hunk 'git-gutter+-show-hunk)\n148 (defalias 'git-gutter+-revert-hunk 'git-gutter+-revert-hunks)\n\n150 (defmacro git-gutter+-awhen (test &rest body)\n151 \"Anaphoric when.\"\n152 (declare (indent 1))\n153 `(let ((it ,test))\n154 (when it ,@body)))\n\n156 (defun git-gutter+-enable-default-display-mode ()\n157 (setq git-gutter+-view-diff-function 'git-gutter+-view-diff-infos\n158 git-gutter+-clear-function 'git-gutter+-clear-diff-infos\n159 git-gutter+-window-config-change-function 'git-gutter+-show-gutter))\n\n161 (unless git-gutter+-view-diff-function\n162 (git-gutter+-enable-default-display-mode))\n\n164 (defun git-gutter+-call-git (args &optional file)\n165 (if (and file (file-remote-p file))\n166 (apply #'process-file git-gutter+-git-executable nil t nil args)\n167 (apply #'call-process git-gutter+-git-executable nil t nil args)))\n\n169 (defun git-gutter+-in-git-repository-p (file)\n170 (with-temp-buffer\n171 (let ((args '(\"rev-parse\" \"--is-inside-work-tree\")))\n172 (when (zerop (git-gutter+-call-git args file))\n173 (goto-char (point-min))\n174 (string= \"true\" (buffer-substring-no-properties\n175 (point) (line-end-position)))))))\n\n177 (defun git-gutter+-root-directory (file)\n178 (with-temp-buffer\n179 (let* ((args '(\"rev-parse\" \"--show-toplevel\"))\n180 (ret (git-gutter+-call-git args file)))\n181 (when (zerop ret)\n182 (goto-char (point-min))\n183 (let ((root (buffer-substring-no-properties (point) (line-end-position))))\n184 (unless (string= root \"\")\n185 (file-name-as-directory root)))))))\n\n187 (defsubst git-gutter+-diff-args (file)\n188 (delq nil (list \"--no-pager\" \"diff\" \"--no-color\" \"--no-ext-diff\" \"-U0\"\n189 git-gutter+-diff-options file)))\n\n191 (defun git-gutter+-diff (curfile)\n192 (let ((args (git-gutter+-diff-args curfile))\n193 (file (buffer-file-name))) ;; for tramp\n194 (with-temp-buffer\n195 (when (zerop (git-gutter+-call-git args file))\n196 (goto-char (point-min))\n197 (let ((diff-header (git-gutter+-get-diff-header))\n198 (diffinfos (git-gutter+-get-diffinfos)))\n199 (list diff-header diffinfos))))))\n\n201 (defun git-gutter+-get-diff-header ()\n202 (save-excursion\n203 (if (re-search-forward git-gutter+-hunk-header-regex nil t)\n204 (buffer-substring (point-min) (match-beginning 0)))))\n\n206 (defsubst git-gutter+-make-diffinfo (type content start end)\n207 (list :type type :content content :start-line start :end-line end))\n\n209 (defun git-gutter+-get-diffinfos ()\n210 (loop while (re-search-forward git-gutter+-hunk-header-regex nil t)\n211 ;; Hunk header format:\n212 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n213 for del-len = (string-to-number (or (match-string 2) \"1\"))\n214 for add-line = (string-to-number (match-string 3))\n215 for add-len = (string-to-number (or (match-string 4) \"1\"))\n216 for type = (cond ((zerop del-len) 'added)\n217 ((zerop add-len) 'deleted)\n218 (t 'modified))\n219 for start-line = (if (eq type 'deleted)\n220 (1+ add-line)\n221 add-line)\n222 for end-line = (if (eq type 'deleted)\n223 start-line\n224 (1- (+ add-line add-len)))\n225 for content = (git-gutter+-diff-content)\n226 collect\n227 (git-gutter+-make-diffinfo type content start-line end-line)))\n\n229 (defun git-gutter+-diff-content ()\n230 (save-excursion\n231 (goto-char (line-beginning-position)) ; Move to beginning of hunk header\n232 (let ((hunk-start (point)))\n233 ;; Move to end of hunk\n234 (forward-line 1)\n235 (if (re-search-forward \"^@@\" nil t)\n236 (backward-char 3) ;; exclude \"\\n@@\"\n237 (goto-char (1- (point-max)))) ; Skip trailing newline\n238 (buffer-substring hunk-start (point)))))\n\n240 (defun git-gutter+-line-to-pos (line)\n241 (save-excursion\n242 (goto-char (point-min))\n243 (forward-line (1- line))\n244 (point)))\n\n246 (defun git-gutter+-before-string (sign)\n247 (let* ((sep-sign git-gutter+-separator-sign)\n248 (sep (when sep-sign\n249 (propertize sep-sign 'face 'git-gutter+-separator)))\n250 (gutter-sep (concat sign sep)))\n251 (propertize \" \" 'display `((margin left-margin) ,gutter-sep))))\n\n253 (defsubst git-gutter+-select-face (type)\n254 (case type\n255 (added 'git-gutter+-added)\n256 (modified 'git-gutter+-modified)\n257 (deleted 'git-gutter+-deleted)))\n\n259 (defsubst git-gutter+-select-sign (type)\n260 (case type\n261 (added git-gutter+-added-sign)\n262 (modified git-gutter+-modified-sign)\n263 (deleted git-gutter+-deleted-sign)))\n\n265 (defun git-gutter+-propertized-sign (type)\n266 (let ((sign (git-gutter+-select-sign type))\n267 (face (git-gutter+-select-face type)))\n268 (propertize sign 'face face)))\n\n270 (defun git-gutter+-view-region (sign start-line end-line)\n271 (let ((beg (git-gutter+-line-to-pos start-line)))\n272 (goto-char beg)\n273 (while (and (<= (line-number-at-pos) end-line) (not (eobp)))\n274 (git-gutter+-view-at-pos sign (point))\n275 (forward-line 1))))\n\n277 (defun git-gutter+-view-at-pos (sign pos)\n278 (let ((ov (make-overlay pos pos)))\n279 (overlay-put ov 'before-string (git-gutter+-before-string sign))\n280 (overlay-put ov 'git-gutter+ t)))\n\n282 (defun git-gutter+-view-diff-info (diffinfo)\n283 (let* ((start-line (plist-get diffinfo :start-line))\n284 (end-line (plist-get diffinfo :end-line))\n285 (type (plist-get diffinfo :type))\n286 (sign (git-gutter+-propertized-sign type)))\n287 (case type\n288 ((modified added) (git-gutter+-view-region sign start-line end-line))\n289 (deleted (git-gutter+-view-at-pos\n290 sign (git-gutter+-line-to-pos start-line))))))\n\n292 (defun git-gutter+-sign-width (sign)\n293 (loop for s across sign\n294 sum (char-width s)))\n\n296 (defun git-gutter+-longest-sign-width ()\n297 (let ((signs (list git-gutter+-modified-sign\n298 git-gutter+-added-sign\n299 git-gutter+-deleted-sign)))\n300 (when git-gutter+-unchanged-sign\n301 (add-to-list 'signs git-gutter+-unchanged-sign))\n302 (+ (apply 'max (mapcar 'git-gutter+-sign-width signs))\n303 (git-gutter+-sign-width git-gutter+-separator-sign))))\n\n305 (defun git-gutter+-view-for-unchanged ()\n306 (save-excursion\n307 (let ((sign (if git-gutter+-unchanged-sign\n308 (propertize git-gutter+-unchanged-sign\n309 'face 'git-gutter+-unchanged)\n310 \" \")))\n311 (goto-char (point-min))\n312 (while (not (eobp))\n313 (git-gutter+-view-at-pos sign (point))\n314 (forward-line 1)))))\n\n316 (defun git-gutter+-set-window-margin (width)\n317 (let ((curwin (get-buffer-window)))\n318 (set-window-margins curwin width (cdr (window-margins curwin)))))\n\n320 (defsubst git-gutter+-file-buffer-p ()\n321 (and (buffer-file-name)\n322 default-directory\n323 (file-directory-p default-directory)))\n\n325 ;;;###autoload\n326 (define-minor-mode git-gutter+-mode\n327 \"Git-Gutter mode\"\n328 :group 'git-gutter+\n329 :init-value nil\n330 :global nil\n331 :lighter git-gutter+-lighter\n332 (if git-gutter+-mode\n333 (if (and (git-gutter+-file-buffer-p)\n334 (git-gutter+-in-git-repository-p (buffer-file-name)))\n335 (progn\n336 (git-gutter+-add-local-hooks)\n337 (git-gutter+-refresh))\n338 (if (called-interactively-p 'any)\n339 (message \"No Git repo for current buffer\"))\n340 (git-gutter+-mode -1))\n341 (git-gutter+-remove-local-hooks)\n342 (git-gutter+-clear)))\n\n344 (defun git-gutter+-add-local-hooks ()\n345 (add-hook 'after-save-hook 'git-gutter+-refresh nil t)\n346 ;; Turn off `git-gutter+-mode' while reverting to prevent any redundant calls to\n347 ;; `git-gutter+-refresh'.\n348 (add-hook 'before-revert-hook 'git-gutter+-turn-off nil t)\n349 (add-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change nil t)\n350 (if git-gutter+-window-config-change-function\n351 (add-hook 'window-configuration-change-hook\n352 git-gutter+-window-config-change-function nil t)))\n\n354 (defun git-gutter+-remove-local-hooks ()\n355 (remove-hook 'after-save-hook 'git-gutter+-refresh t)\n356 (remove-hook 'before-revert-hook 'git-gutter+-turn-off t)\n357 (remove-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change t)\n358 (if git-gutter+-window-config-change-function\n359 (remove-hook 'window-configuration-change-hook\n360 git-gutter+-window-config-change-function t)))\n\n362 (defmacro git-gutter+-in-all-buffers (&rest body)\n363 `(dolist (buf (buffer-list))\n364 (with-current-buffer buf\n365 ,@body)))\n\n367 ;; When `define-globalized-minor-mode' is used to define `global-git-gutter+-mode',\n368 ;; `git-gutter+-mode' and thus `git-gutter+-refresh' get run twice when a new file\n369 ;; is opened. (First for `fundamental-mode', then for the file-specific mode.)\n370 ;; The following definition of `global-git-gutter+-mode' avoids any redundant calls to\n371 ;; `git-gutter+-refresh'.\n\n373 ;;;###autoload\n374 (define-minor-mode global-git-gutter+-mode ()\n375 \"Global Git-Gutter mode\"\n376 :group 'git-gutter+\n377 :init-value nil\n378 :global t\n379 (if global-git-gutter+-mode\n380 (progn\n381 (add-hook 'find-file-hook 'git-gutter+-turn-on)\n382 (add-hook 'after-revert-hook 'git-gutter+-turn-on)\n383 (add-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n384 (git-gutter+-in-all-buffers (git-gutter+-turn-on)))\n385 (remove-hook 'find-file-hook 'git-gutter+-turn-on)\n386 (remove-hook 'after-revert-hook 'git-gutter+-turn-on)\n387 (remove-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n388 (git-gutter+-in-all-buffers (git-gutter+-turn-off))))\n\n390 (defun git-gutter+-turn-on ()\n391 (when (and (buffer-file-name)\n392 (not (memq major-mode git-gutter+-disabled-modes))\n393 (not git-gutter+-mode))\n394 (git-gutter+-mode t)))\n\n396 (defun git-gutter+-turn-off ()\n397 (if git-gutter+-mode (git-gutter+-mode -1)))\n\n399 (defun git-gutter+-reenable-after-major-mode-change ()\n400 (if global-git-gutter+-mode\n401 (add-to-list 'git-gutter+-buffers-to-reenable (current-buffer))))\n\n403 (defun git-gutter+-reenable-buffers ()\n404 (dolist (buf git-gutter+-buffers-to-reenable)\n405 (with-current-buffer buf\n406 (git-gutter+-turn-on)))\n407 (setq git-gutter+-buffers-to-reenable nil))\n\n409 (defsubst git-gutter+-show-gutter-p (diffinfos)\n410 (if git-gutter+-hide-gutter\n411 (or diffinfos git-gutter+-unchanged-sign)\n412 (or global-git-gutter+-mode git-gutter+-unchanged-sign diffinfos)))\n\n414 (defun git-gutter+-show-gutter (&optional diffinfos)\n415 (when (git-gutter+-show-gutter-p (or diffinfos git-gutter+-diffinfos))\n416 (let ((win-width (or git-gutter+-window-width\n417 (git-gutter+-longest-sign-width))))\n418 (git-gutter+-set-window-margin win-width))))\n\n420 (defun git-gutter+-view-diff-infos (diffinfos)\n421 (when (or git-gutter+-unchanged-sign\n422 git-gutter+-separator-sign)\n423 (git-gutter+-view-for-unchanged))\n424 (when diffinfos\n425 (save-excursion\n426 (mapc 'git-gutter+-view-diff-info diffinfos)))\n427 (git-gutter+-show-gutter diffinfos))\n\n429 (defsubst git-gutter+-reset-window-margin-p ()\n430 (or git-gutter+-hide-gutter\n431 (not global-git-gutter+-mode)))\n\n433 (defun git-gutter+-clear-diff-infos ()\n434 (when (git-gutter+-reset-window-margin-p)\n435 (git-gutter+-set-window-margin 0))\n436 (remove-overlays (point-min) (point-max) 'git-gutter+ t))\n\n438 (defun git-gutter+-process-diff (curfile)\n439 (destructuring-bind\n440 (diff-header diffinfos) (git-gutter+-diff curfile)\n441 (setq git-gutter+-diff-header diff-header\n442 git-gutter+-diffinfos diffinfos)\n443 (save-restriction\n444 (widen)\n445 (funcall git-gutter+-view-diff-function diffinfos))))\n\n447 (defun git-gutter+-search-near-diff-index (diffinfos is-reverse)\n448 (loop with current-line = (line-number-at-pos)\n449 with cmp-fn = (if is-reverse '> '<)\n450 for diffinfo in (if is-reverse (reverse diffinfos) diffinfos)\n451 for index = 0 then (1+ index)\n452 for start-line = (plist-get diffinfo :start-line)\n453 when (funcall cmp-fn current-line start-line)\n454 return (if is-reverse\n455 (1- (- (length diffinfos) index))\n456 index)))\n\n458 (defun git-gutter+-diffinfo-at-point ()\n459 (save-restriction\n460 (widen)\n461 (loop with current-line = (line-number-at-pos)\n462 for diffinfo in git-gutter+-diffinfos\n463 for start = (plist-get diffinfo :start-line)\n464 for end = (or (plist-get diffinfo :end-line) (1+ start))\n465 when (and (>= current-line start) (<= current-line end))\n466 return diffinfo)))\n\n468 (defun git-gutter+-collect-deleted-line (str)\n469 (with-temp-buffer\n470 (insert str)\n471 (goto-char (point-min))\n472 (loop while (re-search-forward \"^-\\\\(.*?\\\\)$\" nil t)\n473 collect (match-string 1) into deleted-lines\n474 finally return deleted-lines)))\n\n476 (defun git-gutter+-delete-added-lines (start-line end-line)\n477 (forward-line (1- start-line))\n478 (let ((start-point (point)))\n479 (forward-line (1+ (- end-line start-line)))\n480 (delete-region start-point (point))))\n\n482 (defun git-gutter+-insert-deleted-lines (content)\n483 (dolist (line (git-gutter+-collect-deleted-line content))\n484 (insert (concat line \"\\n\"))))\n\n486 (defun git-gutter+-do-revert-hunk (diffinfo)\n487 (save-excursion\n488 (save-restriction\n489 (widen)\n490 (goto-char (point-min))\n491 (let ((start-line (plist-get diffinfo :start-line))\n492 (end-line (plist-get diffinfo :end-line))\n493 (content (plist-get diffinfo :content)))\n494 (case (plist-get diffinfo :type)\n495 (added (git-gutter+-delete-added-lines start-line end-line))\n496 (deleted (forward-line (1- start-line))\n497 (git-gutter+-insert-deleted-lines content))\n498 (modified (git-gutter+-delete-added-lines start-line end-line)\n499 (git-gutter+-insert-deleted-lines content)))))))\n\n501 (defun git-gutter+-revert-hunks ()\n502 \"Revert hunk at point. If region is active, revert all hunks within the region.\"\n503 (interactive)\n504 (let* ((diffinfos (git-gutter+-selected-diffinfos))\n505 (one-diffinfo-p (= 1 (length diffinfos))))\n506 (save-window-excursion\n507 (if one-diffinfo-p (git-gutter+-show-hunk (car diffinfos)))\n508 (when (and diffinfos\n509 (yes-or-no-p (if one-diffinfo-p\n510 \"Revert hunk?\"\n511 (format \"Revert %d hunks?\" (length diffinfos)))))\n512 ;; Revert diffinfos in reverse so that earlier hunks don't invalidate the\n513 ;; line number information of the later hunks.\n514 (dolist (diffinfo (nreverse diffinfos))\n515 (git-gutter+-do-revert-hunk diffinfo))\n516 (save-buffer))\n517 (if one-diffinfo-p\n518 (git-gutter+-awhen (get-buffer git-gutter+-popup-buffer)\n519 (kill-buffer it))))))\n\n521 (defun git-gutter+-show-hunk (&optional diffinfo)\n522 \"Show hunk at point in another window\"\n523 (interactive)\n524 (git-gutter+-awhen (or diffinfo\n525 (git-gutter+-diffinfo-at-point))\n526 (save-selected-window\n527 (with-current-buffer (get-buffer-create git-gutter+-popup-buffer)\n528 (setq buffer-read-only nil)\n529 (erase-buffer)\n530 (insert (plist-get it :content))\n531 (insert \"\\n\")\n532 (goto-char (point-min))\n533 (diff-mode)\n534 (view-mode)\n535 (pop-to-buffer (current-buffer))))))\n\n537 (defun git-gutter+-next-hunk (arg)\n538 \"Move to next diff hunk\"\n539 (interactive \"p\")\n540 (if (not git-gutter+-diffinfos)\n541 (message \"No changes in buffer\")\n542 (save-restriction\n543 (widen)\n544 (let* ((is-reverse (< arg 0))\n545 (diffinfos git-gutter+-diffinfos)\n546 (len (length diffinfos))\n547 (index (git-gutter+-search-near-diff-index diffinfos is-reverse))\n548 (real-index (if index\n549 (let ((next (if is-reverse (1+ index) (1- index))))\n550 (mod (+ arg next) len))\n551 (if is-reverse (1- (length diffinfos)) 0)))\n552 (diffinfo (nth real-index diffinfos)))\n553 (goto-char (point-min))\n554 (forward-line (1- (plist-get diffinfo :start-line)))\n555 (when (buffer-live-p (get-buffer git-gutter+-popup-buffer))\n556 (save-window-excursion\n557 (git-gutter+-show-hunk)))))))\n\n559 (defun git-gutter+-previous-hunk (arg)\n560 \"Move to previous diff hunk\"\n561 (interactive \"p\")\n562 (git-gutter+-next-hunk (- arg)))\n\n564 (defun git-gutter+-remote-default-directory (dir file)\n565 (let* ((vec (tramp-dissect-file-name file))\n566 (method (aref vec 0))\n567 (user (aref vec 1))\n568 (host (aref vec 2)))\n569 (format \"/%s:%s%s:%s\" method (if user (concat user \"@\") \"\") host dir)))\n\n571 (defun git-gutter+-remote-file-path (dir file)\n572 (let ((file (aref (tramp-dissect-file-name file) 3)))\n573 (replace-regexp-in-string (concat \"\\\\`\" dir) \"\" file)))\n\n575 (defun git-gutter+-local-file-path (file)\n576 (if (eq system-type 'windows-nt)\n577 ;; Cygwin can't handle Windows absolute paths\n578 (file-relative-name file default-directory)\n579 file))\n\n581 (defun git-gutter+-refresh ()\n582 (git-gutter+-clear)\n583 (let ((file (buffer-file-name)))\n584 (when (and file (file-exists-p file))\n585 (if (file-remote-p file)\n586 (let* ((repo-root (git-gutter+-root-directory file))\n587 (default-directory (git-gutter+-remote-default-directory repo-root file)))\n588 (git-gutter+-process-diff (git-gutter+-remote-file-path repo-root file)))\n589 (git-gutter+-process-diff (git-gutter+-local-file-path file))))))\n\n591 (defun git-gutter+-clear ()\n592 (save-restriction\n593 (widen)\n594 (funcall git-gutter+-clear-function))\n595 (setq git-gutter+-diffinfos nil))\n\n\n598 ;;; Staging\n\n600 (defun git-gutter+-stage-hunks ()\n601 \"Stage hunk at point. If region is active, stage all hunk lines within the region.\"\n602 (interactive)\n603 (let* ((line-range (if (use-region-p)\n604 (cons (line-number-at-pos (region-beginning))\n605 (line-number-at-pos (region-end)))))\n606 (diffinfos (git-gutter+-selected-diffinfos line-range)))\n607 (when diffinfos\n608 (let ((error-msg (git-gutter+-stage-diffinfos diffinfos line-range)))\n609 (if error-msg\n610 (message \"Error staging hunks:\\n%s\" error-msg))\n611 (git-gutter+-refresh)))))\n\n613 (defun git-gutter+-selected-diffinfos (&optional line-range)\n614 (unless line-range\n615 (setq line-range (if (use-region-p)\n616 (cons (line-number-at-pos (region-beginning))\n617 (line-number-at-pos (region-end))))))\n618 (if line-range\n619 (git-gutter+-diffinfos-between-lines line-range)\n620 (git-gutter+-awhen (git-gutter+-diffinfo-at-point)\n621 (list it))))\n\n623 (defsubst git-gutter+-diffinfo-between-lines-p (diffinfo start-line end-line)\n624 (let ((diff-start (plist-get diffinfo :start-line))\n625 (diff-end (plist-get diffinfo :end-line)))\n626 (and (<= start-line diff-end)\n627 (<= diff-start end-line))))\n\n629 (defun git-gutter+-diffinfos-between-lines (line-range)\n630 (save-restriction\n631 (widen)\n632 (let ((start-line (car line-range))\n633 (end-line (cdr line-range)))\n634 (delq nil\n635 (mapcar (lambda (diffinfo)\n636 (if (git-gutter+-diffinfo-between-lines-p\n637 diffinfo start-line end-line)\n638 diffinfo))\n639 git-gutter+-diffinfos)))))\n\n641 (defun git-gutter+-stage-diffinfos (diffinfos line-range)\n642 (let ((header git-gutter+-diff-header))\n643 (with-temp-buffer\n644 (insert header)\n645 ;; Insert hunks in reverse so that earlier hunks don't invalidate the line\n646 ;; number information of the later hunks.\n647 (dolist (diffinfo (nreverse diffinfos))\n648 (git-gutter+-insert-diffinfo diffinfo line-range)\n649 (goto-char (point-max)))\n650 (git-gutter+-call-git-on-current-buffer\n651 '(\"apply\" \"--unidiff-zero\" \"--cached\" \"-\")))))\n\n653 (defun git-gutter+-insert-diffinfo (diffinfo line-range)\n654 (let ((content (plist-get diffinfo :content))\n655 (type (plist-get diffinfo :type)))\n656 (if (not line-range)\n657 (git-gutter+-insert-hunk content type)\n658 (let ((diff-start-line (plist-get diffinfo :start-line))\n659 (diff-end-line (plist-get diffinfo :end-line))\n660 (start-line (car line-range))\n661 (end-line (cdr line-range)))\n662 (git-gutter+-insert-hunk content type\n663 (1+ (- start-line diff-start-line))\n664 (1+ (- end-line diff-start-line)))))))\n\n666 (defun git-gutter+-call-git-on-current-buffer (args)\n667 \"Sends the current buffer contents to Git and replaces them with Git's output.\n\n669 RETURNS nil if Git ran successfully. Returns an error description otherwise.\"\n670 (unless (zerop (apply #'call-process-region (point-min) (point-max)\n671 git-gutter+-git-executable t t nil args))\n672 (buffer-string)))\n\n674 (defsubst git-gutter+-read-hunk-header (hunk)\n675 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n676 (string-match git-gutter+-hunk-header-regex hunk)\n677 (list (string-to-number (match-string 1 hunk))\n678 (string-to-number (or (match-string 2 hunk) \"1\"))\n679 (string-to-number (match-string 3 hunk))\n680 (string-to-number (or (match-string 4 hunk) \"1\"))))\n\n682 (defun git-gutter+-insert-hunk (hunk type &optional start end)\n683 \"If START and END are provided, only insert addition (+) lines between\n684 START and END (inclusive). START and END are both line numbers starting with 1.\"\n685 (destructuring-bind\n686 (del-line del-len add-line add-len) (git-gutter+-read-hunk-header hunk)\n687 (let* ((start (max 1 (or start 1)))\n688 (end (min add-len (or end add-len)))\n689 (insert-all-p (or (eq type :deleted)\n690 (and (= start 1) (= end add-len))))\n691 (num-lines-selected (if insert-all-p\n692 add-len\n693 (1+ (- end start)))))\n694 ;; When the user selected the last lines of a hunk with type `modified' (but\n695 ;; not the complete hunk), then don't insert any deletion (-) lines from that\n696 ;; hunk.\n697 (if (and (eq type 'modified)\n698 (> start 1) (= end add-len))\n699 (setq type 'modified-trailing))\n\n701 (save-excursion\n702 (insert hunk \"\\n\"))\n\n704 (git-gutter+-delete-hunk-header)\n\n706 (if (not insert-all-p)\n707 (git-gutter+-modify-hunk type num-lines-selected del-len start))\n\n709 (let ((hunk-header (git-gutter+-make-hunk-header type num-lines-selected\n710 del-line del-len add-line)))\n711 (insert hunk-header \"\\n\")))))\n\n713 (defun git-gutter+-delete-hunk-header ()\n714 (let ((hunk-start (point)))\n715 (forward-line 1)\n716 (delete-region hunk-start (point))))\n\n718 (defun git-gutter+-modify-hunk (type num-lines-selected del-len start)\n719 \"Remove all addition (+) lines from hunk that aren't selected.\n720 If TYPE is not `modified', also remove all deletion (-) lines.\"\n721 (let ((first-line-selected (+ del-len (1- start)))\n722 selected-lines)\n723 (save-excursion\n724 (forward-line first-line-selected)\n725 (let ((selection-start (point)))\n726 (forward-line num-lines-selected)\n727 (setq selected-lines (buffer-substring selection-start (point)))))\n728 (save-excursion\n729 (if (eq type 'modified) (forward-line del-len)) ; skip over deletion (-) lines\n730 (delete-region (point) (point-max))\n731 (insert selected-lines))))\n\n733 (defun git-gutter+-make-hunk-header (type num-lines-selected del-line del-len add-line)\n734 (let ((add-len num-lines-selected))\n735 (case type\n736 (added (setq add-line (1+ del-line)))\n737 (modified-trailing (setq add-line (+ del-line del-len)\n738 del-line (1- add-line)\n739 del-len 0))\n740 (t (setq add-line del-line)))\n741 (format \"@@ -%d,%d +%d,%d @@\"\n742 del-line del-len\n743 add-line add-len)))\n\n\n746 ;;; Committing\n747 ;; This section draws heavily from old Magit source code.\n\n749 (defvar git-gutter+-pre-commit-window-config nil)\n750 (defvar git-gutter+-commit-origin-buffer nil\n751 \"Buffer that started the commit\")\n\n753 (defconst git-gutter+-commit-buffer-name \"*Commit Message*\")\n754 (defconst git-gutter+-staged-changes-buffer-name \"*Staged Changes*\")\n\n756 ;;;###autoload\n757 (defun git-gutter+-commit ()\n758 \"Commit staged changes. If nothing is staged, ask to stage the current buffer.\"\n759 (interactive)\n\n761 (when (and (not (git-gutter+-anything-staged-p))\n762 git-gutter+-diffinfos\n763 (y-or-n-p \"Nothing staged. Stage current buffer? \"))\n764 (git-gutter+-stage-whole-buffer))\n\n766 (let ((file (buffer-file-name))\n767 (dir default-directory))\n768 (git-gutter+-save-window-config-if-needed)\n769 (setq git-gutter+-commit-origin-buffer (current-buffer))\n770 (git-gutter+-open-commit-edit-buffer dir)\n771 (git-gutter+-show-staged-changes file dir)))\n\n773 (defun git-gutter+-stage-and-commit ()\n774 (interactive)\n775 (git-gutter+-stage-hunks)\n776 (git-gutter+-commit))\n\n778 (defun git-gutter+-save-window-config-if-needed ()\n779 ;; Only save the window config if the temporary buffers that get popped-up by\n780 ;; git-gutter+ are not already visible.\n781 ;; In this way, `git-gutter+-commit' can be called twice in a row without\n782 ;; losing the original window config.\n783 (when (not (and git-gutter+-pre-commit-window-config\n784 (get-buffer-window git-gutter+-commit-buffer-name)\n785 (get-buffer-window git-gutter+-staged-changes-buffer-name)))\n786 (setq git-gutter+-pre-commit-window-config (current-window-configuration))))\n\n788 (defun git-gutter+-open-commit-edit-buffer (dir)\n789 \"Opens a buffer for composing the commit message\"\n790 (pop-to-buffer (get-buffer-create git-gutter+-commit-buffer-name))\n791 (setq default-directory dir)\n792 (git-gutter+-commit-mode)\n793 (message \"Type C-c C-c to commit (C-c C-k to cancel).\"))\n\n795 (defsubst git-gutter+-pop-to-staged-changes-buffer ()\n796 (let* ((buf (get-buffer-create git-gutter+-staged-changes-buffer-name))\n797 (window (get-buffer-window buf)))\n798 (if window\n799 ;; Buffer is already visible\n800 (select-window window)\n801 (if (<= (length (window-list)) 2)\n802 (split-window))\n803 (pop-to-buffer buf))))\n\n805 (defun git-gutter+-show-staged-changes (file dir)\n806 (save-selected-window\n807 (git-gutter+-pop-to-staged-changes-buffer)\n808 (setq buffer-read-only nil)\n809 (erase-buffer)\n810 (let ((default-directory dir))\n811 (git-gutter+-call-git '(\"diff\" \"--staged\") file))\n812 (goto-char (point-min))\n813 (diff-mode)\n814 (view-mode)))\n\n816 (defsubst git-gutter+-abort-commit-when-no-changes (allow-empty amend)\n817 (unless (or amend\n818 allow-empty\n819 (git-gutter+-anything-staged-p))\n820 (error\n821 \"Refusing to create empty commit. Maybe you want to amend (%s) or allow-empty (%s)?\"\n822 (key-description (car (where-is-internal\n823 'git-gutter+-commit-toggle-amending)))\n824 (key-description (car (where-is-internal\n825 'git-gutter+-commit-toggle-allow-empty))))))\n\n827 (defsubst git-gutter+-buffer-is-whitespace ()\n828 (save-excursion\n829 (goto-char (point-min))\n830 (looking-at-p \"[ \\t\\n]*\\\\'\")))\n\n832 (defun git-gutter+-publish-commit ()\n833 \"Publish commit\"\n834 (interactive)\n835 (let* ((fields (git-gutter+-commit-get-fields))\n836 (amend (equal \"yes\" (git-gutter+-commit-get-field 'amend fields)))\n837 (allow-empty (equal \"yes\" (git-gutter+-commit-get-field 'allow-empty fields)))\n838 (author (git-gutter+-commit-get-field 'author fields))\n839 (date (git-gutter+-commit-get-field 'date fields)))\n\n841 (git-gutter+-abort-commit-when-no-changes allow-empty amend)\n\n843 (git-gutter+-push-to-comment-ring (buffer-string))\n\n845 (git-gutter+-commit-set-fields nil) ; Delete message header\n\n847 (when (git-gutter+-buffer-is-whitespace)\n848 (erase-buffer)\n849 (insert \"(Empty description)\"))\n\n851 (let ((error-msg (git-gutter+-call-git-on-current-buffer\n852 (append '(\"--no-pager\" \"commit\" \"-F\" \"-\")\n853 (if amend '(\"--amend\"))\n854 (if allow-empty '(\"--allow-empty\"))\n855 (if author (list (concat \"--author=\" author)))\n856 (if date (list (concat \"--date=\" date)))))))\n857 (if error-msg\n858 (progn\n859 (message \"Commit error:\\n%s\" error-msg)\n860 (erase-buffer)\n861 (insert (ring-ref log-edit-comment-ring 0))) ; Reinsert commit message\n862 (message \"Commit successful.\")\n863 (git-gutter+-close-commit-edit-buffer)\n864 (git-gutter+-update-vc-modeline)))))\n\n866 (defun git-gutter+-close-commit-edit-buffer ()\n867 \"Abort edits and discard commit message being composed.\"\n868 (interactive)\n869 (kill-buffer)\n870 (set-window-configuration git-gutter+-pre-commit-window-config))\n\n872 (defun git-gutter+-update-vc-modeline ()\n873 (when (buffer-live-p git-gutter+-commit-origin-buffer)\n874 (with-current-buffer git-gutter+-commit-origin-buffer\n875 ;; Updating the modeline has no effect if the buffer still has\n876 ;; changes - it will remain in the 'modified' state. So skip it then.\n877 (unless git-gutter+-diffinfos\n878 (ignore-errors (vc-find-file-hook))))))\n\n880 (defun git-gutter+-stage-whole-buffer ()\n881 (save-excursion\n882 (mark-whole-buffer)\n883 (git-gutter+-stage-hunks)))\n\n885 (defun git-gutter+-anything-staged-p ()\n886 \"Return t if the current repo has staged changes\"\n887 (not (zerop (git-gutter+-call-git '(\"diff\" \"--quiet\" \"--cached\")))))\n\n889 (defun git-gutter+-commit-toggle-amending ()\n890 \"Toggle whether this will be an amendment to the previous commit.\n891 \\(i.e., whether commit is run via 'git commit --amend')\"\n892 (interactive)\n893 ;; Remove the newline that 'git-commit-mode' adds to a new commit\n894 ;; message buffer by default. This prevents an ugly visual\n895 ;; gap between the commit message header and the previous commit\n896 ;; message.\n897 (when (git-gutter+-buffer-is-whitespace)\n898 (erase-buffer))\n\n900 (let ((amend-was-already-set (git-gutter+-commit-get-field 'amend)))\n901 (git-gutter+-commit-toggle-field 'amend t)\n902 (unless amend-was-already-set\n903 ;; Insert previous commit message\n904 (goto-char (point-max))\n905 (unless (zerop (current-column))\n906 (insert \"\\n\"))\n907 (insert (git-gutter+-get-last-commit-msg)\n908 \"\\n\"))))\n\n910 (defun git-gutter+-commit-toggle-allow-empty ()\n911 \"Toggle whether this commit is allowed to be empty.\n912 \\(i.e., whether commit is run via 'git commit --allow-empty')\"\n913 (interactive)\n914 (git-gutter+-commit-toggle-field 'allow-empty t))\n\n916 (defun git-gutter+-format-author (author email)\n917 (format \"%s <%s>\" author email))\n\n919 (defun git-gutter+-commit-toggle-author ()\n920 \"Toggle whether this commit should have a user-defined author.\"\n921 (interactive)\n922 (git-gutter+-commit-toggle-input\n923 'author (git-gutter+-format-author\n924 (or (git-gutter+-get-cfg \"user\" \"name\") \"Author Name\")\n925 (or (git-gutter+-get-cfg \"user\" \"email\") \"author@email\"))))\n\n927 (defun git-gutter+-commit-toggle-date ()\n928 \"Toggle whether this commit should have a user-defined date.\"\n929 (interactive)\n930 (git-gutter+-commit-toggle-input 'date\n931 ;; ISO 8601\n932 (format-time-string \"%Y-%m-%dT%T%z\" (current-time))))\n\n934 (defun git-gutter+-push-to-comment-ring (comment)\n935 (when (or (ring-empty-p log-edit-comment-ring)\n936 (not (equal comment (ring-ref log-edit-comment-ring 0))))\n937 (ring-insert log-edit-comment-ring comment)))\n\n939 (defun git-gutter+-get-last-commit-msg ()\n940 (git-gutter+-git-output '(\"log\" \"--max-count=1\" \"--pretty=format:%s%n%n%b\" \"HEAD\")))\n\n942 (defun git-gutter+-get-cfg (&rest keys)\n943 (git-gutter+-git-output (list \"config\" (mapconcat 'identity keys \".\"))))\n\n945 (defun git-gutter+-git-output (args)\n946 (with-temp-buffer\n947 (git-gutter+-call-git args)\n948 ;; Delete trailing newlines\n949 (goto-char (point-min))\n950 (if (re-search-forward \"\\n+\\\\'\" nil t)\n951 (replace-match \"\"))\n952 (buffer-string)))\n\n\n955 ;;; Commit message header\n\n957 (defconst git-gutter+-commit-header-end \"-- End of commit options header --\\n\")\n\n959 (defun git-gutter+-commit-get-field (name &optional fields)\n960 (cdr (assq name (or fields (git-gutter+-commit-get-fields)))))\n\n962 (defun git-gutter+-commit-set-field (name value)\n963 (let* ((fields (git-gutter+-commit-get-fields))\n964 (cell (assq name fields)))\n965 (cond (cell\n966 (if value\n967 (rplacd cell value)\n968 (setq fields (delq cell fields))))\n969 (t\n970 (if value\n971 (setq fields (append fields (list (cons name value)))))))\n972 (git-gutter+-commit-set-fields fields)))\n\n974 (defun git-gutter+-commit-toggle-field (name default)\n975 \"Toggle the commit header field named NAME.\n976 If it's currently unset, set it to DEFAULT (t or nil).\"\n977 (let* ((fields (git-gutter+-commit-get-fields))\n978 (cell (assq name fields)))\n979 (if cell\n980 (rplacd cell (if (equal (cdr cell) \"yes\") \"no\" \"yes\"))\n981 (setq fields (acons name (if default \"yes\" \"no\") fields)))\n982 (git-gutter+-commit-set-fields fields)))\n\n984 (defun git-gutter+-commit-toggle-input (name default)\n985 \"Toggle the commit header input named NAME.\n986 If it's currently unset, set it to DEFAULT (a string). If it is\n987 set remove it.\"\n988 (let* ((fields (git-gutter+-commit-get-fields))\n989 (cell (assq name fields)))\n990 (if cell\n991 (setq fields (assq-delete-all name fields))\n992 (setq fields (acons name default fields)))\n993 (git-gutter+-commit-set-fields fields)))\n\n995 (defun git-gutter+-commit-get-fields ()\n996 (let (result)\n997 (goto-char (point-min))\n998 (while (looking-at \"^\\\\([A-Za-z0-9-_]+\\\\): *\\\\(.+\\\\)?$\")\n999 (let ((name (intern (downcase (match-string 1))))\n1000 (value (read (or (match-string 2) \"nil\"))))\n1001 (push (cons name value) result))\n1002 (forward-line))\n1003 (if (looking-at (regexp-quote git-gutter+-commit-header-end))\n1004 (nreverse result))))\n\n1006 (defun git-gutter+-commit-set-fields (fields)\n1007 (goto-char (point-min))\n1008 ;; Delete commit header\n1009 (if (search-forward-regexp (format \"^\\\\(?:[A-Za-z0-9-_]+:.*\\n\\\\)*%s\"\n1010 (regexp-quote git-gutter+-commit-header-end))\n1011 nil t)\n1012 (delete-region (match-beginning 0) (match-end 0)))\n1013 (goto-char (point-min))\n1014 (when fields\n1015 (dolist (field fields)\n1016 (insert (capitalize (symbol-name (car field))) \": \"\n1017 (prin1-to-string (cdr field)) \"\\n\"))\n1018 (insert git-gutter+-commit-header-end)))\n\n\n1021 ;;; git-gutter+-commit-mode\n1022 ;; Like git-commit-mode, but adds keybindings to git-gutter+ commands and\n1023 ;; highlighting support for the commit message header.\n\n1025 (define-derived-mode git-gutter+-commit-mode git-commit-mode \"Git-Gutter-Commit\"\n1026 (setq font-lock-defaults (list (git-gutter+-commit-font-lock-keywords) t)))\n\n1028 (setq git-gutter+-commit-mode-map\n1029 (let ((map (copy-keymap git-commit-mode-map)))\n1030 (define-key map (kbd \"C-c C-c\") 'git-gutter+-publish-commit)\n1031 (define-key map (kbd \"C-c C-k\") 'git-gutter+-close-commit-edit-buffer)\n1032 (define-key map (kbd \"C-c C-a\") 'git-gutter+-commit-toggle-amending)\n1033 (define-key map (kbd \"C-c C-e\") 'git-gutter+-commit-toggle-allow-empty)\n1034 (define-key map (kbd \"C-c C-u\") 'git-gutter+-commit-toggle-author)\n1035 (define-key map (kbd \"C-c C-d\") 'git-gutter+-commit-toggle-date)\n1036 (define-key map (kbd \"C-c C-b\") 'git-commit-ack)\n1037 (define-key map (kbd \"M-p\") 'log-edit-previous-comment)\n1038 (define-key map (kbd \"M-n\") 'log-edit-next-comment)\n1039 map))\n\n1041 (defface git-gutter+-commit-header-face\n1042 '((t :inherit font-lock-comment-face))\n1043 \"Highlights the commit message header\"\n1044 :group 'git-gutter+-faces)\n\n1046 (defconst git-gutter+-commit-header-regex\n1047 (concat \"\\\\(?:.\\\\|\\n\\\\)*?\" (regexp-quote git-gutter+-commit-header-end)))\n\n1049 (defconst git-gutter+-skip-commit-header-regex\n1050 (concat \"\\\\`\\\\(?:\" git-gutter+-commit-header-regex \"\\\\)?\"))\n\n1052 ;; Modify git-commit-summary-regexp to ignore the commit header\n1053 (defadvice git-commit-summary-regexp\n1054 (after ignore-git-gutter+-commit-header activate compile)\n1055 (if (eq major-mode 'git-gutter+-commit-mode)\n1056 (setq ad-return-value\n1057 (concat git-gutter+-skip-commit-header-regex\n1058 (substring ; Remove leading \"\\\\`\"\n1059 ad-return-value 2)))))\n\n1061 (defun git-gutter+-commit-font-lock-keywords ()\n1062 \"Like `git-commit-mode-font-lock-keywords' but with commit header highlighting\"\n1063 `((,(concat \"\\\\`\" git-gutter+-commit-header-regex) . 'git-gutter+-commit-header-face)\n1064 ,@(git-commit-mode-font-lock-keywords)))\n\n\n1067 ;;; Magit synchronization\n1068 ;; Force Magit to refresh git-gutter+ when updating the VC mode line.\n\n1070 (defvar git-gutter+-orig-vc-find-file-hook)\n\n1072 (defvar git-gutter+-vc-find-file-hook-with-refresh\n1073 (lambda ()\n1074 (funcall git-gutter+-orig-vc-find-file-hook)\n1075 (if git-gutter+-mode (git-gutter+-refresh))))\n\n1077 (defadvice magit-update-vc-modeline (around refresh-git-gutter+ compile activate)\n1078 ;; `magit-update-vc-modeline' calls `vc-find-file-hook' (a function!) on each\n1079 ;; buffer in the repo. Temporarily rebind it to `vc-find-file-hook-with-refresh',\n1080 ;; which calls git-gutter+-refresh after updating the VC mode line.\n1081 ;;\n1082 ;; Using `flet' would have been much simpler, but it's deprecated since 24.3.\n1083 (setq git-gutter+-orig-vc-find-file-hook (symbol-function 'vc-find-file-hook))\n1084 (fset 'vc-find-file-hook git-gutter+-vc-find-file-hook-with-refresh)\n1085 (unwind-protect\n1086 ad-do-it\n1087 (fset 'vc-find-file-hook git-gutter+-orig-vc-find-file-hook)))\n\n1089 (provide 'git-gutter+)\n\n1091 ;;; git-gutter+.el ends here\n")) (setq helm-swoop-cache t))) (candidates-in-buffer) (get-line . buffer-substring-no-properties) (keymap keymap (C-M-left . backward-sexp) (C-M-right . forward-sexp) (27 keymap (105 . helm-multi-swoop-all-from-helm-swoop)) (3 keymap (5 . helm-swoop-edit)) keymap (C-M-left . paren-backward-sexp) (C-M-right . paren-forward-sexp) (94 . helm-swoop-caret-match) (menu-bar keymap (help-menu keymap (describe keymap (describe-mode . helm-help)))) (help keymap (109 . helm-help)) (f1 keymap (109 . helm-help)) (8 keymap (109 . helm-help) (104 . undefined) (8 . undefined) (4 . helm-debug-output)) (20 . helm-toggle-resplit-and-swap-windows) (C-tab . undefined) (triple-mouse-3 . ignore) (double-mouse-3 . ignore) (mouse-3 . ignore) (drag-mouse-3 . ignore) (down-mouse-3 . ignore) (triple-mouse-2 . ignore) (double-mouse-2 . ignore) (mouse-2 . ignore) (drag-mouse-2 . ignore) (down-mouse-2 . ignore) (triple-mouse-1 . ignore) (double-mouse-1 . ignore) (mouse-1 . ignore) (drag-mouse-1 . ignore) (down-mouse-1 . ignore) (67108897 . helm-toggle-suspend-update) (3 keymap (21 . helm-force-update) (6 . helm-follow-mode) (11 . helm-kill-selection-and-quit) (25 . helm-yank-selection) (4 . helm-delete-current-selection) (45 . helm-swap-windows)) (67108987 . helm-enlarge-window) (67108989 . helm-narrow-window) (19 . undefined) (18 . undefined) (23 . helm-yank-text-at-point) (24 keymap (2 . helm-resume-list-buffers-after-quit) (98 . helm-resume-previous-session-after-quit) (6 . helm-quit-and-find-file)) (11 . helm-delete-minibuffer-contents) (67108896 . helm-toggle-visible-mark) (0 . helm-toggle-visible-mark) (C-M-up . helm-scroll-other-window-down) (C-M-down . helm-scroll-other-window) (M-prior . helm-scroll-other-window-down) (M-next . helm-scroll-other-window) (12 . helm-recenter-top-bottom-other-window) (15 . helm-next-source) (10 . helm-select-3rd-action) (5 . helm-select-2nd-action-or-end-of-line) ...) (header-line . "[C-c C-e] Edit mode, [M-i] apply all buffers") (action lambda ($line) (helm-swoop--goto-line (when (string-match "^[0-9]+" $line) (string-to-number (match-string 0 $line)))) (when (re-search-forward (mapconcat (quote identity) (split-string helm-pattern " ") "\\|") nil t) (goto-char (match-beginning 0))) (helm-swoop--recenter)) (migemo)) #("git-gutter+-refresh" 0 19 (fontified t face whitespace-line)) "Swoop: " nil "^368 " "*Helm Swoop*" nil nil nil helm-log "[Start session] " make-string 41 43 t helm-normalize-sources nil cua-mode -1 funcall make-byte-code 0 "\300\305\211\301\203\306\307!\210\310 \207" vconcat vector [overriding-local-map helm-alive-p helm-in-file-completion-p nil cua-mode 1 helm-log-save-maybe] 3 "\n\n(fn)" err "\312\211\211\211\305\206\n(()*+,\313\314-\"\315\316\317\320\321\322!\323\"\324\325%DC\216\326\303\301\307\300$\210\327(!\210\330\331!\210\315\332DC\216\333\302\301\304\303\306\307\310\205P\3109\205P\310&\210*\210)?\205r\334\335\316\317\336\321\322\311!\337\"\340\325%\"\210\341\342\335\"\210\343 \330\344\345\346\347\"P!\210-\207" [nil mapcar #[257 "\211JB\207" [] 3 "\n\n(fn V)"] funcall make-byte-code 0 "\300\301\211:\203@\262\211A\262@\262\211L\210A\262\202\266\302\303!\207" vconcat vector [nil helm-log "restore variables"] 5 "\n\n(fn)" helm-initialize helm-display-buffer helm-log "show prompt" #[0 "\300 \207" [helm-cleanup] 1 "\n\n(fn)"] helm-read-pattern-maybe defalias helm-hook51420 "\302\303DC\216\300\211)\207" [overriding-local-map funcall #[0 "\300\301\302\"\207" [remove-hook helm-cleanup-hook helm-hook51420] 3 "\n\n(fn)"]] 2 add-hook helm-cleanup-hook helm-execute-selection-action "[End session] " make-string 41 45 helm-buffer helm-quit helm-in-persistent-action helm-current-source helm-source-name helm-restored-variables] 9 quit #[257 "\300 \210\301\302\303\304\305\"P!\210\306\207" [helm-restore-position-on-quit helm-log "[End session (quit)] " make-string 34 45 nil] 6 "\n\n(fn V)"] overriding-local-map helm-maybe-use-default-as-input helm-sources-using-default-as-input non-essential cursor-in-echo-area] 21 "\n\n(fn)"]()
funcall(#[0 "\311\312\313\314\315\"P!\210\"\316\211#\206:\317\300!\320\316\320:\2038@\262$>\211\262?\211\262\2038A\262\202\266\203#%\320\262&\320\262\203Q\321\322!\210\323\324\325\326\327\330 \"\331\"\332\333%DC\216\334\323\324\325\335\327\330\300\301\302\303\304\305\306\307\310&\n\336\"\337\333%D\340\323\341\334EDC\217,\207" [((name . "git-gutter+.el") (init lambda nil (unless helm-swoop-cache (with-current-buffer (helm-candidate-buffer (quote local)) (insert "1 ;;; git-gutter+.el --- Manage Git hunks straight from the buffer\n\n3 ;; Copyright (C) 2013 by Syohei YOSHIDA and contributors\n\n5 ;; Author: Syohei YOSHIDA <syohex@gmail.com> and contributors\n6 ;; URL: https://github.com/nonsequitur/git-gutter-plus\n7 ;; Version: 0.1\n\n9 ;; This program is free software; you can redistribute it and/or modify\n10 ;; it under the terms of the GNU General Public License as published by\n11 ;; the Free Software Foundation, either version 3 of the License, or\n12 ;; (at your option) any later version.\n\n14 ;; This program is distributed in the hope that it will be useful,\n15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of\n16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n17 ;; GNU General Public License for more details.\n\n19 ;; You should have received a copy of the GNU General Public License\n20 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n22 ;; Package-Requires: ((git-commit-mode \"0.14\"))\n\n24 ;;; Commentary:\n25 ;;\n26 ;; View, stage and revert Git changes straight from the buffer.\n\n28 ;;; Code:\n\n30 (eval-when-compile\n31 (require 'cl))\n\n33 (require 'tramp)\n34 (require 'log-edit)\n35 (require 'git-commit-mode)\n\n37 (defgroup git-gutter+ nil\n38 \"Manage Git hunks straight from the buffer\"\n39 :prefix \"git-gutter+-\"\n40 :group 'vc)\n\n42 (defcustom git-gutter+-window-width nil\n43 \"Character width of the gutter margin. Set this variable if the automatically\n44 calculated width looks wrong. (This can happen with some special characters.)\"\n45 :type 'integer\n46 :group 'git-gutter+)\n\n48 (defcustom git-gutter+-git-executable \"git\"\n49 \"The path of the Git executable.\"\n50 :type 'string\n51 :group 'git-gutter+)\n\n53 (defcustom git-gutter+-diff-options nil\n54 \"List of strings containing extra arguments to 'git diff'\"\n55 :type 'list\n56 :group 'git-gutter+)\n\n58 (defcustom git-gutter+-separator-sign nil\n59 \"Separator sign\"\n60 :type 'string\n61 :group 'git-gutter+)\n\n63 (defcustom git-gutter+-modified-sign \"=\"\n64 \"Modified sign\"\n65 :type 'string\n66 :group 'git-gutter+)\n\n68 (defcustom git-gutter+-added-sign \"+\"\n69 \"Added sign\"\n70 :type 'string\n71 :group 'git-gutter+)\n\n73 (defcustom git-gutter+-deleted-sign \"-\"\n74 \"Deleted sign\"\n75 :type 'string\n76 :group 'git-gutter+)\n\n78 (defcustom git-gutter+-unchanged-sign nil\n79 \"Unchanged sign\"\n80 :type 'string\n81 :group 'git-gutter+)\n\n83 (defcustom git-gutter+-hide-gutter nil\n84 \"Hide gutter if there are no changes\"\n85 :type 'boolean\n86 :group 'git-gutter+)\n\n88 (defcustom git-gutter+-lighter \" GitGutter\"\n89 \"Minor mode lighter in mode-line\"\n90 :type 'string\n91 :group 'git-gutter+)\n\n93 (defface git-gutter+-separator\n94 '((t (:foreground \"cyan\" :weight bold)))\n95 \"Face of the separator\"\n96 :group 'git-gutter+)\n\n98 (defface git-gutter+-modified\n99 '((t (:foreground \"magenta\" :weight bold)))\n100 \"Face for modified lines\"\n101 :group 'git-gutter+)\n\n103 (defface git-gutter+-added\n104 '((t (:foreground \"green\" :weight bold)))\n105 \"Face for added lines\"\n106 :group 'git-gutter+)\n\n108 (defface git-gutter+-deleted\n109 '((t (:foreground \"red\" :weight bold)))\n110 \"Face for deleted lines\"\n111 :group 'git-gutter+)\n\n113 (defface git-gutter+-unchanged\n114 '((t (:background \"yellow\")))\n115 \"Face for unchanged lines\"\n116 :group 'git-gutter+)\n\n118 (defcustom git-gutter+-disabled-modes nil\n119 \"A list of modes for which `global-git-gutter+-mode' should be disabled.\"\n120 :type '(repeat symbol)\n121 :group 'git-gutter+)\n\n123 (defvar git-gutter+-mode-map\n124 (make-sparse-keymap))\n\n126 (defvar git-gutter+-view-diff-function nil\n127 \"Function to call for displaying diffs\")\n\n129 (defvar git-gutter+-clear-function nil\n130 \"Function to call for clearing the diff display\")\n\n132 (defvar git-gutter+-window-config-change-function nil\n133 \"Function to call when the buffer's local window configuration has changed\")\n\n135 (defvar git-gutter+-diffinfos nil)\n136 (defvar git-gutter+-diff-header nil)\n137 (make-variable-buffer-local 'git-gutter+-diffinfos)\n138 (make-variable-buffer-local 'git-gutter+-diff-header)\n\n140 (defvar git-gutter+-popup-buffer \"*git-gutter+-diff*\")\n141 (defvar git-gutter+-buffers-to-reenable nil)\n\n143 (defconst git-gutter+-hunk-header-regex\n144 ;; The same as diff-hunk-header-re-unified\n145 \"^@@ -\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? \\\\+\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? @@\")\n\n147 (defalias 'git-gutter+-popup-hunk 'git-gutter+-show-hunk)\n148 (defalias 'git-gutter+-revert-hunk 'git-gutter+-revert-hunks)\n\n150 (defmacro git-gutter+-awhen (test &rest body)\n151 \"Anaphoric when.\"\n152 (declare (indent 1))\n153 `(let ((it ,test))\n154 (when it ,@body)))\n\n156 (defun git-gutter+-enable-default-display-mode ()\n157 (setq git-gutter+-view-diff-function 'git-gutter+-view-diff-infos\n158 git-gutter+-clear-function 'git-gutter+-clear-diff-infos\n159 git-gutter+-window-config-change-function 'git-gutter+-show-gutter))\n\n161 (unless git-gutter+-view-diff-function\n162 (git-gutter+-enable-default-display-mode))\n\n164 (defun git-gutter+-call-git (args &optional file)\n165 (if (and file (file-remote-p file))\n166 (apply #'process-file git-gutter+-git-executable nil t nil args)\n167 (apply #'call-process git-gutter+-git-executable nil t nil args)))\n\n169 (defun git-gutter+-in-git-repository-p (file)\n170 (with-temp-buffer\n171 (let ((args '(\"rev-parse\" \"--is-inside-work-tree\")))\n172 (when (zerop (git-gutter+-call-git args file))\n173 (goto-char (point-min))\n174 (string= \"true\" (buffer-substring-no-properties\n175 (point) (line-end-position)))))))\n\n177 (defun git-gutter+-root-directory (file)\n178 (with-temp-buffer\n179 (let* ((args '(\"rev-parse\" \"--show-toplevel\"))\n180 (ret (git-gutter+-call-git args file)))\n181 (when (zerop ret)\n182 (goto-char (point-min))\n183 (let ((root (buffer-substring-no-properties (point) (line-end-position))))\n184 (unless (string= root \"\")\n185 (file-name-as-directory root)))))))\n\n187 (defsubst git-gutter+-diff-args (file)\n188 (delq nil (list \"--no-pager\" \"diff\" \"--no-color\" \"--no-ext-diff\" \"-U0\"\n189 git-gutter+-diff-options file)))\n\n191 (defun git-gutter+-diff (curfile)\n192 (let ((args (git-gutter+-diff-args curfile))\n193 (file (buffer-file-name))) ;; for tramp\n194 (with-temp-buffer\n195 (when (zerop (git-gutter+-call-git args file))\n196 (goto-char (point-min))\n197 (let ((diff-header (git-gutter+-get-diff-header))\n198 (diffinfos (git-gutter+-get-diffinfos)))\n199 (list diff-header diffinfos))))))\n\n201 (defun git-gutter+-get-diff-header ()\n202 (save-excursion\n203 (if (re-search-forward git-gutter+-hunk-header-regex nil t)\n204 (buffer-substring (point-min) (match-beginning 0)))))\n\n206 (defsubst git-gutter+-make-diffinfo (type content start end)\n207 (list :type type :content content :start-line start :end-line end))\n\n209 (defun git-gutter+-get-diffinfos ()\n210 (loop while (re-search-forward git-gutter+-hunk-header-regex nil t)\n211 ;; Hunk header format:\n212 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n213 for del-len = (string-to-number (or (match-string 2) \"1\"))\n214 for add-line = (string-to-number (match-string 3))\n215 for add-len = (string-to-number (or (match-string 4) \"1\"))\n216 for type = (cond ((zerop del-len) 'added)\n217 ((zerop add-len) 'deleted)\n218 (t 'modified))\n219 for start-line = (if (eq type 'deleted)\n220 (1+ add-line)\n221 add-line)\n222 for end-line = (if (eq type 'deleted)\n223 start-line\n224 (1- (+ add-line add-len)))\n225 for content = (git-gutter+-diff-content)\n226 collect\n227 (git-gutter+-make-diffinfo type content start-line end-line)))\n\n229 (defun git-gutter+-diff-content ()\n230 (save-excursion\n231 (goto-char (line-beginning-position)) ; Move to beginning of hunk header\n232 (let ((hunk-start (point)))\n233 ;; Move to end of hunk\n234 (forward-line 1)\n235 (if (re-search-forward \"^@@\" nil t)\n236 (backward-char 3) ;; exclude \"\\n@@\"\n237 (goto-char (1- (point-max)))) ; Skip trailing newline\n238 (buffer-substring hunk-start (point)))))\n\n240 (defun git-gutter+-line-to-pos (line)\n241 (save-excursion\n242 (goto-char (point-min))\n243 (forward-line (1- line))\n244 (point)))\n\n246 (defun git-gutter+-before-string (sign)\n247 (let* ((sep-sign git-gutter+-separator-sign)\n248 (sep (when sep-sign\n249 (propertize sep-sign 'face 'git-gutter+-separator)))\n250 (gutter-sep (concat sign sep)))\n251 (propertize \" \" 'display `((margin left-margin) ,gutter-sep))))\n\n253 (defsubst git-gutter+-select-face (type)\n254 (case type\n255 (added 'git-gutter+-added)\n256 (modified 'git-gutter+-modified)\n257 (deleted 'git-gutter+-deleted)))\n\n259 (defsubst git-gutter+-select-sign (type)\n260 (case type\n261 (added git-gutter+-added-sign)\n262 (modified git-gutter+-modified-sign)\n263 (deleted git-gutter+-deleted-sign)))\n\n265 (defun git-gutter+-propertized-sign (type)\n266 (let ((sign (git-gutter+-select-sign type))\n267 (face (git-gutter+-select-face type)))\n268 (propertize sign 'face face)))\n\n270 (defun git-gutter+-view-region (sign start-line end-line)\n271 (let ((beg (git-gutter+-line-to-pos start-line)))\n272 (goto-char beg)\n273 (while (and (<= (line-number-at-pos) end-line) (not (eobp)))\n274 (git-gutter+-view-at-pos sign (point))\n275 (forward-line 1))))\n\n277 (defun git-gutter+-view-at-pos (sign pos)\n278 (let ((ov (make-overlay pos pos)))\n279 (overlay-put ov 'before-string (git-gutter+-before-string sign))\n280 (overlay-put ov 'git-gutter+ t)))\n\n282 (defun git-gutter+-view-diff-info (diffinfo)\n283 (let* ((start-line (plist-get diffinfo :start-line))\n284 (end-line (plist-get diffinfo :end-line))\n285 (type (plist-get diffinfo :type))\n286 (sign (git-gutter+-propertized-sign type)))\n287 (case type\n288 ((modified added) (git-gutter+-view-region sign start-line end-line))\n289 (deleted (git-gutter+-view-at-pos\n290 sign (git-gutter+-line-to-pos start-line))))))\n\n292 (defun git-gutter+-sign-width (sign)\n293 (loop for s across sign\n294 sum (char-width s)))\n\n296 (defun git-gutter+-longest-sign-width ()\n297 (let ((signs (list git-gutter+-modified-sign\n298 git-gutter+-added-sign\n299 git-gutter+-deleted-sign)))\n300 (when git-gutter+-unchanged-sign\n301 (add-to-list 'signs git-gutter+-unchanged-sign))\n302 (+ (apply 'max (mapcar 'git-gutter+-sign-width signs))\n303 (git-gutter+-sign-width git-gutter+-separator-sign))))\n\n305 (defun git-gutter+-view-for-unchanged ()\n306 (save-excursion\n307 (let ((sign (if git-gutter+-unchanged-sign\n308 (propertize git-gutter+-unchanged-sign\n309 'face 'git-gutter+-unchanged)\n310 \" \")))\n311 (goto-char (point-min))\n312 (while (not (eobp))\n313 (git-gutter+-view-at-pos sign (point))\n314 (forward-line 1)))))\n\n316 (defun git-gutter+-set-window-margin (width)\n317 (let ((curwin (get-buffer-window)))\n318 (set-window-margins curwin width (cdr (window-margins curwin)))))\n\n320 (defsubst git-gutter+-file-buffer-p ()\n321 (and (buffer-file-name)\n322 default-directory\n323 (file-directory-p default-directory)))\n\n325 ;;;###autoload\n326 (define-minor-mode git-gutter+-mode\n327 \"Git-Gutter mode\"\n328 :group 'git-gutter+\n329 :init-value nil\n330 :global nil\n331 :lighter git-gutter+-lighter\n332 (if git-gutter+-mode\n333 (if (and (git-gutter+-file-buffer-p)\n334 (git-gutter+-in-git-repository-p (buffer-file-name)))\n335 (progn\n336 (git-gutter+-add-local-hooks)\n337 (git-gutter+-refresh))\n338 (if (called-interactively-p 'any)\n339 (message \"No Git repo for current buffer\"))\n340 (git-gutter+-mode -1))\n341 (git-gutter+-remove-local-hooks)\n342 (git-gutter+-clear)))\n\n344 (defun git-gutter+-add-local-hooks ()\n345 (add-hook 'after-save-hook 'git-gutter+-refresh nil t)\n346 ;; Turn off `git-gutter+-mode' while reverting to prevent any redundant calls to\n347 ;; `git-gutter+-refresh'.\n348 (add-hook 'before-revert-hook 'git-gutter+-turn-off nil t)\n349 (add-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change nil t)\n350 (if git-gutter+-window-config-change-function\n351 (add-hook 'window-configuration-change-hook\n352 git-gutter+-window-config-change-function nil t)))\n\n354 (defun git-gutter+-remove-local-hooks ()\n355 (remove-hook 'after-save-hook 'git-gutter+-refresh t)\n356 (remove-hook 'before-revert-hook 'git-gutter+-turn-off t)\n357 (remove-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change t)\n358 (if git-gutter+-window-config-change-function\n359 (remove-hook 'window-configuration-change-hook\n360 git-gutter+-window-config-change-function t)))\n\n362 (defmacro git-gutter+-in-all-buffers (&rest body)\n363 `(dolist (buf (buffer-list))\n364 (with-current-buffer buf\n365 ,@body)))\n\n367 ;; When `define-globalized-minor-mode' is used to define `global-git-gutter+-mode',\n368 ;; `git-gutter+-mode' and thus `git-gutter+-refresh' get run twice when a new file\n369 ;; is opened. (First for `fundamental-mode', then for the file-specific mode.)\n370 ;; The following definition of `global-git-gutter+-mode' avoids any redundant calls to\n371 ;; `git-gutter+-refresh'.\n\n373 ;;;###autoload\n374 (define-minor-mode global-git-gutter+-mode ()\n375 \"Global Git-Gutter mode\"\n376 :group 'git-gutter+\n377 :init-value nil\n378 :global t\n379 (if global-git-gutter+-mode\n380 (progn\n381 (add-hook 'find-file-hook 'git-gutter+-turn-on)\n382 (add-hook 'after-revert-hook 'git-gutter+-turn-on)\n383 (add-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n384 (git-gutter+-in-all-buffers (git-gutter+-turn-on)))\n385 (remove-hook 'find-file-hook 'git-gutter+-turn-on)\n386 (remove-hook 'after-revert-hook 'git-gutter+-turn-on)\n387 (remove-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n388 (git-gutter+-in-all-buffers (git-gutter+-turn-off))))\n\n390 (defun git-gutter+-turn-on ()\n391 (when (and (buffer-file-name)\n392 (not (memq major-mode git-gutter+-disabled-modes))\n393 (not git-gutter+-mode))\n394 (git-gutter+-mode t)))\n\n396 (defun git-gutter+-turn-off ()\n397 (if git-gutter+-mode (git-gutter+-mode -1)))\n\n399 (defun git-gutter+-reenable-after-major-mode-change ()\n400 (if global-git-gutter+-mode\n401 (add-to-list 'git-gutter+-buffers-to-reenable (current-buffer))))\n\n403 (defun git-gutter+-reenable-buffers ()\n404 (dolist (buf git-gutter+-buffers-to-reenable)\n405 (with-current-buffer buf\n406 (git-gutter+-turn-on)))\n407 (setq git-gutter+-buffers-to-reenable nil))\n\n409 (defsubst git-gutter+-show-gutter-p (diffinfos)\n410 (if git-gutter+-hide-gutter\n411 (or diffinfos git-gutter+-unchanged-sign)\n412 (or global-git-gutter+-mode git-gutter+-unchanged-sign diffinfos)))\n\n414 (defun git-gutter+-show-gutter (&optional diffinfos)\n415 (when (git-gutter+-show-gutter-p (or diffinfos git-gutter+-diffinfos))\n416 (let ((win-width (or git-gutter+-window-width\n417 (git-gutter+-longest-sign-width))))\n418 (git-gutter+-set-window-margin win-width))))\n\n420 (defun git-gutter+-view-diff-infos (diffinfos)\n421 (when (or git-gutter+-unchanged-sign\n422 git-gutter+-separator-sign)\n423 (git-gutter+-view-for-unchanged))\n424 (when diffinfos\n425 (save-excursion\n426 (mapc 'git-gutter+-view-diff-info diffinfos)))\n427 (git-gutter+-show-gutter diffinfos))\n\n429 (defsubst git-gutter+-reset-window-margin-p ()\n430 (or git-gutter+-hide-gutter\n431 (not global-git-gutter+-mode)))\n\n433 (defun git-gutter+-clear-diff-infos ()\n434 (when (git-gutter+-reset-window-margin-p)\n435 (git-gutter+-set-window-margin 0))\n436 (remove-overlays (point-min) (point-max) 'git-gutter+ t))\n\n438 (defun git-gutter+-process-diff (curfile)\n439 (destructuring-bind\n440 (diff-header diffinfos) (git-gutter+-diff curfile)\n441 (setq git-gutter+-diff-header diff-header\n442 git-gutter+-diffinfos diffinfos)\n443 (save-restriction\n444 (widen)\n445 (funcall git-gutter+-view-diff-function diffinfos))))\n\n447 (defun git-gutter+-search-near-diff-index (diffinfos is-reverse)\n448 (loop with current-line = (line-number-at-pos)\n449 with cmp-fn = (if is-reverse '> '<)\n450 for diffinfo in (if is-reverse (reverse diffinfos) diffinfos)\n451 for index = 0 then (1+ index)\n452 for start-line = (plist-get diffinfo :start-line)\n453 when (funcall cmp-fn current-line start-line)\n454 return (if is-reverse\n455 (1- (- (length diffinfos) index))\n456 index)))\n\n458 (defun git-gutter+-diffinfo-at-point ()\n459 (save-restriction\n460 (widen)\n461 (loop with current-line = (line-number-at-pos)\n462 for diffinfo in git-gutter+-diffinfos\n463 for start = (plist-get diffinfo :start-line)\n464 for end = (or (plist-get diffinfo :end-line) (1+ start))\n465 when (and (>= current-line start) (<= current-line end))\n466 return diffinfo)))\n\n468 (defun git-gutter+-collect-deleted-line (str)\n469 (with-temp-buffer\n470 (insert str)\n471 (goto-char (point-min))\n472 (loop while (re-search-forward \"^-\\\\(.*?\\\\)$\" nil t)\n473 collect (match-string 1) into deleted-lines\n474 finally return deleted-lines)))\n\n476 (defun git-gutter+-delete-added-lines (start-line end-line)\n477 (forward-line (1- start-line))\n478 (let ((start-point (point)))\n479 (forward-line (1+ (- end-line start-line)))\n480 (delete-region start-point (point))))\n\n482 (defun git-gutter+-insert-deleted-lines (content)\n483 (dolist (line (git-gutter+-collect-deleted-line content))\n484 (insert (concat line \"\\n\"))))\n\n486 (defun git-gutter+-do-revert-hunk (diffinfo)\n487 (save-excursion\n488 (save-restriction\n489 (widen)\n490 (goto-char (point-min))\n491 (let ((start-line (plist-get diffinfo :start-line))\n492 (end-line (plist-get diffinfo :end-line))\n493 (content (plist-get diffinfo :content)))\n494 (case (plist-get diffinfo :type)\n495 (added (git-gutter+-delete-added-lines start-line end-line))\n496 (deleted (forward-line (1- start-line))\n497 (git-gutter+-insert-deleted-lines content))\n498 (modified (git-gutter+-delete-added-lines start-line end-line)\n499 (git-gutter+-insert-deleted-lines content)))))))\n\n501 (defun git-gutter+-revert-hunks ()\n502 \"Revert hunk at point. If region is active, revert all hunks within the region.\"\n503 (interactive)\n504 (let* ((diffinfos (git-gutter+-selected-diffinfos))\n505 (one-diffinfo-p (= 1 (length diffinfos))))\n506 (save-window-excursion\n507 (if one-diffinfo-p (git-gutter+-show-hunk (car diffinfos)))\n508 (when (and diffinfos\n509 (yes-or-no-p (if one-diffinfo-p\n510 \"Revert hunk?\"\n511 (format \"Revert %d hunks?\" (length diffinfos)))))\n512 ;; Revert diffinfos in reverse so that earlier hunks don't invalidate the\n513 ;; line number information of the later hunks.\n514 (dolist (diffinfo (nreverse diffinfos))\n515 (git-gutter+-do-revert-hunk diffinfo))\n516 (save-buffer))\n517 (if one-diffinfo-p\n518 (git-gutter+-awhen (get-buffer git-gutter+-popup-buffer)\n519 (kill-buffer it))))))\n\n521 (defun git-gutter+-show-hunk (&optional diffinfo)\n522 \"Show hunk at point in another window\"\n523 (interactive)\n524 (git-gutter+-awhen (or diffinfo\n525 (git-gutter+-diffinfo-at-point))\n526 (save-selected-window\n527 (with-current-buffer (get-buffer-create git-gutter+-popup-buffer)\n528 (setq buffer-read-only nil)\n529 (erase-buffer)\n530 (insert (plist-get it :content))\n531 (insert \"\\n\")\n532 (goto-char (point-min))\n533 (diff-mode)\n534 (view-mode)\n535 (pop-to-buffer (current-buffer))))))\n\n537 (defun git-gutter+-next-hunk (arg)\n538 \"Move to next diff hunk\"\n539 (interactive \"p\")\n540 (if (not git-gutter+-diffinfos)\n541 (message \"No changes in buffer\")\n542 (save-restriction\n543 (widen)\n544 (let* ((is-reverse (< arg 0))\n545 (diffinfos git-gutter+-diffinfos)\n546 (len (length diffinfos))\n547 (index (git-gutter+-search-near-diff-index diffinfos is-reverse))\n548 (real-index (if index\n549 (let ((next (if is-reverse (1+ index) (1- index))))\n550 (mod (+ arg next) len))\n551 (if is-reverse (1- (length diffinfos)) 0)))\n552 (diffinfo (nth real-index diffinfos)))\n553 (goto-char (point-min))\n554 (forward-line (1- (plist-get diffinfo :start-line)))\n555 (when (buffer-live-p (get-buffer git-gutter+-popup-buffer))\n556 (save-window-excursion\n557 (git-gutter+-show-hunk)))))))\n\n559 (defun git-gutter+-previous-hunk (arg)\n560 \"Move to previous diff hunk\"\n561 (interactive \"p\")\n562 (git-gutter+-next-hunk (- arg)))\n\n564 (defun git-gutter+-remote-default-directory (dir file)\n565 (let* ((vec (tramp-dissect-file-name file))\n566 (method (aref vec 0))\n567 (user (aref vec 1))\n568 (host (aref vec 2)))\n569 (format \"/%s:%s%s:%s\" method (if user (concat user \"@\") \"\") host dir)))\n\n571 (defun git-gutter+-remote-file-path (dir file)\n572 (let ((file (aref (tramp-dissect-file-name file) 3)))\n573 (replace-regexp-in-string (concat \"\\\\`\" dir) \"\" file)))\n\n575 (defun git-gutter+-local-file-path (file)\n576 (if (eq system-type 'windows-nt)\n577 ;; Cygwin can't handle Windows absolute paths\n578 (file-relative-name file default-directory)\n579 file))\n\n581 (defun git-gutter+-refresh ()\n582 (git-gutter+-clear)\n583 (let ((file (buffer-file-name)))\n584 (when (and file (file-exists-p file))\n585 (if (file-remote-p file)\n586 (let* ((repo-root (git-gutter+-root-directory file))\n587 (default-directory (git-gutter+-remote-default-directory repo-root file)))\n588 (git-gutter+-process-diff (git-gutter+-remote-file-path repo-root file)))\n589 (git-gutter+-process-diff (git-gutter+-local-file-path file))))))\n\n591 (defun git-gutter+-clear ()\n592 (save-restriction\n593 (widen)\n594 (funcall git-gutter+-clear-function))\n595 (setq git-gutter+-diffinfos nil))\n\n\n598 ;;; Staging\n\n600 (defun git-gutter+-stage-hunks ()\n601 \"Stage hunk at point. If region is active, stage all hunk lines within the region.\"\n602 (interactive)\n603 (let* ((line-range (if (use-region-p)\n604 (cons (line-number-at-pos (region-beginning))\n605 (line-number-at-pos (region-end)))))\n606 (diffinfos (git-gutter+-selected-diffinfos line-range)))\n607 (when diffinfos\n608 (let ((error-msg (git-gutter+-stage-diffinfos diffinfos line-range)))\n609 (if error-msg\n610 (message \"Error staging hunks:\\n%s\" error-msg))\n611 (git-gutter+-refresh)))))\n\n613 (defun git-gutter+-selected-diffinfos (&optional line-range)\n614 (unless line-range\n615 (setq line-range (if (use-region-p)\n616 (cons (line-number-at-pos (region-beginning))\n617 (line-number-at-pos (region-end))))))\n618 (if line-range\n619 (git-gutter+-diffinfos-between-lines line-range)\n620 (git-gutter+-awhen (git-gutter+-diffinfo-at-point)\n621 (list it))))\n\n623 (defsubst git-gutter+-diffinfo-between-lines-p (diffinfo start-line end-line)\n624 (let ((diff-start (plist-get diffinfo :start-line))\n625 (diff-end (plist-get diffinfo :end-line)))\n626 (and (<= start-line diff-end)\n627 (<= diff-start end-line))))\n\n629 (defun git-gutter+-diffinfos-between-lines (line-range)\n630 (save-restriction\n631 (widen)\n632 (let ((start-line (car line-range))\n633 (end-line (cdr line-range)))\n634 (delq nil\n635 (mapcar (lambda (diffinfo)\n636 (if (git-gutter+-diffinfo-between-lines-p\n637 diffinfo start-line end-line)\n638 diffinfo))\n639 git-gutter+-diffinfos)))))\n\n641 (defun git-gutter+-stage-diffinfos (diffinfos line-range)\n642 (let ((header git-gutter+-diff-header))\n643 (with-temp-buffer\n644 (insert header)\n645 ;; Insert hunks in reverse so that earlier hunks don't invalidate the line\n646 ;; number information of the later hunks.\n647 (dolist (diffinfo (nreverse diffinfos))\n648 (git-gutter+-insert-diffinfo diffinfo line-range)\n649 (goto-char (point-max)))\n650 (git-gutter+-call-git-on-current-buffer\n651 '(\"apply\" \"--unidiff-zero\" \"--cached\" \"-\")))))\n\n653 (defun git-gutter+-insert-diffinfo (diffinfo line-range)\n654 (let ((content (plist-get diffinfo :content))\n655 (type (plist-get diffinfo :type)))\n656 (if (not line-range)\n657 (git-gutter+-insert-hunk content type)\n658 (let ((diff-start-line (plist-get diffinfo :start-line))\n659 (diff-end-line (plist-get diffinfo :end-line))\n660 (start-line (car line-range))\n661 (end-line (cdr line-range)))\n662 (git-gutter+-insert-hunk content type\n663 (1+ (- start-line diff-start-line))\n664 (1+ (- end-line diff-start-line)))))))\n\n666 (defun git-gutter+-call-git-on-current-buffer (args)\n667 \"Sends the current buffer contents to Git and replaces them with Git's output.\n\n669 RETURNS nil if Git ran successfully. Returns an error description otherwise.\"\n670 (unless (zerop (apply #'call-process-region (point-min) (point-max)\n671 git-gutter+-git-executable t t nil args))\n672 (buffer-string)))\n\n674 (defsubst git-gutter+-read-hunk-header (hunk)\n675 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n676 (string-match git-gutter+-hunk-header-regex hunk)\n677 (list (string-to-number (match-string 1 hunk))\n678 (string-to-number (or (match-string 2 hunk) \"1\"))\n679 (string-to-number (match-string 3 hunk))\n680 (string-to-number (or (match-string 4 hunk) \"1\"))))\n\n682 (defun git-gutter+-insert-hunk (hunk type &optional start end)\n683 \"If START and END are provided, only insert addition (+) lines between\n684 START and END (inclusive). START and END are both line numbers starting with 1.\"\n685 (destructuring-bind\n686 (del-line del-len add-line add-len) (git-gutter+-read-hunk-header hunk)\n687 (let* ((start (max 1 (or start 1)))\n688 (end (min add-len (or end add-len)))\n689 (insert-all-p (or (eq type :deleted)\n690 (and (= start 1) (= end add-len))))\n691 (num-lines-selected (if insert-all-p\n692 add-len\n693 (1+ (- end start)))))\n694 ;; When the user selected the last lines of a hunk with type `modified' (but\n695 ;; not the complete hunk), then don't insert any deletion (-) lines from that\n696 ;; hunk.\n697 (if (and (eq type 'modified)\n698 (> start 1) (= end add-len))\n699 (setq type 'modified-trailing))\n\n701 (save-excursion\n702 (insert hunk \"\\n\"))\n\n704 (git-gutter+-delete-hunk-header)\n\n706 (if (not insert-all-p)\n707 (git-gutter+-modify-hunk type num-lines-selected del-len start))\n\n709 (let ((hunk-header (git-gutter+-make-hunk-header type num-lines-selected\n710 del-line del-len add-line)))\n711 (insert hunk-header \"\\n\")))))\n\n713 (defun git-gutter+-delete-hunk-header ()\n714 (let ((hunk-start (point)))\n715 (forward-line 1)\n716 (delete-region hunk-start (point))))\n\n718 (defun git-gutter+-modify-hunk (type num-lines-selected del-len start)\n719 \"Remove all addition (+) lines from hunk that aren't selected.\n720 If TYPE is not `modified', also remove all deletion (-) lines.\"\n721 (let ((first-line-selected (+ del-len (1- start)))\n722 selected-lines)\n723 (save-excursion\n724 (forward-line first-line-selected)\n725 (let ((selection-start (point)))\n726 (forward-line num-lines-selected)\n727 (setq selected-lines (buffer-substring selection-start (point)))))\n728 (save-excursion\n729 (if (eq type 'modified) (forward-line del-len)) ; skip over deletion (-) lines\n730 (delete-region (point) (point-max))\n731 (insert selected-lines))))\n\n733 (defun git-gutter+-make-hunk-header (type num-lines-selected del-line del-len add-line)\n734 (let ((add-len num-lines-selected))\n735 (case type\n736 (added (setq add-line (1+ del-line)))\n737 (modified-trailing (setq add-line (+ del-line del-len)\n738 del-line (1- add-line)\n739 del-len 0))\n740 (t (setq add-line del-line)))\n741 (format \"@@ -%d,%d +%d,%d @@\"\n742 del-line del-len\n743 add-line add-len)))\n\n\n746 ;;; Committing\n747 ;; This section draws heavily from old Magit source code.\n\n749 (defvar git-gutter+-pre-commit-window-config nil)\n750 (defvar git-gutter+-commit-origin-buffer nil\n751 \"Buffer that started the commit\")\n\n753 (defconst git-gutter+-commit-buffer-name \"*Commit Message*\")\n754 (defconst git-gutter+-staged-changes-buffer-name \"*Staged Changes*\")\n\n756 ;;;###autoload\n757 (defun git-gutter+-commit ()\n758 \"Commit staged changes. If nothing is staged, ask to stage the current buffer.\"\n759 (interactive)\n\n761 (when (and (not (git-gutter+-anything-staged-p))\n762 git-gutter+-diffinfos\n763 (y-or-n-p \"Nothing staged. Stage current buffer? \"))\n764 (git-gutter+-stage-whole-buffer))\n\n766 (let ((file (buffer-file-name))\n767 (dir default-directory))\n768 (git-gutter+-save-window-config-if-needed)\n769 (setq git-gutter+-commit-origin-buffer (current-buffer))\n770 (git-gutter+-open-commit-edit-buffer dir)\n771 (git-gutter+-show-staged-changes file dir)))\n\n773 (defun git-gutter+-stage-and-commit ()\n774 (interactive)\n775 (git-gutter+-stage-hunks)\n776 (git-gutter+-commit))\n\n778 (defun git-gutter+-save-window-config-if-needed ()\n779 ;; Only save the window config if the temporary buffers that get popped-up by\n780 ;; git-gutter+ are not already visible.\n781 ;; In this way, `git-gutter+-commit' can be called twice in a row without\n782 ;; losing the original window config.\n783 (when (not (and git-gutter+-pre-commit-window-config\n784 (get-buffer-window git-gutter+-commit-buffer-name)\n785 (get-buffer-window git-gutter+-staged-changes-buffer-name)))\n786 (setq git-gutter+-pre-commit-window-config (current-window-configuration))))\n\n788 (defun git-gutter+-open-commit-edit-buffer (dir)\n789 \"Opens a buffer for composing the commit message\"\n790 (pop-to-buffer (get-buffer-create git-gutter+-commit-buffer-name))\n791 (setq default-directory dir)\n792 (git-gutter+-commit-mode)\n793 (message \"Type C-c C-c to commit (C-c C-k to cancel).\"))\n\n795 (defsubst git-gutter+-pop-to-staged-changes-buffer ()\n796 (let* ((buf (get-buffer-create git-gutter+-staged-changes-buffer-name))\n797 (window (get-buffer-window buf)))\n798 (if window\n799 ;; Buffer is already visible\n800 (select-window window)\n801 (if (<= (length (window-list)) 2)\n802 (split-window))\n803 (pop-to-buffer buf))))\n\n805 (defun git-gutter+-show-staged-changes (file dir)\n806 (save-selected-window\n807 (git-gutter+-pop-to-staged-changes-buffer)\n808 (setq buffer-read-only nil)\n809 (erase-buffer)\n810 (let ((default-directory dir))\n811 (git-gutter+-call-git '(\"diff\" \"--staged\") file))\n812 (goto-char (point-min))\n813 (diff-mode)\n814 (view-mode)))\n\n816 (defsubst git-gutter+-abort-commit-when-no-changes (allow-empty amend)\n817 (unless (or amend\n818 allow-empty\n819 (git-gutter+-anything-staged-p))\n820 (error\n821 \"Refusing to create empty commit. Maybe you want to amend (%s) or allow-empty (%s)?\"\n822 (key-description (car (where-is-internal\n823 'git-gutter+-commit-toggle-amending)))\n824 (key-description (car (where-is-internal\n825 'git-gutter+-commit-toggle-allow-empty))))))\n\n827 (defsubst git-gutter+-buffer-is-whitespace ()\n828 (save-excursion\n829 (goto-char (point-min))\n830 (looking-at-p \"[ \\t\\n]*\\\\'\")))\n\n832 (defun git-gutter+-publish-commit ()\n833 \"Publish commit\"\n834 (interactive)\n835 (let* ((fields (git-gutter+-commit-get-fields))\n836 (amend (equal \"yes\" (git-gutter+-commit-get-field 'amend fields)))\n837 (allow-empty (equal \"yes\" (git-gutter+-commit-get-field 'allow-empty fields)))\n838 (author (git-gutter+-commit-get-field 'author fields))\n839 (date (git-gutter+-commit-get-field 'date fields)))\n\n841 (git-gutter+-abort-commit-when-no-changes allow-empty amend)\n\n843 (git-gutter+-push-to-comment-ring (buffer-string))\n\n845 (git-gutter+-commit-set-fields nil) ; Delete message header\n\n847 (when (git-gutter+-buffer-is-whitespace)\n848 (erase-buffer)\n849 (insert \"(Empty description)\"))\n\n851 (let ((error-msg (git-gutter+-call-git-on-current-buffer\n852 (append '(\"--no-pager\" \"commit\" \"-F\" \"-\")\n853 (if amend '(\"--amend\"))\n854 (if allow-empty '(\"--allow-empty\"))\n855 (if author (list (concat \"--author=\" author)))\n856 (if date (list (concat \"--date=\" date)))))))\n857 (if error-msg\n858 (progn\n859 (message \"Commit error:\\n%s\" error-msg)\n860 (erase-buffer)\n861 (insert (ring-ref log-edit-comment-ring 0))) ; Reinsert commit message\n862 (message \"Commit successful.\")\n863 (git-gutter+-close-commit-edit-buffer)\n864 (git-gutter+-update-vc-modeline)))))\n\n866 (defun git-gutter+-close-commit-edit-buffer ()\n867 \"Abort edits and discard commit message being composed.\"\n868 (interactive)\n869 (kill-buffer)\n870 (set-window-configuration git-gutter+-pre-commit-window-config))\n\n872 (defun git-gutter+-update-vc-modeline ()\n873 (when (buffer-live-p git-gutter+-commit-origin-buffer)\n874 (with-current-buffer git-gutter+-commit-origin-buffer\n875 ;; Updating the modeline has no effect if the buffer still has\n876 ;; changes - it will remain in the 'modified' state. So skip it then.\n877 (unless git-gutter+-diffinfos\n878 (ignore-errors (vc-find-file-hook))))))\n\n880 (defun git-gutter+-stage-whole-buffer ()\n881 (save-excursion\n882 (mark-whole-buffer)\n883 (git-gutter+-stage-hunks)))\n\n885 (defun git-gutter+-anything-staged-p ()\n886 \"Return t if the current repo has staged changes\"\n887 (not (zerop (git-gutter+-call-git '(\"diff\" \"--quiet\" \"--cached\")))))\n\n889 (defun git-gutter+-commit-toggle-amending ()\n890 \"Toggle whether this will be an amendment to the previous commit.\n891 \\(i.e., whether commit is run via 'git commit --amend')\"\n892 (interactive)\n893 ;; Remove the newline that 'git-commit-mode' adds to a new commit\n894 ;; message buffer by default. This prevents an ugly visual\n895 ;; gap between the commit message header and the previous commit\n896 ;; message.\n897 (when (git-gutter+-buffer-is-whitespace)\n898 (erase-buffer))\n\n900 (let ((amend-was-already-set (git-gutter+-commit-get-field 'amend)))\n901 (git-gutter+-commit-toggle-field 'amend t)\n902 (unless amend-was-already-set\n903 ;; Insert previous commit message\n904 (goto-char (point-max))\n905 (unless (zerop (current-column))\n906 (insert \"\\n\"))\n907 (insert (git-gutter+-get-last-commit-msg)\n908 \"\\n\"))))\n\n910 (defun git-gutter+-commit-toggle-allow-empty ()\n911 \"Toggle whether this commit is allowed to be empty.\n912 \\(i.e., whether commit is run via 'git commit --allow-empty')\"\n913 (interactive)\n914 (git-gutter+-commit-toggle-field 'allow-empty t))\n\n916 (defun git-gutter+-format-author (author email)\n917 (format \"%s <%s>\" author email))\n\n919 (defun git-gutter+-commit-toggle-author ()\n920 \"Toggle whether this commit should have a user-defined author.\"\n921 (interactive)\n922 (git-gutter+-commit-toggle-input\n923 'author (git-gutter+-format-author\n924 (or (git-gutter+-get-cfg \"user\" \"name\") \"Author Name\")\n925 (or (git-gutter+-get-cfg \"user\" \"email\") \"author@email\"))))\n\n927 (defun git-gutter+-commit-toggle-date ()\n928 \"Toggle whether this commit should have a user-defined date.\"\n929 (interactive)\n930 (git-gutter+-commit-toggle-input 'date\n931 ;; ISO 8601\n932 (format-time-string \"%Y-%m-%dT%T%z\" (current-time))))\n\n934 (defun git-gutter+-push-to-comment-ring (comment)\n935 (when (or (ring-empty-p log-edit-comment-ring)\n936 (not (equal comment (ring-ref log-edit-comment-ring 0))))\n937 (ring-insert log-edit-comment-ring comment)))\n\n939 (defun git-gutter+-get-last-commit-msg ()\n940 (git-gutter+-git-output '(\"log\" \"--max-count=1\" \"--pretty=format:%s%n%n%b\" \"HEAD\")))\n\n942 (defun git-gutter+-get-cfg (&rest keys)\n943 (git-gutter+-git-output (list \"config\" (mapconcat 'identity keys \".\"))))\n\n945 (defun git-gutter+-git-output (args)\n946 (with-temp-buffer\n947 (git-gutter+-call-git args)\n948 ;; Delete trailing newlines\n949 (goto-char (point-min))\n950 (if (re-search-forward \"\\n+\\\\'\" nil t)\n951 (replace-match \"\"))\n952 (buffer-string)))\n\n\n955 ;;; Commit message header\n\n957 (defconst git-gutter+-commit-header-end \"-- End of commit options header --\\n\")\n\n959 (defun git-gutter+-commit-get-field (name &optional fields)\n960 (cdr (assq name (or fields (git-gutter+-commit-get-fields)))))\n\n962 (defun git-gutter+-commit-set-field (name value)\n963 (let* ((fields (git-gutter+-commit-get-fields))\n964 (cell (assq name fields)))\n965 (cond (cell\n966 (if value\n967 (rplacd cell value)\n968 (setq fields (delq cell fields))))\n969 (t\n970 (if value\n971 (setq fields (append fields (list (cons name value)))))))\n972 (git-gutter+-commit-set-fields fields)))\n\n974 (defun git-gutter+-commit-toggle-field (name default)\n975 \"Toggle the commit header field named NAME.\n976 If it's currently unset, set it to DEFAULT (t or nil).\"\n977 (let* ((fields (git-gutter+-commit-get-fields))\n978 (cell (assq name fields)))\n979 (if cell\n980 (rplacd cell (if (equal (cdr cell) \"yes\") \"no\" \"yes\"))\n981 (setq fields (acons name (if default \"yes\" \"no\") fields)))\n982 (git-gutter+-commit-set-fields fields)))\n\n984 (defun git-gutter+-commit-toggle-input (name default)\n985 \"Toggle the commit header input named NAME.\n986 If it's currently unset, set it to DEFAULT (a string). If it is\n987 set remove it.\"\n988 (let* ((fields (git-gutter+-commit-get-fields))\n989 (cell (assq name fields)))\n990 (if cell\n991 (setq fields (assq-delete-all name fields))\n992 (setq fields (acons name default fields)))\n993 (git-gutter+-commit-set-fields fields)))\n\n995 (defun git-gutter+-commit-get-fields ()\n996 (let (result)\n997 (goto-char (point-min))\n998 (while (looking-at \"^\\\\([A-Za-z0-9-_]+\\\\): *\\\\(.+\\\\)?$\")\n999 (let ((name (intern (downcase (match-string 1))))\n1000 (value (read (or (match-string 2) \"nil\"))))\n1001 (push (cons name value) result))\n1002 (forward-line))\n1003 (if (looking-at (regexp-quote git-gutter+-commit-header-end))\n1004 (nreverse result))))\n\n1006 (defun git-gutter+-commit-set-fields (fields)\n1007 (goto-char (point-min))\n1008 ;; Delete commit header\n1009 (if (search-forward-regexp (format \"^\\\\(?:[A-Za-z0-9-_]+:.*\\n\\\\)*%s\"\n1010 (regexp-quote git-gutter+-commit-header-end))\n1011 nil t)\n1012 (delete-region (match-beginning 0) (match-end 0)))\n1013 (goto-char (point-min))\n1014 (when fields\n1015 (dolist (field fields)\n1016 (insert (capitalize (symbol-name (car field))) \": \"\n1017 (prin1-to-string (cdr field)) \"\\n\"))\n1018 (insert git-gutter+-commit-header-end)))\n\n\n1021 ;;; git-gutter+-commit-mode\n1022 ;; Like git-commit-mode, but adds keybindings to git-gutter+ commands and\n1023 ;; highlighting support for the commit message header.\n\n1025 (define-derived-mode git-gutter+-commit-mode git-commit-mode \"Git-Gutter-Commit\"\n1026 (setq font-lock-defaults (list (git-gutter+-commit-font-lock-keywords) t)))\n\n1028 (setq git-gutter+-commit-mode-map\n1029 (let ((map (copy-keymap git-commit-mode-map)))\n1030 (define-key map (kbd \"C-c C-c\") 'git-gutter+-publish-commit)\n1031 (define-key map (kbd \"C-c C-k\") 'git-gutter+-close-commit-edit-buffer)\n1032 (define-key map (kbd \"C-c C-a\") 'git-gutter+-commit-toggle-amending)\n1033 (define-key map (kbd \"C-c C-e\") 'git-gutter+-commit-toggle-allow-empty)\n1034 (define-key map (kbd \"C-c C-u\") 'git-gutter+-commit-toggle-author)\n1035 (define-key map (kbd \"C-c C-d\") 'git-gutter+-commit-toggle-date)\n1036 (define-key map (kbd \"C-c C-b\") 'git-commit-ack)\n1037 (define-key map (kbd \"M-p\") 'log-edit-previous-comment)\n1038 (define-key map (kbd \"M-n\") 'log-edit-next-comment)\n1039 map))\n\n1041 (defface git-gutter+-commit-header-face\n1042 '((t :inherit font-lock-comment-face))\n1043 \"Highlights the commit message header\"\n1044 :group 'git-gutter+-faces)\n\n1046 (defconst git-gutter+-commit-header-regex\n1047 (concat \"\\\\(?:.\\\\|\\n\\\\)*?\" (regexp-quote git-gutter+-commit-header-end)))\n\n1049 (defconst git-gutter+-skip-commit-header-regex\n1050 (concat \"\\\\`\\\\(?:\" git-gutter+-commit-header-regex \"\\\\)?\"))\n\n1052 ;; Modify git-commit-summary-regexp to ignore the commit header\n1053 (defadvice git-commit-summary-regexp\n1054 (after ignore-git-gutter+-commit-header activate compile)\n1055 (if (eq major-mode 'git-gutter+-commit-mode)\n1056 (setq ad-return-value\n1057 (concat git-gutter+-skip-commit-header-regex\n1058 (substring ; Remove leading \"\\\\`\"\n1059 ad-return-value 2)))))\n\n1061 (defun git-gutter+-commit-font-lock-keywords ()\n1062 \"Like `git-commit-mode-font-lock-keywords' but with commit header highlighting\"\n1063 `((,(concat \"\\\\`\" git-gutter+-commit-header-regex) . 'git-gutter+-commit-header-face)\n1064 ,@(git-commit-mode-font-lock-keywords)))\n\n\n1067 ;;; Magit synchronization\n1068 ;; Force Magit to refresh git-gutter+ when updating the VC mode line.\n\n1070 (defvar git-gutter+-orig-vc-find-file-hook)\n\n1072 (defvar git-gutter+-vc-find-file-hook-with-refresh\n1073 (lambda ()\n1074 (funcall git-gutter+-orig-vc-find-file-hook)\n1075 (if git-gutter+-mode (git-gutter+-refresh))))\n\n1077 (defadvice magit-update-vc-modeline (around refresh-git-gutter+ compile activate)\n1078 ;; `magit-update-vc-modeline' calls `vc-find-file-hook' (a function!) on each\n1079 ;; buffer in the repo. Temporarily rebind it to `vc-find-file-hook-with-refresh',\n1080 ;; which calls git-gutter+-refresh after updating the VC mode line.\n1081 ;;\n1082 ;; Using `flet' would have been much simpler, but it's deprecated since 24.3.\n1083 (setq git-gutter+-orig-vc-find-file-hook (symbol-function 'vc-find-file-hook))\n1084 (fset 'vc-find-file-hook git-gutter+-vc-find-file-hook-with-refresh)\n1085 (unwind-protect\n1086 ad-do-it\n1087 (fset 'vc-find-file-hook git-gutter+-orig-vc-find-file-hook)))\n\n1089 (provide 'git-gutter+)\n\n1091 ;;; git-gutter+.el ends here\n")) (setq helm-swoop-cache t))) (candidates-in-buffer) (get-line . buffer-substring-no-properties) (keymap keymap (C-M-left . backward-sexp) (C-M-right . forward-sexp) (27 keymap (105 . helm-multi-swoop-all-from-helm-swoop)) (3 keymap (5 . helm-swoop-edit)) keymap (C-M-left . paren-backward-sexp) (C-M-right . paren-forward-sexp) (94 . helm-swoop-caret-match) (menu-bar keymap (help-menu keymap (describe keymap (describe-mode . helm-help)))) (help keymap (109 . helm-help)) (f1 keymap (109 . helm-help)) (8 keymap (109 . helm-help) (104 . undefined) (8 . undefined) (4 . helm-debug-output)) (20 . helm-toggle-resplit-and-swap-windows) (C-tab . undefined) (triple-mouse-3 . ignore) (double-mouse-3 . ignore) (mouse-3 . ignore) (drag-mouse-3 . ignore) (down-mouse-3 . ignore) (triple-mouse-2 . ignore) (double-mouse-2 . ignore) (mouse-2 . ignore) (drag-mouse-2 . ignore) (down-mouse-2 . ignore) (triple-mouse-1 . ignore) (double-mouse-1 . ignore) (mouse-1 . ignore) (drag-mouse-1 . ignore) (down-mouse-1 . ignore) (67108897 . helm-toggle-suspend-update) (3 keymap (21 . helm-force-update) (6 . helm-follow-mode) (11 . helm-kill-selection-and-quit) (25 . helm-yank-selection) (4 . helm-delete-current-selection) (45 . helm-swap-windows)) (67108987 . helm-enlarge-window) (67108989 . helm-narrow-window) (19 . undefined) (18 . undefined) (23 . helm-yank-text-at-point) (24 keymap (2 . helm-resume-list-buffers-after-quit) (98 . helm-resume-previous-session-after-quit) (6 . helm-quit-and-find-file)) (11 . helm-delete-minibuffer-contents) (67108896 . helm-toggle-visible-mark) (0 . helm-toggle-visible-mark) (C-M-up . helm-scroll-other-window-down) (C-M-down . helm-scroll-other-window) (M-prior . helm-scroll-other-window-down) (M-next . helm-scroll-other-window) (12 . helm-recenter-top-bottom-other-window) (15 . helm-next-source) (10 . helm-select-3rd-action) (5 . helm-select-2nd-action-or-end-of-line) ...) (header-line . "[C-c C-e] Edit mode, [M-i] apply all buffers") (action lambda ($line) (helm-swoop--goto-line (when (string-match "^[0-9]+" $line) (string-to-number (match-string 0 $line)))) (when (re-search-forward (mapconcat (quote identity) (split-string helm-pattern " ") "\\|") nil t) (goto-char (match-beginning 0))) (helm-swoop--recenter)) (migemo)) #("git-gutter+-refresh" 0 19 (fontified t face whitespace-line)) "Swoop: " nil "^368 " "*Helm Swoop*" nil nil nil helm-log "[Start session] " make-string 41 43 t helm-normalize-sources nil cua-mode -1 funcall make-byte-code 0 "\300\305\211\301\203\306\307!\210\310 \207" vconcat vector [overriding-local-map helm-alive-p helm-in-file-completion-p nil cua-mode 1 helm-log-save-maybe] 3 "\n\n(fn)" err "\312\211\211\211\305\206\n(()*+,\313\314-\"\315\316\317\320\321\322!\323\"\324\325%DC\216\326\303\301\307\300$\210\327(!\210\330\331!\210\315\332DC\216\333\302\301\304\303\306\307\310\205P\3109\205P\310&\210*\210)?\205r\334\335\316\317\336\321\322\311!\337\"\340\325%\"\210\341\342\335\"\210\343 \330\344\345\346\347\"P!\210-\207" [nil mapcar #[257 "\211JB\207" [] 3 "\n\n(fn V)"] funcall make-byte-code 0 "\300\301\211:\203@\262\211A\262@\262\211L\210A\262\202\266\302\303!\207" vconcat vector [nil helm-log "restore variables"] 5 "\n\n(fn)" helm-initialize helm-display-buffer helm-log "show prompt" #[0 "\300 \207" [helm-cleanup] 1 "\n\n(fn)"] helm-read-pattern-maybe defalias helm-hook51420 "\302\303DC\216\300\211)\207" [overriding-local-map funcall #[0 "\300\301\302\"\207" [remove-hook helm-cleanup-hook helm-hook51420] 3 "\n\n(fn)"]] 2 add-hook helm-cleanup-hook helm-execute-selection-action "[End session] " make-string 41 45 helm-buffer helm-quit helm-in-persistent-action helm-current-source helm-source-name helm-restored-variables] 9 quit #[257 "\300 \210\301\302\303\304\305\"P!\210\306\207" [helm-restore-position-on-quit helm-log "[End session (quit)] " make-string 34 45 nil] 6 "\n\n(fn V)"] overriding-local-map helm-maybe-use-default-as-input helm-sources-using-default-as-input non-essential cursor-in-echo-area] 21 "\n\n(fn)"])
helm-internal(((name . "git-gutter+.el") (init lambda nil (unless helm-swoop-cache (with-current-buffer (helm-candidate-buffer (quote local)) (insert "1 ;;; git-gutter+.el --- Manage Git hunks straight from the buffer\n\n3 ;; Copyright (C) 2013 by Syohei YOSHIDA and contributors\n\n5 ;; Author: Syohei YOSHIDA <syohex@gmail.com> and contributors\n6 ;; URL: https://github.com/nonsequitur/git-gutter-plus\n7 ;; Version: 0.1\n\n9 ;; This program is free software; you can redistribute it and/or modify\n10 ;; it under the terms of the GNU General Public License as published by\n11 ;; the Free Software Foundation, either version 3 of the License, or\n12 ;; (at your option) any later version.\n\n14 ;; This program is distributed in the hope that it will be useful,\n15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of\n16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n17 ;; GNU General Public License for more details.\n\n19 ;; You should have received a copy of the GNU General Public License\n20 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n22 ;; Package-Requires: ((git-commit-mode \"0.14\"))\n\n24 ;;; Commentary:\n25 ;;\n26 ;; View, stage and revert Git changes straight from the buffer.\n\n28 ;;; Code:\n\n30 (eval-when-compile\n31 (require 'cl))\n\n33 (require 'tramp)\n34 (require 'log-edit)\n35 (require 'git-commit-mode)\n\n37 (defgroup git-gutter+ nil\n38 \"Manage Git hunks straight from the buffer\"\n39 :prefix \"git-gutter+-\"\n40 :group 'vc)\n\n42 (defcustom git-gutter+-window-width nil\n43 \"Character width of the gutter margin. Set this variable if the automatically\n44 calculated width looks wrong. (This can happen with some special characters.)\"\n45 :type 'integer\n46 :group 'git-gutter+)\n\n48 (defcustom git-gutter+-git-executable \"git\"\n49 \"The path of the Git executable.\"\n50 :type 'string\n51 :group 'git-gutter+)\n\n53 (defcustom git-gutter+-diff-options nil\n54 \"List of strings containing extra arguments to 'git diff'\"\n55 :type 'list\n56 :group 'git-gutter+)\n\n58 (defcustom git-gutter+-separator-sign nil\n59 \"Separator sign\"\n60 :type 'string\n61 :group 'git-gutter+)\n\n63 (defcustom git-gutter+-modified-sign \"=\"\n64 \"Modified sign\"\n65 :type 'string\n66 :group 'git-gutter+)\n\n68 (defcustom git-gutter+-added-sign \"+\"\n69 \"Added sign\"\n70 :type 'string\n71 :group 'git-gutter+)\n\n73 (defcustom git-gutter+-deleted-sign \"-\"\n74 \"Deleted sign\"\n75 :type 'string\n76 :group 'git-gutter+)\n\n78 (defcustom git-gutter+-unchanged-sign nil\n79 \"Unchanged sign\"\n80 :type 'string\n81 :group 'git-gutter+)\n\n83 (defcustom git-gutter+-hide-gutter nil\n84 \"Hide gutter if there are no changes\"\n85 :type 'boolean\n86 :group 'git-gutter+)\n\n88 (defcustom git-gutter+-lighter \" GitGutter\"\n89 \"Minor mode lighter in mode-line\"\n90 :type 'string\n91 :group 'git-gutter+)\n\n93 (defface git-gutter+-separator\n94 '((t (:foreground \"cyan\" :weight bold)))\n95 \"Face of the separator\"\n96 :group 'git-gutter+)\n\n98 (defface git-gutter+-modified\n99 '((t (:foreground \"magenta\" :weight bold)))\n100 \"Face for modified lines\"\n101 :group 'git-gutter+)\n\n103 (defface git-gutter+-added\n104 '((t (:foreground \"green\" :weight bold)))\n105 \"Face for added lines\"\n106 :group 'git-gutter+)\n\n108 (defface git-gutter+-deleted\n109 '((t (:foreground \"red\" :weight bold)))\n110 \"Face for deleted lines\"\n111 :group 'git-gutter+)\n\n113 (defface git-gutter+-unchanged\n114 '((t (:background \"yellow\")))\n115 \"Face for unchanged lines\"\n116 :group 'git-gutter+)\n\n118 (defcustom git-gutter+-disabled-modes nil\n119 \"A list of modes for which `global-git-gutter+-mode' should be disabled.\"\n120 :type '(repeat symbol)\n121 :group 'git-gutter+)\n\n123 (defvar git-gutter+-mode-map\n124 (make-sparse-keymap))\n\n126 (defvar git-gutter+-view-diff-function nil\n127 \"Function to call for displaying diffs\")\n\n129 (defvar git-gutter+-clear-function nil\n130 \"Function to call for clearing the diff display\")\n\n132 (defvar git-gutter+-window-config-change-function nil\n133 \"Function to call when the buffer's local window configuration has changed\")\n\n135 (defvar git-gutter+-diffinfos nil)\n136 (defvar git-gutter+-diff-header nil)\n137 (make-variable-buffer-local 'git-gutter+-diffinfos)\n138 (make-variable-buffer-local 'git-gutter+-diff-header)\n\n140 (defvar git-gutter+-popup-buffer \"*git-gutter+-diff*\")\n141 (defvar git-gutter+-buffers-to-reenable nil)\n\n143 (defconst git-gutter+-hunk-header-regex\n144 ;; The same as diff-hunk-header-re-unified\n145 \"^@@ -\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? \\\\+\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? @@\")\n\n147 (defalias 'git-gutter+-popup-hunk 'git-gutter+-show-hunk)\n148 (defalias 'git-gutter+-revert-hunk 'git-gutter+-revert-hunks)\n\n150 (defmacro git-gutter+-awhen (test &rest body)\n151 \"Anaphoric when.\"\n152 (declare (indent 1))\n153 `(let ((it ,test))\n154 (when it ,@body)))\n\n156 (defun git-gutter+-enable-default-display-mode ()\n157 (setq git-gutter+-view-diff-function 'git-gutter+-view-diff-infos\n158 git-gutter+-clear-function 'git-gutter+-clear-diff-infos\n159 git-gutter+-window-config-change-function 'git-gutter+-show-gutter))\n\n161 (unless git-gutter+-view-diff-function\n162 (git-gutter+-enable-default-display-mode))\n\n164 (defun git-gutter+-call-git (args &optional file)\n165 (if (and file (file-remote-p file))\n166 (apply #'process-file git-gutter+-git-executable nil t nil args)\n167 (apply #'call-process git-gutter+-git-executable nil t nil args)))\n\n169 (defun git-gutter+-in-git-repository-p (file)\n170 (with-temp-buffer\n171 (let ((args '(\"rev-parse\" \"--is-inside-work-tree\")))\n172 (when (zerop (git-gutter+-call-git args file))\n173 (goto-char (point-min))\n174 (string= \"true\" (buffer-substring-no-properties\n175 (point) (line-end-position)))))))\n\n177 (defun git-gutter+-root-directory (file)\n178 (with-temp-buffer\n179 (let* ((args '(\"rev-parse\" \"--show-toplevel\"))\n180 (ret (git-gutter+-call-git args file)))\n181 (when (zerop ret)\n182 (goto-char (point-min))\n183 (let ((root (buffer-substring-no-properties (point) (line-end-position))))\n184 (unless (string= root \"\")\n185 (file-name-as-directory root)))))))\n\n187 (defsubst git-gutter+-diff-args (file)\n188 (delq nil (list \"--no-pager\" \"diff\" \"--no-color\" \"--no-ext-diff\" \"-U0\"\n189 git-gutter+-diff-options file)))\n\n191 (defun git-gutter+-diff (curfile)\n192 (let ((args (git-gutter+-diff-args curfile))\n193 (file (buffer-file-name))) ;; for tramp\n194 (with-temp-buffer\n195 (when (zerop (git-gutter+-call-git args file))\n196 (goto-char (point-min))\n197 (let ((diff-header (git-gutter+-get-diff-header))\n198 (diffinfos (git-gutter+-get-diffinfos)))\n199 (list diff-header diffinfos))))))\n\n201 (defun git-gutter+-get-diff-header ()\n202 (save-excursion\n203 (if (re-search-forward git-gutter+-hunk-header-regex nil t)\n204 (buffer-substring (point-min) (match-beginning 0)))))\n\n206 (defsubst git-gutter+-make-diffinfo (type content start end)\n207 (list :type type :content content :start-line start :end-line end))\n\n209 (defun git-gutter+-get-diffinfos ()\n210 (loop while (re-search-forward git-gutter+-hunk-header-regex nil t)\n211 ;; Hunk header format:\n212 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n213 for del-len = (string-to-number (or (match-string 2) \"1\"))\n214 for add-line = (string-to-number (match-string 3))\n215 for add-len = (string-to-number (or (match-string 4) \"1\"))\n216 for type = (cond ((zerop del-len) 'added)\n217 ((zerop add-len) 'deleted)\n218 (t 'modified))\n219 for start-line = (if (eq type 'deleted)\n220 (1+ add-line)\n221 add-line)\n222 for end-line = (if (eq type 'deleted)\n223 start-line\n224 (1- (+ add-line add-len)))\n225 for content = (git-gutter+-diff-content)\n226 collect\n227 (git-gutter+-make-diffinfo type content start-line end-line)))\n\n229 (defun git-gutter+-diff-content ()\n230 (save-excursion\n231 (goto-char (line-beginning-position)) ; Move to beginning of hunk header\n232 (let ((hunk-start (point)))\n233 ;; Move to end of hunk\n234 (forward-line 1)\n235 (if (re-search-forward \"^@@\" nil t)\n236 (backward-char 3) ;; exclude \"\\n@@\"\n237 (goto-char (1- (point-max)))) ; Skip trailing newline\n238 (buffer-substring hunk-start (point)))))\n\n240 (defun git-gutter+-line-to-pos (line)\n241 (save-excursion\n242 (goto-char (point-min))\n243 (forward-line (1- line))\n244 (point)))\n\n246 (defun git-gutter+-before-string (sign)\n247 (let* ((sep-sign git-gutter+-separator-sign)\n248 (sep (when sep-sign\n249 (propertize sep-sign 'face 'git-gutter+-separator)))\n250 (gutter-sep (concat sign sep)))\n251 (propertize \" \" 'display `((margin left-margin) ,gutter-sep))))\n\n253 (defsubst git-gutter+-select-face (type)\n254 (case type\n255 (added 'git-gutter+-added)\n256 (modified 'git-gutter+-modified)\n257 (deleted 'git-gutter+-deleted)))\n\n259 (defsubst git-gutter+-select-sign (type)\n260 (case type\n261 (added git-gutter+-added-sign)\n262 (modified git-gutter+-modified-sign)\n263 (deleted git-gutter+-deleted-sign)))\n\n265 (defun git-gutter+-propertized-sign (type)\n266 (let ((sign (git-gutter+-select-sign type))\n267 (face (git-gutter+-select-face type)))\n268 (propertize sign 'face face)))\n\n270 (defun git-gutter+-view-region (sign start-line end-line)\n271 (let ((beg (git-gutter+-line-to-pos start-line)))\n272 (goto-char beg)\n273 (while (and (<= (line-number-at-pos) end-line) (not (eobp)))\n274 (git-gutter+-view-at-pos sign (point))\n275 (forward-line 1))))\n\n277 (defun git-gutter+-view-at-pos (sign pos)\n278 (let ((ov (make-overlay pos pos)))\n279 (overlay-put ov 'before-string (git-gutter+-before-string sign))\n280 (overlay-put ov 'git-gutter+ t)))\n\n282 (defun git-gutter+-view-diff-info (diffinfo)\n283 (let* ((start-line (plist-get diffinfo :start-line))\n284 (end-line (plist-get diffinfo :end-line))\n285 (type (plist-get diffinfo :type))\n286 (sign (git-gutter+-propertized-sign type)))\n287 (case type\n288 ((modified added) (git-gutter+-view-region sign start-line end-line))\n289 (deleted (git-gutter+-view-at-pos\n290 sign (git-gutter+-line-to-pos start-line))))))\n\n292 (defun git-gutter+-sign-width (sign)\n293 (loop for s across sign\n294 sum (char-width s)))\n\n296 (defun git-gutter+-longest-sign-width ()\n297 (let ((signs (list git-gutter+-modified-sign\n298 git-gutter+-added-sign\n299 git-gutter+-deleted-sign)))\n300 (when git-gutter+-unchanged-sign\n301 (add-to-list 'signs git-gutter+-unchanged-sign))\n302 (+ (apply 'max (mapcar 'git-gutter+-sign-width signs))\n303 (git-gutter+-sign-width git-gutter+-separator-sign))))\n\n305 (defun git-gutter+-view-for-unchanged ()\n306 (save-excursion\n307 (let ((sign (if git-gutter+-unchanged-sign\n308 (propertize git-gutter+-unchanged-sign\n309 'face 'git-gutter+-unchanged)\n310 \" \")))\n311 (goto-char (point-min))\n312 (while (not (eobp))\n313 (git-gutter+-view-at-pos sign (point))\n314 (forward-line 1)))))\n\n316 (defun git-gutter+-set-window-margin (width)\n317 (let ((curwin (get-buffer-window)))\n318 (set-window-margins curwin width (cdr (window-margins curwin)))))\n\n320 (defsubst git-gutter+-file-buffer-p ()\n321 (and (buffer-file-name)\n322 default-directory\n323 (file-directory-p default-directory)))\n\n325 ;;;###autoload\n326 (define-minor-mode git-gutter+-mode\n327 \"Git-Gutter mode\"\n328 :group 'git-gutter+\n329 :init-value nil\n330 :global nil\n331 :lighter git-gutter+-lighter\n332 (if git-gutter+-mode\n333 (if (and (git-gutter+-file-buffer-p)\n334 (git-gutter+-in-git-repository-p (buffer-file-name)))\n335 (progn\n336 (git-gutter+-add-local-hooks)\n337 (git-gutter+-refresh))\n338 (if (called-interactively-p 'any)\n339 (message \"No Git repo for current buffer\"))\n340 (git-gutter+-mode -1))\n341 (git-gutter+-remove-local-hooks)\n342 (git-gutter+-clear)))\n\n344 (defun git-gutter+-add-local-hooks ()\n345 (add-hook 'after-save-hook 'git-gutter+-refresh nil t)\n346 ;; Turn off `git-gutter+-mode' while reverting to prevent any redundant calls to\n347 ;; `git-gutter+-refresh'.\n348 (add-hook 'before-revert-hook 'git-gutter+-turn-off nil t)\n349 (add-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change nil t)\n350 (if git-gutter+-window-config-change-function\n351 (add-hook 'window-configuration-change-hook\n352 git-gutter+-window-config-change-function nil t)))\n\n354 (defun git-gutter+-remove-local-hooks ()\n355 (remove-hook 'after-save-hook 'git-gutter+-refresh t)\n356 (remove-hook 'before-revert-hook 'git-gutter+-turn-off t)\n357 (remove-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change t)\n358 (if git-gutter+-window-config-change-function\n359 (remove-hook 'window-configuration-change-hook\n360 git-gutter+-window-config-change-function t)))\n\n362 (defmacro git-gutter+-in-all-buffers (&rest body)\n363 `(dolist (buf (buffer-list))\n364 (with-current-buffer buf\n365 ,@body)))\n\n367 ;; When `define-globalized-minor-mode' is used to define `global-git-gutter+-mode',\n368 ;; `git-gutter+-mode' and thus `git-gutter+-refresh' get run twice when a new file\n369 ;; is opened. (First for `fundamental-mode', then for the file-specific mode.)\n370 ;; The following definition of `global-git-gutter+-mode' avoids any redundant calls to\n371 ;; `git-gutter+-refresh'.\n\n373 ;;;###autoload\n374 (define-minor-mode global-git-gutter+-mode ()\n375 \"Global Git-Gutter mode\"\n376 :group 'git-gutter+\n377 :init-value nil\n378 :global t\n379 (if global-git-gutter+-mode\n380 (progn\n381 (add-hook 'find-file-hook 'git-gutter+-turn-on)\n382 (add-hook 'after-revert-hook 'git-gutter+-turn-on)\n383 (add-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n384 (git-gutter+-in-all-buffers (git-gutter+-turn-on)))\n385 (remove-hook 'find-file-hook 'git-gutter+-turn-on)\n386 (remove-hook 'after-revert-hook 'git-gutter+-turn-on)\n387 (remove-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n388 (git-gutter+-in-all-buffers (git-gutter+-turn-off))))\n\n390 (defun git-gutter+-turn-on ()\n391 (when (and (buffer-file-name)\n392 (not (memq major-mode git-gutter+-disabled-modes))\n393 (not git-gutter+-mode))\n394 (git-gutter+-mode t)))\n\n396 (defun git-gutter+-turn-off ()\n397 (if git-gutter+-mode (git-gutter+-mode -1)))\n\n399 (defun git-gutter+-reenable-after-major-mode-change ()\n400 (if global-git-gutter+-mode\n401 (add-to-list 'git-gutter+-buffers-to-reenable (current-buffer))))\n\n403 (defun git-gutter+-reenable-buffers ()\n404 (dolist (buf git-gutter+-buffers-to-reenable)\n405 (with-current-buffer buf\n406 (git-gutter+-turn-on)))\n407 (setq git-gutter+-buffers-to-reenable nil))\n\n409 (defsubst git-gutter+-show-gutter-p (diffinfos)\n410 (if git-gutter+-hide-gutter\n411 (or diffinfos git-gutter+-unchanged-sign)\n412 (or global-git-gutter+-mode git-gutter+-unchanged-sign diffinfos)))\n\n414 (defun git-gutter+-show-gutter (&optional diffinfos)\n415 (when (git-gutter+-show-gutter-p (or diffinfos git-gutter+-diffinfos))\n416 (let ((win-width (or git-gutter+-window-width\n417 (git-gutter+-longest-sign-width))))\n418 (git-gutter+-set-window-margin win-width))))\n\n420 (defun git-gutter+-view-diff-infos (diffinfos)\n421 (when (or git-gutter+-unchanged-sign\n422 git-gutter+-separator-sign)\n423 (git-gutter+-view-for-unchanged))\n424 (when diffinfos\n425 (save-excursion\n426 (mapc 'git-gutter+-view-diff-info diffinfos)))\n427 (git-gutter+-show-gutter diffinfos))\n\n429 (defsubst git-gutter+-reset-window-margin-p ()\n430 (or git-gutter+-hide-gutter\n431 (not global-git-gutter+-mode)))\n\n433 (defun git-gutter+-clear-diff-infos ()\n434 (when (git-gutter+-reset-window-margin-p)\n435 (git-gutter+-set-window-margin 0))\n436 (remove-overlays (point-min) (point-max) 'git-gutter+ t))\n\n438 (defun git-gutter+-process-diff (curfile)\n439 (destructuring-bind\n440 (diff-header diffinfos) (git-gutter+-diff curfile)\n441 (setq git-gutter+-diff-header diff-header\n442 git-gutter+-diffinfos diffinfos)\n443 (save-restriction\n444 (widen)\n445 (funcall git-gutter+-view-diff-function diffinfos))))\n\n447 (defun git-gutter+-search-near-diff-index (diffinfos is-reverse)\n448 (loop with current-line = (line-number-at-pos)\n449 with cmp-fn = (if is-reverse '> '<)\n450 for diffinfo in (if is-reverse (reverse diffinfos) diffinfos)\n451 for index = 0 then (1+ index)\n452 for start-line = (plist-get diffinfo :start-line)\n453 when (funcall cmp-fn current-line start-line)\n454 return (if is-reverse\n455 (1- (- (length diffinfos) index))\n456 index)))\n\n458 (defun git-gutter+-diffinfo-at-point ()\n459 (save-restriction\n460 (widen)\n461 (loop with current-line = (line-number-at-pos)\n462 for diffinfo in git-gutter+-diffinfos\n463 for start = (plist-get diffinfo :start-line)\n464 for end = (or (plist-get diffinfo :end-line) (1+ start))\n465 when (and (>= current-line start) (<= current-line end))\n466 return diffinfo)))\n\n468 (defun git-gutter+-collect-deleted-line (str)\n469 (with-temp-buffer\n470 (insert str)\n471 (goto-char (point-min))\n472 (loop while (re-search-forward \"^-\\\\(.*?\\\\)$\" nil t)\n473 collect (match-string 1) into deleted-lines\n474 finally return deleted-lines)))\n\n476 (defun git-gutter+-delete-added-lines (start-line end-line)\n477 (forward-line (1- start-line))\n478 (let ((start-point (point)))\n479 (forward-line (1+ (- end-line start-line)))\n480 (delete-region start-point (point))))\n\n482 (defun git-gutter+-insert-deleted-lines (content)\n483 (dolist (line (git-gutter+-collect-deleted-line content))\n484 (insert (concat line \"\\n\"))))\n\n486 (defun git-gutter+-do-revert-hunk (diffinfo)\n487 (save-excursion\n488 (save-restriction\n489 (widen)\n490 (goto-char (point-min))\n491 (let ((start-line (plist-get diffinfo :start-line))\n492 (end-line (plist-get diffinfo :end-line))\n493 (content (plist-get diffinfo :content)))\n494 (case (plist-get diffinfo :type)\n495 (added (git-gutter+-delete-added-lines start-line end-line))\n496 (deleted (forward-line (1- start-line))\n497 (git-gutter+-insert-deleted-lines content))\n498 (modified (git-gutter+-delete-added-lines start-line end-line)\n499 (git-gutter+-insert-deleted-lines content)))))))\n\n501 (defun git-gutter+-revert-hunks ()\n502 \"Revert hunk at point. If region is active, revert all hunks within the region.\"\n503 (interactive)\n504 (let* ((diffinfos (git-gutter+-selected-diffinfos))\n505 (one-diffinfo-p (= 1 (length diffinfos))))\n506 (save-window-excursion\n507 (if one-diffinfo-p (git-gutter+-show-hunk (car diffinfos)))\n508 (when (and diffinfos\n509 (yes-or-no-p (if one-diffinfo-p\n510 \"Revert hunk?\"\n511 (format \"Revert %d hunks?\" (length diffinfos)))))\n512 ;; Revert diffinfos in reverse so that earlier hunks don't invalidate the\n513 ;; line number information of the later hunks.\n514 (dolist (diffinfo (nreverse diffinfos))\n515 (git-gutter+-do-revert-hunk diffinfo))\n516 (save-buffer))\n517 (if one-diffinfo-p\n518 (git-gutter+-awhen (get-buffer git-gutter+-popup-buffer)\n519 (kill-buffer it))))))\n\n521 (defun git-gutter+-show-hunk (&optional diffinfo)\n522 \"Show hunk at point in another window\"\n523 (interactive)\n524 (git-gutter+-awhen (or diffinfo\n525 (git-gutter+-diffinfo-at-point))\n526 (save-selected-window\n527 (with-current-buffer (get-buffer-create git-gutter+-popup-buffer)\n528 (setq buffer-read-only nil)\n529 (erase-buffer)\n530 (insert (plist-get it :content))\n531 (insert \"\\n\")\n532 (goto-char (point-min))\n533 (diff-mode)\n534 (view-mode)\n535 (pop-to-buffer (current-buffer))))))\n\n537 (defun git-gutter+-next-hunk (arg)\n538 \"Move to next diff hunk\"\n539 (interactive \"p\")\n540 (if (not git-gutter+-diffinfos)\n541 (message \"No changes in buffer\")\n542 (save-restriction\n543 (widen)\n544 (let* ((is-reverse (< arg 0))\n545 (diffinfos git-gutter+-diffinfos)\n546 (len (length diffinfos))\n547 (index (git-gutter+-search-near-diff-index diffinfos is-reverse))\n548 (real-index (if index\n549 (let ((next (if is-reverse (1+ index) (1- index))))\n550 (mod (+ arg next) len))\n551 (if is-reverse (1- (length diffinfos)) 0)))\n552 (diffinfo (nth real-index diffinfos)))\n553 (goto-char (point-min))\n554 (forward-line (1- (plist-get diffinfo :start-line)))\n555 (when (buffer-live-p (get-buffer git-gutter+-popup-buffer))\n556 (save-window-excursion\n557 (git-gutter+-show-hunk)))))))\n\n559 (defun git-gutter+-previous-hunk (arg)\n560 \"Move to previous diff hunk\"\n561 (interactive \"p\")\n562 (git-gutter+-next-hunk (- arg)))\n\n564 (defun git-gutter+-remote-default-directory (dir file)\n565 (let* ((vec (tramp-dissect-file-name file))\n566 (method (aref vec 0))\n567 (user (aref vec 1))\n568 (host (aref vec 2)))\n569 (format \"/%s:%s%s:%s\" method (if user (concat user \"@\") \"\") host dir)))\n\n571 (defun git-gutter+-remote-file-path (dir file)\n572 (let ((file (aref (tramp-dissect-file-name file) 3)))\n573 (replace-regexp-in-string (concat \"\\\\`\" dir) \"\" file)))\n\n575 (defun git-gutter+-local-file-path (file)\n576 (if (eq system-type 'windows-nt)\n577 ;; Cygwin can't handle Windows absolute paths\n578 (file-relative-name file default-directory)\n579 file))\n\n581 (defun git-gutter+-refresh ()\n582 (git-gutter+-clear)\n583 (let ((file (buffer-file-name)))\n584 (when (and file (file-exists-p file))\n585 (if (file-remote-p file)\n586 (let* ((repo-root (git-gutter+-root-directory file))\n587 (default-directory (git-gutter+-remote-default-directory repo-root file)))\n588 (git-gutter+-process-diff (git-gutter+-remote-file-path repo-root file)))\n589 (git-gutter+-process-diff (git-gutter+-local-file-path file))))))\n\n591 (defun git-gutter+-clear ()\n592 (save-restriction\n593 (widen)\n594 (funcall git-gutter+-clear-function))\n595 (setq git-gutter+-diffinfos nil))\n\n\n598 ;;; Staging\n\n600 (defun git-gutter+-stage-hunks ()\n601 \"Stage hunk at point. If region is active, stage all hunk lines within the region.\"\n602 (interactive)\n603 (let* ((line-range (if (use-region-p)\n604 (cons (line-number-at-pos (region-beginning))\n605 (line-number-at-pos (region-end)))))\n606 (diffinfos (git-gutter+-selected-diffinfos line-range)))\n607 (when diffinfos\n608 (let ((error-msg (git-gutter+-stage-diffinfos diffinfos line-range)))\n609 (if error-msg\n610 (message \"Error staging hunks:\\n%s\" error-msg))\n611 (git-gutter+-refresh)))))\n\n613 (defun git-gutter+-selected-diffinfos (&optional line-range)\n614 (unless line-range\n615 (setq line-range (if (use-region-p)\n616 (cons (line-number-at-pos (region-beginning))\n617 (line-number-at-pos (region-end))))))\n618 (if line-range\n619 (git-gutter+-diffinfos-between-lines line-range)\n620 (git-gutter+-awhen (git-gutter+-diffinfo-at-point)\n621 (list it))))\n\n623 (defsubst git-gutter+-diffinfo-between-lines-p (diffinfo start-line end-line)\n624 (let ((diff-start (plist-get diffinfo :start-line))\n625 (diff-end (plist-get diffinfo :end-line)))\n626 (and (<= start-line diff-end)\n627 (<= diff-start end-line))))\n\n629 (defun git-gutter+-diffinfos-between-lines (line-range)\n630 (save-restriction\n631 (widen)\n632 (let ((start-line (car line-range))\n633 (end-line (cdr line-range)))\n634 (delq nil\n635 (mapcar (lambda (diffinfo)\n636 (if (git-gutter+-diffinfo-between-lines-p\n637 diffinfo start-line end-line)\n638 diffinfo))\n639 git-gutter+-diffinfos)))))\n\n641 (defun git-gutter+-stage-diffinfos (diffinfos line-range)\n642 (let ((header git-gutter+-diff-header))\n643 (with-temp-buffer\n644 (insert header)\n645 ;; Insert hunks in reverse so that earlier hunks don't invalidate the line\n646 ;; number information of the later hunks.\n647 (dolist (diffinfo (nreverse diffinfos))\n648 (git-gutter+-insert-diffinfo diffinfo line-range)\n649 (goto-char (point-max)))\n650 (git-gutter+-call-git-on-current-buffer\n651 '(\"apply\" \"--unidiff-zero\" \"--cached\" \"-\")))))\n\n653 (defun git-gutter+-insert-diffinfo (diffinfo line-range)\n654 (let ((content (plist-get diffinfo :content))\n655 (type (plist-get diffinfo :type)))\n656 (if (not line-range)\n657 (git-gutter+-insert-hunk content type)\n658 (let ((diff-start-line (plist-get diffinfo :start-line))\n659 (diff-end-line (plist-get diffinfo :end-line))\n660 (start-line (car line-range))\n661 (end-line (cdr line-range)))\n662 (git-gutter+-insert-hunk content type\n663 (1+ (- start-line diff-start-line))\n664 (1+ (- end-line diff-start-line)))))))\n\n666 (defun git-gutter+-call-git-on-current-buffer (args)\n667 \"Sends the current buffer contents to Git and replaces them with Git's output.\n\n669 RETURNS nil if Git ran successfully. Returns an error description otherwise.\"\n670 (unless (zerop (apply #'call-process-region (point-min) (point-max)\n671 git-gutter+-git-executable t t nil args))\n672 (buffer-string)))\n\n674 (defsubst git-gutter+-read-hunk-header (hunk)\n675 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n676 (string-match git-gutter+-hunk-header-regex hunk)\n677 (list (string-to-number (match-string 1 hunk))\n678 (string-to-number (or (match-string 2 hunk) \"1\"))\n679 (string-to-number (match-string 3 hunk))\n680 (string-to-number (or (match-string 4 hunk) \"1\"))))\n\n682 (defun git-gutter+-insert-hunk (hunk type &optional start end)\n683 \"If START and END are provided, only insert addition (+) lines between\n684 START and END (inclusive). START and END are both line numbers starting with 1.\"\n685 (destructuring-bind\n686 (del-line del-len add-line add-len) (git-gutter+-read-hunk-header hunk)\n687 (let* ((start (max 1 (or start 1)))\n688 (end (min add-len (or end add-len)))\n689 (insert-all-p (or (eq type :deleted)\n690 (and (= start 1) (= end add-len))))\n691 (num-lines-selected (if insert-all-p\n692 add-len\n693 (1+ (- end start)))))\n694 ;; When the user selected the last lines of a hunk with type `modified' (but\n695 ;; not the complete hunk), then don't insert any deletion (-) lines from that\n696 ;; hunk.\n697 (if (and (eq type 'modified)\n698 (> start 1) (= end add-len))\n699 (setq type 'modified-trailing))\n\n701 (save-excursion\n702 (insert hunk \"\\n\"))\n\n704 (git-gutter+-delete-hunk-header)\n\n706 (if (not insert-all-p)\n707 (git-gutter+-modify-hunk type num-lines-selected del-len start))\n\n709 (let ((hunk-header (git-gutter+-make-hunk-header type num-lines-selected\n710 del-line del-len add-line)))\n711 (insert hunk-header \"\\n\")))))\n\n713 (defun git-gutter+-delete-hunk-header ()\n714 (let ((hunk-start (point)))\n715 (forward-line 1)\n716 (delete-region hunk-start (point))))\n\n718 (defun git-gutter+-modify-hunk (type num-lines-selected del-len start)\n719 \"Remove all addition (+) lines from hunk that aren't selected.\n720 If TYPE is not `modified', also remove all deletion (-) lines.\"\n721 (let ((first-line-selected (+ del-len (1- start)))\n722 selected-lines)\n723 (save-excursion\n724 (forward-line first-line-selected)\n725 (let ((selection-start (point)))\n726 (forward-line num-lines-selected)\n727 (setq selected-lines (buffer-substring selection-start (point)))))\n728 (save-excursion\n729 (if (eq type 'modified) (forward-line del-len)) ; skip over deletion (-) lines\n730 (delete-region (point) (point-max))\n731 (insert selected-lines))))\n\n733 (defun git-gutter+-make-hunk-header (type num-lines-selected del-line del-len add-line)\n734 (let ((add-len num-lines-selected))\n735 (case type\n736 (added (setq add-line (1+ del-line)))\n737 (modified-trailing (setq add-line (+ del-line del-len)\n738 del-line (1- add-line)\n739 del-len 0))\n740 (t (setq add-line del-line)))\n741 (format \"@@ -%d,%d +%d,%d @@\"\n742 del-line del-len\n743 add-line add-len)))\n\n\n746 ;;; Committing\n747 ;; This section draws heavily from old Magit source code.\n\n749 (defvar git-gutter+-pre-commit-window-config nil)\n750 (defvar git-gutter+-commit-origin-buffer nil\n751 \"Buffer that started the commit\")\n\n753 (defconst git-gutter+-commit-buffer-name \"*Commit Message*\")\n754 (defconst git-gutter+-staged-changes-buffer-name \"*Staged Changes*\")\n\n756 ;;;###autoload\n757 (defun git-gutter+-commit ()\n758 \"Commit staged changes. If nothing is staged, ask to stage the current buffer.\"\n759 (interactive)\n\n761 (when (and (not (git-gutter+-anything-staged-p))\n762 git-gutter+-diffinfos\n763 (y-or-n-p \"Nothing staged. Stage current buffer? \"))\n764 (git-gutter+-stage-whole-buffer))\n\n766 (let ((file (buffer-file-name))\n767 (dir default-directory))\n768 (git-gutter+-save-window-config-if-needed)\n769 (setq git-gutter+-commit-origin-buffer (current-buffer))\n770 (git-gutter+-open-commit-edit-buffer dir)\n771 (git-gutter+-show-staged-changes file dir)))\n\n773 (defun git-gutter+-stage-and-commit ()\n774 (interactive)\n775 (git-gutter+-stage-hunks)\n776 (git-gutter+-commit))\n\n778 (defun git-gutter+-save-window-config-if-needed ()\n779 ;; Only save the window config if the temporary buffers that get popped-up by\n780 ;; git-gutter+ are not already visible.\n781 ;; In this way, `git-gutter+-commit' can be called twice in a row without\n782 ;; losing the original window config.\n783 (when (not (and git-gutter+-pre-commit-window-config\n784 (get-buffer-window git-gutter+-commit-buffer-name)\n785 (get-buffer-window git-gutter+-staged-changes-buffer-name)))\n786 (setq git-gutter+-pre-commit-window-config (current-window-configuration))))\n\n788 (defun git-gutter+-open-commit-edit-buffer (dir)\n789 \"Opens a buffer for composing the commit message\"\n790 (pop-to-buffer (get-buffer-create git-gutter+-commit-buffer-name))\n791 (setq default-directory dir)\n792 (git-gutter+-commit-mode)\n793 (message \"Type C-c C-c to commit (C-c C-k to cancel).\"))\n\n795 (defsubst git-gutter+-pop-to-staged-changes-buffer ()\n796 (let* ((buf (get-buffer-create git-gutter+-staged-changes-buffer-name))\n797 (window (get-buffer-window buf)))\n798 (if window\n799 ;; Buffer is already visible\n800 (select-window window)\n801 (if (<= (length (window-list)) 2)\n802 (split-window))\n803 (pop-to-buffer buf))))\n\n805 (defun git-gutter+-show-staged-changes (file dir)\n806 (save-selected-window\n807 (git-gutter+-pop-to-staged-changes-buffer)\n808 (setq buffer-read-only nil)\n809 (erase-buffer)\n810 (let ((default-directory dir))\n811 (git-gutter+-call-git '(\"diff\" \"--staged\") file))\n812 (goto-char (point-min))\n813 (diff-mode)\n814 (view-mode)))\n\n816 (defsubst git-gutter+-abort-commit-when-no-changes (allow-empty amend)\n817 (unless (or amend\n818 allow-empty\n819 (git-gutter+-anything-staged-p))\n820 (error\n821 \"Refusing to create empty commit. Maybe you want to amend (%s) or allow-empty (%s)?\"\n822 (key-description (car (where-is-internal\n823 'git-gutter+-commit-toggle-amending)))\n824 (key-description (car (where-is-internal\n825 'git-gutter+-commit-toggle-allow-empty))))))\n\n827 (defsubst git-gutter+-buffer-is-whitespace ()\n828 (save-excursion\n829 (goto-char (point-min))\n830 (looking-at-p \"[ \\t\\n]*\\\\'\")))\n\n832 (defun git-gutter+-publish-commit ()\n833 \"Publish commit\"\n834 (interactive)\n835 (let* ((fields (git-gutter+-commit-get-fields))\n836 (amend (equal \"yes\" (git-gutter+-commit-get-field 'amend fields)))\n837 (allow-empty (equal \"yes\" (git-gutter+-commit-get-field 'allow-empty fields)))\n838 (author (git-gutter+-commit-get-field 'author fields))\n839 (date (git-gutter+-commit-get-field 'date fields)))\n\n841 (git-gutter+-abort-commit-when-no-changes allow-empty amend)\n\n843 (git-gutter+-push-to-comment-ring (buffer-string))\n\n845 (git-gutter+-commit-set-fields nil) ; Delete message header\n\n847 (when (git-gutter+-buffer-is-whitespace)\n848 (erase-buffer)\n849 (insert \"(Empty description)\"))\n\n851 (let ((error-msg (git-gutter+-call-git-on-current-buffer\n852 (append '(\"--no-pager\" \"commit\" \"-F\" \"-\")\n853 (if amend '(\"--amend\"))\n854 (if allow-empty '(\"--allow-empty\"))\n855 (if author (list (concat \"--author=\" author)))\n856 (if date (list (concat \"--date=\" date)))))))\n857 (if error-msg\n858 (progn\n859 (message \"Commit error:\\n%s\" error-msg)\n860 (erase-buffer)\n861 (insert (ring-ref log-edit-comment-ring 0))) ; Reinsert commit message\n862 (message \"Commit successful.\")\n863 (git-gutter+-close-commit-edit-buffer)\n864 (git-gutter+-update-vc-modeline)))))\n\n866 (defun git-gutter+-close-commit-edit-buffer ()\n867 \"Abort edits and discard commit message being composed.\"\n868 (interactive)\n869 (kill-buffer)\n870 (set-window-configuration git-gutter+-pre-commit-window-config))\n\n872 (defun git-gutter+-update-vc-modeline ()\n873 (when (buffer-live-p git-gutter+-commit-origin-buffer)\n874 (with-current-buffer git-gutter+-commit-origin-buffer\n875 ;; Updating the modeline has no effect if the buffer still has\n876 ;; changes - it will remain in the 'modified' state. So skip it then.\n877 (unless git-gutter+-diffinfos\n878 (ignore-errors (vc-find-file-hook))))))\n\n880 (defun git-gutter+-stage-whole-buffer ()\n881 (save-excursion\n882 (mark-whole-buffer)\n883 (git-gutter+-stage-hunks)))\n\n885 (defun git-gutter+-anything-staged-p ()\n886 \"Return t if the current repo has staged changes\"\n887 (not (zerop (git-gutter+-call-git '(\"diff\" \"--quiet\" \"--cached\")))))\n\n889 (defun git-gutter+-commit-toggle-amending ()\n890 \"Toggle whether this will be an amendment to the previous commit.\n891 \\(i.e., whether commit is run via 'git commit --amend')\"\n892 (interactive)\n893 ;; Remove the newline that 'git-commit-mode' adds to a new commit\n894 ;; message buffer by default. This prevents an ugly visual\n895 ;; gap between the commit message header and the previous commit\n896 ;; message.\n897 (when (git-gutter+-buffer-is-whitespace)\n898 (erase-buffer))\n\n900 (let ((amend-was-already-set (git-gutter+-commit-get-field 'amend)))\n901 (git-gutter+-commit-toggle-field 'amend t)\n902 (unless amend-was-already-set\n903 ;; Insert previous commit message\n904 (goto-char (point-max))\n905 (unless (zerop (current-column))\n906 (insert \"\\n\"))\n907 (insert (git-gutter+-get-last-commit-msg)\n908 \"\\n\"))))\n\n910 (defun git-gutter+-commit-toggle-allow-empty ()\n911 \"Toggle whether this commit is allowed to be empty.\n912 \\(i.e., whether commit is run via 'git commit --allow-empty')\"\n913 (interactive)\n914 (git-gutter+-commit-toggle-field 'allow-empty t))\n\n916 (defun git-gutter+-format-author (author email)\n917 (format \"%s <%s>\" author email))\n\n919 (defun git-gutter+-commit-toggle-author ()\n920 \"Toggle whether this commit should have a user-defined author.\"\n921 (interactive)\n922 (git-gutter+-commit-toggle-input\n923 'author (git-gutter+-format-author\n924 (or (git-gutter+-get-cfg \"user\" \"name\") \"Author Name\")\n925 (or (git-gutter+-get-cfg \"user\" \"email\") \"author@email\"))))\n\n927 (defun git-gutter+-commit-toggle-date ()\n928 \"Toggle whether this commit should have a user-defined date.\"\n929 (interactive)\n930 (git-gutter+-commit-toggle-input 'date\n931 ;; ISO 8601\n932 (format-time-string \"%Y-%m-%dT%T%z\" (current-time))))\n\n934 (defun git-gutter+-push-to-comment-ring (comment)\n935 (when (or (ring-empty-p log-edit-comment-ring)\n936 (not (equal comment (ring-ref log-edit-comment-ring 0))))\n937 (ring-insert log-edit-comment-ring comment)))\n\n939 (defun git-gutter+-get-last-commit-msg ()\n940 (git-gutter+-git-output '(\"log\" \"--max-count=1\" \"--pretty=format:%s%n%n%b\" \"HEAD\")))\n\n942 (defun git-gutter+-get-cfg (&rest keys)\n943 (git-gutter+-git-output (list \"config\" (mapconcat 'identity keys \".\"))))\n\n945 (defun git-gutter+-git-output (args)\n946 (with-temp-buffer\n947 (git-gutter+-call-git args)\n948 ;; Delete trailing newlines\n949 (goto-char (point-min))\n950 (if (re-search-forward \"\\n+\\\\'\" nil t)\n951 (replace-match \"\"))\n952 (buffer-string)))\n\n\n955 ;;; Commit message header\n\n957 (defconst git-gutter+-commit-header-end \"-- End of commit options header --\\n\")\n\n959 (defun git-gutter+-commit-get-field (name &optional fields)\n960 (cdr (assq name (or fields (git-gutter+-commit-get-fields)))))\n\n962 (defun git-gutter+-commit-set-field (name value)\n963 (let* ((fields (git-gutter+-commit-get-fields))\n964 (cell (assq name fields)))\n965 (cond (cell\n966 (if value\n967 (rplacd cell value)\n968 (setq fields (delq cell fields))))\n969 (t\n970 (if value\n971 (setq fields (append fields (list (cons name value)))))))\n972 (git-gutter+-commit-set-fields fields)))\n\n974 (defun git-gutter+-commit-toggle-field (name default)\n975 \"Toggle the commit header field named NAME.\n976 If it's currently unset, set it to DEFAULT (t or nil).\"\n977 (let* ((fields (git-gutter+-commit-get-fields))\n978 (cell (assq name fields)))\n979 (if cell\n980 (rplacd cell (if (equal (cdr cell) \"yes\") \"no\" \"yes\"))\n981 (setq fields (acons name (if default \"yes\" \"no\") fields)))\n982 (git-gutter+-commit-set-fields fields)))\n\n984 (defun git-gutter+-commit-toggle-input (name default)\n985 \"Toggle the commit header input named NAME.\n986 If it's currently unset, set it to DEFAULT (a string). If it is\n987 set remove it.\"\n988 (let* ((fields (git-gutter+-commit-get-fields))\n989 (cell (assq name fields)))\n990 (if cell\n991 (setq fields (assq-delete-all name fields))\n992 (setq fields (acons name default fields)))\n993 (git-gutter+-commit-set-fields fields)))\n\n995 (defun git-gutter+-commit-get-fields ()\n996 (let (result)\n997 (goto-char (point-min))\n998 (while (looking-at \"^\\\\([A-Za-z0-9-_]+\\\\): *\\\\(.+\\\\)?$\")\n999 (let ((name (intern (downcase (match-string 1))))\n1000 (value (read (or (match-string 2) \"nil\"))))\n1001 (push (cons name value) result))\n1002 (forward-line))\n1003 (if (looking-at (regexp-quote git-gutter+-commit-header-end))\n1004 (nreverse result))))\n\n1006 (defun git-gutter+-commit-set-fields (fields)\n1007 (goto-char (point-min))\n1008 ;; Delete commit header\n1009 (if (search-forward-regexp (format \"^\\\\(?:[A-Za-z0-9-_]+:.*\\n\\\\)*%s\"\n1010 (regexp-quote git-gutter+-commit-header-end))\n1011 nil t)\n1012 (delete-region (match-beginning 0) (match-end 0)))\n1013 (goto-char (point-min))\n1014 (when fields\n1015 (dolist (field fields)\n1016 (insert (capitalize (symbol-name (car field))) \": \"\n1017 (prin1-to-string (cdr field)) \"\\n\"))\n1018 (insert git-gutter+-commit-header-end)))\n\n\n1021 ;;; git-gutter+-commit-mode\n1022 ;; Like git-commit-mode, but adds keybindings to git-gutter+ commands and\n1023 ;; highlighting support for the commit message header.\n\n1025 (define-derived-mode git-gutter+-commit-mode git-commit-mode \"Git-Gutter-Commit\"\n1026 (setq font-lock-defaults (list (git-gutter+-commit-font-lock-keywords) t)))\n\n1028 (setq git-gutter+-commit-mode-map\n1029 (let ((map (copy-keymap git-commit-mode-map)))\n1030 (define-key map (kbd \"C-c C-c\") 'git-gutter+-publish-commit)\n1031 (define-key map (kbd \"C-c C-k\") 'git-gutter+-close-commit-edit-buffer)\n1032 (define-key map (kbd \"C-c C-a\") 'git-gutter+-commit-toggle-amending)\n1033 (define-key map (kbd \"C-c C-e\") 'git-gutter+-commit-toggle-allow-empty)\n1034 (define-key map (kbd \"C-c C-u\") 'git-gutter+-commit-toggle-author)\n1035 (define-key map (kbd \"C-c C-d\") 'git-gutter+-commit-toggle-date)\n1036 (define-key map (kbd \"C-c C-b\") 'git-commit-ack)\n1037 (define-key map (kbd \"M-p\") 'log-edit-previous-comment)\n1038 (define-key map (kbd \"M-n\") 'log-edit-next-comment)\n1039 map))\n\n1041 (defface git-gutter+-commit-header-face\n1042 '((t :inherit font-lock-comment-face))\n1043 \"Highlights the commit message header\"\n1044 :group 'git-gutter+-faces)\n\n1046 (defconst git-gutter+-commit-header-regex\n1047 (concat \"\\\\(?:.\\\\|\\n\\\\)*?\" (regexp-quote git-gutter+-commit-header-end)))\n\n1049 (defconst git-gutter+-skip-commit-header-regex\n1050 (concat \"\\\\`\\\\(?:\" git-gutter+-commit-header-regex \"\\\\)?\"))\n\n1052 ;; Modify git-commit-summary-regexp to ignore the commit header\n1053 (defadvice git-commit-summary-regexp\n1054 (after ignore-git-gutter+-commit-header activate compile)\n1055 (if (eq major-mode 'git-gutter+-commit-mode)\n1056 (setq ad-return-value\n1057 (concat git-gutter+-skip-commit-header-regex\n1058 (substring ; Remove leading \"\\\\`\"\n1059 ad-return-value 2)))))\n\n1061 (defun git-gutter+-commit-font-lock-keywords ()\n1062 \"Like `git-commit-mode-font-lock-keywords' but with commit header highlighting\"\n1063 `((,(concat \"\\\\`\" git-gutter+-commit-header-regex) . 'git-gutter+-commit-header-face)\n1064 ,@(git-commit-mode-font-lock-keywords)))\n\n\n1067 ;;; Magit synchronization\n1068 ;; Force Magit to refresh git-gutter+ when updating the VC mode line.\n\n1070 (defvar git-gutter+-orig-vc-find-file-hook)\n\n1072 (defvar git-gutter+-vc-find-file-hook-with-refresh\n1073 (lambda ()\n1074 (funcall git-gutter+-orig-vc-find-file-hook)\n1075 (if git-gutter+-mode (git-gutter+-refresh))))\n\n1077 (defadvice magit-update-vc-modeline (around refresh-git-gutter+ compile activate)\n1078 ;; `magit-update-vc-modeline' calls `vc-find-file-hook' (a function!) on each\n1079 ;; buffer in the repo. Temporarily rebind it to `vc-find-file-hook-with-refresh',\n1080 ;; which calls git-gutter+-refresh after updating the VC mode line.\n1081 ;;\n1082 ;; Using `flet' would have been much simpler, but it's deprecated since 24.3.\n1083 (setq git-gutter+-orig-vc-find-file-hook (symbol-function 'vc-find-file-hook))\n1084 (fset 'vc-find-file-hook git-gutter+-vc-find-file-hook-with-refresh)\n1085 (unwind-protect\n1086 ad-do-it\n1087 (fset 'vc-find-file-hook git-gutter+-orig-vc-find-file-hook)))\n\n1089 (provide 'git-gutter+)\n\n1091 ;;; git-gutter+.el ends here\n")) (setq helm-swoop-cache t))) (candidates-in-buffer) (get-line . buffer-substring-no-properties) (keymap keymap (C-M-left . backward-sexp) (C-M-right . forward-sexp) (27 keymap (105 . helm-multi-swoop-all-from-helm-swoop)) (3 keymap (5 . helm-swoop-edit)) keymap (C-M-left . paren-backward-sexp) (C-M-right . paren-forward-sexp) (94 . helm-swoop-caret-match) (menu-bar keymap (help-menu keymap (describe keymap (describe-mode . helm-help)))) (help keymap (109 . helm-help)) (f1 keymap (109 . helm-help)) (8 keymap (109 . helm-help) (104 . undefined) (8 . undefined) (4 . helm-debug-output)) (20 . helm-toggle-resplit-and-swap-windows) (C-tab . undefined) (triple-mouse-3 . ignore) (double-mouse-3 . ignore) (mouse-3 . ignore) (drag-mouse-3 . ignore) (down-mouse-3 . ignore) (triple-mouse-2 . ignore) (double-mouse-2 . ignore) (mouse-2 . ignore) (drag-mouse-2 . ignore) (down-mouse-2 . ignore) (triple-mouse-1 . ignore) (double-mouse-1 . ignore) (mouse-1 . ignore) (drag-mouse-1 . ignore) (down-mouse-1 . ignore) (67108897 . helm-toggle-suspend-update) (3 keymap (21 . helm-force-update) (6 . helm-follow-mode) (11 . helm-kill-selection-and-quit) (25 . helm-yank-selection) (4 . helm-delete-current-selection) (45 . helm-swap-windows)) (67108987 . helm-enlarge-window) (67108989 . helm-narrow-window) (19 . undefined) (18 . undefined) (23 . helm-yank-text-at-point) (24 keymap (2 . helm-resume-list-buffers-after-quit) (98 . helm-resume-previous-session-after-quit) (6 . helm-quit-and-find-file)) (11 . helm-delete-minibuffer-contents) (67108896 . helm-toggle-visible-mark) (0 . helm-toggle-visible-mark) (C-M-up . helm-scroll-other-window-down) (C-M-down . helm-scroll-other-window) (M-prior . helm-scroll-other-window-down) (M-next . helm-scroll-other-window) (12 . helm-recenter-top-bottom-other-window) (15 . helm-next-source) (10 . helm-select-3rd-action) (5 . helm-select-2nd-action-or-end-of-line) ...) (header-line . "[C-c C-e] Edit mode, [M-i] apply all buffers") (action lambda ($line) (helm-swoop--goto-line (when (string-match "^[0-9]+" $line) (string-to-number (match-string 0 $line)))) (when (re-search-forward (mapconcat (quote identity) (split-string helm-pattern " ") "\\|") nil t) (goto-char (match-beginning 0))) (helm-swoop--recenter)) (migemo)) #("git-gutter+-refresh" 0 19 (fontified t face whitespace-line)) "Swoop: " nil "^368 " "*Helm Swoop*" nil nil nil)
apply(helm-internal (((name . "git-gutter+.el") (init lambda nil (unless helm-swoop-cache (with-current-buffer (helm-candidate-buffer (quote local)) (insert "1 ;;; git-gutter+.el --- Manage Git hunks straight from the buffer\n\n3 ;; Copyright (C) 2013 by Syohei YOSHIDA and contributors\n\n5 ;; Author: Syohei YOSHIDA <syohex@gmail.com> and contributors\n6 ;; URL: https://github.com/nonsequitur/git-gutter-plus\n7 ;; Version: 0.1\n\n9 ;; This program is free software; you can redistribute it and/or modify\n10 ;; it under the terms of the GNU General Public License as published by\n11 ;; the Free Software Foundation, either version 3 of the License, or\n12 ;; (at your option) any later version.\n\n14 ;; This program is distributed in the hope that it will be useful,\n15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of\n16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n17 ;; GNU General Public License for more details.\n\n19 ;; You should have received a copy of the GNU General Public License\n20 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n22 ;; Package-Requires: ((git-commit-mode \"0.14\"))\n\n24 ;;; Commentary:\n25 ;;\n26 ;; View, stage and revert Git changes straight from the buffer.\n\n28 ;;; Code:\n\n30 (eval-when-compile\n31 (require 'cl))\n\n33 (require 'tramp)\n34 (require 'log-edit)\n35 (require 'git-commit-mode)\n\n37 (defgroup git-gutter+ nil\n38 \"Manage Git hunks straight from the buffer\"\n39 :prefix \"git-gutter+-\"\n40 :group 'vc)\n\n42 (defcustom git-gutter+-window-width nil\n43 \"Character width of the gutter margin. Set this variable if the automatically\n44 calculated width looks wrong. (This can happen with some special characters.)\"\n45 :type 'integer\n46 :group 'git-gutter+)\n\n48 (defcustom git-gutter+-git-executable \"git\"\n49 \"The path of the Git executable.\"\n50 :type 'string\n51 :group 'git-gutter+)\n\n53 (defcustom git-gutter+-diff-options nil\n54 \"List of strings containing extra arguments to 'git diff'\"\n55 :type 'list\n56 :group 'git-gutter+)\n\n58 (defcustom git-gutter+-separator-sign nil\n59 \"Separator sign\"\n60 :type 'string\n61 :group 'git-gutter+)\n\n63 (defcustom git-gutter+-modified-sign \"=\"\n64 \"Modified sign\"\n65 :type 'string\n66 :group 'git-gutter+)\n\n68 (defcustom git-gutter+-added-sign \"+\"\n69 \"Added sign\"\n70 :type 'string\n71 :group 'git-gutter+)\n\n73 (defcustom git-gutter+-deleted-sign \"-\"\n74 \"Deleted sign\"\n75 :type 'string\n76 :group 'git-gutter+)\n\n78 (defcustom git-gutter+-unchanged-sign nil\n79 \"Unchanged sign\"\n80 :type 'string\n81 :group 'git-gutter+)\n\n83 (defcustom git-gutter+-hide-gutter nil\n84 \"Hide gutter if there are no changes\"\n85 :type 'boolean\n86 :group 'git-gutter+)\n\n88 (defcustom git-gutter+-lighter \" GitGutter\"\n89 \"Minor mode lighter in mode-line\"\n90 :type 'string\n91 :group 'git-gutter+)\n\n93 (defface git-gutter+-separator\n94 '((t (:foreground \"cyan\" :weight bold)))\n95 \"Face of the separator\"\n96 :group 'git-gutter+)\n\n98 (defface git-gutter+-modified\n99 '((t (:foreground \"magenta\" :weight bold)))\n100 \"Face for modified lines\"\n101 :group 'git-gutter+)\n\n103 (defface git-gutter+-added\n104 '((t (:foreground \"green\" :weight bold)))\n105 \"Face for added lines\"\n106 :group 'git-gutter+)\n\n108 (defface git-gutter+-deleted\n109 '((t (:foreground \"red\" :weight bold)))\n110 \"Face for deleted lines\"\n111 :group 'git-gutter+)\n\n113 (defface git-gutter+-unchanged\n114 '((t (:background \"yellow\")))\n115 \"Face for unchanged lines\"\n116 :group 'git-gutter+)\n\n118 (defcustom git-gutter+-disabled-modes nil\n119 \"A list of modes for which `global-git-gutter+-mode' should be disabled.\"\n120 :type '(repeat symbol)\n121 :group 'git-gutter+)\n\n123 (defvar git-gutter+-mode-map\n124 (make-sparse-keymap))\n\n126 (defvar git-gutter+-view-diff-function nil\n127 \"Function to call for displaying diffs\")\n\n129 (defvar git-gutter+-clear-function nil\n130 \"Function to call for clearing the diff display\")\n\n132 (defvar git-gutter+-window-config-change-function nil\n133 \"Function to call when the buffer's local window configuration has changed\")\n\n135 (defvar git-gutter+-diffinfos nil)\n136 (defvar git-gutter+-diff-header nil)\n137 (make-variable-buffer-local 'git-gutter+-diffinfos)\n138 (make-variable-buffer-local 'git-gutter+-diff-header)\n\n140 (defvar git-gutter+-popup-buffer \"*git-gutter+-diff*\")\n141 (defvar git-gutter+-buffers-to-reenable nil)\n\n143 (defconst git-gutter+-hunk-header-regex\n144 ;; The same as diff-hunk-header-re-unified\n145 \"^@@ -\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? \\\\+\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? @@\")\n\n147 (defalias 'git-gutter+-popup-hunk 'git-gutter+-show-hunk)\n148 (defalias 'git-gutter+-revert-hunk 'git-gutter+-revert-hunks)\n\n150 (defmacro git-gutter+-awhen (test &rest body)\n151 \"Anaphoric when.\"\n152 (declare (indent 1))\n153 `(let ((it ,test))\n154 (when it ,@body)))\n\n156 (defun git-gutter+-enable-default-display-mode ()\n157 (setq git-gutter+-view-diff-function 'git-gutter+-view-diff-infos\n158 git-gutter+-clear-function 'git-gutter+-clear-diff-infos\n159 git-gutter+-window-config-change-function 'git-gutter+-show-gutter))\n\n161 (unless git-gutter+-view-diff-function\n162 (git-gutter+-enable-default-display-mode))\n\n164 (defun git-gutter+-call-git (args &optional file)\n165 (if (and file (file-remote-p file))\n166 (apply #'process-file git-gutter+-git-executable nil t nil args)\n167 (apply #'call-process git-gutter+-git-executable nil t nil args)))\n\n169 (defun git-gutter+-in-git-repository-p (file)\n170 (with-temp-buffer\n171 (let ((args '(\"rev-parse\" \"--is-inside-work-tree\")))\n172 (when (zerop (git-gutter+-call-git args file))\n173 (goto-char (point-min))\n174 (string= \"true\" (buffer-substring-no-properties\n175 (point) (line-end-position)))))))\n\n177 (defun git-gutter+-root-directory (file)\n178 (with-temp-buffer\n179 (let* ((args '(\"rev-parse\" \"--show-toplevel\"))\n180 (ret (git-gutter+-call-git args file)))\n181 (when (zerop ret)\n182 (goto-char (point-min))\n183 (let ((root (buffer-substring-no-properties (point) (line-end-position))))\n184 (unless (string= root \"\")\n185 (file-name-as-directory root)))))))\n\n187 (defsubst git-gutter+-diff-args (file)\n188 (delq nil (list \"--no-pager\" \"diff\" \"--no-color\" \"--no-ext-diff\" \"-U0\"\n189 git-gutter+-diff-options file)))\n\n191 (defun git-gutter+-diff (curfile)\n192 (let ((args (git-gutter+-diff-args curfile))\n193 (file (buffer-file-name))) ;; for tramp\n194 (with-temp-buffer\n195 (when (zerop (git-gutter+-call-git args file))\n196 (goto-char (point-min))\n197 (let ((diff-header (git-gutter+-get-diff-header))\n198 (diffinfos (git-gutter+-get-diffinfos)))\n199 (list diff-header diffinfos))))))\n\n201 (defun git-gutter+-get-diff-header ()\n202 (save-excursion\n203 (if (re-search-forward git-gutter+-hunk-header-regex nil t)\n204 (buffer-substring (point-min) (match-beginning 0)))))\n\n206 (defsubst git-gutter+-make-diffinfo (type content start end)\n207 (list :type type :content content :start-line start :end-line end))\n\n209 (defun git-gutter+-get-diffinfos ()\n210 (loop while (re-search-forward git-gutter+-hunk-header-regex nil t)\n211 ;; Hunk header format:\n212 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n213 for del-len = (string-to-number (or (match-string 2) \"1\"))\n214 for add-line = (string-to-number (match-string 3))\n215 for add-len = (string-to-number (or (match-string 4) \"1\"))\n216 for type = (cond ((zerop del-len) 'added)\n217 ((zerop add-len) 'deleted)\n218 (t 'modified))\n219 for start-line = (if (eq type 'deleted)\n220 (1+ add-line)\n221 add-line)\n222 for end-line = (if (eq type 'deleted)\n223 start-line\n224 (1- (+ add-line add-len)))\n225 for content = (git-gutter+-diff-content)\n226 collect\n227 (git-gutter+-make-diffinfo type content start-line end-line)))\n\n229 (defun git-gutter+-diff-content ()\n230 (save-excursion\n231 (goto-char (line-beginning-position)) ; Move to beginning of hunk header\n232 (let ((hunk-start (point)))\n233 ;; Move to end of hunk\n234 (forward-line 1)\n235 (if (re-search-forward \"^@@\" nil t)\n236 (backward-char 3) ;; exclude \"\\n@@\"\n237 (goto-char (1- (point-max)))) ; Skip trailing newline\n238 (buffer-substring hunk-start (point)))))\n\n240 (defun git-gutter+-line-to-pos (line)\n241 (save-excursion\n242 (goto-char (point-min))\n243 (forward-line (1- line))\n244 (point)))\n\n246 (defun git-gutter+-before-string (sign)\n247 (let* ((sep-sign git-gutter+-separator-sign)\n248 (sep (when sep-sign\n249 (propertize sep-sign 'face 'git-gutter+-separator)))\n250 (gutter-sep (concat sign sep)))\n251 (propertize \" \" 'display `((margin left-margin) ,gutter-sep))))\n\n253 (defsubst git-gutter+-select-face (type)\n254 (case type\n255 (added 'git-gutter+-added)\n256 (modified 'git-gutter+-modified)\n257 (deleted 'git-gutter+-deleted)))\n\n259 (defsubst git-gutter+-select-sign (type)\n260 (case type\n261 (added git-gutter+-added-sign)\n262 (modified git-gutter+-modified-sign)\n263 (deleted git-gutter+-deleted-sign)))\n\n265 (defun git-gutter+-propertized-sign (type)\n266 (let ((sign (git-gutter+-select-sign type))\n267 (face (git-gutter+-select-face type)))\n268 (propertize sign 'face face)))\n\n270 (defun git-gutter+-view-region (sign start-line end-line)\n271 (let ((beg (git-gutter+-line-to-pos start-line)))\n272 (goto-char beg)\n273 (while (and (<= (line-number-at-pos) end-line) (not (eobp)))\n274 (git-gutter+-view-at-pos sign (point))\n275 (forward-line 1))))\n\n277 (defun git-gutter+-view-at-pos (sign pos)\n278 (let ((ov (make-overlay pos pos)))\n279 (overlay-put ov 'before-string (git-gutter+-before-string sign))\n280 (overlay-put ov 'git-gutter+ t)))\n\n282 (defun git-gutter+-view-diff-info (diffinfo)\n283 (let* ((start-line (plist-get diffinfo :start-line))\n284 (end-line (plist-get diffinfo :end-line))\n285 (type (plist-get diffinfo :type))\n286 (sign (git-gutter+-propertized-sign type)))\n287 (case type\n288 ((modified added) (git-gutter+-view-region sign start-line end-line))\n289 (deleted (git-gutter+-view-at-pos\n290 sign (git-gutter+-line-to-pos start-line))))))\n\n292 (defun git-gutter+-sign-width (sign)\n293 (loop for s across sign\n294 sum (char-width s)))\n\n296 (defun git-gutter+-longest-sign-width ()\n297 (let ((signs (list git-gutter+-modified-sign\n298 git-gutter+-added-sign\n299 git-gutter+-deleted-sign)))\n300 (when git-gutter+-unchanged-sign\n301 (add-to-list 'signs git-gutter+-unchanged-sign))\n302 (+ (apply 'max (mapcar 'git-gutter+-sign-width signs))\n303 (git-gutter+-sign-width git-gutter+-separator-sign))))\n\n305 (defun git-gutter+-view-for-unchanged ()\n306 (save-excursion\n307 (let ((sign (if git-gutter+-unchanged-sign\n308 (propertize git-gutter+-unchanged-sign\n309 'face 'git-gutter+-unchanged)\n310 \" \")))\n311 (goto-char (point-min))\n312 (while (not (eobp))\n313 (git-gutter+-view-at-pos sign (point))\n314 (forward-line 1)))))\n\n316 (defun git-gutter+-set-window-margin (width)\n317 (let ((curwin (get-buffer-window)))\n318 (set-window-margins curwin width (cdr (window-margins curwin)))))\n\n320 (defsubst git-gutter+-file-buffer-p ()\n321 (and (buffer-file-name)\n322 default-directory\n323 (file-directory-p default-directory)))\n\n325 ;;;###autoload\n326 (define-minor-mode git-gutter+-mode\n327 \"Git-Gutter mode\"\n328 :group 'git-gutter+\n329 :init-value nil\n330 :global nil\n331 :lighter git-gutter+-lighter\n332 (if git-gutter+-mode\n333 (if (and (git-gutter+-file-buffer-p)\n334 (git-gutter+-in-git-repository-p (buffer-file-name)))\n335 (progn\n336 (git-gutter+-add-local-hooks)\n337 (git-gutter+-refresh))\n338 (if (called-interactively-p 'any)\n339 (message \"No Git repo for current buffer\"))\n340 (git-gutter+-mode -1))\n341 (git-gutter+-remove-local-hooks)\n342 (git-gutter+-clear)))\n\n344 (defun git-gutter+-add-local-hooks ()\n345 (add-hook 'after-save-hook 'git-gutter+-refresh nil t)\n346 ;; Turn off `git-gutter+-mode' while reverting to prevent any redundant calls to\n347 ;; `git-gutter+-refresh'.\n348 (add-hook 'before-revert-hook 'git-gutter+-turn-off nil t)\n349 (add-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change nil t)\n350 (if git-gutter+-window-config-change-function\n351 (add-hook 'window-configuration-change-hook\n352 git-gutter+-window-config-change-function nil t)))\n\n354 (defun git-gutter+-remove-local-hooks ()\n355 (remove-hook 'after-save-hook 'git-gutter+-refresh t)\n356 (remove-hook 'before-revert-hook 'git-gutter+-turn-off t)\n357 (remove-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change t)\n358 (if git-gutter+-window-config-change-function\n359 (remove-hook 'window-configuration-change-hook\n360 git-gutter+-window-config-change-function t)))\n\n362 (defmacro git-gutter+-in-all-buffers (&rest body)\n363 `(dolist (buf (buffer-list))\n364 (with-current-buffer buf\n365 ,@body)))\n\n367 ;; When `define-globalized-minor-mode' is used to define `global-git-gutter+-mode',\n368 ;; `git-gutter+-mode' and thus `git-gutter+-refresh' get run twice when a new file\n369 ;; is opened. (First for `fundamental-mode', then for the file-specific mode.)\n370 ;; The following definition of `global-git-gutter+-mode' avoids any redundant calls to\n371 ;; `git-gutter+-refresh'.\n\n373 ;;;###autoload\n374 (define-minor-mode global-git-gutter+-mode ()\n375 \"Global Git-Gutter mode\"\n376 :group 'git-gutter+\n377 :init-value nil\n378 :global t\n379 (if global-git-gutter+-mode\n380 (progn\n381 (add-hook 'find-file-hook 'git-gutter+-turn-on)\n382 (add-hook 'after-revert-hook 'git-gutter+-turn-on)\n383 (add-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n384 (git-gutter+-in-all-buffers (git-gutter+-turn-on)))\n385 (remove-hook 'find-file-hook 'git-gutter+-turn-on)\n386 (remove-hook 'after-revert-hook 'git-gutter+-turn-on)\n387 (remove-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n388 (git-gutter+-in-all-buffers (git-gutter+-turn-off))))\n\n390 (defun git-gutter+-turn-on ()\n391 (when (and (buffer-file-name)\n392 (not (memq major-mode git-gutter+-disabled-modes))\n393 (not git-gutter+-mode))\n394 (git-gutter+-mode t)))\n\n396 (defun git-gutter+-turn-off ()\n397 (if git-gutter+-mode (git-gutter+-mode -1)))\n\n399 (defun git-gutter+-reenable-after-major-mode-change ()\n400 (if global-git-gutter+-mode\n401 (add-to-list 'git-gutter+-buffers-to-reenable (current-buffer))))\n\n403 (defun git-gutter+-reenable-buffers ()\n404 (dolist (buf git-gutter+-buffers-to-reenable)\n405 (with-current-buffer buf\n406 (git-gutter+-turn-on)))\n407 (setq git-gutter+-buffers-to-reenable nil))\n\n409 (defsubst git-gutter+-show-gutter-p (diffinfos)\n410 (if git-gutter+-hide-gutter\n411 (or diffinfos git-gutter+-unchanged-sign)\n412 (or global-git-gutter+-mode git-gutter+-unchanged-sign diffinfos)))\n\n414 (defun git-gutter+-show-gutter (&optional diffinfos)\n415 (when (git-gutter+-show-gutter-p (or diffinfos git-gutter+-diffinfos))\n416 (let ((win-width (or git-gutter+-window-width\n417 (git-gutter+-longest-sign-width))))\n418 (git-gutter+-set-window-margin win-width))))\n\n420 (defun git-gutter+-view-diff-infos (diffinfos)\n421 (when (or git-gutter+-unchanged-sign\n422 git-gutter+-separator-sign)\n423 (git-gutter+-view-for-unchanged))\n424 (when diffinfos\n425 (save-excursion\n426 (mapc 'git-gutter+-view-diff-info diffinfos)))\n427 (git-gutter+-show-gutter diffinfos))\n\n429 (defsubst git-gutter+-reset-window-margin-p ()\n430 (or git-gutter+-hide-gutter\n431 (not global-git-gutter+-mode)))\n\n433 (defun git-gutter+-clear-diff-infos ()\n434 (when (git-gutter+-reset-window-margin-p)\n435 (git-gutter+-set-window-margin 0))\n436 (remove-overlays (point-min) (point-max) 'git-gutter+ t))\n\n438 (defun git-gutter+-process-diff (curfile)\n439 (destructuring-bind\n440 (diff-header diffinfos) (git-gutter+-diff curfile)\n441 (setq git-gutter+-diff-header diff-header\n442 git-gutter+-diffinfos diffinfos)\n443 (save-restriction\n444 (widen)\n445 (funcall git-gutter+-view-diff-function diffinfos))))\n\n447 (defun git-gutter+-search-near-diff-index (diffinfos is-reverse)\n448 (loop with current-line = (line-number-at-pos)\n449 with cmp-fn = (if is-reverse '> '<)\n450 for diffinfo in (if is-reverse (reverse diffinfos) diffinfos)\n451 for index = 0 then (1+ index)\n452 for start-line = (plist-get diffinfo :start-line)\n453 when (funcall cmp-fn current-line start-line)\n454 return (if is-reverse\n455 (1- (- (length diffinfos) index))\n456 index)))\n\n458 (defun git-gutter+-diffinfo-at-point ()\n459 (save-restriction\n460 (widen)\n461 (loop with current-line = (line-number-at-pos)\n462 for diffinfo in git-gutter+-diffinfos\n463 for start = (plist-get diffinfo :start-line)\n464 for end = (or (plist-get diffinfo :end-line) (1+ start))\n465 when (and (>= current-line start) (<= current-line end))\n466 return diffinfo)))\n\n468 (defun git-gutter+-collect-deleted-line (str)\n469 (with-temp-buffer\n470 (insert str)\n471 (goto-char (point-min))\n472 (loop while (re-search-forward \"^-\\\\(.*?\\\\)$\" nil t)\n473 collect (match-string 1) into deleted-lines\n474 finally return deleted-lines)))\n\n476 (defun git-gutter+-delete-added-lines (start-line end-line)\n477 (forward-line (1- start-line))\n478 (let ((start-point (point)))\n479 (forward-line (1+ (- end-line start-line)))\n480 (delete-region start-point (point))))\n\n482 (defun git-gutter+-insert-deleted-lines (content)\n483 (dolist (line (git-gutter+-collect-deleted-line content))\n484 (insert (concat line \"\\n\"))))\n\n486 (defun git-gutter+-do-revert-hunk (diffinfo)\n487 (save-excursion\n488 (save-restriction\n489 (widen)\n490 (goto-char (point-min))\n491 (let ((start-line (plist-get diffinfo :start-line))\n492 (end-line (plist-get diffinfo :end-line))\n493 (content (plist-get diffinfo :content)))\n494 (case (plist-get diffinfo :type)\n495 (added (git-gutter+-delete-added-lines start-line end-line))\n496 (deleted (forward-line (1- start-line))\n497 (git-gutter+-insert-deleted-lines content))\n498 (modified (git-gutter+-delete-added-lines start-line end-line)\n499 (git-gutter+-insert-deleted-lines content)))))))\n\n501 (defun git-gutter+-revert-hunks ()\n502 \"Revert hunk at point. If region is active, revert all hunks within the region.\"\n503 (interactive)\n504 (let* ((diffinfos (git-gutter+-selected-diffinfos))\n505 (one-diffinfo-p (= 1 (length diffinfos))))\n506 (save-window-excursion\n507 (if one-diffinfo-p (git-gutter+-show-hunk (car diffinfos)))\n508 (when (and diffinfos\n509 (yes-or-no-p (if one-diffinfo-p\n510 \"Revert hunk?\"\n511 (format \"Revert %d hunks?\" (length diffinfos)))))\n512 ;; Revert diffinfos in reverse so that earlier hunks don't invalidate the\n513 ;; line number information of the later hunks.\n514 (dolist (diffinfo (nreverse diffinfos))\n515 (git-gutter+-do-revert-hunk diffinfo))\n516 (save-buffer))\n517 (if one-diffinfo-p\n518 (git-gutter+-awhen (get-buffer git-gutter+-popup-buffer)\n519 (kill-buffer it))))))\n\n521 (defun git-gutter+-show-hunk (&optional diffinfo)\n522 \"Show hunk at point in another window\"\n523 (interactive)\n524 (git-gutter+-awhen (or diffinfo\n525 (git-gutter+-diffinfo-at-point))\n526 (save-selected-window\n527 (with-current-buffer (get-buffer-create git-gutter+-popup-buffer)\n528 (setq buffer-read-only nil)\n529 (erase-buffer)\n530 (insert (plist-get it :content))\n531 (insert \"\\n\")\n532 (goto-char (point-min))\n533 (diff-mode)\n534 (view-mode)\n535 (pop-to-buffer (current-buffer))))))\n\n537 (defun git-gutter+-next-hunk (arg)\n538 \"Move to next diff hunk\"\n539 (interactive \"p\")\n540 (if (not git-gutter+-diffinfos)\n541 (message \"No changes in buffer\")\n542 (save-restriction\n543 (widen)\n544 (let* ((is-reverse (< arg 0))\n545 (diffinfos git-gutter+-diffinfos)\n546 (len (length diffinfos))\n547 (index (git-gutter+-search-near-diff-index diffinfos is-reverse))\n548 (real-index (if index\n549 (let ((next (if is-reverse (1+ index) (1- index))))\n550 (mod (+ arg next) len))\n551 (if is-reverse (1- (length diffinfos)) 0)))\n552 (diffinfo (nth real-index diffinfos)))\n553 (goto-char (point-min))\n554 (forward-line (1- (plist-get diffinfo :start-line)))\n555 (when (buffer-live-p (get-buffer git-gutter+-popup-buffer))\n556 (save-window-excursion\n557 (git-gutter+-show-hunk)))))))\n\n559 (defun git-gutter+-previous-hunk (arg)\n560 \"Move to previous diff hunk\"\n561 (interactive \"p\")\n562 (git-gutter+-next-hunk (- arg)))\n\n564 (defun git-gutter+-remote-default-directory (dir file)\n565 (let* ((vec (tramp-dissect-file-name file))\n566 (method (aref vec 0))\n567 (user (aref vec 1))\n568 (host (aref vec 2)))\n569 (format \"/%s:%s%s:%s\" method (if user (concat user \"@\") \"\") host dir)))\n\n571 (defun git-gutter+-remote-file-path (dir file)\n572 (let ((file (aref (tramp-dissect-file-name file) 3)))\n573 (replace-regexp-in-string (concat \"\\\\`\" dir) \"\" file)))\n\n575 (defun git-gutter+-local-file-path (file)\n576 (if (eq system-type 'windows-nt)\n577 ;; Cygwin can't handle Windows absolute paths\n578 (file-relative-name file default-directory)\n579 file))\n\n581 (defun git-gutter+-refresh ()\n582 (git-gutter+-clear)\n583 (let ((file (buffer-file-name)))\n584 (when (and file (file-exists-p file))\n585 (if (file-remote-p file)\n586 (let* ((repo-root (git-gutter+-root-directory file))\n587 (default-directory (git-gutter+-remote-default-directory repo-root file)))\n588 (git-gutter+-process-diff (git-gutter+-remote-file-path repo-root file)))\n589 (git-gutter+-process-diff (git-gutter+-local-file-path file))))))\n\n591 (defun git-gutter+-clear ()\n592 (save-restriction\n593 (widen)\n594 (funcall git-gutter+-clear-function))\n595 (setq git-gutter+-diffinfos nil))\n\n\n598 ;;; Staging\n\n600 (defun git-gutter+-stage-hunks ()\n601 \"Stage hunk at point. If region is active, stage all hunk lines within the region.\"\n602 (interactive)\n603 (let* ((line-range (if (use-region-p)\n604 (cons (line-number-at-pos (region-beginning))\n605 (line-number-at-pos (region-end)))))\n606 (diffinfos (git-gutter+-selected-diffinfos line-range)))\n607 (when diffinfos\n608 (let ((error-msg (git-gutter+-stage-diffinfos diffinfos line-range)))\n609 (if error-msg\n610 (message \"Error staging hunks:\\n%s\" error-msg))\n611 (git-gutter+-refresh)))))\n\n613 (defun git-gutter+-selected-diffinfos (&optional line-range)\n614 (unless line-range\n615 (setq line-range (if (use-region-p)\n616 (cons (line-number-at-pos (region-beginning))\n617 (line-number-at-pos (region-end))))))\n618 (if line-range\n619 (git-gutter+-diffinfos-between-lines line-range)\n620 (git-gutter+-awhen (git-gutter+-diffinfo-at-point)\n621 (list it))))\n\n623 (defsubst git-gutter+-diffinfo-between-lines-p (diffinfo start-line end-line)\n624 (let ((diff-start (plist-get diffinfo :start-line))\n625 (diff-end (plist-get diffinfo :end-line)))\n626 (and (<= start-line diff-end)\n627 (<= diff-start end-line))))\n\n629 (defun git-gutter+-diffinfos-between-lines (line-range)\n630 (save-restriction\n631 (widen)\n632 (let ((start-line (car line-range))\n633 (end-line (cdr line-range)))\n634 (delq nil\n635 (mapcar (lambda (diffinfo)\n636 (if (git-gutter+-diffinfo-between-lines-p\n637 diffinfo start-line end-line)\n638 diffinfo))\n639 git-gutter+-diffinfos)))))\n\n641 (defun git-gutter+-stage-diffinfos (diffinfos line-range)\n642 (let ((header git-gutter+-diff-header))\n643 (with-temp-buffer\n644 (insert header)\n645 ;; Insert hunks in reverse so that earlier hunks don't invalidate the line\n646 ;; number information of the later hunks.\n647 (dolist (diffinfo (nreverse diffinfos))\n648 (git-gutter+-insert-diffinfo diffinfo line-range)\n649 (goto-char (point-max)))\n650 (git-gutter+-call-git-on-current-buffer\n651 '(\"apply\" \"--unidiff-zero\" \"--cached\" \"-\")))))\n\n653 (defun git-gutter+-insert-diffinfo (diffinfo line-range)\n654 (let ((content (plist-get diffinfo :content))\n655 (type (plist-get diffinfo :type)))\n656 (if (not line-range)\n657 (git-gutter+-insert-hunk content type)\n658 (let ((diff-start-line (plist-get diffinfo :start-line))\n659 (diff-end-line (plist-get diffinfo :end-line))\n660 (start-line (car line-range))\n661 (end-line (cdr line-range)))\n662 (git-gutter+-insert-hunk content type\n663 (1+ (- start-line diff-start-line))\n664 (1+ (- end-line diff-start-line)))))))\n\n666 (defun git-gutter+-call-git-on-current-buffer (args)\n667 \"Sends the current buffer contents to Git and replaces them with Git's output.\n\n669 RETURNS nil if Git ran successfully. Returns an error description otherwise.\"\n670 (unless (zerop (apply #'call-process-region (point-min) (point-max)\n671 git-gutter+-git-executable t t nil args))\n672 (buffer-string)))\n\n674 (defsubst git-gutter+-read-hunk-header (hunk)\n675 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n676 (string-match git-gutter+-hunk-header-regex hunk)\n677 (list (string-to-number (match-string 1 hunk))\n678 (string-to-number (or (match-string 2 hunk) \"1\"))\n679 (string-to-number (match-string 3 hunk))\n680 (string-to-number (or (match-string 4 hunk) \"1\"))))\n\n682 (defun git-gutter+-insert-hunk (hunk type &optional start end)\n683 \"If START and END are provided, only insert addition (+) lines between\n684 START and END (inclusive). START and END are both line numbers starting with 1.\"\n685 (destructuring-bind\n686 (del-line del-len add-line add-len) (git-gutter+-read-hunk-header hunk)\n687 (let* ((start (max 1 (or start 1)))\n688 (end (min add-len (or end add-len)))\n689 (insert-all-p (or (eq type :deleted)\n690 (and (= start 1) (= end add-len))))\n691 (num-lines-selected (if insert-all-p\n692 add-len\n693 (1+ (- end start)))))\n694 ;; When the user selected the last lines of a hunk with type `modified' (but\n695 ;; not the complete hunk), then don't insert any deletion (-) lines from that\n696 ;; hunk.\n697 (if (and (eq type 'modified)\n698 (> start 1) (= end add-len))\n699 (setq type 'modified-trailing))\n\n701 (save-excursion\n702 (insert hunk \"\\n\"))\n\n704 (git-gutter+-delete-hunk-header)\n\n706 (if (not insert-all-p)\n707 (git-gutter+-modify-hunk type num-lines-selected del-len start))\n\n709 (let ((hunk-header (git-gutter+-make-hunk-header type num-lines-selected\n710 del-line del-len add-line)))\n711 (insert hunk-header \"\\n\")))))\n\n713 (defun git-gutter+-delete-hunk-header ()\n714 (let ((hunk-start (point)))\n715 (forward-line 1)\n716 (delete-region hunk-start (point))))\n\n718 (defun git-gutter+-modify-hunk (type num-lines-selected del-len start)\n719 \"Remove all addition (+) lines from hunk that aren't selected.\n720 If TYPE is not `modified', also remove all deletion (-) lines.\"\n721 (let ((first-line-selected (+ del-len (1- start)))\n722 selected-lines)\n723 (save-excursion\n724 (forward-line first-line-selected)\n725 (let ((selection-start (point)))\n726 (forward-line num-lines-selected)\n727 (setq selected-lines (buffer-substring selection-start (point)))))\n728 (save-excursion\n729 (if (eq type 'modified) (forward-line del-len)) ; skip over deletion (-) lines\n730 (delete-region (point) (point-max))\n731 (insert selected-lines))))\n\n733 (defun git-gutter+-make-hunk-header (type num-lines-selected del-line del-len add-line)\n734 (let ((add-len num-lines-selected))\n735 (case type\n736 (added (setq add-line (1+ del-line)))\n737 (modified-trailing (setq add-line (+ del-line del-len)\n738 del-line (1- add-line)\n739 del-len 0))\n740 (t (setq add-line del-line)))\n741 (format \"@@ -%d,%d +%d,%d @@\"\n742 del-line del-len\n743 add-line add-len)))\n\n\n746 ;;; Committing\n747 ;; This section draws heavily from old Magit source code.\n\n749 (defvar git-gutter+-pre-commit-window-config nil)\n750 (defvar git-gutter+-commit-origin-buffer nil\n751 \"Buffer that started the commit\")\n\n753 (defconst git-gutter+-commit-buffer-name \"*Commit Message*\")\n754 (defconst git-gutter+-staged-changes-buffer-name \"*Staged Changes*\")\n\n756 ;;;###autoload\n757 (defun git-gutter+-commit ()\n758 \"Commit staged changes. If nothing is staged, ask to stage the current buffer.\"\n759 (interactive)\n\n761 (when (and (not (git-gutter+-anything-staged-p))\n762 git-gutter+-diffinfos\n763 (y-or-n-p \"Nothing staged. Stage current buffer? \"))\n764 (git-gutter+-stage-whole-buffer))\n\n766 (let ((file (buffer-file-name))\n767 (dir default-directory))\n768 (git-gutter+-save-window-config-if-needed)\n769 (setq git-gutter+-commit-origin-buffer (current-buffer))\n770 (git-gutter+-open-commit-edit-buffer dir)\n771 (git-gutter+-show-staged-changes file dir)))\n\n773 (defun git-gutter+-stage-and-commit ()\n774 (interactive)\n775 (git-gutter+-stage-hunks)\n776 (git-gutter+-commit))\n\n778 (defun git-gutter+-save-window-config-if-needed ()\n779 ;; Only save the window config if the temporary buffers that get popped-up by\n780 ;; git-gutter+ are not already visible.\n781 ;; In this way, `git-gutter+-commit' can be called twice in a row without\n782 ;; losing the original window config.\n783 (when (not (and git-gutter+-pre-commit-window-config\n784 (get-buffer-window git-gutter+-commit-buffer-name)\n785 (get-buffer-window git-gutter+-staged-changes-buffer-name)))\n786 (setq git-gutter+-pre-commit-window-config (current-window-configuration))))\n\n788 (defun git-gutter+-open-commit-edit-buffer (dir)\n789 \"Opens a buffer for composing the commit message\"\n790 (pop-to-buffer (get-buffer-create git-gutter+-commit-buffer-name))\n791 (setq default-directory dir)\n792 (git-gutter+-commit-mode)\n793 (message \"Type C-c C-c to commit (C-c C-k to cancel).\"))\n\n795 (defsubst git-gutter+-pop-to-staged-changes-buffer ()\n796 (let* ((buf (get-buffer-create git-gutter+-staged-changes-buffer-name))\n797 (window (get-buffer-window buf)))\n798 (if window\n799 ;; Buffer is already visible\n800 (select-window window)\n801 (if (<= (length (window-list)) 2)\n802 (split-window))\n803 (pop-to-buffer buf))))\n\n805 (defun git-gutter+-show-staged-changes (file dir)\n806 (save-selected-window\n807 (git-gutter+-pop-to-staged-changes-buffer)\n808 (setq buffer-read-only nil)\n809 (erase-buffer)\n810 (let ((default-directory dir))\n811 (git-gutter+-call-git '(\"diff\" \"--staged\") file))\n812 (goto-char (point-min))\n813 (diff-mode)\n814 (view-mode)))\n\n816 (defsubst git-gutter+-abort-commit-when-no-changes (allow-empty amend)\n817 (unless (or amend\n818 allow-empty\n819 (git-gutter+-anything-staged-p))\n820 (error\n821 \"Refusing to create empty commit. Maybe you want to amend (%s) or allow-empty (%s)?\"\n822 (key-description (car (where-is-internal\n823 'git-gutter+-commit-toggle-amending)))\n824 (key-description (car (where-is-internal\n825 'git-gutter+-commit-toggle-allow-empty))))))\n\n827 (defsubst git-gutter+-buffer-is-whitespace ()\n828 (save-excursion\n829 (goto-char (point-min))\n830 (looking-at-p \"[ \\t\\n]*\\\\'\")))\n\n832 (defun git-gutter+-publish-commit ()\n833 \"Publish commit\"\n834 (interactive)\n835 (let* ((fields (git-gutter+-commit-get-fields))\n836 (amend (equal \"yes\" (git-gutter+-commit-get-field 'amend fields)))\n837 (allow-empty (equal \"yes\" (git-gutter+-commit-get-field 'allow-empty fields)))\n838 (author (git-gutter+-commit-get-field 'author fields))\n839 (date (git-gutter+-commit-get-field 'date fields)))\n\n841 (git-gutter+-abort-commit-when-no-changes allow-empty amend)\n\n843 (git-gutter+-push-to-comment-ring (buffer-string))\n\n845 (git-gutter+-commit-set-fields nil) ; Delete message header\n\n847 (when (git-gutter+-buffer-is-whitespace)\n848 (erase-buffer)\n849 (insert \"(Empty description)\"))\n\n851 (let ((error-msg (git-gutter+-call-git-on-current-buffer\n852 (append '(\"--no-pager\" \"commit\" \"-F\" \"-\")\n853 (if amend '(\"--amend\"))\n854 (if allow-empty '(\"--allow-empty\"))\n855 (if author (list (concat \"--author=\" author)))\n856 (if date (list (concat \"--date=\" date)))))))\n857 (if error-msg\n858 (progn\n859 (message \"Commit error:\\n%s\" error-msg)\n860 (erase-buffer)\n861 (insert (ring-ref log-edit-comment-ring 0))) ; Reinsert commit message\n862 (message \"Commit successful.\")\n863 (git-gutter+-close-commit-edit-buffer)\n864 (git-gutter+-update-vc-modeline)))))\n\n866 (defun git-gutter+-close-commit-edit-buffer ()\n867 \"Abort edits and discard commit message being composed.\"\n868 (interactive)\n869 (kill-buffer)\n870 (set-window-configuration git-gutter+-pre-commit-window-config))\n\n872 (defun git-gutter+-update-vc-modeline ()\n873 (when (buffer-live-p git-gutter+-commit-origin-buffer)\n874 (with-current-buffer git-gutter+-commit-origin-buffer\n875 ;; Updating the modeline has no effect if the buffer still has\n876 ;; changes - it will remain in the 'modified' state. So skip it then.\n877 (unless git-gutter+-diffinfos\n878 (ignore-errors (vc-find-file-hook))))))\n\n880 (defun git-gutter+-stage-whole-buffer ()\n881 (save-excursion\n882 (mark-whole-buffer)\n883 (git-gutter+-stage-hunks)))\n\n885 (defun git-gutter+-anything-staged-p ()\n886 \"Return t if the current repo has staged changes\"\n887 (not (zerop (git-gutter+-call-git '(\"diff\" \"--quiet\" \"--cached\")))))\n\n889 (defun git-gutter+-commit-toggle-amending ()\n890 \"Toggle whether this will be an amendment to the previous commit.\n891 \\(i.e., whether commit is run via 'git commit --amend')\"\n892 (interactive)\n893 ;; Remove the newline that 'git-commit-mode' adds to a new commit\n894 ;; message buffer by default. This prevents an ugly visual\n895 ;; gap between the commit message header and the previous commit\n896 ;; message.\n897 (when (git-gutter+-buffer-is-whitespace)\n898 (erase-buffer))\n\n900 (let ((amend-was-already-set (git-gutter+-commit-get-field 'amend)))\n901 (git-gutter+-commit-toggle-field 'amend t)\n902 (unless amend-was-already-set\n903 ;; Insert previous commit message\n904 (goto-char (point-max))\n905 (unless (zerop (current-column))\n906 (insert \"\\n\"))\n907 (insert (git-gutter+-get-last-commit-msg)\n908 \"\\n\"))))\n\n910 (defun git-gutter+-commit-toggle-allow-empty ()\n911 \"Toggle whether this commit is allowed to be empty.\n912 \\(i.e., whether commit is run via 'git commit --allow-empty')\"\n913 (interactive)\n914 (git-gutter+-commit-toggle-field 'allow-empty t))\n\n916 (defun git-gutter+-format-author (author email)\n917 (format \"%s <%s>\" author email))\n\n919 (defun git-gutter+-commit-toggle-author ()\n920 \"Toggle whether this commit should have a user-defined author.\"\n921 (interactive)\n922 (git-gutter+-commit-toggle-input\n923 'author (git-gutter+-format-author\n924 (or (git-gutter+-get-cfg \"user\" \"name\") \"Author Name\")\n925 (or (git-gutter+-get-cfg \"user\" \"email\") \"author@email\"))))\n\n927 (defun git-gutter+-commit-toggle-date ()\n928 \"Toggle whether this commit should have a user-defined date.\"\n929 (interactive)\n930 (git-gutter+-commit-toggle-input 'date\n931 ;; ISO 8601\n932 (format-time-string \"%Y-%m-%dT%T%z\" (current-time))))\n\n934 (defun git-gutter+-push-to-comment-ring (comment)\n935 (when (or (ring-empty-p log-edit-comment-ring)\n936 (not (equal comment (ring-ref log-edit-comment-ring 0))))\n937 (ring-insert log-edit-comment-ring comment)))\n\n939 (defun git-gutter+-get-last-commit-msg ()\n940 (git-gutter+-git-output '(\"log\" \"--max-count=1\" \"--pretty=format:%s%n%n%b\" \"HEAD\")))\n\n942 (defun git-gutter+-get-cfg (&rest keys)\n943 (git-gutter+-git-output (list \"config\" (mapconcat 'identity keys \".\"))))\n\n945 (defun git-gutter+-git-output (args)\n946 (with-temp-buffer\n947 (git-gutter+-call-git args)\n948 ;; Delete trailing newlines\n949 (goto-char (point-min))\n950 (if (re-search-forward \"\\n+\\\\'\" nil t)\n951 (replace-match \"\"))\n952 (buffer-string)))\n\n\n955 ;;; Commit message header\n\n957 (defconst git-gutter+-commit-header-end \"-- End of commit options header --\\n\")\n\n959 (defun git-gutter+-commit-get-field (name &optional fields)\n960 (cdr (assq name (or fields (git-gutter+-commit-get-fields)))))\n\n962 (defun git-gutter+-commit-set-field (name value)\n963 (let* ((fields (git-gutter+-commit-get-fields))\n964 (cell (assq name fields)))\n965 (cond (cell\n966 (if value\n967 (rplacd cell value)\n968 (setq fields (delq cell fields))))\n969 (t\n970 (if value\n971 (setq fields (append fields (list (cons name value)))))))\n972 (git-gutter+-commit-set-fields fields)))\n\n974 (defun git-gutter+-commit-toggle-field (name default)\n975 \"Toggle the commit header field named NAME.\n976 If it's currently unset, set it to DEFAULT (t or nil).\"\n977 (let* ((fields (git-gutter+-commit-get-fields))\n978 (cell (assq name fields)))\n979 (if cell\n980 (rplacd cell (if (equal (cdr cell) \"yes\") \"no\" \"yes\"))\n981 (setq fields (acons name (if default \"yes\" \"no\") fields)))\n982 (git-gutter+-commit-set-fields fields)))\n\n984 (defun git-gutter+-commit-toggle-input (name default)\n985 \"Toggle the commit header input named NAME.\n986 If it's currently unset, set it to DEFAULT (a string). If it is\n987 set remove it.\"\n988 (let* ((fields (git-gutter+-commit-get-fields))\n989 (cell (assq name fields)))\n990 (if cell\n991 (setq fields (assq-delete-all name fields))\n992 (setq fields (acons name default fields)))\n993 (git-gutter+-commit-set-fields fields)))\n\n995 (defun git-gutter+-commit-get-fields ()\n996 (let (result)\n997 (goto-char (point-min))\n998 (while (looking-at \"^\\\\([A-Za-z0-9-_]+\\\\): *\\\\(.+\\\\)?$\")\n999 (let ((name (intern (downcase (match-string 1))))\n1000 (value (read (or (match-string 2) \"nil\"))))\n1001 (push (cons name value) result))\n1002 (forward-line))\n1003 (if (looking-at (regexp-quote git-gutter+-commit-header-end))\n1004 (nreverse result))))\n\n1006 (defun git-gutter+-commit-set-fields (fields)\n1007 (goto-char (point-min))\n1008 ;; Delete commit header\n1009 (if (search-forward-regexp (format \"^\\\\(?:[A-Za-z0-9-_]+:.*\\n\\\\)*%s\"\n1010 (regexp-quote git-gutter+-commit-header-end))\n1011 nil t)\n1012 (delete-region (match-beginning 0) (match-end 0)))\n1013 (goto-char (point-min))\n1014 (when fields\n1015 (dolist (field fields)\n1016 (insert (capitalize (symbol-name (car field))) \": \"\n1017 (prin1-to-string (cdr field)) \"\\n\"))\n1018 (insert git-gutter+-commit-header-end)))\n\n\n1021 ;;; git-gutter+-commit-mode\n1022 ;; Like git-commit-mode, but adds keybindings to git-gutter+ commands and\n1023 ;; highlighting support for the commit message header.\n\n1025 (define-derived-mode git-gutter+-commit-mode git-commit-mode \"Git-Gutter-Commit\"\n1026 (setq font-lock-defaults (list (git-gutter+-commit-font-lock-keywords) t)))\n\n1028 (setq git-gutter+-commit-mode-map\n1029 (let ((map (copy-keymap git-commit-mode-map)))\n1030 (define-key map (kbd \"C-c C-c\") 'git-gutter+-publish-commit)\n1031 (define-key map (kbd \"C-c C-k\") 'git-gutter+-close-commit-edit-buffer)\n1032 (define-key map (kbd \"C-c C-a\") 'git-gutter+-commit-toggle-amending)\n1033 (define-key map (kbd \"C-c C-e\") 'git-gutter+-commit-toggle-allow-empty)\n1034 (define-key map (kbd \"C-c C-u\") 'git-gutter+-commit-toggle-author)\n1035 (define-key map (kbd \"C-c C-d\") 'git-gutter+-commit-toggle-date)\n1036 (define-key map (kbd \"C-c C-b\") 'git-commit-ack)\n1037 (define-key map (kbd \"M-p\") 'log-edit-previous-comment)\n1038 (define-key map (kbd \"M-n\") 'log-edit-next-comment)\n1039 map))\n\n1041 (defface git-gutter+-commit-header-face\n1042 '((t :inherit font-lock-comment-face))\n1043 \"Highlights the commit message header\"\n1044 :group 'git-gutter+-faces)\n\n1046 (defconst git-gutter+-commit-header-regex\n1047 (concat \"\\\\(?:.\\\\|\\n\\\\)*?\" (regexp-quote git-gutter+-commit-header-end)))\n\n1049 (defconst git-gutter+-skip-commit-header-regex\n1050 (concat \"\\\\`\\\\(?:\" git-gutter+-commit-header-regex \"\\\\)?\"))\n\n1052 ;; Modify git-commit-summary-regexp to ignore the commit header\n1053 (defadvice git-commit-summary-regexp\n1054 (after ignore-git-gutter+-commit-header activate compile)\n1055 (if (eq major-mode 'git-gutter+-commit-mode)\n1056 (setq ad-return-value\n1057 (concat git-gutter+-skip-commit-header-regex\n1058 (substring ; Remove leading \"\\\\`\"\n1059 ad-return-value 2)))))\n\n1061 (defun git-gutter+-commit-font-lock-keywords ()\n1062 \"Like `git-commit-mode-font-lock-keywords' but with commit header highlighting\"\n1063 `((,(concat \"\\\\`\" git-gutter+-commit-header-regex) . 'git-gutter+-commit-header-face)\n1064 ,@(git-commit-mode-font-lock-keywords)))\n\n\n1067 ;;; Magit synchronization\n1068 ;; Force Magit to refresh git-gutter+ when updating the VC mode line.\n\n1070 (defvar git-gutter+-orig-vc-find-file-hook)\n\n1072 (defvar git-gutter+-vc-find-file-hook-with-refresh\n1073 (lambda ()\n1074 (funcall git-gutter+-orig-vc-find-file-hook)\n1075 (if git-gutter+-mode (git-gutter+-refresh))))\n\n1077 (defadvice magit-update-vc-modeline (around refresh-git-gutter+ compile activate)\n1078 ;; `magit-update-vc-modeline' calls `vc-find-file-hook' (a function!) on each\n1079 ;; buffer in the repo. Temporarily rebind it to `vc-find-file-hook-with-refresh',\n1080 ;; which calls git-gutter+-refresh after updating the VC mode line.\n1081 ;;\n1082 ;; Using `flet' would have been much simpler, but it's deprecated since 24.3.\n1083 (setq git-gutter+-orig-vc-find-file-hook (symbol-function 'vc-find-file-hook))\n1084 (fset 'vc-find-file-hook git-gutter+-vc-find-file-hook-with-refresh)\n1085 (unwind-protect\n1086 ad-do-it\n1087 (fset 'vc-find-file-hook git-gutter+-orig-vc-find-file-hook)))\n\n1089 (provide 'git-gutter+)\n\n1091 ;;; git-gutter+.el ends here\n")) (setq helm-swoop-cache t))) (candidates-in-buffer) (get-line . buffer-substring-no-properties) (keymap keymap (C-M-left . backward-sexp) (C-M-right . forward-sexp) (27 keymap (105 . helm-multi-swoop-all-from-helm-swoop)) (3 keymap (5 . helm-swoop-edit)) keymap (C-M-left . paren-backward-sexp) (C-M-right . paren-forward-sexp) (94 . helm-swoop-caret-match) (menu-bar keymap (help-menu keymap (describe keymap (describe-mode . helm-help)))) (help keymap (109 . helm-help)) (f1 keymap (109 . helm-help)) (8 keymap (109 . helm-help) (104 . undefined) (8 . undefined) (4 . helm-debug-output)) (20 . helm-toggle-resplit-and-swap-windows) (C-tab . undefined) (triple-mouse-3 . ignore) (double-mouse-3 . ignore) (mouse-3 . ignore) (drag-mouse-3 . ignore) (down-mouse-3 . ignore) (triple-mouse-2 . ignore) (double-mouse-2 . ignore) (mouse-2 . ignore) (drag-mouse-2 . ignore) (down-mouse-2 . ignore) (triple-mouse-1 . ignore) (double-mouse-1 . ignore) (mouse-1 . ignore) (drag-mouse-1 . ignore) (down-mouse-1 . ignore) (67108897 . helm-toggle-suspend-update) (3 keymap (21 . helm-force-update) (6 . helm-follow-mode) (11 . helm-kill-selection-and-quit) (25 . helm-yank-selection) (4 . helm-delete-current-selection) (45 . helm-swap-windows)) (67108987 . helm-enlarge-window) (67108989 . helm-narrow-window) (19 . undefined) (18 . undefined) (23 . helm-yank-text-at-point) (24 keymap (2 . helm-resume-list-buffers-after-quit) (98 . helm-resume-previous-session-after-quit) (6 . helm-quit-and-find-file)) (11 . helm-delete-minibuffer-contents) (67108896 . helm-toggle-visible-mark) (0 . helm-toggle-visible-mark) (C-M-up . helm-scroll-other-window-down) (C-M-down . helm-scroll-other-window) (M-prior . helm-scroll-other-window-down) (M-next . helm-scroll-other-window) (12 . helm-recenter-top-bottom-other-window) (15 . helm-next-source) (10 . helm-select-3rd-action) (5 . helm-select-2nd-action-or-end-of-line) ...) (header-line . "[C-c C-e] Edit mode, [M-i] apply all buffers") (action lambda ($line) (helm-swoop--goto-line (when (string-match "^[0-9]+" $line) (string-to-number (match-string 0 $line)))) (when (re-search-forward (mapconcat (quote identity) (split-string helm-pattern " ") "\\|") nil t) (goto-char (match-beginning 0))) (helm-swoop--recenter)) (migemo)) #("git-gutter+-refresh" 0 19 (fontified t face whitespace-line)) "Swoop: " nil "^368 " "*Helm Swoop*" nil nil nil))
helm(((name . "git-gutter+.el") (init lambda nil (unless helm-swoop-cache (with-current-buffer (helm-candidate-buffer (quote local)) (insert "1 ;;; git-gutter+.el --- Manage Git hunks straight from the buffer\n\n3 ;; Copyright (C) 2013 by Syohei YOSHIDA and contributors\n\n5 ;; Author: Syohei YOSHIDA <syohex@gmail.com> and contributors\n6 ;; URL: https://github.com/nonsequitur/git-gutter-plus\n7 ;; Version: 0.1\n\n9 ;; This program is free software; you can redistribute it and/or modify\n10 ;; it under the terms of the GNU General Public License as published by\n11 ;; the Free Software Foundation, either version 3 of the License, or\n12 ;; (at your option) any later version.\n\n14 ;; This program is distributed in the hope that it will be useful,\n15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of\n16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n17 ;; GNU General Public License for more details.\n\n19 ;; You should have received a copy of the GNU General Public License\n20 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n22 ;; Package-Requires: ((git-commit-mode \"0.14\"))\n\n24 ;;; Commentary:\n25 ;;\n26 ;; View, stage and revert Git changes straight from the buffer.\n\n28 ;;; Code:\n\n30 (eval-when-compile\n31 (require 'cl))\n\n33 (require 'tramp)\n34 (require 'log-edit)\n35 (require 'git-commit-mode)\n\n37 (defgroup git-gutter+ nil\n38 \"Manage Git hunks straight from the buffer\"\n39 :prefix \"git-gutter+-\"\n40 :group 'vc)\n\n42 (defcustom git-gutter+-window-width nil\n43 \"Character width of the gutter margin. Set this variable if the automatically\n44 calculated width looks wrong. (This can happen with some special characters.)\"\n45 :type 'integer\n46 :group 'git-gutter+)\n\n48 (defcustom git-gutter+-git-executable \"git\"\n49 \"The path of the Git executable.\"\n50 :type 'string\n51 :group 'git-gutter+)\n\n53 (defcustom git-gutter+-diff-options nil\n54 \"List of strings containing extra arguments to 'git diff'\"\n55 :type 'list\n56 :group 'git-gutter+)\n\n58 (defcustom git-gutter+-separator-sign nil\n59 \"Separator sign\"\n60 :type 'string\n61 :group 'git-gutter+)\n\n63 (defcustom git-gutter+-modified-sign \"=\"\n64 \"Modified sign\"\n65 :type 'string\n66 :group 'git-gutter+)\n\n68 (defcustom git-gutter+-added-sign \"+\"\n69 \"Added sign\"\n70 :type 'string\n71 :group 'git-gutter+)\n\n73 (defcustom git-gutter+-deleted-sign \"-\"\n74 \"Deleted sign\"\n75 :type 'string\n76 :group 'git-gutter+)\n\n78 (defcustom git-gutter+-unchanged-sign nil\n79 \"Unchanged sign\"\n80 :type 'string\n81 :group 'git-gutter+)\n\n83 (defcustom git-gutter+-hide-gutter nil\n84 \"Hide gutter if there are no changes\"\n85 :type 'boolean\n86 :group 'git-gutter+)\n\n88 (defcustom git-gutter+-lighter \" GitGutter\"\n89 \"Minor mode lighter in mode-line\"\n90 :type 'string\n91 :group 'git-gutter+)\n\n93 (defface git-gutter+-separator\n94 '((t (:foreground \"cyan\" :weight bold)))\n95 \"Face of the separator\"\n96 :group 'git-gutter+)\n\n98 (defface git-gutter+-modified\n99 '((t (:foreground \"magenta\" :weight bold)))\n100 \"Face for modified lines\"\n101 :group 'git-gutter+)\n\n103 (defface git-gutter+-added\n104 '((t (:foreground \"green\" :weight bold)))\n105 \"Face for added lines\"\n106 :group 'git-gutter+)\n\n108 (defface git-gutter+-deleted\n109 '((t (:foreground \"red\" :weight bold)))\n110 \"Face for deleted lines\"\n111 :group 'git-gutter+)\n\n113 (defface git-gutter+-unchanged\n114 '((t (:background \"yellow\")))\n115 \"Face for unchanged lines\"\n116 :group 'git-gutter+)\n\n118 (defcustom git-gutter+-disabled-modes nil\n119 \"A list of modes for which `global-git-gutter+-mode' should be disabled.\"\n120 :type '(repeat symbol)\n121 :group 'git-gutter+)\n\n123 (defvar git-gutter+-mode-map\n124 (make-sparse-keymap))\n\n126 (defvar git-gutter+-view-diff-function nil\n127 \"Function to call for displaying diffs\")\n\n129 (defvar git-gutter+-clear-function nil\n130 \"Function to call for clearing the diff display\")\n\n132 (defvar git-gutter+-window-config-change-function nil\n133 \"Function to call when the buffer's local window configuration has changed\")\n\n135 (defvar git-gutter+-diffinfos nil)\n136 (defvar git-gutter+-diff-header nil)\n137 (make-variable-buffer-local 'git-gutter+-diffinfos)\n138 (make-variable-buffer-local 'git-gutter+-diff-header)\n\n140 (defvar git-gutter+-popup-buffer \"*git-gutter+-diff*\")\n141 (defvar git-gutter+-buffers-to-reenable nil)\n\n143 (defconst git-gutter+-hunk-header-regex\n144 ;; The same as diff-hunk-header-re-unified\n145 \"^@@ -\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? \\\\+\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? @@\")\n\n147 (defalias 'git-gutter+-popup-hunk 'git-gutter+-show-hunk)\n148 (defalias 'git-gutter+-revert-hunk 'git-gutter+-revert-hunks)\n\n150 (defmacro git-gutter+-awhen (test &rest body)\n151 \"Anaphoric when.\"\n152 (declare (indent 1))\n153 `(let ((it ,test))\n154 (when it ,@body)))\n\n156 (defun git-gutter+-enable-default-display-mode ()\n157 (setq git-gutter+-view-diff-function 'git-gutter+-view-diff-infos\n158 git-gutter+-clear-function 'git-gutter+-clear-diff-infos\n159 git-gutter+-window-config-change-function 'git-gutter+-show-gutter))\n\n161 (unless git-gutter+-view-diff-function\n162 (git-gutter+-enable-default-display-mode))\n\n164 (defun git-gutter+-call-git (args &optional file)\n165 (if (and file (file-remote-p file))\n166 (apply #'process-file git-gutter+-git-executable nil t nil args)\n167 (apply #'call-process git-gutter+-git-executable nil t nil args)))\n\n169 (defun git-gutter+-in-git-repository-p (file)\n170 (with-temp-buffer\n171 (let ((args '(\"rev-parse\" \"--is-inside-work-tree\")))\n172 (when (zerop (git-gutter+-call-git args file))\n173 (goto-char (point-min))\n174 (string= \"true\" (buffer-substring-no-properties\n175 (point) (line-end-position)))))))\n\n177 (defun git-gutter+-root-directory (file)\n178 (with-temp-buffer\n179 (let* ((args '(\"rev-parse\" \"--show-toplevel\"))\n180 (ret (git-gutter+-call-git args file)))\n181 (when (zerop ret)\n182 (goto-char (point-min))\n183 (let ((root (buffer-substring-no-properties (point) (line-end-position))))\n184 (unless (string= root \"\")\n185 (file-name-as-directory root)))))))\n\n187 (defsubst git-gutter+-diff-args (file)\n188 (delq nil (list \"--no-pager\" \"diff\" \"--no-color\" \"--no-ext-diff\" \"-U0\"\n189 git-gutter+-diff-options file)))\n\n191 (defun git-gutter+-diff (curfile)\n192 (let ((args (git-gutter+-diff-args curfile))\n193 (file (buffer-file-name))) ;; for tramp\n194 (with-temp-buffer\n195 (when (zerop (git-gutter+-call-git args file))\n196 (goto-char (point-min))\n197 (let ((diff-header (git-gutter+-get-diff-header))\n198 (diffinfos (git-gutter+-get-diffinfos)))\n199 (list diff-header diffinfos))))))\n\n201 (defun git-gutter+-get-diff-header ()\n202 (save-excursion\n203 (if (re-search-forward git-gutter+-hunk-header-regex nil t)\n204 (buffer-substring (point-min) (match-beginning 0)))))\n\n206 (defsubst git-gutter+-make-diffinfo (type content start end)\n207 (list :type type :content content :start-line start :end-line end))\n\n209 (defun git-gutter+-get-diffinfos ()\n210 (loop while (re-search-forward git-gutter+-hunk-header-regex nil t)\n211 ;; Hunk header format:\n212 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n213 for del-len = (string-to-number (or (match-string 2) \"1\"))\n214 for add-line = (string-to-number (match-string 3))\n215 for add-len = (string-to-number (or (match-string 4) \"1\"))\n216 for type = (cond ((zerop del-len) 'added)\n217 ((zerop add-len) 'deleted)\n218 (t 'modified))\n219 for start-line = (if (eq type 'deleted)\n220 (1+ add-line)\n221 add-line)\n222 for end-line = (if (eq type 'deleted)\n223 start-line\n224 (1- (+ add-line add-len)))\n225 for content = (git-gutter+-diff-content)\n226 collect\n227 (git-gutter+-make-diffinfo type content start-line end-line)))\n\n229 (defun git-gutter+-diff-content ()\n230 (save-excursion\n231 (goto-char (line-beginning-position)) ; Move to beginning of hunk header\n232 (let ((hunk-start (point)))\n233 ;; Move to end of hunk\n234 (forward-line 1)\n235 (if (re-search-forward \"^@@\" nil t)\n236 (backward-char 3) ;; exclude \"\\n@@\"\n237 (goto-char (1- (point-max)))) ; Skip trailing newline\n238 (buffer-substring hunk-start (point)))))\n\n240 (defun git-gutter+-line-to-pos (line)\n241 (save-excursion\n242 (goto-char (point-min))\n243 (forward-line (1- line))\n244 (point)))\n\n246 (defun git-gutter+-before-string (sign)\n247 (let* ((sep-sign git-gutter+-separator-sign)\n248 (sep (when sep-sign\n249 (propertize sep-sign 'face 'git-gutter+-separator)))\n250 (gutter-sep (concat sign sep)))\n251 (propertize \" \" 'display `((margin left-margin) ,gutter-sep))))\n\n253 (defsubst git-gutter+-select-face (type)\n254 (case type\n255 (added 'git-gutter+-added)\n256 (modified 'git-gutter+-modified)\n257 (deleted 'git-gutter+-deleted)))\n\n259 (defsubst git-gutter+-select-sign (type)\n260 (case type\n261 (added git-gutter+-added-sign)\n262 (modified git-gutter+-modified-sign)\n263 (deleted git-gutter+-deleted-sign)))\n\n265 (defun git-gutter+-propertized-sign (type)\n266 (let ((sign (git-gutter+-select-sign type))\n267 (face (git-gutter+-select-face type)))\n268 (propertize sign 'face face)))\n\n270 (defun git-gutter+-view-region (sign start-line end-line)\n271 (let ((beg (git-gutter+-line-to-pos start-line)))\n272 (goto-char beg)\n273 (while (and (<= (line-number-at-pos) end-line) (not (eobp)))\n274 (git-gutter+-view-at-pos sign (point))\n275 (forward-line 1))))\n\n277 (defun git-gutter+-view-at-pos (sign pos)\n278 (let ((ov (make-overlay pos pos)))\n279 (overlay-put ov 'before-string (git-gutter+-before-string sign))\n280 (overlay-put ov 'git-gutter+ t)))\n\n282 (defun git-gutter+-view-diff-info (diffinfo)\n283 (let* ((start-line (plist-get diffinfo :start-line))\n284 (end-line (plist-get diffinfo :end-line))\n285 (type (plist-get diffinfo :type))\n286 (sign (git-gutter+-propertized-sign type)))\n287 (case type\n288 ((modified added) (git-gutter+-view-region sign start-line end-line))\n289 (deleted (git-gutter+-view-at-pos\n290 sign (git-gutter+-line-to-pos start-line))))))\n\n292 (defun git-gutter+-sign-width (sign)\n293 (loop for s across sign\n294 sum (char-width s)))\n\n296 (defun git-gutter+-longest-sign-width ()\n297 (let ((signs (list git-gutter+-modified-sign\n298 git-gutter+-added-sign\n299 git-gutter+-deleted-sign)))\n300 (when git-gutter+-unchanged-sign\n301 (add-to-list 'signs git-gutter+-unchanged-sign))\n302 (+ (apply 'max (mapcar 'git-gutter+-sign-width signs))\n303 (git-gutter+-sign-width git-gutter+-separator-sign))))\n\n305 (defun git-gutter+-view-for-unchanged ()\n306 (save-excursion\n307 (let ((sign (if git-gutter+-unchanged-sign\n308 (propertize git-gutter+-unchanged-sign\n309 'face 'git-gutter+-unchanged)\n310 \" \")))\n311 (goto-char (point-min))\n312 (while (not (eobp))\n313 (git-gutter+-view-at-pos sign (point))\n314 (forward-line 1)))))\n\n316 (defun git-gutter+-set-window-margin (width)\n317 (let ((curwin (get-buffer-window)))\n318 (set-window-margins curwin width (cdr (window-margins curwin)))))\n\n320 (defsubst git-gutter+-file-buffer-p ()\n321 (and (buffer-file-name)\n322 default-directory\n323 (file-directory-p default-directory)))\n\n325 ;;;###autoload\n326 (define-minor-mode git-gutter+-mode\n327 \"Git-Gutter mode\"\n328 :group 'git-gutter+\n329 :init-value nil\n330 :global nil\n331 :lighter git-gutter+-lighter\n332 (if git-gutter+-mode\n333 (if (and (git-gutter+-file-buffer-p)\n334 (git-gutter+-in-git-repository-p (buffer-file-name)))\n335 (progn\n336 (git-gutter+-add-local-hooks)\n337 (git-gutter+-refresh))\n338 (if (called-interactively-p 'any)\n339 (message \"No Git repo for current buffer\"))\n340 (git-gutter+-mode -1))\n341 (git-gutter+-remove-local-hooks)\n342 (git-gutter+-clear)))\n\n344 (defun git-gutter+-add-local-hooks ()\n345 (add-hook 'after-save-hook 'git-gutter+-refresh nil t)\n346 ;; Turn off `git-gutter+-mode' while reverting to prevent any redundant calls to\n347 ;; `git-gutter+-refresh'.\n348 (add-hook 'before-revert-hook 'git-gutter+-turn-off nil t)\n349 (add-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change nil t)\n350 (if git-gutter+-window-config-change-function\n351 (add-hook 'window-configuration-change-hook\n352 git-gutter+-window-config-change-function nil t)))\n\n354 (defun git-gutter+-remove-local-hooks ()\n355 (remove-hook 'after-save-hook 'git-gutter+-refresh t)\n356 (remove-hook 'before-revert-hook 'git-gutter+-turn-off t)\n357 (remove-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change t)\n358 (if git-gutter+-window-config-change-function\n359 (remove-hook 'window-configuration-change-hook\n360 git-gutter+-window-config-change-function t)))\n\n362 (defmacro git-gutter+-in-all-buffers (&rest body)\n363 `(dolist (buf (buffer-list))\n364 (with-current-buffer buf\n365 ,@body)))\n\n367 ;; When `define-globalized-minor-mode' is used to define `global-git-gutter+-mode',\n368 ;; `git-gutter+-mode' and thus `git-gutter+-refresh' get run twice when a new file\n369 ;; is opened. (First for `fundamental-mode', then for the file-specific mode.)\n370 ;; The following definition of `global-git-gutter+-mode' avoids any redundant calls to\n371 ;; `git-gutter+-refresh'.\n\n373 ;;;###autoload\n374 (define-minor-mode global-git-gutter+-mode ()\n375 \"Global Git-Gutter mode\"\n376 :group 'git-gutter+\n377 :init-value nil\n378 :global t\n379 (if global-git-gutter+-mode\n380 (progn\n381 (add-hook 'find-file-hook 'git-gutter+-turn-on)\n382 (add-hook 'after-revert-hook 'git-gutter+-turn-on)\n383 (add-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n384 (git-gutter+-in-all-buffers (git-gutter+-turn-on)))\n385 (remove-hook 'find-file-hook 'git-gutter+-turn-on)\n386 (remove-hook 'after-revert-hook 'git-gutter+-turn-on)\n387 (remove-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n388 (git-gutter+-in-all-buffers (git-gutter+-turn-off))))\n\n390 (defun git-gutter+-turn-on ()\n391 (when (and (buffer-file-name)\n392 (not (memq major-mode git-gutter+-disabled-modes))\n393 (not git-gutter+-mode))\n394 (git-gutter+-mode t)))\n\n396 (defun git-gutter+-turn-off ()\n397 (if git-gutter+-mode (git-gutter+-mode -1)))\n\n399 (defun git-gutter+-reenable-after-major-mode-change ()\n400 (if global-git-gutter+-mode\n401 (add-to-list 'git-gutter+-buffers-to-reenable (current-buffer))))\n\n403 (defun git-gutter+-reenable-buffers ()\n404 (dolist (buf git-gutter+-buffers-to-reenable)\n405 (with-current-buffer buf\n406 (git-gutter+-turn-on)))\n407 (setq git-gutter+-buffers-to-reenable nil))\n\n409 (defsubst git-gutter+-show-gutter-p (diffinfos)\n410 (if git-gutter+-hide-gutter\n411 (or diffinfos git-gutter+-unchanged-sign)\n412 (or global-git-gutter+-mode git-gutter+-unchanged-sign diffinfos)))\n\n414 (defun git-gutter+-show-gutter (&optional diffinfos)\n415 (when (git-gutter+-show-gutter-p (or diffinfos git-gutter+-diffinfos))\n416 (let ((win-width (or git-gutter+-window-width\n417 (git-gutter+-longest-sign-width))))\n418 (git-gutter+-set-window-margin win-width))))\n\n420 (defun git-gutter+-view-diff-infos (diffinfos)\n421 (when (or git-gutter+-unchanged-sign\n422 git-gutter+-separator-sign)\n423 (git-gutter+-view-for-unchanged))\n424 (when diffinfos\n425 (save-excursion\n426 (mapc 'git-gutter+-view-diff-info diffinfos)))\n427 (git-gutter+-show-gutter diffinfos))\n\n429 (defsubst git-gutter+-reset-window-margin-p ()\n430 (or git-gutter+-hide-gutter\n431 (not global-git-gutter+-mode)))\n\n433 (defun git-gutter+-clear-diff-infos ()\n434 (when (git-gutter+-reset-window-margin-p)\n435 (git-gutter+-set-window-margin 0))\n436 (remove-overlays (point-min) (point-max) 'git-gutter+ t))\n\n438 (defun git-gutter+-process-diff (curfile)\n439 (destructuring-bind\n440 (diff-header diffinfos) (git-gutter+-diff curfile)\n441 (setq git-gutter+-diff-header diff-header\n442 git-gutter+-diffinfos diffinfos)\n443 (save-restriction\n444 (widen)\n445 (funcall git-gutter+-view-diff-function diffinfos))))\n\n447 (defun git-gutter+-search-near-diff-index (diffinfos is-reverse)\n448 (loop with current-line = (line-number-at-pos)\n449 with cmp-fn = (if is-reverse '> '<)\n450 for diffinfo in (if is-reverse (reverse diffinfos) diffinfos)\n451 for index = 0 then (1+ index)\n452 for start-line = (plist-get diffinfo :start-line)\n453 when (funcall cmp-fn current-line start-line)\n454 return (if is-reverse\n455 (1- (- (length diffinfos) index))\n456 index)))\n\n458 (defun git-gutter+-diffinfo-at-point ()\n459 (save-restriction\n460 (widen)\n461 (loop with current-line = (line-number-at-pos)\n462 for diffinfo in git-gutter+-diffinfos\n463 for start = (plist-get diffinfo :start-line)\n464 for end = (or (plist-get diffinfo :end-line) (1+ start))\n465 when (and (>= current-line start) (<= current-line end))\n466 return diffinfo)))\n\n468 (defun git-gutter+-collect-deleted-line (str)\n469 (with-temp-buffer\n470 (insert str)\n471 (goto-char (point-min))\n472 (loop while (re-search-forward \"^-\\\\(.*?\\\\)$\" nil t)\n473 collect (match-string 1) into deleted-lines\n474 finally return deleted-lines)))\n\n476 (defun git-gutter+-delete-added-lines (start-line end-line)\n477 (forward-line (1- start-line))\n478 (let ((start-point (point)))\n479 (forward-line (1+ (- end-line start-line)))\n480 (delete-region start-point (point))))\n\n482 (defun git-gutter+-insert-deleted-lines (content)\n483 (dolist (line (git-gutter+-collect-deleted-line content))\n484 (insert (concat line \"\\n\"))))\n\n486 (defun git-gutter+-do-revert-hunk (diffinfo)\n487 (save-excursion\n488 (save-restriction\n489 (widen)\n490 (goto-char (point-min))\n491 (let ((start-line (plist-get diffinfo :start-line))\n492 (end-line (plist-get diffinfo :end-line))\n493 (content (plist-get diffinfo :content)))\n494 (case (plist-get diffinfo :type)\n495 (added (git-gutter+-delete-added-lines start-line end-line))\n496 (deleted (forward-line (1- start-line))\n497 (git-gutter+-insert-deleted-lines content))\n498 (modified (git-gutter+-delete-added-lines start-line end-line)\n499 (git-gutter+-insert-deleted-lines content)))))))\n\n501 (defun git-gutter+-revert-hunks ()\n502 \"Revert hunk at point. If region is active, revert all hunks within the region.\"\n503 (interactive)\n504 (let* ((diffinfos (git-gutter+-selected-diffinfos))\n505 (one-diffinfo-p (= 1 (length diffinfos))))\n506 (save-window-excursion\n507 (if one-diffinfo-p (git-gutter+-show-hunk (car diffinfos)))\n508 (when (and diffinfos\n509 (yes-or-no-p (if one-diffinfo-p\n510 \"Revert hunk?\"\n511 (format \"Revert %d hunks?\" (length diffinfos)))))\n512 ;; Revert diffinfos in reverse so that earlier hunks don't invalidate the\n513 ;; line number information of the later hunks.\n514 (dolist (diffinfo (nreverse diffinfos))\n515 (git-gutter+-do-revert-hunk diffinfo))\n516 (save-buffer))\n517 (if one-diffinfo-p\n518 (git-gutter+-awhen (get-buffer git-gutter+-popup-buffer)\n519 (kill-buffer it))))))\n\n521 (defun git-gutter+-show-hunk (&optional diffinfo)\n522 \"Show hunk at point in another window\"\n523 (interactive)\n524 (git-gutter+-awhen (or diffinfo\n525 (git-gutter+-diffinfo-at-point))\n526 (save-selected-window\n527 (with-current-buffer (get-buffer-create git-gutter+-popup-buffer)\n528 (setq buffer-read-only nil)\n529 (erase-buffer)\n530 (insert (plist-get it :content))\n531 (insert \"\\n\")\n532 (goto-char (point-min))\n533 (diff-mode)\n534 (view-mode)\n535 (pop-to-buffer (current-buffer))))))\n\n537 (defun git-gutter+-next-hunk (arg)\n538 \"Move to next diff hunk\"\n539 (interactive \"p\")\n540 (if (not git-gutter+-diffinfos)\n541 (message \"No changes in buffer\")\n542 (save-restriction\n543 (widen)\n544 (let* ((is-reverse (< arg 0))\n545 (diffinfos git-gutter+-diffinfos)\n546 (len (length diffinfos))\n547 (index (git-gutter+-search-near-diff-index diffinfos is-reverse))\n548 (real-index (if index\n549 (let ((next (if is-reverse (1+ index) (1- index))))\n550 (mod (+ arg next) len))\n551 (if is-reverse (1- (length diffinfos)) 0)))\n552 (diffinfo (nth real-index diffinfos)))\n553 (goto-char (point-min))\n554 (forward-line (1- (plist-get diffinfo :start-line)))\n555 (when (buffer-live-p (get-buffer git-gutter+-popup-buffer))\n556 (save-window-excursion\n557 (git-gutter+-show-hunk)))))))\n\n559 (defun git-gutter+-previous-hunk (arg)\n560 \"Move to previous diff hunk\"\n561 (interactive \"p\")\n562 (git-gutter+-next-hunk (- arg)))\n\n564 (defun git-gutter+-remote-default-directory (dir file)\n565 (let* ((vec (tramp-dissect-file-name file))\n566 (method (aref vec 0))\n567 (user (aref vec 1))\n568 (host (aref vec 2)))\n569 (format \"/%s:%s%s:%s\" method (if user (concat user \"@\") \"\") host dir)))\n\n571 (defun git-gutter+-remote-file-path (dir file)\n572 (let ((file (aref (tramp-dissect-file-name file) 3)))\n573 (replace-regexp-in-string (concat \"\\\\`\" dir) \"\" file)))\n\n575 (defun git-gutter+-local-file-path (file)\n576 (if (eq system-type 'windows-nt)\n577 ;; Cygwin can't handle Windows absolute paths\n578 (file-relative-name file default-directory)\n579 file))\n\n581 (defun git-gutter+-refresh ()\n582 (git-gutter+-clear)\n583 (let ((file (buffer-file-name)))\n584 (when (and file (file-exists-p file))\n585 (if (file-remote-p file)\n586 (let* ((repo-root (git-gutter+-root-directory file))\n587 (default-directory (git-gutter+-remote-default-directory repo-root file)))\n588 (git-gutter+-process-diff (git-gutter+-remote-file-path repo-root file)))\n589 (git-gutter+-process-diff (git-gutter+-local-file-path file))))))\n\n591 (defun git-gutter+-clear ()\n592 (save-restriction\n593 (widen)\n594 (funcall git-gutter+-clear-function))\n595 (setq git-gutter+-diffinfos nil))\n\n\n598 ;;; Staging\n\n600 (defun git-gutter+-stage-hunks ()\n601 \"Stage hunk at point. If region is active, stage all hunk lines within the region.\"\n602 (interactive)\n603 (let* ((line-range (if (use-region-p)\n604 (cons (line-number-at-pos (region-beginning))\n605 (line-number-at-pos (region-end)))))\n606 (diffinfos (git-gutter+-selected-diffinfos line-range)))\n607 (when diffinfos\n608 (let ((error-msg (git-gutter+-stage-diffinfos diffinfos line-range)))\n609 (if error-msg\n610 (message \"Error staging hunks:\\n%s\" error-msg))\n611 (git-gutter+-refresh)))))\n\n613 (defun git-gutter+-selected-diffinfos (&optional line-range)\n614 (unless line-range\n615 (setq line-range (if (use-region-p)\n616 (cons (line-number-at-pos (region-beginning))\n617 (line-number-at-pos (region-end))))))\n618 (if line-range\n619 (git-gutter+-diffinfos-between-lines line-range)\n620 (git-gutter+-awhen (git-gutter+-diffinfo-at-point)\n621 (list it))))\n\n623 (defsubst git-gutter+-diffinfo-between-lines-p (diffinfo start-line end-line)\n624 (let ((diff-start (plist-get diffinfo :start-line))\n625 (diff-end (plist-get diffinfo :end-line)))\n626 (and (<= start-line diff-end)\n627 (<= diff-start end-line))))\n\n629 (defun git-gutter+-diffinfos-between-lines (line-range)\n630 (save-restriction\n631 (widen)\n632 (let ((start-line (car line-range))\n633 (end-line (cdr line-range)))\n634 (delq nil\n635 (mapcar (lambda (diffinfo)\n636 (if (git-gutter+-diffinfo-between-lines-p\n637 diffinfo start-line end-line)\n638 diffinfo))\n639 git-gutter+-diffinfos)))))\n\n641 (defun git-gutter+-stage-diffinfos (diffinfos line-range)\n642 (let ((header git-gutter+-diff-header))\n643 (with-temp-buffer\n644 (insert header)\n645 ;; Insert hunks in reverse so that earlier hunks don't invalidate the line\n646 ;; number information of the later hunks.\n647 (dolist (diffinfo (nreverse diffinfos))\n648 (git-gutter+-insert-diffinfo diffinfo line-range)\n649 (goto-char (point-max)))\n650 (git-gutter+-call-git-on-current-buffer\n651 '(\"apply\" \"--unidiff-zero\" \"--cached\" \"-\")))))\n\n653 (defun git-gutter+-insert-diffinfo (diffinfo line-range)\n654 (let ((content (plist-get diffinfo :content))\n655 (type (plist-get diffinfo :type)))\n656 (if (not line-range)\n657 (git-gutter+-insert-hunk content type)\n658 (let ((diff-start-line (plist-get diffinfo :start-line))\n659 (diff-end-line (plist-get diffinfo :end-line))\n660 (start-line (car line-range))\n661 (end-line (cdr line-range)))\n662 (git-gutter+-insert-hunk content type\n663 (1+ (- start-line diff-start-line))\n664 (1+ (- end-line diff-start-line)))))))\n\n666 (defun git-gutter+-call-git-on-current-buffer (args)\n667 \"Sends the current buffer contents to Git and replaces them with Git's output.\n\n669 RETURNS nil if Git ran successfully. Returns an error description otherwise.\"\n670 (unless (zerop (apply #'call-process-region (point-min) (point-max)\n671 git-gutter+-git-executable t t nil args))\n672 (buffer-string)))\n\n674 (defsubst git-gutter+-read-hunk-header (hunk)\n675 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n676 (string-match git-gutter+-hunk-header-regex hunk)\n677 (list (string-to-number (match-string 1 hunk))\n678 (string-to-number (or (match-string 2 hunk) \"1\"))\n679 (string-to-number (match-string 3 hunk))\n680 (string-to-number (or (match-string 4 hunk) \"1\"))))\n\n682 (defun git-gutter+-insert-hunk (hunk type &optional start end)\n683 \"If START and END are provided, only insert addition (+) lines between\n684 START and END (inclusive). START and END are both line numbers starting with 1.\"\n685 (destructuring-bind\n686 (del-line del-len add-line add-len) (git-gutter+-read-hunk-header hunk)\n687 (let* ((start (max 1 (or start 1)))\n688 (end (min add-len (or end add-len)))\n689 (insert-all-p (or (eq type :deleted)\n690 (and (= start 1) (= end add-len))))\n691 (num-lines-selected (if insert-all-p\n692 add-len\n693 (1+ (- end start)))))\n694 ;; When the user selected the last lines of a hunk with type `modified' (but\n695 ;; not the complete hunk), then don't insert any deletion (-) lines from that\n696 ;; hunk.\n697 (if (and (eq type 'modified)\n698 (> start 1) (= end add-len))\n699 (setq type 'modified-trailing))\n\n701 (save-excursion\n702 (insert hunk \"\\n\"))\n\n704 (git-gutter+-delete-hunk-header)\n\n706 (if (not insert-all-p)\n707 (git-gutter+-modify-hunk type num-lines-selected del-len start))\n\n709 (let ((hunk-header (git-gutter+-make-hunk-header type num-lines-selected\n710 del-line del-len add-line)))\n711 (insert hunk-header \"\\n\")))))\n\n713 (defun git-gutter+-delete-hunk-header ()\n714 (let ((hunk-start (point)))\n715 (forward-line 1)\n716 (delete-region hunk-start (point))))\n\n718 (defun git-gutter+-modify-hunk (type num-lines-selected del-len start)\n719 \"Remove all addition (+) lines from hunk that aren't selected.\n720 If TYPE is not `modified', also remove all deletion (-) lines.\"\n721 (let ((first-line-selected (+ del-len (1- start)))\n722 selected-lines)\n723 (save-excursion\n724 (forward-line first-line-selected)\n725 (let ((selection-start (point)))\n726 (forward-line num-lines-selected)\n727 (setq selected-lines (buffer-substring selection-start (point)))))\n728 (save-excursion\n729 (if (eq type 'modified) (forward-line del-len)) ; skip over deletion (-) lines\n730 (delete-region (point) (point-max))\n731 (insert selected-lines))))\n\n733 (defun git-gutter+-make-hunk-header (type num-lines-selected del-line del-len add-line)\n734 (let ((add-len num-lines-selected))\n735 (case type\n736 (added (setq add-line (1+ del-line)))\n737 (modified-trailing (setq add-line (+ del-line del-len)\n738 del-line (1- add-line)\n739 del-len 0))\n740 (t (setq add-line del-line)))\n741 (format \"@@ -%d,%d +%d,%d @@\"\n742 del-line del-len\n743 add-line add-len)))\n\n\n746 ;;; Committing\n747 ;; This section draws heavily from old Magit source code.\n\n749 (defvar git-gutter+-pre-commit-window-config nil)\n750 (defvar git-gutter+-commit-origin-buffer nil\n751 \"Buffer that started the commit\")\n\n753 (defconst git-gutter+-commit-buffer-name \"*Commit Message*\")\n754 (defconst git-gutter+-staged-changes-buffer-name \"*Staged Changes*\")\n\n756 ;;;###autoload\n757 (defun git-gutter+-commit ()\n758 \"Commit staged changes. If nothing is staged, ask to stage the current buffer.\"\n759 (interactive)\n\n761 (when (and (not (git-gutter+-anything-staged-p))\n762 git-gutter+-diffinfos\n763 (y-or-n-p \"Nothing staged. Stage current buffer? \"))\n764 (git-gutter+-stage-whole-buffer))\n\n766 (let ((file (buffer-file-name))\n767 (dir default-directory))\n768 (git-gutter+-save-window-config-if-needed)\n769 (setq git-gutter+-commit-origin-buffer (current-buffer))\n770 (git-gutter+-open-commit-edit-buffer dir)\n771 (git-gutter+-show-staged-changes file dir)))\n\n773 (defun git-gutter+-stage-and-commit ()\n774 (interactive)\n775 (git-gutter+-stage-hunks)\n776 (git-gutter+-commit))\n\n778 (defun git-gutter+-save-window-config-if-needed ()\n779 ;; Only save the window config if the temporary buffers that get popped-up by\n780 ;; git-gutter+ are not already visible.\n781 ;; In this way, `git-gutter+-commit' can be called twice in a row without\n782 ;; losing the original window config.\n783 (when (not (and git-gutter+-pre-commit-window-config\n784 (get-buffer-window git-gutter+-commit-buffer-name)\n785 (get-buffer-window git-gutter+-staged-changes-buffer-name)))\n786 (setq git-gutter+-pre-commit-window-config (current-window-configuration))))\n\n788 (defun git-gutter+-open-commit-edit-buffer (dir)\n789 \"Opens a buffer for composing the commit message\"\n790 (pop-to-buffer (get-buffer-create git-gutter+-commit-buffer-name))\n791 (setq default-directory dir)\n792 (git-gutter+-commit-mode)\n793 (message \"Type C-c C-c to commit (C-c C-k to cancel).\"))\n\n795 (defsubst git-gutter+-pop-to-staged-changes-buffer ()\n796 (let* ((buf (get-buffer-create git-gutter+-staged-changes-buffer-name))\n797 (window (get-buffer-window buf)))\n798 (if window\n799 ;; Buffer is already visible\n800 (select-window window)\n801 (if (<= (length (window-list)) 2)\n802 (split-window))\n803 (pop-to-buffer buf))))\n\n805 (defun git-gutter+-show-staged-changes (file dir)\n806 (save-selected-window\n807 (git-gutter+-pop-to-staged-changes-buffer)\n808 (setq buffer-read-only nil)\n809 (erase-buffer)\n810 (let ((default-directory dir))\n811 (git-gutter+-call-git '(\"diff\" \"--staged\") file))\n812 (goto-char (point-min))\n813 (diff-mode)\n814 (view-mode)))\n\n816 (defsubst git-gutter+-abort-commit-when-no-changes (allow-empty amend)\n817 (unless (or amend\n818 allow-empty\n819 (git-gutter+-anything-staged-p))\n820 (error\n821 \"Refusing to create empty commit. Maybe you want to amend (%s) or allow-empty (%s)?\"\n822 (key-description (car (where-is-internal\n823 'git-gutter+-commit-toggle-amending)))\n824 (key-description (car (where-is-internal\n825 'git-gutter+-commit-toggle-allow-empty))))))\n\n827 (defsubst git-gutter+-buffer-is-whitespace ()\n828 (save-excursion\n829 (goto-char (point-min))\n830 (looking-at-p \"[ \\t\\n]*\\\\'\")))\n\n832 (defun git-gutter+-publish-commit ()\n833 \"Publish commit\"\n834 (interactive)\n835 (let* ((fields (git-gutter+-commit-get-fields))\n836 (amend (equal \"yes\" (git-gutter+-commit-get-field 'amend fields)))\n837 (allow-empty (equal \"yes\" (git-gutter+-commit-get-field 'allow-empty fields)))\n838 (author (git-gutter+-commit-get-field 'author fields))\n839 (date (git-gutter+-commit-get-field 'date fields)))\n\n841 (git-gutter+-abort-commit-when-no-changes allow-empty amend)\n\n843 (git-gutter+-push-to-comment-ring (buffer-string))\n\n845 (git-gutter+-commit-set-fields nil) ; Delete message header\n\n847 (when (git-gutter+-buffer-is-whitespace)\n848 (erase-buffer)\n849 (insert \"(Empty description)\"))\n\n851 (let ((error-msg (git-gutter+-call-git-on-current-buffer\n852 (append '(\"--no-pager\" \"commit\" \"-F\" \"-\")\n853 (if amend '(\"--amend\"))\n854 (if allow-empty '(\"--allow-empty\"))\n855 (if author (list (concat \"--author=\" author)))\n856 (if date (list (concat \"--date=\" date)))))))\n857 (if error-msg\n858 (progn\n859 (message \"Commit error:\\n%s\" error-msg)\n860 (erase-buffer)\n861 (insert (ring-ref log-edit-comment-ring 0))) ; Reinsert commit message\n862 (message \"Commit successful.\")\n863 (git-gutter+-close-commit-edit-buffer)\n864 (git-gutter+-update-vc-modeline)))))\n\n866 (defun git-gutter+-close-commit-edit-buffer ()\n867 \"Abort edits and discard commit message being composed.\"\n868 (interactive)\n869 (kill-buffer)\n870 (set-window-configuration git-gutter+-pre-commit-window-config))\n\n872 (defun git-gutter+-update-vc-modeline ()\n873 (when (buffer-live-p git-gutter+-commit-origin-buffer)\n874 (with-current-buffer git-gutter+-commit-origin-buffer\n875 ;; Updating the modeline has no effect if the buffer still has\n876 ;; changes - it will remain in the 'modified' state. So skip it then.\n877 (unless git-gutter+-diffinfos\n878 (ignore-errors (vc-find-file-hook))))))\n\n880 (defun git-gutter+-stage-whole-buffer ()\n881 (save-excursion\n882 (mark-whole-buffer)\n883 (git-gutter+-stage-hunks)))\n\n885 (defun git-gutter+-anything-staged-p ()\n886 \"Return t if the current repo has staged changes\"\n887 (not (zerop (git-gutter+-call-git '(\"diff\" \"--quiet\" \"--cached\")))))\n\n889 (defun git-gutter+-commit-toggle-amending ()\n890 \"Toggle whether this will be an amendment to the previous commit.\n891 \\(i.e., whether commit is run via 'git commit --amend')\"\n892 (interactive)\n893 ;; Remove the newline that 'git-commit-mode' adds to a new commit\n894 ;; message buffer by default. This prevents an ugly visual\n895 ;; gap between the commit message header and the previous commit\n896 ;; message.\n897 (when (git-gutter+-buffer-is-whitespace)\n898 (erase-buffer))\n\n900 (let ((amend-was-already-set (git-gutter+-commit-get-field 'amend)))\n901 (git-gutter+-commit-toggle-field 'amend t)\n902 (unless amend-was-already-set\n903 ;; Insert previous commit message\n904 (goto-char (point-max))\n905 (unless (zerop (current-column))\n906 (insert \"\\n\"))\n907 (insert (git-gutter+-get-last-commit-msg)\n908 \"\\n\"))))\n\n910 (defun git-gutter+-commit-toggle-allow-empty ()\n911 \"Toggle whether this commit is allowed to be empty.\n912 \\(i.e., whether commit is run via 'git commit --allow-empty')\"\n913 (interactive)\n914 (git-gutter+-commit-toggle-field 'allow-empty t))\n\n916 (defun git-gutter+-format-author (author email)\n917 (format \"%s <%s>\" author email))\n\n919 (defun git-gutter+-commit-toggle-author ()\n920 \"Toggle whether this commit should have a user-defined author.\"\n921 (interactive)\n922 (git-gutter+-commit-toggle-input\n923 'author (git-gutter+-format-author\n924 (or (git-gutter+-get-cfg \"user\" \"name\") \"Author Name\")\n925 (or (git-gutter+-get-cfg \"user\" \"email\") \"author@email\"))))\n\n927 (defun git-gutter+-commit-toggle-date ()\n928 \"Toggle whether this commit should have a user-defined date.\"\n929 (interactive)\n930 (git-gutter+-commit-toggle-input 'date\n931 ;; ISO 8601\n932 (format-time-string \"%Y-%m-%dT%T%z\" (current-time))))\n\n934 (defun git-gutter+-push-to-comment-ring (comment)\n935 (when (or (ring-empty-p log-edit-comment-ring)\n936 (not (equal comment (ring-ref log-edit-comment-ring 0))))\n937 (ring-insert log-edit-comment-ring comment)))\n\n939 (defun git-gutter+-get-last-commit-msg ()\n940 (git-gutter+-git-output '(\"log\" \"--max-count=1\" \"--pretty=format:%s%n%n%b\" \"HEAD\")))\n\n942 (defun git-gutter+-get-cfg (&rest keys)\n943 (git-gutter+-git-output (list \"config\" (mapconcat 'identity keys \".\"))))\n\n945 (defun git-gutter+-git-output (args)\n946 (with-temp-buffer\n947 (git-gutter+-call-git args)\n948 ;; Delete trailing newlines\n949 (goto-char (point-min))\n950 (if (re-search-forward \"\\n+\\\\'\" nil t)\n951 (replace-match \"\"))\n952 (buffer-string)))\n\n\n955 ;;; Commit message header\n\n957 (defconst git-gutter+-commit-header-end \"-- End of commit options header --\\n\")\n\n959 (defun git-gutter+-commit-get-field (name &optional fields)\n960 (cdr (assq name (or fields (git-gutter+-commit-get-fields)))))\n\n962 (defun git-gutter+-commit-set-field (name value)\n963 (let* ((fields (git-gutter+-commit-get-fields))\n964 (cell (assq name fields)))\n965 (cond (cell\n966 (if value\n967 (rplacd cell value)\n968 (setq fields (delq cell fields))))\n969 (t\n970 (if value\n971 (setq fields (append fields (list (cons name value)))))))\n972 (git-gutter+-commit-set-fields fields)))\n\n974 (defun git-gutter+-commit-toggle-field (name default)\n975 \"Toggle the commit header field named NAME.\n976 If it's currently unset, set it to DEFAULT (t or nil).\"\n977 (let* ((fields (git-gutter+-commit-get-fields))\n978 (cell (assq name fields)))\n979 (if cell\n980 (rplacd cell (if (equal (cdr cell) \"yes\") \"no\" \"yes\"))\n981 (setq fields (acons name (if default \"yes\" \"no\") fields)))\n982 (git-gutter+-commit-set-fields fields)))\n\n984 (defun git-gutter+-commit-toggle-input (name default)\n985 \"Toggle the commit header input named NAME.\n986 If it's currently unset, set it to DEFAULT (a string). If it is\n987 set remove it.\"\n988 (let* ((fields (git-gutter+-commit-get-fields))\n989 (cell (assq name fields)))\n990 (if cell\n991 (setq fields (assq-delete-all name fields))\n992 (setq fields (acons name default fields)))\n993 (git-gutter+-commit-set-fields fields)))\n\n995 (defun git-gutter+-commit-get-fields ()\n996 (let (result)\n997 (goto-char (point-min))\n998 (while (looking-at \"^\\\\([A-Za-z0-9-_]+\\\\): *\\\\(.+\\\\)?$\")\n999 (let ((name (intern (downcase (match-string 1))))\n1000 (value (read (or (match-string 2) \"nil\"))))\n1001 (push (cons name value) result))\n1002 (forward-line))\n1003 (if (looking-at (regexp-quote git-gutter+-commit-header-end))\n1004 (nreverse result))))\n\n1006 (defun git-gutter+-commit-set-fields (fields)\n1007 (goto-char (point-min))\n1008 ;; Delete commit header\n1009 (if (search-forward-regexp (format \"^\\\\(?:[A-Za-z0-9-_]+:.*\\n\\\\)*%s\"\n1010 (regexp-quote git-gutter+-commit-header-end))\n1011 nil t)\n1012 (delete-region (match-beginning 0) (match-end 0)))\n1013 (goto-char (point-min))\n1014 (when fields\n1015 (dolist (field fields)\n1016 (insert (capitalize (symbol-name (car field))) \": \"\n1017 (prin1-to-string (cdr field)) \"\\n\"))\n1018 (insert git-gutter+-commit-header-end)))\n\n\n1021 ;;; git-gutter+-commit-mode\n1022 ;; Like git-commit-mode, but adds keybindings to git-gutter+ commands and\n1023 ;; highlighting support for the commit message header.\n\n1025 (define-derived-mode git-gutter+-commit-mode git-commit-mode \"Git-Gutter-Commit\"\n1026 (setq font-lock-defaults (list (git-gutter+-commit-font-lock-keywords) t)))\n\n1028 (setq git-gutter+-commit-mode-map\n1029 (let ((map (copy-keymap git-commit-mode-map)))\n1030 (define-key map (kbd \"C-c C-c\") 'git-gutter+-publish-commit)\n1031 (define-key map (kbd \"C-c C-k\") 'git-gutter+-close-commit-edit-buffer)\n1032 (define-key map (kbd \"C-c C-a\") 'git-gutter+-commit-toggle-amending)\n1033 (define-key map (kbd \"C-c C-e\") 'git-gutter+-commit-toggle-allow-empty)\n1034 (define-key map (kbd \"C-c C-u\") 'git-gutter+-commit-toggle-author)\n1035 (define-key map (kbd \"C-c C-d\") 'git-gutter+-commit-toggle-date)\n1036 (define-key map (kbd \"C-c C-b\") 'git-commit-ack)\n1037 (define-key map (kbd \"M-p\") 'log-edit-previous-comment)\n1038 (define-key map (kbd \"M-n\") 'log-edit-next-comment)\n1039 map))\n\n1041 (defface git-gutter+-commit-header-face\n1042 '((t :inherit font-lock-comment-face))\n1043 \"Highlights the commit message header\"\n1044 :group 'git-gutter+-faces)\n\n1046 (defconst git-gutter+-commit-header-regex\n1047 (concat \"\\\\(?:.\\\\|\\n\\\\)*?\" (regexp-quote git-gutter+-commit-header-end)))\n\n1049 (defconst git-gutter+-skip-commit-header-regex\n1050 (concat \"\\\\`\\\\(?:\" git-gutter+-commit-header-regex \"\\\\)?\"))\n\n1052 ;; Modify git-commit-summary-regexp to ignore the commit header\n1053 (defadvice git-commit-summary-regexp\n1054 (after ignore-git-gutter+-commit-header activate compile)\n1055 (if (eq major-mode 'git-gutter+-commit-mode)\n1056 (setq ad-return-value\n1057 (concat git-gutter+-skip-commit-header-regex\n1058 (substring ; Remove leading \"\\\\`\"\n1059 ad-return-value 2)))))\n\n1061 (defun git-gutter+-commit-font-lock-keywords ()\n1062 \"Like `git-commit-mode-font-lock-keywords' but with commit header highlighting\"\n1063 `((,(concat \"\\\\`\" git-gutter+-commit-header-regex) . 'git-gutter+-commit-header-face)\n1064 ,@(git-commit-mode-font-lock-keywords)))\n\n\n1067 ;;; Magit synchronization\n1068 ;; Force Magit to refresh git-gutter+ when updating the VC mode line.\n\n1070 (defvar git-gutter+-orig-vc-find-file-hook)\n\n1072 (defvar git-gutter+-vc-find-file-hook-with-refresh\n1073 (lambda ()\n1074 (funcall git-gutter+-orig-vc-find-file-hook)\n1075 (if git-gutter+-mode (git-gutter+-refresh))))\n\n1077 (defadvice magit-update-vc-modeline (around refresh-git-gutter+ compile activate)\n1078 ;; `magit-update-vc-modeline' calls `vc-find-file-hook' (a function!) on each\n1079 ;; buffer in the repo. Temporarily rebind it to `vc-find-file-hook-with-refresh',\n1080 ;; which calls git-gutter+-refresh after updating the VC mode line.\n1081 ;;\n1082 ;; Using `flet' would have been much simpler, but it's deprecated since 24.3.\n1083 (setq git-gutter+-orig-vc-find-file-hook (symbol-function 'vc-find-file-hook))\n1084 (fset 'vc-find-file-hook git-gutter+-vc-find-file-hook-with-refresh)\n1085 (unwind-protect\n1086 ad-do-it\n1087 (fset 'vc-find-file-hook git-gutter+-orig-vc-find-file-hook)))\n\n1089 (provide 'git-gutter+)\n\n1091 ;;; git-gutter+.el ends here\n")) (setq helm-swoop-cache t))) (candidates-in-buffer) (get-line . buffer-substring-no-properties) (keymap keymap (C-M-left . backward-sexp) (C-M-right . forward-sexp) (27 keymap (105 . helm-multi-swoop-all-from-helm-swoop)) (3 keymap (5 . helm-swoop-edit)) keymap (C-M-left . paren-backward-sexp) (C-M-right . paren-forward-sexp) (94 . helm-swoop-caret-match) (menu-bar keymap (help-menu keymap (describe keymap (describe-mode . helm-help)))) (help keymap (109 . helm-help)) (f1 keymap (109 . helm-help)) (8 keymap (109 . helm-help) (104 . undefined) (8 . undefined) (4 . helm-debug-output)) (20 . helm-toggle-resplit-and-swap-windows) (C-tab . undefined) (triple-mouse-3 . ignore) (double-mouse-3 . ignore) (mouse-3 . ignore) (drag-mouse-3 . ignore) (down-mouse-3 . ignore) (triple-mouse-2 . ignore) (double-mouse-2 . ignore) (mouse-2 . ignore) (drag-mouse-2 . ignore) (down-mouse-2 . ignore) (triple-mouse-1 . ignore) (double-mouse-1 . ignore) (mouse-1 . ignore) (drag-mouse-1 . ignore) (down-mouse-1 . ignore) (67108897 . helm-toggle-suspend-update) (3 keymap (21 . helm-force-update) (6 . helm-follow-mode) (11 . helm-kill-selection-and-quit) (25 . helm-yank-selection) (4 . helm-delete-current-selection) (45 . helm-swap-windows)) (67108987 . helm-enlarge-window) (67108989 . helm-narrow-window) (19 . undefined) (18 . undefined) (23 . helm-yank-text-at-point) (24 keymap (2 . helm-resume-list-buffers-after-quit) (98 . helm-resume-previous-session-after-quit) (6 . helm-quit-and-find-file)) (11 . helm-delete-minibuffer-contents) (67108896 . helm-toggle-visible-mark) (0 . helm-toggle-visible-mark) (C-M-up . helm-scroll-other-window-down) (C-M-down . helm-scroll-other-window) (M-prior . helm-scroll-other-window-down) (M-next . helm-scroll-other-window) (12 . helm-recenter-top-bottom-other-window) (15 . helm-next-source) (10 . helm-select-3rd-action) (5 . helm-select-2nd-action-or-end-of-line) ...) (header-line . "[C-c C-e] Edit mode, [M-i] apply all buffers") (action lambda ($line) (helm-swoop--goto-line (when (string-match "^[0-9]+" $line) (string-to-number (match-string 0 $line)))) (when (re-search-forward (mapconcat (quote identity) (split-string helm-pattern " ") "\\|") nil t) (goto-char (match-beginning 0))) (helm-swoop--recenter)) (migemo)) #("git-gutter+-refresh" 0 19 (fontified t face whitespace-line)) "Swoop: " nil "^368 " "*Helm Swoop*" nil nil nil)
apply(helm (((name . "git-gutter+.el") (init lambda nil (unless helm-swoop-cache (with-current-buffer (helm-candidate-buffer (quote local)) (insert "1 ;;; git-gutter+.el --- Manage Git hunks straight from the buffer\n\n3 ;; Copyright (C) 2013 by Syohei YOSHIDA and contributors\n\n5 ;; Author: Syohei YOSHIDA <syohex@gmail.com> and contributors\n6 ;; URL: https://github.com/nonsequitur/git-gutter-plus\n7 ;; Version: 0.1\n\n9 ;; This program is free software; you can redistribute it and/or modify\n10 ;; it under the terms of the GNU General Public License as published by\n11 ;; the Free Software Foundation, either version 3 of the License, or\n12 ;; (at your option) any later version.\n\n14 ;; This program is distributed in the hope that it will be useful,\n15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of\n16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n17 ;; GNU General Public License for more details.\n\n19 ;; You should have received a copy of the GNU General Public License\n20 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n22 ;; Package-Requires: ((git-commit-mode \"0.14\"))\n\n24 ;;; Commentary:\n25 ;;\n26 ;; View, stage and revert Git changes straight from the buffer.\n\n28 ;;; Code:\n\n30 (eval-when-compile\n31 (require 'cl))\n\n33 (require 'tramp)\n34 (require 'log-edit)\n35 (require 'git-commit-mode)\n\n37 (defgroup git-gutter+ nil\n38 \"Manage Git hunks straight from the buffer\"\n39 :prefix \"git-gutter+-\"\n40 :group 'vc)\n\n42 (defcustom git-gutter+-window-width nil\n43 \"Character width of the gutter margin. Set this variable if the automatically\n44 calculated width looks wrong. (This can happen with some special characters.)\"\n45 :type 'integer\n46 :group 'git-gutter+)\n\n48 (defcustom git-gutter+-git-executable \"git\"\n49 \"The path of the Git executable.\"\n50 :type 'string\n51 :group 'git-gutter+)\n\n53 (defcustom git-gutter+-diff-options nil\n54 \"List of strings containing extra arguments to 'git diff'\"\n55 :type 'list\n56 :group 'git-gutter+)\n\n58 (defcustom git-gutter+-separator-sign nil\n59 \"Separator sign\"\n60 :type 'string\n61 :group 'git-gutter+)\n\n63 (defcustom git-gutter+-modified-sign \"=\"\n64 \"Modified sign\"\n65 :type 'string\n66 :group 'git-gutter+)\n\n68 (defcustom git-gutter+-added-sign \"+\"\n69 \"Added sign\"\n70 :type 'string\n71 :group 'git-gutter+)\n\n73 (defcustom git-gutter+-deleted-sign \"-\"\n74 \"Deleted sign\"\n75 :type 'string\n76 :group 'git-gutter+)\n\n78 (defcustom git-gutter+-unchanged-sign nil\n79 \"Unchanged sign\"\n80 :type 'string\n81 :group 'git-gutter+)\n\n83 (defcustom git-gutter+-hide-gutter nil\n84 \"Hide gutter if there are no changes\"\n85 :type 'boolean\n86 :group 'git-gutter+)\n\n88 (defcustom git-gutter+-lighter \" GitGutter\"\n89 \"Minor mode lighter in mode-line\"\n90 :type 'string\n91 :group 'git-gutter+)\n\n93 (defface git-gutter+-separator\n94 '((t (:foreground \"cyan\" :weight bold)))\n95 \"Face of the separator\"\n96 :group 'git-gutter+)\n\n98 (defface git-gutter+-modified\n99 '((t (:foreground \"magenta\" :weight bold)))\n100 \"Face for modified lines\"\n101 :group 'git-gutter+)\n\n103 (defface git-gutter+-added\n104 '((t (:foreground \"green\" :weight bold)))\n105 \"Face for added lines\"\n106 :group 'git-gutter+)\n\n108 (defface git-gutter+-deleted\n109 '((t (:foreground \"red\" :weight bold)))\n110 \"Face for deleted lines\"\n111 :group 'git-gutter+)\n\n113 (defface git-gutter+-unchanged\n114 '((t (:background \"yellow\")))\n115 \"Face for unchanged lines\"\n116 :group 'git-gutter+)\n\n118 (defcustom git-gutter+-disabled-modes nil\n119 \"A list of modes for which `global-git-gutter+-mode' should be disabled.\"\n120 :type '(repeat symbol)\n121 :group 'git-gutter+)\n\n123 (defvar git-gutter+-mode-map\n124 (make-sparse-keymap))\n\n126 (defvar git-gutter+-view-diff-function nil\n127 \"Function to call for displaying diffs\")\n\n129 (defvar git-gutter+-clear-function nil\n130 \"Function to call for clearing the diff display\")\n\n132 (defvar git-gutter+-window-config-change-function nil\n133 \"Function to call when the buffer's local window configuration has changed\")\n\n135 (defvar git-gutter+-diffinfos nil)\n136 (defvar git-gutter+-diff-header nil)\n137 (make-variable-buffer-local 'git-gutter+-diffinfos)\n138 (make-variable-buffer-local 'git-gutter+-diff-header)\n\n140 (defvar git-gutter+-popup-buffer \"*git-gutter+-diff*\")\n141 (defvar git-gutter+-buffers-to-reenable nil)\n\n143 (defconst git-gutter+-hunk-header-regex\n144 ;; The same as diff-hunk-header-re-unified\n145 \"^@@ -\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? \\\\+\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? @@\")\n\n147 (defalias 'git-gutter+-popup-hunk 'git-gutter+-show-hunk)\n148 (defalias 'git-gutter+-revert-hunk 'git-gutter+-revert-hunks)\n\n150 (defmacro git-gutter+-awhen (test &rest body)\n151 \"Anaphoric when.\"\n152 (declare (indent 1))\n153 `(let ((it ,test))\n154 (when it ,@body)))\n\n156 (defun git-gutter+-enable-default-display-mode ()\n157 (setq git-gutter+-view-diff-function 'git-gutter+-view-diff-infos\n158 git-gutter+-clear-function 'git-gutter+-clear-diff-infos\n159 git-gutter+-window-config-change-function 'git-gutter+-show-gutter))\n\n161 (unless git-gutter+-view-diff-function\n162 (git-gutter+-enable-default-display-mode))\n\n164 (defun git-gutter+-call-git (args &optional file)\n165 (if (and file (file-remote-p file))\n166 (apply #'process-file git-gutter+-git-executable nil t nil args)\n167 (apply #'call-process git-gutter+-git-executable nil t nil args)))\n\n169 (defun git-gutter+-in-git-repository-p (file)\n170 (with-temp-buffer\n171 (let ((args '(\"rev-parse\" \"--is-inside-work-tree\")))\n172 (when (zerop (git-gutter+-call-git args file))\n173 (goto-char (point-min))\n174 (string= \"true\" (buffer-substring-no-properties\n175 (point) (line-end-position)))))))\n\n177 (defun git-gutter+-root-directory (file)\n178 (with-temp-buffer\n179 (let* ((args '(\"rev-parse\" \"--show-toplevel\"))\n180 (ret (git-gutter+-call-git args file)))\n181 (when (zerop ret)\n182 (goto-char (point-min))\n183 (let ((root (buffer-substring-no-properties (point) (line-end-position))))\n184 (unless (string= root \"\")\n185 (file-name-as-directory root)))))))\n\n187 (defsubst git-gutter+-diff-args (file)\n188 (delq nil (list \"--no-pager\" \"diff\" \"--no-color\" \"--no-ext-diff\" \"-U0\"\n189 git-gutter+-diff-options file)))\n\n191 (defun git-gutter+-diff (curfile)\n192 (let ((args (git-gutter+-diff-args curfile))\n193 (file (buffer-file-name))) ;; for tramp\n194 (with-temp-buffer\n195 (when (zerop (git-gutter+-call-git args file))\n196 (goto-char (point-min))\n197 (let ((diff-header (git-gutter+-get-diff-header))\n198 (diffinfos (git-gutter+-get-diffinfos)))\n199 (list diff-header diffinfos))))))\n\n201 (defun git-gutter+-get-diff-header ()\n202 (save-excursion\n203 (if (re-search-forward git-gutter+-hunk-header-regex nil t)\n204 (buffer-substring (point-min) (match-beginning 0)))))\n\n206 (defsubst git-gutter+-make-diffinfo (type content start end)\n207 (list :type type :content content :start-line start :end-line end))\n\n209 (defun git-gutter+-get-diffinfos ()\n210 (loop while (re-search-forward git-gutter+-hunk-header-regex nil t)\n211 ;; Hunk header format:\n212 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n213 for del-len = (string-to-number (or (match-string 2) \"1\"))\n214 for add-line = (string-to-number (match-string 3))\n215 for add-len = (string-to-number (or (match-string 4) \"1\"))\n216 for type = (cond ((zerop del-len) 'added)\n217 ((zerop add-len) 'deleted)\n218 (t 'modified))\n219 for start-line = (if (eq type 'deleted)\n220 (1+ add-line)\n221 add-line)\n222 for end-line = (if (eq type 'deleted)\n223 start-line\n224 (1- (+ add-line add-len)))\n225 for content = (git-gutter+-diff-content)\n226 collect\n227 (git-gutter+-make-diffinfo type content start-line end-line)))\n\n229 (defun git-gutter+-diff-content ()\n230 (save-excursion\n231 (goto-char (line-beginning-position)) ; Move to beginning of hunk header\n232 (let ((hunk-start (point)))\n233 ;; Move to end of hunk\n234 (forward-line 1)\n235 (if (re-search-forward \"^@@\" nil t)\n236 (backward-char 3) ;; exclude \"\\n@@\"\n237 (goto-char (1- (point-max)))) ; Skip trailing newline\n238 (buffer-substring hunk-start (point)))))\n\n240 (defun git-gutter+-line-to-pos (line)\n241 (save-excursion\n242 (goto-char (point-min))\n243 (forward-line (1- line))\n244 (point)))\n\n246 (defun git-gutter+-before-string (sign)\n247 (let* ((sep-sign git-gutter+-separator-sign)\n248 (sep (when sep-sign\n249 (propertize sep-sign 'face 'git-gutter+-separator)))\n250 (gutter-sep (concat sign sep)))\n251 (propertize \" \" 'display `((margin left-margin) ,gutter-sep))))\n\n253 (defsubst git-gutter+-select-face (type)\n254 (case type\n255 (added 'git-gutter+-added)\n256 (modified 'git-gutter+-modified)\n257 (deleted 'git-gutter+-deleted)))\n\n259 (defsubst git-gutter+-select-sign (type)\n260 (case type\n261 (added git-gutter+-added-sign)\n262 (modified git-gutter+-modified-sign)\n263 (deleted git-gutter+-deleted-sign)))\n\n265 (defun git-gutter+-propertized-sign (type)\n266 (let ((sign (git-gutter+-select-sign type))\n267 (face (git-gutter+-select-face type)))\n268 (propertize sign 'face face)))\n\n270 (defun git-gutter+-view-region (sign start-line end-line)\n271 (let ((beg (git-gutter+-line-to-pos start-line)))\n272 (goto-char beg)\n273 (while (and (<= (line-number-at-pos) end-line) (not (eobp)))\n274 (git-gutter+-view-at-pos sign (point))\n275 (forward-line 1))))\n\n277 (defun git-gutter+-view-at-pos (sign pos)\n278 (let ((ov (make-overlay pos pos)))\n279 (overlay-put ov 'before-string (git-gutter+-before-string sign))\n280 (overlay-put ov 'git-gutter+ t)))\n\n282 (defun git-gutter+-view-diff-info (diffinfo)\n283 (let* ((start-line (plist-get diffinfo :start-line))\n284 (end-line (plist-get diffinfo :end-line))\n285 (type (plist-get diffinfo :type))\n286 (sign (git-gutter+-propertized-sign type)))\n287 (case type\n288 ((modified added) (git-gutter+-view-region sign start-line end-line))\n289 (deleted (git-gutter+-view-at-pos\n290 sign (git-gutter+-line-to-pos start-line))))))\n\n292 (defun git-gutter+-sign-width (sign)\n293 (loop for s across sign\n294 sum (char-width s)))\n\n296 (defun git-gutter+-longest-sign-width ()\n297 (let ((signs (list git-gutter+-modified-sign\n298 git-gutter+-added-sign\n299 git-gutter+-deleted-sign)))\n300 (when git-gutter+-unchanged-sign\n301 (add-to-list 'signs git-gutter+-unchanged-sign))\n302 (+ (apply 'max (mapcar 'git-gutter+-sign-width signs))\n303 (git-gutter+-sign-width git-gutter+-separator-sign))))\n\n305 (defun git-gutter+-view-for-unchanged ()\n306 (save-excursion\n307 (let ((sign (if git-gutter+-unchanged-sign\n308 (propertize git-gutter+-unchanged-sign\n309 'face 'git-gutter+-unchanged)\n310 \" \")))\n311 (goto-char (point-min))\n312 (while (not (eobp))\n313 (git-gutter+-view-at-pos sign (point))\n314 (forward-line 1)))))\n\n316 (defun git-gutter+-set-window-margin (width)\n317 (let ((curwin (get-buffer-window)))\n318 (set-window-margins curwin width (cdr (window-margins curwin)))))\n\n320 (defsubst git-gutter+-file-buffer-p ()\n321 (and (buffer-file-name)\n322 default-directory\n323 (file-directory-p default-directory)))\n\n325 ;;;###autoload\n326 (define-minor-mode git-gutter+-mode\n327 \"Git-Gutter mode\"\n328 :group 'git-gutter+\n329 :init-value nil\n330 :global nil\n331 :lighter git-gutter+-lighter\n332 (if git-gutter+-mode\n333 (if (and (git-gutter+-file-buffer-p)\n334 (git-gutter+-in-git-repository-p (buffer-file-name)))\n335 (progn\n336 (git-gutter+-add-local-hooks)\n337 (git-gutter+-refresh))\n338 (if (called-interactively-p 'any)\n339 (message \"No Git repo for current buffer\"))\n340 (git-gutter+-mode -1))\n341 (git-gutter+-remove-local-hooks)\n342 (git-gutter+-clear)))\n\n344 (defun git-gutter+-add-local-hooks ()\n345 (add-hook 'after-save-hook 'git-gutter+-refresh nil t)\n346 ;; Turn off `git-gutter+-mode' while reverting to prevent any redundant calls to\n347 ;; `git-gutter+-refresh'.\n348 (add-hook 'before-revert-hook 'git-gutter+-turn-off nil t)\n349 (add-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change nil t)\n350 (if git-gutter+-window-config-change-function\n351 (add-hook 'window-configuration-change-hook\n352 git-gutter+-window-config-change-function nil t)))\n\n354 (defun git-gutter+-remove-local-hooks ()\n355 (remove-hook 'after-save-hook 'git-gutter+-refresh t)\n356 (remove-hook 'before-revert-hook 'git-gutter+-turn-off t)\n357 (remove-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change t)\n358 (if git-gutter+-window-config-change-function\n359 (remove-hook 'window-configuration-change-hook\n360 git-gutter+-window-config-change-function t)))\n\n362 (defmacro git-gutter+-in-all-buffers (&rest body)\n363 `(dolist (buf (buffer-list))\n364 (with-current-buffer buf\n365 ,@body)))\n\n367 ;; When `define-globalized-minor-mode' is used to define `global-git-gutter+-mode',\n368 ;; `git-gutter+-mode' and thus `git-gutter+-refresh' get run twice when a new file\n369 ;; is opened. (First for `fundamental-mode', then for the file-specific mode.)\n370 ;; The following definition of `global-git-gutter+-mode' avoids any redundant calls to\n371 ;; `git-gutter+-refresh'.\n\n373 ;;;###autoload\n374 (define-minor-mode global-git-gutter+-mode ()\n375 \"Global Git-Gutter mode\"\n376 :group 'git-gutter+\n377 :init-value nil\n378 :global t\n379 (if global-git-gutter+-mode\n380 (progn\n381 (add-hook 'find-file-hook 'git-gutter+-turn-on)\n382 (add-hook 'after-revert-hook 'git-gutter+-turn-on)\n383 (add-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n384 (git-gutter+-in-all-buffers (git-gutter+-turn-on)))\n385 (remove-hook 'find-file-hook 'git-gutter+-turn-on)\n386 (remove-hook 'after-revert-hook 'git-gutter+-turn-on)\n387 (remove-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n388 (git-gutter+-in-all-buffers (git-gutter+-turn-off))))\n\n390 (defun git-gutter+-turn-on ()\n391 (when (and (buffer-file-name)\n392 (not (memq major-mode git-gutter+-disabled-modes))\n393 (not git-gutter+-mode))\n394 (git-gutter+-mode t)))\n\n396 (defun git-gutter+-turn-off ()\n397 (if git-gutter+-mode (git-gutter+-mode -1)))\n\n399 (defun git-gutter+-reenable-after-major-mode-change ()\n400 (if global-git-gutter+-mode\n401 (add-to-list 'git-gutter+-buffers-to-reenable (current-buffer))))\n\n403 (defun git-gutter+-reenable-buffers ()\n404 (dolist (buf git-gutter+-buffers-to-reenable)\n405 (with-current-buffer buf\n406 (git-gutter+-turn-on)))\n407 (setq git-gutter+-buffers-to-reenable nil))\n\n409 (defsubst git-gutter+-show-gutter-p (diffinfos)\n410 (if git-gutter+-hide-gutter\n411 (or diffinfos git-gutter+-unchanged-sign)\n412 (or global-git-gutter+-mode git-gutter+-unchanged-sign diffinfos)))\n\n414 (defun git-gutter+-show-gutter (&optional diffinfos)\n415 (when (git-gutter+-show-gutter-p (or diffinfos git-gutter+-diffinfos))\n416 (let ((win-width (or git-gutter+-window-width\n417 (git-gutter+-longest-sign-width))))\n418 (git-gutter+-set-window-margin win-width))))\n\n420 (defun git-gutter+-view-diff-infos (diffinfos)\n421 (when (or git-gutter+-unchanged-sign\n422 git-gutter+-separator-sign)\n423 (git-gutter+-view-for-unchanged))\n424 (when diffinfos\n425 (save-excursion\n426 (mapc 'git-gutter+-view-diff-info diffinfos)))\n427 (git-gutter+-show-gutter diffinfos))\n\n429 (defsubst git-gutter+-reset-window-margin-p ()\n430 (or git-gutter+-hide-gutter\n431 (not global-git-gutter+-mode)))\n\n433 (defun git-gutter+-clear-diff-infos ()\n434 (when (git-gutter+-reset-window-margin-p)\n435 (git-gutter+-set-window-margin 0))\n436 (remove-overlays (point-min) (point-max) 'git-gutter+ t))\n\n438 (defun git-gutter+-process-diff (curfile)\n439 (destructuring-bind\n440 (diff-header diffinfos) (git-gutter+-diff curfile)\n441 (setq git-gutter+-diff-header diff-header\n442 git-gutter+-diffinfos diffinfos)\n443 (save-restriction\n444 (widen)\n445 (funcall git-gutter+-view-diff-function diffinfos))))\n\n447 (defun git-gutter+-search-near-diff-index (diffinfos is-reverse)\n448 (loop with current-line = (line-number-at-pos)\n449 with cmp-fn = (if is-reverse '> '<)\n450 for diffinfo in (if is-reverse (reverse diffinfos) diffinfos)\n451 for index = 0 then (1+ index)\n452 for start-line = (plist-get diffinfo :start-line)\n453 when (funcall cmp-fn current-line start-line)\n454 return (if is-reverse\n455 (1- (- (length diffinfos) index))\n456 index)))\n\n458 (defun git-gutter+-diffinfo-at-point ()\n459 (save-restriction\n460 (widen)\n461 (loop with current-line = (line-number-at-pos)\n462 for diffinfo in git-gutter+-diffinfos\n463 for start = (plist-get diffinfo :start-line)\n464 for end = (or (plist-get diffinfo :end-line) (1+ start))\n465 when (and (>= current-line start) (<= current-line end))\n466 return diffinfo)))\n\n468 (defun git-gutter+-collect-deleted-line (str)\n469 (with-temp-buffer\n470 (insert str)\n471 (goto-char (point-min))\n472 (loop while (re-search-forward \"^-\\\\(.*?\\\\)$\" nil t)\n473 collect (match-string 1) into deleted-lines\n474 finally return deleted-lines)))\n\n476 (defun git-gutter+-delete-added-lines (start-line end-line)\n477 (forward-line (1- start-line))\n478 (let ((start-point (point)))\n479 (forward-line (1+ (- end-line start-line)))\n480 (delete-region start-point (point))))\n\n482 (defun git-gutter+-insert-deleted-lines (content)\n483 (dolist (line (git-gutter+-collect-deleted-line content))\n484 (insert (concat line \"\\n\"))))\n\n486 (defun git-gutter+-do-revert-hunk (diffinfo)\n487 (save-excursion\n488 (save-restriction\n489 (widen)\n490 (goto-char (point-min))\n491 (let ((start-line (plist-get diffinfo :start-line))\n492 (end-line (plist-get diffinfo :end-line))\n493 (content (plist-get diffinfo :content)))\n494 (case (plist-get diffinfo :type)\n495 (added (git-gutter+-delete-added-lines start-line end-line))\n496 (deleted (forward-line (1- start-line))\n497 (git-gutter+-insert-deleted-lines content))\n498 (modified (git-gutter+-delete-added-lines start-line end-line)\n499 (git-gutter+-insert-deleted-lines content)))))))\n\n501 (defun git-gutter+-revert-hunks ()\n502 \"Revert hunk at point. If region is active, revert all hunks within the region.\"\n503 (interactive)\n504 (let* ((diffinfos (git-gutter+-selected-diffinfos))\n505 (one-diffinfo-p (= 1 (length diffinfos))))\n506 (save-window-excursion\n507 (if one-diffinfo-p (git-gutter+-show-hunk (car diffinfos)))\n508 (when (and diffinfos\n509 (yes-or-no-p (if one-diffinfo-p\n510 \"Revert hunk?\"\n511 (format \"Revert %d hunks?\" (length diffinfos)))))\n512 ;; Revert diffinfos in reverse so that earlier hunks don't invalidate the\n513 ;; line number information of the later hunks.\n514 (dolist (diffinfo (nreverse diffinfos))\n515 (git-gutter+-do-revert-hunk diffinfo))\n516 (save-buffer))\n517 (if one-diffinfo-p\n518 (git-gutter+-awhen (get-buffer git-gutter+-popup-buffer)\n519 (kill-buffer it))))))\n\n521 (defun git-gutter+-show-hunk (&optional diffinfo)\n522 \"Show hunk at point in another window\"\n523 (interactive)\n524 (git-gutter+-awhen (or diffinfo\n525 (git-gutter+-diffinfo-at-point))\n526 (save-selected-window\n527 (with-current-buffer (get-buffer-create git-gutter+-popup-buffer)\n528 (setq buffer-read-only nil)\n529 (erase-buffer)\n530 (insert (plist-get it :content))\n531 (insert \"\\n\")\n532 (goto-char (point-min))\n533 (diff-mode)\n534 (view-mode)\n535 (pop-to-buffer (current-buffer))))))\n\n537 (defun git-gutter+-next-hunk (arg)\n538 \"Move to next diff hunk\"\n539 (interactive \"p\")\n540 (if (not git-gutter+-diffinfos)\n541 (message \"No changes in buffer\")\n542 (save-restriction\n543 (widen)\n544 (let* ((is-reverse (< arg 0))\n545 (diffinfos git-gutter+-diffinfos)\n546 (len (length diffinfos))\n547 (index (git-gutter+-search-near-diff-index diffinfos is-reverse))\n548 (real-index (if index\n549 (let ((next (if is-reverse (1+ index) (1- index))))\n550 (mod (+ arg next) len))\n551 (if is-reverse (1- (length diffinfos)) 0)))\n552 (diffinfo (nth real-index diffinfos)))\n553 (goto-char (point-min))\n554 (forward-line (1- (plist-get diffinfo :start-line)))\n555 (when (buffer-live-p (get-buffer git-gutter+-popup-buffer))\n556 (save-window-excursion\n557 (git-gutter+-show-hunk)))))))\n\n559 (defun git-gutter+-previous-hunk (arg)\n560 \"Move to previous diff hunk\"\n561 (interactive \"p\")\n562 (git-gutter+-next-hunk (- arg)))\n\n564 (defun git-gutter+-remote-default-directory (dir file)\n565 (let* ((vec (tramp-dissect-file-name file))\n566 (method (aref vec 0))\n567 (user (aref vec 1))\n568 (host (aref vec 2)))\n569 (format \"/%s:%s%s:%s\" method (if user (concat user \"@\") \"\") host dir)))\n\n571 (defun git-gutter+-remote-file-path (dir file)\n572 (let ((file (aref (tramp-dissect-file-name file) 3)))\n573 (replace-regexp-in-string (concat \"\\\\`\" dir) \"\" file)))\n\n575 (defun git-gutter+-local-file-path (file)\n576 (if (eq system-type 'windows-nt)\n577 ;; Cygwin can't handle Windows absolute paths\n578 (file-relative-name file default-directory)\n579 file))\n\n581 (defun git-gutter+-refresh ()\n582 (git-gutter+-clear)\n583 (let ((file (buffer-file-name)))\n584 (when (and file (file-exists-p file))\n585 (if (file-remote-p file)\n586 (let* ((repo-root (git-gutter+-root-directory file))\n587 (default-directory (git-gutter+-remote-default-directory repo-root file)))\n588 (git-gutter+-process-diff (git-gutter+-remote-file-path repo-root file)))\n589 (git-gutter+-process-diff (git-gutter+-local-file-path file))))))\n\n591 (defun git-gutter+-clear ()\n592 (save-restriction\n593 (widen)\n594 (funcall git-gutter+-clear-function))\n595 (setq git-gutter+-diffinfos nil))\n\n\n598 ;;; Staging\n\n600 (defun git-gutter+-stage-hunks ()\n601 \"Stage hunk at point. If region is active, stage all hunk lines within the region.\"\n602 (interactive)\n603 (let* ((line-range (if (use-region-p)\n604 (cons (line-number-at-pos (region-beginning))\n605 (line-number-at-pos (region-end)))))\n606 (diffinfos (git-gutter+-selected-diffinfos line-range)))\n607 (when diffinfos\n608 (let ((error-msg (git-gutter+-stage-diffinfos diffinfos line-range)))\n609 (if error-msg\n610 (message \"Error staging hunks:\\n%s\" error-msg))\n611 (git-gutter+-refresh)))))\n\n613 (defun git-gutter+-selected-diffinfos (&optional line-range)\n614 (unless line-range\n615 (setq line-range (if (use-region-p)\n616 (cons (line-number-at-pos (region-beginning))\n617 (line-number-at-pos (region-end))))))\n618 (if line-range\n619 (git-gutter+-diffinfos-between-lines line-range)\n620 (git-gutter+-awhen (git-gutter+-diffinfo-at-point)\n621 (list it))))\n\n623 (defsubst git-gutter+-diffinfo-between-lines-p (diffinfo start-line end-line)\n624 (let ((diff-start (plist-get diffinfo :start-line))\n625 (diff-end (plist-get diffinfo :end-line)))\n626 (and (<= start-line diff-end)\n627 (<= diff-start end-line))))\n\n629 (defun git-gutter+-diffinfos-between-lines (line-range)\n630 (save-restriction\n631 (widen)\n632 (let ((start-line (car line-range))\n633 (end-line (cdr line-range)))\n634 (delq nil\n635 (mapcar (lambda (diffinfo)\n636 (if (git-gutter+-diffinfo-between-lines-p\n637 diffinfo start-line end-line)\n638 diffinfo))\n639 git-gutter+-diffinfos)))))\n\n641 (defun git-gutter+-stage-diffinfos (diffinfos line-range)\n642 (let ((header git-gutter+-diff-header))\n643 (with-temp-buffer\n644 (insert header)\n645 ;; Insert hunks in reverse so that earlier hunks don't invalidate the line\n646 ;; number information of the later hunks.\n647 (dolist (diffinfo (nreverse diffinfos))\n648 (git-gutter+-insert-diffinfo diffinfo line-range)\n649 (goto-char (point-max)))\n650 (git-gutter+-call-git-on-current-buffer\n651 '(\"apply\" \"--unidiff-zero\" \"--cached\" \"-\")))))\n\n653 (defun git-gutter+-insert-diffinfo (diffinfo line-range)\n654 (let ((content (plist-get diffinfo :content))\n655 (type (plist-get diffinfo :type)))\n656 (if (not line-range)\n657 (git-gutter+-insert-hunk content type)\n658 (let ((diff-start-line (plist-get diffinfo :start-line))\n659 (diff-end-line (plist-get diffinfo :end-line))\n660 (start-line (car line-range))\n661 (end-line (cdr line-range)))\n662 (git-gutter+-insert-hunk content type\n663 (1+ (- start-line diff-start-line))\n664 (1+ (- end-line diff-start-line)))))))\n\n666 (defun git-gutter+-call-git-on-current-buffer (args)\n667 \"Sends the current buffer contents to Git and replaces them with Git's output.\n\n669 RETURNS nil if Git ran successfully. Returns an error description otherwise.\"\n670 (unless (zerop (apply #'call-process-region (point-min) (point-max)\n671 git-gutter+-git-executable t t nil args))\n672 (buffer-string)))\n\n674 (defsubst git-gutter+-read-hunk-header (hunk)\n675 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n676 (string-match git-gutter+-hunk-header-regex hunk)\n677 (list (string-to-number (match-string 1 hunk))\n678 (string-to-number (or (match-string 2 hunk) \"1\"))\n679 (string-to-number (match-string 3 hunk))\n680 (string-to-number (or (match-string 4 hunk) \"1\"))))\n\n682 (defun git-gutter+-insert-hunk (hunk type &optional start end)\n683 \"If START and END are provided, only insert addition (+) lines between\n684 START and END (inclusive). START and END are both line numbers starting with 1.\"\n685 (destructuring-bind\n686 (del-line del-len add-line add-len) (git-gutter+-read-hunk-header hunk)\n687 (let* ((start (max 1 (or start 1)))\n688 (end (min add-len (or end add-len)))\n689 (insert-all-p (or (eq type :deleted)\n690 (and (= start 1) (= end add-len))))\n691 (num-lines-selected (if insert-all-p\n692 add-len\n693 (1+ (- end start)))))\n694 ;; When the user selected the last lines of a hunk with type `modified' (but\n695 ;; not the complete hunk), then don't insert any deletion (-) lines from that\n696 ;; hunk.\n697 (if (and (eq type 'modified)\n698 (> start 1) (= end add-len))\n699 (setq type 'modified-trailing))\n\n701 (save-excursion\n702 (insert hunk \"\\n\"))\n\n704 (git-gutter+-delete-hunk-header)\n\n706 (if (not insert-all-p)\n707 (git-gutter+-modify-hunk type num-lines-selected del-len start))\n\n709 (let ((hunk-header (git-gutter+-make-hunk-header type num-lines-selected\n710 del-line del-len add-line)))\n711 (insert hunk-header \"\\n\")))))\n\n713 (defun git-gutter+-delete-hunk-header ()\n714 (let ((hunk-start (point)))\n715 (forward-line 1)\n716 (delete-region hunk-start (point))))\n\n718 (defun git-gutter+-modify-hunk (type num-lines-selected del-len start)\n719 \"Remove all addition (+) lines from hunk that aren't selected.\n720 If TYPE is not `modified', also remove all deletion (-) lines.\"\n721 (let ((first-line-selected (+ del-len (1- start)))\n722 selected-lines)\n723 (save-excursion\n724 (forward-line first-line-selected)\n725 (let ((selection-start (point)))\n726 (forward-line num-lines-selected)\n727 (setq selected-lines (buffer-substring selection-start (point)))))\n728 (save-excursion\n729 (if (eq type 'modified) (forward-line del-len)) ; skip over deletion (-) lines\n730 (delete-region (point) (point-max))\n731 (insert selected-lines))))\n\n733 (defun git-gutter+-make-hunk-header (type num-lines-selected del-line del-len add-line)\n734 (let ((add-len num-lines-selected))\n735 (case type\n736 (added (setq add-line (1+ del-line)))\n737 (modified-trailing (setq add-line (+ del-line del-len)\n738 del-line (1- add-line)\n739 del-len 0))\n740 (t (setq add-line del-line)))\n741 (format \"@@ -%d,%d +%d,%d @@\"\n742 del-line del-len\n743 add-line add-len)))\n\n\n746 ;;; Committing\n747 ;; This section draws heavily from old Magit source code.\n\n749 (defvar git-gutter+-pre-commit-window-config nil)\n750 (defvar git-gutter+-commit-origin-buffer nil\n751 \"Buffer that started the commit\")\n\n753 (defconst git-gutter+-commit-buffer-name \"*Commit Message*\")\n754 (defconst git-gutter+-staged-changes-buffer-name \"*Staged Changes*\")\n\n756 ;;;###autoload\n757 (defun git-gutter+-commit ()\n758 \"Commit staged changes. If nothing is staged, ask to stage the current buffer.\"\n759 (interactive)\n\n761 (when (and (not (git-gutter+-anything-staged-p))\n762 git-gutter+-diffinfos\n763 (y-or-n-p \"Nothing staged. Stage current buffer? \"))\n764 (git-gutter+-stage-whole-buffer))\n\n766 (let ((file (buffer-file-name))\n767 (dir default-directory))\n768 (git-gutter+-save-window-config-if-needed)\n769 (setq git-gutter+-commit-origin-buffer (current-buffer))\n770 (git-gutter+-open-commit-edit-buffer dir)\n771 (git-gutter+-show-staged-changes file dir)))\n\n773 (defun git-gutter+-stage-and-commit ()\n774 (interactive)\n775 (git-gutter+-stage-hunks)\n776 (git-gutter+-commit))\n\n778 (defun git-gutter+-save-window-config-if-needed ()\n779 ;; Only save the window config if the temporary buffers that get popped-up by\n780 ;; git-gutter+ are not already visible.\n781 ;; In this way, `git-gutter+-commit' can be called twice in a row without\n782 ;; losing the original window config.\n783 (when (not (and git-gutter+-pre-commit-window-config\n784 (get-buffer-window git-gutter+-commit-buffer-name)\n785 (get-buffer-window git-gutter+-staged-changes-buffer-name)))\n786 (setq git-gutter+-pre-commit-window-config (current-window-configuration))))\n\n788 (defun git-gutter+-open-commit-edit-buffer (dir)\n789 \"Opens a buffer for composing the commit message\"\n790 (pop-to-buffer (get-buffer-create git-gutter+-commit-buffer-name))\n791 (setq default-directory dir)\n792 (git-gutter+-commit-mode)\n793 (message \"Type C-c C-c to commit (C-c C-k to cancel).\"))\n\n795 (defsubst git-gutter+-pop-to-staged-changes-buffer ()\n796 (let* ((buf (get-buffer-create git-gutter+-staged-changes-buffer-name))\n797 (window (get-buffer-window buf)))\n798 (if window\n799 ;; Buffer is already visible\n800 (select-window window)\n801 (if (<= (length (window-list)) 2)\n802 (split-window))\n803 (pop-to-buffer buf))))\n\n805 (defun git-gutter+-show-staged-changes (file dir)\n806 (save-selected-window\n807 (git-gutter+-pop-to-staged-changes-buffer)\n808 (setq buffer-read-only nil)\n809 (erase-buffer)\n810 (let ((default-directory dir))\n811 (git-gutter+-call-git '(\"diff\" \"--staged\") file))\n812 (goto-char (point-min))\n813 (diff-mode)\n814 (view-mode)))\n\n816 (defsubst git-gutter+-abort-commit-when-no-changes (allow-empty amend)\n817 (unless (or amend\n818 allow-empty\n819 (git-gutter+-anything-staged-p))\n820 (error\n821 \"Refusing to create empty commit. Maybe you want to amend (%s) or allow-empty (%s)?\"\n822 (key-description (car (where-is-internal\n823 'git-gutter+-commit-toggle-amending)))\n824 (key-description (car (where-is-internal\n825 'git-gutter+-commit-toggle-allow-empty))))))\n\n827 (defsubst git-gutter+-buffer-is-whitespace ()\n828 (save-excursion\n829 (goto-char (point-min))\n830 (looking-at-p \"[ \\t\\n]*\\\\'\")))\n\n832 (defun git-gutter+-publish-commit ()\n833 \"Publish commit\"\n834 (interactive)\n835 (let* ((fields (git-gutter+-commit-get-fields))\n836 (amend (equal \"yes\" (git-gutter+-commit-get-field 'amend fields)))\n837 (allow-empty (equal \"yes\" (git-gutter+-commit-get-field 'allow-empty fields)))\n838 (author (git-gutter+-commit-get-field 'author fields))\n839 (date (git-gutter+-commit-get-field 'date fields)))\n\n841 (git-gutter+-abort-commit-when-no-changes allow-empty amend)\n\n843 (git-gutter+-push-to-comment-ring (buffer-string))\n\n845 (git-gutter+-commit-set-fields nil) ; Delete message header\n\n847 (when (git-gutter+-buffer-is-whitespace)\n848 (erase-buffer)\n849 (insert \"(Empty description)\"))\n\n851 (let ((error-msg (git-gutter+-call-git-on-current-buffer\n852 (append '(\"--no-pager\" \"commit\" \"-F\" \"-\")\n853 (if amend '(\"--amend\"))\n854 (if allow-empty '(\"--allow-empty\"))\n855 (if author (list (concat \"--author=\" author)))\n856 (if date (list (concat \"--date=\" date)))))))\n857 (if error-msg\n858 (progn\n859 (message \"Commit error:\\n%s\" error-msg)\n860 (erase-buffer)\n861 (insert (ring-ref log-edit-comment-ring 0))) ; Reinsert commit message\n862 (message \"Commit successful.\")\n863 (git-gutter+-close-commit-edit-buffer)\n864 (git-gutter+-update-vc-modeline)))))\n\n866 (defun git-gutter+-close-commit-edit-buffer ()\n867 \"Abort edits and discard commit message being composed.\"\n868 (interactive)\n869 (kill-buffer)\n870 (set-window-configuration git-gutter+-pre-commit-window-config))\n\n872 (defun git-gutter+-update-vc-modeline ()\n873 (when (buffer-live-p git-gutter+-commit-origin-buffer)\n874 (with-current-buffer git-gutter+-commit-origin-buffer\n875 ;; Updating the modeline has no effect if the buffer still has\n876 ;; changes - it will remain in the 'modified' state. So skip it then.\n877 (unless git-gutter+-diffinfos\n878 (ignore-errors (vc-find-file-hook))))))\n\n880 (defun git-gutter+-stage-whole-buffer ()\n881 (save-excursion\n882 (mark-whole-buffer)\n883 (git-gutter+-stage-hunks)))\n\n885 (defun git-gutter+-anything-staged-p ()\n886 \"Return t if the current repo has staged changes\"\n887 (not (zerop (git-gutter+-call-git '(\"diff\" \"--quiet\" \"--cached\")))))\n\n889 (defun git-gutter+-commit-toggle-amending ()\n890 \"Toggle whether this will be an amendment to the previous commit.\n891 \\(i.e., whether commit is run via 'git commit --amend')\"\n892 (interactive)\n893 ;; Remove the newline that 'git-commit-mode' adds to a new commit\n894 ;; message buffer by default. This prevents an ugly visual\n895 ;; gap between the commit message header and the previous commit\n896 ;; message.\n897 (when (git-gutter+-buffer-is-whitespace)\n898 (erase-buffer))\n\n900 (let ((amend-was-already-set (git-gutter+-commit-get-field 'amend)))\n901 (git-gutter+-commit-toggle-field 'amend t)\n902 (unless amend-was-already-set\n903 ;; Insert previous commit message\n904 (goto-char (point-max))\n905 (unless (zerop (current-column))\n906 (insert \"\\n\"))\n907 (insert (git-gutter+-get-last-commit-msg)\n908 \"\\n\"))))\n\n910 (defun git-gutter+-commit-toggle-allow-empty ()\n911 \"Toggle whether this commit is allowed to be empty.\n912 \\(i.e., whether commit is run via 'git commit --allow-empty')\"\n913 (interactive)\n914 (git-gutter+-commit-toggle-field 'allow-empty t))\n\n916 (defun git-gutter+-format-author (author email)\n917 (format \"%s <%s>\" author email))\n\n919 (defun git-gutter+-commit-toggle-author ()\n920 \"Toggle whether this commit should have a user-defined author.\"\n921 (interactive)\n922 (git-gutter+-commit-toggle-input\n923 'author (git-gutter+-format-author\n924 (or (git-gutter+-get-cfg \"user\" \"name\") \"Author Name\")\n925 (or (git-gutter+-get-cfg \"user\" \"email\") \"author@email\"))))\n\n927 (defun git-gutter+-commit-toggle-date ()\n928 \"Toggle whether this commit should have a user-defined date.\"\n929 (interactive)\n930 (git-gutter+-commit-toggle-input 'date\n931 ;; ISO 8601\n932 (format-time-string \"%Y-%m-%dT%T%z\" (current-time))))\n\n934 (defun git-gutter+-push-to-comment-ring (comment)\n935 (when (or (ring-empty-p log-edit-comment-ring)\n936 (not (equal comment (ring-ref log-edit-comment-ring 0))))\n937 (ring-insert log-edit-comment-ring comment)))\n\n939 (defun git-gutter+-get-last-commit-msg ()\n940 (git-gutter+-git-output '(\"log\" \"--max-count=1\" \"--pretty=format:%s%n%n%b\" \"HEAD\")))\n\n942 (defun git-gutter+-get-cfg (&rest keys)\n943 (git-gutter+-git-output (list \"config\" (mapconcat 'identity keys \".\"))))\n\n945 (defun git-gutter+-git-output (args)\n946 (with-temp-buffer\n947 (git-gutter+-call-git args)\n948 ;; Delete trailing newlines\n949 (goto-char (point-min))\n950 (if (re-search-forward \"\\n+\\\\'\" nil t)\n951 (replace-match \"\"))\n952 (buffer-string)))\n\n\n955 ;;; Commit message header\n\n957 (defconst git-gutter+-commit-header-end \"-- End of commit options header --\\n\")\n\n959 (defun git-gutter+-commit-get-field (name &optional fields)\n960 (cdr (assq name (or fields (git-gutter+-commit-get-fields)))))\n\n962 (defun git-gutter+-commit-set-field (name value)\n963 (let* ((fields (git-gutter+-commit-get-fields))\n964 (cell (assq name fields)))\n965 (cond (cell\n966 (if value\n967 (rplacd cell value)\n968 (setq fields (delq cell fields))))\n969 (t\n970 (if value\n971 (setq fields (append fields (list (cons name value)))))))\n972 (git-gutter+-commit-set-fields fields)))\n\n974 (defun git-gutter+-commit-toggle-field (name default)\n975 \"Toggle the commit header field named NAME.\n976 If it's currently unset, set it to DEFAULT (t or nil).\"\n977 (let* ((fields (git-gutter+-commit-get-fields))\n978 (cell (assq name fields)))\n979 (if cell\n980 (rplacd cell (if (equal (cdr cell) \"yes\") \"no\" \"yes\"))\n981 (setq fields (acons name (if default \"yes\" \"no\") fields)))\n982 (git-gutter+-commit-set-fields fields)))\n\n984 (defun git-gutter+-commit-toggle-input (name default)\n985 \"Toggle the commit header input named NAME.\n986 If it's currently unset, set it to DEFAULT (a string). If it is\n987 set remove it.\"\n988 (let* ((fields (git-gutter+-commit-get-fields))\n989 (cell (assq name fields)))\n990 (if cell\n991 (setq fields (assq-delete-all name fields))\n992 (setq fields (acons name default fields)))\n993 (git-gutter+-commit-set-fields fields)))\n\n995 (defun git-gutter+-commit-get-fields ()\n996 (let (result)\n997 (goto-char (point-min))\n998 (while (looking-at \"^\\\\([A-Za-z0-9-_]+\\\\): *\\\\(.+\\\\)?$\")\n999 (let ((name (intern (downcase (match-string 1))))\n1000 (value (read (or (match-string 2) \"nil\"))))\n1001 (push (cons name value) result))\n1002 (forward-line))\n1003 (if (looking-at (regexp-quote git-gutter+-commit-header-end))\n1004 (nreverse result))))\n\n1006 (defun git-gutter+-commit-set-fields (fields)\n1007 (goto-char (point-min))\n1008 ;; Delete commit header\n1009 (if (search-forward-regexp (format \"^\\\\(?:[A-Za-z0-9-_]+:.*\\n\\\\)*%s\"\n1010 (regexp-quote git-gutter+-commit-header-end))\n1011 nil t)\n1012 (delete-region (match-beginning 0) (match-end 0)))\n1013 (goto-char (point-min))\n1014 (when fields\n1015 (dolist (field fields)\n1016 (insert (capitalize (symbol-name (car field))) \": \"\n1017 (prin1-to-string (cdr field)) \"\\n\"))\n1018 (insert git-gutter+-commit-header-end)))\n\n\n1021 ;;; git-gutter+-commit-mode\n1022 ;; Like git-commit-mode, but adds keybindings to git-gutter+ commands and\n1023 ;; highlighting support for the commit message header.\n\n1025 (define-derived-mode git-gutter+-commit-mode git-commit-mode \"Git-Gutter-Commit\"\n1026 (setq font-lock-defaults (list (git-gutter+-commit-font-lock-keywords) t)))\n\n1028 (setq git-gutter+-commit-mode-map\n1029 (let ((map (copy-keymap git-commit-mode-map)))\n1030 (define-key map (kbd \"C-c C-c\") 'git-gutter+-publish-commit)\n1031 (define-key map (kbd \"C-c C-k\") 'git-gutter+-close-commit-edit-buffer)\n1032 (define-key map (kbd \"C-c C-a\") 'git-gutter+-commit-toggle-amending)\n1033 (define-key map (kbd \"C-c C-e\") 'git-gutter+-commit-toggle-allow-empty)\n1034 (define-key map (kbd \"C-c C-u\") 'git-gutter+-commit-toggle-author)\n1035 (define-key map (kbd \"C-c C-d\") 'git-gutter+-commit-toggle-date)\n1036 (define-key map (kbd \"C-c C-b\") 'git-commit-ack)\n1037 (define-key map (kbd \"M-p\") 'log-edit-previous-comment)\n1038 (define-key map (kbd \"M-n\") 'log-edit-next-comment)\n1039 map))\n\n1041 (defface git-gutter+-commit-header-face\n1042 '((t :inherit font-lock-comment-face))\n1043 \"Highlights the commit message header\"\n1044 :group 'git-gutter+-faces)\n\n1046 (defconst git-gutter+-commit-header-regex\n1047 (concat \"\\\\(?:.\\\\|\\n\\\\)*?\" (regexp-quote git-gutter+-commit-header-end)))\n\n1049 (defconst git-gutter+-skip-commit-header-regex\n1050 (concat \"\\\\`\\\\(?:\" git-gutter+-commit-header-regex \"\\\\)?\"))\n\n1052 ;; Modify git-commit-summary-regexp to ignore the commit header\n1053 (defadvice git-commit-summary-regexp\n1054 (after ignore-git-gutter+-commit-header activate compile)\n1055 (if (eq major-mode 'git-gutter+-commit-mode)\n1056 (setq ad-return-value\n1057 (concat git-gutter+-skip-commit-header-regex\n1058 (substring ; Remove leading \"\\\\`\"\n1059 ad-return-value 2)))))\n\n1061 (defun git-gutter+-commit-font-lock-keywords ()\n1062 \"Like `git-commit-mode-font-lock-keywords' but with commit header highlighting\"\n1063 `((,(concat \"\\\\`\" git-gutter+-commit-header-regex) . 'git-gutter+-commit-header-face)\n1064 ,@(git-commit-mode-font-lock-keywords)))\n\n\n1067 ;;; Magit synchronization\n1068 ;; Force Magit to refresh git-gutter+ when updating the VC mode line.\n\n1070 (defvar git-gutter+-orig-vc-find-file-hook)\n\n1072 (defvar git-gutter+-vc-find-file-hook-with-refresh\n1073 (lambda ()\n1074 (funcall git-gutter+-orig-vc-find-file-hook)\n1075 (if git-gutter+-mode (git-gutter+-refresh))))\n\n1077 (defadvice magit-update-vc-modeline (around refresh-git-gutter+ compile activate)\n1078 ;; `magit-update-vc-modeline' calls `vc-find-file-hook' (a function!) on each\n1079 ;; buffer in the repo. Temporarily rebind it to `vc-find-file-hook-with-refresh',\n1080 ;; which calls git-gutter+-refresh after updating the VC mode line.\n1081 ;;\n1082 ;; Using `flet' would have been much simpler, but it's deprecated since 24.3.\n1083 (setq git-gutter+-orig-vc-find-file-hook (symbol-function 'vc-find-file-hook))\n1084 (fset 'vc-find-file-hook git-gutter+-vc-find-file-hook-with-refresh)\n1085 (unwind-protect\n1086 ad-do-it\n1087 (fset 'vc-find-file-hook git-gutter+-orig-vc-find-file-hook)))\n\n1089 (provide 'git-gutter+)\n\n1091 ;;; git-gutter+.el ends here\n")) (setq helm-swoop-cache t))) (candidates-in-buffer) (get-line . buffer-substring-no-properties) (keymap keymap (C-M-left . backward-sexp) (C-M-right . forward-sexp) (27 keymap (105 . helm-multi-swoop-all-from-helm-swoop)) (3 keymap (5 . helm-swoop-edit)) keymap (C-M-left . paren-backward-sexp) (C-M-right . paren-forward-sexp) (94 . helm-swoop-caret-match) (menu-bar keymap (help-menu keymap (describe keymap (describe-mode . helm-help)))) (help keymap (109 . helm-help)) (f1 keymap (109 . helm-help)) (8 keymap (109 . helm-help) (104 . undefined) (8 . undefined) (4 . helm-debug-output)) (20 . helm-toggle-resplit-and-swap-windows) (C-tab . undefined) (triple-mouse-3 . ignore) (double-mouse-3 . ignore) (mouse-3 . ignore) (drag-mouse-3 . ignore) (down-mouse-3 . ignore) (triple-mouse-2 . ignore) (double-mouse-2 . ignore) (mouse-2 . ignore) (drag-mouse-2 . ignore) (down-mouse-2 . ignore) (triple-mouse-1 . ignore) (double-mouse-1 . ignore) (mouse-1 . ignore) (drag-mouse-1 . ignore) (down-mouse-1 . ignore) (67108897 . helm-toggle-suspend-update) (3 keymap (21 . helm-force-update) (6 . helm-follow-mode) (11 . helm-kill-selection-and-quit) (25 . helm-yank-selection) (4 . helm-delete-current-selection) (45 . helm-swap-windows)) (67108987 . helm-enlarge-window) (67108989 . helm-narrow-window) (19 . undefined) (18 . undefined) (23 . helm-yank-text-at-point) (24 keymap (2 . helm-resume-list-buffers-after-quit) (98 . helm-resume-previous-session-after-quit) (6 . helm-quit-and-find-file)) (11 . helm-delete-minibuffer-contents) (67108896 . helm-toggle-visible-mark) (0 . helm-toggle-visible-mark) (C-M-up . helm-scroll-other-window-down) (C-M-down . helm-scroll-other-window) (M-prior . helm-scroll-other-window-down) (M-next . helm-scroll-other-window) (12 . helm-recenter-top-bottom-other-window) (15 . helm-next-source) (10 . helm-select-3rd-action) (5 . helm-select-2nd-action-or-end-of-line) ...) (header-line . "[C-c C-e] Edit mode, [M-i] apply all buffers") (action lambda ($line) (helm-swoop--goto-line (when (string-match "^[0-9]+" $line) (string-to-number (match-string 0 $line)))) (when (re-search-forward (mapconcat (quote identity) (split-string helm-pattern " ") "\\|") nil t) (goto-char (match-beginning 0))) (helm-swoop--recenter)) (migemo)) #("git-gutter+-refresh" 0 19 (fontified t face whitespace-line)) "Swoop: " nil "^368 " "*Helm Swoop*" nil nil nil))
#[0 "\303\301\304\305\306\307\310\311\300!\312\"\313\314%\n\"\"\207" [(:sources ((name . "git-gutter+.el") (init lambda nil (unless helm-swoop-cache (with-current-buffer (helm-candidate-buffer ...) (insert "1 ;;; git-gutter+.el --- Manage Git hunks straight from the buffer\n\n3 ;; Copyright (C) 2013 by Syohei YOSHIDA and contributors\n\n5 ;; Author: Syohei YOSHIDA <syohex@gmail.com> and contributors\n6 ;; URL: https://github.com/nonsequitur/git-gutter-plus\n7 ;; Version: 0.1\n\n9 ;; This program is free software; you can redistribute it and/or modify\n10 ;; it under the terms of the GNU General Public License as published by\n11 ;; the Free Software Foundation, either version 3 of the License, or\n12 ;; (at your option) any later version.\n\n14 ;; This program is distributed in the hope that it will be useful,\n15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of\n16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n17 ;; GNU General Public License for more details.\n\n19 ;; You should have received a copy of the GNU General Public License\n20 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n22 ;; Package-Requires: ((git-commit-mode \"0.14\"))\n\n24 ;;; Commentary:\n25 ;;\n26 ;; View, stage and revert Git changes straight from the buffer.\n\n28 ;;; Code:\n\n30 (eval-when-compile\n31 (require 'cl))\n\n33 (require 'tramp)\n34 (require 'log-edit)\n35 (require 'git-commit-mode)\n\n37 (defgroup git-gutter+ nil\n38 \"Manage Git hunks straight from the buffer\"\n39 :prefix \"git-gutter+-\"\n40 :group 'vc)\n\n42 (defcustom git-gutter+-window-width nil\n43 \"Character width of the gutter margin. Set this variable if the automatically\n44 calculated width looks wrong. (This can happen with some special characters.)\"\n45 :type 'integer\n46 :group 'git-gutter+)\n\n48 (defcustom git-gutter+-git-executable \"git\"\n49 \"The path of the Git executable.\"\n50 :type 'string\n51 :group 'git-gutter+)\n\n53 (defcustom git-gutter+-diff-options nil\n54 \"List of strings containing extra arguments to 'git diff'\"\n55 :type 'list\n56 :group 'git-gutter+)\n\n58 (defcustom git-gutter+-separator-sign nil\n59 \"Separator sign\"\n60 :type 'string\n61 :group 'git-gutter+)\n\n63 (defcustom git-gutter+-modified-sign \"=\"\n64 \"Modified sign\"\n65 :type 'string\n66 :group 'git-gutter+)\n\n68 (defcustom git-gutter+-added-sign \"+\"\n69 \"Added sign\"\n70 :type 'string\n71 :group 'git-gutter+)\n\n73 (defcustom git-gutter+-deleted-sign \"-\"\n74 \"Deleted sign\"\n75 :type 'string\n76 :group 'git-gutter+)\n\n78 (defcustom git-gutter+-unchanged-sign nil\n79 \"Unchanged sign\"\n80 :type 'string\n81 :group 'git-gutter+)\n\n83 (defcustom git-gutter+-hide-gutter nil\n84 \"Hide gutter if there are no changes\"\n85 :type 'boolean\n86 :group 'git-gutter+)\n\n88 (defcustom git-gutter+-lighter \" GitGutter\"\n89 \"Minor mode lighter in mode-line\"\n90 :type 'string\n91 :group 'git-gutter+)\n\n93 (defface git-gutter+-separator\n94 '((t (:foreground \"cyan\" :weight bold)))\n95 \"Face of the separator\"\n96 :group 'git-gutter+)\n\n98 (defface git-gutter+-modified\n99 '((t (:foreground \"magenta\" :weight bold)))\n100 \"Face for modified lines\"\n101 :group 'git-gutter+)\n\n103 (defface git-gutter+-added\n104 '((t (:foreground \"green\" :weight bold)))\n105 \"Face for added lines\"\n106 :group 'git-gutter+)\n\n108 (defface git-gutter+-deleted\n109 '((t (:foreground \"red\" :weight bold)))\n110 \"Face for deleted lines\"\n111 :group 'git-gutter+)\n\n113 (defface git-gutter+-unchanged\n114 '((t (:background \"yellow\")))\n115 \"Face for unchanged lines\"\n116 :group 'git-gutter+)\n\n118 (defcustom git-gutter+-disabled-modes nil\n119 \"A list of modes for which `global-git-gutter+-mode' should be disabled.\"\n120 :type '(repeat symbol)\n121 :group 'git-gutter+)\n\n123 (defvar git-gutter+-mode-map\n124 (make-sparse-keymap))\n\n126 (defvar git-gutter+-view-diff-function nil\n127 \"Function to call for displaying diffs\")\n\n129 (defvar git-gutter+-clear-function nil\n130 \"Function to call for clearing the diff display\")\n\n132 (defvar git-gutter+-window-config-change-function nil\n133 \"Function to call when the buffer's local window configuration has changed\")\n\n135 (defvar git-gutter+-diffinfos nil)\n136 (defvar git-gutter+-diff-header nil)\n137 (make-variable-buffer-local 'git-gutter+-diffinfos)\n138 (make-variable-buffer-local 'git-gutter+-diff-header)\n\n140 (defvar git-gutter+-popup-buffer \"*git-gutter+-diff*\")\n141 (defvar git-gutter+-buffers-to-reenable nil)\n\n143 (defconst git-gutter+-hunk-header-regex\n144 ;; The same as diff-hunk-header-re-unified\n145 \"^@@ -\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? \\\\+\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? @@\")\n\n147 (defalias 'git-gutter+-popup-hunk 'git-gutter+-show-hunk)\n148 (defalias 'git-gutter+-revert-hunk 'git-gutter+-revert-hunks)\n\n150 (defmacro git-gutter+-awhen (test &rest body)\n151 \"Anaphoric when.\"\n152 (declare (indent 1))\n153 `(let ((it ,test))\n154 (when it ,@body)))\n\n156 (defun git-gutter+-enable-default-display-mode ()\n157 (setq git-gutter+-view-diff-function 'git-gutter+-view-diff-infos\n158 git-gutter+-clear-function 'git-gutter+-clear-diff-infos\n159 git-gutter+-window-config-change-function 'git-gutter+-show-gutter))\n\n161 (unless git-gutter+-view-diff-function\n162 (git-gutter+-enable-default-display-mode))\n\n164 (defun git-gutter+-call-git (args &optional file)\n165 (if (and file (file-remote-p file))\n166 (apply #'process-file git-gutter+-git-executable nil t nil args)\n167 (apply #'call-process git-gutter+-git-executable nil t nil args)))\n\n169 (defun git-gutter+-in-git-repository-p (file)\n170 (with-temp-buffer\n171 (let ((args '(\"rev-parse\" \"--is-inside-work-tree\")))\n172 (when (zerop (git-gutter+-call-git args file))\n173 (goto-char (point-min))\n174 (string= \"true\" (buffer-substring-no-properties\n175 (point) (line-end-position)))))))\n\n177 (defun git-gutter+-root-directory (file)\n178 (with-temp-buffer\n179 (let* ((args '(\"rev-parse\" \"--show-toplevel\"))\n180 (ret (git-gutter+-call-git args file)))\n181 (when (zerop ret)\n182 (goto-char (point-min))\n183 (let ((root (buffer-substring-no-properties (point) (line-end-position))))\n184 (unless (string= root \"\")\n185 (file-name-as-directory root)))))))\n\n187 (defsubst git-gutter+-diff-args (file)\n188 (delq nil (list \"--no-pager\" \"diff\" \"--no-color\" \"--no-ext-diff\" \"-U0\"\n189 git-gutter+-diff-options file)))\n\n191 (defun git-gutter+-diff (curfile)\n192 (let ((args (git-gutter+-diff-args curfile))\n193 (file (buffer-file-name))) ;; for tramp\n194 (with-temp-buffer\n195 (when (zerop (git-gutter+-call-git args file))\n196 (goto-char (point-min))\n197 (let ((diff-header (git-gutter+-get-diff-header))\n198 (diffinfos (git-gutter+-get-diffinfos)))\n199 (list diff-header diffinfos))))))\n\n201 (defun git-gutter+-get-diff-header ()\n202 (save-excursion\n203 (if (re-search-forward git-gutter+-hunk-header-regex nil t)\n204 (buffer-substring (point-min) (match-beginning 0)))))\n\n206 (defsubst git-gutter+-make-diffinfo (type content start end)\n207 (list :type type :content content :start-line start :end-line end))\n\n209 (defun git-gutter+-get-diffinfos ()\n210 (loop while (re-search-forward git-gutter+-hunk-header-regex nil t)\n211 ;; Hunk header format:\n212 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n213 for del-len = (string-to-number (or (match-string 2) \"1\"))\n214 for add-line = (string-to-number (match-string 3))\n215 for add-len = (string-to-number (or (match-string 4) \"1\"))\n216 for type = (cond ((zerop del-len) 'added)\n217 ((zerop add-len) 'deleted)\n218 (t 'modified))\n219 for start-line = (if (eq type 'deleted)\n220 (1+ add-line)\n221 add-line)\n222 for end-line = (if (eq type 'deleted)\n223 start-line\n224 (1- (+ add-line add-len)))\n225 for content = (git-gutter+-diff-content)\n226 collect\n227 (git-gutter+-make-diffinfo type content start-line end-line)))\n\n229 (defun git-gutter+-diff-content ()\n230 (save-excursion\n231 (goto-char (line-beginning-position)) ; Move to beginning of hunk header\n232 (let ((hunk-start (point)))\n233 ;; Move to end of hunk\n234 (forward-line 1)\n235 (if (re-search-forward \"^@@\" nil t)\n236 (backward-char 3) ;; exclude \"\\n@@\"\n237 (goto-char (1- (point-max)))) ; Skip trailing newline\n238 (buffer-substring hunk-start (point)))))\n\n240 (defun git-gutter+-line-to-pos (line)\n241 (save-excursion\n242 (goto-char (point-min))\n243 (forward-line (1- line))\n244 (point)))\n\n246 (defun git-gutter+-before-string (sign)\n247 (let* ((sep-sign git-gutter+-separator-sign)\n248 (sep (when sep-sign\n249 (propertize sep-sign 'face 'git-gutter+-separator)))\n250 (gutter-sep (concat sign sep)))\n251 (propertize \" \" 'display `((margin left-margin) ,gutter-sep))))\n\n253 (defsubst git-gutter+-select-face (type)\n254 (case type\n255 (added 'git-gutter+-added)\n256 (modified 'git-gutter+-modified)\n257 (deleted 'git-gutter+-deleted)))\n\n259 (defsubst git-gutter+-select-sign (type)\n260 (case type\n261 (added git-gutter+-added-sign)\n262 (modified git-gutter+-modified-sign)\n263 (deleted git-gutter+-deleted-sign)))\n\n265 (defun git-gutter+-propertized-sign (type)\n266 (let ((sign (git-gutter+-select-sign type))\n267 (face (git-gutter+-select-face type)))\n268 (propertize sign 'face face)))\n\n270 (defun git-gutter+-view-region (sign start-line end-line)\n271 (let ((beg (git-gutter+-line-to-pos start-line)))\n272 (goto-char beg)\n273 (while (and (<= (line-number-at-pos) end-line) (not (eobp)))\n274 (git-gutter+-view-at-pos sign (point))\n275 (forward-line 1))))\n\n277 (defun git-gutter+-view-at-pos (sign pos)\n278 (let ((ov (make-overlay pos pos)))\n279 (overlay-put ov 'before-string (git-gutter+-before-string sign))\n280 (overlay-put ov 'git-gutter+ t)))\n\n282 (defun git-gutter+-view-diff-info (diffinfo)\n283 (let* ((start-line (plist-get diffinfo :start-line))\n284 (end-line (plist-get diffinfo :end-line))\n285 (type (plist-get diffinfo :type))\n286 (sign (git-gutter+-propertized-sign type)))\n287 (case type\n288 ((modified added) (git-gutter+-view-region sign start-line end-line))\n289 (deleted (git-gutter+-view-at-pos\n290 sign (git-gutter+-line-to-pos start-line))))))\n\n292 (defun git-gutter+-sign-width (sign)\n293 (loop for s across sign\n294 sum (char-width s)))\n\n296 (defun git-gutter+-longest-sign-width ()\n297 (let ((signs (list git-gutter+-modified-sign\n298 git-gutter+-added-sign\n299 git-gutter+-deleted-sign)))\n300 (when git-gutter+-unchanged-sign\n301 (add-to-list 'signs git-gutter+-unchanged-sign))\n302 (+ (apply 'max (mapcar 'git-gutter+-sign-width signs))\n303 (git-gutter+-sign-width git-gutter+-separator-sign))))\n\n305 (defun git-gutter+-view-for-unchanged ()\n306 (save-excursion\n307 (let ((sign (if git-gutter+-unchanged-sign\n308 (propertize git-gutter+-unchanged-sign\n309 'face 'git-gutter+-unchanged)\n310 \" \")))\n311 (goto-char (point-min))\n312 (while (not (eobp))\n313 (git-gutter+-view-at-pos sign (point))\n314 (forward-line 1)))))\n\n316 (defun git-gutter+-set-window-margin (width)\n317 (let ((curwin (get-buffer-window)))\n318 (set-window-margins curwin width (cdr (window-margins curwin)))))\n\n320 (defsubst git-gutter+-file-buffer-p ()\n321 (and (buffer-file-name)\n322 default-directory\n323 (file-directory-p default-directory)))\n\n325 ;;;###autoload\n326 (define-minor-mode git-gutter+-mode\n327 \"Git-Gutter mode\"\n328 :group 'git-gutter+\n329 :init-value nil\n330 :global nil\n331 :lighter git-gutter+-lighter\n332 (if git-gutter+-mode\n333 (if (and (git-gutter+-file-buffer-p)\n334 (git-gutter+-in-git-repository-p (buffer-file-name)))\n335 (progn\n336 (git-gutter+-add-local-hooks)\n337 (git-gutter+-refresh))\n338 (if (called-interactively-p 'any)\n339 (message \"No Git repo for current buffer\"))\n340 (git-gutter+-mode -1))\n341 (git-gutter+-remove-local-hooks)\n342 (git-gutter+-clear)))\n\n344 (defun git-gutter+-add-local-hooks ()\n345 (add-hook 'after-save-hook 'git-gutter+-refresh nil t)\n346 ;; Turn off `git-gutter+-mode' while reverting to prevent any redundant calls to\n347 ;; `git-gutter+-refresh'.\n348 (add-hook 'before-revert-hook 'git-gutter+-turn-off nil t)\n349 (add-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change nil t)\n350 (if git-gutter+-window-config-change-function\n351 (add-hook 'window-configuration-change-hook\n352 git-gutter+-window-config-change-function nil t)))\n\n354 (defun git-gutter+-remove-local-hooks ()\n355 (remove-hook 'after-save-hook 'git-gutter+-refresh t)\n356 (remove-hook 'before-revert-hook 'git-gutter+-turn-off t)\n357 (remove-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change t)\n358 (if git-gutter+-window-config-change-function\n359 (remove-hook 'window-configuration-change-hook\n360 git-gutter+-window-config-change-function t)))\n\n362 (defmacro git-gutter+-in-all-buffers (&rest body)\n363 `(dolist (buf (buffer-list))\n364 (with-current-buffer buf\n365 ,@body)))\n\n367 ;; When `define-globalized-minor-mode' is used to define `global-git-gutter+-mode',\n368 ;; `git-gutter+-mode' and thus `git-gutter+-refresh' get run twice when a new file\n369 ;; is opened. (First for `fundamental-mode', then for the file-specific mode.)\n370 ;; The following definition of `global-git-gutter+-mode' avoids any redundant calls to\n371 ;; `git-gutter+-refresh'.\n\n373 ;;;###autoload\n374 (define-minor-mode global-git-gutter+-mode ()\n375 \"Global Git-Gutter mode\"\n376 :group 'git-gutter+\n377 :init-value nil\n378 :global t\n379 (if global-git-gutter+-mode\n380 (progn\n381 (add-hook 'find-file-hook 'git-gutter+-turn-on)\n382 (add-hook 'after-revert-hook 'git-gutter+-turn-on)\n383 (add-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n384 (git-gutter+-in-all-buffers (git-gutter+-turn-on)))\n385 (remove-hook 'find-file-hook 'git-gutter+-turn-on)\n386 (remove-hook 'after-revert-hook 'git-gutter+-turn-on)\n387 (remove-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n388 (git-gutter+-in-all-buffers (git-gutter+-turn-off))))\n\n390 (defun git-gutter+-turn-on ()\n391 (when (and (buffer-file-name)\n392 (not (memq major-mode git-gutter+-disabled-modes))\n393 (not git-gutter+-mode))\n394 (git-gutter+-mode t)))\n\n396 (defun git-gutter+-turn-off ()\n397 (if git-gutter+-mode (git-gutter+-mode -1)))\n\n399 (defun git-gutter+-reenable-after-major-mode-change ()\n400 (if global-git-gutter+-mode\n401 (add-to-list 'git-gutter+-buffers-to-reenable (current-buffer))))\n\n403 (defun git-gutter+-reenable-buffers ()\n404 (dolist (buf git-gutter+-buffers-to-reenable)\n405 (with-current-buffer buf\n406 (git-gutter+-turn-on)))\n407 (setq git-gutter+-buffers-to-reenable nil))\n\n409 (defsubst git-gutter+-show-gutter-p (diffinfos)\n410 (if git-gutter+-hide-gutter\n411 (or diffinfos git-gutter+-unchanged-sign)\n412 (or global-git-gutter+-mode git-gutter+-unchanged-sign diffinfos)))\n\n414 (defun git-gutter+-show-gutter (&optional diffinfos)\n415 (when (git-gutter+-show-gutter-p (or diffinfos git-gutter+-diffinfos))\n416 (let ((win-width (or git-gutter+-window-width\n417 (git-gutter+-longest-sign-width))))\n418 (git-gutter+-set-window-margin win-width))))\n\n420 (defun git-gutter+-view-diff-infos (diffinfos)\n421 (when (or git-gutter+-unchanged-sign\n422 git-gutter+-separator-sign)\n423 (git-gutter+-view-for-unchanged))\n424 (when diffinfos\n425 (save-excursion\n426 (mapc 'git-gutter+-view-diff-info diffinfos)))\n427 (git-gutter+-show-gutter diffinfos))\n\n429 (defsubst git-gutter+-reset-window-margin-p ()\n430 (or git-gutter+-hide-gutter\n431 (not global-git-gutter+-mode)))\n\n433 (defun git-gutter+-clear-diff-infos ()\n434 (when (git-gutter+-reset-window-margin-p)\n435 (git-gutter+-set-window-margin 0))\n436 (remove-overlays (point-min) (point-max) 'git-gutter+ t))\n\n438 (defun git-gutter+-process-diff (curfile)\n439 (destructuring-bind\n440 (diff-header diffinfos) (git-gutter+-diff curfile)\n441 (setq git-gutter+-diff-header diff-header\n442 git-gutter+-diffinfos diffinfos)\n443 (save-restriction\n444 (widen)\n445 (funcall git-gutter+-view-diff-function diffinfos))))\n\n447 (defun git-gutter+-search-near-diff-index (diffinfos is-reverse)\n448 (loop with current-line = (line-number-at-pos)\n449 with cmp-fn = (if is-reverse '> '<)\n450 for diffinfo in (if is-reverse (reverse diffinfos) diffinfos)\n451 for index = 0 then (1+ index)\n452 for start-line = (plist-get diffinfo :start-line)\n453 when (funcall cmp-fn current-line start-line)\n454 return (if is-reverse\n455 (1- (- (length diffinfos) index))\n456 index)))\n\n458 (defun git-gutter+-diffinfo-at-point ()\n459 (save-restriction\n460 (widen)\n461 (loop with current-line = (line-number-at-pos)\n462 for diffinfo in git-gutter+-diffinfos\n463 for start = (plist-get diffinfo :start-line)\n464 for end = (or (plist-get diffinfo :end-line) (1+ start))\n465 when (and (>= current-line start) (<= current-line end))\n466 return diffinfo)))\n\n468 (defun git-gutter+-collect-deleted-line (str)\n469 (with-temp-buffer\n470 (insert str)\n471 (goto-char (point-min))\n472 (loop while (re-search-forward \"^-\\\\(.*?\\\\)$\" nil t)\n473 collect (match-string 1) into deleted-lines\n474 finally return deleted-lines)))\n\n476 (defun git-gutter+-delete-added-lines (start-line end-line)\n477 (forward-line (1- start-line))\n478 (let ((start-point (point)))\n479 (forward-line (1+ (- end-line start-line)))\n480 (delete-region start-point (point))))\n\n482 (defun git-gutter+-insert-deleted-lines (content)\n483 (dolist (line (git-gutter+-collect-deleted-line content))\n484 (insert (concat line \"\\n\"))))\n\n486 (defun git-gutter+-do-revert-hunk (diffinfo)\n487 (save-excursion\n488 (save-restriction\n489 (widen)\n490 (goto-char (point-min))\n491 (let ((start-line (plist-get diffinfo :start-line))\n492 (end-line (plist-get diffinfo :end-line))\n493 (content (plist-get diffinfo :content)))\n494 (case (plist-get diffinfo :type)\n495 (added (git-gutter+-delete-added-lines start-line end-line))\n496 (deleted (forward-line (1- start-line))\n497 (git-gutter+-insert-deleted-lines content))\n498 (modified (git-gutter+-delete-added-lines start-line end-line)\n499 (git-gutter+-insert-deleted-lines content)))))))\n\n501 (defun git-gutter+-revert-hunks ()\n502 \"Revert hunk at point. If region is active, revert all hunks within the region.\"\n503 (interactive)\n504 (let* ((diffinfos (git-gutter+-selected-diffinfos))\n505 (one-diffinfo-p (= 1 (length diffinfos))))\n506 (save-window-excursion\n507 (if one-diffinfo-p (git-gutter+-show-hunk (car diffinfos)))\n508 (when (and diffinfos\n509 (yes-or-no-p (if one-diffinfo-p\n510 \"Revert hunk?\"\n511 (format \"Revert %d hunks?\" (length diffinfos)))))\n512 ;; Revert diffinfos in reverse so that earlier hunks don't invalidate the\n513 ;; line number information of the later hunks.\n514 (dolist (diffinfo (nreverse diffinfos))\n515 (git-gutter+-do-revert-hunk diffinfo))\n516 (save-buffer))\n517 (if one-diffinfo-p\n518 (git-gutter+-awhen (get-buffer git-gutter+-popup-buffer)\n519 (kill-buffer it))))))\n\n521 (defun git-gutter+-show-hunk (&optional diffinfo)\n522 \"Show hunk at point in another window\"\n523 (interactive)\n524 (git-gutter+-awhen (or diffinfo\n525 (git-gutter+-diffinfo-at-point))\n526 (save-selected-window\n527 (with-current-buffer (get-buffer-create git-gutter+-popup-buffer)\n528 (setq buffer-read-only nil)\n529 (erase-buffer)\n530 (insert (plist-get it :content))\n531 (insert \"\\n\")\n532 (goto-char (point-min))\n533 (diff-mode)\n534 (view-mode)\n535 (pop-to-buffer (current-buffer))))))\n\n537 (defun git-gutter+-next-hunk (arg)\n538 \"Move to next diff hunk\"\n539 (interactive \"p\")\n540 (if (not git-gutter+-diffinfos)\n541 (message \"No changes in buffer\")\n542 (save-restriction\n543 (widen)\n544 (let* ((is-reverse (< arg 0))\n545 (diffinfos git-gutter+-diffinfos)\n546 (len (length diffinfos))\n547 (index (git-gutter+-search-near-diff-index diffinfos is-reverse))\n548 (real-index (if index\n549 (let ((next (if is-reverse (1+ index) (1- index))))\n550 (mod (+ arg next) len))\n551 (if is-reverse (1- (length diffinfos)) 0)))\n552 (diffinfo (nth real-index diffinfos)))\n553 (goto-char (point-min))\n554 (forward-line (1- (plist-get diffinfo :start-line)))\n555 (when (buffer-live-p (get-buffer git-gutter+-popup-buffer))\n556 (save-window-excursion\n557 (git-gutter+-show-hunk)))))))\n\n559 (defun git-gutter+-previous-hunk (arg)\n560 \"Move to previous diff hunk\"\n561 (interactive \"p\")\n562 (git-gutter+-next-hunk (- arg)))\n\n564 (defun git-gutter+-remote-default-directory (dir file)\n565 (let* ((vec (tramp-dissect-file-name file))\n566 (method (aref vec 0))\n567 (user (aref vec 1))\n568 (host (aref vec 2)))\n569 (format \"/%s:%s%s:%s\" method (if user (concat user \"@\") \"\") host dir)))\n\n571 (defun git-gutter+-remote-file-path (dir file)\n572 (let ((file (aref (tramp-dissect-file-name file) 3)))\n573 (replace-regexp-in-string (concat \"\\\\`\" dir) \"\" file)))\n\n575 (defun git-gutter+-local-file-path (file)\n576 (if (eq system-type 'windows-nt)\n577 ;; Cygwin can't handle Windows absolute paths\n578 (file-relative-name file default-directory)\n579 file))\n\n581 (defun git-gutter+-refresh ()\n582 (git-gutter+-clear)\n583 (let ((file (buffer-file-name)))\n584 (when (and file (file-exists-p file))\n585 (if (file-remote-p file)\n586 (let* ((repo-root (git-gutter+-root-directory file))\n587 (default-directory (git-gutter+-remote-default-directory repo-root file)))\n588 (git-gutter+-process-diff (git-gutter+-remote-file-path repo-root file)))\n589 (git-gutter+-process-diff (git-gutter+-local-file-path file))))))\n\n591 (defun git-gutter+-clear ()\n592 (save-restriction\n593 (widen)\n594 (funcall git-gutter+-clear-function))\n595 (setq git-gutter+-diffinfos nil))\n\n\n598 ;;; Staging\n\n600 (defun git-gutter+-stage-hunks ()\n601 \"Stage hunk at point. If region is active, stage all hunk lines within the region.\"\n602 (interactive)\n603 (let* ((line-range (if (use-region-p)\n604 (cons (line-number-at-pos (region-beginning))\n605 (line-number-at-pos (region-end)))))\n606 (diffinfos (git-gutter+-selected-diffinfos line-range)))\n607 (when diffinfos\n608 (let ((error-msg (git-gutter+-stage-diffinfos diffinfos line-range)))\n609 (if error-msg\n610 (message \"Error staging hunks:\\n%s\" error-msg))\n611 (git-gutter+-refresh)))))\n\n613 (defun git-gutter+-selected-diffinfos (&optional line-range)\n614 (unless line-range\n615 (setq line-range (if (use-region-p)\n616 (cons (line-number-at-pos (region-beginning))\n617 (line-number-at-pos (region-end))))))\n618 (if line-range\n619 (git-gutter+-diffinfos-between-lines line-range)\n620 (git-gutter+-awhen (git-gutter+-diffinfo-at-point)\n621 (list it))))\n\n623 (defsubst git-gutter+-diffinfo-between-lines-p (diffinfo start-line end-line)\n624 (let ((diff-start (plist-get diffinfo :start-line))\n625 (diff-end (plist-get diffinfo :end-line)))\n626 (and (<= start-line diff-end)\n627 (<= diff-start end-line))))\n\n629 (defun git-gutter+-diffinfos-between-lines (line-range)\n630 (save-restriction\n631 (widen)\n632 (let ((start-line (car line-range))\n633 (end-line (cdr line-range)))\n634 (delq nil\n635 (mapcar (lambda (diffinfo)\n636 (if (git-gutter+-diffinfo-between-lines-p\n637 diffinfo start-line end-line)\n638 diffinfo))\n639 git-gutter+-diffinfos)))))\n\n641 (defun git-gutter+-stage-diffinfos (diffinfos line-range)\n642 (let ((header git-gutter+-diff-header))\n643 (with-temp-buffer\n644 (insert header)\n645 ;; Insert hunks in reverse so that earlier hunks don't invalidate the line\n646 ;; number information of the later hunks.\n647 (dolist (diffinfo (nreverse diffinfos))\n648 (git-gutter+-insert-diffinfo diffinfo line-range)\n649 (goto-char (point-max)))\n650 (git-gutter+-call-git-on-current-buffer\n651 '(\"apply\" \"--unidiff-zero\" \"--cached\" \"-\")))))\n\n653 (defun git-gutter+-insert-diffinfo (diffinfo line-range)\n654 (let ((content (plist-get diffinfo :content))\n655 (type (plist-get diffinfo :type)))\n656 (if (not line-range)\n657 (git-gutter+-insert-hunk content type)\n658 (let ((diff-start-line (plist-get diffinfo :start-line))\n659 (diff-end-line (plist-get diffinfo :end-line))\n660 (start-line (car line-range))\n661 (end-line (cdr line-range)))\n662 (git-gutter+-insert-hunk content type\n663 (1+ (- start-line diff-start-line))\n664 (1+ (- end-line diff-start-line)))))))\n\n666 (defun git-gutter+-call-git-on-current-buffer (args)\n667 \"Sends the current buffer contents to Git and replaces them with Git's output.\n\n669 RETURNS nil if Git ran successfully. Returns an error description otherwise.\"\n670 (unless (zerop (apply #'call-process-region (point-min) (point-max)\n671 git-gutter+-git-executable t t nil args))\n672 (buffer-string)))\n\n674 (defsubst git-gutter+-read-hunk-header (hunk)\n675 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n676 (string-match git-gutter+-hunk-header-regex hunk)\n677 (list (string-to-number (match-string 1 hunk))\n678 (string-to-number (or (match-string 2 hunk) \"1\"))\n679 (string-to-number (match-string 3 hunk))\n680 (string-to-number (or (match-string 4 hunk) \"1\"))))\n\n682 (defun git-gutter+-insert-hunk (hunk type &optional start end)\n683 \"If START and END are provided, only insert addition (+) lines between\n684 START and END (inclusive). START and END are both line numbers starting with 1.\"\n685 (destructuring-bind\n686 (del-line del-len add-line add-len) (git-gutter+-read-hunk-header hunk)\n687 (let* ((start (max 1 (or start 1)))\n688 (end (min add-len (or end add-len)))\n689 (insert-all-p (or (eq type :deleted)\n690 (and (= start 1) (= end add-len))))\n691 (num-lines-selected (if insert-all-p\n692 add-len\n693 (1+ (- end start)))))\n694 ;; When the user selected the last lines of a hunk with type `modified' (but\n695 ;; not the complete hunk), then don't insert any deletion (-) lines from that\n696 ;; hunk.\n697 (if (and (eq type 'modified)\n698 (> start 1) (= end add-len))\n699 (setq type 'modified-trailing))\n\n701 (save-excursion\n702 (insert hunk \"\\n\"))\n\n704 (git-gutter+-delete-hunk-header)\n\n706 (if (not insert-all-p)\n707 (git-gutter+-modify-hunk type num-lines-selected del-len start))\n\n709 (let ((hunk-header (git-gutter+-make-hunk-header type num-lines-selected\n710 del-line del-len add-line)))\n711 (insert hunk-header \"\\n\")))))\n\n713 (defun git-gutter+-delete-hunk-header ()\n714 (let ((hunk-start (point)))\n715 (forward-line 1)\n716 (delete-region hunk-start (point))))\n\n718 (defun git-gutter+-modify-hunk (type num-lines-selected del-len start)\n719 \"Remove all addition (+) lines from hunk that aren't selected.\n720 If TYPE is not `modified', also remove all deletion (-) lines.\"\n721 (let ((first-line-selected (+ del-len (1- start)))\n722 selected-lines)\n723 (save-excursion\n724 (forward-line first-line-selected)\n725 (let ((selection-start (point)))\n726 (forward-line num-lines-selected)\n727 (setq selected-lines (buffer-substring selection-start (point)))))\n728 (save-excursion\n729 (if (eq type 'modified) (forward-line del-len)) ; skip over deletion (-) lines\n730 (delete-region (point) (point-max))\n731 (insert selected-lines))))\n\n733 (defun git-gutter+-make-hunk-header (type num-lines-selected del-line del-len add-line)\n734 (let ((add-len num-lines-selected))\n735 (case type\n736 (added (setq add-line (1+ del-line)))\n737 (modified-trailing (setq add-line (+ del-line del-len)\n738 del-line (1- add-line)\n739 del-len 0))\n740 (t (setq add-line del-line)))\n741 (format \"@@ -%d,%d +%d,%d @@\"\n742 del-line del-len\n743 add-line add-len)))\n\n\n746 ;;; Committing\n747 ;; This section draws heavily from old Magit source code.\n\n749 (defvar git-gutter+-pre-commit-window-config nil)\n750 (defvar git-gutter+-commit-origin-buffer nil\n751 \"Buffer that started the commit\")\n\n753 (defconst git-gutter+-commit-buffer-name \"*Commit Message*\")\n754 (defconst git-gutter+-staged-changes-buffer-name \"*Staged Changes*\")\n\n756 ;;;###autoload\n757 (defun git-gutter+-commit ()\n758 \"Commit staged changes. If nothing is staged, ask to stage the current buffer.\"\n759 (interactive)\n\n761 (when (and (not (git-gutter+-anything-staged-p))\n762 git-gutter+-diffinfos\n763 (y-or-n-p \"Nothing staged. Stage current buffer? \"))\n764 (git-gutter+-stage-whole-buffer))\n\n766 (let ((file (buffer-file-name))\n767 (dir default-directory))\n768 (git-gutter+-save-window-config-if-needed)\n769 (setq git-gutter+-commit-origin-buffer (current-buffer))\n770 (git-gutter+-open-commit-edit-buffer dir)\n771 (git-gutter+-show-staged-changes file dir)))\n\n773 (defun git-gutter+-stage-and-commit ()\n774 (interactive)\n775 (git-gutter+-stage-hunks)\n776 (git-gutter+-commit))\n\n778 (defun git-gutter+-save-window-config-if-needed ()\n779 ;; Only save the window config if the temporary buffers that get popped-up by\n780 ;; git-gutter+ are not already visible.\n781 ;; In this way, `git-gutter+-commit' can be called twice in a row without\n782 ;; losing the original window config.\n783 (when (not (and git-gutter+-pre-commit-window-config\n784 (get-buffer-window git-gutter+-commit-buffer-name)\n785 (get-buffer-window git-gutter+-staged-changes-buffer-name)))\n786 (setq git-gutter+-pre-commit-window-config (current-window-configuration))))\n\n788 (defun git-gutter+-open-commit-edit-buffer (dir)\n789 \"Opens a buffer for composing the commit message\"\n790 (pop-to-buffer (get-buffer-create git-gutter+-commit-buffer-name))\n791 (setq default-directory dir)\n792 (git-gutter+-commit-mode)\n793 (message \"Type C-c C-c to commit (C-c C-k to cancel).\"))\n\n795 (defsubst git-gutter+-pop-to-staged-changes-buffer ()\n796 (let* ((buf (get-buffer-create git-gutter+-staged-changes-buffer-name))\n797 (window (get-buffer-window buf)))\n798 (if window\n799 ;; Buffer is already visible\n800 (select-window window)\n801 (if (<= (length (window-list)) 2)\n802 (split-window))\n803 (pop-to-buffer buf))))\n\n805 (defun git-gutter+-show-staged-changes (file dir)\n806 (save-selected-window\n807 (git-gutter+-pop-to-staged-changes-buffer)\n808 (setq buffer-read-only nil)\n809 (erase-buffer)\n810 (let ((default-directory dir))\n811 (git-gutter+-call-git '(\"diff\" \"--staged\") file))\n812 (goto-char (point-min))\n813 (diff-mode)\n814 (view-mode)))\n\n816 (defsubst git-gutter+-abort-commit-when-no-changes (allow-empty amend)\n817 (unless (or amend\n818 allow-empty\n819 (git-gutter+-anything-staged-p))\n820 (error\n821 \"Refusing to create empty commit. Maybe you want to amend (%s) or allow-empty (%s)?\"\n822 (key-description (car (where-is-internal\n823 'git-gutter+-commit-toggle-amending)))\n824 (key-description (car (where-is-internal\n825 'git-gutter+-commit-toggle-allow-empty))))))\n\n827 (defsubst git-gutter+-buffer-is-whitespace ()\n828 (save-excursion\n829 (goto-char (point-min))\n830 (looking-at-p \"[ \\t\\n]*\\\\'\")))\n\n832 (defun git-gutter+-publish-commit ()\n833 \"Publish commit\"\n834 (interactive)\n835 (let* ((fields (git-gutter+-commit-get-fields))\n836 (amend (equal \"yes\" (git-gutter+-commit-get-field 'amend fields)))\n837 (allow-empty (equal \"yes\" (git-gutter+-commit-get-field 'allow-empty fields)))\n838 (author (git-gutter+-commit-get-field 'author fields))\n839 (date (git-gutter+-commit-get-field 'date fields)))\n\n841 (git-gutter+-abort-commit-when-no-changes allow-empty amend)\n\n843 (git-gutter+-push-to-comment-ring (buffer-string))\n\n845 (git-gutter+-commit-set-fields nil) ; Delete message header\n\n847 (when (git-gutter+-buffer-is-whitespace)\n848 (erase-buffer)\n849 (insert \"(Empty description)\"))\n\n851 (let ((error-msg (git-gutter+-call-git-on-current-buffer\n852 (append '(\"--no-pager\" \"commit\" \"-F\" \"-\")\n853 (if amend '(\"--amend\"))\n854 (if allow-empty '(\"--allow-empty\"))\n855 (if author (list (concat \"--author=\" author)))\n856 (if date (list (concat \"--date=\" date)))))))\n857 (if error-msg\n858 (progn\n859 (message \"Commit error:\\n%s\" error-msg)\n860 (erase-buffer)\n861 (insert (ring-ref log-edit-comment-ring 0))) ; Reinsert commit message\n862 (message \"Commit successful.\")\n863 (git-gutter+-close-commit-edit-buffer)\n864 (git-gutter+-update-vc-modeline)))))\n\n866 (defun git-gutter+-close-commit-edit-buffer ()\n867 \"Abort edits and discard commit message being composed.\"\n868 (interactive)\n869 (kill-buffer)\n870 (set-window-configuration git-gutter+-pre-commit-window-config))\n\n872 (defun git-gutter+-update-vc-modeline ()\n873 (when (buffer-live-p git-gutter+-commit-origin-buffer)\n874 (with-current-buffer git-gutter+-commit-origin-buffer\n875 ;; Updating the modeline has no effect if the buffer still has\n876 ;; changes - it will remain in the 'modified' state. So skip it then.\n877 (unless git-gutter+-diffinfos\n878 (ignore-errors (vc-find-file-hook))))))\n\n880 (defun git-gutter+-stage-whole-buffer ()\n881 (save-excursion\n882 (mark-whole-buffer)\n883 (git-gutter+-stage-hunks)))\n\n885 (defun git-gutter+-anything-staged-p ()\n886 \"Return t if the current repo has staged changes\"\n887 (not (zerop (git-gutter+-call-git '(\"diff\" \"--quiet\" \"--cached\")))))\n\n889 (defun git-gutter+-commit-toggle-amending ()\n890 \"Toggle whether this will be an amendment to the previous commit.\n891 \\(i.e., whether commit is run via 'git commit --amend')\"\n892 (interactive)\n893 ;; Remove the newline that 'git-commit-mode' adds to a new commit\n894 ;; message buffer by default. This prevents an ugly visual\n895 ;; gap between the commit message header and the previous commit\n896 ;; message.\n897 (when (git-gutter+-buffer-is-whitespace)\n898 (erase-buffer))\n\n900 (let ((amend-was-already-set (git-gutter+-commit-get-field 'amend)))\n901 (git-gutter+-commit-toggle-field 'amend t)\n902 (unless amend-was-already-set\n903 ;; Insert previous commit message\n904 (goto-char (point-max))\n905 (unless (zerop (current-column))\n906 (insert \"\\n\"))\n907 (insert (git-gutter+-get-last-commit-msg)\n908 \"\\n\"))))\n\n910 (defun git-gutter+-commit-toggle-allow-empty ()\n911 \"Toggle whether this commit is allowed to be empty.\n912 \\(i.e., whether commit is run via 'git commit --allow-empty')\"\n913 (interactive)\n914 (git-gutter+-commit-toggle-field 'allow-empty t))\n\n916 (defun git-gutter+-format-author (author email)\n917 (format \"%s <%s>\" author email))\n\n919 (defun git-gutter+-commit-toggle-author ()\n920 \"Toggle whether this commit should have a user-defined author.\"\n921 (interactive)\n922 (git-gutter+-commit-toggle-input\n923 'author (git-gutter+-format-author\n924 (or (git-gutter+-get-cfg \"user\" \"name\") \"Author Name\")\n925 (or (git-gutter+-get-cfg \"user\" \"email\") \"author@email\"))))\n\n927 (defun git-gutter+-commit-toggle-date ()\n928 \"Toggle whether this commit should have a user-defined date.\"\n929 (interactive)\n930 (git-gutter+-commit-toggle-input 'date\n931 ;; ISO 8601\n932 (format-time-string \"%Y-%m-%dT%T%z\" (current-time))))\n\n934 (defun git-gutter+-push-to-comment-ring (comment)\n935 (when (or (ring-empty-p log-edit-comment-ring)\n936 (not (equal comment (ring-ref log-edit-comment-ring 0))))\n937 (ring-insert log-edit-comment-ring comment)))\n\n939 (defun git-gutter+-get-last-commit-msg ()\n940 (git-gutter+-git-output '(\"log\" \"--max-count=1\" \"--pretty=format:%s%n%n%b\" \"HEAD\")))\n\n942 (defun git-gutter+-get-cfg (&rest keys)\n943 (git-gutter+-git-output (list \"config\" (mapconcat 'identity keys \".\"))))\n\n945 (defun git-gutter+-git-output (args)\n946 (with-temp-buffer\n947 (git-gutter+-call-git args)\n948 ;; Delete trailing newlines\n949 (goto-char (point-min))\n950 (if (re-search-forward \"\\n+\\\\'\" nil t)\n951 (replace-match \"\"))\n952 (buffer-string)))\n\n\n955 ;;; Commit message header\n\n957 (defconst git-gutter+-commit-header-end \"-- End of commit options header --\\n\")\n\n959 (defun git-gutter+-commit-get-field (name &optional fields)\n960 (cdr (assq name (or fields (git-gutter+-commit-get-fields)))))\n\n962 (defun git-gutter+-commit-set-field (name value)\n963 (let* ((fields (git-gutter+-commit-get-fields))\n964 (cell (assq name fields)))\n965 (cond (cell\n966 (if value\n967 (rplacd cell value)\n968 (setq fields (delq cell fields))))\n969 (t\n970 (if value\n971 (setq fields (append fields (list (cons name value)))))))\n972 (git-gutter+-commit-set-fields fields)))\n\n974 (defun git-gutter+-commit-toggle-field (name default)\n975 \"Toggle the commit header field named NAME.\n976 If it's currently unset, set it to DEFAULT (t or nil).\"\n977 (let* ((fields (git-gutter+-commit-get-fields))\n978 (cell (assq name fields)))\n979 (if cell\n980 (rplacd cell (if (equal (cdr cell) \"yes\") \"no\" \"yes\"))\n981 (setq fields (acons name (if default \"yes\" \"no\") fields)))\n982 (git-gutter+-commit-set-fields fields)))\n\n984 (defun git-gutter+-commit-toggle-input (name default)\n985 \"Toggle the commit header input named NAME.\n986 If it's currently unset, set it to DEFAULT (a string). If it is\n987 set remove it.\"\n988 (let* ((fields (git-gutter+-commit-get-fields))\n989 (cell (assq name fields)))\n990 (if cell\n991 (setq fields (assq-delete-all name fields))\n992 (setq fields (acons name default fields)))\n993 (git-gutter+-commit-set-fields fields)))\n\n995 (defun git-gutter+-commit-get-fields ()\n996 (let (result)\n997 (goto-char (point-min))\n998 (while (looking-at \"^\\\\([A-Za-z0-9-_]+\\\\): *\\\\(.+\\\\)?$\")\n999 (let ((name (intern (downcase (match-string 1))))\n1000 (value (read (or (match-string 2) \"nil\"))))\n1001 (push (cons name value) result))\n1002 (forward-line))\n1003 (if (looking-at (regexp-quote git-gutter+-commit-header-end))\n1004 (nreverse result))))\n\n1006 (defun git-gutter+-commit-set-fields (fields)\n1007 (goto-char (point-min))\n1008 ;; Delete commit header\n1009 (if (search-forward-regexp (format \"^\\\\(?:[A-Za-z0-9-_]+:.*\\n\\\\)*%s\"\n1010 (regexp-quote git-gutter+-commit-header-end))\n1011 nil t)\n1012 (delete-region (match-beginning 0) (match-end 0)))\n1013 (goto-char (point-min))\n1014 (when fields\n1015 (dolist (field fields)\n1016 (insert (capitalize (symbol-name (car field))) \": \"\n1017 (prin1-to-string (cdr field)) \"\\n\"))\n1018 (insert git-gutter+-commit-header-end)))\n\n\n1021 ;;; git-gutter+-commit-mode\n1022 ;; Like git-commit-mode, but adds keybindings to git-gutter+ commands and\n1023 ;; highlighting support for the commit message header.\n\n1025 (define-derived-mode git-gutter+-commit-mode git-commit-mode \"Git-Gutter-Commit\"\n1026 (setq font-lock-defaults (list (git-gutter+-commit-font-lock-keywords) t)))\n\n1028 (setq git-gutter+-commit-mode-map\n1029 (let ((map (copy-keymap git-commit-mode-map)))\n1030 (define-key map (kbd \"C-c C-c\") 'git-gutter+-publish-commit)\n1031 (define-key map (kbd \"C-c C-k\") 'git-gutter+-close-commit-edit-buffer)\n1032 (define-key map (kbd \"C-c C-a\") 'git-gutter+-commit-toggle-amending)\n1033 (define-key map (kbd \"C-c C-e\") 'git-gutter+-commit-toggle-allow-empty)\n1034 (define-key map (kbd \"C-c C-u\") 'git-gutter+-commit-toggle-author)\n1035 (define-key map (kbd \"C-c C-d\") 'git-gutter+-commit-toggle-date)\n1036 (define-key map (kbd \"C-c C-b\") 'git-commit-ack)\n1037 (define-key map (kbd \"M-p\") 'log-edit-previous-comment)\n1038 (define-key map (kbd \"M-n\") 'log-edit-next-comment)\n1039 map))\n\n1041 (defface git-gutter+-commit-header-face\n1042 '((t :inherit font-lock-comment-face))\n1043 \"Highlights the commit message header\"\n1044 :group 'git-gutter+-faces)\n\n1046 (defconst git-gutter+-commit-header-regex\n1047 (concat \"\\\\(?:.\\\\|\\n\\\\)*?\" (regexp-quote git-gutter+-commit-header-end)))\n\n1049 (defconst git-gutter+-skip-commit-header-regex\n1050 (concat \"\\\\`\\\\(?:\" git-gutter+-commit-header-regex \"\\\\)?\"))\n\n1052 ;; Modify git-commit-summary-regexp to ignore the commit header\n1053 (defadvice git-commit-summary-regexp\n1054 (after ignore-git-gutter+-commit-header activate compile)\n1055 (if (eq major-mode 'git-gutter+-commit-mode)\n1056 (setq ad-return-value\n1057 (concat git-gutter+-skip-commit-header-regex\n1058 (substring ; Remove leading \"\\\\`\"\n1059 ad-return-value 2)))))\n\n1061 (defun git-gutter+-commit-font-lock-keywords ()\n1062 \"Like `git-commit-mode-font-lock-keywords' but with commit header highlighting\"\n1063 `((,(concat \"\\\\`\" git-gutter+-commit-header-regex) . 'git-gutter+-commit-header-face)\n1064 ,@(git-commit-mode-font-lock-keywords)))\n\n\n1067 ;;; Magit synchronization\n1068 ;; Force Magit to refresh git-gutter+ when updating the VC mode line.\n\n1070 (defvar git-gutter+-orig-vc-find-file-hook)\n\n1072 (defvar git-gutter+-vc-find-file-hook-with-refresh\n1073 (lambda ()\n1074 (funcall git-gutter+-orig-vc-find-file-hook)\n1075 (if git-gutter+-mode (git-gutter+-refresh))))\n\n1077 (defadvice magit-update-vc-modeline (around refresh-git-gutter+ compile activate)\n1078 ;; `magit-update-vc-modeline' calls `vc-find-file-hook' (a function!) on each\n1079 ;; buffer in the repo. Temporarily rebind it to `vc-find-file-hook-with-refresh',\n1080 ;; which calls git-gutter+-refresh after updating the VC mode line.\n1081 ;;\n1082 ;; Using `flet' would have been much simpler, but it's deprecated since 24.3.\n1083 (setq git-gutter+-orig-vc-find-file-hook (symbol-function 'vc-find-file-hook))\n1084 (fset 'vc-find-file-hook git-gutter+-vc-find-file-hook-with-refresh)\n1085 (unwind-protect\n1086 ad-do-it\n1087 (fset 'vc-find-file-hook git-gutter+-orig-vc-find-file-hook)))\n\n1089 (provide 'git-gutter+)\n\n1091 ;;; git-gutter+.el ends here\n")) (setq helm-swoop-cache t))) (candidates-in-buffer) (get-line . buffer-substring-no-properties) (keymap keymap (C-M-left . backward-sexp) (C-M-right . forward-sexp) (27 keymap (105 . helm-multi-swoop-all-from-helm-swoop)) (3 keymap (5 . helm-swoop-edit)) keymap (C-M-left . paren-backward-sexp) (C-M-right . paren-forward-sexp) (94 . helm-swoop-caret-match) (menu-bar keymap (help-menu keymap (describe keymap ...))) (help keymap (109 . helm-help)) (f1 keymap (109 . helm-help)) (8 keymap (109 . helm-help) (104 . undefined) (8 . undefined) (4 . helm-debug-output)) (20 . helm-toggle-resplit-and-swap-windows) (C-tab . undefined) (triple-mouse-3 . ignore) (double-mouse-3 . ignore) (mouse-3 . ignore) (drag-mouse-3 . ignore) (down-mouse-3 . ignore) (triple-mouse-2 . ignore) (double-mouse-2 . ignore) (mouse-2 . ignore) (drag-mouse-2 . ignore) (down-mouse-2 . ignore) (triple-mouse-1 . ignore) (double-mouse-1 . ignore) (mouse-1 . ignore) (drag-mouse-1 . ignore) (down-mouse-1 . ignore) (67108897 . helm-toggle-suspend-update) (3 keymap (21 . helm-force-update) (6 . helm-follow-mode) (11 . helm-kill-selection-and-quit) (25 . helm-yank-selection) (4 . helm-delete-current-selection) (45 . helm-swap-windows)) (67108987 . helm-enlarge-window) (67108989 . helm-narrow-window) (19 . undefined) (18 . undefined) (23 . helm-yank-text-at-point) (24 keymap (2 . helm-resume-list-buffers-after-quit) (98 . helm-resume-previous-session-after-quit) (6 . helm-quit-and-find-file)) (11 . helm-delete-minibuffer-contents) (67108896 . helm-toggle-visible-mark) (0 . helm-toggle-visible-mark) (C-M-up . helm-scroll-other-window-down) (C-M-down . helm-scroll-other-window) (M-prior . helm-scroll-other-window-down) (M-next . helm-scroll-other-window) (12 . helm-recenter-top-bottom-other-window) (15 . helm-next-source) (10 . helm-select-3rd-action) (5 . helm-select-2nd-action-or-end-of-line) ...) (header-line . "[C-c C-e] Edit mode, [M-i] apply all buffers") (action lambda ($line) (helm-swoop--goto-line (when (string-match "^[0-9]+" $line) (string-to-number ...))) (when (re-search-forward (mapconcat ... ... "\\|") nil t) (goto-char (match-beginning 0))) (helm-swoop--recenter)) (migemo)) :buffer "*Helm Swoop*" :input #("git-gutter+-refresh" 0 19 (fontified t face whitespace-line)) :prompt "Swoop: " :preselect "^368 " :candidate-number-limit 19999) helm helm-argument-keys apply mapcar make-byte-code 257 "\301\300\"\207" vconcat vector [plist-get] 4 "\n\n(fn KEY)"] 9 "\n\n(fn)"]()
helm-let-internal(((helm-candidate-number-limit . 19999)) #[0 "\303\301\304\305\306\307\310\311\300!\312\"\313\314%\n\"\"\207" [(:sources ((name . "git-gutter+.el") (init lambda nil (unless helm-swoop-cache (with-current-buffer (helm-candidate-buffer ...) (insert "1 ;;; git-gutter+.el --- Manage Git hunks straight from the buffer\n\n3 ;; Copyright (C) 2013 by Syohei YOSHIDA and contributors\n\n5 ;; Author: Syohei YOSHIDA <syohex@gmail.com> and contributors\n6 ;; URL: https://github.com/nonsequitur/git-gutter-plus\n7 ;; Version: 0.1\n\n9 ;; This program is free software; you can redistribute it and/or modify\n10 ;; it under the terms of the GNU General Public License as published by\n11 ;; the Free Software Foundation, either version 3 of the License, or\n12 ;; (at your option) any later version.\n\n14 ;; This program is distributed in the hope that it will be useful,\n15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of\n16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n17 ;; GNU General Public License for more details.\n\n19 ;; You should have received a copy of the GNU General Public License\n20 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n22 ;; Package-Requires: ((git-commit-mode \"0.14\"))\n\n24 ;;; Commentary:\n25 ;;\n26 ;; View, stage and revert Git changes straight from the buffer.\n\n28 ;;; Code:\n\n30 (eval-when-compile\n31 (require 'cl))\n\n33 (require 'tramp)\n34 (require 'log-edit)\n35 (require 'git-commit-mode)\n\n37 (defgroup git-gutter+ nil\n38 \"Manage Git hunks straight from the buffer\"\n39 :prefix \"git-gutter+-\"\n40 :group 'vc)\n\n42 (defcustom git-gutter+-window-width nil\n43 \"Character width of the gutter margin. Set this variable if the automatically\n44 calculated width looks wrong. (This can happen with some special characters.)\"\n45 :type 'integer\n46 :group 'git-gutter+)\n\n48 (defcustom git-gutter+-git-executable \"git\"\n49 \"The path of the Git executable.\"\n50 :type 'string\n51 :group 'git-gutter+)\n\n53 (defcustom git-gutter+-diff-options nil\n54 \"List of strings containing extra arguments to 'git diff'\"\n55 :type 'list\n56 :group 'git-gutter+)\n\n58 (defcustom git-gutter+-separator-sign nil\n59 \"Separator sign\"\n60 :type 'string\n61 :group 'git-gutter+)\n\n63 (defcustom git-gutter+-modified-sign \"=\"\n64 \"Modified sign\"\n65 :type 'string\n66 :group 'git-gutter+)\n\n68 (defcustom git-gutter+-added-sign \"+\"\n69 \"Added sign\"\n70 :type 'string\n71 :group 'git-gutter+)\n\n73 (defcustom git-gutter+-deleted-sign \"-\"\n74 \"Deleted sign\"\n75 :type 'string\n76 :group 'git-gutter+)\n\n78 (defcustom git-gutter+-unchanged-sign nil\n79 \"Unchanged sign\"\n80 :type 'string\n81 :group 'git-gutter+)\n\n83 (defcustom git-gutter+-hide-gutter nil\n84 \"Hide gutter if there are no changes\"\n85 :type 'boolean\n86 :group 'git-gutter+)\n\n88 (defcustom git-gutter+-lighter \" GitGutter\"\n89 \"Minor mode lighter in mode-line\"\n90 :type 'string\n91 :group 'git-gutter+)\n\n93 (defface git-gutter+-separator\n94 '((t (:foreground \"cyan\" :weight bold)))\n95 \"Face of the separator\"\n96 :group 'git-gutter+)\n\n98 (defface git-gutter+-modified\n99 '((t (:foreground \"magenta\" :weight bold)))\n100 \"Face for modified lines\"\n101 :group 'git-gutter+)\n\n103 (defface git-gutter+-added\n104 '((t (:foreground \"green\" :weight bold)))\n105 \"Face for added lines\"\n106 :group 'git-gutter+)\n\n108 (defface git-gutter+-deleted\n109 '((t (:foreground \"red\" :weight bold)))\n110 \"Face for deleted lines\"\n111 :group 'git-gutter+)\n\n113 (defface git-gutter+-unchanged\n114 '((t (:background \"yellow\")))\n115 \"Face for unchanged lines\"\n116 :group 'git-gutter+)\n\n118 (defcustom git-gutter+-disabled-modes nil\n119 \"A list of modes for which `global-git-gutter+-mode' should be disabled.\"\n120 :type '(repeat symbol)\n121 :group 'git-gutter+)\n\n123 (defvar git-gutter+-mode-map\n124 (make-sparse-keymap))\n\n126 (defvar git-gutter+-view-diff-function nil\n127 \"Function to call for displaying diffs\")\n\n129 (defvar git-gutter+-clear-function nil\n130 \"Function to call for clearing the diff display\")\n\n132 (defvar git-gutter+-window-config-change-function nil\n133 \"Function to call when the buffer's local window configuration has changed\")\n\n135 (defvar git-gutter+-diffinfos nil)\n136 (defvar git-gutter+-diff-header nil)\n137 (make-variable-buffer-local 'git-gutter+-diffinfos)\n138 (make-variable-buffer-local 'git-gutter+-diff-header)\n\n140 (defvar git-gutter+-popup-buffer \"*git-gutter+-diff*\")\n141 (defvar git-gutter+-buffers-to-reenable nil)\n\n143 (defconst git-gutter+-hunk-header-regex\n144 ;; The same as diff-hunk-header-re-unified\n145 \"^@@ -\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? \\\\+\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? @@\")\n\n147 (defalias 'git-gutter+-popup-hunk 'git-gutter+-show-hunk)\n148 (defalias 'git-gutter+-revert-hunk 'git-gutter+-revert-hunks)\n\n150 (defmacro git-gutter+-awhen (test &rest body)\n151 \"Anaphoric when.\"\n152 (declare (indent 1))\n153 `(let ((it ,test))\n154 (when it ,@body)))\n\n156 (defun git-gutter+-enable-default-display-mode ()\n157 (setq git-gutter+-view-diff-function 'git-gutter+-view-diff-infos\n158 git-gutter+-clear-function 'git-gutter+-clear-diff-infos\n159 git-gutter+-window-config-change-function 'git-gutter+-show-gutter))\n\n161 (unless git-gutter+-view-diff-function\n162 (git-gutter+-enable-default-display-mode))\n\n164 (defun git-gutter+-call-git (args &optional file)\n165 (if (and file (file-remote-p file))\n166 (apply #'process-file git-gutter+-git-executable nil t nil args)\n167 (apply #'call-process git-gutter+-git-executable nil t nil args)))\n\n169 (defun git-gutter+-in-git-repository-p (file)\n170 (with-temp-buffer\n171 (let ((args '(\"rev-parse\" \"--is-inside-work-tree\")))\n172 (when (zerop (git-gutter+-call-git args file))\n173 (goto-char (point-min))\n174 (string= \"true\" (buffer-substring-no-properties\n175 (point) (line-end-position)))))))\n\n177 (defun git-gutter+-root-directory (file)\n178 (with-temp-buffer\n179 (let* ((args '(\"rev-parse\" \"--show-toplevel\"))\n180 (ret (git-gutter+-call-git args file)))\n181 (when (zerop ret)\n182 (goto-char (point-min))\n183 (let ((root (buffer-substring-no-properties (point) (line-end-position))))\n184 (unless (string= root \"\")\n185 (file-name-as-directory root)))))))\n\n187 (defsubst git-gutter+-diff-args (file)\n188 (delq nil (list \"--no-pager\" \"diff\" \"--no-color\" \"--no-ext-diff\" \"-U0\"\n189 git-gutter+-diff-options file)))\n\n191 (defun git-gutter+-diff (curfile)\n192 (let ((args (git-gutter+-diff-args curfile))\n193 (file (buffer-file-name))) ;; for tramp\n194 (with-temp-buffer\n195 (when (zerop (git-gutter+-call-git args file))\n196 (goto-char (point-min))\n197 (let ((diff-header (git-gutter+-get-diff-header))\n198 (diffinfos (git-gutter+-get-diffinfos)))\n199 (list diff-header diffinfos))))))\n\n201 (defun git-gutter+-get-diff-header ()\n202 (save-excursion\n203 (if (re-search-forward git-gutter+-hunk-header-regex nil t)\n204 (buffer-substring (point-min) (match-beginning 0)))))\n\n206 (defsubst git-gutter+-make-diffinfo (type content start end)\n207 (list :type type :content content :start-line start :end-line end))\n\n209 (defun git-gutter+-get-diffinfos ()\n210 (loop while (re-search-forward git-gutter+-hunk-header-regex nil t)\n211 ;; Hunk header format:\n212 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n213 for del-len = (string-to-number (or (match-string 2) \"1\"))\n214 for add-line = (string-to-number (match-string 3))\n215 for add-len = (string-to-number (or (match-string 4) \"1\"))\n216 for type = (cond ((zerop del-len) 'added)\n217 ((zerop add-len) 'deleted)\n218 (t 'modified))\n219 for start-line = (if (eq type 'deleted)\n220 (1+ add-line)\n221 add-line)\n222 for end-line = (if (eq type 'deleted)\n223 start-line\n224 (1- (+ add-line add-len)))\n225 for content = (git-gutter+-diff-content)\n226 collect\n227 (git-gutter+-make-diffinfo type content start-line end-line)))\n\n229 (defun git-gutter+-diff-content ()\n230 (save-excursion\n231 (goto-char (line-beginning-position)) ; Move to beginning of hunk header\n232 (let ((hunk-start (point)))\n233 ;; Move to end of hunk\n234 (forward-line 1)\n235 (if (re-search-forward \"^@@\" nil t)\n236 (backward-char 3) ;; exclude \"\\n@@\"\n237 (goto-char (1- (point-max)))) ; Skip trailing newline\n238 (buffer-substring hunk-start (point)))))\n\n240 (defun git-gutter+-line-to-pos (line)\n241 (save-excursion\n242 (goto-char (point-min))\n243 (forward-line (1- line))\n244 (point)))\n\n246 (defun git-gutter+-before-string (sign)\n247 (let* ((sep-sign git-gutter+-separator-sign)\n248 (sep (when sep-sign\n249 (propertize sep-sign 'face 'git-gutter+-separator)))\n250 (gutter-sep (concat sign sep)))\n251 (propertize \" \" 'display `((margin left-margin) ,gutter-sep))))\n\n253 (defsubst git-gutter+-select-face (type)\n254 (case type\n255 (added 'git-gutter+-added)\n256 (modified 'git-gutter+-modified)\n257 (deleted 'git-gutter+-deleted)))\n\n259 (defsubst git-gutter+-select-sign (type)\n260 (case type\n261 (added git-gutter+-added-sign)\n262 (modified git-gutter+-modified-sign)\n263 (deleted git-gutter+-deleted-sign)))\n\n265 (defun git-gutter+-propertized-sign (type)\n266 (let ((sign (git-gutter+-select-sign type))\n267 (face (git-gutter+-select-face type)))\n268 (propertize sign 'face face)))\n\n270 (defun git-gutter+-view-region (sign start-line end-line)\n271 (let ((beg (git-gutter+-line-to-pos start-line)))\n272 (goto-char beg)\n273 (while (and (<= (line-number-at-pos) end-line) (not (eobp)))\n274 (git-gutter+-view-at-pos sign (point))\n275 (forward-line 1))))\n\n277 (defun git-gutter+-view-at-pos (sign pos)\n278 (let ((ov (make-overlay pos pos)))\n279 (overlay-put ov 'before-string (git-gutter+-before-string sign))\n280 (overlay-put ov 'git-gutter+ t)))\n\n282 (defun git-gutter+-view-diff-info (diffinfo)\n283 (let* ((start-line (plist-get diffinfo :start-line))\n284 (end-line (plist-get diffinfo :end-line))\n285 (type (plist-get diffinfo :type))\n286 (sign (git-gutter+-propertized-sign type)))\n287 (case type\n288 ((modified added) (git-gutter+-view-region sign start-line end-line))\n289 (deleted (git-gutter+-view-at-pos\n290 sign (git-gutter+-line-to-pos start-line))))))\n\n292 (defun git-gutter+-sign-width (sign)\n293 (loop for s across sign\n294 sum (char-width s)))\n\n296 (defun git-gutter+-longest-sign-width ()\n297 (let ((signs (list git-gutter+-modified-sign\n298 git-gutter+-added-sign\n299 git-gutter+-deleted-sign)))\n300 (when git-gutter+-unchanged-sign\n301 (add-to-list 'signs git-gutter+-unchanged-sign))\n302 (+ (apply 'max (mapcar 'git-gutter+-sign-width signs))\n303 (git-gutter+-sign-width git-gutter+-separator-sign))))\n\n305 (defun git-gutter+-view-for-unchanged ()\n306 (save-excursion\n307 (let ((sign (if git-gutter+-unchanged-sign\n308 (propertize git-gutter+-unchanged-sign\n309 'face 'git-gutter+-unchanged)\n310 \" \")))\n311 (goto-char (point-min))\n312 (while (not (eobp))\n313 (git-gutter+-view-at-pos sign (point))\n314 (forward-line 1)))))\n\n316 (defun git-gutter+-set-window-margin (width)\n317 (let ((curwin (get-buffer-window)))\n318 (set-window-margins curwin width (cdr (window-margins curwin)))))\n\n320 (defsubst git-gutter+-file-buffer-p ()\n321 (and (buffer-file-name)\n322 default-directory\n323 (file-directory-p default-directory)))\n\n325 ;;;###autoload\n326 (define-minor-mode git-gutter+-mode\n327 \"Git-Gutter mode\"\n328 :group 'git-gutter+\n329 :init-value nil\n330 :global nil\n331 :lighter git-gutter+-lighter\n332 (if git-gutter+-mode\n333 (if (and (git-gutter+-file-buffer-p)\n334 (git-gutter+-in-git-repository-p (buffer-file-name)))\n335 (progn\n336 (git-gutter+-add-local-hooks)\n337 (git-gutter+-refresh))\n338 (if (called-interactively-p 'any)\n339 (message \"No Git repo for current buffer\"))\n340 (git-gutter+-mode -1))\n341 (git-gutter+-remove-local-hooks)\n342 (git-gutter+-clear)))\n\n344 (defun git-gutter+-add-local-hooks ()\n345 (add-hook 'after-save-hook 'git-gutter+-refresh nil t)\n346 ;; Turn off `git-gutter+-mode' while reverting to prevent any redundant calls to\n347 ;; `git-gutter+-refresh'.\n348 (add-hook 'before-revert-hook 'git-gutter+-turn-off nil t)\n349 (add-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change nil t)\n350 (if git-gutter+-window-config-change-function\n351 (add-hook 'window-configuration-change-hook\n352 git-gutter+-window-config-change-function nil t)))\n\n354 (defun git-gutter+-remove-local-hooks ()\n355 (remove-hook 'after-save-hook 'git-gutter+-refresh t)\n356 (remove-hook 'before-revert-hook 'git-gutter+-turn-off t)\n357 (remove-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change t)\n358 (if git-gutter+-window-config-change-function\n359 (remove-hook 'window-configuration-change-hook\n360 git-gutter+-window-config-change-function t)))\n\n362 (defmacro git-gutter+-in-all-buffers (&rest body)\n363 `(dolist (buf (buffer-list))\n364 (with-current-buffer buf\n365 ,@body)))\n\n367 ;; When `define-globalized-minor-mode' is used to define `global-git-gutter+-mode',\n368 ;; `git-gutter+-mode' and thus `git-gutter+-refresh' get run twice when a new file\n369 ;; is opened. (First for `fundamental-mode', then for the file-specific mode.)\n370 ;; The following definition of `global-git-gutter+-mode' avoids any redundant calls to\n371 ;; `git-gutter+-refresh'.\n\n373 ;;;###autoload\n374 (define-minor-mode global-git-gutter+-mode ()\n375 \"Global Git-Gutter mode\"\n376 :group 'git-gutter+\n377 :init-value nil\n378 :global t\n379 (if global-git-gutter+-mode\n380 (progn\n381 (add-hook 'find-file-hook 'git-gutter+-turn-on)\n382 (add-hook 'after-revert-hook 'git-gutter+-turn-on)\n383 (add-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n384 (git-gutter+-in-all-buffers (git-gutter+-turn-on)))\n385 (remove-hook 'find-file-hook 'git-gutter+-turn-on)\n386 (remove-hook 'after-revert-hook 'git-gutter+-turn-on)\n387 (remove-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n388 (git-gutter+-in-all-buffers (git-gutter+-turn-off))))\n\n390 (defun git-gutter+-turn-on ()\n391 (when (and (buffer-file-name)\n392 (not (memq major-mode git-gutter+-disabled-modes))\n393 (not git-gutter+-mode))\n394 (git-gutter+-mode t)))\n\n396 (defun git-gutter+-turn-off ()\n397 (if git-gutter+-mode (git-gutter+-mode -1)))\n\n399 (defun git-gutter+-reenable-after-major-mode-change ()\n400 (if global-git-gutter+-mode\n401 (add-to-list 'git-gutter+-buffers-to-reenable (current-buffer))))\n\n403 (defun git-gutter+-reenable-buffers ()\n404 (dolist (buf git-gutter+-buffers-to-reenable)\n405 (with-current-buffer buf\n406 (git-gutter+-turn-on)))\n407 (setq git-gutter+-buffers-to-reenable nil))\n\n409 (defsubst git-gutter+-show-gutter-p (diffinfos)\n410 (if git-gutter+-hide-gutter\n411 (or diffinfos git-gutter+-unchanged-sign)\n412 (or global-git-gutter+-mode git-gutter+-unchanged-sign diffinfos)))\n\n414 (defun git-gutter+-show-gutter (&optional diffinfos)\n415 (when (git-gutter+-show-gutter-p (or diffinfos git-gutter+-diffinfos))\n416 (let ((win-width (or git-gutter+-window-width\n417 (git-gutter+-longest-sign-width))))\n418 (git-gutter+-set-window-margin win-width))))\n\n420 (defun git-gutter+-view-diff-infos (diffinfos)\n421 (when (or git-gutter+-unchanged-sign\n422 git-gutter+-separator-sign)\n423 (git-gutter+-view-for-unchanged))\n424 (when diffinfos\n425 (save-excursion\n426 (mapc 'git-gutter+-view-diff-info diffinfos)))\n427 (git-gutter+-show-gutter diffinfos))\n\n429 (defsubst git-gutter+-reset-window-margin-p ()\n430 (or git-gutter+-hide-gutter\n431 (not global-git-gutter+-mode)))\n\n433 (defun git-gutter+-clear-diff-infos ()\n434 (when (git-gutter+-reset-window-margin-p)\n435 (git-gutter+-set-window-margin 0))\n436 (remove-overlays (point-min) (point-max) 'git-gutter+ t))\n\n438 (defun git-gutter+-process-diff (curfile)\n439 (destructuring-bind\n440 (diff-header diffinfos) (git-gutter+-diff curfile)\n441 (setq git-gutter+-diff-header diff-header\n442 git-gutter+-diffinfos diffinfos)\n443 (save-restriction\n444 (widen)\n445 (funcall git-gutter+-view-diff-function diffinfos))))\n\n447 (defun git-gutter+-search-near-diff-index (diffinfos is-reverse)\n448 (loop with current-line = (line-number-at-pos)\n449 with cmp-fn = (if is-reverse '> '<)\n450 for diffinfo in (if is-reverse (reverse diffinfos) diffinfos)\n451 for index = 0 then (1+ index)\n452 for start-line = (plist-get diffinfo :start-line)\n453 when (funcall cmp-fn current-line start-line)\n454 return (if is-reverse\n455 (1- (- (length diffinfos) index))\n456 index)))\n\n458 (defun git-gutter+-diffinfo-at-point ()\n459 (save-restriction\n460 (widen)\n461 (loop with current-line = (line-number-at-pos)\n462 for diffinfo in git-gutter+-diffinfos\n463 for start = (plist-get diffinfo :start-line)\n464 for end = (or (plist-get diffinfo :end-line) (1+ start))\n465 when (and (>= current-line start) (<= current-line end))\n466 return diffinfo)))\n\n468 (defun git-gutter+-collect-deleted-line (str)\n469 (with-temp-buffer\n470 (insert str)\n471 (goto-char (point-min))\n472 (loop while (re-search-forward \"^-\\\\(.*?\\\\)$\" nil t)\n473 collect (match-string 1) into deleted-lines\n474 finally return deleted-lines)))\n\n476 (defun git-gutter+-delete-added-lines (start-line end-line)\n477 (forward-line (1- start-line))\n478 (let ((start-point (point)))\n479 (forward-line (1+ (- end-line start-line)))\n480 (delete-region start-point (point))))\n\n482 (defun git-gutter+-insert-deleted-lines (content)\n483 (dolist (line (git-gutter+-collect-deleted-line content))\n484 (insert (concat line \"\\n\"))))\n\n486 (defun git-gutter+-do-revert-hunk (diffinfo)\n487 (save-excursion\n488 (save-restriction\n489 (widen)\n490 (goto-char (point-min))\n491 (let ((start-line (plist-get diffinfo :start-line))\n492 (end-line (plist-get diffinfo :end-line))\n493 (content (plist-get diffinfo :content)))\n494 (case (plist-get diffinfo :type)\n495 (added (git-gutter+-delete-added-lines start-line end-line))\n496 (deleted (forward-line (1- start-line))\n497 (git-gutter+-insert-deleted-lines content))\n498 (modified (git-gutter+-delete-added-lines start-line end-line)\n499 (git-gutter+-insert-deleted-lines content)))))))\n\n501 (defun git-gutter+-revert-hunks ()\n502 \"Revert hunk at point. If region is active, revert all hunks within the region.\"\n503 (interactive)\n504 (let* ((diffinfos (git-gutter+-selected-diffinfos))\n505 (one-diffinfo-p (= 1 (length diffinfos))))\n506 (save-window-excursion\n507 (if one-diffinfo-p (git-gutter+-show-hunk (car diffinfos)))\n508 (when (and diffinfos\n509 (yes-or-no-p (if one-diffinfo-p\n510 \"Revert hunk?\"\n511 (format \"Revert %d hunks?\" (length diffinfos)))))\n512 ;; Revert diffinfos in reverse so that earlier hunks don't invalidate the\n513 ;; line number information of the later hunks.\n514 (dolist (diffinfo (nreverse diffinfos))\n515 (git-gutter+-do-revert-hunk diffinfo))\n516 (save-buffer))\n517 (if one-diffinfo-p\n518 (git-gutter+-awhen (get-buffer git-gutter+-popup-buffer)\n519 (kill-buffer it))))))\n\n521 (defun git-gutter+-show-hunk (&optional diffinfo)\n522 \"Show hunk at point in another window\"\n523 (interactive)\n524 (git-gutter+-awhen (or diffinfo\n525 (git-gutter+-diffinfo-at-point))\n526 (save-selected-window\n527 (with-current-buffer (get-buffer-create git-gutter+-popup-buffer)\n528 (setq buffer-read-only nil)\n529 (erase-buffer)\n530 (insert (plist-get it :content))\n531 (insert \"\\n\")\n532 (goto-char (point-min))\n533 (diff-mode)\n534 (view-mode)\n535 (pop-to-buffer (current-buffer))))))\n\n537 (defun git-gutter+-next-hunk (arg)\n538 \"Move to next diff hunk\"\n539 (interactive \"p\")\n540 (if (not git-gutter+-diffinfos)\n541 (message \"No changes in buffer\")\n542 (save-restriction\n543 (widen)\n544 (let* ((is-reverse (< arg 0))\n545 (diffinfos git-gutter+-diffinfos)\n546 (len (length diffinfos))\n547 (index (git-gutter+-search-near-diff-index diffinfos is-reverse))\n548 (real-index (if index\n549 (let ((next (if is-reverse (1+ index) (1- index))))\n550 (mod (+ arg next) len))\n551 (if is-reverse (1- (length diffinfos)) 0)))\n552 (diffinfo (nth real-index diffinfos)))\n553 (goto-char (point-min))\n554 (forward-line (1- (plist-get diffinfo :start-line)))\n555 (when (buffer-live-p (get-buffer git-gutter+-popup-buffer))\n556 (save-window-excursion\n557 (git-gutter+-show-hunk)))))))\n\n559 (defun git-gutter+-previous-hunk (arg)\n560 \"Move to previous diff hunk\"\n561 (interactive \"p\")\n562 (git-gutter+-next-hunk (- arg)))\n\n564 (defun git-gutter+-remote-default-directory (dir file)\n565 (let* ((vec (tramp-dissect-file-name file))\n566 (method (aref vec 0))\n567 (user (aref vec 1))\n568 (host (aref vec 2)))\n569 (format \"/%s:%s%s:%s\" method (if user (concat user \"@\") \"\") host dir)))\n\n571 (defun git-gutter+-remote-file-path (dir file)\n572 (let ((file (aref (tramp-dissect-file-name file) 3)))\n573 (replace-regexp-in-string (concat \"\\\\`\" dir) \"\" file)))\n\n575 (defun git-gutter+-local-file-path (file)\n576 (if (eq system-type 'windows-nt)\n577 ;; Cygwin can't handle Windows absolute paths\n578 (file-relative-name file default-directory)\n579 file))\n\n581 (defun git-gutter+-refresh ()\n582 (git-gutter+-clear)\n583 (let ((file (buffer-file-name)))\n584 (when (and file (file-exists-p file))\n585 (if (file-remote-p file)\n586 (let* ((repo-root (git-gutter+-root-directory file))\n587 (default-directory (git-gutter+-remote-default-directory repo-root file)))\n588 (git-gutter+-process-diff (git-gutter+-remote-file-path repo-root file)))\n589 (git-gutter+-process-diff (git-gutter+-local-file-path file))))))\n\n591 (defun git-gutter+-clear ()\n592 (save-restriction\n593 (widen)\n594 (funcall git-gutter+-clear-function))\n595 (setq git-gutter+-diffinfos nil))\n\n\n598 ;;; Staging\n\n600 (defun git-gutter+-stage-hunks ()\n601 \"Stage hunk at point. If region is active, stage all hunk lines within the region.\"\n602 (interactive)\n603 (let* ((line-range (if (use-region-p)\n604 (cons (line-number-at-pos (region-beginning))\n605 (line-number-at-pos (region-end)))))\n606 (diffinfos (git-gutter+-selected-diffinfos line-range)))\n607 (when diffinfos\n608 (let ((error-msg (git-gutter+-stage-diffinfos diffinfos line-range)))\n609 (if error-msg\n610 (message \"Error staging hunks:\\n%s\" error-msg))\n611 (git-gutter+-refresh)))))\n\n613 (defun git-gutter+-selected-diffinfos (&optional line-range)\n614 (unless line-range\n615 (setq line-range (if (use-region-p)\n616 (cons (line-number-at-pos (region-beginning))\n617 (line-number-at-pos (region-end))))))\n618 (if line-range\n619 (git-gutter+-diffinfos-between-lines line-range)\n620 (git-gutter+-awhen (git-gutter+-diffinfo-at-point)\n621 (list it))))\n\n623 (defsubst git-gutter+-diffinfo-between-lines-p (diffinfo start-line end-line)\n624 (let ((diff-start (plist-get diffinfo :start-line))\n625 (diff-end (plist-get diffinfo :end-line)))\n626 (and (<= start-line diff-end)\n627 (<= diff-start end-line))))\n\n629 (defun git-gutter+-diffinfos-between-lines (line-range)\n630 (save-restriction\n631 (widen)\n632 (let ((start-line (car line-range))\n633 (end-line (cdr line-range)))\n634 (delq nil\n635 (mapcar (lambda (diffinfo)\n636 (if (git-gutter+-diffinfo-between-lines-p\n637 diffinfo start-line end-line)\n638 diffinfo))\n639 git-gutter+-diffinfos)))))\n\n641 (defun git-gutter+-stage-diffinfos (diffinfos line-range)\n642 (let ((header git-gutter+-diff-header))\n643 (with-temp-buffer\n644 (insert header)\n645 ;; Insert hunks in reverse so that earlier hunks don't invalidate the line\n646 ;; number information of the later hunks.\n647 (dolist (diffinfo (nreverse diffinfos))\n648 (git-gutter+-insert-diffinfo diffinfo line-range)\n649 (goto-char (point-max)))\n650 (git-gutter+-call-git-on-current-buffer\n651 '(\"apply\" \"--unidiff-zero\" \"--cached\" \"-\")))))\n\n653 (defun git-gutter+-insert-diffinfo (diffinfo line-range)\n654 (let ((content (plist-get diffinfo :content))\n655 (type (plist-get diffinfo :type)))\n656 (if (not line-range)\n657 (git-gutter+-insert-hunk content type)\n658 (let ((diff-start-line (plist-get diffinfo :start-line))\n659 (diff-end-line (plist-get diffinfo :end-line))\n660 (start-line (car line-range))\n661 (end-line (cdr line-range)))\n662 (git-gutter+-insert-hunk content type\n663 (1+ (- start-line diff-start-line))\n664 (1+ (- end-line diff-start-line)))))))\n\n666 (defun git-gutter+-call-git-on-current-buffer (args)\n667 \"Sends the current buffer contents to Git and replaces them with Git's output.\n\n669 RETURNS nil if Git ran successfully. Returns an error description otherwise.\"\n670 (unless (zerop (apply #'call-process-region (point-min) (point-max)\n671 git-gutter+-git-executable t t nil args))\n672 (buffer-string)))\n\n674 (defsubst git-gutter+-read-hunk-header (hunk)\n675 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n676 (string-match git-gutter+-hunk-header-regex hunk)\n677 (list (string-to-number (match-string 1 hunk))\n678 (string-to-number (or (match-string 2 hunk) \"1\"))\n679 (string-to-number (match-string 3 hunk))\n680 (string-to-number (or (match-string 4 hunk) \"1\"))))\n\n682 (defun git-gutter+-insert-hunk (hunk type &optional start end)\n683 \"If START and END are provided, only insert addition (+) lines between\n684 START and END (inclusive). START and END are both line numbers starting with 1.\"\n685 (destructuring-bind\n686 (del-line del-len add-line add-len) (git-gutter+-read-hunk-header hunk)\n687 (let* ((start (max 1 (or start 1)))\n688 (end (min add-len (or end add-len)))\n689 (insert-all-p (or (eq type :deleted)\n690 (and (= start 1) (= end add-len))))\n691 (num-lines-selected (if insert-all-p\n692 add-len\n693 (1+ (- end start)))))\n694 ;; When the user selected the last lines of a hunk with type `modified' (but\n695 ;; not the complete hunk), then don't insert any deletion (-) lines from that\n696 ;; hunk.\n697 (if (and (eq type 'modified)\n698 (> start 1) (= end add-len))\n699 (setq type 'modified-trailing))\n\n701 (save-excursion\n702 (insert hunk \"\\n\"))\n\n704 (git-gutter+-delete-hunk-header)\n\n706 (if (not insert-all-p)\n707 (git-gutter+-modify-hunk type num-lines-selected del-len start))\n\n709 (let ((hunk-header (git-gutter+-make-hunk-header type num-lines-selected\n710 del-line del-len add-line)))\n711 (insert hunk-header \"\\n\")))))\n\n713 (defun git-gutter+-delete-hunk-header ()\n714 (let ((hunk-start (point)))\n715 (forward-line 1)\n716 (delete-region hunk-start (point))))\n\n718 (defun git-gutter+-modify-hunk (type num-lines-selected del-len start)\n719 \"Remove all addition (+) lines from hunk that aren't selected.\n720 If TYPE is not `modified', also remove all deletion (-) lines.\"\n721 (let ((first-line-selected (+ del-len (1- start)))\n722 selected-lines)\n723 (save-excursion\n724 (forward-line first-line-selected)\n725 (let ((selection-start (point)))\n726 (forward-line num-lines-selected)\n727 (setq selected-lines (buffer-substring selection-start (point)))))\n728 (save-excursion\n729 (if (eq type 'modified) (forward-line del-len)) ; skip over deletion (-) lines\n730 (delete-region (point) (point-max))\n731 (insert selected-lines))))\n\n733 (defun git-gutter+-make-hunk-header (type num-lines-selected del-line del-len add-line)\n734 (let ((add-len num-lines-selected))\n735 (case type\n736 (added (setq add-line (1+ del-line)))\n737 (modified-trailing (setq add-line (+ del-line del-len)\n738 del-line (1- add-line)\n739 del-len 0))\n740 (t (setq add-line del-line)))\n741 (format \"@@ -%d,%d +%d,%d @@\"\n742 del-line del-len\n743 add-line add-len)))\n\n\n746 ;;; Committing\n747 ;; This section draws heavily from old Magit source code.\n\n749 (defvar git-gutter+-pre-commit-window-config nil)\n750 (defvar git-gutter+-commit-origin-buffer nil\n751 \"Buffer that started the commit\")\n\n753 (defconst git-gutter+-commit-buffer-name \"*Commit Message*\")\n754 (defconst git-gutter+-staged-changes-buffer-name \"*Staged Changes*\")\n\n756 ;;;###autoload\n757 (defun git-gutter+-commit ()\n758 \"Commit staged changes. If nothing is staged, ask to stage the current buffer.\"\n759 (interactive)\n\n761 (when (and (not (git-gutter+-anything-staged-p))\n762 git-gutter+-diffinfos\n763 (y-or-n-p \"Nothing staged. Stage current buffer? \"))\n764 (git-gutter+-stage-whole-buffer))\n\n766 (let ((file (buffer-file-name))\n767 (dir default-directory))\n768 (git-gutter+-save-window-config-if-needed)\n769 (setq git-gutter+-commit-origin-buffer (current-buffer))\n770 (git-gutter+-open-commit-edit-buffer dir)\n771 (git-gutter+-show-staged-changes file dir)))\n\n773 (defun git-gutter+-stage-and-commit ()\n774 (interactive)\n775 (git-gutter+-stage-hunks)\n776 (git-gutter+-commit))\n\n778 (defun git-gutter+-save-window-config-if-needed ()\n779 ;; Only save the window config if the temporary buffers that get popped-up by\n780 ;; git-gutter+ are not already visible.\n781 ;; In this way, `git-gutter+-commit' can be called twice in a row without\n782 ;; losing the original window config.\n783 (when (not (and git-gutter+-pre-commit-window-config\n784 (get-buffer-window git-gutter+-commit-buffer-name)\n785 (get-buffer-window git-gutter+-staged-changes-buffer-name)))\n786 (setq git-gutter+-pre-commit-window-config (current-window-configuration))))\n\n788 (defun git-gutter+-open-commit-edit-buffer (dir)\n789 \"Opens a buffer for composing the commit message\"\n790 (pop-to-buffer (get-buffer-create git-gutter+-commit-buffer-name))\n791 (setq default-directory dir)\n792 (git-gutter+-commit-mode)\n793 (message \"Type C-c C-c to commit (C-c C-k to cancel).\"))\n\n795 (defsubst git-gutter+-pop-to-staged-changes-buffer ()\n796 (let* ((buf (get-buffer-create git-gutter+-staged-changes-buffer-name))\n797 (window (get-buffer-window buf)))\n798 (if window\n799 ;; Buffer is already visible\n800 (select-window window)\n801 (if (<= (length (window-list)) 2)\n802 (split-window))\n803 (pop-to-buffer buf))))\n\n805 (defun git-gutter+-show-staged-changes (file dir)\n806 (save-selected-window\n807 (git-gutter+-pop-to-staged-changes-buffer)\n808 (setq buffer-read-only nil)\n809 (erase-buffer)\n810 (let ((default-directory dir))\n811 (git-gutter+-call-git '(\"diff\" \"--staged\") file))\n812 (goto-char (point-min))\n813 (diff-mode)\n814 (view-mode)))\n\n816 (defsubst git-gutter+-abort-commit-when-no-changes (allow-empty amend)\n817 (unless (or amend\n818 allow-empty\n819 (git-gutter+-anything-staged-p))\n820 (error\n821 \"Refusing to create empty commit. Maybe you want to amend (%s) or allow-empty (%s)?\"\n822 (key-description (car (where-is-internal\n823 'git-gutter+-commit-toggle-amending)))\n824 (key-description (car (where-is-internal\n825 'git-gutter+-commit-toggle-allow-empty))))))\n\n827 (defsubst git-gutter+-buffer-is-whitespace ()\n828 (save-excursion\n829 (goto-char (point-min))\n830 (looking-at-p \"[ \\t\\n]*\\\\'\")))\n\n832 (defun git-gutter+-publish-commit ()\n833 \"Publish commit\"\n834 (interactive)\n835 (let* ((fields (git-gutter+-commit-get-fields))\n836 (amend (equal \"yes\" (git-gutter+-commit-get-field 'amend fields)))\n837 (allow-empty (equal \"yes\" (git-gutter+-commit-get-field 'allow-empty fields)))\n838 (author (git-gutter+-commit-get-field 'author fields))\n839 (date (git-gutter+-commit-get-field 'date fields)))\n\n841 (git-gutter+-abort-commit-when-no-changes allow-empty amend)\n\n843 (git-gutter+-push-to-comment-ring (buffer-string))\n\n845 (git-gutter+-commit-set-fields nil) ; Delete message header\n\n847 (when (git-gutter+-buffer-is-whitespace)\n848 (erase-buffer)\n849 (insert \"(Empty description)\"))\n\n851 (let ((error-msg (git-gutter+-call-git-on-current-buffer\n852 (append '(\"--no-pager\" \"commit\" \"-F\" \"-\")\n853 (if amend '(\"--amend\"))\n854 (if allow-empty '(\"--allow-empty\"))\n855 (if author (list (concat \"--author=\" author)))\n856 (if date (list (concat \"--date=\" date)))))))\n857 (if error-msg\n858 (progn\n859 (message \"Commit error:\\n%s\" error-msg)\n860 (erase-buffer)\n861 (insert (ring-ref log-edit-comment-ring 0))) ; Reinsert commit message\n862 (message \"Commit successful.\")\n863 (git-gutter+-close-commit-edit-buffer)\n864 (git-gutter+-update-vc-modeline)))))\n\n866 (defun git-gutter+-close-commit-edit-buffer ()\n867 \"Abort edits and discard commit message being composed.\"\n868 (interactive)\n869 (kill-buffer)\n870 (set-window-configuration git-gutter+-pre-commit-window-config))\n\n872 (defun git-gutter+-update-vc-modeline ()\n873 (when (buffer-live-p git-gutter+-commit-origin-buffer)\n874 (with-current-buffer git-gutter+-commit-origin-buffer\n875 ;; Updating the modeline has no effect if the buffer still has\n876 ;; changes - it will remain in the 'modified' state. So skip it then.\n877 (unless git-gutter+-diffinfos\n878 (ignore-errors (vc-find-file-hook))))))\n\n880 (defun git-gutter+-stage-whole-buffer ()\n881 (save-excursion\n882 (mark-whole-buffer)\n883 (git-gutter+-stage-hunks)))\n\n885 (defun git-gutter+-anything-staged-p ()\n886 \"Return t if the current repo has staged changes\"\n887 (not (zerop (git-gutter+-call-git '(\"diff\" \"--quiet\" \"--cached\")))))\n\n889 (defun git-gutter+-commit-toggle-amending ()\n890 \"Toggle whether this will be an amendment to the previous commit.\n891 \\(i.e., whether commit is run via 'git commit --amend')\"\n892 (interactive)\n893 ;; Remove the newline that 'git-commit-mode' adds to a new commit\n894 ;; message buffer by default. This prevents an ugly visual\n895 ;; gap between the commit message header and the previous commit\n896 ;; message.\n897 (when (git-gutter+-buffer-is-whitespace)\n898 (erase-buffer))\n\n900 (let ((amend-was-already-set (git-gutter+-commit-get-field 'amend)))\n901 (git-gutter+-commit-toggle-field 'amend t)\n902 (unless amend-was-already-set\n903 ;; Insert previous commit message\n904 (goto-char (point-max))\n905 (unless (zerop (current-column))\n906 (insert \"\\n\"))\n907 (insert (git-gutter+-get-last-commit-msg)\n908 \"\\n\"))))\n\n910 (defun git-gutter+-commit-toggle-allow-empty ()\n911 \"Toggle whether this commit is allowed to be empty.\n912 \\(i.e., whether commit is run via 'git commit --allow-empty')\"\n913 (interactive)\n914 (git-gutter+-commit-toggle-field 'allow-empty t))\n\n916 (defun git-gutter+-format-author (author email)\n917 (format \"%s <%s>\" author email))\n\n919 (defun git-gutter+-commit-toggle-author ()\n920 \"Toggle whether this commit should have a user-defined author.\"\n921 (interactive)\n922 (git-gutter+-commit-toggle-input\n923 'author (git-gutter+-format-author\n924 (or (git-gutter+-get-cfg \"user\" \"name\") \"Author Name\")\n925 (or (git-gutter+-get-cfg \"user\" \"email\") \"author@email\"))))\n\n927 (defun git-gutter+-commit-toggle-date ()\n928 \"Toggle whether this commit should have a user-defined date.\"\n929 (interactive)\n930 (git-gutter+-commit-toggle-input 'date\n931 ;; ISO 8601\n932 (format-time-string \"%Y-%m-%dT%T%z\" (current-time))))\n\n934 (defun git-gutter+-push-to-comment-ring (comment)\n935 (when (or (ring-empty-p log-edit-comment-ring)\n936 (not (equal comment (ring-ref log-edit-comment-ring 0))))\n937 (ring-insert log-edit-comment-ring comment)))\n\n939 (defun git-gutter+-get-last-commit-msg ()\n940 (git-gutter+-git-output '(\"log\" \"--max-count=1\" \"--pretty=format:%s%n%n%b\" \"HEAD\")))\n\n942 (defun git-gutter+-get-cfg (&rest keys)\n943 (git-gutter+-git-output (list \"config\" (mapconcat 'identity keys \".\"))))\n\n945 (defun git-gutter+-git-output (args)\n946 (with-temp-buffer\n947 (git-gutter+-call-git args)\n948 ;; Delete trailing newlines\n949 (goto-char (point-min))\n950 (if (re-search-forward \"\\n+\\\\'\" nil t)\n951 (replace-match \"\"))\n952 (buffer-string)))\n\n\n955 ;;; Commit message header\n\n957 (defconst git-gutter+-commit-header-end \"-- End of commit options header --\\n\")\n\n959 (defun git-gutter+-commit-get-field (name &optional fields)\n960 (cdr (assq name (or fields (git-gutter+-commit-get-fields)))))\n\n962 (defun git-gutter+-commit-set-field (name value)\n963 (let* ((fields (git-gutter+-commit-get-fields))\n964 (cell (assq name fields)))\n965 (cond (cell\n966 (if value\n967 (rplacd cell value)\n968 (setq fields (delq cell fields))))\n969 (t\n970 (if value\n971 (setq fields (append fields (list (cons name value)))))))\n972 (git-gutter+-commit-set-fields fields)))\n\n974 (defun git-gutter+-commit-toggle-field (name default)\n975 \"Toggle the commit header field named NAME.\n976 If it's currently unset, set it to DEFAULT (t or nil).\"\n977 (let* ((fields (git-gutter+-commit-get-fields))\n978 (cell (assq name fields)))\n979 (if cell\n980 (rplacd cell (if (equal (cdr cell) \"yes\") \"no\" \"yes\"))\n981 (setq fields (acons name (if default \"yes\" \"no\") fields)))\n982 (git-gutter+-commit-set-fields fields)))\n\n984 (defun git-gutter+-commit-toggle-input (name default)\n985 \"Toggle the commit header input named NAME.\n986 If it's currently unset, set it to DEFAULT (a string). If it is\n987 set remove it.\"\n988 (let* ((fields (git-gutter+-commit-get-fields))\n989 (cell (assq name fields)))\n990 (if cell\n991 (setq fields (assq-delete-all name fields))\n992 (setq fields (acons name default fields)))\n993 (git-gutter+-commit-set-fields fields)))\n\n995 (defun git-gutter+-commit-get-fields ()\n996 (let (result)\n997 (goto-char (point-min))\n998 (while (looking-at \"^\\\\([A-Za-z0-9-_]+\\\\): *\\\\(.+\\\\)?$\")\n999 (let ((name (intern (downcase (match-string 1))))\n1000 (value (read (or (match-string 2) \"nil\"))))\n1001 (push (cons name value) result))\n1002 (forward-line))\n1003 (if (looking-at (regexp-quote git-gutter+-commit-header-end))\n1004 (nreverse result))))\n\n1006 (defun git-gutter+-commit-set-fields (fields)\n1007 (goto-char (point-min))\n1008 ;; Delete commit header\n1009 (if (search-forward-regexp (format \"^\\\\(?:[A-Za-z0-9-_]+:.*\\n\\\\)*%s\"\n1010 (regexp-quote git-gutter+-commit-header-end))\n1011 nil t)\n1012 (delete-region (match-beginning 0) (match-end 0)))\n1013 (goto-char (point-min))\n1014 (when fields\n1015 (dolist (field fields)\n1016 (insert (capitalize (symbol-name (car field))) \": \"\n1017 (prin1-to-string (cdr field)) \"\\n\"))\n1018 (insert git-gutter+-commit-header-end)))\n\n\n1021 ;;; git-gutter+-commit-mode\n1022 ;; Like git-commit-mode, but adds keybindings to git-gutter+ commands and\n1023 ;; highlighting support for the commit message header.\n\n1025 (define-derived-mode git-gutter+-commit-mode git-commit-mode \"Git-Gutter-Commit\"\n1026 (setq font-lock-defaults (list (git-gutter+-commit-font-lock-keywords) t)))\n\n1028 (setq git-gutter+-commit-mode-map\n1029 (let ((map (copy-keymap git-commit-mode-map)))\n1030 (define-key map (kbd \"C-c C-c\") 'git-gutter+-publish-commit)\n1031 (define-key map (kbd \"C-c C-k\") 'git-gutter+-close-commit-edit-buffer)\n1032 (define-key map (kbd \"C-c C-a\") 'git-gutter+-commit-toggle-amending)\n1033 (define-key map (kbd \"C-c C-e\") 'git-gutter+-commit-toggle-allow-empty)\n1034 (define-key map (kbd \"C-c C-u\") 'git-gutter+-commit-toggle-author)\n1035 (define-key map (kbd \"C-c C-d\") 'git-gutter+-commit-toggle-date)\n1036 (define-key map (kbd \"C-c C-b\") 'git-commit-ack)\n1037 (define-key map (kbd \"M-p\") 'log-edit-previous-comment)\n1038 (define-key map (kbd \"M-n\") 'log-edit-next-comment)\n1039 map))\n\n1041 (defface git-gutter+-commit-header-face\n1042 '((t :inherit font-lock-comment-face))\n1043 \"Highlights the commit message header\"\n1044 :group 'git-gutter+-faces)\n\n1046 (defconst git-gutter+-commit-header-regex\n1047 (concat \"\\\\(?:.\\\\|\\n\\\\)*?\" (regexp-quote git-gutter+-commit-header-end)))\n\n1049 (defconst git-gutter+-skip-commit-header-regex\n1050 (concat \"\\\\`\\\\(?:\" git-gutter+-commit-header-regex \"\\\\)?\"))\n\n1052 ;; Modify git-commit-summary-regexp to ignore the commit header\n1053 (defadvice git-commit-summary-regexp\n1054 (after ignore-git-gutter+-commit-header activate compile)\n1055 (if (eq major-mode 'git-gutter+-commit-mode)\n1056 (setq ad-return-value\n1057 (concat git-gutter+-skip-commit-header-regex\n1058 (substring ; Remove leading \"\\\\`\"\n1059 ad-return-value 2)))))\n\n1061 (defun git-gutter+-commit-font-lock-keywords ()\n1062 \"Like `git-commit-mode-font-lock-keywords' but with commit header highlighting\"\n1063 `((,(concat \"\\\\`\" git-gutter+-commit-header-regex) . 'git-gutter+-commit-header-face)\n1064 ,@(git-commit-mode-font-lock-keywords)))\n\n\n1067 ;;; Magit synchronization\n1068 ;; Force Magit to refresh git-gutter+ when updating the VC mode line.\n\n1070 (defvar git-gutter+-orig-vc-find-file-hook)\n\n1072 (defvar git-gutter+-vc-find-file-hook-with-refresh\n1073 (lambda ()\n1074 (funcall git-gutter+-orig-vc-find-file-hook)\n1075 (if git-gutter+-mode (git-gutter+-refresh))))\n\n1077 (defadvice magit-update-vc-modeline (around refresh-git-gutter+ compile activate)\n1078 ;; `magit-update-vc-modeline' calls `vc-find-file-hook' (a function!) on each\n1079 ;; buffer in the repo. Temporarily rebind it to `vc-find-file-hook-with-refresh',\n1080 ;; which calls git-gutter+-refresh after updating the VC mode line.\n1081 ;;\n1082 ;; Using `flet' would have been much simpler, but it's deprecated since 24.3.\n1083 (setq git-gutter+-orig-vc-find-file-hook (symbol-function 'vc-find-file-hook))\n1084 (fset 'vc-find-file-hook git-gutter+-vc-find-file-hook-with-refresh)\n1085 (unwind-protect\n1086 ad-do-it\n1087 (fset 'vc-find-file-hook git-gutter+-orig-vc-find-file-hook)))\n\n1089 (provide 'git-gutter+)\n\n1091 ;;; git-gutter+.el ends here\n")) (setq helm-swoop-cache t))) (candidates-in-buffer) (get-line . buffer-substring-no-properties) (keymap keymap (C-M-left . backward-sexp) (C-M-right . forward-sexp) (27 keymap (105 . helm-multi-swoop-all-from-helm-swoop)) (3 keymap (5 . helm-swoop-edit)) keymap (C-M-left . paren-backward-sexp) (C-M-right . paren-forward-sexp) (94 . helm-swoop-caret-match) (menu-bar keymap (help-menu keymap (describe keymap ...))) (help keymap (109 . helm-help)) (f1 keymap (109 . helm-help)) (8 keymap (109 . helm-help) (104 . undefined) (8 . undefined) (4 . helm-debug-output)) (20 . helm-toggle-resplit-and-swap-windows) (C-tab . undefined) (triple-mouse-3 . ignore) (double-mouse-3 . ignore) (mouse-3 . ignore) (drag-mouse-3 . ignore) (down-mouse-3 . ignore) (triple-mouse-2 . ignore) (double-mouse-2 . ignore) (mouse-2 . ignore) (drag-mouse-2 . ignore) (down-mouse-2 . ignore) (triple-mouse-1 . ignore) (double-mouse-1 . ignore) (mouse-1 . ignore) (drag-mouse-1 . ignore) (down-mouse-1 . ignore) (67108897 . helm-toggle-suspend-update) (3 keymap (21 . helm-force-update) (6 . helm-follow-mode) (11 . helm-kill-selection-and-quit) (25 . helm-yank-selection) (4 . helm-delete-current-selection) (45 . helm-swap-windows)) (67108987 . helm-enlarge-window) (67108989 . helm-narrow-window) (19 . undefined) (18 . undefined) (23 . helm-yank-text-at-point) (24 keymap (2 . helm-resume-list-buffers-after-quit) (98 . helm-resume-previous-session-after-quit) (6 . helm-quit-and-find-file)) (11 . helm-delete-minibuffer-contents) (67108896 . helm-toggle-visible-mark) (0 . helm-toggle-visible-mark) (C-M-up . helm-scroll-other-window-down) (C-M-down . helm-scroll-other-window) (M-prior . helm-scroll-other-window-down) (M-next . helm-scroll-other-window) (12 . helm-recenter-top-bottom-other-window) (15 . helm-next-source) (10 . helm-select-3rd-action) (5 . helm-select-2nd-action-or-end-of-line) ...) (header-line . "[C-c C-e] Edit mode, [M-i] apply all buffers") (action lambda ($line) (helm-swoop--goto-line (when (string-match "^[0-9]+" $line) (string-to-number ...))) (when (re-search-forward (mapconcat ... ... "\\|") nil t) (goto-char (match-beginning 0))) (helm-swoop--recenter)) (migemo)) :buffer "*Helm Swoop*" :input #("git-gutter+-refresh" 0 19 (fontified t face whitespace-line)) :prompt "Swoop: " :preselect "^368 " :candidate-number-limit 19999) helm helm-argument-keys apply mapcar make-byte-code 257 "\301\300\"\207" vconcat vector [plist-get] 4 "\n\n(fn KEY)"] 9 "\n\n(fn)"])
helm(:sources ((name . "git-gutter+.el") (init lambda nil (unless helm-swoop-cache (with-current-buffer (helm-candidate-buffer (quote local)) (insert "1 ;;; git-gutter+.el --- Manage Git hunks straight from the buffer\n\n3 ;; Copyright (C) 2013 by Syohei YOSHIDA and contributors\n\n5 ;; Author: Syohei YOSHIDA <syohex@gmail.com> and contributors\n6 ;; URL: https://github.com/nonsequitur/git-gutter-plus\n7 ;; Version: 0.1\n\n9 ;; This program is free software; you can redistribute it and/or modify\n10 ;; it under the terms of the GNU General Public License as published by\n11 ;; the Free Software Foundation, either version 3 of the License, or\n12 ;; (at your option) any later version.\n\n14 ;; This program is distributed in the hope that it will be useful,\n15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of\n16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n17 ;; GNU General Public License for more details.\n\n19 ;; You should have received a copy of the GNU General Public License\n20 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n22 ;; Package-Requires: ((git-commit-mode \"0.14\"))\n\n24 ;;; Commentary:\n25 ;;\n26 ;; View, stage and revert Git changes straight from the buffer.\n\n28 ;;; Code:\n\n30 (eval-when-compile\n31 (require 'cl))\n\n33 (require 'tramp)\n34 (require 'log-edit)\n35 (require 'git-commit-mode)\n\n37 (defgroup git-gutter+ nil\n38 \"Manage Git hunks straight from the buffer\"\n39 :prefix \"git-gutter+-\"\n40 :group 'vc)\n\n42 (defcustom git-gutter+-window-width nil\n43 \"Character width of the gutter margin. Set this variable if the automatically\n44 calculated width looks wrong. (This can happen with some special characters.)\"\n45 :type 'integer\n46 :group 'git-gutter+)\n\n48 (defcustom git-gutter+-git-executable \"git\"\n49 \"The path of the Git executable.\"\n50 :type 'string\n51 :group 'git-gutter+)\n\n53 (defcustom git-gutter+-diff-options nil\n54 \"List of strings containing extra arguments to 'git diff'\"\n55 :type 'list\n56 :group 'git-gutter+)\n\n58 (defcustom git-gutter+-separator-sign nil\n59 \"Separator sign\"\n60 :type 'string\n61 :group 'git-gutter+)\n\n63 (defcustom git-gutter+-modified-sign \"=\"\n64 \"Modified sign\"\n65 :type 'string\n66 :group 'git-gutter+)\n\n68 (defcustom git-gutter+-added-sign \"+\"\n69 \"Added sign\"\n70 :type 'string\n71 :group 'git-gutter+)\n\n73 (defcustom git-gutter+-deleted-sign \"-\"\n74 \"Deleted sign\"\n75 :type 'string\n76 :group 'git-gutter+)\n\n78 (defcustom git-gutter+-unchanged-sign nil\n79 \"Unchanged sign\"\n80 :type 'string\n81 :group 'git-gutter+)\n\n83 (defcustom git-gutter+-hide-gutter nil\n84 \"Hide gutter if there are no changes\"\n85 :type 'boolean\n86 :group 'git-gutter+)\n\n88 (defcustom git-gutter+-lighter \" GitGutter\"\n89 \"Minor mode lighter in mode-line\"\n90 :type 'string\n91 :group 'git-gutter+)\n\n93 (defface git-gutter+-separator\n94 '((t (:foreground \"cyan\" :weight bold)))\n95 \"Face of the separator\"\n96 :group 'git-gutter+)\n\n98 (defface git-gutter+-modified\n99 '((t (:foreground \"magenta\" :weight bold)))\n100 \"Face for modified lines\"\n101 :group 'git-gutter+)\n\n103 (defface git-gutter+-added\n104 '((t (:foreground \"green\" :weight bold)))\n105 \"Face for added lines\"\n106 :group 'git-gutter+)\n\n108 (defface git-gutter+-deleted\n109 '((t (:foreground \"red\" :weight bold)))\n110 \"Face for deleted lines\"\n111 :group 'git-gutter+)\n\n113 (defface git-gutter+-unchanged\n114 '((t (:background \"yellow\")))\n115 \"Face for unchanged lines\"\n116 :group 'git-gutter+)\n\n118 (defcustom git-gutter+-disabled-modes nil\n119 \"A list of modes for which `global-git-gutter+-mode' should be disabled.\"\n120 :type '(repeat symbol)\n121 :group 'git-gutter+)\n\n123 (defvar git-gutter+-mode-map\n124 (make-sparse-keymap))\n\n126 (defvar git-gutter+-view-diff-function nil\n127 \"Function to call for displaying diffs\")\n\n129 (defvar git-gutter+-clear-function nil\n130 \"Function to call for clearing the diff display\")\n\n132 (defvar git-gutter+-window-config-change-function nil\n133 \"Function to call when the buffer's local window configuration has changed\")\n\n135 (defvar git-gutter+-diffinfos nil)\n136 (defvar git-gutter+-diff-header nil)\n137 (make-variable-buffer-local 'git-gutter+-diffinfos)\n138 (make-variable-buffer-local 'git-gutter+-diff-header)\n\n140 (defvar git-gutter+-popup-buffer \"*git-gutter+-diff*\")\n141 (defvar git-gutter+-buffers-to-reenable nil)\n\n143 (defconst git-gutter+-hunk-header-regex\n144 ;; The same as diff-hunk-header-re-unified\n145 \"^@@ -\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? \\\\+\\\\([0-9]+\\\\)\\\\(?:,\\\\([0-9]+\\\\)\\\\)? @@\")\n\n147 (defalias 'git-gutter+-popup-hunk 'git-gutter+-show-hunk)\n148 (defalias 'git-gutter+-revert-hunk 'git-gutter+-revert-hunks)\n\n150 (defmacro git-gutter+-awhen (test &rest body)\n151 \"Anaphoric when.\"\n152 (declare (indent 1))\n153 `(let ((it ,test))\n154 (when it ,@body)))\n\n156 (defun git-gutter+-enable-default-display-mode ()\n157 (setq git-gutter+-view-diff-function 'git-gutter+-view-diff-infos\n158 git-gutter+-clear-function 'git-gutter+-clear-diff-infos\n159 git-gutter+-window-config-change-function 'git-gutter+-show-gutter))\n\n161 (unless git-gutter+-view-diff-function\n162 (git-gutter+-enable-default-display-mode))\n\n164 (defun git-gutter+-call-git (args &optional file)\n165 (if (and file (file-remote-p file))\n166 (apply #'process-file git-gutter+-git-executable nil t nil args)\n167 (apply #'call-process git-gutter+-git-executable nil t nil args)))\n\n169 (defun git-gutter+-in-git-repository-p (file)\n170 (with-temp-buffer\n171 (let ((args '(\"rev-parse\" \"--is-inside-work-tree\")))\n172 (when (zerop (git-gutter+-call-git args file))\n173 (goto-char (point-min))\n174 (string= \"true\" (buffer-substring-no-properties\n175 (point) (line-end-position)))))))\n\n177 (defun git-gutter+-root-directory (file)\n178 (with-temp-buffer\n179 (let* ((args '(\"rev-parse\" \"--show-toplevel\"))\n180 (ret (git-gutter+-call-git args file)))\n181 (when (zerop ret)\n182 (goto-char (point-min))\n183 (let ((root (buffer-substring-no-properties (point) (line-end-position))))\n184 (unless (string= root \"\")\n185 (file-name-as-directory root)))))))\n\n187 (defsubst git-gutter+-diff-args (file)\n188 (delq nil (list \"--no-pager\" \"diff\" \"--no-color\" \"--no-ext-diff\" \"-U0\"\n189 git-gutter+-diff-options file)))\n\n191 (defun git-gutter+-diff (curfile)\n192 (let ((args (git-gutter+-diff-args curfile))\n193 (file (buffer-file-name))) ;; for tramp\n194 (with-temp-buffer\n195 (when (zerop (git-gutter+-call-git args file))\n196 (goto-char (point-min))\n197 (let ((diff-header (git-gutter+-get-diff-header))\n198 (diffinfos (git-gutter+-get-diffinfos)))\n199 (list diff-header diffinfos))))))\n\n201 (defun git-gutter+-get-diff-header ()\n202 (save-excursion\n203 (if (re-search-forward git-gutter+-hunk-header-regex nil t)\n204 (buffer-substring (point-min) (match-beginning 0)))))\n\n206 (defsubst git-gutter+-make-diffinfo (type content start end)\n207 (list :type type :content content :start-line start :end-line end))\n\n209 (defun git-gutter+-get-diffinfos ()\n210 (loop while (re-search-forward git-gutter+-hunk-header-regex nil t)\n211 ;; Hunk header format:\n212 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n213 for del-len = (string-to-number (or (match-string 2) \"1\"))\n214 for add-line = (string-to-number (match-string 3))\n215 for add-len = (string-to-number (or (match-string 4) \"1\"))\n216 for type = (cond ((zerop del-len) 'added)\n217 ((zerop add-len) 'deleted)\n218 (t 'modified))\n219 for start-line = (if (eq type 'deleted)\n220 (1+ add-line)\n221 add-line)\n222 for end-line = (if (eq type 'deleted)\n223 start-line\n224 (1- (+ add-line add-len)))\n225 for content = (git-gutter+-diff-content)\n226 collect\n227 (git-gutter+-make-diffinfo type content start-line end-line)))\n\n229 (defun git-gutter+-diff-content ()\n230 (save-excursion\n231 (goto-char (line-beginning-position)) ; Move to beginning of hunk header\n232 (let ((hunk-start (point)))\n233 ;; Move to end of hunk\n234 (forward-line 1)\n235 (if (re-search-forward \"^@@\" nil t)\n236 (backward-char 3) ;; exclude \"\\n@@\"\n237 (goto-char (1- (point-max)))) ; Skip trailing newline\n238 (buffer-substring hunk-start (point)))))\n\n240 (defun git-gutter+-line-to-pos (line)\n241 (save-excursion\n242 (goto-char (point-min))\n243 (forward-line (1- line))\n244 (point)))\n\n246 (defun git-gutter+-before-string (sign)\n247 (let* ((sep-sign git-gutter+-separator-sign)\n248 (sep (when sep-sign\n249 (propertize sep-sign 'face 'git-gutter+-separator)))\n250 (gutter-sep (concat sign sep)))\n251 (propertize \" \" 'display `((margin left-margin) ,gutter-sep))))\n\n253 (defsubst git-gutter+-select-face (type)\n254 (case type\n255 (added 'git-gutter+-added)\n256 (modified 'git-gutter+-modified)\n257 (deleted 'git-gutter+-deleted)))\n\n259 (defsubst git-gutter+-select-sign (type)\n260 (case type\n261 (added git-gutter+-added-sign)\n262 (modified git-gutter+-modified-sign)\n263 (deleted git-gutter+-deleted-sign)))\n\n265 (defun git-gutter+-propertized-sign (type)\n266 (let ((sign (git-gutter+-select-sign type))\n267 (face (git-gutter+-select-face type)))\n268 (propertize sign 'face face)))\n\n270 (defun git-gutter+-view-region (sign start-line end-line)\n271 (let ((beg (git-gutter+-line-to-pos start-line)))\n272 (goto-char beg)\n273 (while (and (<= (line-number-at-pos) end-line) (not (eobp)))\n274 (git-gutter+-view-at-pos sign (point))\n275 (forward-line 1))))\n\n277 (defun git-gutter+-view-at-pos (sign pos)\n278 (let ((ov (make-overlay pos pos)))\n279 (overlay-put ov 'before-string (git-gutter+-before-string sign))\n280 (overlay-put ov 'git-gutter+ t)))\n\n282 (defun git-gutter+-view-diff-info (diffinfo)\n283 (let* ((start-line (plist-get diffinfo :start-line))\n284 (end-line (plist-get diffinfo :end-line))\n285 (type (plist-get diffinfo :type))\n286 (sign (git-gutter+-propertized-sign type)))\n287 (case type\n288 ((modified added) (git-gutter+-view-region sign start-line end-line))\n289 (deleted (git-gutter+-view-at-pos\n290 sign (git-gutter+-line-to-pos start-line))))))\n\n292 (defun git-gutter+-sign-width (sign)\n293 (loop for s across sign\n294 sum (char-width s)))\n\n296 (defun git-gutter+-longest-sign-width ()\n297 (let ((signs (list git-gutter+-modified-sign\n298 git-gutter+-added-sign\n299 git-gutter+-deleted-sign)))\n300 (when git-gutter+-unchanged-sign\n301 (add-to-list 'signs git-gutter+-unchanged-sign))\n302 (+ (apply 'max (mapcar 'git-gutter+-sign-width signs))\n303 (git-gutter+-sign-width git-gutter+-separator-sign))))\n\n305 (defun git-gutter+-view-for-unchanged ()\n306 (save-excursion\n307 (let ((sign (if git-gutter+-unchanged-sign\n308 (propertize git-gutter+-unchanged-sign\n309 'face 'git-gutter+-unchanged)\n310 \" \")))\n311 (goto-char (point-min))\n312 (while (not (eobp))\n313 (git-gutter+-view-at-pos sign (point))\n314 (forward-line 1)))))\n\n316 (defun git-gutter+-set-window-margin (width)\n317 (let ((curwin (get-buffer-window)))\n318 (set-window-margins curwin width (cdr (window-margins curwin)))))\n\n320 (defsubst git-gutter+-file-buffer-p ()\n321 (and (buffer-file-name)\n322 default-directory\n323 (file-directory-p default-directory)))\n\n325 ;;;###autoload\n326 (define-minor-mode git-gutter+-mode\n327 \"Git-Gutter mode\"\n328 :group 'git-gutter+\n329 :init-value nil\n330 :global nil\n331 :lighter git-gutter+-lighter\n332 (if git-gutter+-mode\n333 (if (and (git-gutter+-file-buffer-p)\n334 (git-gutter+-in-git-repository-p (buffer-file-name)))\n335 (progn\n336 (git-gutter+-add-local-hooks)\n337 (git-gutter+-refresh))\n338 (if (called-interactively-p 'any)\n339 (message \"No Git repo for current buffer\"))\n340 (git-gutter+-mode -1))\n341 (git-gutter+-remove-local-hooks)\n342 (git-gutter+-clear)))\n\n344 (defun git-gutter+-add-local-hooks ()\n345 (add-hook 'after-save-hook 'git-gutter+-refresh nil t)\n346 ;; Turn off `git-gutter+-mode' while reverting to prevent any redundant calls to\n347 ;; `git-gutter+-refresh'.\n348 (add-hook 'before-revert-hook 'git-gutter+-turn-off nil t)\n349 (add-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change nil t)\n350 (if git-gutter+-window-config-change-function\n351 (add-hook 'window-configuration-change-hook\n352 git-gutter+-window-config-change-function nil t)))\n\n354 (defun git-gutter+-remove-local-hooks ()\n355 (remove-hook 'after-save-hook 'git-gutter+-refresh t)\n356 (remove-hook 'before-revert-hook 'git-gutter+-turn-off t)\n357 (remove-hook 'change-major-mode-hook 'git-gutter+-reenable-after-major-mode-change t)\n358 (if git-gutter+-window-config-change-function\n359 (remove-hook 'window-configuration-change-hook\n360 git-gutter+-window-config-change-function t)))\n\n362 (defmacro git-gutter+-in-all-buffers (&rest body)\n363 `(dolist (buf (buffer-list))\n364 (with-current-buffer buf\n365 ,@body)))\n\n367 ;; When `define-globalized-minor-mode' is used to define `global-git-gutter+-mode',\n368 ;; `git-gutter+-mode' and thus `git-gutter+-refresh' get run twice when a new file\n369 ;; is opened. (First for `fundamental-mode', then for the file-specific mode.)\n370 ;; The following definition of `global-git-gutter+-mode' avoids any redundant calls to\n371 ;; `git-gutter+-refresh'.\n\n373 ;;;###autoload\n374 (define-minor-mode global-git-gutter+-mode ()\n375 \"Global Git-Gutter mode\"\n376 :group 'git-gutter+\n377 :init-value nil\n378 :global t\n379 (if global-git-gutter+-mode\n380 (progn\n381 (add-hook 'find-file-hook 'git-gutter+-turn-on)\n382 (add-hook 'after-revert-hook 'git-gutter+-turn-on)\n383 (add-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n384 (git-gutter+-in-all-buffers (git-gutter+-turn-on)))\n385 (remove-hook 'find-file-hook 'git-gutter+-turn-on)\n386 (remove-hook 'after-revert-hook 'git-gutter+-turn-on)\n387 (remove-hook 'after-change-major-mode-hook 'git-gutter+-reenable-buffers)\n388 (git-gutter+-in-all-buffers (git-gutter+-turn-off))))\n\n390 (defun git-gutter+-turn-on ()\n391 (when (and (buffer-file-name)\n392 (not (memq major-mode git-gutter+-disabled-modes))\n393 (not git-gutter+-mode))\n394 (git-gutter+-mode t)))\n\n396 (defun git-gutter+-turn-off ()\n397 (if git-gutter+-mode (git-gutter+-mode -1)))\n\n399 (defun git-gutter+-reenable-after-major-mode-change ()\n400 (if global-git-gutter+-mode\n401 (add-to-list 'git-gutter+-buffers-to-reenable (current-buffer))))\n\n403 (defun git-gutter+-reenable-buffers ()\n404 (dolist (buf git-gutter+-buffers-to-reenable)\n405 (with-current-buffer buf\n406 (git-gutter+-turn-on)))\n407 (setq git-gutter+-buffers-to-reenable nil))\n\n409 (defsubst git-gutter+-show-gutter-p (diffinfos)\n410 (if git-gutter+-hide-gutter\n411 (or diffinfos git-gutter+-unchanged-sign)\n412 (or global-git-gutter+-mode git-gutter+-unchanged-sign diffinfos)))\n\n414 (defun git-gutter+-show-gutter (&optional diffinfos)\n415 (when (git-gutter+-show-gutter-p (or diffinfos git-gutter+-diffinfos))\n416 (let ((win-width (or git-gutter+-window-width\n417 (git-gutter+-longest-sign-width))))\n418 (git-gutter+-set-window-margin win-width))))\n\n420 (defun git-gutter+-view-diff-infos (diffinfos)\n421 (when (or git-gutter+-unchanged-sign\n422 git-gutter+-separator-sign)\n423 (git-gutter+-view-for-unchanged))\n424 (when diffinfos\n425 (save-excursion\n426 (mapc 'git-gutter+-view-diff-info diffinfos)))\n427 (git-gutter+-show-gutter diffinfos))\n\n429 (defsubst git-gutter+-reset-window-margin-p ()\n430 (or git-gutter+-hide-gutter\n431 (not global-git-gutter+-mode)))\n\n433 (defun git-gutter+-clear-diff-infos ()\n434 (when (git-gutter+-reset-window-margin-p)\n435 (git-gutter+-set-window-margin 0))\n436 (remove-overlays (point-min) (point-max) 'git-gutter+ t))\n\n438 (defun git-gutter+-process-diff (curfile)\n439 (destructuring-bind\n440 (diff-header diffinfos) (git-gutter+-diff curfile)\n441 (setq git-gutter+-diff-header diff-header\n442 git-gutter+-diffinfos diffinfos)\n443 (save-restriction\n444 (widen)\n445 (funcall git-gutter+-view-diff-function diffinfos))))\n\n447 (defun git-gutter+-search-near-diff-index (diffinfos is-reverse)\n448 (loop with current-line = (line-number-at-pos)\n449 with cmp-fn = (if is-reverse '> '<)\n450 for diffinfo in (if is-reverse (reverse diffinfos) diffinfos)\n451 for index = 0 then (1+ index)\n452 for start-line = (plist-get diffinfo :start-line)\n453 when (funcall cmp-fn current-line start-line)\n454 return (if is-reverse\n455 (1- (- (length diffinfos) index))\n456 index)))\n\n458 (defun git-gutter+-diffinfo-at-point ()\n459 (save-restriction\n460 (widen)\n461 (loop with current-line = (line-number-at-pos)\n462 for diffinfo in git-gutter+-diffinfos\n463 for start = (plist-get diffinfo :start-line)\n464 for end = (or (plist-get diffinfo :end-line) (1+ start))\n465 when (and (>= current-line start) (<= current-line end))\n466 return diffinfo)))\n\n468 (defun git-gutter+-collect-deleted-line (str)\n469 (with-temp-buffer\n470 (insert str)\n471 (goto-char (point-min))\n472 (loop while (re-search-forward \"^-\\\\(.*?\\\\)$\" nil t)\n473 collect (match-string 1) into deleted-lines\n474 finally return deleted-lines)))\n\n476 (defun git-gutter+-delete-added-lines (start-line end-line)\n477 (forward-line (1- start-line))\n478 (let ((start-point (point)))\n479 (forward-line (1+ (- end-line start-line)))\n480 (delete-region start-point (point))))\n\n482 (defun git-gutter+-insert-deleted-lines (content)\n483 (dolist (line (git-gutter+-collect-deleted-line content))\n484 (insert (concat line \"\\n\"))))\n\n486 (defun git-gutter+-do-revert-hunk (diffinfo)\n487 (save-excursion\n488 (save-restriction\n489 (widen)\n490 (goto-char (point-min))\n491 (let ((start-line (plist-get diffinfo :start-line))\n492 (end-line (plist-get diffinfo :end-line))\n493 (content (plist-get diffinfo :content)))\n494 (case (plist-get diffinfo :type)\n495 (added (git-gutter+-delete-added-lines start-line end-line))\n496 (deleted (forward-line (1- start-line))\n497 (git-gutter+-insert-deleted-lines content))\n498 (modified (git-gutter+-delete-added-lines start-line end-line)\n499 (git-gutter+-insert-deleted-lines content)))))))\n\n501 (defun git-gutter+-revert-hunks ()\n502 \"Revert hunk at point. If region is active, revert all hunks within the region.\"\n503 (interactive)\n504 (let* ((diffinfos (git-gutter+-selected-diffinfos))\n505 (one-diffinfo-p (= 1 (length diffinfos))))\n506 (save-window-excursion\n507 (if one-diffinfo-p (git-gutter+-show-hunk (car diffinfos)))\n508 (when (and diffinfos\n509 (yes-or-no-p (if one-diffinfo-p\n510 \"Revert hunk?\"\n511 (format \"Revert %d hunks?\" (length diffinfos)))))\n512 ;; Revert diffinfos in reverse so that earlier hunks don't invalidate the\n513 ;; line number information of the later hunks.\n514 (dolist (diffinfo (nreverse diffinfos))\n515 (git-gutter+-do-revert-hunk diffinfo))\n516 (save-buffer))\n517 (if one-diffinfo-p\n518 (git-gutter+-awhen (get-buffer git-gutter+-popup-buffer)\n519 (kill-buffer it))))))\n\n521 (defun git-gutter+-show-hunk (&optional diffinfo)\n522 \"Show hunk at point in another window\"\n523 (interactive)\n524 (git-gutter+-awhen (or diffinfo\n525 (git-gutter+-diffinfo-at-point))\n526 (save-selected-window\n527 (with-current-buffer (get-buffer-create git-gutter+-popup-buffer)\n528 (setq buffer-read-only nil)\n529 (erase-buffer)\n530 (insert (plist-get it :content))\n531 (insert \"\\n\")\n532 (goto-char (point-min))\n533 (diff-mode)\n534 (view-mode)\n535 (pop-to-buffer (current-buffer))))))\n\n537 (defun git-gutter+-next-hunk (arg)\n538 \"Move to next diff hunk\"\n539 (interactive \"p\")\n540 (if (not git-gutter+-diffinfos)\n541 (message \"No changes in buffer\")\n542 (save-restriction\n543 (widen)\n544 (let* ((is-reverse (< arg 0))\n545 (diffinfos git-gutter+-diffinfos)\n546 (len (length diffinfos))\n547 (index (git-gutter+-search-near-diff-index diffinfos is-reverse))\n548 (real-index (if index\n549 (let ((next (if is-reverse (1+ index) (1- index))))\n550 (mod (+ arg next) len))\n551 (if is-reverse (1- (length diffinfos)) 0)))\n552 (diffinfo (nth real-index diffinfos)))\n553 (goto-char (point-min))\n554 (forward-line (1- (plist-get diffinfo :start-line)))\n555 (when (buffer-live-p (get-buffer git-gutter+-popup-buffer))\n556 (save-window-excursion\n557 (git-gutter+-show-hunk)))))))\n\n559 (defun git-gutter+-previous-hunk (arg)\n560 \"Move to previous diff hunk\"\n561 (interactive \"p\")\n562 (git-gutter+-next-hunk (- arg)))\n\n564 (defun git-gutter+-remote-default-directory (dir file)\n565 (let* ((vec (tramp-dissect-file-name file))\n566 (method (aref vec 0))\n567 (user (aref vec 1))\n568 (host (aref vec 2)))\n569 (format \"/%s:%s%s:%s\" method (if user (concat user \"@\") \"\") host dir)))\n\n571 (defun git-gutter+-remote-file-path (dir file)\n572 (let ((file (aref (tramp-dissect-file-name file) 3)))\n573 (replace-regexp-in-string (concat \"\\\\`\" dir) \"\" file)))\n\n575 (defun git-gutter+-local-file-path (file)\n576 (if (eq system-type 'windows-nt)\n577 ;; Cygwin can't handle Windows absolute paths\n578 (file-relative-name file default-directory)\n579 file))\n\n581 (defun git-gutter+-refresh ()\n582 (git-gutter+-clear)\n583 (let ((file (buffer-file-name)))\n584 (when (and file (file-exists-p file))\n585 (if (file-remote-p file)\n586 (let* ((repo-root (git-gutter+-root-directory file))\n587 (default-directory (git-gutter+-remote-default-directory repo-root file)))\n588 (git-gutter+-process-diff (git-gutter+-remote-file-path repo-root file)))\n589 (git-gutter+-process-diff (git-gutter+-local-file-path file))))))\n\n591 (defun git-gutter+-clear ()\n592 (save-restriction\n593 (widen)\n594 (funcall git-gutter+-clear-function))\n595 (setq git-gutter+-diffinfos nil))\n\n\n598 ;;; Staging\n\n600 (defun git-gutter+-stage-hunks ()\n601 \"Stage hunk at point. If region is active, stage all hunk lines within the region.\"\n602 (interactive)\n603 (let* ((line-range (if (use-region-p)\n604 (cons (line-number-at-pos (region-beginning))\n605 (line-number-at-pos (region-end)))))\n606 (diffinfos (git-gutter+-selected-diffinfos line-range)))\n607 (when diffinfos\n608 (let ((error-msg (git-gutter+-stage-diffinfos diffinfos line-range)))\n609 (if error-msg\n610 (message \"Error staging hunks:\\n%s\" error-msg))\n611 (git-gutter+-refresh)))))\n\n613 (defun git-gutter+-selected-diffinfos (&optional line-range)\n614 (unless line-range\n615 (setq line-range (if (use-region-p)\n616 (cons (line-number-at-pos (region-beginning))\n617 (line-number-at-pos (region-end))))))\n618 (if line-range\n619 (git-gutter+-diffinfos-between-lines line-range)\n620 (git-gutter+-awhen (git-gutter+-diffinfo-at-point)\n621 (list it))))\n\n623 (defsubst git-gutter+-diffinfo-between-lines-p (diffinfo start-line end-line)\n624 (let ((diff-start (plist-get diffinfo :start-line))\n625 (diff-end (plist-get diffinfo :end-line)))\n626 (and (<= start-line diff-end)\n627 (<= diff-start end-line))))\n\n629 (defun git-gutter+-diffinfos-between-lines (line-range)\n630 (save-restriction\n631 (widen)\n632 (let ((start-line (car line-range))\n633 (end-line (cdr line-range)))\n634 (delq nil\n635 (mapcar (lambda (diffinfo)\n636 (if (git-gutter+-diffinfo-between-lines-p\n637 diffinfo start-line end-line)\n638 diffinfo))\n639 git-gutter+-diffinfos)))))\n\n641 (defun git-gutter+-stage-diffinfos (diffinfos line-range)\n642 (let ((header git-gutter+-diff-header))\n643 (with-temp-buffer\n644 (insert header)\n645 ;; Insert hunks in reverse so that earlier hunks don't invalidate the line\n646 ;; number information of the later hunks.\n647 (dolist (diffinfo (nreverse diffinfos))\n648 (git-gutter+-insert-diffinfo diffinfo line-range)\n649 (goto-char (point-max)))\n650 (git-gutter+-call-git-on-current-buffer\n651 '(\"apply\" \"--unidiff-zero\" \"--cached\" \"-\")))))\n\n653 (defun git-gutter+-insert-diffinfo (diffinfo line-range)\n654 (let ((content (plist-get diffinfo :content))\n655 (type (plist-get diffinfo :type)))\n656 (if (not line-range)\n657 (git-gutter+-insert-hunk content type)\n658 (let ((diff-start-line (plist-get diffinfo :start-line))\n659 (diff-end-line (plist-get diffinfo :end-line))\n660 (start-line (car line-range))\n661 (end-line (cdr line-range)))\n662 (git-gutter+-insert-hunk content type\n663 (1+ (- start-line diff-start-line))\n664 (1+ (- end-line diff-start-line)))))))\n\n666 (defun git-gutter+-call-git-on-current-buffer (args)\n667 \"Sends the current buffer contents to Git and replaces them with Git's output.\n\n669 RETURNS nil if Git ran successfully. Returns an error description otherwise.\"\n670 (unless (zerop (apply #'call-process-region (point-min) (point-max)\n671 git-gutter+-git-executable t t nil args))\n672 (buffer-string)))\n\n674 (defsubst git-gutter+-read-hunk-header (hunk)\n675 ;; @@ -{del-line},{del-len} +{add-line},{add-len} @@\n676 (string-match git-gutter+-hunk-header-regex hunk)\n677 (list (string-to-number (match-string 1 hunk))\n678 (string-to-number (or (match-string 2 hunk) \"1\"))\n679 (string-to-number (match-string 3 hunk))\n680 (string-to-number (or (match-string 4 hunk) \"1\"))))\n\n682 (defun git-gutter+-insert-hunk (hunk type &optional start end)\n683 \"If START and END are provided, only insert addition (+) lines between\n684 START and END (inclusive). START and END are both line numbers starting with 1.\"\n685 (destructuring-bind\n686 (del-line del-len add-line add-len) (git-gutter+-read-hunk-header hunk)\n687 (let* ((start (max 1 (or start 1)))\n688 (end (min add-len (or end add-len)))\n689 (insert-all-p (or (eq type :deleted)\n690 (and (= start 1) (= end add-len))))\n691 (num-lines-selected (if insert-all-p\n692 add-len\n693 (1+ (- end start)))))\n694 ;; When the user selected the last lines of a hunk with type `modified' (but\n695 ;; not the complete hunk), then don't insert any deletion (-) lines from that\n696 ;; hunk.\n697 (if (and (eq type 'modified)\n698 (> start 1) (= end add-len))\n699 (setq type 'modified-trailing))\n\n701 (save-excursion\n702 (insert hunk \"\\n\"))\n\n704 (git-gutter+-delete-hunk-header)\n\n706 (if (not insert-all-p)\n707 (git-gutter+-modify-hunk type num-lines-selected del-len start))\n\n709 (let ((hunk-header (git-gutter+-make-hunk-header type num-lines-selected\n710 del-line del-len add-line)))\n711 (insert hunk-header \"\\n\")))))\n\n713 (defun git-gutter+-delete-hunk-header ()\n714 (let ((hunk-start (point)))\n715 (forward-line 1)\n716 (delete-region hunk-start (point))))\n\n718 (defun git-gutter+-modify-hunk (type num-lines-selected del-len start)\n719 \"Remove all addition (+) lines from hunk that aren't selected.\n720 If TYPE is not `modified', also remove all deletion (-) lines.\"\n721 (let ((first-line-selected (+ del-len (1- start)))\n722 selected-lines)\n723 (save-excursion\n724 (forward-line first-line-selected)\n725 (let ((selection-start (point)))\n726 (forward-line num-lines-selected)\n727 (setq selected-lines (buffer-substring selection-start (point)))))\n728 (save-excursion\n729 (if (eq type 'modified) (forward-line del-len)) ; skip over deletion (-) lines\n730 (delete-region (point) (point-max))\n731 (insert selected-lines))))\n\n733 (defun git-gutter+-make-hunk-header (type num-lines-selected del-line del-len add-line)\n734 (let ((add-len num-lines-selected))\n735 (case type\n736 (added (setq add-line (1+ del-line)))\n737 (modified-trailing (setq add-line (+ del-line del-len)\n738 del-line (1- add-line)\n739 del-len 0))\n740 (t (setq add-line del-line)))\n741 (format \"@@ -%d,%d +%d,%d @@\"\n742 del-line del-len\n743 add-line add-len)))\n\n\n746 ;;; Committing\n747 ;; This section draws heavily from old Magit source code.\n\n749 (defvar git-gutter+-pre-commit-window-config nil)\n750 (defvar git-gutter+-commit-origin-buffer nil\n751 \"Buffer that started the commit\")\n\n753 (defconst git-gutter+-commit-buffer-name \"*Commit Message*\")\n754 (defconst git-gutter+-staged-changes-buffer-name \"*Staged Changes*\")\n\n756 ;;;###autoload\n757 (defun git-gutter+-commit ()\n758 \"Commit staged changes. If nothing is staged, ask to stage the current buffer.\"\n759 (interactive)\n\n761 (when (and (not (git-gutter+-anything-staged-p))\n762 git-gutter+-diffinfos\n763 (y-or-n-p \"Nothing staged. Stage current buffer? \"))\n764 (git-gutter+-stage-whole-buffer))\n\n766 (let ((file (buffer-file-name))\n767 (dir default-directory))\n768 (git-gutter+-save-window-config-if-needed)\n769 (setq git-gutter+-commit-origin-buffer (current-buffer))\n770 (git-gutter+-open-commit-edit-buffer dir)\n771 (git-gutter+-show-staged-changes file dir)))\n\n773 (defun git-gutter+-stage-and-commit ()\n774 (interactive)\n775 (git-gutter+-stage-hunks)\n776 (git-gutter+-commit))\n\n778 (defun git-gutter+-save-window-config-if-needed ()\n779 ;; Only save the window config if the temporary buffers that get popped-up by\n780 ;; git-gutter+ are not already visible.\n781 ;; In this way, `git-gutter+-commit' can be called twice in a row without\n782 ;; losing the original window config.\n783 (when (not (and git-gutter+-pre-commit-window-config\n784 (get-buffer-window git-gutter+-commit-buffer-name)\n785 (get-buffer-window git-gutter+-staged-changes-buffer-name)))\n786 (setq git-gutter+-pre-commit-window-config (current-window-configuration))))\n\n788 (defun git-gutter+-open-commit-edit-buffer (dir)\n789 \"Opens a buffer for composing the commit message\"\n790 (pop-to-buffer (get-buffer-create git-gutter+-commit-buffer-name))\n791 (setq default-directory dir)\n792 (git-gutter+-commit-mode)\n793 (message \"Type C-c C-c to commit (C-c C-k to cancel).\"))\n\n795 (defsubst git-gutter+-pop-to-staged-changes-buffer ()\n796 (let* ((buf (get-buffer-create git-gutter+-staged-changes-buffer-name))\n797 (window (get-buffer-window buf)))\n798 (if window\n799 ;; Buffer is already visible\n800 (select-window window)\n801 (if (<= (length (window-list)) 2)\n802 (split-window))\n803 (pop-to-buffer buf))))\n\n805 (defun git-gutter+-show-staged-changes (file dir)\n806 (save-selected-window\n807 (git-gutter+-pop-to-staged-changes-buffer)\n808 (setq buffer-read-only nil)\n809 (erase-buffer)\n810 (let ((default-directory dir))\n811 (git-gutter+-call-git '(\"diff\" \"--staged\") file))\n812 (goto-char (point-min))\n813 (diff-mode)\n814 (view-mode)))\n\n816 (defsubst git-gutter+-abort-commit-when-no-changes (allow-empty amend)\n817 (unless (or amend\n818 allow-empty\n819 (git-gutter+-anything-staged-p))\n820 (error\n821 \"Refusing to create empty commit. Maybe you want to amend (%s) or allow-empty (%s)?\"\n822 (key-description (car (where-is-internal\n823 'git-gutter+-commit-toggle-amending)))\n824 (key-description (car (where-is-internal\n825 'git-gutter+-commit-toggle-allow-empty))))))\n\n827 (defsubst git-gutter+-buffer-is-whitespace ()\n828 (save-excursion\n829 (goto-char (point-min))\n830 (looking-at-p \"[ \\t\\n]*\\\\'\")))\n\n832 (defun git-gutter+-publish-commit ()\n833 \"Publish commit\"\n834 (interactive)\n835 (let* ((fields (git-gutter+-commit-get-fields))\n836 (amend (equal \"yes\" (git-gutter+-commit-get-field 'amend fields)))\n837 (allow-empty (equal \"yes\" (git-gutter+-commit-get-field 'allow-empty fields)))\n838 (author (git-gutter+-commit-get-field 'author fields))\n839 (date (git-gutter+-commit-get-field 'date fields)))\n\n841 (git-gutter+-abort-commit-when-no-changes allow-empty amend)\n\n843 (git-gutter+-push-to-comment-ring (buffer-string))\n\n845 (git-gutter+-commit-set-fields nil) ; Delete message header\n\n847 (when (git-gutter+-buffer-is-whitespace)\n848 (erase-buffer)\n849 (insert \"(Empty description)\"))\n\n851 (let ((error-msg (git-gutter+-call-git-on-current-buffer\n852 (append '(\"--no-pager\" \"commit\" \"-F\" \"-\")\n853 (if amend '(\"--amend\"))\n854 (if allow-empty '(\"--allow-empty\"))\n855 (if author (list (concat \"--author=\" author)))\n856 (if date (list (concat \"--date=\" date)))))))\n857 (if error-msg\n858 (progn\n859 (message \"Commit error:\\n%s\" error-msg)\n860 (erase-buffer)\n861 (insert (ring-ref log-edit-comment-ring 0))) ; Reinsert commit message\n862 (message \"Commit successful.\")\n863 (git-gutter+-close-commit-edit-buffer)\n864 (git-gutter+-update-vc-modeline)))))\n\n866 (defun git-gutter+-close-commit-edit-buffer ()\n867 \"Abort edits and discard commit message being composed.\"\n868 (interactive)\n869 (kill-buffer)\n870 (set-window-configuration git-gutter+-pre-commit-window-config))\n\n872 (defun git-gutter+-update-vc-modeline ()\n873 (when (buffer-live-p git-gutter+-commit-origin-buffer)\n874 (with-current-buffer git-gutter+-commit-origin-buffer\n875 ;; Updating the modeline has no effect if the buffer still has\n876 ;; changes - it will remain in the 'modified' state. So skip it then.\n877 (unless git-gutter+-diffinfos\n878 (ignore-errors (vc-find-file-hook))))))\n\n880 (defun git-gutter+-stage-whole-buffer ()\n881 (save-excursion\n882 (mark-whole-buffer)\n883 (git-gutter+-stage-hunks)))\n\n885 (defun git-gutter+-anything-staged-p ()\n886 \"Return t if the current repo has staged changes\"\n887 (not (zerop (git-gutter+-call-git '(\"diff\" \"--quiet\" \"--cached\")))))\n\n889 (defun git-gutter+-commit-toggle-amending ()\n890 \"Toggle whether this will be an amendment to the previous commit.\n891 \\(i.e., whether commit is run via 'git commit --amend')\"\n892 (interactive)\n893 ;; Remove the newline that 'git-commit-mode' adds to a new commit\n894 ;; message buffer by default. This prevents an ugly visual\n895 ;; gap between the commit message header and the previous commit\n896 ;; message.\n897 (when (git-gutter+-buffer-is-whitespace)\n898 (erase-buffer))\n\n900 (let ((amend-was-already-set (git-gutter+-commit-get-field 'amend)))\n901 (git-gutter+-commit-toggle-field 'amend t)\n902 (unless amend-was-already-set\n903 ;; Insert previous commit message\n904 (goto-char (point-max))\n905 (unless (zerop (current-column))\n906 (insert \"\\n\"))\n907 (insert (git-gutter+-get-last-commit-msg)\n908 \"\\n\"))))\n\n910 (defun git-gutter+-commit-toggle-allow-empty ()\n911 \"Toggle whether this commit is allowed to be empty.\n912 \\(i.e., whether commit is run via 'git commit --allow-empty')\"\n913 (interactive)\n914 (git-gutter+-commit-toggle-field 'allow-empty t))\n\n916 (defun git-gutter+-format-author (author email)\n917 (format \"%s <%s>\" author email))\n\n919 (defun git-gutter+-commit-toggle-author ()\n920 \"Toggle whether this commit should have a user-defined author.\"\n921 (interactive)\n922 (git-gutter+-commit-toggle-input\n923 'author (git-gutter+-format-author\n924 (or (git-gutter+-get-cfg \"user\" \"name\") \"Author Name\")\n925 (or (git-gutter+-get-cfg \"user\" \"email\") \"author@email\"))))\n\n927 (defun git-gutter+-commit-toggle-date ()\n928 \"Toggle whether this commit should have a user-defined date.\"\n929 (interactive)\n930 (git-gutter+-commit-toggle-input 'date\n931 ;; ISO 8601\n932 (format-time-string \"%Y-%m-%dT%T%z\" (current-time))))\n\n934 (defun git-gutter+-push-to-comment-ring (comment)\n935 (when (or (ring-empty-p log-edit-comment-ring)\n936 (not (equal comment (ring-ref log-edit-comment-ring 0))))\n937 (ring-insert log-edit-comment-ring comment)))\n\n939 (defun git-gutter+-get-last-commit-msg ()\n940 (git-gutter+-git-output '(\"log\" \"--max-count=1\" \"--pretty=format:%s%n%n%b\" \"HEAD\")))\n\n942 (defun git-gutter+-get-cfg (&rest keys)\n943 (git-gutter+-git-output (list \"config\" (mapconcat 'identity keys \".\"))))\n\n945 (defun git-gutter+-git-output (args)\n946 (with-temp-buffer\n947 (git-gutter+-call-git args)\n948 ;; Delete trailing newlines\n949 (goto-char (point-min))\n950 (if (re-search-forward \"\\n+\\\\'\" nil t)\n951 (replace-match \"\"))\n952 (buffer-string)))\n\n\n955 ;;; Commit message header\n\n957 (defconst git-gutter+-commit-header-end \"-- End of commit options header --\\n\")\n\n959 (defun git-gutter+-commit-get-field (name &optional fields)\n960 (cdr (assq name (or fields (git-gutter+-commit-get-fields)))))\n\n962 (defun git-gutter+-commit-set-field (name value)\n963 (let* ((fields (git-gutter+-commit-get-fields))\n964 (cell (assq name fields)))\n965 (cond (cell\n966 (if value\n967 (rplacd cell value)\n968 (setq fields (delq cell fields))))\n969 (t\n970 (if value\n971 (setq fields (append fields (list (cons name value)))))))\n972 (git-gutter+-commit-set-fields fields)))\n\n974 (defun git-gutter+-commit-toggle-field (name default)\n975 \"Toggle the commit header field named NAME.\n976 If it's currently unset, set it to DEFAULT (t or nil).\"\n977 (let* ((fields (git-gutter+-commit-get-fields))\n978 (cell (assq name fields)))\n979 (if cell\n980 (rplacd cell (if (equal (cdr cell) \"yes\") \"no\" \"yes\"))\n981 (setq fields (acons name (if default \"yes\" \"no\") fields)))\n982 (git-gutter+-commit-set-fields fields)))\n\n984 (defun git-gutter+-commit-toggle-input (name default)\n985 \"Toggle the commit header input named NAME.\n986 If it's currently unset, set it to DEFAULT (a string). If it is\n987 set remove it.\"\n988 (let* ((fields (git-gutter+-commit-get-fields))\n989 (cell (assq name fields)))\n990 (if cell\n991 (setq fields (assq-delete-all name fields))\n992 (setq fields (acons name default fields)))\n993 (git-gutter+-commit-set-fields fields)))\n\n995 (defun git-gutter+-commit-get-fields ()\n996 (let (result)\n997 (goto-char (point-min))\n998 (while (looking-at \"^\\\\([A-Za-z0-9-_]+\\\\): *\\\\(.+\\\\)?$\")\n999 (let ((name (intern (downcase (match-string 1))))\n1000 (value (read (or (match-string 2) \"nil\"))))\n1001 (push (cons name value) result))\n1002 (forward-line))\n1003 (if (looking-at (regexp-quote git-gutter+-commit-header-end))\n1004 (nreverse result))))\n\n1006 (defun git-gutter+-commit-set-fields (fields)\n1007 (goto-char (point-min))\n1008 ;; Delete commit header\n1009 (if (search-forward-regexp (format \"^\\\\(?:[A-Za-z0-9-_]+:.*\\n\\\\)*%s\"\n1010 (regexp-quote git-gutter+-commit-header-end))\n1011 nil t)\n1012 (delete-region (match-beginning 0) (match-end 0)))\n1013 (goto-char (point-min))\n1014 (when fields\n1015 (dolist (field fields)\n1016 (insert (capitalize (symbol-name (car field))) \": \"\n1017 (prin1-to-string (cdr field)) \"\\n\"))\n1018 (insert git-gutter+-commit-header-end)))\n\n\n1021 ;;; git-gutter+-commit-mode\n1022 ;; Like git-commit-mode, but adds keybindings to git-gutter+ commands and\n1023 ;; highlighting support for the commit message header.\n\n1025 (define-derived-mode git-gutter+-commit-mode git-commit-mode \"Git-Gutter-Commit\"\n1026 (setq font-lock-defaults (list (git-gutter+-commit-font-lock-keywords) t)))\n\n1028 (setq git-gutter+-commit-mode-map\n1029 (let ((map (copy-keymap git-commit-mode-map)))\n1030 (define-key map (kbd \"C-c C-c\") 'git-gutter+-publish-commit)\n1031 (define-key map (kbd \"C-c C-k\") 'git-gutter+-close-commit-edit-buffer)\n1032 (define-key map (kbd \"C-c C-a\") 'git-gutter+-commit-toggle-amending)\n1033 (define-key map (kbd \"C-c C-e\") 'git-gutter+-commit-toggle-allow-empty)\n1034 (define-key map (kbd \"C-c C-u\") 'git-gutter+-commit-toggle-author)\n1035 (define-key map (kbd \"C-c C-d\") 'git-gutter+-commit-toggle-date)\n1036 (define-key map (kbd \"C-c C-b\") 'git-commit-ack)\n1037 (define-key map (kbd \"M-p\") 'log-edit-previous-comment)\n1038 (define-key map (kbd \"M-n\") 'log-edit-next-comment)\n1039 map))\n\n1041 (defface git-gutter+-commit-header-face\n1042 '((t :inherit font-lock-comment-face))\n1043 \"Highlights the commit message header\"\n1044 :group 'git-gutter+-faces)\n\n1046 (defconst git-gutter+-commit-header-regex\n1047 (concat \"\\\\(?:.\\\\|\\n\\\\)*?\" (regexp-quote git-gutter+-commit-header-end)))\n\n1049 (defconst git-gutter+-skip-commit-header-regex\n1050 (concat \"\\\\`\\\\(?:\" git-gutter+-commit-header-regex \"\\\\)?\"))\n\n1052 ;; Modify git-commit-summary-regexp to ignore the commit header\n1053 (defadvice git-commit-summary-regexp\n1054 (after ignore-git-gutter+-commit-header activate compile)\n1055 (if (eq major-mode 'git-gutter+-commit-mode)\n1056 (setq ad-return-value\n1057 (concat git-gutter+-skip-commit-header-regex\n1058 (substring ; Remove leading \"\\\\`\"\n1059 ad-return-value 2)))))\n\n1061 (defun git-gutter+-commit-font-lock-keywords ()\n1062 \"Like `git-commit-mode-font-lock-keywords' but with commit header highlighting\"\n1063 `((,(concat \"\\\\`\" git-gutter+-commit-header-regex) . 'git-gutter+-commit-header-face)\n1064 ,@(git-commit-mode-font-lock-keywords)))\n\n\n1067 ;;; Magit synchronization\n1068 ;; Force Magit to refresh git-gutter+ when updating the VC mode line.\n\n1070 (defvar git-gutter+-orig-vc-find-file-hook)\n\n1072 (defvar git-gutter+-vc-find-file-hook-with-refresh\n1073 (lambda ()\n1074 (funcall git-gutter+-orig-vc-find-file-hook)\n1075 (if git-gutter+-mode (git-gutter+-refresh))))\n\n1077 (defadvice magit-update-vc-modeline (around refresh-git-gutter+ compile activate)\n1078 ;; `magit-update-vc-modeline' calls `vc-find-file-hook' (a function!) on each\n1079 ;; buffer in the repo. Temporarily rebind it to `vc-find-file-hook-with-refresh',\n1080 ;; which calls git-gutter+-refresh after updating the VC mode line.\n1081 ;;\n1082 ;; Using `flet' would have been much simpler, but it's deprecated since 24.3.\n1083 (setq git-gutter+-orig-vc-find-file-hook (symbol-function 'vc-find-file-hook))\n1084 (fset 'vc-find-file-hook git-gutter+-vc-find-file-hook-with-refresh)\n1085 (unwind-protect\n1086 ad-do-it\n1087 (fset 'vc-find-file-hook git-gutter+-orig-vc-find-file-hook)))\n\n1089 (provide 'git-gutter+)\n\n1091 ;;; git-gutter+.el ends here\n")) (setq helm-swoop-cache t))) (candidates-in-buffer) (get-line . buffer-substring-no-properties) (keymap keymap (C-M-left . backward-sexp) (C-M-right . forward-sexp) (27 keymap (105 . helm-multi-swoop-all-from-helm-swoop)) (3 keymap (5 . helm-swoop-edit)) keymap (C-M-left . paren-backward-sexp) (C-M-right . paren-forward-sexp) (94 . helm-swoop-caret-match) (menu-bar keymap (help-menu keymap (describe keymap (describe-mode . helm-help)))) (help keymap (109 . helm-help)) (f1 keymap (109 . helm-help)) (8 keymap (109 . helm-help) (104 . undefined) (8 . undefined) (4 . helm-debug-output)) (20 . helm-toggle-resplit-and-swap-windows) (C-tab . undefined) (triple-mouse-3 . ignore) (double-mouse-3 . ignore) (mouse-3 . ignore) (drag-mouse-3 . ignore) (down-mouse-3 . ignore) (triple-mouse-2 . ignore) (double-mouse-2 . ignore) (mouse-2 . ignore) (drag-mouse-2 . ignore) (down-mouse-2 . ignore) (triple-mouse-1 . ignore) (double-mouse-1 . ignore) (mouse-1 . ignore) (drag-mouse-1 . ignore) (down-mouse-1 . ignore) (67108897 . helm-toggle-suspend-update) (3 keymap (21 . helm-force-update) (6 . helm-follow-mode) (11 . helm-kill-selection-and-quit) (25 . helm-yank-selection) (4 . helm-delete-current-selection) (45 . helm-swap-windows)) (67108987 . helm-enlarge-window) (67108989 . helm-narrow-window) (19 . undefined) (18 . undefined) (23 . helm-yank-text-at-point) (24 keymap (2 . helm-resume-list-buffers-after-quit) (98 . helm-resume-previous-session-after-quit) (6 . helm-quit-and-find-file)) (11 . helm-delete-minibuffer-contents) (67108896 . helm-toggle-visible-mark) (0 . helm-toggle-visible-mark) (C-M-up . helm-scroll-other-window-down) (C-M-down . helm-scroll-other-window) (M-prior . helm-scroll-other-window-down) (M-next . helm-scroll-other-window) (12 . helm-recenter-top-bottom-other-window) (15 . helm-next-source) (10 . helm-select-3rd-action) (5 . helm-select-2nd-action-or-end-of-line) ...) (header-line . "[C-c C-e] Edit mode, [M-i] apply all buffers") (action lambda ($line) (helm-swoop--goto-line (when (string-match "^[0-9]+" $line) (string-to-number (match-string 0 $line)))) (when (re-search-forward (mapconcat (quote identity) (split-string helm-pattern " ") "\\|") nil t) (goto-char (match-beginning 0))) (helm-swoop--recenter)) (migemo)) :buffer "*Helm Swoop*" :input #("git-gutter+-refresh" 0 19 (fontified t face whitespace-line)) :prompt "Swoop: " :preselect "^368 " :candidate-number-limit 19999)
(let ((helm-display-function helm-swoop-split-window-function) (helm-display-source-at-screen-top nil) (helm-completion-window-scroll-margin 5)) (helm :sources (or $source (if (> helm-swoop-last-prefix-number 1) (helm-c-source-swoop-multiline helm-swoop-last-prefix-number) (helm-c-source-swoop))) :buffer helm-swoop-buffer :input $query :prompt helm-swoop-prompt :preselect (if (string-match "^[ \n ]*$" (helm-swoop--get-string-at-line)) (save-excursion (if (re-search-forward "[^ \n ]" nil t) (format "^%s " (line-number-at-pos)) (re-search-backward "[^ \n ]" nil t) (format "^%s " (line-number-at-pos)))) (format "^%s " (line-number-at-pos))) :candidate-number-limit helm-swoop-candidate-number-limit))
(progn (ad-enable-advice (quote helm-next-line) (quote around) (quote helm-swoop-next-line)) (ad-activate (quote helm-next-line)) (ad-enable-advice (quote helm-previous-line) (quote around) (quote helm-swoop-previous-line)) (ad-activate (quote helm-previous-line)) (ad-enable-advice (quote helm-move--next-line-fn) (quote around) (quote helm-multi-swoop-next-line-cycle)) (ad-activate (quote helm-move--next-line-fn)) (ad-enable-advice (quote helm-move--previous-line-fn) (quote around) (quote helm-multi-swoop-previous-line-cycle)) (ad-activate (quote helm-move--previous-line-fn)) (add-hook (quote helm-update-hook) (quote helm-swoop--pattern-match)) (add-hook (quote helm-after-update-hook) (quote helm-swoop--keep-nearest-position) t) (cond ($query (if (string-match "\\(\\^\\[0\\-9\\]\\+\\.\\)\\(.*\\)" $query) $query $query)) (mark-active (let (($st (buffer-substring-no-properties (region-beginning) (region-end)))) (if (string-match "\n" $st) (message "Multi line region is not allowed") (setq $query $st)))) ((setq $query (funcall helm-swoop-pre-input-function))) (t (setq $query ""))) (helm-swoop--recenter) (move-beginning-of-line 1) (helm-swoop--target-line-overlay-move) (let ((helm-display-function helm-swoop-split-window-function) (helm-display-source-at-screen-top nil) (helm-completion-window-scroll-margin 5)) (helm :sources (or $source (if (> helm-swoop-last-prefix-number 1) (helm-c-source-swoop-multiline helm-swoop-last-prefix-number) (helm-c-source-swoop))) :buffer helm-swoop-buffer :input $query :prompt helm-swoop-prompt :preselect (if (string-match "^[ \n ]*$" (helm-swoop--get-string-at-line)) (save-excursion (if (re-search-forward "[^ \n ]" nil t) (format "^%s " (line-number-at-pos)) (re-search-backward "[^ \n ]" nil t) (format "^%s " (line-number-at-pos)))) (format "^%s " (line-number-at-pos))) :candidate-number-limit helm-swoop-candidate-number-limit)))
(unwind-protect (progn (ad-enable-advice (quote helm-next-line) (quote around) (quote helm-swoop-next-line)) (ad-activate (quote helm-next-line)) (ad-enable-advice (quote helm-previous-line) (quote around) (quote helm-swoop-previous-line)) (ad-activate (quote helm-previous-line)) (ad-enable-advice (quote helm-move--next-line-fn) (quote around) (quote helm-multi-swoop-next-line-cycle)) (ad-activate (quote helm-move--next-line-fn)) (ad-enable-advice (quote helm-move--previous-line-fn) (quote around) (quote helm-multi-swoop-previous-line-cycle)) (ad-activate (quote helm-move--previous-line-fn)) (add-hook (quote helm-update-hook) (quote helm-swoop--pattern-match)) (add-hook (quote helm-after-update-hook) (quote helm-swoop--keep-nearest-position) t) (cond ($query (if (string-match "\\(\\^\\[0\\-9\\]\\+\\.\\)\\(.*\\)" $query) $query $query)) (mark-active (let (($st (buffer-substring-no-properties ... ...))) (if (string-match "\n" $st) (message "Multi line region is not allowed") (setq $query $st)))) ((setq $query (funcall helm-swoop-pre-input-function))) (t (setq $query ""))) (helm-swoop--recenter) (move-beginning-of-line 1) (helm-swoop--target-line-overlay-move) (let ((helm-display-function helm-swoop-split-window-function) (helm-display-source-at-screen-top nil) (helm-completion-window-scroll-margin 5)) (helm :sources (or $source (if (> helm-swoop-last-prefix-number 1) (helm-c-source-swoop-multiline helm-swoop-last-prefix-number) (helm-c-source-swoop))) :buffer helm-swoop-buffer :input $query :prompt helm-swoop-prompt :preselect (if (string-match "^[ \n ]*$" (helm-swoop--get-string-at-line)) (save-excursion (if (re-search-forward "[^ \n ]" nil t) (format "^%s " ...) (re-search-backward "[^ \n ]" nil t) (format "^%s " ...))) (format "^%s " (line-number-at-pos))) :candidate-number-limit helm-swoop-candidate-number-limit))) (helm-swoop--restore))
(progn (setq helm-swoop-synchronizing-window (selected-window)) (setq helm-swoop-last-point (cons (point) (buffer-name (current-buffer)))) (setq helm-swoop-last-line-info (cons (current-buffer) (line-number-at-pos))) (if (boundp (quote helm-swoop-last-query)) nil (set (make-local-variable (quote helm-swoop-last-query)) "")) (setq helm-swoop-target-buffer (current-buffer)) (helm-swoop--set-prefix $multiline) (setq helm-swoop-line-overlay (make-overlay (point) (point))) (overlay-put helm-swoop-line-overlay (quote face) (if (< 1 helm-swoop-last-prefix-number) (quote helm-swoop-target-line-block-face) (quote helm-swoop-target-line-face))) (cond ((not (boundp (quote helm-swoop-cache))) (set (make-local-variable (quote helm-swoop-cache)) nil)) ((buffer-modified-p) (setq helm-swoop-cache nil))) (cond ((not (boundp (quote helm-swoop-list-cache))) (set (make-local-variable (quote helm-swoop-list-cache)) nil)) ((buffer-modified-p) (setq helm-swoop-list-cache nil))) (unwind-protect (progn (ad-enable-advice (quote helm-next-line) (quote around) (quote helm-swoop-next-line)) (ad-activate (quote helm-next-line)) (ad-enable-advice (quote helm-previous-line) (quote around) (quote helm-swoop-previous-line)) (ad-activate (quote helm-previous-line)) (ad-enable-advice (quote helm-move--next-line-fn) (quote around) (quote helm-multi-swoop-next-line-cycle)) (ad-activate (quote helm-move--next-line-fn)) (ad-enable-advice (quote helm-move--previous-line-fn) (quote around) (quote helm-multi-swoop-previous-line-cycle)) (ad-activate (quote helm-move--previous-line-fn)) (add-hook (quote helm-update-hook) (quote helm-swoop--pattern-match)) (add-hook (quote helm-after-update-hook) (quote helm-swoop--keep-nearest-position) t) (cond ($query (if (string-match "\\(\\^\\[0\\-9\\]\\+\\.\\)\\(.*\\)" $query) $query $query)) (mark-active (let (($st ...)) (if (string-match "\n" $st) (message "Multi line region is not allowed") (setq $query $st)))) ((setq $query (funcall helm-swoop-pre-input-function))) (t (setq $query ""))) (helm-swoop--recenter) (move-beginning-of-line 1) (helm-swoop--target-line-overlay-move) (let ((helm-display-function helm-swoop-split-window-function) (helm-display-source-at-screen-top nil) (helm-completion-window-scroll-margin 5)) (helm :sources (or $source (if (> helm-swoop-last-prefix-number 1) (helm-c-source-swoop-multiline helm-swoop-last-prefix-number) (helm-c-source-swoop))) :buffer helm-swoop-buffer :input $query :prompt helm-swoop-prompt :preselect (if (string-match "^[ \n ]*$" (helm-swoop--get-string-at-line)) (save-excursion (if ... ... ... ...)) (format "^%s " (line-number-at-pos))) :candidate-number-limit helm-swoop-candidate-number-limit))) (helm-swoop--restore)))
(let* (($query (car (cdr (memq (quote :$query) --cl-rest--)))) ($source (car (cdr (memq (quote :$source) --cl-rest--)))) ($multiline (car (cdr (or (memq (quote :$multiline) --cl-rest--) (list nil current-prefix-arg)))))) (let ((--cl-keys-- --cl-rest--)) (while --cl-keys-- (cond ((memq (car --cl-keys--) (quote (:$query :$source :$multiline :allow-other-keys))) (setq --cl-keys-- (cdr (cdr --cl-keys--)))) ((car (cdr (memq ... --cl-rest--))) (setq --cl-keys-- nil)) (t (error "Keyword argument %s not one of (:$query :$source :$multiline)" (car --cl-keys--)))))) (progn (setq helm-swoop-synchronizing-window (selected-window)) (setq helm-swoop-last-point (cons (point) (buffer-name (current-buffer)))) (setq helm-swoop-last-line-info (cons (current-buffer) (line-number-at-pos))) (if (boundp (quote helm-swoop-last-query)) nil (set (make-local-variable (quote helm-swoop-last-query)) "")) (setq helm-swoop-target-buffer (current-buffer)) (helm-swoop--set-prefix $multiline) (setq helm-swoop-line-overlay (make-overlay (point) (point))) (overlay-put helm-swoop-line-overlay (quote face) (if (< 1 helm-swoop-last-prefix-number) (quote helm-swoop-target-line-block-face) (quote helm-swoop-target-line-face))) (cond ((not (boundp (quote helm-swoop-cache))) (set (make-local-variable (quote helm-swoop-cache)) nil)) ((buffer-modified-p) (setq helm-swoop-cache nil))) (cond ((not (boundp (quote helm-swoop-list-cache))) (set (make-local-variable (quote helm-swoop-list-cache)) nil)) ((buffer-modified-p) (setq helm-swoop-list-cache nil))) (unwind-protect (progn (ad-enable-advice (quote helm-next-line) (quote around) (quote helm-swoop-next-line)) (ad-activate (quote helm-next-line)) (ad-enable-advice (quote helm-previous-line) (quote around) (quote helm-swoop-previous-line)) (ad-activate (quote helm-previous-line)) (ad-enable-advice (quote helm-move--next-line-fn) (quote around) (quote helm-multi-swoop-next-line-cycle)) (ad-activate (quote helm-move--next-line-fn)) (ad-enable-advice (quote helm-move--previous-line-fn) (quote around) (quote helm-multi-swoop-previous-line-cycle)) (ad-activate (quote helm-move--previous-line-fn)) (add-hook (quote helm-update-hook) (quote helm-swoop--pattern-match)) (add-hook (quote helm-after-update-hook) (quote helm-swoop--keep-nearest-position) t) (cond ($query (if (string-match "\\(\\^\\[0\\-9\\]\\+\\.\\)\\(.*\\)" $query) $query $query)) (mark-active (let (...) (if ... ... ...))) ((setq $query (funcall helm-swoop-pre-input-function))) (t (setq $query ""))) (helm-swoop--recenter) (move-beginning-of-line 1) (helm-swoop--target-line-overlay-move) (let ((helm-display-function helm-swoop-split-window-function) (helm-display-source-at-screen-top nil) (helm-completion-window-scroll-margin 5)) (helm :sources (or $source (if ... ... ...)) :buffer helm-swoop-buffer :input $query :prompt helm-swoop-prompt :preselect (if (string-match "^[ \n ]*$" ...) (save-excursion ...) (format "^%s " ...)) :candidate-number-limit helm-swoop-candidate-number-limit))) (helm-swoop--restore))))
helm-swoop()
call-interactively(helm-swoop nil nil)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment