X-Git-Url: https://thelambdalab.xyz/gitweb/index.cgi?p=elpher.git;a=blobdiff_plain;f=elpher.el;h=a108518ee409f369aab362f9ed3ffa170871c2f9;hp=3fbe0ae4c7e8b3eb3be90449af7c295b0d0137a1;hb=48342f4df45b76756677c47e5205f6a4acdd370f;hpb=8d1d4dded80a52b3d3694bb26df1f5396c2018b2 diff --git a/elpher.el b/elpher.el index 3fbe0ae..a108518 100644 --- a/elpher.el +++ b/elpher.el @@ -92,13 +92,13 @@ (lambda (s) (let ((_xterm-color-render nil)) (xterm-color-filter s))) - 'ansi-color-filter-apply) + #'ansi-color-filter-apply) "A function to filter out ANSI escape sequences.") (defalias 'elpher-color-apply (if (fboundp 'xterm-color-filter) - 'xterm-color-filter - 'ansi-color-apply) + #'xterm-color-filter + #'ansi-color-apply) "A function to apply ANSI escape sequences.") ;;; Global constants @@ -128,30 +128,25 @@ (finger elpher-get-finger-page elpher-render-text "txt" elpher-text) (telnet elpher-get-telnet-page nil "tel" elpher-telnet) (other-url elpher-get-other-url-page nil "url" elpher-other-url) - ((special start) elpher-get-start-page nil) - ((special history) elpher-get-history-page nil) - ((special history-all) elpher-get-history-all-page nil)) + ((special start) elpher-get-start-page nil "E" elpher-index) + ((special history) elpher-get-history-page nil "E" elpher-index) + ((special visited-pages) elpher-get-visited-pages-page nil "E" elpher-index)) "Association list from types to getters, renderers, margin codes and index faces.") -;;; Internal variables -;; - -;; buffer-local -(defvar elpher--gemini-page-headings nil - "List of headings on the page.") - - ;;; Declarations to avoid compiler warnings. ;; (eval-when-compile - (defvar bookmark-make-record-function) + (declare-function ansi-color-filter-apply "ansi-color") + (declare-function ansi-color-apply "ansi-color") (declare-function bookmark-store "bookmark") (declare-function org-link-store-props "ol") (declare-function org-link-set-parameters "ol") - (defvar thing-at-point-uri-schemes) - (defvar mu4e~view-beginning-of-url-regexp)) + (defvar ansi-color-context) + (defvar bookmark-make-record-function) + (defvar mu4e~view-beginning-of-url-regexp) + (defvar thing-at-point-uri-schemes)) ;;; Customization group @@ -397,11 +392,6 @@ requiring gopher-over-TLS." "Create an ADDRESS object corresponding to the given special address symbol TYPE." type) -(defun elpher-make-start-page () - "Create the start page." - (elpher-make-page "Elpher Start Page" - (elpher-make-special-address 'start))) - (defun elpher-address-to-url (address) "Get string representation of ADDRESS, or nil if ADDRESS is special." (if (elpher-address-special-p address) @@ -501,6 +491,11 @@ If no address is defined, returns 0. (This is for compatibility with the URL li "Create a page with DISPLAY-STRING and ADDRESS." (list display-string address)) +(defun elpher-make-start-page () + "Create the start page." + (elpher-make-page "Elpher Start Page" + (elpher-make-special-address 'start))) + (defun elpher-page-display-string (page) "Retrieve the display string corresponding to PAGE." (elt page 0)) @@ -517,25 +512,28 @@ If no address is defined, returns 0. (This is for compatibility with the URL li "The current page for this Elpher buffer.") (defvar elpher-history nil - "The local history for this Elpher buffer. + "The local history stack for this Elpher buffer. This variable is used by `elpher-back' and `elpher-show-history'.") -(defvar elpher-history-all nil +(defvar elpher-visited-pages nil "The global history for all Elpher buffers. -This variable is used by `elpher-show-history-all'.") +This variable is used by `elpher-show-visited-pages'.") (defun elpher-visit-page (page &optional renderer no-history) "Visit PAGE using its own renderer or RENDERER, if non-nil. -Additionally, push PAGE onto the stack of previously-visited pages, -unless NO-HISTORY is non-nil." +Additionally, push PAGE onto the history stack and the list of +previously-visited pages,unless NO-HISTORY is non-nil." (elpher-save-pos) (elpher-process-cleanup) - (unless (or no-history - (equal (elpher-page-address elpher-current-page) - (elpher-page-address page))) - (push elpher-current-page elpher-history) - (push elpher-current-page elpher-history-all)) + (unless no-history + (unless (equal (elpher-page-address elpher-current-page) + (elpher-page-address page)) + (push elpher-current-page elpher-history) + (unless (or (elpher-address-special-p (elpher-page-address page)) + (and elpher-visited-pages + (equal page (car elpher-visited-pages)))) + (push page elpher-visited-pages)))) (setq-local elpher-current-page page) (let* ((address (elpher-page-address page)) (type (elpher-address-type address)) @@ -605,7 +603,8 @@ unless NO-HISTORY is non-nil." (unless (eq major-mode 'elpher-mode) ;; avoid resetting buffer-local variables (elpher-mode)) - (let ((inhibit-read-only t)) + (let ((inhibit-read-only t) + (ansi-color-context nil)) ;; clean ansi interpreter state (setq-local network-security-level (default-value 'network-security-level)) (erase-buffer) @@ -708,12 +707,28 @@ the host operating system and the local network capabilities.)" (condition-case nil (let* ((kill-buffer-query-functions nil) (port (elpher-address-port address)) - (service (if (> port 0) port default-port)) (host (elpher-address-host address)) - (socks (or elpher-socks-always (string-suffix-p ".onion" host))) + (service (if (> port 0) port default-port)) (response-string-parts nil) (bytes-received 0) (hkbytes-received 0) + (socks (or elpher-socks-always (string-suffix-p ".onion" host))) + (gnutls-params (list :type 'gnutls-x509pki + :hostname host + :keylist + (elpher-get-current-keylist address))) + (proc (if socks (socks-open-network-stream "elpher-process" nil host service) + (make-network-process :name "elpher-process" + :host host + :family (and force-ipv4 'ipv4) + :service service + :buffer nil + :nowait t + :tls-parameters + (and use-tls + (cons 'gnutls-x509pki + (apply #'gnutls-boot-parameters + gnutls-params)))))) (timer (run-at-time elpher-connection-timeout nil (lambda () (elpher-process-cleanup) @@ -736,21 +751,7 @@ the host operating system and the local network capabilities.)" response-processor nil force-ipv4)) (t - (elpher-network-error address "Connection time-out.")))))) - (gnutls-params (list :type 'gnutls-x509pki :hostname host - :keylist (elpher-get-current-keylist address))) - (proc (if socks (socks-open-network-stream "elpher-process" nil host service) - (make-network-process :name "elpher-process" - :host host - :family (and force-ipv4 'ipv4) - :service service - :buffer nil - :nowait t - :tls-parameters - (and use-tls - (cons 'gnutls-x509pki - (apply #'gnutls-boot-parameters - gnutls-params))))))) + (elpher-network-error address "Connection time-out."))))))) (setq elpher-network-timer timer) (set-process-coding-system proc 'binary 'binary) (set-process-query-on-exit-flag proc nil) @@ -1063,7 +1064,7 @@ If ADDRESS is not supplied or nil the record is rendered as an (defconst elpher-url-regex "\\([a-zA-Z]+\\)://\\([a-zA-Z0-9.-]*[a-zA-Z0-9-]\\|\\[[a-zA-Z0-9:]+\\]\\)\\(:[0-9]+\\)?\\(/\\([0-9a-zA-Z_~?/@|:.%#=&-]*[0-9a-zA-Z_~?/@|#-]\\)?\\)?" - "Regexp used to locate and buttinofy URLs in text files loaded by elpher.") + "Regexp used to locate and buttonify URLs in text files loaded by elpher.") (defun elpher-buttonify-urls (string) "Turn substrings which look like urls in STRING into clickable buttons." @@ -1082,9 +1083,6 @@ If ADDRESS is not supplied or nil the record is rendered as an 'face 'button))) (buffer-string))) -(defconst elpher-ansi-regex "\x1b\\[[^m]*m" - "Incomplete regexp used to strip out some troublesome ANSI escape sequences.") - (defun elpher-process-text-for-display (string) "Perform any desired processing of STRING prior to display as text. Currently includes buttonifying URLs and processing ANSI escape codes." @@ -1463,6 +1461,9 @@ treatment that a separate function is warranted." (insert (propertize display-string 'face 'elpher-unknown))) (insert "\n")))) +(defvar elpher--gemini-page-headings nil + "List of headings on the page.") + (defun elpher-gemini-insert-header (header-line) "Insert header described by HEADER-LINE into a text/gemini document. The gemini map file line describing the header is given @@ -1603,7 +1604,7 @@ The result is rendered using RENDERER." (browse-url url))))) -;; Start page page retrieval +;; Start page retrieval (defun elpher-get-start-page (renderer) "Getter which displays the start page (RENDERER must be nil)." @@ -1620,7 +1621,7 @@ The result is rendered using RENDERER." "\n" " - TAB/Shift-TAB: next/prev item on current page\n" " - RET/mouse-1: open item under cursor\n" - " - m/M: select an item on current page by name (autocompletes) or number\n" + " - m: select an item on current page by name (autocompletes)\n" " - u/mouse-3/U: return to previous page or to the start page\n" " - g: go to a particular address (gopher, gemini, finger)\n" " - o/O: open a different address selector or the root menu of the current server\n" @@ -1629,7 +1630,7 @@ The result is rendered using RENDERER." " - c/C: copy URL representation of item under cursor or current page\n" " - a/A: bookmark the item under cursor or current page\n" " - B: list all bookmarks\n" - " - s/S: show history of current buffer or for all buffers\n" + " - s/S: show current history stack or all previously visted pages\n" " - r: redraw current page (using cached contents if available)\n" " - R: reload current page (regenerates cache)\n" " - !: set character coding system for gopher (default is to autodetect)\n" @@ -1655,7 +1656,7 @@ The result is rendered using RENDERER." 'face 'link 'action (lambda (_) (interactive) - (call-interactively #'bookmark-bmenu-list)) + (call-interactively #'elpher-open-bookmarks)) 'follow-link t 'help-echo help-string)) (insert ".\n") @@ -1688,50 +1689,58 @@ The result is rendered using RENDERER." ;; History page retrieval -(defun elpher-history () - "Show the history of pages leading to the current page in this buffer. -Use \\[elpher-history-all] to see the entire history. +(defun elpher-show-history () + "Show the current contents of elpher's history stack. +Use \\[elpher-show-visited-pages] to see the entire history. This is rendered using `elpher-get-history-page' via `elpher-type-map'." (interactive) (elpher-visit-page - (elpher-make-page "Elpher History Page" + (elpher-make-page "Current History Stack" (elpher-make-special-address 'history)))) -(defun elpher-history-all () +(defun elpher-show-visited-pages () "Show the all the pages you've visited using Elpher. -Use \\[elpher-history] to see just the history for the current buffer. -This is rendered using `elpher-get-history-all-page' via `elpher-type-map'." +Use \\[elpher-show-history] to see just the current history stack. +This is rendered using `elpher-get-visited-pages-page' via `elpher-type-map'." (interactive) (elpher-visit-page - (elpher-make-page "Elpher History Of All Seen Pages" - (elpher-make-special-address 'history-all)))) + (elpher-make-page "Elpher Visted Pages" + (elpher-make-special-address 'visited-pages)))) (defun elpher-get-history-page (renderer) "Getter which displays the history page (RENDERER must be nil)." (when renderer (elpher-visit-previous-page) (error "Command not supported for history page")) - (elpher-show-history elpher-history)) + (elpher-display-history-links elpher-history "Current history stack")) -(defun elpher-get-history-all-page (renderer) - "Getter which displays the history page (RENDERER must be nil)." +(defun elpher-get-visited-pages-page (renderer) + "Getter which displays the list of visited pages (RENDERER must be nil)." (when renderer (elpher-visit-previous-page) (error "Command not supported for history page")) - (elpher-show-history elpher-history-all)) - -(defun elpher-show-history (pages) - "Show all PAGES in the Elpher buffer." - (elpher-with-clean-buffer - (insert "---- Visited link history ----\n\n") - (if pages - (dolist (page pages) - (when page - (let ((display-string (elpher-page-display-string page)) - (address (elpher-page-address page))) - (elpher-insert-index-record display-string address)))) - (insert "No history items found.\n")) - (insert "\n----------------------------"))) + (elpher-display-history-links + (seq-filter (lambda (page) + (not (elpher-address-special-p (elpher-page-address page)))) + elpher-visited-pages) + "All visited pages")) + +(defun elpher-display-history-links (pages title) + "Show all PAGES in an Elpher buffer with a given TITLE." + (let* ((title-line (concat "---- " title " ----")) + (footer-line (make-string (length title-line) ?-))) + (elpher-with-clean-buffer + (insert title-line "\n\n") + (if pages + (dolist (page pages) + (when page + (let ((display-string (elpher-page-display-string page)) + (address (elpher-page-address page))) + (elpher-insert-index-record display-string address)))) + (insert "No history items found.\n")) + (insert "\n" footer-line "\n" + "Select and entry or press 'u' to return to the previous page.") + (elpher-restore-pos)))) ;;; Bookmarks @@ -1774,15 +1783,21 @@ record for the current elpher page." (let* ((url (cdr (assq 'location bookmark)))) (elpher-go url))) -(defun elpher-set-bookmark-no-overwrite () +(defun elpher-bookmark-link () "Bookmark the link at point. -To bookmark the current page, use \\[bookmark-set-no-overwrite]." +To bookmark the current page, use \\[elpher-bookmark-current]." (interactive) (let ((elpher-bookmark-link t)) (bookmark-set-no-overwrite))) +(defun elpher-bookmark-current () + "Bookmark the current page. +To bookmark the link at point use \\[elpher-bookmark-link]." + (interactive) + (call-interactively #'bookmark-set-no-overwrite)) + (defun elpher-bookmark-import (file) - "Import Elpher bookmarks file FILE into Emacs bookmarks." + "Import legacy Elpher bookmarks file FILE into Emacs bookmarks." (interactive (list (if (and (boundp 'elpher-bookmarks-file) (file-readable-p elpher-bookmarks-file)) elpher-bookmarks-file @@ -1801,6 +1816,23 @@ To bookmark the current page, use \\[bookmark-set-no-overwrite]." (bookmark-store display-string (cdr record) t))) (bookmark-save)) +(defun elpher-open-bookmarks () + "Display the current list of elpher bookmarks. +This is just a call to `bookmark-bmenu-list', but we also check for a legacy +bookmark file and offer to import it." + (interactive) + (let ((old-bookmarks-file (or (and (boundp 'elpher-bookmarks-file) + elpher-bookmarks-file) + (locate-user-emacs-file "elpher-bookmarks")))) + (when (and (file-readable-p old-bookmarks-file) + (y-or-n-p (concat "Legacy elpher-bookmarks file \"" + old-bookmarks-file + "\" found. Import now?"))) + (elpher-bookmark-import old-bookmarks-file) + (rename-file old-bookmarks-file (concat old-bookmarks-file "-legacy")))) + (call-interactively #'bookmark-bmenu-list)) + + ;;; Integrations ;; @@ -2019,7 +2051,7 @@ When run interactively HOST-OR-URL is read from the minibuffer." #'elpher-render-download t))) -(defun elpher-build-link-map () +(defun elpher--build-link-map () "Build alist mapping link names to destination pages in current buffer." (let ((link-map nil) (b (next-button (point-min) t))) @@ -2031,7 +2063,7 @@ When run interactively HOST-OR-URL is read from the minibuffer." (defun elpher-jump () "Select a directory entry by name. Similar to the info browser (m)enu command." (interactive) - (let* ((link-map (elpher-build-link-map))) + (let* ((link-map (elpher--build-link-map))) (if link-map (let ((key (let ((completion-ignore-case t)) (completing-read "Directory item/link: " @@ -2125,8 +2157,8 @@ When run interactively HOST-OR-URL is read from the minibuffer." (define-key map (kbd "g") 'elpher-go) (define-key map (kbd "o") 'elpher-go-current) (define-key map (kbd "O") 'elpher-root-dir) - (define-key map (kbd "s") 'elpher-history) - (define-key map (kbd "S") 'elpher-history-all) + (define-key map (kbd "s") 'elpher-show-history) + (define-key map (kbd "S") 'elpher-show-visited-pages) (define-key map (kbd "r") 'elpher-redraw) (define-key map (kbd "R") 'elpher-reload) (define-key map (kbd "T") 'elpher-toggle-tls) @@ -2138,9 +2170,9 @@ When run interactively HOST-OR-URL is read from the minibuffer." (define-key map (kbd "I") 'elpher-info-current) (define-key map (kbd "c") 'elpher-copy-link-url) (define-key map (kbd "C") 'elpher-copy-current-url) - (define-key map (kbd "a") 'elpher-set-bookmark-no-overwrite) - (define-key map (kbd "A") 'bookmark-set-no-overwrite) - (define-key map (kbd "B") 'bookmark-bmenu-list) + (define-key map (kbd "a") 'elpher-bookmark-link) + (define-key map (kbd "A") 'elpher-bookmark-current) + (define-key map (kbd "B") 'elpher-open-bookmarks) (define-key map (kbd "!") 'elpher-set-gopher-coding-system) (define-key map (kbd "F") 'elpher-forget-current-certificate) (when (fboundp 'evil-define-key*) @@ -2157,6 +2189,8 @@ When run interactively HOST-OR-URL is read from the minibuffer." (kbd "g") 'elpher-go (kbd "o") 'elpher-go-current (kbd "O") 'elpher-root-dir + (kbd "s") 'elpher-show-history + (kbd "S") 'elpher-show-visited-pages (kbd "r") 'elpher-redraw (kbd "R") 'elpher-reload (kbd "T") 'elpher-toggle-tls @@ -2168,9 +2202,9 @@ When run interactively HOST-OR-URL is read from the minibuffer." (kbd "I") 'elpher-info-current (kbd "c") 'elpher-copy-link-url (kbd "C") 'elpher-copy-current-url - (kbd "a") 'elpher-set-bookmark-no-overwrite - (kbd "A") 'bookmark-set-no-overwrite - (kbd "B") 'bookmark-bmenu-list + (kbd "a") 'elpher-bookmark-link + (kbd "A") 'elpher-bookmark-current + (kbd "B") 'elpher-open-bookmarks (kbd "!") 'elpher-set-gopher-coding-system (kbd "F") 'elpher-forget-current-certificate)) map)