Added Abhiseck Paira to the list of contributors.
[elpher.git] / elpher.el
index 705880f..391bc8b 100644 (file)
--- a/elpher.el
+++ b/elpher.el
@@ -5,6 +5,7 @@
 ;; Copyright (C) 2021 Christopher Brannon <chris@the-brannons.com>
 ;; Copyright (C) 2021 Omar Polo <op@omarpolo.com>
 ;; Copyright (C) 2021 Noodles! <nnoodle@chiru.no>
+;; Copyright (C) 2021 Abhiseck Paira <abhiseckpaira@disroot.org>
 ;; Copyright (C) 2020-2021 Alex Schroeder <alex@gnu.org>
 ;; Copyright (C) 2020 Zhiwei Chen <chenzhiwei03@kuaishou.com>
 ;; Copyright (C) 2020 condy0919 <condy0919@gmail.com>
@@ -19,7 +20,7 @@
 
 ;; Author: Tim Vaughan <plugd@thelambdalab.xyz>
 ;; Created: 11 April 2019
-;; Version: 3.0.0
+;; Version: 3.1.0
 ;; Keywords: comm gopher
 ;; Homepage: https://thelambdalab.xyz/elpher
 ;; Package-Requires: ((emacs "27.1"))
 ;;
 
 (require 'seq)
-(require 'pp)
 (require 'shr)
 (require 'url-util)
 (require 'subr-x)
-(require 'dns)
 (require 'nsm)
 (require 'gnutls)
 (require 'socks)
-
-;;; ANSI colors or XTerm colors
-
-(or (require 'xterm-color nil t)
-    (require 'ansi-color))
-
-(defalias 'elpher-color-filter-apply
-  (if (fboundp 'xterm-color-filter)
-      (lambda (s)
-        (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
-    #'ansi-color-apply)
-  "A function to apply ANSI escape sequences.")
+(require 'bookmark)
 
 ;;; Global constants
 ;;
 
-(defconst elpher-version "3.0.0"
+(defconst elpher-version "3.1.0"
   "Current version of elpher.")
 
 (defconst elpher-margin-width 6
   (defvar ansi-color-context)
   (defvar bookmark-make-record-function)
   (defvar mu4e~view-beginning-of-url-regexp)
-  (defvar thing-at-point-uri-schemes))
+  (defvar thing-at-point-uri-schemes)
+  (defvar xterm-color-preserve-properties))
 
 
 ;;; Customization group
@@ -606,6 +588,7 @@ previously-visited pages,unless NO-HISTORY is non-nil."
 
 (defmacro elpher-with-clean-buffer (&rest args)
   "Evaluate ARGS with a clean *elpher* buffer as current."
+  (declare (debug (body))) ;; Allow edebug to step through body
   `(with-current-buffer elpher-buffer-name
      (unless (eq major-mode 'elpher-mode)
        ;; avoid resetting buffer-local variables
@@ -654,6 +637,57 @@ away CRs and any terminating period."
   (elpher-decode (replace-regexp-in-string "\n\\.\n$" "\n"
                                            (replace-regexp-in-string "\r" "" string))))
 
+;;; Buttonify urls
+
+(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 buttonify URLs in text files loaded by elpher.")
+
+(defun elpher-buttonify-urls (string)
+  "Turn substrings which look like urls in STRING into clickable buttons."
+  (with-temp-buffer
+    (insert string)
+    (goto-char (point-min))
+    (while (re-search-forward elpher-url-regex nil t)
+      (let ((page (elpher-make-page (substring-no-properties (match-string 0))
+                                    (elpher-address-from-url (match-string 0)))))
+        (make-text-button (match-beginning 0)
+                          (match-end 0)
+                          'elpher-page  page
+                          'action #'elpher-click-link
+                          'follow-link t
+                          'help-echo #'elpher--page-button-help
+                          'face 'button)))
+    (buffer-string)))
+
+;;; ANSI colors or XTerm colors (application and filtering)
+
+(or (require 'xterm-color nil t)
+    (require 'ansi-color))
+
+(defalias 'elpher-color-filter-apply
+  (if (fboundp 'xterm-color-filter)
+      (lambda (s)
+        (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
+    #'ansi-color-apply)
+  "A function to apply ANSI escape sequences.")
+
+;;; Processing text for display
+
+(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."
+  (elpher-buttonify-urls (if elpher-filter-ansi-from-text
+                             (elpher-color-filter-apply string)
+                           (elpher-color-apply string))))
+
 
 ;;; Network error reporting
 ;;
@@ -689,7 +723,7 @@ ERROR can be either an error object or a string."
       (cancel-timer elpher-network-timer)))
 
 (defun elpher-make-network-timer (thunk)
-  "Creates a timer to run the THUNK after `elpher-connection-timeout' seconds.
+  "Create a timer to run the THUNK after `elpher-connection-timeout' seconds.
 This is just a wraper around `run-at-time' which additionally sets the
 buffer-local variable `elpher-network-timer' to allow
 `elpher-process-cleanup' to also clear the timer."
@@ -1079,34 +1113,6 @@ If ADDRESS is not supplied or nil the record is rendered as an
 
 ;; Text rendering
 
-(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 buttonify URLs in text files loaded by elpher.")
-
-(defun elpher-buttonify-urls (string)
-  "Turn substrings which look like urls in STRING into clickable buttons."
-  (with-temp-buffer
-    (insert string)
-    (goto-char (point-min))
-    (while (re-search-forward elpher-url-regex nil t)
-      (let ((page (elpher-make-page (substring-no-properties (match-string 0))
-                                    (elpher-address-from-url (match-string 0)))))
-        (make-text-button (match-beginning 0)
-                          (match-end 0)
-                          'elpher-page  page
-                          'action #'elpher-click-link
-                          'follow-link t
-                          'help-echo #'elpher--page-button-help
-                          'face 'button)))
-    (buffer-string)))
-
-(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."
-  (elpher-buttonify-urls (if elpher-filter-ansi-from-text
-                             (elpher-color-filter-apply string)
-                           (elpher-color-apply string))))
-
 (defun elpher-render-text (data &optional _mime-type-string)
   "Render DATA as text.  MIME-TYPE-STRING is unused."
   (elpher-with-clean-buffer
@@ -1669,7 +1675,7 @@ The result is rendered using RENDERER."
    (insert "\n"
            "Your bookmarks are stored in your ")
    (let ((help-string "RET,mouse-1: Open bookmark list"))
-     (insert-text-button "Emacs bookmark list"
+     (insert-text-button "bookmark list"
                          'face 'link
                          'action (lambda (_)
                                    (interactive)
@@ -1708,8 +1714,8 @@ The result is rendered using RENDERER."
                        'help-echo help-string))
    (insert "\n")
    (insert (propertize
-            (concat "  (These documents should be available if you have installed Elpher \n"
-                    "   using MELPA. Otherwise you may have to install the manual yourself.)\n")
+            (concat "(These documents should be available if you have installed Elpher \n"
+                    " using MELPA. Otherwise you may have to install the manual yourself.)\n")
             'face 'shadow))
    (elpher-restore-pos)))
 
@@ -1753,7 +1759,7 @@ This is rendered using `elpher-get-visited-pages-page' via `elpher-type-map'."
 
 (defun elpher-display-history-links (pages title)
   "Show all PAGES in an Elpher buffer with a given TITLE."
-  (let* ((title-line (concat "---- " title " ----"))
+  (let* ((title-line (concat " ---- " title " ----"))
          (footer-line (make-string (length title-line) ?-)))
     (elpher-with-clean-buffer
      (insert title-line "\n\n")
@@ -1764,7 +1770,7 @@ This is rendered using `elpher-get-visited-pages-page' via `elpher-type-map'."
                   (address (elpher-page-address page)))
                (elpher-insert-index-record display-string address))))
        (insert "No history items found.\n"))
-     (insert "\n" footer-line "\n"
+     (insert "\n " footer-line "\n"
              "Select an entry or press 'u' to return to the previous page.")
      (elpher-restore-pos))))
 
@@ -1840,7 +1846,6 @@ To bookmark the link at point use \\[elpher-bookmark-link]."
                       (read-file-name "Old Elpher bookmarks: "
                                       user-emacs-directory nil t
                                       "elpher-bookmarks"))))
-  (require 'bookmark)
   (dolist (bookmark (with-temp-buffer
                      (insert-file-contents file)
                      (read (current-buffer))))
@@ -1857,31 +1862,29 @@ To bookmark the link at point use \\[elpher-bookmark-link]."
   (when renderer
     (elpher-visit-previous-page)
     (error "Command not supported for bookmarks page"))
-  (let* ((names (seq-filter (lambda (name)
-                              (let ((record (bookmark-get-bookmark-record name)))
-                                (eq (alist-get 'handler record) 'elpher-bookmark-jump)))
-                            (bookmark-all-names))))
-    (elpher-with-clean-buffer
-     (insert " ---- Elpher Bookmarks ---- \n\n")
-     (if names
-         (dolist (name (sort names #'string<))
-           (when names
-             (let* ((url (alist-get 'location (bookmark-get-bookmark-record name)))
-                    (address (elpher-address-from-url url)))
-               (elpher-insert-index-record name address))))
-       (insert "No bookmarked pages found.\n"))
-     (insert "\n --------------------------\n\n"
-             "Select an entry or press 'u' to return to the previous page.\n\n")
-     (insert "To rename or delete bookmark entries, open your bookmark list\n"
-             "using the ")
-     (insert-text-button "Emacs bookmark menu"
-                         'action (lambda (_)
-                                   (interactive)
-                                   (call-interactively #'bookmark-bmenu-list))
-                         'follow-link t
-                         'help-echo "RET,mouse-1: open Emacs bookmark menu")
-     (insert (substitute-command-keys " via '\\[bookmark-bmenu-list]'."))
-     (elpher-restore-pos))))
+  (elpher-with-clean-buffer
+   (insert " ---- Elpher Bookmarks ---- \n\n")
+   (bookmark-maybe-load-default-file)
+   (dolist (bookmark (bookmark-maybe-sort-alist))
+     (when (eq #'elpher-bookmark-jump (alist-get 'handler (cdr bookmark)))
+       (let* ((name (car bookmark))
+              (url (alist-get 'location (cdr bookmark)))
+              (address (elpher-address-from-url url)))
+         (elpher-insert-index-record name address))))
+   (when (<= (line-number-at-pos) 3)
+     (insert "No bookmarked pages found.\n"))
+   (insert "\n --------------------------\n\n"
+           "Select an entry or press 'u' to return to the previous page.\n\n"
+           "Bookmarks can be renamed or deleted via the ")
+   (insert-text-button "Emacs bookmark menu"
+                       'action (lambda (_)
+                                 (interactive)
+                                 (call-interactively #'bookmark-bmenu-list))
+                       'follow-link t
+                       'help-echo "RET,mouse-1: open Emacs bookmark menu")
+   (insert (substitute-command-keys
+            ",\nwhich can also be opened from anywhere using '\\[bookmark-bmenu-list]'."))
+   (elpher-restore-pos)))
 
 (defun elpher-show-bookmarks ()
   "Display the current list of elpher bookmarks.
@@ -2015,6 +2018,12 @@ supports the old protocol elpher, where the link is self-contained."
 (setq mu4e~view-beginning-of-url-regexp
       "\\(?:https?\\|gopher\\|finger\\|gemini\\)://\\|mailto:")
 
+;;; eww:
+
+;; Let elpher handle gemini, gopher links in eww buffer.
+(setq eww-use-browse-url
+      "\\`mailto:\\|\\(\\`gemini\\|\\`gopher\\|\\`finger\\)://")
+
 ;;; Interactive procedures
 ;;