* image-mode.el (image-mode): Add image-after-revert-hook to after-revert-hook.
[bpt/emacs.git] / lisp / ibuf-ext.el
index 257fe89..dcea1e5 100644 (file)
@@ -1,7 +1,7 @@
 ;;; ibuf-ext.el --- extensions for ibuffer
 
-;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
-;;   2008 Free Software Foundation, Inc.
+;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+;;   2009, 2010  Free Software Foundation, Inc.
 
 ;; Author: Colin Walters <walters@verbum.org>
 ;; Maintainer: John Paul Wallington <jpw@gnu.org>
@@ -91,11 +91,6 @@ regardless of any active filters in this buffer."
 (defvar ibuffer-tmp-show-regexps nil
   "A list of regexps which should match buffer names to always show.")
 
-(defvar ibuffer-auto-mode nil
-  "If non-nil, Ibuffer auto-mode should be enabled for this buffer.
-Do not set this variable directly!  Use the function
-`ibuffer-auto-mode' instead.")
-
 (defvar ibuffer-auto-buffers-changed nil)
 
 (defcustom ibuffer-saved-filters '(("gnus"
@@ -220,6 +215,16 @@ Currently, this only applies to `ibuffer-saved-filters' and
         (ibuffer-included-in-filters-p buf ibuffer-filtering-qualifiers)
         (ibuffer-buf-matches-predicates buf ibuffer-always-show-predicates)))))
 
