From: Alex Schroeder <alex@gnu.org>
Date: Mon, 20 Jul 2020 09:27:51 +0000 (+0200)
Subject: Implement three commands for history items
X-Git-Url: https://thelambdalab.xyz/gitweb/index.cgi?a=commitdiff_plain;h=dcfd5645105c9db716298cfa1f290e0485694a43;p=elpher.git

Implement three commands for history items

In the Elpher menu, history are shown when invoking it using a prefix.
The history items aren't being shown in a buffer, so switching to
those buffers is not possible. Three buffer menu commands have been
implemented (RET, o, C-o) such that they work with history items.
---

diff --git a/elpher.el b/elpher.el
index 1da26a6..b2bc1c5 100644
--- a/elpher.el
+++ b/elpher.el
@@ -2023,9 +2023,9 @@ With an optional argument, add all the history items, too."
     (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)
@@ -2059,10 +2059,10 @@ With an optional argument, add all the history items, too."
       '(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]
@@ -2099,17 +2099,20 @@ With an optional argument, add all the history items, too."
 
 (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.
@@ -2129,6 +2132,43 @@ In Elpher Menu mode, the following commands are defined:
 \\[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 ()
@@ -2147,8 +2187,9 @@ In Elpher Menu mode, the following commands are defined:
 
 (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)
@@ -2205,38 +2246,56 @@ An item is a list (BUFFER VECTOR) where BUFFER is the buffer this
 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