update
[emacs-init.git] / setup / magit.el
1 (add-to-list 'load-path (concat (file-name-directory
2                                  (directory-file-name
3                                   (file-name-directory
4                                    (or load-file-name
5                                        (when (boundp 'bytecomp-filename) bytecomp-filename)
6                                        buffer-file-name))))
7                                 "magit/lisp"))
8
9 (add-to-list 'load-path (concat (file-name-directory
10                                  (directory-file-name
11                                   (file-name-directory
12                                    (or load-file-name
13                                        (when (boundp 'bytecomp-filename) bytecomp-filename)
14                                        buffer-file-name))))
15                                 "with-editor"))
16
17 (add-to-list 'load-path (concat (file-name-directory
18                                  (directory-file-name
19                                   (file-name-directory
20                                    (or load-file-name
21                                        (when (boundp 'bytecomp-filename) bytecomp-filename)
22                                        buffer-file-name))))
23                                 "auto-install"))
24
25 (require 'cl)
26
27 (if (not (functionp 'run-hook-wrapped))
28     (defun run-hook-wrapped (hook wrap-function &rest args)
29       (loop for fn in hook
30             thereis (apply 'wrap-function fn args))))
31
32 (if (not (functionp 'process-live-p))
33     (defun process-live-p (process)
34       (memq (process-status process)
35             '(run open listen connect stop))))
36
37 (require 'magit)
38
39 ;; Add additional %-escapes ...
40 (defun magit-insert-branch-1
41     (section branch format current branches face
42              &optional hash message upstream ahead behind gone)
43   "For internal use, don't add to a hook."
44   (let* ((head  (or (car magit-refresh-args) current "HEAD"))
45          (count (and branch
46                      (magit-refs-format-commit-count branch head format)))
47          (mark  (cond ((or (equal branch head)
48                            (and (not branch) (equal head "HEAD")))
49                        (if (equal branch current)
50                            (propertize "@" 'face 'magit-head)
51                          (propertize "#" 'face 'magit-tag)))
52                       ((equal branch current)
53                        (propertize "." 'face 'magit-head)))))
54     (when upstream
55       (setq upstream (propertize upstream 'face
56                                  (if (member upstream branches)
57                                      'magit-branch-local
58                                    'magit-branch-remote))))
59     (magit-insert-heading
60       (format-spec
61        format
62        `((?a . ,(or ahead ""))
63          (?b . ,(or behind ""))
64          (?c . ,(or mark count ""))
65          (?C . ,(or mark " "))
66          (?h . ,(or (propertize hash 'face 'magit-hash) ""))
67          (?m . ,(or message ""))
68          (?n . ,(propertize (or branch "(detached)") 'face face))
69          (?u . ,(or upstream ""))
70          (?U . ,(if upstream (format (propertize " [%s]" 'face 'magit-dimmed)  upstream) ""))
71          (?d . ,(if upstream
72                   (let ((msg (cond
73                               (gone
74                                (concat (propertize gone 'face 'error)))
75                               ((or ahead behind)
76                                (concat (and ahead (format "ahead %s" ahead))
77                                        (and ahead behind ", ")
78                                        (and behind (format "behind %s" behind))))
79                               (t nil))))
80                     (if msg
81                       (format (propertize "[%s] " 'face 'magit-dimmed) msg)
82                       ""))
83                   ""))
84          (?D . ,(if upstream
85                     (format (propertize "[%s%s] " 'face 'magit-dimmed)
86                             upstream
87                             (cond
88                              (gone
89                               (concat ": " (propertize gone 'face 'error)))
90                              ((or ahead behind)
91                               (concat ": "
92                                       (and ahead (format "ahead %s" ahead))
93                                       (and ahead behind ", ")
94                                       (and behind (format "behind %s" behind))))
95                              (t "")))
96                   "")))))
97     (when magit-show-margin
98       (magit-refs-format-margin branch))
99     (magit-refs-insert-cherry-commits head branch section)))
100
101 (setq magit-refs-local-branch-format "%C %-48n %-1.1u %d%m")
102 (setq magit-refs-remote-branch-format "%C %-48n   %m")
103
104 (when (eq system-type 'windows-nt)
105
106   (require 'advice)
107
108   (setf (symbol-function 'builtin-process-file) (symbol-function 'process-file))
109
110   (defvar my-magit-shell "c:\\Program Files (x86)\\Git\\bin\\sh")
111
112   (defun my-magit-process-file (program &optional infile buffer display &rest args)
113     (builtin-process-file my-magit-shell infile buffer display
114                           "-c" (mapconcat 'shell-quote-argument (cons "/bin/git" args) " ")))
115
116   (defadvice magit-cmd-output (around my-magit-process-file activate)
117     (letf (((symbol-function 'process-file) (symbol-function 'my-magit-process-file)))
118       ad-do-it))
119
120   (defadvice magit-git-exit-code (around my-magit-process-file activate)
121     (letf (((symbol-function 'process-file) (symbol-function 'my-magit-process-file)))
122       ad-do-it))
123
124   (defadvice magit-run (around activate)
125     (letf (((symbol-function 'process-file) (symbol-function 'my-magit-process-file)))
126       ad-do-it))
127
128 ); End Windows-NT
129
130 (defadvice magit-mode-quit-window (around my-magit-mode-quit-window activate)
131   (letf (((symbol-function 'selected-window) (lambda ())))
132     ad-do-it))
133
134 (global-set-key "\C-cGS" 'magit-status)
135 (global-set-key "\C-cGW" 'magit-file-popup)
136
137 (defun my-shell-command-to-string (cmd)
138   (shell-command cmd " *my-shell-command-to-string*")
139   (save-current-buffer
140     (set-buffer " *my-shell-command-to-string*")
141     (prog1
142         (buffer-string)
143       (kill-buffer " *my-shell-command-to-string*"))))
144
145 (defun git-repo-files ()
146   (let ((default-directory (magit-toplevel default-directory)))
147     (split-string (my-shell-command-to-string "git ls-files") "\n")))
148
149 (defun find-file-in-git-repo ()
150   (interactive)
151   (let ((repo (magit-toplevel default-directory))
152         (files (git-repo-files)))
153     (find-file
154      (concat repo
155              (ido-completing-read
156               "Find file in git repo: "
157               (remove-if (lambda (x) (string= "" x))
158               files))))))
159
160 (defun grep-in-git-repo (regexp &optional words-only)
161   (interactive "sGrep files in Git repo regexp: \nP")
162   (let ((default-directory (magit-toplevel default-directory)))
163     (if (not default-directory)
164         (error "not a Git directory"))
165     (grep (format "git ls-files -z | xargs -r0 grep -d skip -nH -E%s -- %s"
166                   (if words-only " -w" "") (shell-quote-argument regexp)))))
167
168 (setenv "GIT_PAGER" "cat")
169 (setenv "GIT_MAN_VIEWER" "woman")
170 (setenv "GIT_EDITOR" "emacsclient")
171
172 (defun find-file-maybe-git (&optional nogit)
173   (interactive "P")
174   (if (and (not nogit) (magit-toplevel default-directory))
175       (call-interactively 'find-file-in-git-repo)
176     (call-interactively 'ido-find-file)))
177
178 (global-set-key "\C-x\C-f" 'find-file-maybe-git)
179 (global-set-key "\C-cGG" 'grep-in-git-repo)
180
181 (defun git-files-find-symbol (symbol)
182   (interactive (list (read-string "Symbol: " (current-word))))
183   (let ((dir (magit-toplevel default-directory)))
184     (if (not dir) (error "No git repository"))
185     (let ((default-directory dir))
186       (grep (format "git ls-files -z | xargs -r0 grep -d skip -nwHF %s" symbol)))))
187
188 (defun git-files-find-class-decl (symbol)
189   (interactive (list (read-string "Symbol: " (current-word))))
190   (let ((dir (magit-toplevel default-directory)))
191     (if (not dir) (error "No git repository"))
192     (let ((default-directory dir))
193       (grep (format (concat "git ls-files -z"
194                             " | xargs -r0 grep -d skip -nwHF %s"
195                             " | grep -Ew '(class|struct|typedef|using)'"
196                             " | grep -vEw 'friend'")
197                     symbol)))))
198
199 (global-set-key "\C-cGF" 'git-files-find-symbol)
200 (global-set-key "\C-cGC" 'git-files-find-class-decl)
201
202 (defun dired-git-files ()
203   (interactive)
204   (let ((default-directory (magit-toplevel default-directory))\
205         (ls-lisp-use-insert-directory-program t)
206         files)
207     (setq files (delete-if '(lambda (file) (string= file ""))
208                            (split-string (shell-command-to-string "git ls-files") "\n")))
209     (dired (cons default-directory files))))
210
211 (global-set-key "\C-cGD" 'dired-git-files)
212
213 (defun dired-grep-git-files (regexp &optional words-only)
214   (interactive "sRegexp: \nP")
215   (let ((default-directory (magit-toplevel default-directory))
216         (cmd (format "git ls-files -z | xargs -r0 grep -d skip -l -E%s -- %s"
217                      (if words-only " -w" "") (shell-quote-argument regexp))))
218     (if (not default-directory)
219         (error "not in Git repository"))
220     (setq files (delete-if '(lambda (file) (string= file ""))
221                            (split-string (shell-command-to-string cmd)  "\n")))
222     (dired (cons default-directory files))))
223
224 (global-set-key "\C-cGH" 'dired-grep-git-files)
225
226 (defun magit-svn-fetch ()
227   (interactive)
228   (magit-run-git-async "svn" "fetch"))
229
230 (define-key magit-mode-map "Nf" 'magit-svn-fetch)
231
232 (defun magit-quit-window (&optional kill-buffer)
233   (interactive "P")
234   (quit-window kill-buffer))
235
236 (defun magit-diff-master-mergebase (&optional args files)
237   (interactive (magit-diff-arguments))
238   (magit-diff-working-tree
239    (magit-git-string "merge-base" "master" "HEAD") args files))
240
241 (magit-define-popup-action 'magit-diff-popup
242   ?m "Diff merge-base master" 'magit-diff-master-mergebase)
243
244 (magit-define-popup-switch 'magit-log-popup
245   ?f "first parent" "--first-parent")
246
247 (defun magit-reset-to-upstream ()
248   (interactive)
249   (magit-run-git "reset" "--hard" "@{u}"))
250
251 (magit-define-popup-action 'magit-pull-popup
252   ?X "HARD Reset to upstream (force pull after remote rebase)" 'magit-reset-to-upstream)
253
254 (require 'ffap)
255
256 (defun g0dil-magit-old-version-jump-to-current ()
257   (interactive)
258   (let ((current-file (ffap-file-exists-string
259                        (file-name-nondirectory
260                         (replace-regexp-in-string "\\.~.*$" "" (buffer-name))))))
261     (if current-file
262         (g0dil-goto-equivalent-position current-file)
263       (error "current version of file not found"))))
264
265 (define-key magit-blob-mode-map "c" 'g0dil-magit-old-version-jump-to-current)
266
267 (defun g0dil-magit-diff-jump-to-current ()
268   (interactive)
269   (let ((section-file-name (loop for ident in (magit-section-ident (magit-current-section))
270                                  if (and (consp ident) (eq (car ident) 'file))
271                                  return (cdr ident)
272                                  finally return nil)))
273     (if (ffap-file-exists-string section-file-name)
274         (g0dil-goto-equivalent-position section-file-name)
275       (error "current version of file not found"))))
276
277 (define-key magit-revision-mode-map (kbd "C-c RET") 'g0dil-magit-diff-jump-to-current)
278
279 ; ignore whitespace
280 ; (setq magit-diff-options '("-w"))