]> code.delx.au - gnu-emacs/blobdiff - lisp/bs.el
*** empty log message ***
[gnu-emacs] / lisp / bs.el
index 3d4468d7da4eb5278269e78d50c3981e4589c784..06c2474fa5d34c62caad648e8c32e32f2cbbef5d 100644 (file)
@@ -1,6 +1,7 @@
 ;;; bs.el --- menu for selecting and displaying buffers
 
-;; Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+;; Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+;;   2005, 2006, 2007 Free Software Foundation, Inc.
 ;; Author: Olaf Sylvester <Olaf.Sylvester@netsurf.de>
 ;; Maintainer: Olaf Sylvester <Olaf.Sylvester@netsurf.de>
 ;; Keywords: convenience
@@ -9,7 +10,7 @@
 
 ;; 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:
 
 ;; Version: 1.17
-;; X-URL: http://home.netsurf.de/olaf.sylvester/emacs
+;; X-URL: http://www.geekware.de/software/emacs
 ;;
 ;; The bs-package contains a main function bs-show for poping up a
 ;; buffer in a way similar to `list-buffers' and `electric-buffer-list':
@@ -65,7 +66,7 @@
 ;; The package bs combines the advantages of the Emacs functions
 ;; `list-buffers' and `electric-buffer-list'.
 ;;
-;; Additioal features for Buffer Selection Menu:
+;; Additional features for Buffer Selection Menu:
 ;;  - configurable list of buffers (show only files etc.).
 ;;  - comfortable way to change displayed subset of all buffers.
 ;;  - show sorted list of buffers.
   "Buffer Selection: Maintaining buffers by buffer menu."
   :version "21.1"
   :link '(emacs-commentary-link "bs")
-  :link '(url-link "http://home.netsurf.de/olaf.sylvester/emacs")
+  :link '(url-link "http://www.geekware.de/software/emacs")
   :group 'convenience)
 
