(define-key map "1" 'Buffer-menu-1-window)
(define-key map "f" 'Buffer-menu-this-window)
(define-key map "e" 'Buffer-menu-this-window)
- (define-key map "\C-m" 'Buffer-menu-this-window)
- (define-key map "o" 'Buffer-menu-other-window)
- (define-key map "\C-o" 'Buffer-menu-switch-other-window)
+ (define-key map "\C-m" 'elpher-menu-this-window)
+ (define-key map "o" 'elpher-menu-other-window)
+ (define-key map "\C-o" 'elpher-menu-switch-other-window)
(define-key map "d" 'Buffer-menu-delete)
(define-key map "k" 'Buffer-menu-delete)
(define-key map "\C-k" 'Buffer-menu-delete)
'(menu-item "Select Current" Buffer-menu-1-window
:help "Select this line's buffer, alone, in full frame"))
(bindings--define-key menu-map [ow]
- '(menu-item "Select in Other Window" Buffer-menu-other-window
+ '(menu-item "Select in Other Window" elpher-menu-other-window
:help "Select this line's buffer in other window, leaving buffer menu visible"))
(bindings--define-key menu-map [tw]
- '(menu-item "Select in Current Window" Buffer-menu-this-window
+ '(menu-item "Select in Current Window" elpher-menu-this-window
:help "Select this line's buffer in this window"))
(bindings--define-key menu-map [s2] menu-bar-separator)
(bindings--define-key menu-map [is]
(define-derived-mode elpher-menu-mode tabulated-list-mode "Elpher Menu"
"Major mode for Elpher Menu buffers.
-The Elpher Menu is invoked by the command \\[elpher-menu].
+The Elpher Menu is invoked by the command \\[elpher-menu]. When
+invoked with a prefix, the command also shows history items.
+Since history items are no longer showing in a buffer, many of
+the commands shown below will not work on them.
In Elpher Menu mode, the following commands are defined:
\\<elpher-menu-mode-map>
\\[quit-window] Remove the Buffer Menu from the display.
-\\[tabulated-list-sort] sorts buffers according to the current
+\\[tabulated-list-sort] Sorts buffers according to the current
column. With a numerical argument, sort by that column.
-\\[Buffer-menu-this-window] Select current line's buffer in place of the buffer menu.
-\\[Buffer-menu-other-window] Select that buffer in another window,
+\\[elpher-menu-this-window] Select current line's buffer in place of the buffer menu.
+\\[elpher-menu-other-window] Select that buffer in another window,
so the Buffer Menu remains visible in its window.
-\\[Buffer-menu-switch-other-window] Make another window display that buffer.
+\\[elpher-menu-switch-other-window] Make another window display that buffer.
\\[Buffer-menu-mark] Mark current line's buffer to be displayed.
\\[Buffer-menu-select] Select current line's buffer.
Also show buffers marked with m, in other windows.
\\[Buffer-menu-bury] Bury the buffer listed on this line."
(add-hook 'tabulated-list-revert-hook 'elpher-menu-refresh nil t))
+(defun elpher-menu-this-window ()
+ "Select this line’s buffer in this window.
+Switch to the buffer, if possible. If there is no buffer, chances
+are that we're looking at a history item. Let's visit the item
+instead of complaining that their buffers have been killed."
+ (interactive)
+ (elpher-menu-handle-buffer-or-data 'switch-to-buffer))
+
+(defun elpher-menu-other-window ()
+ "Select this line’s buffer in other window, leaving buffer menu visible."
+ (interactive)
+ (elpher-menu-handle-buffer-or-data 'switch-to-buffer-other-window))
+
+(defun elpher-menu-switch-other-window ()
+ "Make the other window select this line's buffer.
+The current window remains selected."
+ (interactive)
+ (elpher-menu-handle-buffer-or-data
+ (lambda (buf) (display-buffer buf t))))
+
+(defun elpher-menu-handle-buffer-or-data (buffer-func)
+ "Handle an item in `elpher-menu-mode'.
+Determine the entry ID of the Tabulated List entry at point. If
+ID is a buffer, invoke BUFFER-FUNC on it. Otherwise, ID is a
+list (BUFFER FUNC ARGS...). Switch to BUFFER using BUFFER-FUNC
+and apply FUNC to ARGS."
+ (let ((data (tabulated-list-get-id)))
+ (cond ((bufferp data)
+ (funcall buffer-func data))
+ ((and (listp data)
+ (buffer-live-p (nth 0 data))
+ (fboundp (nth 1 data)))
+ (funcall buffer-func (nth 0 data))
+ (apply (nth 1 data) (nthcdr 2 data)))
+ (t
+ (error "There's no entry on this line of the menu")))))
+
(defvar elpher-title nil)
(defun elpher-find-title ()
(defun elpher-menu-refresh (&optional arg)
"Refresh the list of buffers.
-With an optional argument, add all the history items, too."
- ;; Set up `tabulated-list-format'.
+With an optional argument, add all the history items, too. Note
+that there are no buffers for history items so many of the buffer
+menu commands won't work on them."
(setq tabulated-list-format
(vector '("T" 1 t)
'("URL" 40 t)
item refers to and VECTOR is what to display in the tabulated
list established by `elpher-menu-refresh'. See
`tabulated-list-format'."
- (let ((separator (list (current-buffer)
- (vector
- "-"
- (make-string 25 ?-)
- (make-string 25 ?-)))))
+ ;; Every section starts with the current page, followed by some
+ ;; history items, and ends with the separator.
+ (let ((separator (list nil
+ (vector "-"
+ (make-string 25 ?-)
+ (make-string 25 ?-)))))
(cond ((eq major-mode 'elpher-mode)
- ;; every section starts with the current page and ends with
- ;; the separator
- (mapcar (lambda (page)
- (if page
- (list (current-buffer)
+ ;; A pair is (BUFFER-OR-DATA . PAGE) where BUFFER-OR-DTA is
+ ;; the current buffer, if possible, or list (BUFFER FUNC
+ ;; &rest ARGS) telling us which BUFFER to switch to, and
+ ;; what function to call. The last item of elpher-history
+ ;; has a nil page, so when that shows up, use the separator
+ (mapcar (lambda (pair)
+ (if (cdr pair)
+ (list (car pair)
(vector "G"
(or (elpher-address-to-url
- (elpher-page-address page)) "none")
- (or (elpher-page-display-string page) "?")))
+ (elpher-page-address (cdr pair))) "none")
+ (or (elpher-page-display-string (cdr pair)) "?")))
separator))
- (cons elpher-current-page elpher-history)))
+ (cons (cons (current-buffer) elpher-current-page)
+ (mapcar (lambda (page)
+ (cons (list (current-buffer) 'elpher-visit-page page)
+ page))
+ elpher-history))))
((eq major-mode 'gemini-mode)
- ;; no history means a list of one item
+ ;; No history means a list of one item. Add a separator.
(list (list (current-buffer)
(vector "E"
(or (elpher-address-to-url
(elpher-page-address elpher-current-page)))
(or (elpher-page-display-string elpher-current-page)
- (buffer-name))))))
+ (buffer-name))))
+ separator))
((eq major-mode 'eww-mode)
- (nconc (mapcar (lambda (data)
- (list (current-buffer)
- (vector "W"
- (or (plist-get data :url) "none")
- (or (plist-get data :title) "none"))))
- (cons eww-data eww-history))
+ ;; A pair is (BUFFER-OR-DATA . PAGE) where BUFFER-OR-DTA is
+ ;; the current buffer, if possible, or list (BUFFER FUNC
+ ;; &rest ARGS) telling us which BUFFER to switch to, and
+ ;; what function to call. Add the separator at the end.
+ (nconc (cons (list (current-buffer)
+ (vector "W"
+ (or (plist-get eww-data :url) "none")
+ (or (plist-get eww-data :title) "none")))
+ (mapcar (lambda (data)
+ (list
+ (list (current-buffer) 'eww-restore-history data)
+ (vector "W"
+ (or (plist-get data :url) "none")
+ (or (plist-get data :title) "none"))))
+ eww-history))
(list separator))))))
;;; Main start procedure