comparison lisp/iswitchb.el @ 17616:a64126a1f870

Initial revision
author Richard M. Stallman <rms@gnu.org>
date Fri, 02 May 1997 00:22:11 +0000
parents
children 4851316697c1
comparison
equal deleted inserted replaced
17615:32f90c43d1d2 17616:a64126a1f870
1 ;;; ISWITCHB.EL --- switch between buffers using substrings
2
3 ;; Copyright (C) 1996, 1997 Free Software Foundation, Inc.
4
5 ;; Author: Stephen Eglen <stephene@cogs.susx.ac.uk>
6 ;; Maintainer: Stephen Eglen <stephene@cogs.susx.ac.uk>
7 ;; Created: 15 Dec 1996
8 ;; $Revision: 1.26 $
9 ;; Keywords: extensions
10 ;; location: http://www.cogs.susx.ac.uk/users/stephene/emacs
11
12
13 ;; This program is free software; you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation; either version 2, or (at your option)
16 ;; any later version.
17
18 ;; This program is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
22
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs; see the file COPYING. If not, write to the
25 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 ;; Boston, MA 02111-1307, USA.
27
28 ;; LCD Archive Entry:
29 ;; iswitchb|Stephen Eglen|<stephene@cogs.susx.ac.uk>
30 ;; |switch between buffers using substrings
31 ;; |$Date: 1997/03/23 18:10:48 $|$Revision: 1.26 $|~/packages/iswitchb.el
32
33
34 ;;; Installation:
35
36 ;; To load the package, do
37 ;; (require 'iswitchb)
38 ;; To get the functions in this package bound to keys, do
39 ;; (iswitchb-default-keybindings)
40 ;;
41 ;; Has been tested on Emacs 19.34 and XEmacs 19.14. I think it needs
42 ;; at least Emacs 19.29 to run.
43
44 ;;; Commentary:
45
46 ;; As you type in a substring, the list of buffers currently matching
47 ;; the substring are displayed as you type. The list is ordered so
48 ;; that the most recent buffers visited come at the start of the list.
49 ;; The buffer at the start of the list will be the one visited when
50 ;; you press return. By typing more of the substring, the list is
51 ;; narrowed down so that gradually the buffer you want will be at the
52 ;; top of the list. Alternatively, you can use C-s an C-r to rotate
53 ;; buffer names in the list until the one you want is at the top of
54 ;; the list. Completion is also available so that you can see what is
55 ;; common to all of the matching buffers as you type.
56
57 ;; This code is similar to a couple of other packages. Michael R Cook
58 ;; <mcook@cognex.com wrote a similar buffer switching package, but
59 ;; does exact matching rather than substring matching on buffer names.
60 ;; I also modified a couple of functions from icomplete.el to provide
61 ;; the completion feedback in the minibuffer.
62
63 ;;; Example
64
65 ;;If I have two buffers called "123456" and "123", with "123456" the
66 ;;most recent, when I use iswitchb, I first of all get presented with
67 ;;the default buffer (xxx) to switch to:
68 ;;
69 ;; iswitch {default xxx}
70 ;;
71 ;; If I then press 2:
72 ;; iswitch 2[3]{123456,123}
73 ;;
74 ;; The list in {} are the matching buffers, most recent first (buffers
75 ;; visible in the current frame are put at the end of the list by
76 ;; default). At any time I can select the item at the head of the
77 ;; list by pressing RET. I can also bring the put the first element
78 ;; at the end of the list by pressing C-s, or put the last element at
79 ;; the head of the list by pressing C-r. The item in [] indicates
80 ;; what can be added to my input by pressing TAB. In this case, I
81 ;; will get "3" added to my input. So, press TAB:
82 ;; iswitch 23{123456,123}
83 ;;
84 ;; At this point, I still have two matching buffers.
85 ;; If I want the first buffer in the list, I simply press RET. If I
86 ;; wanted the second in the list, I could press C-s to move it to the
87 ;; top of the list and then RET to select it.
88 ;;
89 ;;However, If I type 4, I only have one match left:
90 ;; iswitch 234[123456] [Matched]
91 ;;
92 ;;Since there is only one matching buffer left, it is given in [] and we
93 ;;see the text [Matched] afterwards. I can now press TAB or RET to go
94 ;;to that buffer.
95 ;;
96 ;; If however, I now type "a":
97 ;; iswitch 234a [No match]
98 ;; There are no matching buffers. If I press RET or TAB, I can be
99 ;; prompted to create a new buffer called "234a".
100 ;;
101 ;; Of course, where this function comes in really useful is when you
102 ;; can specify the buffer using only a few keystrokes. In the above
103 ;; example, the quickest way to get to the "123456" buffer would be
104 ;; just to type 4 and then RET (assuming there isnt any newer buffer
105 ;; with 4 in its name).
106
107 ;; To see a full list of all matching buffers in a separate buffer,
108 ;; hit ? or press TAB when there are no further completions to the
109 ;; substring.
110
111 ;;
112 ;; See the doc string of iswitchb for full keybindings and features.
113 ;; (describe-function 'iswitchb)
114
115 ;;; Customisation
116
117 ;; See the User Variables section below for easy ways to change the
118 ;; functionality of the program.
119 ;; To modify the keybindings, use the hook provided. For example:
120 ;;(add-hook 'iswitchb-define-mode-map-hook
121 ;; 'iswitchb-my-keys)
122 ;;
123 ;;(defun iswitchb-my-keys ()
124 ;; "Add my keybings for iswitchb."
125 ;; (define-key iswitchb-mode-map " " 'iswitchb-next-match)
126 ;; )
127 ;;
128 ;; Seeing all the matching buffers.
129 ;; If you have many matching buffers, they may not all fit onto one
130 ;; line of the minibuffer. In this case, you should use rsz-mini
131 ;; (resize-minibuffer-mode). You can also limit iswitchb so that it
132 ;; only shows a certain number of lines -- see the documentation for
133 ;; `iswitchb-minibuffer-setup-hook'.
134
135
136 ;; Changing the list of buffers.
137
138 ;; By default, the list of current buffers is most recent first,
139 ;; oldest last, with the exception that the buffers visible in the
140 ;; current frame are put at the end of the list. A hook exists to
141 ;; allow other functions to order the list. For example, if you add:
142 ;;
143 ;; (add-hook 'iswitchb-make-buflist-hook 'iswitchb-summaries-to-end)
144 ;;
145 ;; then all buffers matching "Summary" are moved to the end of the
146 ;; list. (I find this handy for keeping the INBOX Summary and so on
147 ;; out of the way.) It also moves buffers matching "output\*$" to the
148 ;; end of the list (these are created by AUC TeX when compiling.)
149 ;; Other functions could be made available which alter the list of
150 ;; matching buffers (either deleting or rearranging elements.)
151
152 ;; Font-Lock
153
154 ;; If you have font-lock loaded, the first matching buffer is
155 ;; highlighted. To switch this off, set (setq iswitchb-use-fonts nil)
156 ;; I don't use font-lock that much, so I've hardcoded the faces. If
157 ;; this is too harsh, let me know. Colouring of the matching buffer
158 ;; name was suggested by Carsten Dominik (dominik@strw.leidenuniv.nl)
159
160 ;;; Comparison with iswitch-buffer
161
162 ;; This package is a rewrite of iswitch-buffer, using the minibuffer
163 ;; rather than the echo area. The advantages of using the minibuffer
164 ;; are several:
165 ;; o minibuffer has more powerful editing facilities
166 ;; o doesnt interfere with other packages that use the echo area
167 ;; o *Messages* buffer doesnt get filled up with all of the messages that
168 ;; go to the modeline
169 ;; o cursor is in the minibuffer, which somehow looks right.
170 ;; o minibuffer can be resized dynamically to show all the possible matching
171 ;; buffers rather than just the first line's worth (using rsz-mini).
172 ;;
173 ;; Disadvantages:
174 ;; o cant change the prompt to indicate status of searching (eg whether
175 ;; regexp searching is currently on).
176
177
178 ;;; Acknowledgements
179
180 ;; Thanks to Jari Aalto <jari.aalto@poboxes.com> for help with the
181 ;; first version of this package, iswitch-buffer. Thanks also to many
182 ;; others for testing earlier versions.
183
184 ;;; Code:
185
186 (defconst iswitchb-version (substring "$Revision: 1.26 $" 11 -2)
187 "$Id: iswitchb.el,v 1.26 1997/03/23 18:10:48 stephene Exp $
188
189 Report bugs to: Stephen Eglen <stephene@cogs.susx.ac.uk>")
190
191
192 ;;; User Variables
193 ;;
194 ;; These are some things you might want to change.
195
196 (defvar iswitchb-case case-fold-search
197 "*Non-nil if searching of buffer names should ignore case.")
198
199 (defvar iswitchb-buffer-ignore
200 '("^ ")
201 "*List of regexps or functions matching buffer names to ignore. For
202 example, traditional behavior is not to list buffers whose names begin
203 with a space, for which the regexp is \"^ \". See the source file for
204 example functions that filter buffernames.")
205
206 ;;; Examples for setting the value of iswitchb-buffer-ignore
207 ;(defun -c-mode (name)
208 ; "Ignore all c mode buffers -- example function for iswitchb."
209 ; (save-excursion
210 ; (set-buffer name)
211 ; (string-match "^C$" mode-name)))
212
213 ;(setq iswitchb-buffer-ignore '("^ " ignore-c-mode))
214 ;(setq iswitchb-buffer-ignore '("^ " "\\.c$" "\\.h$"))
215
216
217 (defvar iswitchb-default-method 'always-frame
218 "*How to switch to new buffer when using iswitchb.
219 Possible values:
220 `samewindow' Show new buffer in same window
221 `otherwindow' Show new buffer in another window (same frame)
222 `otherframe' Show new buffer in another frame
223 `maybe-frame' If a buffer is visible in another frame, prompt to ask if you
224 you want to see the buffer in the same window of the current
225 frame or in the other frame.
226 `always-frame' If a buffer is visible in another frame, raise that
227 frame. Otherwise, visit the buffer in the same window.")
228
229 (defvar iswitchb-regexp nil
230 "*Non-nil means that iswitchb will do regexp matching. Value can be
231 toggled within iswitchb.")
232
233 (defvar iswitchb-newbuffer t
234 "*Non-nil means create new buffer if no buffer matches substring.
235 See also `iswitchb-prompt-newbuffer'.")
236
237 (defvar iswitchb-prompt-newbuffer t
238 "*Non-nil means prompt user to confirm before creating new buffer.
239 See also `iswitchb-newbuffer'.")
240
241 (defvar iswitchb-define-mode-map-hook nil
242 "*Hook to define keys in `iswitchb-mode-map' for extra keybindings.")
243
244
245 (defvar iswitchb-use-fonts t
246 "*Non-nil means use fonts for showing first match.")
247
248 (defvar iswitchb-make-buflist-hook nil
249 "*Hook to run when list of matching buffers is created.")
250
251
252 (defvar iswitchb-method nil
253 "*Stores the method for viewing the selected buffer. Its value is
254 one of `samewindow', `otherwindow', `otherframe', `maybe-frame' or
255 `always-frame'. See `iswitchb-default-method' for details of
256 values.")
257
258 (defvar iswitchb-all-frames 'visible
259 "*Argument to pass to `walk-windows' when finding visible buffers.
260 See documentation of `walk-windows' for useful values.")
261
262 ;;; THINGS TO DO / BUGS
263
264 ;; In Xemacs, the default buffer is not shown the first time you enter
265 ; the minibuffer, but if you type a char and then delete a char, the
266 ; default appears. The first time we enter the minibuffer in XEmacs,
267 ; the default msg is not displayed, presumably because the hook is not
268 ; being called. I have put in a temporary hack therefore at the
269 ; bottom of this file.
270 ;
271 ; There is also a problem with the backspace key in XEmacs, so I have
272 ; bound it to the normal backward-delete-char.
273
274 ;; iswitch-buffer features Not yet implemented:
275 ; C-f Quit iswitch and drop into find-file
276
277
278 ;; Do we need the variable iswitchb-use-mycompletion?
279
280
281 ;;; Internal Variables
282 (defvar iswitchb-minibuffer-setup-hook nil
283 "*Iswitchb-specific customization of minibuffer setup.
284
285 This hook is run during minibuffer setup iff iswitchb will be active.
286 It is intended for use in customizing iswitchb for interoperation
287 with other packages. For instance:
288
289 \(add-hook 'iswitchb-minibuffer-setup-hook
290 \(function
291 \(lambda ()
292 \(make-local-variable 'resize-minibuffer-window-max-height)
293 \(setq resize-minibuffer-window-max-height 3))))
294
295 will constrain rsz-mini to a maximum minibuffer height of 3 lines when
296 iswitchb is running. Copied from icomplete-minibuffer-setup-hook")
297
298 (defvar iswitchb-eoinput 1
299 "Point where minibuffer input ends and completion info begins.
300 Copied from icomplete-eoinput.")
301 (make-variable-buffer-local 'iswitchb-eoinput)
302
303
304 (defvar iswitchb-buflist nil
305 "Stores the current list of buffers that will be searched through.
306 The list is ordered, so that the most recent buffers come first,
307 although by default, the buffers visible in the current frame are put
308 at the end of the list. Created by `iswitchb-make-buflist'.")
309
310 ;; todo -- is this necessary?
311
312 (defvar iswitchb-use-mycompletion nil
313 "Non-nil means use iswitchb completion feedback. Should only be set
314 to t by iswitchb functions, so that it doesnt interfere with other
315 minibuffer usage.")
316
317 (defvar iswitchb-change-word-sub nil
318 "Private variable used by `iswitchb-word-matching-substring'.")
319
320
321 (defvar iswitchb-common-match-string nil
322 "Stores the string that is common to all matching buffers.")
323
324
325 (defvar iswitchb-rescan nil
326 "Non-nil means we need to regenerate the list of matching buffers.")
327
328 (defvar iswitchb-text nil
329 "Stores the users string as it is typed in.")
330
331 (defvar iswitchb-matches nil
332 "List of buffers currenly matching `iswitchb-text'.")
333
334 (defvar iswitchb-default-buffer nil
335 "Default buffer to switch to.")
336
337 (defvar iswitchb-mode-map nil
338 "Keymap for iswitchb.")
339
340 (defvar iswitchb-history nil
341 "History of buffers selected using iswitchb.")
342
343 (defvar iswitchb-exit nil
344 "Flag to monitor how iswitchb exits. If equal to `takeprompt', we
345 use the prompt as the buffer name to be selected.")
346
347 (defvar iswitchb-buffer-ignore-orig nil
348 "Stores original value of `iswitchb-buffer-ignore'.")
349
350 (defvar iswitchb-xemacs (string-match "XEmacs" (emacs-version))
351 "Non-nil if we are running XEmacs. Otherwise, assume we are running Emacs.")
352
353
354 ;;; FUNCTIONS
355
356
357 ;;; ISWITCHB KEYMAP
358 (defun iswitchb-define-mode-map ()
359 "Set up the keymap for iswitchb."
360 (interactive)
361 (let (map)
362 ;; generated every time so that it can inheret new functions.
363 ;;(or iswitchb-mode-map
364
365 (setq map (copy-keymap minibuffer-local-map))
366 (define-key map "?" 'iswitchb-completion-help)
367 (define-key map "\C-s" 'iswitchb-next-match)
368 (define-key map "\C-r" 'iswitchb-prev-match)
369 (define-key map "\t" 'iswitchb-complete)
370 (define-key map "\C-j" 'iswitchb-select-buffer-text)
371 (define-key map "\C-t" 'iswitchb-toggle-regexp)
372 ;;(define-key map "\C-a" 'iswitchb-toggle-ignore)
373 (define-key map "\C-c" 'iswitchb-toggle-case)
374 (setq iswitchb-mode-map map)
375 (run-hooks 'iswitchb-define-mode-map-hook)
376 ))
377
378
379
380 ;;; MAIN FUNCTION
381 (defun iswitchb ()
382 "Switch to buffer matching a substring.
383 As you type in a string, all of the buffers matching the string are
384 displayed. When you have found the buffer you want, it can then be
385 selected. As you type, most keys have their normal keybindings,
386 except for the following:
387 \\<iswitchb-mode-map>
388
389 RET Select the buffer at the front of the list of matches. If the
390 list is emptty, possibly prompt to create new buffer.
391
392 \\[iswitchb-select-buffer-text] Select the current prompt as the buffer.
393 If no buffer is found, prompt for a new one.
394
395 \\[iswitchb-next-match] Put the first element at the end of the list.
396 \\[iswitchb-prev-match] Put the last element at the start of the list.
397 \\[iswitchb-complete] Complete a common suffix to the current string that
398 matches all buffers. If there is only one match, select that buffer.
399 If there is no common suffix, show a list of all matching buffers
400 in a separate window.
401 \\[iswitchb-toggle-regexp] Toggle rexep searching.
402 \\[iswitchb-toggle-case] Toggle case-sensitive searching of buffer names.
403 \\[iswitchb-completion-help] Show list of matching buffers in separate window.
404 "
405 ;;\\[iswitchb-toggle-ignore] Toggle ignoring certain buffers (see \
406 ;;`iswitchb-buffer-ignore')
407
408 (let
409 (
410 prompt
411 buf-sel
412 iswitchb-final-text
413 (minibuffer-confirm-incomplete nil) ;XEmacs todo: prevent `;confirm'
414 (icomplete-mode nil) ;; prevent icomplete starting up
415 (minibuffer-local-completion-map minibuffer-local-completion-map)
416 ;; can only use fonts if they have been bound.
417 (iswitchb-use-fonts (and iswitchb-use-fonts
418 (boundp 'font-lock-comment-face)
419 (boundp 'font-lock-function-name-face)))
420 )
421
422 (iswitchb-define-mode-map)
423 (setq minibuffer-local-completion-map iswitchb-mode-map)
424
425 (setq iswitchb-exit nil)
426 (setq iswitchb-rescan t)
427 (setq iswitchb-text "")
428 (setq iswitchb-matches nil)
429 ;;(setq iswitchb-default-buffer (buffer-name (other-buffer)))
430 (setq prompt (format "iswitch "))
431 (iswitchb-make-buflist)
432 (setq iswitchb-default-buffer (format "%s" (car iswitchb-buflist)))
433
434 ;; highlight the default.
435 (if iswitchb-use-fonts
436 (put-text-property 0 (length iswitchb-default-buffer)
437 'face
438 'font-lock-function-name-face
439 iswitchb-default-buffer))
440
441 ;; prompt the user for the buffer name
442 (setq iswitchb-final-text (completing-read prompt
443 ;;nil
444 '(("dummy".1))
445 ;;("2".2) ("3".3))
446 nil nil
447 nil;init string
448 'iswitchb-history))
449 ;;(message "chosen text %s" iswitchb-final-text)
450 ;; Choose the buffer name: either the text typed in, or the head
451 ;; of the list of matches
452 (if (or
453 (eq iswitchb-exit 'takeprompt)
454 (null iswitchb-matches))
455 (setq buf-sel iswitchb-final-text)
456 ;; else take head of list
457 (setq buf-sel (car iswitchb-matches)))
458
459 ;; Or possibly choose the default buffer
460 (if (equal iswitchb-final-text "")
461 (setq buf-sel iswitchb-default-buffer))
462
463 ;; View the buffer
464 (message "go to buf %s" buf-sel)
465
466 (if (get-buffer buf-sel)
467 ;; buffer exists, so view it and then exit
468 (iswitchb-visit-buffer buf-sel)
469 ;; else buffer doesnt exist
470 (iswitchb-possible-new-buffer buf-sel))
471
472 ))
473
474
475 ;;; COMPLETION CODE
476
477 (defun iswitchb-set-common-completion ()
478 "Find common completion of `iswitchb-text' in `iswitchb-matches'. The
479 result is stored in `iswitchb-common-match-string'."
480
481 (let* (val)
482 (setq iswitchb-common-match-string nil)
483 (if (and iswitchb-matches
484 (stringp iswitchb-text)
485 (> (length iswitchb-text) 0))
486 (if (setq val (iswitchb-find-common-substring
487 iswitchb-matches iswitchb-text))
488 (setq iswitchb-common-match-string val)))
489 val
490 ))
491
492
493 (defun iswitchb-complete ()
494 "Try and complete the current pattern amongst the buffer names."
495 (interactive)
496 (let (res)
497 (cond ((not iswitchb-matches)
498
499 ;; todo
500 ;;(message "No buffer completions.")
501 ;;(sit-for 0.3)
502 (iswitchb-completion-help)
503 )
504
505 ((eq 1 (length iswitchb-matches))
506 ;; only one choice, so select it.
507 (exit-minibuffer))
508
509 (t
510 ;; else there could be some completions
511
512 (setq res (iswitchb-find-common-substring
513 iswitchb-matches iswitchb-text))
514 (if (and (not (memq res '(t nil)))
515 (not (eq res iswitchb-text)))
516 ;; found something to complete, so put it in the minibuff.
517 (progn
518 (setq iswitchb-rescan nil)
519 (delete-region (point-min) (point))
520 (insert res))
521 ;; else nothing to complete
522 (iswitchb-completion-help)
523 )
524 )
525 )))
526
527
528
529 ;;; TOGGLE FUNCTIONS
530
531 (defun iswitchb-toggle-case ()
532 "Toggle the value of `iswitchb-case'."
533 (interactive)
534 (setq iswitchb-case (not iswitchb-case))
535 ;; ask for list to be regenerated.
536 (setq iswitchb-rescan t)
537 )
538
539 (defun iswitchb-toggle-regexp ()
540 "Toggle the value of `iswitchb-regexp'."
541 (interactive)
542 (setq iswitchb-regexp (not iswitchb-regexp))
543 ;; ask for list to be regenerated.
544 (setq iswitchb-rescan t)
545 )
546
547
548 (defun iswitchb-toggle-ignore ()
549 "Toggle ignoring buffers specified with `iswitchb-buffer-ignore'."
550 (interactive)
551 (if iswitchb-buffer-ignore
552 (progn
553 (setq iswitchb-buffer-ignore-orig iswitchb-buffer-ignore)
554 (setq iswitchb-buffer-ignore nil)
555 )
556 ;; else
557 (setq iswitchb-buffer-ignore iswitchb-buffer-ignore-orig)
558 )
559 ;; ask for list to be regenerated.
560 (setq iswitchb-rescan t)
561 )
562
563
564 (defun iswitchb-select-buffer-text ()
565 "Select the buffer named by the prompt. If no buffer exactly
566 matching the prompt exists, a new one is possibly created."
567 (interactive)
568 (setq iswitchb-exit 'takeprompt)
569 (exit-minibuffer))
570
571
572 (defun iswitchb-next-match ()
573 "Put first element of `iswitchb-matches' at the end of the list."
574 (interactive)
575 (let ((tmp (car iswitchb-matches)))
576 (setq iswitchb-matches (cdr iswitchb-matches))
577 (setq iswitchb-matches (append iswitchb-matches (list tmp)))
578 (setq iswitchb-rescan nil)
579 ))
580
581 (defun iswitchb-prev-match ()
582 "Put last element of `iswitchb-matches' at the front of the list."
583 (interactive)
584 (setq iswitchb-matches (iswitchb-rotate-list iswitchb-matches))
585 (setq iswitchb-rescan nil)
586 )
587
588
589
590
591 ;;; CREATE LIST OF ALL CURRENT BUFFERS
592
593 (defun iswitchb-make-buflist ()
594 "Set `iswitchb-buflist' to the current list of buffers. Buffers
595 that are currently visible are put at the end of the list."
596
597 (setq iswitchb-buflist
598 (let (buflist
599 iswitchb-current-buffers)
600 (setq iswitchb-current-buffers (iswitchb-get-buffers-in-frames))
601 (setq buflist (mapcar 'buffer-name (buffer-list)))
602 (setq buflist (delq nil
603 (mapcar
604 '(lambda (x)
605 (if (not (iswitchb-ignore-buffername-p x))
606 x))
607 buflist)))
608 (mapcar 'iswitchb-to-end iswitchb-current-buffers)
609
610 (run-hooks 'iswitchb-make-buflist-hook)
611 buflist)))
612
613
614 (defun iswitchb-to-end (elem)
615 "Move ELEM to the end of BUFLIST."
616 (setq buflist (delq elem buflist))
617 ;;(message "removing %s" elem)
618 (setq buflist (append buflist (list elem))))
619
620
621
622
623 (defun iswitchb-get-buffers-in-frames (&optional current)
624
625 "Return the list of buffers that are visible in the current frame.
626 If optional argument `current' is given, restrict searching to the
627 current frame, rather than all frames, regardless of value of
628 `iswitchb-all-frames'."
629
630 (let ((iswitchb-bufs-in-frame nil))
631
632 (walk-windows 'iswitchb-get-bufname nil
633 (if current
634 nil
635 iswitchb-all-frames))
636 iswitchb-bufs-in-frame))
637
638
639 (defun iswitchb-get-bufname (win)
640 "Used by `iswitchb-get-buffers-in-frames' to walk through all windows."
641 (setq iswitchb-bufs-in-frame
642 (cons (buffer-name (window-buffer win))
643 iswitchb-bufs-in-frame)))
644
645
646 ;;; FIND MATCHING BUFFERS
647
648 (defun iswitchb-set-matches ()
649 "Set `iswitchb-matches' to the list of buffers matching prompt."
650
651 (if iswitchb-rescan
652 (setq iswitchb-matches
653 (let* ((buflist iswitchb-buflist)
654 )
655 (if (> (length iswitchb-text) 0)
656 (iswitchb-get-matched-buffers iswitchb-text iswitchb-regexp
657 buflist)
658 ;; else no text, no matches
659 nil)))))
660
661 (defun iswitchb-get-matched-buffers
662 (regexp &optional string-format buffer-list)
663 "Return matched buffers. If STRING-FORMAT is non-nil, consider
664 REGEXP as string. BUFFER-LIST can be list of buffers or list of
665 strings."
666
667 (let* ((case-fold-search iswitchb-case)
668 ;; need reverse since we are building up list backwards
669 (list (reverse buffer-list))
670 (do-string (stringp (car list)))
671 name
672 ret
673 )
674 (mapcar
675 (function
676 (lambda (x)
677
678 (if do-string
679 (setq name x) ;We already have the name
680 (setq name (buffer-name x)))
681
682 (cond
683 ((and (or (and string-format (string-match regexp name))
684 (and (null string-format)
685 (string-match (regexp-quote regexp) name)))
686
687 ;; todo (not (iswitchb-ignore-buffername-p name))
688 )
689 (setq ret (cons name ret))
690 ))))
691 list)
692 ret
693 ))
694
695
696
697
698 (defun iswitchb-ignore-buffername-p (bufname)
699 "Return t if the buffer BUFNAME should be ignored."
700 (let ((data (match-data))
701 (re-list iswitchb-buffer-ignore)
702 ignorep
703 nextstr
704 )
705 (while re-list
706 (setq nextstr (car re-list))
707 (cond
708 ((stringp nextstr)
709 (if (string-match nextstr bufname)
710 (progn
711 (setq ignorep t)
712 (setq re-list nil))))
713 ((fboundp nextstr)
714 (if (funcall nextstr bufname)
715 (progn
716 (setq ignorep t)
717 (setq re-list nil))
718 ))
719 )
720 (setq re-list (cdr re-list)))
721 (store-match-data data)
722
723 ;; return the result
724 ignorep)
725 )
726
727
728
729 (defun iswitchb-word-matching-substring (word)
730 "Return part of WORD before 1st match to `iswitchb-change-word-sub'.
731 If `iswitchb-change-word-sub' cannot be found in WORD, return nil."
732 (let ((case-fold-search iswitchb-case))
733 (let ((m (string-match iswitchb-change-word-sub word)))
734 (if m
735 (substring word m)
736 ;; else no match
737 nil))))
738
739
740
741
742
743
744 (defun iswitchb-find-common-substring (lis subs)
745 "Return common string following SUBS in each element of LIS."
746 (let (res
747 alist
748 iswitchb-change-word-sub
749 )
750 (setq iswitchb-change-word-sub
751 (if iswitchb-regexp
752 subs
753 (regexp-quote subs)))
754 (setq res (mapcar 'iswitchb-word-matching-substring lis))
755 (setq res (delq nil res)) ;; remove any nil elements (shouldnt happen)
756 (setq alist (mapcar 'iswitchb-makealist res)) ;; could use an OBARRAY
757
758 ;; try-completion returns t if there is an exact match.
759 (let ((completion-ignore-case iswitchb-case))
760
761 (try-completion subs alist)
762 )))
763
764
765 (defun iswitchb-makealist (res)
766 "Return dotted pair (RES . 1)."
767 (cons res 1))
768
769 ;; from Wayne Mesard <wmesard@esd.sgi.com>
770 (defun iswitchb-rotate-list (lis)
771 "Destructively removes the last element from LIS.
772 Return the modified list with the last element prepended to it."
773 (if (<= (length lis) 1)
774 lis
775 (let ((las lis)
776 (prev lis))
777 (while (consp (cdr las))
778 (setq prev las
779 las (cdr las)))
780 (setcdr prev nil)
781 (cons (car las) lis))
782 ))
783
784
785 (defun iswitchb-completion-help ()
786 "Show possible completions in a *Buffer Completions* buffer."
787 ;; we could allow this buffer to be used to select match, but I think
788 ;; choose-completion-string will need redifining, so it just inserts
789 ;; choice with out any previous input.
790 (interactive)
791 (let ((completion-setup-hook nil) ;disable fancy highlight/selection.
792 )
793 (with-output-to-temp-buffer "*Buffer Completions*"
794 (if iswitchb-xemacs
795
796 ;; XEmacs extents are put on by default, doesn't seem to be
797 ;; any way of switching them off.
798 (display-completion-list (if iswitchb-matches
799 iswitchb-matches
800 iswitchb-buflist)
801 :help-string "iswitchb "
802 :activate-callback
803 '(lambda (x y z)
804 (message "doesnt work yet, sorry!")))
805 ;; else running Emacs
806 (display-completion-list (if iswitchb-matches
807 iswitchb-matches
808 iswitchb-buflist))
809 ))))
810
811 ;;; VISIT CHOSEN BUFFER
812 (defun iswitchb-visit-buffer (buffer)
813 "Visit buffer named BUFFER according to `iswitchb-method'."
814 (let* (win newframe)
815 (cond
816 ((eq iswitchb-method 'samewindow)
817 (switch-to-buffer buffer))
818
819 ((memq iswitchb-method '(always-frame maybe-frame))
820 (cond
821 ((and (setq win (iswitchb-window-buffer-p buffer))
822 (or (eq iswitchb-method 'always-frame)
823 (y-or-n-p "Jump to frame? ")))
824 (setq newframe (window-frame win))
825 (raise-frame newframe)
826 (select-frame newframe)
827 (select-window win)
828 (if (not iswitchb-xemacs)
829 ;; reposition mouse to make frame active. not needed in XEmacs
830 ;; This line came from the other-frame defun in Emacs.
831 (set-mouse-position (selected-frame) (1- (frame-width)) 0))
832 )
833 (t
834 ;; No buffer in other frames...
835 (switch-to-buffer buffer)
836 )))
837
838
839
840 ((eq iswitchb-method 'otherwindow)
841 (switch-to-buffer-other-window buffer))
842
843 ((eq iswitchb-method 'otherframe)
844 (progn
845 (switch-to-buffer-other-frame buffer)
846 (if (not iswitchb-xemacs)
847 (set-mouse-position (selected-frame) (1- (frame-width)) 0))
848 )
849 ) )))
850
851 (defun iswitchb-possible-new-buffer (buf)
852 "Possibly create and visit a new buffer called BUF."
853
854 (let ((newbufcreated))
855 (if (and iswitchb-newbuffer
856 (or
857 (not iswitchb-prompt-newbuffer)
858
859 (and iswitchb-prompt-newbuffer
860 (y-or-n-p
861 (format
862 "No buffer matching `%s', create one? "
863 buf)))))
864 ;; then create a new buffer
865 (progn
866 (setq newbufcreated (get-buffer-create buf))
867 (if (fboundp 'set-buffer-major-mode)
868 (set-buffer-major-mode newbufcreated))
869 (iswitchb-visit-buffer newbufcreated))
870 ;; else wont create new buffer
871 (message (format "no buffer matching `%s'" buf))
872 )))
873
874 (defun iswitchb-window-buffer-p (buffer)
875 "Return window pointer if BUFFER is visible in another frame. If
876 BUFFER is visible in the current frame, return nil."
877
878 (interactive)
879
880 (let ((blist (iswitchb-get-buffers-in-frames 'current)))
881 ;;If the buffer is visible in current frame, return nil
882 (if (memq buffer blist)
883 nil
884 ;; maybe in other frame...
885 (get-buffer-window buffer 'visible)
886 )))
887
888 ;;; KEYBINDINGS AND TOP LEVEL FUNCTIONS.
889 (defun iswitchb-default-keybindings ()
890 "Set up default keybindings for iswitchb.
891 Call this function to override the normal bindings."
892 (interactive)
893 (global-set-key "b" 'iswitchb-buffer)
894 (global-set-key "4b" 'iswitchb-buffer-other-window)
895 (global-set-key "5b" 'iswitchb-buffer-other-frame))
896
897
898
899 ;;;###autoload
900 (defun iswitchb-buffer ()
901 "Switch to another buffer.
902
903 The buffer name is selected interactively by typing a substring. The
904 buffer is displayed according to `iswitchb-default-method' -- the
905 default is to show it in the same window, unless it is already visible
906 in another frame. For details of keybindings, do `C-h f
907 iswitchb-mode'."
908
909 (interactive)
910 (setq iswitchb-method iswitchb-default-method)
911 (iswitchb-entry))
912
913
914 ;;;###autoload
915 (defun iswitchb-buffer-other-window ()
916 "Switch to another buffer and show it in another window.
917 The buffer name is selected interactively by typing a substring.
918 For details of keybindings, do `C-h f iswitchb-mode'."
919 (interactive)
920 (setq iswitchb-method 'otherwindow)
921 (iswitchb-entry))
922
923
924
925 ;;;###autoload
926 (defun iswitchb-buffer-other-frame ()
927 "Switch to another buffer and show it in another frame.
928 The buffer name is selected interactively by typing a substring.
929 For details of keybindings, do `C-h f iswitchb-mode'."
930 (interactive)
931 (setq iswitchb-method 'otherframe)
932 (iswitchb-entry))
933
934
935
936 (defun iswitchb-entry ()
937 "Simply fall into iswitchb -- the main function."
938 (iswitchb))
939
940
941
942
943
944 ;;; XEMACS HACK FOR SHOWING DEFAULT BUFFER
945
946 ;; The first time we enter the minibuffer, Emacs puts up the default
947 ;; buffer to switch to, but XEmacs doesnt -- presumably there is a
948 ;; subtle difference in the two, either in icomplete or somewhere
949 ;; else. The default is shown for both whenever we delete all of our
950 ;; text though, indicating its just a problem the first time we enter
951 ;; the function. To solve this, we use another entry hook for emacs
952 ;; to show the default the first time we enter the minibuffer.
953
954 (defun iswitchb-init-Xemacs-trick ()
955 "Display default buffer when first entering minibuffer. This is a
956 hack for XEmacs, and should really be handled by iswitchb-exhibit."
957 (if (iswitchb-entryfn-p)
958 (progn
959 (iswitchb-show-default-buffer)
960 (goto-char (point-min)))))
961
962 ;; add this hook for Xemacs only.
963 (if iswitchb-xemacs
964 (add-hook 'iswitchb-minibuffer-setup-hook
965 'iswitchb-init-Xemacs-trick))
966
967
968 ;;; XEMACS / BACKSPACE key
969 ;; For some reason, if the backspace key is pressed in xemacs, the
970 ;; line gets confused, so I've added a simple key definition to make
971 ;; backspace act like the normal delete key.
972
973 (defun iswitchb-xemacs-backspacekey ()
974 "Bind backspace to `backward-delete-char'."
975 (define-key iswitchb-mode-map '[backspace] 'backward-delete-char)
976 (define-key iswitchb-mode-map '[(meta backspace)] 'backward-kill-word)
977 )
978
979
980 (if iswitchb-xemacs
981 (add-hook 'iswitchb-define-mode-map-hook
982 'iswitchb-xemacs-backspacekey))
983
984
985
986 ;;; ICOMPLETE TYPE CODE
987
988 (defun iswitchb-exhibit ()
989 "Find matching buffers and display them in the minibuffer.
990 Copied from `icomplete-exhibit' with two changes:
991 1. It prints a default buffer name when there is no text yet entered.
992 2. It calls my completion routine rather than the standard completion."
993
994 (if iswitchb-use-mycompletion
995 (let ((contents (buffer-substring (point-min)(point-max)))
996 (buffer-undo-list t))
997 (save-excursion
998 (goto-char (point-max))
999 ; Register the end of input, so we
1000 ; know where the extra stuff
1001 ; (match-status info) begins:
1002 (if (not (boundp 'iswitchb-eoinput))
1003 ;; In case it got wiped out by major mode business:
1004 (make-local-variable 'iswitchb-eoinput))
1005 (setq iswitchb-eoinput (point))
1006 ;; Update the list of matches
1007 (setq iswitchb-text contents)
1008 (iswitchb-set-matches)
1009 (setq iswitchb-rescan t)
1010 (iswitchb-set-common-completion)
1011
1012 ;; Insert the match-status information:
1013 (if (> (point-max) 1)
1014 (insert-string
1015 (iswitchb-completions
1016 contents
1017 minibuffer-completion-table
1018 minibuffer-completion-predicate
1019 (not minibuffer-completion-confirm)))
1020 ;; else put in default
1021 (iswitchb-show-default-buffer))
1022 ))))
1023
1024 (defun iswitchb-show-default-buffer ()
1025 "Insert the default buffer to switch to."
1026 ;; insert done this way to preserve any text-propertes.
1027 (insert (concat " {" iswitchb-default-buffer "} [Default]")))
1028
1029 (defun iswitchb-completions
1030 (name candidates predicate require-match)
1031 "Return the string that is displayed after the user's text.
1032 Modified from `icomplete-completions'."
1033
1034 (let ((comps iswitchb-matches)
1035 ; "-determined" - only one candidate
1036 (open-bracket-determined (if require-match "(" "["))
1037 (close-bracket-determined (if require-match ")" "]"))
1038 ;"-prospects" - more than one candidate
1039 (open-bracket-prospects "{")
1040 (close-bracket-prospects "}")
1041 first
1042 )
1043
1044 (if (and iswitchb-use-fonts comps)
1045 (progn
1046 (setq first (car comps))
1047 (setq first (format "%s" first))
1048 (put-text-property 0 (length first) 'face
1049 (if (eq (length comps) 1)
1050 'font-lock-comment-face
1051 'font-lock-function-name-face)
1052 first)
1053 (setq comps (cons first (cdr comps)))
1054 ))
1055
1056 (cond ((null comps) (format " %sNo match%s"
1057 open-bracket-determined
1058 close-bracket-determined))
1059
1060 ((null (cdr comps)) ;one match
1061 (concat (if (and (> (length (car comps))
1062 (length name)))
1063 (concat open-bracket-determined
1064 ;; when there is one match, show the
1065 ;; matching buffer name in full
1066 (car comps)
1067 close-bracket-determined)
1068 "")
1069 (if (not iswitchb-use-fonts) " [Matched]")
1070 ))
1071 (t ;multiple matches
1072 (let* (
1073 ;;(most (try-completion name candidates predicate))
1074 (most nil)
1075 (most-len (length most))
1076 most-is-exact
1077 first
1078 (alternatives
1079 (apply
1080 (function concat)
1081 (cdr (apply
1082 (function nconc)
1083 (mapcar '(lambda (com)
1084 (if (= (length com) most-len)
1085 ;; Most is one exact match,
1086 ;; note that and leave out
1087 ;; for later indication:
1088 (progn
1089 (setq most-is-exact t)
1090 ())
1091 (list ","
1092 (substring com
1093 most-len))))
1094 comps))))))
1095
1096 (concat
1097
1098 ;; put in common completion item -- what you get by
1099 ;; pressing tab
1100 (if (> (length iswitchb-common-match-string) (length name))
1101 (concat open-bracket-determined
1102 (substring iswitchb-common-match-string
1103 (length name))
1104 close-bracket-determined)
1105 )
1106 ;; end of partial matches...
1107
1108 ;; think this bit can be ignored.
1109 (and (> most-len (length name))
1110 (concat open-bracket-determined
1111 (substring most (length name))
1112 close-bracket-determined))
1113
1114 ;; list all alternatives
1115 open-bracket-prospects
1116 (if most-is-exact
1117 (concat "," alternatives)
1118 alternatives)
1119 close-bracket-prospects)))
1120 )))
1121
1122 (defun iswitchb-minibuffer-setup ()
1123 "Set up minibuffer for iswitchb. Copied from
1124 `icomplete-minibuffer-setup-hook'."
1125 (if (iswitchb-entryfn-p)
1126 (progn
1127
1128 (make-local-variable 'iswitchb-use-mycompletion)
1129 (setq iswitchb-use-mycompletion t)
1130 (make-local-hook 'pre-command-hook)
1131 (add-hook 'pre-command-hook
1132 'iswitchb-pre-command
1133 nil t)
1134 (make-local-hook 'post-command-hook)
1135 (add-hook 'post-command-hook
1136 'iswitchb-post-command
1137 nil t)
1138
1139 (run-hooks 'iswitchb-minibuffer-setup-hook)
1140 )
1141 ))
1142
1143
1144 (defun iswitchb-pre-command ()
1145 "Run before command in iswitchb."
1146 (iswitchb-tidy))
1147
1148
1149 (defun iswitchb-post-command ()
1150 "Run after command in iswitchb."
1151 (iswitchb-exhibit)
1152 )
1153
1154
1155
1156 (defun iswitchb-tidy ()
1157 "Remove completions display, if any, prior to new user input.
1158 Copied from `icomplete-tidy'."
1159
1160 (if (and (boundp 'iswitchb-eoinput)
1161 iswitchb-eoinput)
1162
1163 (if (> iswitchb-eoinput (point-max))
1164 ;; Oops, got rug pulled out from under us - reinit:
1165 (setq iswitchb-eoinput (point-max))
1166 (let ((buffer-undo-list buffer-undo-list )) ; prevent entry
1167 (delete-region iswitchb-eoinput (point-max))))
1168
1169 ;; Reestablish the local variable 'cause minibuffer-setup is weird:
1170 (make-local-variable 'iswitchb-eoinput)
1171 (setq iswitchb-eoinput 1)))
1172
1173
1174 (defun iswitchb-entryfn-p ()
1175 "Return non-nil if `this-command' shows we are using iswitchb-buffer."
1176 (and (symbolp this-command) ; ignore lambda functions
1177 (member (symbol-name this-command)
1178 '("iswitchb-buffer"
1179 "iswitchb-buffer-other-frame"
1180 "iswitchb-buffer-other-window"))))
1181
1182 (defun iswitchb-summaries-to-end ()
1183 "Move the summaries to the end of the list. This is an example
1184 function which can be hooked on to `iswitchb-make-buflist-hook'.
1185 Any buffer matching the regexps `Summary' or `output\*$'are put to
1186 the end of the list."
1187
1188 (let ((summaries (delq nil (mapcar
1189 '(lambda (x)
1190 (if (or
1191 (string-match "Summary" x)
1192 (string-match "output\\*$" x))
1193 x))
1194 buflist)
1195 )))
1196
1197 (mapcar 'iswitchb-to-end summaries)))
1198
1199
1200
1201 ;;; HOOKS
1202 (add-hook 'minibuffer-setup-hook 'iswitchb-minibuffer-setup)
1203
1204 (provide 'iswitchb)
1205
1206 ;;; ISWITCHB.EL ends here