;;; iswitchb.el --- switch between buffers using substrings
-;; Copyright (C) 1996, 1997, 2000, 2001, 2003 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004,
+;; 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
;; Author: Stephen Eglen <stephen@gnu.org>
;; Maintainer: Stephen Eglen <stephen@gnu.org>
;; Keywords: completion convenience
-;; location: http://www.anc.ed.ac.uk/~stephen/emacs/
;; This file is part of GNU Emacs.
;; GNU Emacs 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 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
;;; Commentary:
;; Font-Lock
-;; If you have font-lock loaded, the first matching buffer is
-;; highlighted. To switch this off, set (setq iswitchb-use-fonts nil)
-;; I don't use font-lock that much, so I've hardcoded the faces. If
-;; this is too harsh, let me know. Colouring of the matching buffer
-;; name was suggested by Carsten Dominik (dominik@strw.leidenuniv.nl)
+;; font-lock is used to highlight the first matching buffer. To
+;; switch this off, set (setq iswitchb-use-faces nil). Colouring of
+;; the matching buffer name was suggested by Carsten Dominik
+;; (dominik@strw.leidenuniv.nl)
;; Replacement for read-buffer
;; Regexp matching
-;; There is limited provision for regexp matching within iswitchb,
-;; enabled through `iswitchb-regexp'. This allows you to type `c$'
-;; for example and see all buffer names ending in `c'. This facility
-;; is quite limited though in two respects. First, you can't
-;; currently type in expressions like `[0-9]' directly -- you have to
-;; type them in when iswitchb-regexp is nil and then toggle on the
-;; regexp functionality. Likewise, don't enter an expression
-;; containing `\' in regexp mode. If you try, iswitchb gets confused,
-;; so just hit C-g and try again. Secondly, no completion mechanism
-;; is currently offered when regexp searching.
+;; There is provision for regexp matching within iswitchb, enabled
+;; through `iswitchb-regexp'. This allows you to type `c$' for
+;; example and see all buffer names ending in `c'. No completion
+;; mechanism is currently offered when regexp searching.
;;; TODO
(fboundp 'last)))
(require 'cl))
-;; Set up the custom library.
-;; taken from http://www.dina.kvl.dk/~abraham/custom/
-(eval-and-compile
- (condition-case ()
- (require 'custom)
- (error nil))
- (if (and (featurep 'custom) (fboundp 'custom-declare-variable))
- nil ;; We've got what we needed
- ;; We have the old custom-library, hack around it!
- (defmacro defgroup (&rest args)
- nil)
- (defmacro defcustom (var value doc &rest args)
- `(defvar ,var ,value ,doc))))
+(require 'font-lock)
;;; User Variables
;;
example functions that filter buffernames."
:type '(repeat (choice regexp function))
:group 'iswitchb)
+(put 'iswitchb-buffer-ignore 'risky-local-variable t)
(defcustom iswitchb-max-to-show nil
"*If non-nil, limit the number of names shown in the minibuffer.
:type 'hook
:group 'iswitchb)
-;;; Examples for setting the value of iswitchb-buffer-ignore
-;(defun iswitchb-ignore-c-mode (name)
-; "Ignore all c mode buffers -- example function for iswitchb."
-; (save-excursion
-; (set-buffer name)
-; (string-match "^C$" mode-name)))
+;; Examples for setting the value of iswitchb-buffer-ignore
+;;(defun iswitchb-ignore-c-mode (name)
+;; "Ignore all c mode buffers -- example function for iswitchb."
+;; (with-current-buffer name
+;; (derived-mode-p 'c-mode)))
-;(setq iswitchb-buffer-ignore '("^ " iswitchb-ignore-c-mode))
-;(setq iswitchb-buffer-ignore '("^ " "\\.c$" "\\.h$"))
+;;(setq iswitchb-buffer-ignore '("^ " iswitchb-ignore-c-mode))
+;;(setq iswitchb-buffer-ignore '("^ " "\\.c\\'" "\\.h\\'"))
(defcustom iswitchb-default-method 'always-frame
"*How to switch to new buffer when using `iswitchb-buffer'.
:type 'boolean
:group 'iswitchb)
-(defcustom iswitchb-use-fonts t
+(defcustom iswitchb-use-faces t
"*Non-nil means use font-lock fonts for showing first match."
:type 'boolean
:group 'iswitchb)
+(define-obsolete-variable-alias 'iswitchb-use-fonts 'iswitchb-use-faces "22.1")
(defcustom iswitchb-use-frame-buffer-list nil
"*Non-nil means use the currently selected frame's buffer list."
(defcustom iswitchb-minibuffer-setup-hook nil
"Iswitchb-specific customization of minibuffer setup.
-This hook is run during minibuffer setup iff `iswitchb' will be active.
+This hook is run during minibuffer setup if `iswitchb' is active.
For instance:
\(add-hook 'iswitchb-minibuffer-setup-hook
'\(lambda () (set (make-local-variable 'max-mini-window-height) 3)))
:type 'hook
:group 'iswitchb)
+(defface iswitchb-single-match
+ '((t
+ (:inherit font-lock-comment-face)))
+ "Iswitchb face for single matching buffer name."
+ :version "22.1"
+ :group 'iswitchb)
+
+(defface iswitchb-current-match
+ '((t
+ (:inherit font-lock-function-name-face)))
+ "Iswitchb face for current matching buffer name."
+ :version "22.1"
+ :group 'iswitchb)
+
+(defface iswitchb-virtual-matches
+ '((t
+ (:inherit font-lock-builtin-face)))
+ "Iswitchb face for matching virtual buffer names.
+See also `iswitchb-use-virtual-buffers'."
+ :version "22.1"
+ :group 'iswitchb)
+
+(defface iswitchb-invalid-regexp
+ '((t
+ (:inherit font-lock-warning-face)))
+ "Iswitchb face for indicating invalid regexp. "
+ :version "22.1"
+ :group 'iswitchb)
+
;; Do we need the variable iswitchb-use-mycompletion?
;;; Internal Variables
(defvar iswitchb-global-map
(let ((map (make-sparse-keymap)))
- (substitute-key-definition 'switch-to-buffer ; normally C-x b
- 'iswitchb-buffer map global-map)
- (substitute-key-definition 'switch-to-buffer-other-window ; C-x 4 b
- 'iswitchb-buffer-other-window map global-map)
- (substitute-key-definition 'switch-to-buffer-other-frame ; C-x 5 b
- 'iswitchb-buffer-other-frame map global-map)
- (substitute-key-definition 'display-buffer ; C-x 4 C-o
- 'iswitchb-display-buffer map global-map)
+ (dolist (b '((switch-to-buffer . iswitchb-buffer)
+ (switch-to-buffer-other-window . iswitchb-buffer-other-window)
+ (switch-to-buffer-other-frame . iswitchb-buffer-other-frame)
+ (display-buffer . iswitchb-display-buffer)))
+ (if (fboundp 'command-remapping)
+ (define-key map (vector 'remap (car b)) (cdr b))
+ (substitute-key-definition (car b) (cdr b) map global-map)))
map)
"Global keymap for `iswitchb-mode'.")
(defvar iswitchb-minibuf-depth nil
"Value we expect to be returned by `minibuffer-depth' in the minibuffer.")
+(defvar iswitchb-common-match-inserted nil
+ "Non-nil if we have just inserted a common match in the minibuffer.")
+
+(defvar iswitchb-invalid-regexp)
+
;;; FUNCTIONS
;;; ISWITCHB KEYMAP
(define-key map "\C-j" 'iswitchb-select-buffer-text)
(define-key map "\C-t" 'iswitchb-toggle-regexp)
(define-key map "\C-x\C-f" 'iswitchb-find-file)
- ;;(define-key map "\C-a" 'iswitchb-toggle-ignore)
+ (define-key map "\C-n" 'iswitchb-toggle-ignore)
(define-key map "\C-c" 'iswitchb-toggle-case)
(define-key map "\C-k" 'iswitchb-kill-buffer)
(define-key map "\C-m" 'iswitchb-exit-minibuffer)
;;`iswitchb-buffer-ignore')
(let* ((prompt "iswitch ")
+ iswitchb-invalid-regexp
(buf (iswitchb-read-buffer prompt)))
;;(message "chosen text %s" iswitchb-final-text)
(cond ( (eq iswitchb-exit 'findfile)
(call-interactively 'find-file))
-
+ (iswitchb-invalid-regexp
+ (message "Won't make invalid regexp named buffer"))
(t
;; View the buffer
;;(message "go to buf %s" buf)
buf-sel
iswitchb-final-text
(icomplete-mode nil) ;; prevent icomplete starting up
- ;; can only use fonts if they have been bound.
- (iswitchb-use-fonts (and iswitchb-use-fonts
- (boundp 'font-lock-comment-face)
- (boundp 'font-lock-function-name-face))))
+ )
(iswitchb-define-mode-map)
(setq iswitchb-exit nil)
(let (res)
(cond ((not iswitchb-matches)
(run-hooks 'iswitchb-cannot-complete-hook))
-
+ (iswitchb-invalid-regexp
+ ;; Do nothing
+ )
((= 1 (length iswitchb-matches))
;; only one choice, so select it.
(exit-minibuffer))
(not (equal res iswitchb-text)))
;; found something to complete, so put it in the minibuffer.
(progn
- (setq iswitchb-rescan nil)
+ (setq iswitchb-rescan nil
+ iswitchb-common-match-inserted t)
(delete-region (minibuffer-prompt-end) (point))
(insert res))
;; else nothing to complete
(defun iswitchb-to-end (lst)
"Move the elements from LST to the end of `iswitchb-temp-buflist'."
- (mapcar
- (lambda (elem)
- (setq iswitchb-temp-buflist (delq elem iswitchb-temp-buflist)))
- lst)
+ (dolist (elem lst)
+ (setq iswitchb-temp-buflist (delq elem iswitchb-temp-buflist)))
(setq iswitchb-temp-buflist (nconc iswitchb-temp-buflist lst)))
(defun iswitchb-get-buffers-in-frames (&optional current)
"Return buffers matching REGEXP.
If STRING-FORMAT is nil, consider REGEXP as just a string.
BUFFER-LIST can be list of buffers or list of strings."
- (let* ((case-fold-search (iswitchb-case))
- ;; need reverse since we are building up list backwards
- (list (reverse buffer-list))
- (do-string (stringp (car list)))
- name
- ret)
- (mapcar
- (lambda (x)
-
- (if do-string
- (setq name x) ;We already have the name
- (setq name (buffer-name x)))
-
- (cond
- ((and (or (and string-format (string-match regexp name))
- (and (null string-format)
- (string-match (regexp-quote regexp) name)))
-
- (not (iswitchb-ignore-buffername-p name)))
- (setq ret (cons name ret))
- )))
- list)
- ret))
+ (let* ((case-fold-search (iswitchb-case))
+ name ret)
+ (if (null string-format) (setq regexp (regexp-quote regexp)))
+ (setq iswitchb-invalid-regexp nil)
+ (condition-case error
+ (dolist (x buffer-list (nreverse ret))
+ (setq name (if (stringp x) x (buffer-name x)))
+ (when (and (string-match regexp name)
+ (not (iswitchb-ignore-buffername-p name)))
+ (push name ret)))
+ (invalid-regexp
+ (setq iswitchb-invalid-regexp t)
+ (cdr error)))))
(defun iswitchb-ignore-buffername-p (bufname)
"Return t if the buffer BUFNAME should be ignored."
(progn
(setq ignorep t)
(setq re-list nil))))
- ((fboundp nextstr)
+ ((functionp nextstr)
(if (funcall nextstr bufname)
(progn
(setq ignorep t)
(temp-buf "*Completions*")
(win))
- (if (eq last-command this-command)
+ (if (and (eq last-command this-command)
+ (not iswitchb-common-match-inserted))
;; scroll buffer
(progn
(set-buffer temp-buf)
(fundamental-mode))
(display-completion-list (if iswitchb-matches
iswitchb-matches
- iswitchb-buflist))
- )))))
+ iswitchb-buflist))))
+ (setq iswitchb-common-match-inserted nil))))
;;; KILL CURRENT BUFFER
(set-buffer-major-mode newbufcreated))
(iswitchb-visit-buffer newbufcreated))
;; else wont create new buffer
- (message (format "no buffer matching `%s'" buf)))))
+ (message "no buffer matching `%s'" buf))))
(defun iswitchb-window-buffer-p (buffer)
"Return window pointer if BUFFER is visible in another frame.
;; Insert the match-status information:
(insert (iswitchb-completions
- contents
- (not minibuffer-completion-confirm)))))))
+ contents))))))
(eval-when-compile
(defvar most-len)
(setq most-is-exact t))
(substring com most-len)))
-(defun iswitchb-completions (name require-match)
+(defun iswitchb-completions (name)
"Return the string that is displayed after the user's text.
Modified from `icomplete-completions'."
(let ((comps iswitchb-matches)
; "-determined" - only one candidate
- (open-bracket-determined (if require-match "(" "["))
- (close-bracket-determined (if require-match ")" "]"))
+ (open-bracket-determined "[")
+ (close-bracket-determined "]")
;"-prospects" - more than one candidate
(open-bracket-prospects "{")
(close-bracket-prospects "}")
first)
- (if (and iswitchb-use-fonts comps)
+ (if (and iswitchb-use-faces comps)
(progn
(setq first (car comps))
(setq first (format "%s" first))
(put-text-property 0 (length first) 'face
(if (= (length comps) 1)
- 'font-lock-comment-face
- 'font-lock-function-name-face)
+ (if iswitchb-invalid-regexp
+ 'iswitchb-invalid-regexp
+ 'iswitchb-single-match)
+ 'iswitchb-current-match)
first)
(setq comps (cons first (cdr comps)))))
(let ((comp comps))
(while comp
(put-text-property 0 (length (car comp))
- 'face 'font-lock-builtin-face
+ 'face 'iswitchb-virtual-matches
(car comp))
(setq comp (cdr comp))))))
open-bracket-determined
close-bracket-determined))
- ((null (cdr comps)) ;one match
- (concat (if (and (> (length (car comps))
- (length name)))
- (concat open-bracket-determined
+ (iswitchb-invalid-regexp
+ (concat " " (car comps)))
+ ((null (cdr comps)) ;one match
+ (concat
+ (if (if (not iswitchb-regexp)
+ (= (length name)
+ (length (car comps)))
+ (string-match name (car comps))
+ (string-equal (match-string 0 (car comps))
+ (car comps)))
+ ""
+ (concat open-bracket-determined
;; when there is one match, show the
;; matching buffer name in full
(car comps)
- close-bracket-determined)
- "")
- (if (not iswitchb-use-fonts) " [Matched]")))
+ close-bracket-determined))
+ (if (not iswitchb-use-faces) " [Matched]")))
(t ;multiple matches
(if (and iswitchb-max-to-show
(> (length comps) iswitchb-max-to-show))
(iswitchb-to-end summaries)))
(defun iswitchb-case ()
- "Return non-nil iff we should ignore case when matching.
+ "Return non-nil if we should ignore case when matching.
See the variable `iswitchb-case' for details."
(if iswitchb-case
(if (featurep 'xemacs)
;;;###autoload
(define-minor-mode iswitchb-mode
"Toggle Iswitchb global minor mode.
-With arg, turn Iswitchb mode on if and only iff ARG is positive.
+With arg, turn Iswitchb mode on if ARG is positive, otherwise turn it off.
This mode enables switching between buffers using substrings. See
`iswitchb' for details."
nil nil iswitchb-global-map :global t :group 'iswitchb
(provide 'iswitchb)
-;;; arch-tag: d74198ae-753f-44f2-b34f-0c515398d90a
+;; arch-tag: d74198ae-753f-44f2-b34f-0c515398d90a
;;; iswitchb.el ends here