Commits

Anonymous committed 1f3f9e9

Add buff-menu+ and ruby tweaks

Comments (0)

Files changed (4)

.emacs.d/buff-menu+.el

+;;; buff-menu+.el --- Extensions to `buff-menu.el'.    -*- coding:utf-8 -*-
+;;
+;; Filename: buff-menu+.el
+;; Description: Extensions to `buff-menu.el'
+;; Author: Drew Adams
+;; Maintainer: Drew Adams (concat "drew.adams" "@" "oracle" ".com")
+;; Copyright (C) 1996-2011, Drew Adams, all rights reserved.
+;; Created: Mon Sep 11 10:29:56 1995
+;; Version: 21.0
+;; Last-Updated: Thu Oct 27 15:58:30 2011 (-0700)
+;;           By: dradams
+;;     Update #: 2736
+;; URL: http://www.emacswiki.org/cgi-bin/wiki/buff-menu+.el
+;; Keywords: mouse, local, convenience
+;; Compatibility: GNU Emacs: 20.x, 21.x, 22.x, 23.x
+;;
+;; Features that might be required by this library:
+;;
+;;   `avoid', `fit-frame', `frame-fns', `misc-cmds', `misc-fns'.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Commentary:
+;;
+;;    Extensions to `buff-menu.el', including: new bindings, faces,
+;;    and menus; selective column display; and directional column
+;;    sorting.
+;;
+;;    Note: By default, the buffer menu is shown in a different
+;;          window.  If you prefer to show it in the current window,
+;;          then just do this:
+;;
+;;          (add-to-list 'same-window-buffer-names "*Buffer List*")
+;;
+;;  Faces defined here:
+;;
+;;    `buffer-menu-headings', `buffer-menu-current-buffer',
+;;    `buffer-menu-directory-buffer', `buffer-menu-flagged-buffer',
+;;    `buffer-menu-marked-buffer', `buffer-menu-star-buffer',
+;;    `buffer-menu-view-mark', `buffer-menu-delete-mark',
+;;    `buffer-menu-save-mark', `buffer-menu-modified-mark',
+;;    `buffer-menu-read-only-mark', `buffer-menu-buffer-name',
+;;    `buffer-menu-mode', `buffer-menu-size', `buffer-menu-time',
+;;    `buffer-menu-file-name'.
+;;
+;;  User options defined here (Emacs 22+):
+;;
+;;    `Buffer-menu-file-flag', `Buffer-menu-mode-flag',
+;;    `Buffer-menu-time-flag', `Buffer-menu-time-format'.
+;;
+;;  Commands defined here:
+;;
+;;    `buffer-menu-decrease-max-buffer+size' (Emacs 22+),
+;;    `Buffer-menu-delete-flagged',
+;;    `buffer-menu-increase-max-buffer+size' (Emacs 22+),
+;;    `Buffer-menu-mouse-3-menu', `Buffer-menu-mouse-delete',
+;;    `Buffer-menu-mouse-execute', `Buffer-menu-mouse-modified',
+;;    `Buffer-menu-mouse-other-window', `Buffer-menu-mouse-save',
+;;    `Buffer-menu-mouse-unmark', `buffer-menu-toggle-file-column'
+;;    (Emacs 22+), `buffer-menu-toggle-mode-column' (Emacs 22+),
+;;    `buffer-menu-toggle-time-column' (Emacs 22+),
+;;    `buffer-menu-toggle-time-format' (Emacs 22+).
+;;
+;;  Internal variables defined here:
+;;
+;;    `buffer-menu-buffer-name',
+;;    `Buffer-menu-buffer+size-computed-width',
+;;    `buffer-menu-current-buffer', `buffer-menu-directory-buffer',
+;;    `buffer-menu-flagged-buffer', `buffer-menu-marked-buffer',
+;;    `buffer-menu-star-buffer', `buffer-menu-delete-mark',
+;;    `buffer-menu-file-name', `buffer-menu-font-lock-keywords',
+;;    `buffer-menu-headings', `buffer-menu-mode',
+;;    `buffer-menu-modified-mark', `buffer-menu-read-only-mark',
+;;    `buffer-menu-save-mark', `buffer-menu-size', `buffer-menu-time',
+;;    `buffer-menu-view-mark'.
+;;
+;;  Other functions defined here:
+;;
+;;    `Buffer-menu-fontify-and-adjust-frame',
+;;    `buffer-menu-set-default-value'.
+;;
+;;
+;;  ***** NOTE: The following user option (variable) defined in
+;;              `buff-menu.el' has been REDEFINED HERE:
+;;
+;;  `Buffer-menu-sort-column' - A user option now. Numeric, default=1.
+;;
+;;
+;;  ***** NOTE: The following hook defined in `buff-menu.el'
+;;              has been REDEFINED HERE:
+;;
+;;  `buffer-menu-mode-hook' - Fontifies buffer and fits its frame.
+;;
+;;
+;;  ***** NOTE: The following functions defined in `buff-menu.el'
+;;              have been REDEFINED HERE:
+;;
+;;  `buffer-menu' -
+;;     1. Different help message.
+;;     2. Prefix ARG =< 0 now means list (all) buffers alphabetically.
+;;        (It used to mean the same as ARG > 0.)
+;;        Prefix ARG >= 0 means list just file buffers.
+;;     3. Use pop-to-buffer instead of switch-to-buffer.
+;;  `Buffer-menu-beginning' - Protected with `boundp' for Emacs 20.
+;;  `Buffer-menu-buffer+size' - Use computed width for Buffer + Size.
+;;  `Buffer-menu-execute' - Deletes windows (frame) when kills buffer.
+;;  `Buffer-menu-make-sort-button' -
+;;     1. If same column as last sort, flip direction of sort.
+;;     2. Column header face indicates sort direction.
+;;     3. CRM is indicated by COLUMN = 1, not by nil COLUMN.
+;;  `Buffer-menu-mode' -
+;;     1. Doc string reflects new bindings.
+;;     2. mouse-face on whole line, not just buffer name.
+;;  `Buffer-menu-select' - When Buffer Menu is `window-dedicated-p',
+;;                         uses `pop-to-buffer' to display.
+;;  `Buffer-menu-sort' -
+;;     1. Allow negative COLUMN. Allow COLUMN = 1 or -1.
+;;     2. When COLUMN = `Buffer-menu-sort-column', then flip that.
+;;     3. Added message at end indicating the kind of sort.
+;;  `list-buffers-noselect' - Use longest buffer name+size to indent.
+;;                          - Change sort direction if same column.
+;;                          - Add sort buttons for CRM and Time also.
+;;                          - Sort test is different: no sort for CRM.
+;;                          - Go to bob if `desired-point' undefined.
+;;
+;;  In your init file (`~/.emacs') file, do this:
+;;
+;;    (require 'buff-menu+)
+;;
+;;  NOTE:
+;;
+;;  1. This file MUST be saved with encoding UTF-8 or equivalent,
+;;     because it contains an em-dash character.
+;;
+;;  2. If you byte-compile this using a version of Emacs prior to 23,
+;;     and you use the byte-compiled file with Emacs 23 or later, then
+;;     some keys, such as `q', will not be defined in the buffer list.
+;;     (So byte-compile it using Emacs 23 or later.)
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Change Log:
+;;
+;; 2011/10/27 dadams
+;;     Handle Dired buffers like file buffers, e.g., wrt arg FILES-ONLY.
+;; 2011/06/29 dadams
+;;     Buffer-menu-buffer+size: Corrected SPC syntax (for Emacs 20) from ?\s  to ?\ .
+;; 2011/05/02 dadams
+;;     buffer-menu-font-lock-keywords, Buffer-menu(-mouse)-execute, list-buffers-noselect,
+;;       Buffer-menu-mouse-unmark:
+;;         Accommodate frame-bufs.el.
+;; 2011/04/28 dadams
+;;     Buffer-menu-fontify-and-adjust-frame:
+;;       Fix bug introduced 2011-04-16: Do frame operations inside save-window-excursion.
+;; 2011/04/22 dadams
+;;     list-buffers-noselect: Removed (if buffer-list... around the dolist.
+;; 2011/04/18 dadams
+;;     Buffer-menu-sort, Buffer-menu-revert-function, buffer-menu:
+;;       Use Buffer-menu-buffer-column, not hard-coded 4.  Thx to Alp Aker.
+;; 2011/04/16 dadams
+;;     Buffer-menu-fontify-and-adjust-frame:
+;;       Use with-current-buffer, not save(-window)-excursion.  Thx to Alp Aker.
+;; 2011/02/20 dadams
+;;     list-buffers-noselect: Use only Emacs 22+ call to format-mode-line.
+;;                            Use property font-lock-face, not face.
+;;     Buffer-menu-sort: Typo: setq buffer-read-only was missing value.
+;; 2011/02/03 dadams
+;;     All deffaces: Provided default values for dark-background screens too.
+;; 2011/01/03 dadams
+;;     Removed autoload cookies from non def* sexps.
+;; 2010/07/15 dadams
+;;     Buffer-menu-fontify-and-adjust-frame:
+;;       Added call to font-lock-refresh-defaults.  Thx to Bastian Beischer.
+;; 2009/07/27 dadams
+;;     Buffer-menu-revert-function: Updated wrt Emacs 23: use window-buffer.
+;;     Buffer-menu-mode (Emacs 23): Use revert-buffer in doc string, not Buffer-menu-revert.
+;;     Buffer-menu-(sort|delete-flagged): Buffer-menu-revert -> Buffer-menu-revert-function.
+;;     Do defvars to silence byte-compiler for all Emacs versions.
+;; 2009/05/26 dadams
+;;     Buffer-menu-mode: Added separate definition for Emacs 23, because derived mode (keys etc.).
+;; 2009/04/16 dadams
+;;     buffer-menu-font-lock-keywords: Fix regexp for truncated star buffers (...[).
+;; 2009/02/22 dadams
+;;     Added comment to Commentary about how to show the buffer menu in the same window.
+;; 2008/02/09 dadams
+;;     Added: Buffer-menu-delete-flagged. Bound to C-M-x and added to Buffer-menu-mouse-3-menu.
+;; 2008/02/05 dadams
+;;     Added: buffer-menu-toggle-time-format, Buffer-menu-time-format.
+;;     buffer-menu-font-lock-keywords, list-buffers-noselect: Treat short and long time formats.
+;;     list-buffers-noselect: Extend column buttons from one column to the next (beyond text).
+;;     Removed optional arg for column toggles.
+;;     Renamed buffer-menu-set-flag to buffer-menu-set-default-value.
+;;     Buffer-menu-buffer+size: Add name-props and size-props only if non-nil.
+;; 2008/02/04 dadams
+;;     buffer-menu-font-lock-keywords: Highlight Dired buffer name even if no Mode.
+;;                                     Allow multiple digits in <N>.
+;;     list-buffers-noselect:
+;;       Compute longest buffer name + size combination, and use when indenting file name.
+;;     Added: Buffer-menu-buffer+size, buffer-menu-(de|in)crease-max-buffer+size (and bound),
+;;            Buffer-menu-buffer+size-computed-width.
+;;     buffer-menu: Updated doc string.
+;;     Thx to Tom Wurgler for suggestions.
+;; 2008/02/03 dadams
+;;     buffer-menu-font-lock-keywords: Highlight Dired buffer name, if file flag but no mode flag.
+;; 2008/02/01 dadams
+;;     Allow <0-9> after star buffer names.  Thx to Tom Wurgler.
+;; 2008/01/31 dadams
+;;     Added options to hide columns.  Thx to Tom Wurgler for the suggestion.
+;;       Buffer-menu-*-flag, and changed buffer-menu-font-lock-keywords accordingly.
+;;       list-buffers-noselect: Update for Buffer-menu-*-flag.
+;;       Added: *-set-flag, *-toggle-*-column, buffer-menu-font-lock-keywords (function).
+;;     Group Buffer-Menu-Plus: Remove prefix.  Different parent group for Emacs 22.
+;; 2008/01/05 dadams
+;;     list-buffers-noselect: Eval underline char at compile time - see comment.
+;;     Buffer-menu-sort-column: Made it a user option.
+;;     Removed: Buffer-menu-sort-button-map, Buffer-menu-sort-by-column.
+;;     Don't define for Emacs before version 22: Buffer-menu-make-sort-button, Buffer-menu-sort*.
+;; 2007/09/23 dadams
+;;     Removed second arg to undefine-killer-commands.
+;;     Brought up to date with Emacs 22.
+;; 2007/02/28 dadams
+;;     buffer-menu-font-lock-keywords: regexp tweaks.
+;; 2007/02/26 dadams
+;;     Added: buffer-menu-(star|directory|marked|flagged)-buffer.
+;;     buffer-menu-font-lock-keywords: Treat new faces.  Thx to Tom Wurgler <twurgl@goodyear.com>.
+;; 2007/02/16 dadams
+;;     buffer-menu: Fixed use of negative arg when using header line.
+;;     list-buffers-noselect:
+;;       Don't sort if sort column is 1 or -1.  Instead, just don't reverse list if -1.
+;;       Go to point-min if desired-point is not defined.
+;;     Buffer-menu-make-sort-button: Different help echoes for CRM and Buffer.
+;;     Buffer-menu-sort, Buffer-menu-make-sort-button:
+;;       Add to help message for CRM sort: mention Buffer-menu-use-frame-buffer-list.
+;;     Buffer-menu-mode: Mention sorting columns in doc string.
+;;     Add defvar for Buffer-menu-use-frame-buffer-list to quiet byte compiler.
+;;     Changed all Emacs 22 tests to test emacs-major-version. 
+;; 2007/02/05 dadams
+;;     list-buffers-noselect: Use ?\u2014 for the EM dash.  Thx to Henry Atting.
+;; 2007/02/02 dadams
+;;     Added coding declaration to file header.  Thx to Henry Atting.
+;;     Changed temporary emacs version tests to > emacs 21.
+;; 2006/04/10 dadams
+;;      list-buffers-noselect: Updated Emacs 22 version wrt latest CVS version.
+;; 2006/01/07 dadams
+;;      Added :link for sending bug report.
+;; 2006/01/06 dadams
+;;     Added defgroup 'Buffer-Menu-Plus.  Added :link.
+;; 2005/11/04 dadams
+;;     Added: Buffer-menu-sort-button-map, Buffer-menu-sort-by-column, if not available in Emacs.
+;; 2005/11/01 dadams
+;;     Buffer-menu-make-sort-button: Updated to reflect latest CVS version:
+;;       Added text property: column.  Use Buffer-menu-sort-button-map.
+;;       Mention mouse-1 in :help.
+;; 2005/07/08 dadams
+;;     Buffer-menu-fontify-and-adjust-frame: Wrapped in save-*excursion's.
+;; 2005/07/04 dadams
+;;     Buffer-menu-fontify-and-adjust-frame: Fixed typo: boundp -> fboundp.
+;; 2005/06/22 dadams
+;;     Use defface for faces now.
+;;     Renamed faces: *-face to *.
+;;     No longer require def-face-const.el.
+;; 2005/06/21 dadams
+;;     list-buffers-noselect: Emacs 22 renamed Buffer-menu-buffer-face to Buffer-menu-buffer.
+;; 2005/05/17 dadams
+;;     Updated to work with Emacs 22.x.
+;; 2004/12/05 dadams
+;;     Buffer-menu-execute, Buffer-menu-mouse-execute: minor corrections.
+;; 2004/11/30 dadams
+;;     Added Time column (with sorting).
+;;       Added buffer-menu-time-face.
+;;       Buffer-menu-sort, Buffer-menu-make-sort-button, list-buffers-noselect,
+;;     list-buffers-noselect: Major changes: Time column, updated to latest CVS (new 2nd arg) etc.
+;;     buffer-menu-font-lock-keywords: Rewrote for time etc.
+;;     Sort CRM column also now.
+;;     Buffer-menu-fontify-and-fit-frame renamed to Buffer-menu-fontify-and-adjust-frame.
+;;       Added raise-frame (but Emacs bug, so raise doesn't work on Windows).
+;;       turn-on-font-lock, instead of font-lock-fontify-buffer.
+;;     Removed defvar ;;;###autoload's.
+;; 2004/11/23 dadams
+;;     buffer-menu-mode-hook: call font-lock-fontify-buffer.
+;;     buffer-menu: Do not call font-lock-fontify-buffer.
+;;     Added Buffer-menu-fontify-and-fit-frame. Hook fits frame too.
+;;     Require fit-frame.el.
+;;     Removed Buffer-menu-revert.
+;; 2004/11/20 dadams
+;;     Refined to deal with Emacs 21 < 21.3.50 (soon to be 22.x)
+;; 2004/11/19 dadams
+;;     Protected tests of Buffer-menu-use-header-line with boundp for older versions.
+;; 2004/11/13 dadams
+;;     buffer-menu-font-lock-keywords: overwrite for *-mode-face, *-size-face, *-file-name-face.
+;; 2004/10/17 dadams
+;;     Updated to include Daniel Pfeiffer's fix to buff-menu.el of bug I reported on losing
+;;       marks when you sort columns:
+;;         1) Added Buffer-menu-revert-function, 2) Added (and modified) Buffer-menu-beginning,
+;;         3) Use Buffer-menu-beginning in Buffer-menu-execute and Buffer-menu-select,
+;;         4) Buffer-menu-sort: incorporated Daniel's mark-saving code.
+;;     Note: when the new version comes out (from CVS),  I will 1) update list-buffers-noselect
+;;       to new version that uses 4-arg version of format-mode-line and 2) remove new definition
+;;       of Buffer-menu-revert-function added here now.
+;; 2004/10/16 dadams
+;;     Added directional column sorting, with highlighting:
+;;       Added: Buffer-menu-make-sort-button, Buffer-menu-sort.
+;;       list-buffers-noselect: Add sort button for CRM. Sort directionally.
+;;     Only require cl.el when compile.
+;;     Buffer-menu-revert: Fontify for Emacs 21 also (needed after revert).
+;; 2004/10/15 dadams
+;;     Buffer-menu-mode: Don't skip first two lines if Buffer-menu-use-header-line.
+;; 2004/10/13 dadams
+;;     Updated for Emacs 21:
+;;       buffer-menu-font-lock-keywords, Buffer-menu-mode, Buffer-menu-execute, Buffer-menu-select
+;;       Added list-buffers-noselect for Emacs 21 (bug fix).
+;;       require cl.el only when compile on Emacs 20.
+;;     Added Buffer-menu-revert: Fontifies.
+;; 2004/07/21 dadams
+;;     Buffer-menu-mode: Don't set Buffer-menu-buffer-column unless < Emacs 20.
+;; 2001/01/02 dadams
+;;     Protect undefine-killer-commands via fboundp.
+;; 1999/08/26 dadams
+;;     1. Added: buffer-menu-*-face's, buffer-menu-font-lock-keywords.
+;;     2. Add buffer-menu-font-lock-keywords to buffer-menu-mode-hook.
+;; 1997/03/21 dadams
+;;     Buffer-menu-execute, Buffer-menu-mouse-execute:
+;;       Only use kill-buffer-and-its-windows if fboundp.
+;; 1996/07/01 dadams
+;;     buffer-menu: Prefix arg =< 0 sorts alphabetically now.
+;; 1996/07/01 dadams
+;;     Added redefinition of Buffer-menu-select.
+;; 1996/04/26 dadams
+;;     Put escaped newlines on long-line strings.
+;; 1996/01/25 dadams
+;;     1. kill-buffer -> kill-buffer-and-its-windows.
+;;     2. Buffer-menu-mode: Put mouse-face on whole buffer line.
+;; 1996/01/12 dadams
+;;     Redefined buffer-menu.
+;; 1996/01/09 dadams
+;;     kill-buffer -> kill-buffer-delete-frames
+;; 1995/12/28 dadams
+;;     Buffer-menu-mouse-3-menu: Corrected by adding temp local var.
+;; 1995/12/14 dadams
+;;     1. Highlight buffer line when mouse-3 menu displayed.
+;;        Added Buffer-menu-overlay.
+;;     2. mouse-3 menu is reduced to non-buffer-specifics when not on a buffer line.
+;; 1995/12/13 dadams
+;;     Added Buffer-menu-mouse-3-menu.  Use it instead of Buffer-menu-mouse-3-map.
+;; 1995/12/13 dadams
+;;     1) Put back Buffer-menu-select, in place of Buffer-menu-mouse-other-window.
+;;     2) Added menu on mouse-3: Added: Buffer-menu-mouse-3-map,
+;;        Buffer-menu-mouse-execute, Buffer-menu-mouse-modified,
+;;        Buffer-menu-mouse-delete, Buffer-menu-mouse-save,
+;;        Buffer-menu-mouse-unmark.
+;; 1995/09/11 dadams
+;;     Buffer-menu-mode: Added bindings list to doc string.
+;; 1995/09/11 dadams
+;;     Redefined Buffer-menu-execute: deletes frame w/ kill.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program; see the file COPYING.  If not, write to
+;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
+;; Floor, Boston, MA 02110-1301, USA.
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Code:
+
+ ;; Cannot do (require 'buff-menu), because `buff-menu.el' does no `provide'.
+ ;; Don't want to do a (load-library "buff-menu") either, because it wouldn't
+ ;; allow doing (eval-after-load "buff-menu" '(progn (require 'buff-menu+)))
+
+(eval-when-compile (require 'cl)) ;; case, (plus, for Emacs 20: push, pop, dolist,
+                                  ;;        and, for Emacs <20: cadr, when, unless)
+
+(require 'misc-fns nil t) ;; (no error if not found): undefine-killer-commands
+(require 'misc-cmds nil t) ;; (no error if not found): kill-buffer-and-its-windows
+(require 'fit-frame nil t) ;; (no error if not found): fit-frame
+
+
+;; To quiet the byte compiler:
+(defvar Buffer-menu-buffer+size-width)
+(defvar Buffer-menu-file-flag)
+(defvar Buffer-menu-files-only)
+(defvar Buffer-menu-mode-flag)
+(defvar Buffer-menu-mode-width)
+(defvar Buffer-menu-sort-column)
+(defvar Buffer-menu-sort-button-map)
+(defvar Buffer-menu-time-flag)
+(defvar Buffer-menu-time-format)
+(defvar Buffer-menu-use-frame-buffer-list)
+(defvar Buffer-menu-use-header-line)
+(defvar frame-bufs-mode)                ; Defined in `frame-bufs.el'
+(defvar frame-bufs-full-list)           ; Defined in `frame-bufs.el'
+(defvar header-line-format)
+(defvar Info-current-file)
+(defvar Info-current-node)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+(unless (> emacs-major-version 21)
+  (defgroup Buffer-Menu-Plus nil
+    "Enhancements to the buffer menu."
+    :link `(url-link :tag "Send Bug Report"
+            ,(concat "mailto:" "drew.adams" "@" "oracle" ".com?subject=\
+buff-menu+.el bug: \
+&body=Describe bug here, starting with `emacs -q'.  \
+Don't forget to mention your Emacs and library versions."))
+    :link '(url-link :tag "Other Libraries by Drew"
+            "http://www.emacswiki.org/cgi-bin/wiki/DrewsElispLibraries")
+    :link '(url-link :tag "Download"
+            "http://www.emacswiki.org/cgi-bin/wiki/buff-menu+.el")
+    :link '(url-link :tag "Description"
+            "http://www.emacswiki.org/cgi-bin/wiki/BufferMenu#BufferMenuPlus")
+    :link '(emacs-commentary-link :tag "Commentary" "buff-menu+")
+    :group 'tools :group 'convenience))
+
+(when (> emacs-major-version 21)
+  (defgroup Buffer-Menu-Plus nil
+    "Enhancements to the buffer menu."
+    :link `(url-link :tag "Send Bug Report"
+            ,(concat "mailto:" "drew.adams" "@" "oracle" ".com?subject=\
+buff-menu+.el bug: \
+&body=Describe bug here, starting with `emacs -q'.  \
+Don't forget to mention your Emacs and library versions."))
+    :link '(url-link :tag "Other Libraries by Drew"
+            "http://www.emacswiki.org/cgi-bin/wiki/DrewsElispLibraries")
+    :link '(url-link :tag "Download"
+            "http://www.emacswiki.org/cgi-bin/wiki/buff-menu+.el")
+    :link '(url-link :tag "Description"
+            "http://www.emacswiki.org/cgi-bin/wiki/BufferMenu#BufferMenuPlus")
+    :link '(emacs-commentary-link :tag "Commentary" "buff-menu+")
+    :group 'Buffer-menu :group 'tools :group 'convenience)
+
+  (defvar Buffer-menu-buffer+size-computed-width 0
+    "Max width of all buffer names, plus 4 for initial `CRM '.")
+
+  (defun buffer-menu-increase-max-buffer+size ()
+    "Increase option `Buffer-menu-buffer+size-width' by one."
+    (interactive)
+    (when (> (1+ Buffer-menu-buffer+size-width) 150) (error "Cannot increase further"))
+    (setq Buffer-menu-buffer+size-width  (1+ Buffer-menu-buffer+size-width))
+    (buffer-menu)
+    (message "New max width: %s" Buffer-menu-buffer+size-width))
+
+  (defun buffer-menu-decrease-max-buffer+size ()
+    "Decrease option `Buffer-menu-buffer+size-width' by one."
+    (interactive)
+    (let ((orig  Buffer-menu-buffer+size-width))
+      (condition-case nil
+          (progn
+            (setq Buffer-menu-buffer+size-width  (1- Buffer-menu-buffer+size-width))
+            (buffer-menu)
+            (message "New max width: %s" Buffer-menu-buffer+size-width))
+        (error (progn (setq Buffer-menu-buffer+size-width  orig)
+                      (buffer-menu)
+                      (error "Cannot decrease further"))))))
+
+  (define-key Buffer-menu-mode-map "+" 'buffer-menu-increase-max-buffer+size)
+  (define-key Buffer-menu-mode-map "-" 'buffer-menu-decrease-max-buffer+size)
+  (define-key Buffer-menu-mode-map "\C-\M-x" 'Buffer-menu-delete-flagged)
+
+  (defun buffer-menu-toggle-time-format ()
+    "Toggle `Buffer-menu-time-format' and redisplay Buffer Menu."
+    (interactive)
+    (buffer-menu-set-default-value 'Buffer-menu-time-format
+                                   (if (eq 'short Buffer-menu-time-format) 'long 'short))
+    (buffer-menu))
+
+  (defun buffer-menu-toggle-time-column ()
+    "Toggle `Buffer-menu-time-flag' and redisplay Buffer Menu."
+    (interactive)
+    (buffer-menu-set-default-value 'Buffer-menu-time-flag (not Buffer-menu-time-flag))
+    (buffer-menu))
+
+  (defun buffer-menu-toggle-mode-column ()
+    "Toggle `Buffer-menu-mode-flag' and redisplay Buffer Menu."
+    (interactive)
+    (buffer-menu-set-default-value 'Buffer-menu-mode-flag (not Buffer-menu-mode-flag))
+    (buffer-menu))
+
+  (defun buffer-menu-toggle-file-column ()
+    "Toggle `Buffer-menu-file-flag' and redisplay Buffer Menu."
+    (interactive)
+    (buffer-menu-set-default-value 'Buffer-menu-file-flag (not Buffer-menu-file-flag))
+    (buffer-menu))
+
+  (defun buffer-menu-set-default-value (symb val)
+    "Set default value of SYMB to VAL.
+Update `buffer-menu-font-lock-keywords' accordingly."
+    (set-default symb val)
+    (setq buffer-menu-font-lock-keywords  (buffer-menu-font-lock-keywords)))
+
+  (defun buffer-menu-font-lock-keywords ()
+    "Returns the list of font lock keywords for the buffer menu."
+    (let* ((frame-bufs-p       (and (boundp 'frame-bufs-mode) frame-bufs-mode))
+           (bit-column-header  (if frame-bufs-p "CRM[ F].*" "CRM.*"))
+           (bits               (if frame-bufs-p "....." "...."))
+           (shortbits          (if frame-bufs-p "...." "...")))
+      (list
+       (list (concat "^\\(" bit-column-header "\\)") 1 'buffer-menu-headings) ; CRM or CRMF
+       (list (concat "^" bits
+                     "\\(.*[^ \t\n]\\)[ \t]+[0-9]+[ \t]+\\(.* \\(AM\\|PM\\)\\)?\\([^/\n]+\\)")
+             (list 1 'buffer-menu-buffer-name)) ; Default buffer name
+       (cond (Buffer-menu-mode-flag     ; Directory buffer name
+              (list (concat "^" bits "\\(.*[^ \t\n]\\)[ \t]+[0-9]+[ \t]+[a-zA-Z :0-9]*[ \t]+Dired")
+                    1 'buffer-menu-directory-buffer t t))
+             (Buffer-menu-file-flag
+              (list (concat "^" bits "\\(.*[^ \t\n]\\)[ \t]+[0-9]+[ \t]+[^/\n]+[ \t\n]\
+\\(\\([~]\\|\\([a-zA-Z]:\\)\\)?/.*/\\)$")
+                    1 'buffer-menu-directory-buffer t t))
+             ;; We can't show that it's a directory, because we have no way of knowing that
+             (t (list "")))
+       (list (concat "^" bits
+                     "\\(\\*.*[^ \t\n][[*]\\(<[0-9]+>\\)?\\)[ \t]+") ; Star buffer (e.g. *scratch*)
+             1 'buffer-menu-star-buffer t t)
+       ;; Time & Mode
+       (cond ((and Buffer-menu-time-flag Buffer-menu-mode-flag (eq 'short Buffer-menu-time-format))
+              (list "^.*[ \t][0-9]+[ \t]+\\([0-2][0-9]:[0-5][0-9]:[0-5][0-9]\\)?\\([^\n]+\\)"
+                    (list 1 'buffer-menu-time t t) (list 2 'buffer-menu-mode t t)))
+             ((and Buffer-menu-time-flag Buffer-menu-mode-flag)
+              (list "^.*[ \t][0-9]+[ \t]+\\(.* \\(AM\\|PM\\)\\)?\\([^\n]+\\)"
+                    (list 1 'buffer-menu-time t t) (list 3 'buffer-menu-mode t t)))
+             (Buffer-menu-time-flag
+              (if (eq 'short Buffer-menu-time-format)
+                  (list "^.*[ \t][0-9]+[ \t]+\\([0-2][0-9]:[0-5][0-9]:[0-5][0-9]\\)?"
+                        (list 1 'buffer-menu-time t t))
+                (list "^.*[ \t][0-9]+[ \t]+\\(.* \\(AM\\|PM\\)\\)?" (list 1 'buffer-menu-time t t))))
+             (Buffer-menu-mode-flag
+              (list "^.*[ \t][0-9]+[ \t]+\\([^/\n]+\\)" 1 'buffer-menu-mode t t))
+             (t ""))
+       (list "^.*[ \t]\\([0-9]+\\)\\(  \\|[\n]\\)" 1 'buffer-menu-size t t) ; Size
+       (if Buffer-menu-file-flag
+           (list "^.*[ \t][0-9]+[ \t]+[^/\n]+[ \t\n]\
+\\(\\(\\([~]\\|\\([a-zA-Z]:\\)\\)*/.*\\)\\|([^ \t]+).*\\)$" ; File name of Info file + node
+                 1 'buffer-menu-file-name t t)
+         "")
+       (list "^\\([.]\\)" 1 'buffer-menu-current-buffer t t) ; Current buffer mark (.)
+       (list "^\\(>\\)" 1 'buffer-menu-view-mark t t) ; To view mark (>)
+       (list (concat "^>" shortbits
+                     "\\(.*[^ \t\n]\\)[ \t]+[0-9]+[ \t]+\\(.* \\(AM\\|PM\\)\\)?\\([^/\n]+\\)")
+             (list 1 'buffer-menu-marked-buffer 'prepend t)) ; Buffer name when marked (>)
+       (list (concat "^D" shortbits
+                     "\\(.*[^ \t\n]\\)[ \t]+[0-9]+[ \t]+\\(.* \\(AM\\|PM\\)\\)?\\([^/\n]+\\)")
+             (list 1 'buffer-menu-flagged-buffer t t)) ; Buffer name when flagged (D)
+       (list "^\\(D\\)" 1 'buffer-menu-delete-mark t t) ; Deletion flag (D)
+       (list "^..\\(S\\)" 1 'buffer-menu-save-mark t t) ; Save flag (S)
+       (list "^..\\([*]\\)" 1 'buffer-menu-modified-mark t t) ; Buffer-modified-p (*)
+       (list "^.\\(%\\)" 1 'buffer-menu-read-only-mark t t) ; Read-only-p (%)
+       )))
+
+  (defcustom Buffer-menu-time-format 'short
+    "*Format for Time column of buffer menu."
+    :type '(choice
+            (const :tag "Short: hh:mm:ss"          short)
+            (const :tag "Long: day hh:mm:ss AM/PM" long))
+    :group 'Buffer-Menu-Plus)
+
+  (defcustom Buffer-menu-time-flag t
+    "*Non-nil means Buffer Menu displays the last time the buffer was displayed."
+    :type 'boolean :group 'Buffer-Menu-Plus
+    :initialize 'custom-initialize-default
+    :set 'buffer-menu-set-default-value)
+
+  (defcustom Buffer-menu-mode-flag t
+    "*Non-nil means Buffer Menu displays the buffer's mode."
+    :type 'boolean :group 'Buffer-Menu-Plus
+    :initialize 'custom-initialize-default
+    :set 'buffer-menu-set-default-value)
+
+  (defcustom Buffer-menu-file-flag t
+    "*Non-nil means Buffer Menu displays the buffer's file."
+    :type 'boolean :group 'Buffer-Menu-Plus
+    :initialize 'custom-initialize-default
+    :set 'buffer-menu-set-default-value)  
+
+
+  ;; REPLACE ORIGINAL in `buff-menu.el'.
+  ;;
+  ;; A user option now.  It must be numeric.  Initial value is 1, not nil.
+  ;;
+  (defcustom Buffer-menu-sort-column 1
+    "*Sorted by (1) visit, (2) buffer, (3) size, (4) time, (5) mode, (6) file.
+Click a column heading to sort by that field and update this option."
+    :type '(choice
+            (const :tag "Sort by time of last visit" 1)
+            (const :tag "Sort by buffer name"        2)
+            (const :tag "Sort by buffer size"        3)
+            (const :tag "Sort by time of last use"   4)
+            (const :tag "Sort by file name"          5))
+    :group 'Buffer-Menu-Plus)
+
+
+  ;; This is needed because `buff-menu.el' is preloaded and set to nil.
+  (setq Buffer-menu-sort-column  (or Buffer-menu-sort-column 1))
+
+
+  ;; REPLACE ORIGINAL in `buff-menu.el'.
+  ;;
+  ;; Use `Buffer-menu-buffer+size-computed-width', not `Buffer-menu-buffer+size-width'.
+  ;;
+  (defun Buffer-menu-buffer+size (name size &optional name-props size-props)
+    (if (> (+ (length name) (length size) 1) Buffer-menu-buffer+size-computed-width)
+        (setq name  (if (string-match "<[0-9]+>$" name)
+                        (concat (substring name 0 (- Buffer-menu-buffer+size-computed-width
+                                                     (max (length size) 3)
+                                                     (match-end 0)
+                                                     (- (match-beginning 0))
+                                                     2))
+                                "["     ; Cut-off character.
+                                (match-string 0 name))
+                      (concat (substring name 0 (- Buffer-menu-buffer+size-computed-width
+                                                   (max (length size) 3)
+                                                   2))
+                              "[")))    ; Cut-off character.
+      (setq name  (copy-sequence name))) ; Don't put properties on (buffer-name).
+    (when name-props (add-text-properties 0 (length name) name-props name))
+    (when size-props (add-text-properties 0 (length size) size-props size))
+    (concat name (make-string (- Buffer-menu-buffer+size-computed-width
+                                 (length name)
+                                 (length size))
+                              ?\  )     ; ?\  instead of ?\s, so can be byte-compiled in Emacs 20.
+            size))
+  )
+
+;;; Faces used to fontify buffer.
+
+(defface buffer-menu-headings
+    '((((background dark))
+       (:foreground "#00005A5AFFFF" :background "#FFFF9B9BFFFF")) ; ~ blue, pink
+      (t (:foreground "Orange" :background "DarkGreen")))
+  "*Face used for headings in *Buffer List* buffer."
+  :group 'Buffer-Menu-Plus
+  :group 'font-lock-highlighting-faces)
+(defvar buffer-menu-headings 'buffer-menu-headings)
+
+(defface buffer-menu-current-buffer
+    '((((background dark)) (:foreground "Cyan" :background "#808000002B2B")) ; dark red brown
+      (t (:foreground "Red" :background "Aquamarine")))
+  "*Face used for current buffer mark in *Buffer List* buffer."
+  :group 'Buffer-Menu-Plus
+  :group 'font-lock-highlighting-faces)
+(defvar buffer-menu-current-buffer 'buffer-menu-current-buffer)
+
+(defface buffer-menu-view-mark
+    '((((background dark)) (:foreground "Cyan" :background "#808000002B2B")) ; dark red brown
+      (t (:foreground "Red" :background "Aquamarine")))
+  "*Face used for buffers to view mark (>) in *Buffer List* buffer."
+  :group 'Buffer-Menu-Plus
+  :group 'font-lock-highlighting-faces)
+(defvar buffer-menu-view-mark 'buffer-menu-view-mark)
+
+(defface buffer-menu-star-buffer
+    '((((background dark)) (:foreground "#FFFFFFFF7474")) ; ~ light yellow
+      (t (:foreground "DarkBlue")))
+  "*Face used for buffers named \"*...*\"in *Buffer List* buffer."
+  :group 'Buffer-Menu-Plus :group 'font-lock-highlighting-faces)
+(defvar buffer-menu-star-buffer 'buffer-menu-star-buffer)
+
+(defface buffer-menu-directory-buffer
+    '((((background dark)) (:foreground "Yellow" :background "#525227271919")) ; ~ dark brown
+      (t (:foreground "Blue" :background "LightBlue")))
+  "*Face used for directory buffers in *Buffer List* buffer."
+  :group 'Buffer-Menu-Plus :group 'font-lock-highlighting-faces)
+(defvar buffer-menu-directory-buffer 'buffer-menu-directory-buffer)
+
+(defface buffer-menu-marked-buffer
+    '((t (:underline t)))
+  "*Face used for buffers marked with `>' in *Buffer List* buffer."
+  :group 'Buffer-Menu-Plus :group 'font-lock-highlighting-faces)
+(defvar buffer-menu-marked-buffer 'buffer-menu-marked-buffer)
+
+(defface buffer-menu-flagged-buffer
+    '((((background dark)) (:foreground "Cyan"))
+      (t (:foreground "Red")))
+  "*Face used for buffers marked with `D' in *Buffer List* buffer."
+  :group 'Buffer-Menu-Plus :group 'font-lock-highlighting-faces)
+(defvar buffer-menu-flagged-buffer 'buffer-menu-flagged-buffer)
+
+(defface buffer-menu-delete-mark
+    '((((background dark)) (:foreground "#808000002B2B" :background "Cyan"))
+      (t (:foreground "Aquamarine" :background "Red")))
+  "*Face used for buffers to delete mark (D) in *Buffer List* buffer."
+  :group 'Buffer-Menu-Plus
+  :group 'font-lock-highlighting-faces)
+(defvar buffer-menu-delete-mark 'buffer-menu-delete-mark)
+
+(defface buffer-menu-save-mark
+    '((((background dark)) (:foreground "#00005A5AFFFF" :background "Yellow")) ; ~blue
+      (t (:foreground "Orange" :background "Blue")))
+  "*Face used for buffers to save mark (S) in *Buffer List* buffer."
+  :group 'Buffer-Menu-Plus
+  :group 'font-lock-highlighting-faces)
+(defvar buffer-menu-save-mark 'buffer-menu-save-mark)
+
+(defface buffer-menu-modified-mark
+    '((((background dark)) (:foreground "#00007373FFFF")) ; ~ blue
+      (t (:foreground "DarkOrange")))
+  "*Face used for modified buffers mark (*) in *Buffer List* buffer."
+  :group 'Buffer-Menu-Plus
+  :group 'font-lock-highlighting-faces)
+(defvar buffer-menu-modified-mark 'buffer-menu-modified-mark)
+
+(defface buffer-menu-read-only-mark
+    '((((background dark)) (:foreground "Blue"))
+      (t (:foreground "Yellow")))
+  "*Face used for read-only buffers mark (%) in *Buffer List* buffer."
+  :group 'Buffer-Menu-Plus
+  :group 'font-lock-highlighting-faces)
+(defvar buffer-menu-read-only-mark 'buffer-menu-read-only-mark)
+
+(defface buffer-menu-buffer-name
+    '((((background dark)) (:foreground "Yellow"))
+      (t (:foreground "Blue")))
+  "*Face used for buffer names in *Buffer List* buffer."
+  :group 'Buffer-Menu-Plus
+  :group 'font-lock-highlighting-faces)
+(defvar buffer-menu-buffer-name 'buffer-menu-buffer-name)
+;; Redefine standard face `Buffer-menu-buffer' as `buffer-menu-buffer-name'.
+(put 'Buffer-menu-buffer 'face-alias 'buffer-menu-buffer-name)
+
+(defface buffer-menu-mode
+    '((((background dark)) (:foreground "#FFFF9B9BFFFF")) ; ~ pink
+      (t (:foreground "DarkGreen")))
+  "*Face used for buffer modes in *Buffer List* buffer."
+  :group 'Buffer-Menu-Plus
+  :group 'font-lock-highlighting-faces)
+(defvar buffer-menu-mode 'buffer-menu-mode)
+
+(defface buffer-menu-size
+    '((((background dark)) (:foreground "#7474FFFFFFFF")) ; ~ light cyan
+      (t (:foreground "DarkRed")))
+  "*Face used for buffer sizes in *Buffer List* buffer."
+  :group 'Buffer-Menu-Plus
+  :group 'font-lock-highlighting-faces)
+(defvar buffer-menu-size 'buffer-menu-size)
+
+(defface buffer-menu-time
+    '((((background dark)) (:foreground "#74749A9AF7F7")) ; ~ light blue
+      (t (:foreground "DarkGoldenrod4")))
+  "*Face used for buffer time in *Buffer List* buffer."
+  :group 'Buffer-Menu-Plus
+  :group 'font-lock-highlighting-faces)
+(defvar buffer-menu-time 'buffer-menu-time)
+
+(defface buffer-menu-file-name
+    '((((background dark)) (:foreground "#7474FFFF7474")) ; ~ light green
+      (t (:foreground "DarkMagenta")))
+  "*Face used for file names in *Buffer List* buffer."
+  :group 'Buffer-Menu-Plus
+  :group 'font-lock-highlighting-faces)
+(defvar buffer-menu-file-name 'buffer-menu-file-name)
+
+(if (> emacs-major-version 21)
+    (defvar buffer-menu-font-lock-keywords (buffer-menu-font-lock-keywords) ; Emacs 22
+      "*Expressions to highlight in Buffer Menu mode.")
+  (defvar buffer-menu-font-lock-keywords ; Emacs 20, 21
+    (list
+     (list "^\\( M.*\\)" 1 'buffer-menu-headings)
+     (list "^....\\(.*[^ \t\n]\\)[ \t]+[0-9]+[ \t]+" ; Default buffer name
+           1 'buffer-menu-buffer-name)
+     (list "^....\\(.*[^ \t\n]\\)[ \t]+[0-9]+[ \t]+[a-zA-Z :0-9]*[ \t]+Dired"
+           1 'buffer-menu-directory-buffer t t) ; Directory buffer name
+     (list "^....\\(\\*.*[^ \t\n]\\*\\(<[0-9]+>\\)?\\)[ \t]+" ; Star buffer name
+           1 'buffer-menu-star-buffer t t)
+     (list "^.*[ \t][0-9]+[ \t]+\\([^/\n]+\\)" 1 'buffer-menu-mode t t) ; Mode
+     (list "^.*[ \t]\\([0-9]+\\)[ \t]+[^/\n]+" 1 'buffer-menu-size t t) ; Size
+     (list "^.*[ \t][0-9]+[ \t]+[^/\n]+[ \t\n]\\(\\([~]\\|\\([a-zA-Z]:\\)\\)*/.*\\)$"
+           1 'buffer-menu-file-name t t) ; File name
+     (list "^\\([.]\\)" 1 'buffer-menu-current-buffer t t) ; Current buffer mark (.)
+     (list "^\\(>\\)" 1 'buffer-menu-view-mark t t) ; To view mark (>)
+     (list "^>...\\(.*[^ \t\n]\\)[ \t\]+[0-9]" ; Buffer name when marked (>)
+           1 'buffer-menu-marked-buffer 'prepend t)
+     (list "^D...\\(.*[^ \t\n]\\)[ \t\]+[0-9]" ; Buffer name when flagged (D)
+           1 'buffer-menu-flagged-buffer t t)
+     (list "^\\(D\\)" 1 'buffer-menu-delete-mark t t) ; Deletion flag (D)
+     (list "^.\\(S\\)" 1 'buffer-menu-save-mark t t) ; Save flag (S)
+     (list "^.\\([*]\\)" 1 'buffer-menu-modified-mark t t) ; Buffer-modified-p (*)
+     (list "^..\\(%\\)" 1 'buffer-menu-read-only-mark t t) ; Read-only-p (%)
+     ) "*Expressions to highlight in Buffer Menu mode."))
+
+
+;; Undefine some bindings that would try to modify a buffer-menu buffer. Their key sequences
+;; will then appear to the user as available for local (Buffer Menu) definition.
+(when (fboundp 'undefine-killer-commands) (undefine-killer-commands Buffer-menu-mode-map))
+
+
+;; REPLACE ORIGINAL in `buff-menu.el'.
+;;
+;; Protect `Buffer-menu-files-only' with boundp (for Emacs 20).
+;;
+(defun Buffer-menu-revert-function (ignore1 ignore2)
+  (unless (eq buffer-undo-list t) (setq buffer-undo-list  ()))
+  ;; We can not use save-excursion here.  The buffer gets erased.
+  (let ((opoint            (point))
+        (eobp              (eobp))
+        (ocol              (current-column))
+        (oline             (progn (move-to-column Buffer-menu-buffer-column)
+                                  (get-text-property (point) 'buffer)))
+        (prop              (point-min))
+        ;; Do not make undo records for the reversion.
+        (buffer-undo-list  t))
+    ;; We can be called by Auto Revert Mode with the "*Buffer Menu*"
+    ;; temporarily the current buffer.  Make sure that the
+    ;; interactively current buffer is correctly identified with a `.'
+    ;; by `list-buffers-noselect'.
+    (with-current-buffer (window-buffer)
+      (list-buffers-noselect (and (boundp 'Buffer-menu-files-only) Buffer-menu-files-only)))
+    (if oline
+        (while (setq prop  (next-single-property-change prop 'buffer))
+          (when (eq (get-text-property prop 'buffer) oline)
+            (goto-char prop)
+            (move-to-column ocol)))
+      (goto-char (if eobp (point-max) opoint)))))
+
+(defun Buffer-menu-fontify-and-adjust-frame ()
+  "Use for `buffer-menu-mode-hook'.  Fontify, fit and raise frame."
+  (with-current-buffer (get-buffer-create "*Buffer List*")
+    (when (< emacs-major-version 21) (make-local-variable 'font-lock-defaults))
+    (setq font-lock-defaults  '(buffer-menu-font-lock-keywords t))
+    (turn-on-font-lock)
+    (when (get-buffer-window (current-buffer) 'visible)
+      (save-window-excursion
+        (select-window (get-buffer-window (current-buffer) 'visible))
+        (when (and (fboundp 'fit-frame) (one-window-p t)) (fit-frame))
+        (raise-frame)))
+    (when (fboundp 'font-lock-refresh-defaults) (font-lock-refresh-defaults))))
+
+;; Fontify buffer, then fit and raise its frame.
+(add-hook 'buffer-menu-mode-hook 'Buffer-menu-fontify-and-adjust-frame)
+
+
+;; REPLACE ORIGINAL in `buff-menu.el'.
+;;
+;; Treat Emacs 20 too.
+;;
+(defun Buffer-menu-beginning ()
+  (goto-char (point-min))
+  (unless (and (boundp 'Buffer-menu-use-header-line) Buffer-menu-use-header-line)
+    (forward-line)))
+
+
+;; REPLACE ORIGINAL in `buff-menu.el'.
+;;
+;;   1. Different help message.
+;;   2. Prefix ARG =< 0 now means list all buffers alphabetically.
+;;      (It used to mean the same as ARG > 0.)
+;;      Prefix ARG >= 0 means list just file buffers.
+;;   3. Use `pop-to-buffer' instead of `switch-to-buffer'.
+;;      This means that the buffer menu is shown in a different window.
+;;      If you prefer to show it in the current window, then just do this:
+;;          (add-to-list 'same-window-buffer-names "*Buffer List*")
+;;
+;;;###autoload
+(defun buffer-menu (&optional arg)
+  "Show a menu to let you save, delete or select buffers.
+By default (no or null prefix arg), the buffers are listed in order of
+last access (visit).  With a non-nil prefix ARG:
+  ARG >= 0  means only buffers visiting files are listed.
+  ARG <= 0  means the buffers are listed alphabetically.
+ (ARG = 0   means only buffers visiting files, listed alphabetically.)
+
+Type `?' in buffer \"*Buffer List*\" for more information.
+Type `q' there to quit the buffer menu."
+  (interactive "P")
+  (let ((num-arg  (prefix-numeric-value arg)))
+    (if (and arg (< num-arg 0)) (list-buffers) (list-buffers arg))
+    (let ((newpoint  (save-excursion (set-buffer "*Buffer List*") (point))))
+      (pop-to-buffer "*Buffer List*")
+      (when (and arg (not (> num-arg 0))) ; Sort lines after header.
+        (let ((buffer-read-only  nil))
+          (goto-char (point-min))
+          (unless Buffer-menu-use-header-line (forward-line 2)) ; Header.
+          (forward-char Buffer-menu-buffer-column)
+          (sort-columns nil (point) (save-excursion (goto-char (point-max))
+                                                    (when (bolp) (backward-char 1))
+                                                    (point)))))
+      (goto-char newpoint)))
+  (message "Help: ?;   Menu: mouse-3;   Show: v;   Mark: u,m,s,d;   \
+Save/Delete: x;   Misc: g,~,%%,t"))
+
+
+;; REPLACE ORIGINAL in `buff-menu.el'.
+;;
+;; 1. Doc string reflects new bindings.
+;; 2. mouse-face on whole line, not just buffer name.
+;; 3. Compatible with Emacs prior to Emacs 22 also.
+;;
+(when (< emacs-major-version 23)
+  (defun Buffer-menu-mode ()
+    "Major mode for editing a list of buffers.
+Each line describes one of the buffers in Emacs.
+In Buffer menu mode, chars do not insert themselves, but are commands.
+\\<Buffer-menu-mode-map>
+\(\"Current line\" here is the line of the text cursor or the mouse.)
+
+
+Display Options
+---------------
+Click `mouse-3' for a context-sensitive menu of buffer operations.
+
+These features are available for Emacs 22 and later:
+
+* You can click a column heading to sort by that column.  Clicking
+  again reverses the sort direction.  The current sort column is
+  indicated by an underlined or overlined column heading.  Sorting by
+  column `CRM' depends on the value of option
+  `Buffer-menu-use-frame-buffer-list'.
+
+* You can resize the Buffer and Size columns using `+' and `-'.
+
+* You can toggle the display of columns Time, Mode, and File using
+  commands `buffer-menu-toggle-time-column',
+  `buffer-menu-toggle-mode-column', and
+  `buffer-menu-toggle-file-column'.  You can toggle the Time format
+  using command `buffer-menu-toggle-time-format'.
+
+Column `CRM':
+ `C' shows `>' if you have marked the buffer to be displayed,
+           `D' if you have marked it for deletion, and
+           `.' for the buffer from which you came (current).
+ `R' shows `%' if the buffer is read-only.
+ `M' shows `*' if the buffer is modified, and
+           `S' if you have marked it for saving.
+
+The other columns are the Buffer name, its Size in characters, the
+last Time the buffer was displayed, its major Mode, and the visited
+File name (if any).
+
+Displaying Buffers
+------------------
+\\[Buffer-menu-mouse-select], \\[Buffer-menu-select], \\[Buffer-menu-this-window] -- \
+Select current line's buffer.
+\\[Buffer-menu-mark]\t-- Mark current line's buffer `>' to be displayed (via \
+`\\[Buffer-menu-select]').
+\\[Buffer-menu-select]\t-- Show buffers marked `>'.  Select current line's \
+buffer.
+\\[Buffer-menu-1-window]\t-- Select current line's buffer (only) in a \
+full-frame window.
+\\[Buffer-menu-2-window]\t-- Select current line's buffer in one window.
+\t   Display previous buffer in a second window.
+\\[Buffer-menu-switch-other-window]\t-- Display current line's buffer in \
+another window.  No select.
+\\[Buffer-menu-view]\t-- select current line's buffer, but in view-mode.
+\\[Buffer-menu-view-other-window]\t-- select that buffer in
+  another window, in view-mode.
+\\[Buffer-menu-toggle-files-only]\t-- toggle whether to display only file buffers.
+
+Marking/Unmarking Buffers to be Saved/Deleted
+---------------------------------------------
+\\[Buffer-menu-save]\t-- Mark current line's buffer `S' to be saved.    \
+Cursor down.
+\\[Buffer-menu-delete]\t-- Mark current line's buffer `D' to be deleted.  \
+Cursor down.
+\\[Buffer-menu-delete-backwards]\t-- Mark current line's buffer `D' to be \
+deleted.  Cursor up.
+\\[Buffer-menu-unmark]\t-- Unmark current line.  Cursor down. (Prefix arg: \
+Cursor up.)
+\\[Buffer-menu-backup-unmark]\t-- Cursor up, then unmark line.
+
+Saving/Deleting Buffers
+-----------------------
+\\[Buffer-menu-execute]\t-- Save / Delete marked buffers (marks `S', `D').
+\\[Buffer-menu-delete-flagged]\t-- Delete all buffers marked `D', even if modified.
+
+Miscellaneous
+-------------
+\\[Buffer-menu-revert]\t-- Update the list of buffers.
+\\[Buffer-menu-not-modified]\t-- Clear modified-flag on current line's buffer.
+\\[Buffer-menu-toggle-read-only]\t-- Toggle read-only status of current \
+line's buffer.
+\\[Buffer-menu-visit-tags-table]\t-- `visit-tags-table' using current line's \
+buffer.
+
+
+Bindings in Buffer Menu mode:
+----------------------------
+
+\\{Buffer-menu-mode-map}"
+    (kill-all-local-variables)
+    (use-local-map Buffer-menu-mode-map)
+    (setq major-mode  'Buffer-menu-mode
+          mode-name   "Buffer Menu")
+    (save-excursion
+      (goto-char (point-min))
+      (when (< emacs-major-version 20)  ; Hardcoded to 4, starting in Emacs 20
+        (search-forward "Buffer")
+        (backward-word 1)
+        (setq Buffer-menu-buffer-column  (current-column)))
+      (when (or (not (boundp 'Buffer-menu-use-header-line)) (not Buffer-menu-use-header-line))
+        (forward-line 2))               ; First two lines are title, unless use header line.
+      (while (not (eobp))
+        (put-text-property (point)
+                           (save-excursion (end-of-line) (point))
+                           'mouse-face 'highlight)
+        (forward-line 1)))
+    (set (make-local-variable 'revert-buffer-function) 'Buffer-menu-revert-function)
+    (when (> emacs-major-version 21)
+      (set (make-local-variable 'buffer-stale-function) #'(lambda (&optional noconfirm) 'fast)))
+    (setq truncate-lines    t
+          buffer-read-only  t)
+    (if (> emacs-major-version 21)
+        (run-mode-hooks 'buffer-menu-mode-hook)
+      (run-hooks 'buffer-menu-mode-hook))))
+
+
+;; REPLACE ORIGINAL in `buff-menu.el'.
+;;
+;; 1. Doc string reflects new bindings.
+;; 2. mouse-face on whole line, not just buffer name.
+;;
+;; NOTE: If you byte-compile this file with Emacs 20 and then use the byte-compiled result,
+;; `buff-menu+.elc', in Emacs 23, then keys such as `q' and `g' will not be defined.  It's best
+;; to byte-compile `buff-menu+.el' with the same Emacs version where you use `buff-menu+.elc'.
+;;
+(when (> emacs-major-version 22)
+  ;; Buffer Menu mode is suitable only for specially formatted data.
+  (put 'Buffer-menu-mode 'mode-class 'special)
+
+  (define-derived-mode Buffer-menu-mode special-mode "Buffer Menu"
+    "Major mode for editing a list of buffers.
+Each line describes one of the buffers in Emacs.
+In Buffer menu mode, chars do not insert themselves, but are commands.
+\\<Buffer-menu-mode-map>
+\(\"Current line\" here is the line of the text cursor or the mouse.)
+
+
+Display Options
+---------------
+Click `mouse-3' for a context-sensitive menu of buffer operations.
+
+These features are available for Emacs 22 and later:
+
+* You can click a column heading to sort by that column.  Clicking
+  again reverses the sort direction.  The current sort column is
+  indicated by an underlined or overlined column heading.  Sorting by
+  column `CRM' depends on the value of option
+  `Buffer-menu-use-frame-buffer-list'.
+
+* You can resize the Buffer and Size columns using `+' and `-'.
+
+* You can toggle the display of columns Time, Mode, and File using
+  commands `buffer-menu-toggle-time-column',
+  `buffer-menu-toggle-mode-column', and
+  `buffer-menu-toggle-file-column'.  You can toggle the Time format
+  using command `buffer-menu-toggle-time-format'.
+
+Column `CRM':
+ `C' shows `>' if you have marked the buffer to be displayed,
+           `D' if you have marked it for deletion, and
+           `.' for the buffer from which you came (current).
+ `R' shows `%' if the buffer is read-only.
+ `M' shows `*' if the buffer is modified, and
+           `S' if you have marked it for saving.
+
+The other columns are the Buffer name, its Size in characters, the
+last Time the buffer was displayed, its major Mode, and the visited
+File name (if any).
+
+Displaying Buffers
+------------------
+\\[Buffer-menu-mouse-select], \\[Buffer-menu-select], \\[Buffer-menu-this-window], \
+\\[Buffer-menu-other-window] -- Select current line's buffer.
+\\[Buffer-menu-mark]\t-- Mark current line's buffer `>' to be displayed (via \
+`\\[Buffer-menu-select]').
+\\[Buffer-menu-select]\t-- Show buffers marked `>'.  Select current line's \
+buffer.
+\\[Buffer-menu-1-window]\t-- Select current line's buffer (only) in a \
+full-frame window.
+\\[Buffer-menu-2-window]\t-- Select current line's buffer in one window.
+\t   Display previous buffer in a second window.
+\\[Buffer-menu-switch-other-window]\t-- Display current line's buffer in \
+another window.  No select.
+\\[Buffer-menu-view]\t-- select current line's buffer, but in view-mode.
+\\[Buffer-menu-view-other-window]\t-- select that buffer in
+  another window, in view-mode.
+\\[Buffer-menu-toggle-files-only]\t-- toggle whether to display only file & Dired buffers.
+
+Marking/Unmarking Buffers to be Saved/Deleted
+---------------------------------------------
+\\[Buffer-menu-save]\t-- Mark current line's buffer `S' to be saved.    \
+Cursor down.
+\\[Buffer-menu-delete]\t-- Mark current line's buffer `D' to be deleted.  \
+Cursor down.
+\\[Buffer-menu-delete-backwards]\t-- Mark current line's buffer `D' to be \
+deleted.  Cursor up.
+\\[Buffer-menu-unmark]\t-- Unmark current line.  Cursor down. (Prefix arg: \
+Cursor up.)
+\\[Buffer-menu-backup-unmark]\t-- Cursor up, then unmark line.
+
+Saving/Deleting Buffers
+-----------------------
+\\[Buffer-menu-execute]\t-- Save / Delete marked buffers (marks `S', `D').
+\\[Buffer-menu-delete-flagged]\t-- Delete all buffers marked `D', even if modified.
+
+Miscellaneous
+-------------
+\\[revert-buffer]\t-- Update the list of buffers.
+\\[Buffer-menu-not-modified]\t-- Clear modified-flag on current line's buffer.
+\\[Buffer-menu-toggle-read-only]\t-- Toggle read-only status of current \
+line's buffer.
+\\[Buffer-menu-visit-tags-table]\t-- `visit-tags-table' using current line's \
+buffer.
+\\[Buffer-menu-isearch-buffers] -- Do incremental search in the marked buffers.
+\\[Buffer-menu-isearch-buffers-regexp] -- Isearch for regexp in the marked buffers.
+\\[Buffer-menu-bury] -- bury the buffer listed on this line.
+
+
+Bindings in Buffer Menu mode:
+----------------------------
+
+\\{Buffer-menu-mode-map}"
+    (save-excursion
+      (let ((inhibit-read-only  t))
+        (goto-char (point-min))
+        (when (or (not (boundp 'Buffer-menu-use-header-line)) (not Buffer-menu-use-header-line))
+          (forward-line 2))             ; First two lines are title, unless use header line.
+        (while (not (eobp))
+          (put-text-property (point) (save-excursion (end-of-line) (point))
+                             'mouse-face 'highlight)
+          (forward-line 1))))
+    (set (make-local-variable 'revert-buffer-function) 'Buffer-menu-revert-function)
+    (set (make-local-variable 'buffer-stale-function) #'(lambda (&optional noconfirm) 'fast))
+    (setq truncate-lines    t
+          buffer-read-only  t)))
+
+;;;###autoload
+(defun Buffer-menu-delete-flagged ()
+  "Delete all buffers marked `D', even if they have been modified.
+If there are any file buffers that have been modified since the last
+save, then you must confirm the deletion of all at once.
+
+You can mark a buffer for deletion (`D') using command `\\<Buffer-menu-mode-map>\
+\\[Buffer-menu-delete]'."
+  (interactive)
+  (save-excursion
+    (Buffer-menu-beginning)
+    (let ((buff-menu-buffer  (current-buffer))
+          (buffer-read-only  nil)
+          (bufs              ())
+          (mod-bufs          ())
+          (kill-fn           (if (fboundp 'kill-buffer-and-its-windows)
+                                 #'kill-buffer-and-its-windows
+                               #'kill-buffer))
+          buf)
+      (while (re-search-forward "^D" nil t)
+        (forward-char -1)
+        (setq buf  (Buffer-menu-buffer nil))
+        (unless (or (eq buf nil) (eq buf buff-menu-buffer))
+          (push buf bufs)
+          (when (and (buffer-file-name buf) (buffer-modified-p buf)) (push buf mod-bufs)))
+        (forward-line 1))
+      (unless bufs (error "No buffers flagged for deletion"))
+      (when (and mod-bufs (let ((visible-bell  t)) (ding) t)
+                 (let ((last-nonmenu-event  nil)
+                       (use-dialog-box      t))
+                   (not (yes-or-no-p
+                         (concat "Modified buffers.  Delete all anyway? (`"
+                                 (mapconcat (lambda (b) (buffer-name b)) mod-bufs "', `")
+                                 "')")))))
+        (error "OK, no buffers deleted"))
+      (dolist (buf bufs)
+        (save-excursion
+          (set-buffer buf)
+          (set-buffer-modified-p nil)
+          (funcall kill-fn buf)))
+      (Buffer-menu-revert-function nil nil))))
+
+
+;; REPLACE ORIGINAL in `buff-menu.el'.
+;;
+;; 1. Deletes frame when kills buffer.
+;; 2. Compatible with Emacs prior to Emacs 22 also.
+;; 3. Accommodate `frame-bufs.el'.
+;;
+;;;###autoload
+(defun Buffer-menu-execute ()
+  "Save or delete buffers marked `S' (\"save\") or `D' (\"delete\").
+Buffers can be so marked using commands `\\<Buffer-menu-mode-map>\
+\\[Buffer-menu-save]' and `\\[Buffer-menu-delete]', respectively."
+  (interactive)  
+  (when (and (boundp 'frame-bufs-mode) frame-bufs-mode) (frame-bufs-buffer-menu-execute))
+  (save-excursion
+    (Buffer-menu-beginning)
+    (while (if (> emacs-major-version 21)
+               (re-search-forward "^..S" nil t)
+             (re-search-forward "^.S" nil t))
+      (let ((modp  nil))
+        (save-excursion
+          (set-buffer (Buffer-menu-buffer t))
+          (save-buffer)
+          (setq modp  (buffer-modified-p)))
+        (let ((buffer-read-only  nil))
+          (delete-char -1)
+          (insert (if modp ?* ? ))))))
+  (save-excursion
+    (Buffer-menu-beginning)
+    (let ((buff-menu-buffer  (current-buffer))
+          (buffer-read-only  nil))
+      (while (re-search-forward "^D" nil t)
+        (forward-char -1)
+        (let ((buf  (Buffer-menu-buffer nil)))
+          (or (eq buf nil) (eq buf buff-menu-buffer)
+              (save-excursion (if (fboundp 'kill-buffer-and-its-windows)
+                                  (kill-buffer-and-its-windows buf)
+                                (kill-buffer buf))))
+          (if (and buf (buffer-name buf))
+              (progn (delete-char 1) (insert ? ))
+            (delete-region (point) (progn (forward-line 1) (point)))
+            (unless (bobp) (forward-char -1))))))))
+
+
+;; REPLACE ORIGINAL in `buff-menu.el'.
+;;
+;; When Buffer Menu is `window-dedicated-p', uses `pop-to-buffer' to display.
+;;
+;;;###autoload
+(defun Buffer-menu-select ()
+  "Select this line's buffer; also display buffers marked with `>'.
+You can mark buffers with command `\\<Buffer-menu-mode-map>\\[Buffer-menu-mark]'.
+If the window is `window-dedicated-p', then another window is used;
+else, all windows previously in the frame are replaced by this one."
+  (interactive)
+  (let ((buff    (Buffer-menu-buffer t))
+        (menu    (current-buffer))
+        (others  ())
+        tem)
+    (Buffer-menu-beginning)
+    (while (re-search-forward "^>" nil t)
+      (setq tem  (Buffer-menu-buffer t))
+      (let ((buffer-read-only  nil)) (delete-char -1) (insert ?\ ))
+      (or (eq tem buff) (memq tem others) (setq others  (cons tem others))))
+    (setq others  (nreverse others))
+    (cond ((window-dedicated-p (selected-window)) ; Can't split dedicated win.
+           (pop-to-buffer buff)
+           (unless (eq menu buff) (bury-buffer menu))
+           (while others
+             (pop-to-buffer (car others))
+             (pop others)))
+          (t
+           (setq tem  (/ (1- (frame-height)) (1+ (length others))))
+           (delete-other-windows)
+           (switch-to-buffer buff)
+           (unless (eq menu buff) (bury-buffer menu))
+           (if (equal (length others) 0)
+               (progn
+;;;              ;; Restore previous window configuration before displaying
+;;;              ;; selected buffers.
+;;;              (if Buffer-menu-window-config
+;;;                  (progn (set-window-configuration
+;;;                            Buffer-menu-window-config)
+;;;                         (setq Buffer-menu-window-config  nil)))
+                 (switch-to-buffer buff))
+             (while others
+               (split-window nil tem)
+               (other-window 1)
+               (switch-to-buffer (car others))
+               (setq others  (cdr others)))
+             (other-window 1))))))      ;back to the beginning!      ; Back to the beginning.
+
+
+;; REPLACE ORIGINAL in `buff-menu.el'.
+;;
+;; Allow negative COLUMN.  Allow COLUMN = 1 or -1.
+;; When COLUMN = `Buffer-menu-sort-column', then flip `Buffer-menu-sort-column'.
+;; Message at end.
+;;
+(when (> emacs-major-version 21)
+  (defun Buffer-menu-sort (column)
+    "Sort the buffer menu by COLUMN.
+Consecutive executions of the same COLUMN reverse the sort order."
+    (interactive "P")
+    (when column
+      (setq column  (prefix-numeric-value column))
+      (when (= column 0) (setq column  1))
+      (when (> column 6) (setq column  6))
+      (when (< column -6) (setq column  -6)))
+    (if (equal Buffer-menu-sort-column column)
+        (setq Buffer-menu-sort-column  (- column))
+      (setq Buffer-menu-sort-column  column))
+    (let (buffer-read-only lll buf m1 m2)
+      (save-excursion
+        (Buffer-menu-beginning)
+        (while (not (eobp))
+          (when (buffer-live-p
+                 (setq buf  (get-text-property (+ (point) Buffer-menu-buffer-column) 'buffer)))
+            (setq m1  (char-after)
+                  m1  (and (memq m1 '(?> ?D)) m1)
+                  m2  (char-after (+ (point) 2))
+                  m2  (and (eq m2 ?S) m2))
+            (when (or m1 m2) (push (list buf m1 m2) lll)))
+          (forward-line)))
+      (Buffer-menu-revert-function nil nil)
+      (setq buffer-read-only  t)
+      (save-excursion
+        (Buffer-menu-beginning)
+        (while (not (eobp))
+          (when (setq buf  (assq (get-text-property (+ (point) Buffer-menu-buffer-column) 'buffer)
+                                 lll))
+            (setq m1  (cadr buf)
+                  m2  (cadr (cdr buf)))
+            (when m1 (delete-char 1) (insert m1) (backward-char 1))
+            (when m2 (forward-char 2) (delete-char 1) (insert m2)))
+          (forward-line))))
+    (message "Buffers are now sorted %s%s."
+             (case (abs column)
+               (1 "by time of last visit - see `Buffer-menu-use-frame-buffer-list'")
+               (2 "by buffer name")
+               (3 "by size")
+               (4 "by time of last display")
+               (5 "by major-mode name")
+               (otherwise "by associated file (including path)"))
+             (if (natnump Buffer-menu-sort-column) ", ascending" ", descending"))))
+
+
+;; REPLACE ORIGINAL in `buff-menu.el'.
+;;
+;; If same column as last sort, then flip direction of sort.
+;; CRM is indicated by COLUMN = 1, not by nil COLUMN.
+;; Apply different face to sort column heading, depending on direction.
+;;
+(when (> emacs-major-version 21)
+  (defun Buffer-menu-make-sort-button (name button-column)
+    (let ((the-sort-column-p  nil))
+      (when (equal button-column (abs Buffer-menu-sort-column))
+        (setq the-sort-column-p  t
+              button-column      (- button-column)))
+      (propertize name 'column button-column
+                  'help-echo (case (abs button-column)
+                               (1 (if Buffer-menu-use-header-line
+                                      "mouse-1, mouse-2: sort by time of last visit - \
+see `Buffer-menu-use-frame-buffer-list'"
+                                    "mouse-2, RET: sort by time of last visit - \
+see `Buffer-menu-use-frame-buffer-list'"))
+                               (2 (if Buffer-menu-use-header-line
+                                      "mouse-1, mouse-2: sort by buffer name"
+                                    "mouse-2, RET: sort by buffer name"))
+                               (4 "mouse-1, mouse-2: sort by time of last display/access")
+                               (t (if Buffer-menu-use-header-line
+                                      (concat "mouse-1, mouse-2: sort by " (downcase name))
+                                    (concat "mouse-2, RET: sort by " (downcase name)))))
+                  'mouse-face 'highlight
+                  (when the-sort-column-p 'face) (when the-sort-column-p
+                                                   (if (natnump Buffer-menu-sort-column)
+                                                       '(:underline t)
+                                                     '(:overline t)))
+                  'keymap Buffer-menu-sort-button-map))))
+
+
+;; REPLACE ORIGINAL in `buff-menu.el'.
+;;
+;; 1. Compute longest buffer name + size combination, and use when indenting file name.
+;; 2. Add sort buttons for CRM and Time also.
+;; 3. The test for column 1 (CRM) to determine whether to sort is =1, not null.
+;; 4. Sort direction depends on sign of `Buffer-menu-sort-column'.
+;; 5. Go to beginning of buffer if `desired-point' is not defined.
+;; 6. Accommodate `frame-bufs.el'.
+;; 7. Treat Dired buffers like file buffers, e.g., wrt FILES-ONLY.
+;;
+(when (> emacs-major-version 21)
+  (defun list-buffers-noselect (&optional files-only buffer-list)
+    "Create and return a buffer with a list of names of existing buffers.
+The buffer is named `*Buffer List*'.
+Note that buffers with names starting with spaces are omitted.
+Non-null optional arg FILES-ONLY means mention only file buffers.
+
+If BUFFER-LIST is non-nil, it should be a list of buffers;
+it means list those buffers and no others.
+
+For more information, see the function `buffer-menu'."
+    ;; Compute longest buffer name + size combination.
+    ;; $$$$$$ Could be costly if lots of buffers - maybe have an option to be able to not do it?
+    (let ((len  0)
+          buf+size)
+      (setq Buffer-menu-buffer+size-computed-width  Buffer-menu-buffer+size-width)
+      (dolist (buffer (buffer-list))
+        (setq buf+size  (concat (buffer-name buffer) (number-to-string (buffer-size buffer))))
+        (when (and (not (string= (substring buf+size 0 1) " ")) ; Don't count internal buffers.
+                   (> (length buf+size) len))
+          (setq len  (length buf+size))))
+      (when (< (+ len 1) Buffer-menu-buffer+size-width)
+        (setq Buffer-menu-buffer+size-computed-width  (+ len 1))))
+    (let* ((old-buffer       (current-buffer))
+           (standard-output  standard-output)
+           (mode-end         (if Buffer-menu-mode-flag
+                                 (make-string (- Buffer-menu-mode-width 4) ?\ )
+                               ""))
+           (frame-bufs-p     (and (boundp 'frame-bufs-mode) frame-bufs-mode))
+           (header
+            (concat (Buffer-menu-make-sort-button
+                     (concat "CRM" (if frame-bufs-p (if frame-bufs-full-list "F" " ") "")) 1)
+                    " "
+                    (Buffer-menu-buffer+size (Buffer-menu-make-sort-button "Buffer" 2)
+                                             (Buffer-menu-make-sort-button "Size" 3))
+                    "  "
+                    (and Buffer-menu-time-flag
+                         (if (eq 'short Buffer-menu-time-format)
+                             (Buffer-menu-make-sort-button "Time   " 4)
+                           (Buffer-menu-make-sort-button "Time          " 4)))
+                    (and Buffer-menu-time-flag "   ")
+                    (and Buffer-menu-mode-flag
+                         (Buffer-menu-make-sort-button (concat "Mode" mode-end) 5))
+                    (if Buffer-menu-mode-flag
+                        (if Buffer-menu-time-flag " " "  ")
+                      (and (not Buffer-menu-time-flag) " "))
+                    (and Buffer-menu-file-flag (Buffer-menu-make-sort-button
+                                                "File           " 6))
+                    "\n"))
+           list desired-point name buffer-time mode file)
+      (when (and (boundp 'Buffer-menu-use-header-line) Buffer-menu-use-header-line)
+        (let ((pos  0))
+          ;; Turn whitespace chars in the header into stretch specs so
+          ;; they work regardless of the header-line face.
+          (while (string-match "[ \t\n]+" header pos)
+            (setq pos  (match-end 0))
+            (put-text-property (match-beginning 0) pos 'display
+                               ;; Assume fixed-size chars in the buffer.
+                               (list 'space :align-to pos)
+                               header)
+            (put-text-property (match-beginning 0) (1- pos) 'mouse-face 'highlight header)))
+        ;; REMOVED:
+        ;; Try to better align the one-char headers.
+        ;; (put-text-property 0 (if frame-bufs-p 4 3) 'face 'fixed-pitch header)
+        ;; Add a "dummy" leading space to align the beginning of the header
+        ;; line with the beginning of the text (rather than with the left
+        ;; scrollbar or the left fringe). --Stef
+        (setq header  (concat (propertize " " 'display '(space :align-to 0)) header)))
+      (with-current-buffer (get-buffer-create "*Buffer List*")
+        (setq buffer-read-only  nil)
+        (erase-buffer)
+        (setq standard-output  (current-buffer))
+        (unless (and (boundp 'Buffer-menu-use-header-line) Buffer-menu-use-header-line)
+          ;; Use U+2014 (EM DASH) to underline if possible, else use U+002D (HYPHEN-MINUS).
+          ;; Must eval this at compile time.
+          ;; Tried a runtime check of (char-displayable-p ?\u2014), but if this is compiled in
+          ;; an Emacs version before 22 then get an error that `char-displayable-p' is called
+          ;; with two args (since ?\u is interpreted as ?u).
+          (let ((underline  (eval-when-compile (if (> emacs-major-version 21) ?\u2014 ?-))))
+            (insert header (apply 'string
+                                  (mapcar (lambda (ch) (if (memq ch '(?\n ?\  )) ch underline))
+                                          header)))))
+;;;;           (insert header (propertize "---" 'face 'fixed-pitch) " ")
+;;;;           (insert (Buffer-menu-buffer+size "------" "----"))
+;;;;           (insert "  ----" mode-end "----\n")
+;;;;           (put-text-property 1 (point) 'intangible t))
+        ;; Collect info for every buffer we're interested in.
+        (dolist (buffer  (or buffer-list
+                             (and frame-bufs-p  (frame-bufs-buffer-list (selected-frame)
+                                                                        frame-bufs-full-list))
+                             (buffer-list (and Buffer-menu-use-frame-buffer-list
+                                               (selected-frame)))))
+          (with-current-buffer buffer
+            (let ((name  (buffer-name))
+                  (file  (or buffer-file-name
+                             (and (eq major-mode 'dired-mode) default-directory))))
+              (unless (and (not buffer-list)
+                           (or
+                            ;; Don't mention internal buffers.
+                            (and (string= (substring name 0 1) " ") (null file))
+                            ;; Maybe don't mention buffers without files.
+                            (and files-only (not file))
+                            (string= name "*Buffer List*")))
+                ;; Otherwise output info.
+                (let (;; Need to record two values for time: numerical time value, for
+                      ;; sorting, and string time value, for display.
+                      (buffer-time (and Buffer-menu-time-flag
+                                        (cons (or (float-time buffer-display-time) 0)
+                                              (if buffer-display-time
+                                                  (format-time-string
+                                                   (if (eq 'short Buffer-menu-time-format)
+                                                       "%02H:%02M:%02S"
+                                                     "%_3a %_2l:%02M:%02S %_2p")
+                                                   buffer-display-time)
+                                                (if (eq 'short Buffer-menu-time-format)
+                                                    "        "
+                                                  "               ")))))
+                      (mode (concat (format-mode-line mode-name nil nil buffer)
+                                    (and mode-line-process
+                                         (format-mode-line
+                                          mode-line-process nil nil buffer))))
+                      (bits (concat (if (eq buffer old-buffer) "." " ")
+                                    ;; Make output buffer appear read-only, even though it is not
+                                    ;; (yet).  Actually make it read-only later.
+                                    (if (or (eq buffer standard-output) buffer-read-only) 
+                                        "%" 
+                                      " ")
+                                    (if (buffer-modified-p) "*" " ") ; Modified mark.
+                                    (if frame-bufs-p ; Frame-bufs info.
+                                        (frame-bufs-bit-info buffer)
+                                      "")
+                                    " "))) ; Space separator.
+                  (unless file
+                    ;; No visited file.  Check local value of `list-buffers-directory' and,
+                    ;; for Info buffers, `Info-current-file'.
+                    (cond ((and (boundp 'list-buffers-directory) list-buffers-directory)
+                           (setq file  list-buffers-directory))
+                          ((eq major-mode 'Info-mode)
+                           (setq file  Info-current-file)
+                           (cond ((equal file "dir")
+                                  (setq file  "*Info Directory*"))
+                                 ((eq file 'apropos)
+                                  (setq file  "*Info Apropos*"))
+                                 ((eq file 'history)
+                                  (setq file  "*Info History*"))
+                                 ((eq file 'toc)
+                                  (setq file  "*Info TOC*"))
+                                 ((not (stringp file)) ; avoid errors
+                                  (setq file  nil))
+                                 (t
+                                  (setq file  (concat "(" (file-name-nondirectory file) ")"
+                                                      Info-current-node)))))))
+                  (push (list buffer bits name (buffer-size) buffer-time mode file) list))))))
+        ;; Preserve original list order (by reversing).
+        ;; Flip it if Buffer-menu-sort-column = -1.
+        (unless (eq -1 Buffer-menu-sort-column) (setq list  (nreverse list)))
+        ;; Place the buffers's info in the output buffer, sorted if necessary.
+        (dolist (buffer (if (eq 1 (abs Buffer-menu-sort-column))
+                            list
+                          (let* ((descending-p             (natnump Buffer-menu-sort-column))
+                                 (Buffer-menu-sort-column  (abs Buffer-menu-sort-column)))
+                            (sort list
+                                  (cond ((eq Buffer-menu-sort-column 3) ; Size
+                                         (if descending-p
+                                             (lambda (a b) (< (nth 3 a) (nth 3 b)))
+                                           (lambda (a b) (< (nth 3 b) (nth 3 a)))))
+                                        ((eq Buffer-menu-sort-column 4) ; Time (value)
+                                         (if descending-p
+                                             (lambda (a b) (< (car (nth 4 a)) (car (nth 4 b))))
+                                           (lambda (a b) (< (car (nth 4 b)) (car (nth 4 a))))))
+                                        (t
+                                         (if descending-p
+                                             (lambda (a b)
+                                               (string< (nth Buffer-menu-sort-column a)
+                                                        (nth Buffer-menu-sort-column b)))
+                                           (lambda (a b)
+                                             (string< (nth Buffer-menu-sort-column b)
+                                                      (nth Buffer-menu-sort-column a))))))))))
+          (when (eq (car buffer) old-buffer) (setq desired-point  (point)))
+          (insert (cadr buffer)
+                  ;; Put the buffer name into a text property
+                  ;; so we don't have to extract it from the text.
+                  ;; This way we avoid problems with unusual buffer names.
+                  (Buffer-menu-buffer+size (nth 2 buffer)
+                                           (int-to-string (nth 3 buffer))
+                                           `(buffer-name ,(nth 2 buffer) buffer ,(car buffer)
+                                             font-lock-face
+                                             ,(if (facep 'Buffer-menu-buffer-face)
+                                                  'Buffer-menu-buffer-face ; < Emacs 22
+                                                  'Buffer-menu-buffer) ; Emacs 22
+                                             mouse-face highlight
+                                             help-echo "mouse-2: select this buffer")))
+          (when Buffer-menu-time-flag (insert "  " (cdr (nth 4 buffer)))) ; Time
+          (when Buffer-menu-mode-flag
+            (insert "  "
+                    (if (> (length (nth 5 buffer)) Buffer-menu-mode-width) ; Mode
+                        (substring (nth 5 buffer) 0 Buffer-menu-mode-width)
+                      (nth 5 buffer))))
+          (when (and Buffer-menu-file-flag (nth 6 buffer)) ; File
+            (indent-to (+ Buffer-menu-buffer-column Buffer-menu-buffer+size-computed-width
+                          (if Buffer-menu-mode-flag (1+ Buffer-menu-mode-width) 0)
+                          (if Buffer-menu-time-flag
+                              (if (eq 'short Buffer-menu-time-format) 9 16)
+                            0)
+                          3)
+                       1)
+            (princ (abbreviate-file-name (nth 6 buffer))))
+          (princ "\n"))
+        (Buffer-menu-mode)
+        (when (and (boundp 'Buffer-menu-use-header-line) Buffer-menu-use-header-line)
+          (setq header-line-format  header))
+        ;; DESIRED-POINT doesn't have to be set; it is not set when the
+        ;; current buffer is not displayed for some reason.
+        (goto-char (or desired-point (point-min)))
+        (setq Buffer-menu-files-only  files-only)
+        (set-buffer-modified-p nil)
+        (current-buffer)))))
+
+(define-key Buffer-menu-mode-map [down-mouse-3] 'Buffer-menu-mouse-3-menu)
+(define-key Buffer-menu-mode-map [mouse-3] 'ignore)
+
+;; Another way, but it shows the menu even if not on a buffer line,
+;; and it doesn't show it if on the line but not on the buffer name itself.
+;;(defvar Buffer-menu-mouse-3-map (make-sparse-keymap "Buffers"))
+;;(define-key Buffer-menu-mouse-3-map [Buffer-menu-mouse-execute]
+;;  '("Execute: Save/Delete Marked Buffers" . Buffer-menu-mouse-execute))
+;;(define-key Buffer-menu-mouse-3-map [Buffer-menu-mouse-modified]
+;;  '("Mark as Modified/Unmodified (*)" . Buffer-menu-mouse-modified))
+;;(define-key Buffer-menu-mouse-3-map [Buffer-menu-mouse-delete]
+;;  '("Mark to Delete Buffer (D)" . Buffer-menu-mouse-delete))
+;;(define-key Buffer-menu-mouse-3-map [Buffer-menu-mouse-save]
+;;  '("Mark to Save Buffer (S)" . Buffer-menu-mouse-save))
+;;(define-key Buffer-menu-mouse-3-map [Buffer-menu-mouse-unmark]
+;;  '("Unmark Buffer" . Buffer-menu-mouse-unmark))
+;;(define-key Buffer-menu-mouse-3-map [Buffer-menu-mouse-select]
+;;  '("Select Buffer" . Buffer-menu-mouse-select))
+
+(defvar Buffer-menu-overlay nil
+  "Overlay to highlight line of buffer during popup of `mouse-3' menu.")
+
+;;;###autoload
+(defun Buffer-menu-mouse-3-menu (event)
+  "Pop up menu for Mouse-3 for buffer listed in buffer menu."
+  (interactive "e")
+  (let* ((mouse-pos    (event-start event))
+         bol eol temp
+         (buffer-name  (save-excursion
+                         (set-buffer (window-buffer (posn-window mouse-pos)))
+                         (save-excursion
+                           (goto-char (posn-point mouse-pos))
+                           (save-excursion (setq bol  (progn (beginning-of-line) (point))
+                                                 eol  (progn (end-of-line) (point))))
+                           (if Buffer-menu-overlay ; Don't recreate if exists.
+                               (move-overlay Buffer-menu-overlay bol eol (current-buffer))
+                             (setq Buffer-menu-overlay  (make-overlay bol eol))
+                             (overlay-put Buffer-menu-overlay 'face 'region))
+                           (setq temp  (and (not (eobp)) (Buffer-menu-buffer nil)))
+                           ;; Nil if mouse is not on a buffer name.
+                           (and temp (buffer-name temp)))))) ; temp no longer used.
+    (sit-for 0)
+    (let ((selection
+           (x-popup-menu
+            event
+            (list
+             "Menu"
+             (if buffer-name
+                 (list
+                  buffer-name
+                  '("Select Buffer" . Buffer-menu-mouse-select)
+                  '("Unmark Buffer" . Buffer-menu-mouse-unmark)
+                  '("Mark to Save Buffer (S)" . Buffer-menu-mouse-save)
+                  '("Mark to Delete Buffer (D)" . Buffer-menu-mouse-delete)
+                  '("Mark as Modified/Unmodified (*)" . Buffer-menu-mouse-modified)
+                  '("--")               ; Separator: next not buffer-specific.
+                  '("Execute: Save/Delete Marked Buffers" . Buffer-menu-mouse-execute)
+                  '("Delete All `D', Even If Modified" . Buffer-menu-delete-flagged))
+               (list ""
+                     '("Execute: Save/Delete Marked Buffers" . Buffer-menu-mouse-execute)
+                     '("Delete All `D', Even If Modified" . Buffer-menu-delete-flagged)))))))
+      (when Buffer-menu-overlay (delete-overlay Buffer-menu-overlay))
+      (and selection (call-interactively selection)))))
+
+;; Don't need this if use dedicated frame for buffer menu.
+;;;###autoload
+(defun Buffer-menu-mouse-other-window (event)
+  "Select, in another window, the buffer on whose line you click."
+  (interactive "e")
+  (let (buffer)
+    (save-excursion
+      (set-buffer (window-buffer (posn-window (event-end event))))
+      (save-excursion
+        (goto-char (posn-point (event-end event)))
+        (setq buffer  (Buffer-menu-buffer t))))
+    (select-window (posn-window (event-end event)))
+    (switch-to-buffer-other-window buffer)))
+
+;;;###autoload
+(defun Buffer-menu-mouse-unmark (event)
+  "Cancel all requested operations on buffer."
+  (interactive "e")
+  (let ((frame-bufs-p  (and (boundp 'frame-bufs) frame-bufs-mode))
+        buffer)
+    (save-excursion
+      (set-buffer (window-buffer (posn-window (event-end event))))
+      (save-excursion
+        (goto-char (posn-point (event-end event)))
+        (setq buffer  (Buffer-menu-buffer t))))
+    (select-window (posn-window (event-end event)))
+    (goto-char (posn-point (event-end event)))
+    (beginning-of-line)
+    (if (looking-at " [-M]")            ;header lines
+        (ding)
+      (let* ((mod               (buffer-modified-p buffer))
+             (readonly          (save-excursion (set-buffer buffer) buffer-read-only))
+             (buffer-read-only  nil)
+             (local-info        (if frame-bufs-p
+                                    (frame-bufs-bit-info buffer)
+                                  "")))
+        (delete-char (if frame-bufs-p 4 3))
+        (insert (concat (if readonly (if mod " *%" "  %") (if mod " * " "   ")) local-info))))
+    (beginning-of-line)))
+
+;;;###autoload
+(defun Buffer-menu-mouse-save (event)
+  "Mark buffer to be saved.
+Actual deletion is done via `\\<Buffer-menu-mode-map>\\[Buffer-menu-execute]' \
+or `\\<Buffer-menu-mode-map>\\[Buffer-menu-mouse-execute]'."
+  (interactive "e")
+  (select-window (posn-window (event-end event)))
+  (goto-char (posn-point (event-end event)))
+  (beginning-of-line)
+  (forward-char 1)
+  (if (looking-at " [-M]")              ;header lines
+      (ding)
+    (let ((buffer-read-only  nil)) (delete-char 1) (insert ?S)))
+  (beginning-of-line))
+
+;;;###autoload
+(defun Buffer-menu-mouse-delete (event)
+  "Mark buffer to be deleted.
+Actual deletion is done via `\\<Buffer-menu-mode-map>\\[Buffer-menu-execute]' \
+or `\\<Buffer-menu-mode-map>\\[Buffer-menu-mouse-execute]'."
+  (interactive "e")
+  (select-window (posn-window (event-end event)))
+  (goto-char (posn-point (event-end event)))
+  (beginning-of-line)
+  (if (looking-at " [-M]")              ;header lines
+      (ding)
+    (let ((buffer-read-only  nil))  (delete-char 1) (insert ?D)))
+  (beginning-of-line))
+
+;;;###autoload
+(defun Buffer-menu-mouse-modified (event)
+  "Mark buffer as unmodified (no changes to save) if modified, and vice versa."
+  (interactive "e")
+  (select-window (posn-window (event-end event)))
+  (goto-char (posn-point (event-end event)))
+  (beginning-of-line)
+  (forward-char 1)
+  (let ((buffer-read-only  nil)
+        modified-p)
+    (save-excursion
+      (set-buffer (Buffer-menu-buffer t))
+      (set-buffer-modified-p (not (buffer-modified-p))))
+    (cond ((= ?\* (char-after (point)))
+           (delete-char 1)
+           (insert ?\ ))
+          (t
+           (delete-char 1)
+           (insert ?\*))))
+  (beginning-of-line))
+
+;;;###autoload
+(defun Buffer-menu-mouse-execute (event)
+  "Save and/or delete buffers marked `S' or `D', respectively.
+Buffers can be marked via commands `\\<Buffer-menu-mode-map>\
+\\[Buffer-menu-save]' and `\\<Buffer-menu-mode-map>\\[Buffer-menu-delete]'
+\(or `\\<Buffer-menu-mode-map>\\[Buffer-menu-mouse-save]' and \
+`\\<Buffer-menu-mode-map>\\[Buffer-menu-mouse-delete]')."
+  (interactive "e")
+  (select-window (posn-window (event-end event)))
+  (when (and (boundp 'frame-bufs-mode) frame-bufs-mode) (frame-bufs-buffer-menu-execute))
+  (save-excursion
+    (Buffer-menu-beginning)
+    (while (if (> emacs-major-version 21)
+               (re-search-forward "^..S" nil t)
+             (re-search-forward "^.S" nil t))
+      (let ((modp  nil))
+        (save-excursion
+          (set-buffer (Buffer-menu-buffer t))
+          (save-buffer)
+          (setq modp  (buffer-modified-p)))
+        (let ((buffer-read-only  nil))  (delete-char -1) (insert (if modp ?* ? ))))))
+  (save-excursion
+    (Buffer-menu-beginning)
+    (let ((buff-menu-buffer  (current-buffer))
+          (buffer-read-only  nil))
+      (while (re-search-forward "^D" nil t)
+        (forward-char -1)
+        (let ((buf  (Buffer-menu-buffer nil)))
+          (or (eq buf nil) (eq buf buff-menu-buffer)
+              (save-excursion (if (fboundp 'kill-buffer-and-its-windows)
+                                  (kill-buffer-and-its-windows buf)
+                                (kill-buffer buf))))
+          (if (and buf (buffer-name buf))
+              (progn (delete-char 1) (insert ? ))
+            (delete-region (point) (progn (forward-line 1) (point)))
+            (unless (bobp) (forward-char -1))))))))
+
+;;;;;;;;;;;;;;;;;;;;;;;
+
+(provide 'buff-menu+)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; buff-menu+.el ends here

.emacs.d/ri-emacs/ri-emacs.rb

+## ri-emacs.rb helper script for use with ri-ruby.el
+#
+# Author: Kristof Bastiaensen <kristof@vleeuwen.org>
+#
+#
+#    Copyright (C) 2004,2006 Kristof Bastiaensen
+#
+#    This program is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation; either version 2 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program; if not, write to the Free Software
+#    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#----------------------------------------------------------------------
+#
+#  For information on how to use and install see ri-ruby.el
+#
+
+require 'rdoc/ri/ri_paths'
+require 'rdoc/ri/ri_cache'
+require 'rdoc/ri/ri_util'
+require 'rdoc/ri/ri_reader'
+require 'rdoc/ri/ri_formatter'
+require 'rdoc/ri/ri_display'
+
+class DefaultDisplay
+   def full_params(method)
+      method.params.split(/\n/).each do |p|
+         p.sub!(/^#{method.name}\(/o,'(')
+         unless p =~ /\b\.\b/
+            p = method.full_name + p
+         end
+         @formatter.wrap(p) 
+         @formatter.break_to_newline
+      end
+   end
+end
+
+def ruby_minimum_version?(*version)
+   VERSION.split(".").
+      map{ |i| i.to_i }.
+      <=>(version) > -1
+end
+
+class RiEmacs
+   Options = Struct.new(:formatter, :use_stdout, :width)
+
+   def initialize(paths)
+      options = Options.new
+
+      options.use_stdout = true
+      options.formatter = RI::TextFormatter.for("ansi")
+      options.width = 72
+
+      if ruby_minimum_version?(1, 8, 5)
+         begin
+            require 'rubygems'
+            Dir["#{Gem.path}/doc/*/ri"].each do |path|
+               RI::Paths::PATH << path
+            end
+         rescue LoadError
+         end
+      end
+
+      paths = paths || RI::Paths::PATH
+
+      @ri_reader = RI::RiReader.new(RI::RiCache.new(paths))
+      @display = RiDisplay.new(options)
+   end
+
+   def lookup_keyw(keyw)
+      begin
+         desc = NameDescriptor.new(keyw)
+      rescue RiError => e
+         return nil
+      end
+
+      last_space = @ri_reader.top_level_namespace
+      class_name = nil
+      container = desc.class_names.inject(last_space) do
+         |container, class_name|
+         last_space = @ri_reader.lookup_namespace_in(class_name, container)
+         last_space.find_all {|m| m.name == class_name}
+      end
+      
+      if desc.method_name.nil?
+         if [?., ?:, ?#].include? keyw[-1]
+            namespaces = @ri_reader.lookup_namespace_in("", container)
+            is_class_method = case keyw[-1]
+                              when ?.: nil
+                              when ?:: true
+                              when ?#: false
+                              end
+            methods = @ri_reader.find_methods("", is_class_method,
+                                               container)
+            return nil if methods.empty? && namespaces.empty?
+         else
+            #class_name = desc.class_names.last
+            namespaces = last_space.find_all{ |n| n.name.index(class_name).zero? }
+            return nil if namespaces.empty?
+            methods = []
+         end
+      else
+         return nil if container.empty?
+         namespaces = []
+         methods = @ri_reader.
+            find_methods(desc.method_name,
+                         desc.is_class_method,
+                         container).
+            find_all { |m| m.name.index(desc.method_name).zero? }
+         return nil if methods.empty?
+      end
+
+      return desc, methods, namespaces
+   end
+
+   def completion_list(keyw)
+      return @ri_reader.full_class_names if keyw == ""
+
+      desc, methods, namespaces = lookup_keyw(keyw)
+      return nil unless desc
+
+      if desc.class_names.empty?
+         return methods.map { |m| m.name }.uniq
+      else
+         return methods.map { |m| m.full_name } +
+            namespaces.map { |n| n.full_name }
+      end
+   end
+
+   def complete(keyw, type)
+      list = completion_list(keyw)
+
+      if list.nil?
+         return "nil"
+      elsif type == :all
+         return "(" + list.map { |w| w.inspect }.join(" ") + ")"
+      elsif type == :lambda
+         if list.find { |n|
+               n.split(/(::)|#|\./) == keyw.split(/(::)|#|\./) }
+            return "t"
+         else
+            return "nil"
+         end
+      # type == try
+      elsif list.size == 1 and
+            list[0].split(/(::)|#|\./) == keyw.split(/(::)|#|\./)
+         return "t"
+      end
+
+      first = list.shift;
+      if first =~ /(.*)((?:::)|(?:#))(.*)/
+         other = $1 + ($2 == "::" ? "#" : "::") + $3
+      end
+                        
+      len = first.size
+      match_both = false
+      list.each do |w|
+         while w[0, len] != first[0, len]
+            if other and w[0, len] == other[0, len]
+               match_both = true
+               break
+            end
+            len -= 1
+         end
+      end
+
+      if match_both
+         return other.sub(/(.*)((?:::)|(?:#))/) {
+            $1 + "." }[0, len].inspect
+      else
+         return first[0, len].inspect
+      end
+   end
+
+   def display_info(keyw)
+      desc, methods, namespaces = lookup_keyw(keyw)
+      return false if desc.nil?
+      
+      if desc.method_name
+         methods = methods.find_all { |m| m.name == desc.method_name }
+         return false if methods.empty?
+         meth = @ri_reader.get_method(methods[0])
+         @display.display_method_info(meth)
+      else
+         namespaces = namespaces.find_all { |n| n.full_name == desc.full_class_name }
+         return false if namespaces.empty?
+         klass = @ri_reader.get_class(namespaces[0])
+         @display.display_class_info(klass, @ri_reader)
+      end
+
+      return true
+   end
+
+   def display_args(keyw)
+      desc, methods, namespaces = lookup_keyw(keyw)
+      return nil unless desc && desc.class_names.empty?
+
+      methods = methods.find_all { |m| m.name == desc.method_name }
+      return false if methods.empty?
+      methods.each do |m|
+        meth = @ri_reader.get_method(m)
+        @display.full_params(meth)
+      end
+
+      return true
+   end
+
+   # return a list of classes for the method keyw
+   # return nil if keyw has already a class
+   def class_list(keyw, rep='\1')
+      desc, methods, namespaces = lookup_keyw(keyw)
+      return nil unless desc && desc.class_names.empty?
+
+      methods = methods.find_all { |m| m.name == desc.method_name }
+
+      return "(" + methods.map do |m|
+         "(" + m.full_name.sub(/(.*)(#|(::)).*/,
+                                rep).inspect + ")"
+      end.uniq.join(" ") + ")"
+   end
+
+   # flag means (#|::) 
+   # return a list of classes and flag for the method keyw
+   # return nil if keyw has already a class
+   def class_list_with_flag(keyw)
+     class_list(keyw, '\1\2')
+   end
+end
+
+class Command
+   def initialize(ri)
+      @ri = ri
+   end
+
+   Command2Method = {
+      "TRY_COMPLETION" => :try_completion,
+      "COMPLETE_ALL" => :complete_all,
+      "LAMBDA" => :lambda,
+      "CLASS_LIST" => :class_list,
+      "CLASS_LIST_WITH_FLAG" => :class_list_with_flag,
+      "DISPLAY_ARGS" => :display_args,
+      "DISPLAY_INFO" => :display_info}
+      
+   def read_next
+      line = STDIN.gets
+      cmd, param = /(\w+)(.*)$/.match(line)[1..2]
+      method = Command2Method[cmd]
+      fail "unrecognised command: #{cmd}" if method.nil?
+      send(method, param.strip)
+      STDOUT.flush
+   end
+
+   def try_completion(keyw)
+      STDOUT.puts @ri.complete(keyw, :try)
+   end
+
+   def complete_all(keyw)
+      STDOUT.puts @ri.complete(keyw, :all)
+   end
+
+   def lambda(keyw)
+      STDOUT.puts @ri.complete(keyw, :lambda)
+   end
+
+   def class_list(keyw)
+      STDOUT.puts @ri.class_list(keyw)
+   end
+
+   def class_list_with_flag(keyw)
+      STDOUT.puts @ri.class_list_with_flag(keyw)
+   end
+
+   def display_args(keyw)
+      @ri.display_args(keyw)
+      STDOUT.puts "RI_EMACS_END_OF_INFO"
+   end
+
+   def display_info(keyw)
+      @ri.display_info(keyw)
+      STDOUT.puts "RI_EMACS_END_OF_INFO"
+   end
+
+   def test
+      [:try, :all, :lambda].each do |t|
+         @ri.complete("each", t) or
+            fail "@ri.complete(\"each\", #{t.inspect}) returned nil"
+      end
+      @ri.display_info("Array#each") or
+         raise 'display_info("Array#each") returned false'
+   end
+end
+
+arg = ARGV[0]
+
+if arg == "--test"
+   cmd = Command.new(RiEmacs.new(nil))
+   cmd.test
+   puts "Test succeeded"
+else
+   cmd = Command.new(RiEmacs.new(arg))
+   STDOUT.puts 'READY'
+   STDOUT.flush
+   loop { cmd.read_next }
+end

.emacs.d/ri-emacs/ri-ruby.el

+;;;; ri-ruby.el emacs wrapper around ri
+;;
+;; Author: Kristof Bastiaensen <kristof@vleeuwen.org>
+;;
+;;
+;;    Copyright (C) 2004,2006 Kristof Bastiaensen
+;;
+;;    This program is free software; you can redistribute it and/or modify
+;;    it under the terms of the GNU General Public License as published by
+;;    the Free Software Foundation; either version 2 of the License, or
+;;    (at your option) any later version.
+;;
+;;    This program is distributed in the hope that it will be useful,
+;;    but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;    GNU General Public License for more details.
+;;
+;;    You should have received a copy of the GNU General Public License
+;;    along with this program; if not, write to the Free Software
+;;    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;;----------------------------------------------------------------------
+;;
+;;
+;;  Installing:
+;;  ===========
+;;
+;;  add the following to your init.el, replacing the filenames with
+;;  their correct locations:
+;;
+;;  (setq ri-ruby-script "/home/kristof/.xemacs/ri-emacs.rb")