(Temporarily?) removed link numbering code.
[elpher.git] / elpher.el
index 6530949..3fbe0ae 100644 (file)
--- a/elpher.el
+++ b/elpher.el
@@ -19,9 +19,9 @@
 
 ;; Author: Tim Vaughan <plugd@thelambdalab.xyz>
 ;; Created: 11 April 2019
-;; Version: 2.11.0
+;; Version: 3.0.0
 ;; Keywords: comm gopher
-;; Homepage: https://alexschroeder.ch/cgit/elpher
+;; Homepage: https://thelambdalab.xyz/elpher
 ;; Package-Requires: ((emacs "27.1"))
 
 ;; This file is not part of GNU Emacs.
@@ -62,7 +62,8 @@
 
 ;; Elpher is under active development.  Any suggestions for
 ;; improvements are welcome, and can be made on the official
-;; project page, https://alexschroeder.ch/cgit/elpher.
+;; project page, gopher://thelambdalab.xyz/elpher, or via the
+;; project mailing list at https://lists.sr.ht/~michel-slm/elpher.
 
 ;;; Code:
 
 (defalias 'elpher-color-filter-apply
   (if (fboundp 'xterm-color-filter)
       (lambda (s)
-        (let ((xterm-color-render nil))
+        (let ((_xterm-color-render nil))
           (xterm-color-filter s)))
     'ansi-color-filter-apply)
   "A function to filter out ANSI escape sequences.")
+
 (defalias 'elpher-color-apply
   (if (fboundp 'xterm-color-filter)
       'xterm-color-filter
 ;;; Global constants
 ;;
 
-(defconst elpher-version "2.11.0"
+(defconst elpher-version "3.0.0"
   "Current version of elpher.")
 
 (defconst elpher-margin-width 6
   "List of headings on the page.")
 
 
+;;; Declarations to avoid compiler warnings.
+;;
+
+(eval-when-compile
+  (defvar bookmark-make-record-function)
+  (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))
+
+
 ;;; Customization group
 ;;
 
@@ -225,11 +239,6 @@ some servers which do not support IPv6 can take a long time to time-out."
 Otherwise, the SOCKS proxy is only used for connections to onion services."
   :type '(boolean))
 
-(defcustom elpher-number-links nil
-  "If non-nil, number links in pages when rendering.
-Links can be followed numerically by pressing `M' and entering by the link number."
-  :type '(boolean))
-
 ;; Face customizations
 
 (defgroup elpher-faces nil
@@ -522,7 +531,6 @@ Additionally, push PAGE onto the stack of previously-visited pages,
 unless NO-HISTORY is non-nil."
   (elpher-save-pos)
   (elpher-process-cleanup)
-  (elpher-reset-link-number-counter)
   (unless (or no-history
               (equal (elpher-page-address elpher-current-page)
                      (elpher-page-address page)))
@@ -531,8 +539,7 @@ unless NO-HISTORY is non-nil."
   (setq-local elpher-current-page page)
   (let* ((address (elpher-page-address page))
          (type (elpher-address-type address))
-         (type-record (cdr (assoc type elpher-type-map)))
-         (page-links nil))
+         (type-record (cdr (assoc type elpher-type-map))))
     (if type-record
         (funcall (car type-record)
                  (if renderer
@@ -1007,22 +1014,6 @@ displayed.  The _WINDOW argument is currently unused."
                                                 address
                                               (elpher-address-to-url address))))))))
 
-(defvar elpher--link-number-counter 0)
-(defun elpher-reset-link-number-counter ()
-  (setq-local elpher--link-number-counter 0))
-
-(defun elpher--insert-text-button (label &rest properties)
-  "Inserts a potentially-numbered button into the current buffer.
-The text for the button is provided by LABEL, while the button
-properties in PROPERTIES are as per `insert-text-button'."
-
-  (if elpher-number-links
-      (setq-local elpher--link-number-counter (+ elpher--link-number-counter 1)))
-  (let ((pref (if elpher-number-links
-                  (concat "[" (number-to-string elpher--link-number-counter) "] ")
-                "")))
-    (apply #'insert-text-button (cons (concat pref label) properties))))
-
 (defun elpher-insert-index-record (display-string &optional address)
   "Function to insert an index record into the current buffer.
 The contents of the record are dictated by DISPLAY-STRING and ADDRESS.
@@ -1036,12 +1027,12 @@ If ADDRESS is not supplied or nil the record is rendered as an
                (filtered-display-string (elpher-color-filter-apply display-string))
                (page (elpher-make-page filtered-display-string address)))
           (elpher-insert-margin margin-code)
-          (elpher--insert-text-button filtered-display-string
-                                      'face face
-                                      'elpher-page page
-                                      'action #'elpher-click-link
-                                      'follow-link t
-                                      'help-echo #'elpher--page-button-help))
+          (insert-text-button filtered-display-string
+                              'face face
+                              'elpher-page page
+                              'action #'elpher-click-link
+                              'follow-link t
+                              'help-echo #'elpher--page-button-help))
       (pcase type
         ('nil ;; Information
          (elpher-insert-margin)
@@ -1288,10 +1279,15 @@ that the response was malformed."
          (error "Gemini server response unknown: %s %s"
                 response-code response-meta))))))
 
-(unless (fboundp 'read-answer)
-  (defun read-answer (question answers)
-    "Backfill for the new read-answer code."
-    (completing-read question (mapcar 'identity answers))))
+(defun elpher--read-answer-polyfill (question answers)
+  "Polyfill for `read-answer' in Emacs 26.1.
+QUESTION is a string containing a question, and ANSWERS
+is a list of possible answers."
+    (completing-read question (mapcar 'identity answers)))
+
+(if (fboundp 'read-answer)
+    (defalias 'elpher-read-answer 'read-answer)
+  (defalias 'elpher-read-answer 'elpher--read-answer-polyfill))
 
 (defun elpher-choose-client-certificate ()
   "Prompt for a client certificate to use to establish a TLS connection."
@@ -1458,12 +1454,12 @@ treatment that a separate function is warranted."
           (let* ((face (elt type-map-entry 3))
                  (filtered-display-string (elpher-color-filter-apply display-string))
                  (page (elpher-make-page filtered-display-string address)))
-            (elpher--insert-text-button filtered-display-string
-                                        'face face
-                                        'elpher-page page
-                                        'action #'elpher-click-link
-                                        'follow-link t
-                                        'help-echo #'elpher--page-button-help))
+            (insert-text-button filtered-display-string
+                                'face face
+                                'elpher-page page
+                                'action #'elpher-click-link
+                                'follow-link t
+                                'help-echo #'elpher--page-button-help))
         (insert (propertize display-string 'face 'elpher-unknown)))
       (insert "\n"))))
 
@@ -1626,8 +1622,8 @@ The result is rendered using RENDERER."
            " - RET/mouse-1: open item under cursor\n"
            " - m/M: select an item on current page by name (autocompletes) or number\n"
            " - u/mouse-3/U: return to previous page or to the start page\n"
-           " - o/O: visit different selector or the root menu of the current server\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"
            " - d/D: download item under cursor or current page\n"
            " - i/I: info on item under cursor or current page\n"
            " - c/C: copy URL representation of item under cursor or current page\n"
@@ -1652,6 +1648,20 @@ The result is rendered using RENDERER."
                                (elpher-make-gopher-address ?7 "/v2/vs" "gopher.floodgap.com" 70))
    (elpher-insert-index-record "Gemini Search Engine (geminispace.info)"
                                (elpher-address-from-url "gemini://geminispace.info/search"))
+   (insert "\n"
+           "Your bookmarks are stored in your ")
+   (let ((help-string "RET,mouse-1: Open Emacs bookmark list"))
+     (insert-text-button "Emacs bookmark list"
+                         'face 'link
+                         'action (lambda (_)
+                                   (interactive)
+                                   (call-interactively #'bookmark-bmenu-list))
+                         'follow-link t
+                         'help-echo help-string))
+   (insert ".\n")
+   (insert (propertize
+            "(Bookmarks from legacy elpher-bookmarks files will be automatically imported.)\n"
+            'face 'shadow))
    (insert "\n"
            "For Elpher release news or to leave feedback, visit:\n")
    (elpher-insert-index-record "The Elpher Project Page"
@@ -1662,13 +1672,13 @@ The result is rendered using RENDERER."
    (insert "\n"
            "** Refer to the ")
    (let ((help-string "RET,mouse-1: Open Elpher info manual (if available)"))
-     (elpher--insert-text-button "Elpher info manual"
-                                 'face 'link
-                                 'action (lambda (_)
-                                           (interactive)
-                                           (info "(elpher)"))
-                                 'follow-link t
-                                 'help-echo help-string))
+     (insert-text-button "Elpher info manual"
+                         'face 'link
+                         'action (lambda (_)
+                                   (interactive)
+                                   (info "(elpher)"))
+                         'follow-link t
+                         'help-echo help-string))
    (insert " for the full documentation. **\n")
    (insert (propertize
             (concat "  (This should be available if you have installed Elpher using\n"
@@ -1796,11 +1806,6 @@ To bookmark the current page, use \\[bookmark-set-no-overwrite]."
 
 ;;; Org
 
-;; Avoid byte compilation warnings.
-(eval-when-compile
-  (declare-function org-link-store-props "ol")
-  (declare-function org-link-set-parameters "ol"))
-
 (defun elpher-org-export-link (link description format protocol)
   "Export a LINK with DESCRIPTION for the given PROTOCOL and FORMAT.
 
@@ -1844,7 +1849,8 @@ supports the old protocol elpher, where the link is self-contained."
                (format "%s:%s" protocol link))))
     (elpher-go url)))
 
-(with-eval-after-load 'org
+(defun elpher-org-mode-integration ()
+  "Set up `elpher' integration for `org-mode'."
   (org-link-set-parameters
    "elpher"
    :store #'elpher-org-store-link
@@ -1867,11 +1873,9 @@ supports the old protocol elpher, where the link is self-contained."
              (elpher-org-export-link link description format "finger"))
    :follow (lambda (link _arg) (elpher-org-follow-link link "finger"))))
 
-;;; Browse URL
+(add-hook 'org-mode-hook #'elpher-org-mode-integration)
 
-;; Avoid byte compilation warnings.
-(eval-when-compile
-  (defvar thing-at-point-uri-schemes))
+;;; Browse URL
 
 ;;;###autoload
 (defun elpher-browse-url-elpher (url &rest _args)
@@ -1905,13 +1909,9 @@ supports the old protocol elpher, where the link is self-contained."
 
 ;;; Mu4e:
 
-(eval-when-compile
-  (defvar mu4e~view-beginning-of-url-regexp))
-
-(with-eval-after-load 'mu4e-view
-  ;; Make mu4e aware of the gemini world
-  (setq mu4e~view-beginning-of-url-regexp
-        "\\(?:https?\\|gopher\\|finger\\|gemini\\)://\\|mailto:"))
+;; Make mu4e aware of the gemini world
+(setq mu4e~view-beginning-of-url-regexp
+      "\\(?:https?\\|gopher\\|finger\\|gemini\\)://\\|mailto:")
 
 ;;; Interactive procedures
 ;;
@@ -2041,17 +2041,6 @@ When run interactively HOST-OR-URL is read from the minibuffer."
                 (goto-char (button-start b))
                 (button-activate b)))))))
 
-(defun elpher-jump-to-number (n)
-  "Jump to directory entry number N."
-  (interactive "nDirectory item/link number: ")
-  (let* ((link-map (reverse (elpher-build-link-map))))
-    (if link-map
-        (if (<= 1 n (length link-map))
-            (let ((b (cdr (elt link-map (- n 1)))))
-              (goto-char (button-start b))
-              (button-activate b))
-          (error "No link with that number.")))))
-
 (defun elpher-root-dir ()
   "Visit root of current server."
   (interactive)
@@ -2133,9 +2122,9 @@ When run interactively HOST-OR-URL is read from the minibuffer."
     (define-key map (kbd "^") 'elpher-back)
     (define-key map [mouse-3] 'elpher-back)
     (define-key map (kbd "U") 'elpher-back-to-start)
-    (define-key map (kbd "O") 'elpher-root-dir)
     (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 "r") 'elpher-redraw)
@@ -2145,7 +2134,6 @@ When run interactively HOST-OR-URL is read from the minibuffer."
     (define-key map (kbd "d") 'elpher-download)
     (define-key map (kbd "D") 'elpher-download-current)
     (define-key map (kbd "m") 'elpher-jump)
-    (define-key map (kbd "M") 'elpher-jump-to-number)
     (define-key map (kbd "i") 'elpher-info-link)
     (define-key map (kbd "I") 'elpher-info-current)
     (define-key map (kbd "c") 'elpher-copy-link-url)
@@ -2166,8 +2154,9 @@ When run interactively HOST-OR-URL is read from the minibuffer."
        (kbd "^") 'elpher-back
        [mouse-3] 'elpher-back
        (kbd "U") 'elpher-back-to-start
-       (kbd "o") 'elpher-go
-       (kbd "O") 'elpher-go-current
+       (kbd "g") 'elpher-go
+       (kbd "o") 'elpher-go-current
+       (kbd "O") 'elpher-root-dir
        (kbd "r") 'elpher-redraw
        (kbd "R") 'elpher-reload
        (kbd "T") 'elpher-toggle-tls
@@ -2175,7 +2164,6 @@ When run interactively HOST-OR-URL is read from the minibuffer."
        (kbd "d") 'elpher-download
        (kbd "D") 'elpher-download-current
        (kbd "m") 'elpher-jump
-       (kbd "M") 'elpher-jump-to-number
        (kbd "i") 'elpher-info-link
        (kbd "I") 'elpher-info-current
        (kbd "c") 'elpher-copy-link-url
@@ -2199,7 +2187,7 @@ functions which initialize the client, namely
   (setq-local elpher-history nil)
   (setq-local elpher-buffer-name (buffer-name))
   (setq-local bookmark-make-record-function #'elpher-bookmark-make-record)
-  (setq-local imenu-create-index-function #'elpher--gemini-page-headings))
+  (setq-local imenu-create-index-function (lambda () elpher--gemini-page-headings)))
 
 (when (fboundp 'evil-set-initial-state)
   (evil-set-initial-state 'elpher-mode 'motion))