Because of the nature of my work, I need to have a large number of buffers at my fingertips. My buffer list becomes somewhat large, and I need to switch between them quickly while maintaining a train of thought. A good buffer selection mechanism is crucial for productive work. For several years I found that setting a key to the BS buffer list command (see BSBufferSelection) gave me most of what I needed. I learned about sorting and sub-setting the list through variables and hooks that BS provides to locate desired buffers quickly.

Eventually, though, using BS only is somewhat onerous. To switch buffers, one needs to bring up the list of buffers, then find and pick the one desired. You can’t look at the contents first before picking a buffer to type into. To look at one buffer before typing into another necessitates using BS twice. Splitting windows helps with this, but I felt that I could devise something better.

In many situations there is usually a set of a few buffers that are frequently switched to; other buffers are useful to keep on hand, but they don’t need to be looked at as frequently. The similarity of this behavior to paging schemes in operating systems is obvious; the “locality of reference” principle, the “working set” of pages in internal memory, etc. An improved system would let one flip through a “working set” of buffers with minimum effort but would also allow rapid access to the whole buffer list. The system would be minimal and easily tweaked. It would not interrupt the normal work flow, require only the absolute minimum of keystrokes, and be natural to use.

This new system is called ShortList (SL).

ShortList functionality:

In ShortList, the list of buffers stored internally is called SL-list. Three keys are user-defined:

1) The <SL add key>, bound to function (SL-add-key), to add the current buffer to SL-list. (I map M-a to (SL-add-key)).

2) The <SL delete key>, bound to (SL-del-key), to delete the current buffer from SL-list (I map M-d to (SL-del-key); the system also deletes buffers from the short list if the buffer is killed).

3) The <SL function key>, bound to (SL-show) (I use [kp-0]).

When the <SL function key> is pressed, and if SL-list is empty, BS list (my own preferred built-in buffer list function) is invoked. This matches my prior scheme. However, if the user has selected some buffers for SL-list, the behavior changes.

With a non-empty SL-list, when <SL function key> is pressed, the ShortList is displayed in the minibuffer. The current (visible) buffer is highlighted in the ShortList. To view another buffer, press either a number or left or right cursor keys. The newly selected buffer is immediately displayed and the ShortList display is updated. Whenever the ShortList is displayed the left and right arrow keys and number keys are intercepted to switch buffers. If <SL function key> is pressed again, it is intercepted and the full BS list of all buffers appears. Pressing any other key while the Shortlist is shown will cause its function to be executed by the mode of the current buffer, and the ShortList display disappears. For instance, pressing a letter while the ShortList shows will cause (self-insert-command) to be executed in most modes.

Set up:

Here’s a pointer to the ShortList code (shortlist.el); after loading you will need to define the three global keys mentioned above.

Development notes:

A separate mode is overkill, yet some key strokes need to captured and redefined to do the buffer switching. The core of SL uses the Emacs built-in function (read-key-sequence-vector) and the Emacs built-in variable unread-command-events. (read-key-sequence-vector) captures a keystroke as a vector without executing the bound function. Inside the SL-show function, the key is tested and if the keystroke is used for buffer switching it executes within the function. If the key is one not used by the function, then it is “pushed back” (to the variable unread-command-events), to be by reread and executed in the current buffer’s mode.

This scheme works beautifully; see the skeleton function below:

(defun example ()
  "Example function showing the use of read-key-sequence-vector and unread-command-events."
  (let (loop-fl ky kys) 
    (setq loop-fl t)
    (while loop-fl
      (setq loop-fl nil)
      (setq ky (read-key-sequence-vector nil))
      (setq kys (format "%S" ky))  ;; use for string comparisons of the vector
       ((string-match "\\[7\\]" kys) ; allow ^G quitting of this function
        (setq quit-flag t)) ; system-wide built-in flag
       ((string-match "\\[left\\]" kys)  ; move left and right through list
        ;; do whatever you do when pressing the left arrow
        (setq loop-fl t))  ; repeat loop - stay in function
       ((string-match "\\[right\\]" kys)
        ;; do whatever you do when pressing the right arrow
        (setq loop-fl t))  ; repeat loop - stay in function
       ;;; etc. etc. - one cond entry for each key to capture
       (t    ; something else: push back the typed character, exit loop, and let the parent mode handle it
	(setq unread-command-events (append (listify-key-sequence ky) unread-command-events)))))))

In the ShortList system, SL-show is the function that does this. You can modify this function to define your own set of keys.

Parent page : BufferSwitching