;; Author: Tim Vaughan <timv@ughan.xyz>
;; Created: 11 April 2019
-;; Version: 2.7.0
+;; Version: 2.7.1
;; Keywords: comm gopher
;; Homepage: http://thelambdalab.xyz/elpher
;; Package-Requires: ((emacs "26"))
;;; Commentary:
-;; Elpher aims to provide a practical and friendly gopher client
-;; for GNU Emacs. It supports:
+;; Elpher aims to provide a practical and friendly gopher, gemini,
+;; and finger client for GNU Emacs. It supports:
;; - intuitive keyboard and mouse-driven browsing,
;; - out-of-the-box compatibility with evil-mode,
;;; Global constants
;;
-(defconst elpher-version "2.7.0"
+(defconst elpher-version "2.7.1"
"Current version of elpher.")
(defconst elpher-margin-width 6
:type '(boolean))
(defcustom elpher-gemini-TLS-cert-checks nil
- "If non-nil, verify gemini server TLS certificates using the default
-emacs security protocol. Otherwise, certificate verification is disabled.
+ "If non-nil, verify gemini server TLS certs using the default security level.
+Otherwise, certificate verification is disabled.
This defaults to off because it is standard practice for Gemini servers
to use self-signed certificates, meaning that most servers provide what
-emacs considers to be an invalid certificate."
+EMACS considers to be an invalid certificate."
:type '(boolean))
(defcustom elpher-gemini-max-fill-width 80
"Retrieve the address corresponding to PAGE."
(elt page 1))
+(defun elpher-page-set-address (page new-address)
+ "Set the address corresponding to PAGE to NEW-ADDRESS."
+ (setcar (cdr page) new-address))
+
(defvar elpher-current-page nil)
(defvar elpher-history nil)
(let ((previous-page (pop elpher-history)))
(if previous-page
(elpher-visit-page previous-page nil t)
- (error "No previous page."))))
+ (error "No previous page"))))
(defun elpher-reload-current-page ()
"Reload the current page, discarding any existing cached content."
"gemini"))
(error "Server tried to automatically redirect to non-gemini URL: %s"
response-meta))
+ (elpher-page-set-address elpher-current-page redirect-address)
(add-to-list 'elpher-gemini-redirect-chain redirect-address)
(elpher-get-gemini-response redirect-address renderer)))
(?4 ; Temporary failure
(_other
(error "Unsupported MIME type %S" mime-type))))))
-(defun elpher-gemini-get-link-url (line)
- "Extract the url portion of LINE, a gemini map file link line."
- (string-trim (elt (split-string (substring line 2)) 0)))
-
-(defun elpher-gemini-get-link-display-string (line)
- "Extract the display string portion of LINE, a gemini map file link line."
- (let* ((rest (string-trim (elt (split-string line "=>") 1)))
+(defun elpher-gemini-get-link-url (link-line)
+ "Extract the url portion of LINK-LINE, a gemini map file link line.
+Returns nil in the event that the contents of the line following the
+=> prefix are empty."
+ (let ((l (split-string (substring link-line 2))))
+ (if l
+ (string-trim (elt l 0))
+ nil)))
+
+(defun elpher-gemini-get-link-display-string (link-line)
+ "Extract the display string portion of LINK-LINE, a gemini map file link line.
+Returns the url portion in the event that the display-string portion is empty."
+ (let* ((rest (string-trim (elt (split-string link-line "=>") 1)))
(idx (string-match "[ \t]" rest)))
- (if idx
- (string-trim (substring rest (+ idx 1)))
- "")))
+ (string-trim (if idx
+ (substring rest (+ idx 1))
+ rest))))
(defun elpher-collapse-dot-sequences (filename)
"Collapse dot sequences in FILENAME.
address))
(defun elpher-gemini-insert-link (link-line)
- "Insert link into a text/gemini document."
+ "Insert link described by LINK-LINE into a text/gemini document."
(let* ((url (elpher-gemini-get-link-url link-line))
- (display-string (let ((s (elpher-gemini-get-link-display-string link-line)))
- (if (string-empty-p s) url s)))
+ (display-string (elpher-gemini-get-link-display-string link-line))
(address (elpher-address-from-gemini-url url))
(type (if address (elpher-address-type address) nil))
(type-map-entry (cdr (assoc type elpher-type-map))))
- (insert "→ ")
- (if type-map-entry
- (let* ((face (elt type-map-entry 3))
- (filtered-display-string (ansi-color-filter-apply display-string))
- (page (elpher-make-page filtered-display-string address)))
- (insert-text-button filtered-display-string
- 'face face
- 'elpher-page page
- 'action #'elpher-click-link
- 'follow-link t
- 'help-echo (elpher-page-button-help page)))
- (insert (propertize display-string 'face 'elpher-unknown)))
- (insert "\n")))
+ (when display-string
+ (insert "→ ")
+ (if type-map-entry
+ (let* ((face (elt type-map-entry 3))
+ (filtered-display-string (ansi-color-filter-apply display-string))
+ (page (elpher-make-page filtered-display-string address)))
+ (insert-text-button filtered-display-string
+ 'face face
+ 'elpher-page page
+ 'action #'elpher-click-link
+ 'follow-link t
+ 'help-echo (elpher-page-button-help page)))
+ (insert (propertize display-string 'face 'elpher-unknown)))
+ (insert "\n"))))
(defun elpher-gemini-insert-header (header-line)
- "Insert header into a text/gemini document.
+ "Insert header described by HEADER-LINE into a text/gemini document.
The gemini map file line describing the header is given
by HEADER-LINE."
(when (string-match "^\\(#+\\)[ \t]*" header-line)
(unless (display-graphic-p)
(insert (make-string level ?#) " "))
(insert (propertize header 'face
- (case level
- ((1) 'elpher-gemini-heading1)
- ((2) 'elpher-gemini-heading2)
- ((3) 'elpher-gemini-heading3)
- (t 'default)))
+ (pcase level
+ (1 'elpher-gemini-heading1)
+ (2 'elpher-gemini-heading2)
+ (3 'elpher-gemini-heading3)
+ (_ 'default)))
"\n"))))
(defun elpher-render-gemini-map (data _parameters)
" - m: select an item on current page by name (autocompletes)\n"
" - u/mouse-3: return to previous page\n"
" - o/O: visit different selector or the root menu of the current server\n"
- " - g: go to a particular gopher address\n"
+ " - g: go to a particular address (gopher, gemini, finger)\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"
(elpher-insert-index-record "Floodgap Systems Gopher Server"
(elpher-make-gopher-address ?1 "" "gopher.floodgap.com" 70))
(insert "\n"
- "Alternatively, select the following item and enter some search terms:\n")
+ "Alternatively, select a search engine and enter some search terms:\n")
+ (elpher-insert-index-record "GUS Gemini Search Engine"
+ (elpher-address-from-url "gemini://gus.guru/search"))
(elpher-insert-index-record "Veronica-2 Gopher Search Engine"
(elpher-make-gopher-address ?7 "/v2/vs" "gopher.floodgap.com" 70))
(insert "\n"