X-Git-Url: https://thelambdalab.xyz/gitweb/index.cgi?a=blobdiff_plain;f=elpher.el;h=acd89fce2b5c9a8c62738300a5985db1302f3ed8;hb=d583c4f64c7e59845633931ec364703bf9eb2abb;hp=4a141b761239979e59af3c2a90ce3af59699f9a7;hpb=f9d15bdf681fdd418bd51c4325704d127b7814bc;p=elpher.git diff --git a/elpher.el b/elpher.el index 4a141b7..acd89fc 100644 --- a/elpher.el +++ b/elpher.el @@ -1368,17 +1368,20 @@ treatment that a separate function is warranted." The gemini map file line describing the header is given by HEADER-LINE." (when (string-match "^\\(#+\\)[ \t]*" header-line) - (let ((level (length (match-string 1 header-line))) - (header (substring header-line (match-end 0)))) + (let* ((level (length (match-string 1 header-line))) + (header (substring header-line (match-end 0))) + (face (pcase level + (1 'elpher-gemini-heading1) + (2 'elpher-gemini-heading2) + (3 'elpher-gemini-heading3) + (_ 'default))) + (fill-column (/ (* fill-column + (font-get (font-spec :name (face-font 'default)) :size)) + (font-get (font-spec :name (face-font face)) :size)))) (unless (display-graphic-p) (insert (make-string level ?#) " ")) - (insert (propertize header 'face - (pcase level - (1 'elpher-gemini-heading1) - (2 'elpher-gemini-heading2) - (3 'elpher-gemini-heading3) - (_ 'default))) - "\n")))) + (insert (propertize header 'face face)) + (newline)))) (defun elpher-gemini-insert-text (text-line) "Insert a plain non-preformatted TEXT-LINE into a text/gemini document. @@ -2005,12 +2008,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 @@ -2022,9 +2026,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) @@ -2058,10 +2062,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] @@ -2098,17 +2102,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. @@ -2128,6 +2135,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 () @@ -2137,45 +2181,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 ;;