More git files
authorJoerg Jaspert <joerg@debian.org>
Sun, 11 May 2014 12:08:53 +0000 (14:08 +0200)
committerJoerg Jaspert <joerg@debian.org>
Sun, 11 May 2014 12:08:53 +0000 (14:08 +0200)
.emacs.d/elisp/local/magit-filenotify.el [new file with mode: 0644]
.emacs.d/elisp/local/magit-find-file.el [new file with mode: 0644]
.emacs.d/elisp/local/magit-simple-keys.el [new file with mode: 0644]
.emacs.d/elisp/mo-git-blame/mo-git-blame.el

diff --git a/.emacs.d/elisp/local/magit-filenotify.el b/.emacs.d/elisp/local/magit-filenotify.el
new file mode 100644 (file)
index 0000000..c3976cd
--- /dev/null
@@ -0,0 +1,155 @@
+;;; magit-filenotify.el --- Refresh status buffer when git tree changes -*- lexical-binding: t -*-
+;; Version: 20140409.559
+
+;; Copyright (C) 2013 RĂ¼diger Sonderfeld
+
+;; Author: RĂ¼diger Sonderfeld <ruediger@c-plusplus.de>
+;; Created: 17 Jul 2013
+;; Keywords: tools
+;; Package-Requires: ((magit "1.3.0"))
+
+;; This file is NOT part of GNU Emacs.
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This module comes with a minor mode `magit-filenotify' which tracks
+;; changes in the source tree using `file-notify' and refreshes the magit
+;; status buffer.  Emacs 24.4 with `file-notify-support' is required for it to
+;; work.
+
+;;; Code:
+
+(require 'magit)
+(require 'cl-lib)
+(require 'filenotify)
+
+(defgroup magit-filenotify nil
+  "Refresh status buffer if source tree changes"
+  :prefix "magit-filenotify"
+  :group 'magit)
+
+(defcustom magit-filenotify-ignored '("\\`\\.#"
+                                   "\\`flycheck_")
+  "A list of regexp for filenames that will be ignored by the callback."
+  :group 'magit-filenotify
+  :type '(repeat regexp))
+
+(defun magit-filenotify--directories ()
+  "List all directories containing files watched by git."
+  ;; TODO: add .git directory?
+  (cons
+   default-directory
+   (cl-remove-duplicates
+    (cl-loop for file in (magit-git-lines "ls-files")
+             for tmp = (file-name-directory file)
+             when tmp
+             collect (expand-file-name tmp))
+    :test #'string=)))
+
+(defvar magit-filenotify-data (make-hash-table)
+  "A hash table to map watch-descriptors to a list (DIRECTORY STATUS-BUFFER).")
+
+(defun magit-filenotify--callback (ev)
+  "Handle file-notify callbacks.
+Argument EV contains the watch data."
+  (unless
+      (let ((file (car (last ev))) res)
+        (dolist (rx magit-filenotify-ignored res)
+          (when (string-match rx (file-name-nondirectory file))
+            (setq res t))))
+    (let* ((wd (car ev))
+           (data (gethash wd magit-filenotify-data))
+           (buffer (cadr data)))
+      (if (buffer-live-p buffer)
+          (with-current-buffer buffer
+            (magit-refresh))
+        (file-notify-rm-watch wd)
+        (remhash wd magit-filenotify-data)))))
+
+(defun magit-filenotify-start ()
+  "Start watching for changes to the source tree using filenotify.
+This can only be called from a magit status buffer."
+  (unless (derived-mode-p 'magit-status-mode)
+    (error "Only works in magit status buffer"))
+  (dolist (dir (magit-filenotify--directories))
+    (puthash (file-notify-add-watch dir
+                                '(change attribute-change)
+                                #'magit-filenotify--callback)
+             (list dir (current-buffer))
+             magit-filenotify-data)))
+
+(defun magit-filenotify-stop ()
+  "Stop watching for changes to the source tree using filenotify.
+This can only be called from a magit status buffer."
+  (unless (derived-mode-p 'magit-status-mode)
+    (error "Only works in magit status buffer"))
+  (maphash
+   (lambda (k v)
+     (when (equal (cadr v) (current-buffer)) ; or use buffer?
+       (file-notify-rm-watch k)
+       (remhash k magit-filenotify-data)))
+   magit-filenotify-data))
+
+(defun magit-filenotify-watching-p ()
+  "Return non-nil if current source tree is watched."
+  (unless (derived-mode-p 'magit-status-mode)
+    (error "Only works in magit status buffer"))
+  (let (ret)
+    (maphash (lambda (_k v)
+               (when (and (not ret)
+                          (equal (cadr v) (current-buffer)))
+                 (setq ret t)))
+             magit-filenotify-data)
+    ret))
+
+(defcustom magit-filenotify-lighter " MagitFilenotify"
+  "String to display in mode line when `magit-filenotify-mode' is active."
+  :group 'magit-filenotify
+  :type 'string)
+
+;;;###autoload
+(define-minor-mode magit-filenotify-mode
+  "Refresh status buffer if source tree changes."
+  :lighter magit-filenotify-lighter
+  :group 'magit-filenotify
+  (if magit-filenotify-mode
+      (magit-filenotify-start)
+    (magit-filenotify-stop)))
+
+(defun magit-filenotify-stop-all ()
+  "Stop watching for changes in all git trees."
+  (interactive)
+  (maphash
+   (lambda (k _v) (file-notify-rm-watch k))
+   magit-filenotify-data)
+  (clrhash magit-filenotify-data))
+
+;;; Loading
+(easy-menu-add-item magit-mode-menu nil
+                    ["Auto Refresh" magit-filenotify-mode
+                     :style toggle
+                     :selected (magit-filenotify-watching-p)
+                     :help "Refresh magit status buffer when source tree updates"]
+                    "Refresh")
+
+(defun magit-filenotify-unload-function ()
+  "Cleanup when module is unloaded."
+  (magit-filenotify-stop-all)
+  (easy-menu-remove-item magit-mode-menu nil "Auto Refresh"))
+
+(provide 'magit-filenotify)
+
+;;; magit-filenotify.el ends here
diff --git a/.emacs.d/elisp/local/magit-find-file.el b/.emacs.d/elisp/local/magit-find-file.el
new file mode 100644 (file)
index 0000000..8058a6c
--- /dev/null
@@ -0,0 +1,90 @@
+;;; magit-find-file.el --- completing-read over all files in Git
+
+;; Copyright (C) 2013 Bradley Wright
+
+;; Author: Bradley Wright <brad@intranation.com>
+;; Keywords: git
+;; URL: https://github.com/bradleywright/magit-find-file.el
+;; Version: 20130915.423
+;; X-Original-Version: 1.0.4
+;; Package-Requires: ((magit "1.2.0"))
+
+;; This file is not part of GNU Emacs.
+
+;; This file is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This file is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this file.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This is a Git-powered replacement for something like TextMate's
+;; Cmd-t.
+
+;; Uses a configurable completing-read to open any file in the
+;; Git repository of the current buffer.
+
+;; Usage:
+;;
+;;     (require 'magit-find-file) ;; if not using the ELPA package
+;;     (global-set-key (kbd "C-c p") 'magit-find-file-completing-read)
+;;
+;; Customize 'magit-completing-read-function to change the completing
+;; read engine used (so it should behave like Magit does for you).
+;;
+;; Customize 'magit-find-file-skip-images to include images in your
+;; candidate list. This is t by default.
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(require 'magit)
+
+(defgroup magit-find-file nil
+  "Use Magit to completing-read over files"
+  :prefix "magit-find-file-"
+  :group 'tools)
+
+(defcustom magit-find-file-skip-images t
+  "Skip images in completing-read candidate list."
+  :group 'magit-find-file
+  :type 'boolean)
+
+(defun magit-find-file-is-image (name)
+  "Identifies images by extension."
+  (if magit-find-file-skip-images
+      (member (file-name-extension name) '("jpg" "png" "gif" "jpeg"))
+    nil))
+
+;;;###autoload
+(defun magit-find-file-completing-read ()
+  "Uses a completing read to open a file from git ls-files"
+  (interactive)
+  (let ((default-directory (magit-get-top-dir)))
+    (if default-directory
+        (find-file
+         (magit-completing-read
+          (format "Find file: %s" (abbreviate-file-name default-directory))
+          (remove-if 'magit-find-file-is-image (magit-git-lines "ls-files" "--exclude-standard" "-co"))))
+      (error "Not a git repository."))))
+
+(provide 'magit-find-file)
+
+;; Local Variables:
+;; coding: utf-8
+;; indent-tabs-mode: nil
+;; mangle-whitespace: t
+;; require-final-newline: t
+;; checkdoc-minor-mode: t
+;; byte-compile-warnings: (not cl-functions) (not magit-get-top-dir)
+;; End:
+
+;;; magit-find-file.el ends here
diff --git a/.emacs.d/elisp/local/magit-simple-keys.el b/.emacs.d/elisp/local/magit-simple-keys.el
new file mode 100644 (file)
index 0000000..cd7690d
--- /dev/null
@@ -0,0 +1,59 @@
+;;; magit-simple-keys.el --- simple keybindings for Magit
+
+;; Copyright (C) 2011 Ramkumar Ramachandra
+;; Version: 1.0.0
+;; Adapted-by: Phil Hagelberg
+;; Package-Requires: ((magit "1.0.0"))
+;;
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This plug-in overrides the keybindings in magit-key-mode with
+;; simpler keybindings; it does this by picking the most obviously
+;; used command in each key group
+
+;;; Code:
+
+(require 'magit)
+
+(defvar magit-key-mode-mapping
+  '((logging magit-display-log)
+    (running magit-shell-command)
+    (fetching magit-fetch-current)
+    (pushing magit-push)
+    (pulling magit-pull)
+    (branching magit-checkout)
+    (tagging magit-tag)
+    (stashing magit-stash)
+    (merging magit-merge)
+    (submodule magit-submodule-update)))
+
+(defun magit-key-mode-generate (term mapping-function)
+  "Generate alias for the key-group term"
+  (eval
+   `(defalias ',(intern (concat "magit-key-mode-popup-" (symbol-name term)))
+       mapping-function)))
+
+;; generate the aliases using the mapping in key-mode-mapping
+(mapc (lambda (g)
+        (magit-key-mode-generate (car g) (cadr g)))
+      magit-key-mode-mapping)
+
+;;;###autoload
+(eval-after-load 'magit
+  '(require 'magit-simple-keys))
+
+(provide 'magit-simple-keys)
+;;; magit-simple-keys.el ends here
index 750eed8..fa9d0d7 100644 (file)
@@ -5,7 +5,8 @@
 
 ;; Author: Moritz Bunkus <moritz@bunkus.org>
 ;; Maintainer: Moritz Bunkus <moritz@bunkus.org>
-;; Version: 0.1.0
+;; Version: 20140409.320
+;; X-Original-Version: 0.1.0
 ;; Keywords: tools
 
 ;; mo-git-blame is free software; you can redistribute it and/or
@@ -87,7 +88,7 @@ interactive use, e.g. the file name, current revision etc.")
   "MoGitBlame menu"
   '("MoGitBlame"
     ["Re-blame for revision at point" mo-git-blame-reblame-for-revision-at t]
-    ["Re-blame for ancestor of revision at point" mo-git-blame-reblame-for-ancestor-of-revision-at-point t]
+    ["Re-blame for ancestor of revision at point" mo-git-blame-reblame-for-ancestor-of-revision-at t]
     ["Raw content for revision at point" mo-git-blame-content-for-revision-at t]
     ["Log for revision at point" mo-git-blame-log-for-revision-at t]
     ["Overwrite file with revision at point" mo-git-blame-overwrite-file-with-revision-at t]
@@ -116,6 +117,12 @@ interactive use, e.g. the file name, current revision etc.")
   :group 'mo-git-blame
   :type 'string)
 
+(defcustom mo-git-blame-git-blame-args ""
+  "Additional arguments to pass to git blame."
+  :group 'mo-git-blame
+  :type 'string)
+
+
 (defcustom mo-git-blame-incremental t
   "Runs `git blame' in the background with the --incremental
 option if this variable is non-nil."
@@ -140,6 +147,17 @@ option if this variable is non-nil."
                  (const :tag "If available" if-available)
                  (const :tag "Never" never)))
 
+(defcustom mo-git-blame-use-magit 'if-available
+  "Controls whether or not magit will be used. Possible choices:
+
+  `never'        -- do not use magit even if it is loaded
+  `if-available' -- use magit if it has been loaded before
+  `always'       -- automatically load magit and use it"
+  :group 'mo-git-blame
+  :type '(choice (const :tag "Always" always)
+                 (const :tag "If available" if-available)
+                 (const :tag "Never" never)))
+
 ;; This function was taken from magit (called 'magit-trim-line' there).
 (defun mo-git-blame-trim-line (str)
   (cond ((string= str "")
@@ -162,17 +180,14 @@ option if this variable is non-nil."
   (mo-git-blame-trim-line (mo-git-blame-git-output args)))
 
 (defun mo-git-blame-get-top-dir (cwd)
-  (let ((cwd (expand-file-name cwd))
-        git-dir)
-    (setq git-dir
-          (or (getenv "GIT_WORK_TREE")
-              (if (file-directory-p cwd)
-                  (let* ((default-directory cwd)
-                         (dir (mo-git-blame-git-string "rev-parse" "--git-dir"))
-                         (dir (concat (or (file-remote-p cwd) "") dir))
-                         (dir (if dir (file-name-directory (expand-file-name dir)) "")))
-                    (if (and dir (file-directory-p dir))
-                        (file-name-as-directory dir))))))
+  (let* ((cwd (expand-file-name cwd))
+         (git-dir (or (getenv "GIT_WORK_TREE")
+                      (if (file-directory-p cwd)
+                          (let* ((default-directory cwd)
+                                 (dir (mo-git-blame-git-string "rev-parse" "--show-toplevel"))
+                                 (dir (concat (or (file-remote-p cwd) "") dir)))
+                            (if (and dir (file-directory-p dir))
+                                (file-name-as-directory dir)))))))
     (or git-dir
         (error "No Git repository found"))))
 
@@ -352,13 +367,29 @@ git is already/still running."
   (interactive)
   (mo-git-blame-log-for-revision (plist-get mo-git-blame-vars :current-revision)))
 
+(defun mo-git-blame-show-revision--diff-mode (revision)
+  "Internal function that fills the current buffer with revision using diff-mode"
+  (erase-buffer)
+  (mo-git-blame-run "show" revision)
+  (goto-char (point-min))
+  (diff-mode))
+
+(defun mo-git-blame-show-revision--magit (revision)
+  "Internal function that fills the current buffer with revision using magit"
+  (let ((magit-commit-buffer-name (buffer-name)))
+    (magit-show-commit revision)))
+
 (defun mo-git-blame-show-revision (revision)
-  (let ((buffer (mo-git-blame-get-output-buffer)))
+  (let ((buffer (mo-git-blame-get-output-buffer))
+        (the-func (cond ((eq mo-git-blame-use-magit 'always)
+                         (require 'magit)
+                         'mo-git-blame-show-revision--magit)
+                        ((and (eq mo-git-blame-use-magit 'if-available)
+                              (functionp 'magit-show-commit))
+                         'mo-git-blame-show-revision--magit)
+                        (t 'mo-git-blame-show-revision--diff-mode))))
     (with-current-buffer buffer
-      (erase-buffer)
-      (mo-git-blame-run "show" revision)
-      (goto-char (point-min))
-      (diff-mode))
+      (funcall the-func revision))
     (display-buffer buffer)))
 
 (defun mo-git-blame-show-revision-at ()
@@ -512,6 +543,11 @@ from elisp.
         truncate-lines t)
   (use-local-map mo-git-blame-mode-map))
 
+(defun mo-git-blame--make-args (args)
+  (delete ""
+          (append (list mo-git-blame-git-blame-args)
+                  args)))
+
 (defun mo-git-blame-run-blame-normally (start-line lines-to-blame)
   (let* ((num-content-lines (mo-git-blame-number-of-content-lines))
          (num-lines-to-append (if (and start-line
@@ -527,7 +563,7 @@ from elisp.
     (if start-line
         (setq args (append (list "-L" (format "%d,+%d" start-line lines-to-blame))
                            args)))
-    (apply 'mo-git-blame-run "blame" args)
+    (apply 'mo-git-blame-run "blame" (mo-git-blame--make-args args))
 
     (if num-lines-to-append
         (dotimes (i num-lines-to-append)
@@ -544,7 +580,7 @@ from elisp.
         (setq args (append (list "-L" (format "%d,+%d" start-line lines-to-blame))
                            args)))
     (mo-git-blame-assert-not-running)
-    (apply 'mo-git-blame-run* "blame" args)))
+    (apply 'mo-git-blame-run* "blame" (mo-git-blame--make-args args))))
 
 (defun mo-git-blame-init-blame-buffer (start-line lines-to-blame)
   (if mo-git-blame-incremental
@@ -757,7 +793,15 @@ blamed."
   (interactive)
   (if (null (buffer-file-name))
       (error "The current buffer is not associated with a file."))
-  (mo-git-blame-file (buffer-file-name)))
+  (mo-git-blame-file (file-truename (buffer-file-name))))
+
+;;;###autoload
+(defun mo-git-blame-current-for-revision (revision)
+  "Calls `mo-git-blame-file' for `revision' for the current buffer."
+  (interactive "sRevision: ")
+  (if (null (buffer-file-name))
+      (error "The current buffer is not associated with a file."))
+  (mo-git-blame-file (file-truename (buffer-file-name)) revision))
 
 (provide 'mo-git-blame)