+;;;###autoload
+(define-minor-mode ibuffer-auto-mode
+  "Toggle use of Ibuffer's auto-update facility.
+With numeric ARG, enable auto-update if and only if ARG is positive."
+  nil nil nil
+  (unless (derived-mode-p 'ibuffer-mode)
+    (error "This buffer is not in Ibuffer mode"))
+  (frame-or-buffer-changed-p 'ibuffer-auto-buffers-changed) ; Initialize state vector
+  (add-hook 'post-command-hook 'ibuffer-auto-update-changed))
+
 (defun ibuffer-auto-update-changed ()
   (when (frame-or-buffer-changed-p 'ibuffer-auto-buffers-changed)
     (dolist (buf (buffer-list))
@@ -229,20 +234,6 @@ Currently, this only applies to `ibuffer-saved-filters' and
                     (derived-mode-p 'ibuffer-mode))
            (ibuffer-update nil t)))))))
 
-;;;###autoload
-(defun ibuffer-auto-mode (&optional arg)
-  "Toggle use of Ibuffer's auto-update facility.
-With numeric ARG, enable auto-update if and only if ARG is positive."
-  (interactive)
-  (unless (derived-mode-p 'ibuffer-mode)
-    (error "This buffer is not in Ibuffer mode"))
-  (set (make-local-variable 'ibuffer-auto-mode)
-       (if arg
-          (plusp arg)
-        (not ibuffer-auto-mode)))
-  (frame-or-buffer-changed-p 'ibuffer-auto-buffers-changed) ; Initialize state vector
-  (add-hook 'post-command-hook 'ibuffer-auto-update-changed))
-
 ;;;###autoload
 (defun ibuffer-mouse-filter-by-mode (event)
   "Enable or disable filtering by the major mode chosen via mouse."
@@ -408,6 +399,24 @@ To evaluate a form without viewing the buffer, see `ibuffer-do-eval'."
    :modifier-p :maybe)
   (revert-buffer t t))
 
+;;;###autoload (autoload 'ibuffer-do-isearch "ibuf-ext")
+(define-ibuffer-op ibuffer-do-isearch ()
+  "Perform a `isearch-forward' in marked buffers."
+  (:interactive ()
+   :opstring "searched in"
+   :complex t
+   :modifier-p :maybe)
+  (multi-isearch-buffers (ibuffer-get-marked-buffers)))
+
+;;;###autoload (autoload 'ibuffer-do-isearch-regexp "ibuf-ext")
+(define-ibuffer-op ibuffer-do-isearch-regexp ()
+  "Perform a `isearch-forward-regexp' in marked buffers."
+  (:interactive ()
+   :opstring "searched regexp in"
+   :complex t
+   :modifier-p :maybe)
+  (multi-isearch-buffers-regexp (ibuffer-get-marked-buffers)))
+
 ;;;###autoload (autoload 'ibuffer-do-replace-regexp "ibuf-ext")
 (define-ibuffer-op replace-regexp (from-str to-str)
   "Perform a `replace-regexp' in marked buffers."
@@ -526,10 +535,11 @@ To evaluate a form without viewing the buffer, see `ibuffer-do-eval'."
       (dolist (filtergroup filter-group-alist)
        (let ((filterset (cdr filtergroup)))
          (multiple-value-bind (hip-crowd lamers)
-             (ibuffer-split-list (lambda (bufmark)
-                                   (ibuffer-included-in-filters-p (car bufmark)
-                                                                  filterset))
-                                 bmarklist)
+             (values-list
+              (ibuffer-split-list (lambda (bufmark)
+                                    (ibuffer-included-in-filters-p (car bufmark)
+                                                                   filterset))
+                                  bmarklist))
            (aset vec i hip-crowd)
            (incf i)
            (setq bmarklist lamers))))
@@ -1023,9 +1033,8 @@ currently used by buffers."
   "Toggle current view to buffers with filename matching QUALIFIER."
   (:description "filename"
    :reader (read-from-minibuffer "Filter by filename (regexp): "))
-  (ibuffer-awhen (with-current-buffer buf
-                  (ibuffer-buffer-file-name))
-                (string-match qualifier it)))
+  (ibuffer-awhen (buffer-local-value 'buffer-file-name buf)
+    (string-match qualifier it)))
 
 ;;;###autoload (autoload 'ibuffer-filter-by-size-gt  "ibuf-ext")
 (define-ibuffer-filter size-gt
@@ -1143,10 +1152,10 @@ Ordering is lexicographic."
   (string-lessp
    ;; FIXME: For now just compare the file name and the process name
    ;; (if it exists).  Is there a better way to do this?
-   (or (buffer-file-name (car a)) 
+   (or (buffer-file-name (car a))
        (let ((pr-a (get-buffer-process (car a))))
         (and (processp pr-a) (process-name pr-a))))
-   (or (buffer-file-name (car b)) 
+   (or (buffer-file-name (car b))
        (let ((pr-b (get-buffer-process (car b))))
         (and (processp pr-b) (process-name pr-b))))))
 
@@ -1298,15 +1307,68 @@ a prefix argument reverses the meaning of that variable."
          (error "No buffer with name %s" name)
        (goto-char buf-point)))))
 
+(declare-function diff-sentinel "diff" (code))
+
+(defun ibuffer-diff-buffer-with-file-1 (buffer)
+  (let ((bufferfile (buffer-local-value 'buffer-file-name buffer))
+       (tempfile (make-temp-file "buffer-content-")))
+    (when bufferfile
+      (unwind-protect
+         (progn
+           (with-current-buffer buffer
+             (write-region nil nil tempfile nil 'nomessage))
+           (let* ((old (expand-file-name bufferfile))
+                  (new (expand-file-name tempfile))
+                  (oldtmp (file-local-copy old))
+                  (newtmp (file-local-copy new))
+                  (switches diff-switches)
+                  (command
+                   (mapconcat
+                    'identity
+                    `(,diff-command
+                      ;; Use explicitly specified switches
+                      ,@(if (listp switches) switches (list switches))
+                      ,@(if (or old new)
+                            (list "-L" (shell-quote-argument old)
+                                  "-L" (shell-quote-argument
+                                        (format "Buffer %s" (buffer-name buffer)))))
+                      ,(shell-quote-argument (or oldtmp old))
+                      ,(shell-quote-argument (or newtmp new)))
+                    " "))
+                  proc)
+             (let ((inhibit-read-only t))
+               (insert command "\n")
+               (diff-sentinel
+                (call-process shell-file-name nil
+                              (current-buffer) nil
+                              shell-command-switch command)))
+             (insert "\n"))))
+      (sit-for 0)
+      (when (file-exists-p tempfile)
+       (delete-file tempfile)))))
+
 ;;;###autoload
 (defun ibuffer-diff-with-file ()
-  "View the differences between this buffer and its associated file.
+  "View the differences between marked buffers and their associated files.
+If no buffers are marked, use buffer at point.
 This requires the external program \"diff\" to be in your `exec-path'."
   (interactive)
-  (let ((buf (ibuffer-current-buffer)))
-    (unless (buffer-live-p buf)
-      (error "Buffer %s has been killed" buf))
-    (diff-buffer-with-file buf)))
+  (require 'diff)
+  (let ((marked-bufs (ibuffer-get-marked-buffers)))
+    (when (null marked-bufs)
+      (setq marked-bufs (list (ibuffer-current-buffer t))))
+    (with-current-buffer (get-buffer-create "*Ibuffer Diff*")
+      (setq buffer-read-only nil)
+      (buffer-disable-undo (current-buffer))
+      (erase-buffer)
+      (buffer-enable-undo (current-buffer))
+      (diff-mode)
+      (dolist (buf marked-bufs)
+       (unless (buffer-live-p buf)
+         (error "Buffer %s has been killed" buf))
+       (ibuffer-diff-buffer-with-file-1 buf))
+      (setq buffer-read-only t)))
+  (switch-to-buffer "*Ibuffer Diff*"))
 
 ;;;###autoload
 (defun ibuffer-copy-filename-as-kill (&optional arg)
@@ -1361,7 +1423,8 @@ You can then feed the file name(s) to other commands with \\[yank]."
          nil
          group)))
     (ibuffer-redisplay t)
-    (message "Marked %s buffers" count)))
+    (unless (eq ibuffer-mark-on-buffer-mark ?\s)
+      (message "Marked %s buffers" count))))
 
 ;;;###autoload
 (defun ibuffer-mark-by-name-regexp (regexp)
@@ -1414,8 +1477,7 @@ You can then feed the file name(s) to other commands with \\[yank]."
                                      ""))))))
   (ibuffer-mark-on-buffer
    #'(lambda (buf)
-       (with-current-buffer buf
-        (eq major-mode mode)))))
+       (eq (buffer-local-value 'major-mode buf) mode))))
 
 ;;;###autoload
 (defun ibuffer-mark-modified-buffers ()
@@ -1527,5 +1589,9 @@ defaults to one."
 
 (provide 'ibuf-ext)
 
+;; Local Variables:
+;; generated-autoload-file: "ibuffer.el"
+;; End:
+
 ;; arch-tag: 9af21953-deda-4c30-b76d-f81d9128e76d
 ;;; ibuf-ext.el ends here