Make byte-compiler happy again
[elpher.git] / elpher.el
index 3fbe0ae..a108518 100644 (file)
--- a/elpher.el
+++ b/elpher.el
       (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
     (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)