X-Git-Url: https://thelambdalab.xyz/gitweb/index.cgi?p=elpher.git;a=blobdiff_plain;f=elpher.el;h=29687f1b62bc1c32e7bd9e79255117904f10a972;hp=a4c88311c8906f9acd7f180af8d8be9ab29adca1;hb=a2074b070a34f3d424638df01bd86dc7dc934cb3;hpb=14cd726993f266d890dcef7b582d173a97926377 diff --git a/elpher.el b/elpher.el index a4c8831..29687f1 100644 --- a/elpher.el +++ b/elpher.el @@ -2010,12 +2010,13 @@ functions which initialize the gopher client, namely ;;; Menu ;; -(defun elpher-menu () - "Show a list of all your `elpher' buffers." - (interactive) +(defun elpher-menu (&optional arg) + "Show a list of all your `elpher' buffers. +With an optional argument, add all the history items, too." + (interactive "P") (switch-to-buffer (get-buffer-create "*Elpher Menu*")) (elpher-menu-mode) - (elpher-menu-refresh) + (elpher-menu-refresh arg) (tabulated-list-print)) (defvar elpher-menu-mode-map @@ -2027,9 +2028,9 @@ functions which initialize the gopher client, namely (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) @@ -2063,10 +2064,10 @@ functions which initialize the gopher client, namely '(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] @@ -2103,17 +2104,20 @@ functions which initialize the gopher client, namely (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: \\ \\[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. @@ -2133,6 +2137,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 () @@ -2142,45 +2183,126 @@ In Elpher Menu mode, the following commands are defined: (let ((start (text-property-any (point-min) (point-max) 'face 'elpher-gemini-heading1))) - (if start - (save-excursion - (goto-char start) - (setq-local elpher-title - (buffer-substring-no-properties - start (line-end-position)))) - "none")))) - -(defun elpher-menu-refresh () - "Refresh the list of buffers." - ;; Set up `tabulated-list-format'. + (when start + (save-excursion + (goto-char start) + (setq-local elpher-title + (buffer-substring-no-properties + start (line-end-position)))))))) + +(defun elpher-menu-refresh (&optional arg) + "Refresh the list of buffers. +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" 35 t) - '("Name" 35 t)) - tabulated-list-sort-key '("Name")) + '("Name" 30 t) + '("URL" 40 t)) + tabulated-list-sort-key nil) ;; Collect info for each buffer we're interested in. (let (entries) (dolist (buf (buffer-list)) (with-current-buffer buf - (when (memq major-mode '(elpher-mode eww-mode)) - (push (list buf - (vector - (cond ((eq major-mode 'elpher-mode) "E") - ((eq major-mode 'eww-mode) "W")) - (cond ((eq major-mode 'elpher-mode) - (or (elpher-address-to-url - (elpher-page-address elpher-current-page)) - "none")) - ((eq major-mode 'eww-mode) - (eww-current-url))) - (cond ((eq major-mode 'elpher-mode) - (elpher-find-title)) - ((eq major-mode 'eww-mode) - (plist-get eww-data :title))))) - entries)))) + (when (memq major-mode '(elpher-mode eww-mode gemini-mode)) + (if arg + (setq entries (nconc (elpher-menu-refresh-history) entries)) + (push (elpher-menu-refresh-current) entries))))) (setq tabulated-list-entries (nreverse entries))) (tabulated-list-init-header)) +(defun elpher-menu-refresh-current () + "Returns an item for `elpher-menu-refresh' +based on the current buffer. + +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'." + (list (current-buffer) + (cond ((eq major-mode 'elpher-mode) + (vector "G" + (or (elpher-find-title) + (elpher-page-display-string elpher-current-page) + (buffer-name)) + (or (elpher-address-to-url + (elpher-page-address elpher-current-page)) + "none"))) + ((eq major-mode 'gemini-mode) + (vector "E" + (or (elpher-page-display-string elpher-current-page) + (buffer-name)) + (or (elpher-address-to-url + (elpher-page-address elpher-current-page)) + "none"))) + ((eq major-mode 'eww-mode) + (vector "W" + (or (plist-get eww-data :title) + (buffer-name)) + (or (eww-current-url) + "none")))))) + +(defun elpher-menu-refresh-history () + "Return current entries for `elpher-menu-refresh'. +This returns a list of items for the current buffer, based on the +buffer's history. + +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'." + ;; 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) + ;; 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-page-display-string (cdr pair)) "?") + (or (elpher-address-to-url + (elpher-page-address (cdr pair))) "none"))) + separator)) + (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. Add a separator. + (list (list (current-buffer) + (vector "E" + (or (elpher-page-display-string elpher-current-page) + (buffer-name)) + (or (elpher-address-to-url + (elpher-page-address elpher-current-page))))) + separator)) + ((eq major-mode 'eww-mode) + ;; 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 :title) "none") + (or (plist-get eww-data :url) "none"))) + (mapcar (lambda (data) + (list + (list (current-buffer) 'eww-restore-history data) + (vector "W" + (or (plist-get data :title) "none") + (or (plist-get data :url) "none")))) + eww-history)) + (list separator)))))) + ;;; Main start procedure ;;