-(defgroup bs-appearence nil
-  "Buffer Selection appearence: Appearence of bs buffer menu."
+(defgroup bs-appearance nil
+  "Buffer Selection appearance: Appearance of bs buffer menu."
   :group 'bs)
 
 (defcustom bs-attributes-list
     (""       2   2 left  "  "))
   "*List specifying the layout of a Buffer Selection Menu buffer.
 Each entry specifies a column and is a list of the form of:
-(HEADER MINIMUM-LENGTH MAXIMUM-LENGTH ALIGNMENT FUN-OR-STRING)
-HEADER         : string for header for first line or a function
-  which calculates column title.
-MINIMUM-LENGTH : minimum width of column (number or name of function).
-  The function must return a positive integer.
-MAXIMUM-LENGTH : maximum width of column (number or name of function)
-                 (currently ignored)
-ALIGNMENT      : alignment of column: (`left' `right' `middle')
-FUN-OR-STRING  : Name of a function for calculating the value or
-a string for a constant value.
-The function gets as parameter the buffer we have started
+\(HEADER MINIMUM-LENGTH MAXIMUM-LENGTH ALIGNMENT FUN-OR-STRING)
+
+HEADER         : String for header for first line or a function
+                 which calculates column title.
+MINIMUM-LENGTH : Minimum width of column (number or name of function).
+                 The function must return a positive integer.
+MAXIMUM-LENGTH : Maximum width of column (number or name of function)
+                 (currently ignored).
+ALIGNMENT      : Alignment of column (`left', `right', `middle').
+FUN-OR-STRING  : Name of a function for calculating the value or a
+                 string for a constant value.
+
+The function gets as parameter the buffer where we have started
 buffer selection and the list of all buffers to show.  The function must
-return a string representing the columns value."
-  :group 'bs-appearence
+return a string representing the column's value."
+  :group 'bs-appearance
   :type '(repeat sexp))
 
-(defvar bs--running-in-xemacs (string-match "XEmacs" (emacs-version))
-  "Non-nil when running under XEmacs.")
-
-
 (defun bs--make-header-match-string ()
   "Return a regexp matching the first line of a Buffer Selection Menu buffer."
   (let ((res "^\\(")
-       (ele  bs-attributes-list))
+       (ele bs-attributes-list))
     (while ele
       (setq res (concat res (car (car ele)) " *"))
       (setq ele (cdr ele)))
     (concat res "$\\)")))
 
-;;; Font-Lock-Settings
+;; Font-Lock-Settings
 (defvar bs-mode-font-lock-keywords
-  (list;; header in font-lock-type-face
+  (list ;; header in font-lock-type-face
    (list (bs--make-header-match-string)
         '(1 font-lock-type-face append) '(1 'bold append))
    ;; Buffername embedded by *
@@ -208,7 +207,7 @@ return a string representing the columns value."
 
 (defcustom bs-max-window-height 20
   "*Maximal window height of Buffer Selection Menu."
-  :group 'bs-appearence
+  :group 'bs-appearance
   :type 'integer)
 
 (defvar bs-dont-show-regexp nil
@@ -243,7 +242,8 @@ The function gets one argument - the buffer to test.")
 
 (defvar bs-buffer-sort-function nil
   "Sort function to sort the buffers that appear in Buffer Selection Menu.
-The functions gets two arguments - the buffers to compare.")
+The function gets two arguments - the buffers to compare.
+It must return non-nil if the first buffer should sort before the second.")
 
 (defcustom bs-maximal-buffer-name-column 45
   "*Maximum column width for buffer names.
@@ -251,7 +251,7 @@ The column for buffer names has dynamic width.  The width depends on
 maximal and minimal length of names of buffers to show.  The maximal
 width is bounded by `bs-maximal-buffer-name-column'.
 See also `bs-minimal-buffer-name-column'."
-  :group 'bs-appearence
+  :group 'bs-appearance
   :type 'integer)
 
 (defcustom bs-minimal-buffer-name-column 15
@@ -260,7 +260,7 @@ The column for buffer names has dynamic width.  The width depends on
 maximal and minimal length of names of buffers to show.  The minimal
 width is bounded by `bs-minimal-buffer-name-column'.
 See also `bs-maximal-buffer-name-column'."
-  :group 'bs-appearence
+  :group 'bs-appearance
   :type 'integer)
 
 (defconst bs-header-lines-length 2
@@ -269,22 +269,22 @@ See also `bs-maximal-buffer-name-column'."
 (defcustom bs-configurations
   '(("all" nil nil nil nil nil)
     ("files" nil nil nil bs-visits-non-file bs-sort-buffer-interns-are-last)
-    ("files-and-scratch" "^\\*scratch\\*" nil nil bs-visits-non-file
+    ("files-and-scratch" "^\\*scratch\\*$" nil nil bs-visits-non-file
      bs-sort-buffer-interns-are-last)
     ("all-intern-last" nil nil nil nil bs-sort-buffer-interns-are-last))
   "*List of all configurations you can use in the Buffer Selection Menu.
 A configuration describes which buffers appear in Buffer Selection Menu
-and describes the order of buffers.  A configuration is a list with
+and also the order of buffers.  A configuration is a list with
 six elements.  The first element is a string and describes the configuration.
 The following five elements represent the values for Buffer Selection Menu
-configurations variables `bs-dont-show-regexp', `bs-dont-show-function',
-`bs-must-show-regexp', `bs-must-show-function' and `bs-buffer-sort-function'.
+configuration variables `bs-must-show-regexp', `bs-must-show-function',
+`bs-dont-show-regexp', `bs-dont-show-function' and `bs-buffer-sort-function'.
 By setting these variables you define a configuration."
-  :group 'bs-appearence
+  :group 'bs-appearance
   :type '(repeat sexp))
 
 (defcustom bs-default-configuration "files"
-  "*Name of default configuration used by in the Buffer Selection Menu.
+  "*Name of default configuration used by the Buffer Selection Menu.
 \\<bs-mode-map>
 Will be changed using key \\[bs-select-next-configuration].
 Must be a string used in `bs-configurations' for naming a configuration."
@@ -300,7 +300,7 @@ Must be a string used in `bs-configurations' for naming a configuration."
 
 (defvar bs-current-configuration bs-default-configuration
   "Name of current configuration.
-Must be a string found in `bs-configurations' for naming a configuration.")
+Must be a string used in `bs-configurations' for naming a configuration.")
 
 (defcustom bs-cycle-configuration-name nil
   "*Name of configuration used when cycling through the buffer list.
@@ -312,32 +312,32 @@ Must be a string used in `bs-configurations' for naming a configuration."
 
 (defcustom bs-string-show-always "+"
   "*String added in column 1 indicating a buffer will always be shown."
-  :group 'bs-appearence
+  :group 'bs-appearance
   :type 'string)
 
 (defcustom bs-string-show-never "-"
   "*String added in column 1 indicating a buffer will never be shown."
-  :group 'bs-appearence
+  :group 'bs-appearance
   :type 'string)
 
 (defcustom bs-string-current "."
   "*String added in column 1 indicating the current buffer."
-  :group 'bs-appearence
+  :group 'bs-appearance
   :type 'string)
 
 (defcustom bs-string-current-marked "#"
   "*String added in column 1 indicating the current buffer when it is marked."
-  :group 'bs-appearence
+  :group 'bs-appearance
   :type 'string)
 
 (defcustom bs-string-marked ">"
   "*String added in column 1 indicating a marked buffer."
-  :group 'bs-appearence
+  :group 'bs-appearance
   :type 'string)
 
 (defcustom bs-string-show-normally  " "
-  "*String added in column 1 indicating a unmarked buffer."
-  :group 'bs-appearence
+  "*String added in column 1 indicating an unmarked buffer."
+  :group 'bs-appearance
   :type 'string)
 
 (defvar bs--name-entry-length 20
@@ -345,13 +345,13 @@ Must be a string used in `bs-configurations' for naming a configuration."
 Used internally, only.")
 
 ;; ----------------------------------------------------------------------
-;; Intern globals
+;; Internal globals
 ;; ----------------------------------------------------------------------
 
 (defvar bs-buffer-show-mark nil
   "Flag for the current mode for showing this buffer.
-A value of nil means buffer will be shown depending on the current on
-current configuration.
+A value of nil means buffer will be shown depending on the current
+configuration.
 A value of `never' means to never show the buffer.
 A value of `always' means to show buffer regardless of the configuration.")
 
@@ -362,7 +362,6 @@ A value of `always' means to show buffer regardless of the configuration.")
   (make-face 'region)
   (set-face-background 'region "gray75"))
 
-
 (defun bs--sort-by-name (b1 b2)
   "Compare buffers B1 and B2 by buffer name."
   (string< (buffer-name b1)
@@ -393,9 +392,9 @@ A value of `always' means to show buffer regardless of the configuration.")
     ("by nothing"  nil                  nil      nil))
   "*List of all possible sorting aspects for Buffer Selection Menu.
 You can add a new entry with a call to `bs-define-sort-function'.
-Each element is a list of four elements (NAME FUNCTION REGEXP-FOR-SORTING FACE)
+Each element is a list of four elements (NAME FUNCTION REGEXP-FOR-SORTING FACE).
 NAME specifies the sort order defined by function FUNCTION.
-FUNCTION nil means don't sort the buffer list.  Otherwise the functions
+FUNCTION nil means don't sort the buffer list.  Otherwise the function
 must have two parameters - the buffers to compare.
 REGEXP-FOR-SORTING is a regular expression which describes the
 column title to highlight.
@@ -441,7 +440,7 @@ naming a sort behavior.  Default is \"by nothing\" which means no sorting."
 
 (defvar bs--show-all nil
   "Flag whether showing all buffers regardless of current configuration.
-Non nil means to show all buffers.  Otherwise show buffers
+Non-nil means to show all buffers.  Otherwise show buffers
 defined by current configuration `bs-current-configuration'.")
 
 (defvar bs--window-config-coming-from nil
@@ -459,76 +458,68 @@ Used internally, only.")
 (defvar bs--marked-buffers nil
   "Currently marked buffers in Buffer Selection Menu.")
 
-(defvar bs-mode-map ()
+(defvar bs-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map " "       'bs-select)
+    (define-key map "f"       'bs-select)
+    (define-key map "v"       'bs-view)
+    (define-key map "!"       'bs-select-in-one-window)
+    (define-key map [mouse-2] 'bs-mouse-select)        ;; for GNU EMACS
+    (define-key map [button2] 'bs-mouse-select) ;; for XEmacs
+    (define-key map "F"       'bs-select-other-frame)
+    (let ((key ?1))
+      (while (<= key ?9)
+       (define-key map (char-to-string key) 'digit-argument)
+       (setq key (1+ key))))
+    (define-key map "-"       'negative-argument)
+    (define-key map "\e-"     'negative-argument)
+    (define-key map "o"       'bs-select-other-window)
+    (define-key map "\C-o"    'bs-tmp-select-other-window)
+    ;; for GNU EMACS
+    (define-key map [mouse-3] 'bs-mouse-select-other-frame)
+    ;; for XEmacs
+    (define-key map [button3] 'bs-mouse-select-other-frame)
+    (define-key map [up]      'bs-up)
+    (define-key map "n"       'bs-down)
+    (define-key map "p"       'bs-up)
+    (define-key map [down]    'bs-down)
+    (define-key map "\C-m"    'bs-select)
+    (define-key map "b"       'bs-bury-buffer)
+    (define-key map "s"       'bs-save)
+    (define-key map "S"       'bs-show-sorted)
+    (define-key map "a"       'bs-toggle-show-all)
+    (define-key map "d"       'bs-delete)
+    (define-key map "\C-d"    'bs-delete-backward)
+    (define-key map "k"       'bs-delete)
+    (define-key map "g"       'bs-refresh)
+    (define-key map "C"       'bs-set-configuration-and-refresh)
+    (define-key map "c"       'bs-select-next-configuration)
+    (define-key map "q"       'bs-kill)
+    ;; (define-key map "z"       'bs-kill)
+    (define-key map "\C-c\C-c" 'bs-kill)
+    (define-key map "\C-g"    'bs-abort)
+    (define-key map "\C-]"    'bs-abort)
+    (define-key map "%"       'bs-toggle-readonly)
+    (define-key map "~"       'bs-clear-modified)
+    (define-key map "M"       'bs-toggle-current-to-show)
+    (define-key map "+"       'bs-set-current-buffer-to-show-always)
+    ;;(define-key map "-"       'bs-set-current-buffer-to-show-never)
+    (define-key map "t"       'bs-visit-tags-table)
+    (define-key map "m"       'bs-mark-current)
+    (define-key map "u"       'bs-unmark-current)
+    (define-key map ">"       'scroll-right)
+    (define-key map "<"       'scroll-left)
+    (define-key map "?"       'bs-help)
+    map)
   "Keymap of `bs-mode'.")
 
-(if bs-mode-map
-    ()
-  (setq bs-mode-map (make-sparse-keymap))
-  (define-key bs-mode-map " "       'bs-select)
-  (define-key bs-mode-map "f"       'bs-select)
-  (define-key bs-mode-map "v"       'bs-view)
-  (define-key bs-mode-map "!"       'bs-select-in-one-window)
-  (define-key bs-mode-map [mouse-2] 'bs-mouse-select) ;; for GNU EMACS
-  (define-key bs-mode-map [button2] 'bs-mouse-select) ;; for XEmacs
-  (define-key bs-mode-map "F"       'bs-select-other-frame)
-
-  (let ((key ?1))
-    (while (<= key ?9)
-      (define-key bs-mode-map (char-to-string key) 'digit-argument)
-      (setq key (1+ key))))
-
-  (define-key bs-mode-map "-"       'negative-argument)
-  (define-key bs-mode-map "\e-"     'negative-argument)
-
-  (define-key bs-mode-map "o"       'bs-select-other-window)
-  (define-key bs-mode-map "\C-o"    'bs-tmp-select-other-window)
-  ;; for GNU EMACS
-  (define-key bs-mode-map [mouse-3] 'bs-mouse-select-other-frame)
-  ;; for XEmacs
-  (define-key bs-mode-map [button3] 'bs-mouse-select-other-frame)
-  (define-key bs-mode-map [up]      'bs-up)
-  (define-key bs-mode-map "n"       'bs-down)
-  (define-key bs-mode-map "p"       'bs-up)
-  (define-key bs-mode-map [down]    'bs-down)
-  (define-key bs-mode-map "\C-m"    'bs-select)
-  (define-key bs-mode-map "b"       'bs-bury-buffer)
-  (define-key bs-mode-map "s"       'bs-save)
-  (define-key bs-mode-map "S"       'bs-show-sorted)
-  (define-key bs-mode-map "a"       'bs-toggle-show-all)
-  (define-key bs-mode-map "d"       'bs-delete)
-  (define-key bs-mode-map "\C-d"    'bs-delete-backward)
-  (define-key bs-mode-map "k"       'bs-delete)
-  (define-key bs-mode-map "g"       'bs-refresh)
-  (define-key bs-mode-map "C"       'bs-set-configuration-and-refresh)
-  (define-key bs-mode-map "c"       'bs-select-next-configuration)
-  (define-key bs-mode-map "q"       'bs-kill)
-  ;; (define-key bs-mode-map "z"       'bs-kill)
-  (define-key bs-mode-map "\C-c\C-c" 'bs-kill)
-  (define-key bs-mode-map "\C-g"    'bs-abort)
-  (define-key bs-mode-map "\C-]"    'bs-abort)
-  (define-key bs-mode-map "%"       'bs-toggle-readonly)
-  (define-key bs-mode-map "~"       'bs-clear-modified)
-  (define-key bs-mode-map "M"       'bs-toggle-current-to-show)
-  (define-key bs-mode-map "+"       'bs-set-current-buffer-to-show-always)
-  ;;(define-key bs-mode-map "-"       'bs-set-current-buffer-to-show-never)
-  (define-key bs-mode-map "t"       'bs-visit-tags-table)
-  (define-key bs-mode-map "m"       'bs-mark-current)
-  (define-key bs-mode-map "u"       'bs-unmark-current)
-  (define-key bs-mode-map ">"       'scroll-right)
-  (define-key bs-mode-map "<"       'scroll-left)
-  (define-key bs-mode-map "\e\e"    nil)
-  (define-key bs-mode-map "\e\e\e"  'bs-kill)
-  (define-key bs-mode-map [escape escape escape] 'bs-kill)
-  (define-key bs-mode-map "?"       'bs-help))
-
 ;; ----------------------------------------------------------------------
 ;; Functions
 ;; ----------------------------------------------------------------------
 
 (defun bs-buffer-list (&optional list sort-description)
   "Return a list of buffers to be shown.
-LIST is a list of buffers to test for appearence in Buffer Selection Menu.
+LIST is a list of buffers to test for appearance in Buffer Selection Menu.
 The result list depends on the global variables `bs-dont-show-regexp',
 `bs-must-show-regexp', `bs-dont-show-function', `bs-must-show-function'
 and `bs-buffer-sort-function'.
@@ -556,9 +547,7 @@ a special function.  SORT-DESCRIPTION is an element of `bs-sort-functions'."
             (extern-must-show-from-fun (and bs-must-show-function
                                             (funcall bs-must-show-function
                                                      (car list))))
-            (show-flag (save-excursion
-                         (set-buffer (car list))
-                         bs-buffer-show-mark)))
+            (show-flag (buffer-local-value 'bs-buffer-show-mark (car list))))
        (if (or (eq show-flag 'always)
                (and (or bs--show-all (not (eq show-flag 'never)))
                     (not int-show-never)
@@ -593,8 +582,8 @@ a special function.  SORT-DESCRIPTION is an element of `bs-sort-functions'."
 
 (defun bs--redisplay (&optional keep-line-p sort-description)
   "Redisplay whole Buffer Selection Menu.
-If KEEP-LINE-P is non nil the point will stay on current line.
-SORT-DESCRIPTION is an element of `bs-sort-functions'"
+If KEEP-LINE-P is non-nil the point will stay on current line.
+SORT-DESCRIPTION is an element of `bs-sort-functions'."
   (let ((line (1+ (count-lines 1 (point)))))
     (bs-show-in-buffer (bs-buffer-list nil sort-description))
     (if keep-line-p
@@ -624,12 +613,29 @@ actually the line which begins with character in `bs-string-current' or
     (format "Show buffer by configuration %S"
            bs-current-configuration)))
 
-(defun bs-mode ()
+(defun bs--track-window-changes (frame)
+  "Track window changes to refresh the buffer list.
+Used from `window-size-change-functions'."
+  (let ((win (get-buffer-window "*buffer-selection*" frame)))
+    (when win
+      (with-selected-window win
+       (bs--set-window-height)))))
+
+(defun bs--remove-hooks ()
+  "Remove `bs--track-window-changes' and auxiliary hooks."
+  (remove-hook 'window-size-change-functions 'bs--track-window-changes)
+  ;; Remove itself
+  (remove-hook 'kill-buffer-hook 'bs--remove-hooks t)
+  (remove-hook 'change-major-mode-hook 'bs--remove-hooks t))
+
+(put 'bs-mode 'mode-class 'special)
+
+(define-derived-mode bs-mode () "Buffer-Selection-Menu"
   "Major mode for editing a subset of Emacs' buffers.
 \\<bs-mode-map>
 Aside from two header lines each line describes one buffer.
 Move to a line representing the buffer you want to edit and select
-buffer by \\[bs-select] or SPC. Abort buffer list with \\[bs-kill].
+buffer by \\[bs-select] or SPC.  Abort buffer list with \\[bs-kill].
 There are many key commands similar to `Buffer-menu-mode' for
 manipulating the buffer list and buffers.
 For faster navigation each digit key is a digit argument.
@@ -640,8 +646,8 @@ For faster navigation each digit key is a digit argument.
 \\[bs-tmp-select-other-window] -- make another window display that buffer and
     remain in Buffer Selection Menu.
 \\[bs-mouse-select] -- select current line's buffer and other marked buffers.
-\\[bs-save] -- save current line's buffer immediatly.
-\\[bs-delete] -- kill current line's buffer immediatly.
+\\[bs-save] -- save current line's buffer immediately.
+\\[bs-delete] -- kill current line's buffer immediately.
 \\[bs-toggle-readonly] -- toggle read-only status of current line's buffer.
 \\[bs-clear-modified] -- clear modified-flag on that buffer.
 \\[bs-mark-current] -- mark current line's buffer to be displayed.
@@ -652,29 +658,39 @@ apply selected configuration.
 \\[bs-select-next-configuration] -- select and apply next \
 available Buffer Selection Menu configuration.
 \\[bs-kill] -- leave Buffer Selection Menu without a selection.
-\\[bs-toggle-current-to-show] -- toggle status of appearence .
+\\[bs-toggle-current-to-show] -- toggle status of appearance.
 \\[bs-set-current-buffer-to-show-always] -- mark current line's buffer \
 to show always.
-\\[bs-visit-tags-table] -- call `visit-tags-table' on current line'w buffer.
+\\[bs-visit-tags-table] -- call `visit-tags-table' on current line's buffer.
 \\[bs-help] -- display this help text."
-  (interactive)
-  (kill-all-local-variables)
-  (use-local-map bs-mode-map)
   (make-local-variable 'font-lock-defaults)
   (make-local-variable 'font-lock-verbose)
-  (setq major-mode 'bs-mode
-       mode-name "Buffer-Selection-Menu"
-       buffer-read-only t
+  (make-local-variable 'font-lock-global-modes)
+  (buffer-disable-undo)
+  (setq buffer-read-only t
        truncate-lines t
+       show-trailing-whitespace nil
+       font-lock-global-modes '(not bs-mode)
        font-lock-defaults '(bs-mode-font-lock-keywords t)
        font-lock-verbose nil)
-  (run-hooks 'bs-mode-hook))
+  (add-hook 'window-size-change-functions 'bs--track-window-changes)
+  (add-hook 'kill-buffer-hook 'bs--remove-hooks nil t)
+  (add-hook 'change-major-mode-hook 'bs--remove-hooks nil t))
+
+(defun bs--restore-window-config ()
+  "Restore window configuration on the current frame."
+  (when bs--window-config-coming-from
+    (let ((frame (selected-frame)))
+      (unwind-protect
+          (set-window-configuration bs--window-config-coming-from)
+       (select-frame frame)))
+    (setq bs--window-config-coming-from nil)))
 
 (defun bs-kill ()
-  "Let buffer disappear and reset window-configuration."
+  "Let buffer disappear and reset window configuration."
   (interactive)
   (bury-buffer (current-buffer))
-  (set-window-configuration bs--window-config-coming-from))
+  (bs--restore-window-config))
 
 (defun bs-abort ()
   "Ding and leave Buffer Selection Menu without a selection."
@@ -694,30 +710,14 @@ Refresh whole Buffer Selection Menu."
   (interactive)
   (bs--redisplay t))
 
-(defun bs--window-for-buffer (buffer-name)
-  "Return a window showing a buffer with name BUFFER-NAME.
-Take only windows of current frame into account.
-Return nil if there is no such buffer."
-  (let ((window nil))
-    (walk-windows (lambda (wind)
-                   (if (string= (buffer-name (window-buffer wind))
-                                buffer-name)
-                       (setq window wind))))
-    window))
-
 (defun bs--set-window-height ()
   "Change the height of the selected window to suit the current buffer list."
   (unless (one-window-p t)
-    (shrink-window (- (window-height (selected-window))
-                     ;; window-height in xemacs includes mode-line
-                     (+ (if bs--running-in-xemacs 3 1)
-                        bs-header-lines-length
-                        (min (length bs-current-list)
-                             bs-max-window-height))))))
+    (fit-window-to-buffer (selected-window) bs-max-window-height)))
 
 (defun bs--current-buffer ()
   "Return buffer on current line.
-Raise an error if not an a buffer line."
+Raise an error if not on a buffer line."
   (beginning-of-line)
   (let ((line (+ (- bs-header-lines-length)
                 (count-lines 1 (point)))))
@@ -743,14 +743,14 @@ Leave Buffer Selection Menu."
 (defun bs-select ()
   "Select current line's buffer and other marked buffers.
 If there are no marked buffers the window configuration before starting
-Buffer Selectin Menu will be restored.
+Buffer Selection Menu will be restored.
 If there are marked buffers each marked buffer and the current line's buffer
 will be selected in a window.
 Leave Buffer Selection Menu."
   (interactive)
   (let ((buffer (bs--current-buffer)))
     (bury-buffer (current-buffer))
-    (set-window-configuration bs--window-config-coming-from)
+    (bs--restore-window-config)
     (switch-to-buffer buffer)
     (if bs--marked-buffers
        ;; Some marked buffers for selection
@@ -768,13 +768,13 @@ Leave Buffer Selection Menu."
 
 (defun bs-select-other-window ()
   "Select current line's buffer by `switch-to-buffer-other-window'.
-The window configuration before starting Buffer Selectin Menu will be restored
+The window configuration before starting Buffer Selection Menu will be restored
 unless there is no other window.  In this case a new window will be created.
 Leave Buffer Selection Menu."
   (interactive)
   (let ((buffer (bs--current-buffer)))
     (bury-buffer (current-buffer))
-    (set-window-configuration bs--window-config-coming-from)
+    (bs--restore-window-config)
     (switch-to-buffer-other-window buffer)))
 
 (defun bs-tmp-select-other-window ()
@@ -790,13 +790,13 @@ Leave Buffer Selection Menu."
   (interactive)
   (let ((buffer (bs--current-buffer)))
     (bury-buffer (current-buffer))
-    (set-window-configuration bs--window-config-coming-from)
+    (bs--restore-window-config)
     (switch-to-buffer-other-frame buffer)))
 
 (defun bs-mouse-select-other-frame (event)
   "Select selected line's buffer in new created frame.
 Leave Buffer Selection Menu.
-EVENT: a mouse click EVENT."
+EVENT: a mouse click event."
   (interactive "e")
   (mouse-set-point event)
   (bs-select-other-frame))
@@ -875,9 +875,7 @@ always.  Otherwise it is marked to show never."
   "Set value `bs-buffer-show-mark' of buffer BUFFER to WHAT.
 Redisplay current line and display a message describing
 the status of buffer on current line."
-  (save-excursion
-    (set-buffer buffer)
-    (setq bs-buffer-show-mark what))
+  (with-current-buffer buffer (setq bs-buffer-show-mark what))
   (bs--update-current-line)
   (bs--set-window-height)
   (bs--show-config-message what))
@@ -926,8 +924,9 @@ WHAT is a value of nil, `never', or `always'."
   (interactive)
   (let ((current (bs--current-buffer))
        (inhibit-read-only t))
+    (unless (kill-buffer current)
+      (error "Buffer was not deleted"))
     (setq bs-current-list (delq current bs-current-list))
-    (kill-buffer current)
     (beginning-of-line)
     (delete-region (point) (save-excursion
                             (end-of-line)
@@ -948,7 +947,7 @@ WHAT is a value of nil, `never', or `always'."
       (bs-up 1))))
 
 (defun bs-show-sorted ()
-  "Show buffer list sorted by buffer name."
+  "Show buffer list sorted by next sort aspect."
   (interactive)
   (setq bs--current-sort-function
        (bs-next-config-aux (car bs--current-sort-function)
@@ -984,7 +983,7 @@ Default is `bs--current-sort-function'."
 
 (defun bs-toggle-readonly ()
   "Toggle read-only status for buffer on current line.
-Uses Function `vc-toggle-read-only'."
+Uses function `vc-toggle-read-only'."
   (interactive)
   (let ((buffer (bs--current-buffer)))
     (save-excursion
@@ -1018,14 +1017,11 @@ Uses Function `vc-toggle-read-only'."
 (defun bs--up ()
   "Move cursor vertically up one line.
 If on top of buffer list go to last line."
-  (interactive "p")
-  (previous-line 1)
-  (if (<= (count-lines 1 (point)) (1- bs-header-lines-length))
-      (progn
-       (goto-char (point-max))
-       (beginning-of-line)
-       (recenter -1))
-    (beginning-of-line)))
+  (if (> (count-lines 1 (point)) bs-header-lines-length)
+      (forward-line -1)
+    (goto-char (point-max))
+    (beginning-of-line)
+    (recenter -1)))
 
 (defun bs-down (arg)
   "Move cursor vertically down ARG lines in Buffer Selection Menu."
@@ -1037,19 +1033,18 @@ If on top of buffer list go to last line."
 (defun bs--down ()
   "Move cursor vertically down one line.
 If at end of buffer list go to first line."
-  (let ((last (line-end-position)))
-    (if (eq last (point-max))
-       (goto-line (1+ bs-header-lines-length))
-      (next-line 1))))
+  (if (eq (line-end-position) (point-max))
+      (goto-line (1+ bs-header-lines-length))
+    (forward-line 1)))
 
 (defun bs-visits-non-file (buffer)
-  "Return t or nil whether BUFFER visits no file.
+  "Return whether BUFFER visits no file.
 A value of t means BUFFER belongs to no file.
 A value of nil means BUFFER belongs to a file."
   (not (buffer-file-name buffer)))
 
 (defun bs-sort-buffer-interns-are-last (b1 b2)
-  "Function for sorting intern buffers B1 and B2 at the end of all buffers."
+  "Function for sorting internal buffers at the end of all buffers."
   (string-match "^\\*" (buffer-name b2)))
 
 ;; ----------------------------------------------------------------------
@@ -1057,7 +1052,7 @@ A value of nil means BUFFER belongs to a file."
 ;; ----------------------------------------------------------------------
 
 (defun bs-config-clear ()
-  "*Reset all variables which specify a configuration.
+  "Reset all variables which specify a configuration.
 These variables are `bs-dont-show-regexp', `bs-must-show-regexp',
 `bs-dont-show-function', `bs-must-show-function' and
 `bs-buffer-sort-function'."
@@ -1070,7 +1065,7 @@ These variables are `bs-dont-show-regexp', `bs-must-show-regexp',
 (defun bs-config--only-files ()
   "Define a configuration for showing only buffers visiting a file."
   (bs-config-clear)
-  (setq;; I want to see *-buffers at the end
+  (setq ;; I want to see *-buffers at the end
    bs-buffer-sort-function 'bs-sort-buffer-interns-are-last
    ;; Don't show files who don't belong to a file
    bs-dont-show-function 'bs-visits-non-file))
@@ -1078,12 +1073,12 @@ These variables are `bs-dont-show-regexp', `bs-must-show-regexp',
 (defun bs-config--files-and-scratch ()
   "Define a configuration for showing buffer *scratch* and file buffers."
   (bs-config-clear)
-  (setq;; I want to see *-buffers at the end
+  (setq ;; I want to see *-buffers at the end
    bs-buffer-sort-function 'bs-sort-buffer-interns-are-last
    ;; Don't show files who don't belong to a file
    bs-dont-show-function 'bs-visits-non-file
    ;; Show *scratch* buffer.
-   bs-must-show-regexp "^\\*scratch\\*"))
+   bs-must-show-regexp "^\\*scratch\\*$"))
 
 (defun bs-config--all ()
   "Define a configuration for showing all buffers.
@@ -1092,7 +1087,7 @@ Reset all according variables by `bs-config-clear'."
 
 (defun bs-config--all-intern-last ()
   "Define a configuration for showing all buffers.
-Intern buffers appear at end of all buffers."
+Internal buffers appear at end of all buffers."
   (bs-config-clear)
   ;; I want to see *-buffers at the end
   (setq bs-buffer-sort-function 'bs-sort-buffer-interns-are-last))
@@ -1154,7 +1149,7 @@ will be used."
     (setq bs-default-configuration bs-current-configuration)
     (bs--redisplay t)
     (bs--set-window-height)
-    (bs-message-without-log "Selected config: %s" (car config))))
+    (bs-message-without-log "Selected configuration: %s" (car config))))
 
 (defun bs-show-in-buffer (list)
   "Display buffer list LIST in buffer *buffer-selection*.
@@ -1183,7 +1178,8 @@ and move point to current buffer."
     (bs--set-window-height)
     (bs--goto-current-buffer)
     (font-lock-fontify-buffer)
-    (bs-apply-sort-faces)))
+    (bs-apply-sort-faces)
+    (set-buffer-modified-p nil)))
 
 (defun bs-next-buffer (&optional buffer-list sorting-p)
   "Return next buffer and buffer list for buffer cycling in BUFFER-LIST.
@@ -1214,12 +1210,12 @@ buffer list used for buffer cycling."
 
 (defun bs-message-without-log (&rest args)
   "Like `message' but don't log it on the message log.
-All arguments ARGS are transfered to function `message'."
+All arguments ARGS are transferred to function `message'."
   (let ((message-log-max nil))
     (apply 'message args)))
 
 (defvar bs--cycle-list nil
-  "Currentyl buffer list used for cycling.")
+  "Current buffer list used for cycling.")
 
 ;;;###autoload
 (defun bs-cycle-next ()
@@ -1232,9 +1228,8 @@ by buffer configuration `bs-cycle-configuration-name'."
        (bs-must-show-regexp   bs-must-show-regexp)
        (bs-dont-show-function bs-dont-show-function)
        (bs-must-show-function bs-must-show-function)
-       (bs--show-all          bs--show-all))
-    (if bs-cycle-configuration-name
-       (bs-set-configuration bs-cycle-configuration-name))
+       (bs--show-all          nil))
+    (bs-set-configuration (or bs-cycle-configuration-name bs-default-configuration))
     (let ((bs-buffer-sort-function nil)
          (bs--current-sort-function nil))
       (let* ((tupel (bs-next-buffer (if (or (eq last-command
@@ -1244,15 +1239,17 @@ by buffer configuration `bs-cycle-configuration-name'."
                                        bs--cycle-list)))
             (next (car tupel))
             (cycle-list (cdr tupel)))
+       (unless (window-dedicated-p (selected-window))
+         ;; We don't want the frame iconified if the only window in the frame
+         ;; happens to be dedicated; let's get the error from switch-to-buffer
+         (bury-buffer))
+       (switch-to-buffer next)
        (setq bs--cycle-list (append (cdr cycle-list)
                                     (list (car cycle-list))))
-       (bury-buffer)
-       (switch-to-buffer next)
        (bs-message-without-log "Next buffers: %s"
                                (or (cdr bs--cycle-list)
                                    "this buffer"))))))
 
-
 ;;;###autoload
 (defun bs-cycle-previous ()
   "Select previous buffer defined by buffer cycling.
@@ -1264,9 +1261,8 @@ by buffer configuration `bs-cycle-configuration-name'."
        (bs-must-show-regexp   bs-must-show-regexp)
        (bs-dont-show-function bs-dont-show-function)
        (bs-must-show-function bs-must-show-function)
-       (bs--show-all          bs--show-all))
-    (if bs-cycle-configuration-name
-       (bs-set-configuration bs-cycle-configuration-name))
+       (bs--show-all          nil))
+    (bs-set-configuration (or bs-cycle-configuration-name bs-default-configuration))
     (let ((bs-buffer-sort-function nil)
          (bs--current-sort-function nil))
       (let* ((tupel (bs-previous-buffer (if (or (eq last-command
@@ -1276,9 +1272,9 @@ by buffer configuration `bs-cycle-configuration-name'."
                                            bs--cycle-list)))
             (prev-buffer (car tupel))
             (cycle-list (cdr tupel)))
+       (switch-to-buffer prev-buffer)
        (setq bs--cycle-list (append (last cycle-list)
                                     (reverse (cdr (reverse cycle-list)))))
-       (switch-to-buffer prev-buffer)
        (bs-message-without-log "Previous buffers: %s"
                                (or (reverse (cdr bs--cycle-list))
                                    "this buffer"))))))
@@ -1296,11 +1292,11 @@ or a string."
 (defun bs--get-marked-string (start-buffer all-buffers)
   "Return a string which describes whether current buffer is marked.
 START-BUFFER is the buffer where we started buffer selection.
-ALL-BUFFERS is the list of buffer appearing in Buffer Selection Menu.
+ALL-BUFFERS is the list of buffers appearing in Buffer Selection Menu.
 The result string is one of `bs-string-current', `bs-string-current-marked',
 `bs-string-marked', `bs-string-show-normally', `bs-string-show-never', or
 `bs-string-show-always'."
-  (cond;; current buffer is the buffer we started buffer selection.
+  (cond ;; current buffer is the buffer we started buffer selection.
    ((eq (current-buffer) start-buffer)
     (if (memq (current-buffer) bs--marked-buffers)
        bs-string-current-marked        ; buffer is marked
@@ -1321,19 +1317,19 @@ The result string is one of `bs-string-current', `bs-string-current-marked',
 (defun bs--get-modified-string (start-buffer all-buffers)
   "Return a string which describes whether current buffer is modified.
 START-BUFFER is the buffer where we started buffer selection.
-ALL-BUFFERS is the list of buffer appearing in Buffer Selection Menu."
+ALL-BUFFERS is the list of buffers appearing in Buffer Selection Menu."
   (if (buffer-modified-p) "*" " "))
 
 (defun bs--get-readonly-string (start-buffer all-buffers)
   "Return a string which describes whether current buffer is read only.
 START-BUFFER is the buffer where we started buffer selection.
-ALL-BUFFERS is the list of buffer appearing in Buffer Selection Menu."
+ALL-BUFFERS is the list of buffers appearing in Buffer Selection Menu."
   (if buffer-read-only "%" " "))
 
 (defun bs--get-size-string (start-buffer all-buffers)
   "Return a string which describes the size of current buffer.
 START-BUFFER is the buffer where we started buffer selection.
-ALL-BUFFERS is the list of buffer appearing in Buffer Selection Menu."
+ALL-BUFFERS is the list of buffers appearing in Buffer Selection Menu."
   (int-to-string (buffer-size)))
 
 (defun bs--get-name (start-buffer all-buffers)
@@ -1341,19 +1337,15 @@ ALL-BUFFERS is the list of buffer appearing in Buffer Selection Menu."
 The name of current buffer gets additional text properties
 for mouse highlighting.
 START-BUFFER is the buffer where we started buffer selection.
-ALL-BUFFERS is the list of buffer appearing in Buffer Selection Menu."
-  (let ((name (copy-sequence (buffer-name))))
-    (put-text-property 0 (length name) 'mouse-face 'highlight name)
-    (if (< (length name) bs--name-entry-length)
-       (concat name
-               (make-string (- bs--name-entry-length (length name)) ? ))
-      name)))
-
+ALL-BUFFERS is the list of buffers appearing in Buffer Selection Menu."
+  (propertize (buffer-name)
+              'help-echo "mouse-2: select this buffer, mouse-3: select in other frame"
+              'mouse-face 'highlight))
 
 (defun bs--get-mode-name (start-buffer all-buffers)
   "Return the name of mode of current buffer for Buffer Selection Menu.
 START-BUFFER is the buffer where we started buffer selection.
-ALL-BUFFERS is the list of buffer appearing in Buffer Selection Menu."
+ALL-BUFFERS is the list of buffers appearing in Buffer Selection Menu."
   mode-name)
 
 (defun bs--get-file-name (start-buffer all-buffers)
@@ -1362,14 +1354,12 @@ This is the variable `buffer-file-name' of current buffer.
 If current mode is `dired-mode' or `shell-mode' it returns the
 default directory.
 START-BUFFER is the buffer where we started buffer selection.
-ALL-BUFFERS is the list of buffer appearing in Buffer Selection Menu."
-  (let ((string (copy-sequence (if (member major-mode
-                                          '(shell-mode dired-mode))
-                                  default-directory
-                                (or buffer-file-name "")))))
-    (put-text-property 0 (length string) 'mouse-face 'highlight string)
-    string))
-
+ALL-BUFFERS is the list of buffers appearing in Buffer Selection Menu."
+  (propertize (if (member major-mode '(shell-mode dired-mode))
+                  default-directory
+                (or buffer-file-name ""))
+              'mouse-face 'highlight
+              'help-echo "mouse-2: select this buffer, mouse-3: select in other frame"))
 
 (defun bs--insert-one-entry (buffer)
   "Generate one entry for buffer BUFFER in Buffer Selection Menu.
@@ -1400,20 +1390,19 @@ normally *buffer-selection*."
     string))
 
 (defun bs--format-aux (string align len)
-  "Generate a string with STRING with alignment ALIGN and length LEN.
+  "Pad STRING to length LEN with alignment ALIGN.
 ALIGN is one of the symbols `left', `middle', or `right'."
-  (let ((length (length string)))
-    (if (>= length len)
-       string
-      (if (eq 'right align)
-         (concat (make-string (- len length) ? ) string)
-       (concat string (make-string (- len length) ? ))))))
+  (let* ((width (length string))
+         (len (max len width)))
+    (format (format "%%%s%ds" (if (eq align 'right) "" "-") len)
+            (if (eq align 'middle)
+                (concat (make-string (/ (- len width) 2) ?\s) string)
+              string))))
 
 (defun bs--show-header ()
   "Insert header for Buffer Selection Menu in current buffer."
-  (mapcar '(lambda (string)
-            (insert string "\n"))
-         (bs--create-header)))
+  (dolist (string (bs--create-header))
+    (insert string "\n")))
 
 (defun bs--get-name-length ()
   "Return value of `bs--name-entry-length'."
@@ -1436,7 +1425,7 @@ ALIGN is one of the symbols `left', `middle', or `right'."
                   "")))
 
 (defun bs--show-with-configuration (name &optional arg)
-  "Display buffer list of configuration with NAME name.
+  "Display buffer list of configuration with name NAME.
 Set configuration NAME and determine window for Buffer Selection Menu.
 Unless current buffer is buffer *buffer-selection* we have to save
 the buffer we started Buffer Selection Menu and the current window
@@ -1451,17 +1440,20 @@ for buffer selection."
     (unless (string= "*buffer-selection*" (buffer-name))
       ;; Only when not in buffer *buffer-selection*
       ;; we have to set the buffer we started the command
-      (progn
-       (setq bs--buffer-coming-from (current-buffer))
-       (setq bs--window-config-coming-from (current-window-configuration))))
+      (setq bs--buffer-coming-from (current-buffer)))
     (let ((liste (bs-buffer-list))
-         (active-window (bs--window-for-buffer "*buffer-selection*")))
+         (active-window (get-window-with-predicate
+                          (lambda (w)
+                            (string= (buffer-name (window-buffer w))
+                                     "*buffer-selection*"))
+                         nil (selected-frame))))
       (if active-window
          (select-window active-window)
-       (if (> (window-height (selected-window)) 7)
-           (progn
-             (split-window-vertically)
-             (other-window 1))))
+       (bs--restore-window-config)
+       (setq bs--window-config-coming-from (current-window-configuration))
+       (when (> (window-height (selected-window)) 7)
+          (split-window-vertically)
+          (other-window 1)))
       (bs-show-in-buffer liste)
       (bs-message-without-log "%s" (bs--current-config-message)))))
 
@@ -1470,7 +1462,7 @@ for buffer selection."
 If PREFIX-ARG is nil return `bs-default-configuration'.
 If PREFIX-ARG is an integer return PREFIX-ARG element of `bs-configurations'.
 Otherwise return `bs-alternative-configuration'."
-  (cond;; usually activation
+  (cond ;; usually activation
    ((null prefix-arg)
     bs-default-configuration)
    ;; call with integer as prefix argument
@@ -1496,7 +1488,7 @@ Otherwise return `bs-alternative-configuration'."
   "Make a menu of buffers so you can manipulate buffers or the buffer list.
 \\<bs-mode-map>
 There are many key commands similar to `Buffer-menu-mode' for
-manipulating buffer list and buffers itself.
+manipulating the buffer list and the buffers themselves.
 User can move with [up] or [down], select a buffer
 by \\[bs-select] or [SPC]\n
 Type \\[bs-kill] to leave Buffer Selection Menu without a selection.
@@ -1508,7 +1500,8 @@ name of buffer configuration."
   (setq bs--marked-buffers nil)
   (bs--show-with-configuration (bs--configuration-name-for-prefix-arg arg)))
 
-;;; Now provide feature bs
+;; Now provide feature bs
 (provide 'bs)
 
+;;; arch-tag: c0d9ab34-bf06-4368-ae9d-af88878e6802
 ;;; bs.el ends here