;;; elpher.el --- A friendly gopher and gemini client -*- lexical-binding: t -*-
-;; Copyright (C) 2021 Jens Östlund <jostlund@gmail.com>
-;; Copyright (C) 2021 F. Jason Park <jp@neverwas.me>
-;; 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>
-;; Copyright (C) 2020 Alexis <flexibeast@gmail.com>
-;; Copyright (C) 2020 Étienne Deparis <etienne@depar.is>
-;; Copyright (C) 2020 Simon Nicolussi <sinic@sinic.name>
-;; Copyright (C) 2020 Michel Alexandre Salim <michel@michel-slm.name>
-;; Copyright (C) 2020 Koushk Roy <kroy@twilio.com>
-;; Copyright (C) 2020 Vee <vee@vnsf.xyz>
-;; Copyright (C) 2020 Simon South <simon@simonsouth.net>
-;; Copyright (C) 2019-2021 Tim Vaughan <plugd@thelambdalab.xyz>
+;; Copyright (C) 2019-2022 Tim Vaughan <plugd@thelambdalab.xyz>
+;; Copyright (C) 2020-2022 Elpher contributors (See info manual for full list)
;; Author: Tim Vaughan <plugd@thelambdalab.xyz>
;; Created: 11 April 2019
-;; Version: 3.2.2
+;; Version: 3.3.1
;; Keywords: comm gopher
;; Homepage: https://thelambdalab.xyz/elpher
;; Package-Requires: ((emacs "27.1"))
;;; Global constants
;;
-(defconst elpher-version "3.2.2"
+(defconst elpher-version "3.3.1"
"Current version of elpher.")
(defconst elpher-margin-width 6
(defvar bookmark-make-record-function)
(defvar mu4e~view-beginning-of-url-regexp)
(defvar eww-use-browse-url)
- (defvar thing-at-point-uri-schemes)
- (defvar xterm-color-preserve-properties))
+ (defvar thing-at-point-uri-schemes))
;;; Customization group
(defcustom elpher-filter-ansi-from-text nil
"If non-nil, filter ANSI escape sequences from text.
-The default behaviour is to use the ansi-color package to interpret these
-sequences."
+The default behaviour is to use the ansi-color package (or xterm-color if it is
+available) to interpret these sequences."
:type '(boolean))
(defcustom elpher-certificate-directory
(unwind-protect
(let ((url (url-generic-parse-url url-string)))
(unless (and (not (url-fullness url)) (url-type url))
- (setf (url-fullness url) t)
(unless (url-type url)
(setf (url-type url) default-scheme))
(unless (url-host url)
(if (cdr p)
(concat "/" (mapconcat #'identity (cdr p) "/"))
""))))
- (when (url-host url)
+ (when (not (string-empty-p (url-host url)))
+ (setf (url-fullness url) t)
(setf (url-host url) (puny-encode-domain (url-host url))))
(when (or (equal "gopher" (url-type url))
(equal "gophers" (url-type url)))
;; avoid resetting buffer-local variables
(elpher-mode))
(let ((inhibit-read-only t)
- (ansi-color-context nil)) ;; clean ansi interpreter state
+ (ansi-color-context nil)) ;; clean ansi interpreter state (also next 2 lines)
+ (setq-local xterm-color--current-fg nil)
+ (setq-local xterm-color--current-bg nil)
(setq-local network-security-level
(default-value 'network-security-level))
(erase-buffer)
(if (display-images-p)
(let* ((image (create-image
data
- nil t))
- (window (get-buffer-window elpher-buffer-name)))
- (when window
- (setf (image-property image :max-width) (window-body-width window t))
- (setf (image-property image :max-height) (window-body-height window t)))
- (elpher-with-clean-buffer
- (insert-image image)
- (elpher-restore-pos)))
+ nil t)))
+ (if (not image)
+ (error "Unsupported image format")
+ (let ((window (get-buffer-window elpher-buffer-name)))
+ (when window
+ (setf (image-property image :max-width) (window-body-width window t))
+ (setf (image-property image :max-height) (window-body-height window t))))
+ (elpher-with-clean-buffer
+ (insert-image image)
+ (elpher-restore-pos))))
(elpher-render-download data))))
;; Search retrieval and rendering
(let ((address (url-generic-parse-url url))
(current-address (elpher-page-address elpher-current-page)))
(unless (and (url-type address) (not (url-fullness address))) ;avoid mangling mailto: urls
- (setf (url-fullness address) t)
(if (url-host address) ;if there is an explicit host, filenames are absolute
(if (string-empty-p (url-filename address))
(setf (url-filename address) "/")) ;ensure empty filename is marked as absolute
(setf (url-host address) (url-host current-address))
+ (setf (url-fullness address) (url-host address)) ; set fullness to t if host is set
(setf (url-portspec address) (url-portspec current-address)) ; (url-port) too slow!
(unless (string-prefix-p "/" (url-filename address)) ;deal with relative links
(setf (url-filename address)
(address (elpher-address-from-gemini-url url))
(type (if address (elpher-address-type address) nil))
(type-map-entry (cdr (assoc type elpher-type-map)))
- (fill-prefix (make-string (+ 1 (length elpher-gemini-link-string)) ?\s))
- (insert elpher-gemini-link-string))
- (if type-map-entry
- (let* ((face (elt type-map-entry 3))
- (display-string (or given-display-string
- (elpher-address-to-iri address)))
- (page (elpher-make-page display-string
- address)))
- (insert-text-button 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)))
- (newline)))))
+ (fill-prefix (make-string (+ 1 (length elpher-gemini-link-string)) ?\s)))
+ (when type-map-entry
+ (insert elpher-gemini-link-string)
+ (let* ((face (elt type-map-entry 3))
+ (display-string (or given-display-string
+ (elpher-address-to-iri address)))
+ (page (elpher-make-page display-string
+ address)))
+ (insert-text-button display-string
+ 'face face
+ 'elpher-page page
+ 'action #'elpher-click-link
+ 'follow-link t
+ 'help-echo #'elpher--page-button-help))
+ (newline))))))
(defun elpher-gemini-insert-header (header-line)
"Insert header described by HEADER-LINE into a text/gemini document.
width defined by `elpher-gemini-max-fill-width'."
(string-match
(rx (: line-start
- (* (any " \t"))
(optional
(group (or (: "*" (+ (any " \t")))
(: ">" (* (any " \t"))))))))
(propertize text-line 'face 'elpher-gemini-quoted))
(t text-line))
text-line))
- (adaptive-fill-mode t)
- ;; fill-prefix is important for adaptive-fill-mode: without
- ;; it, multi-line list items are not indented correct
- (fill-prefix (if (match-string 1 text-line)
+ (fill-prefix (if line-prefix
(make-string (length (match-string 0 text-line)) ?\s)
nil)))
(insert (elpher-process-text-for-display processed-text-line))
(defun elpher-render-gemini-map (data _parameters)
"Render DATA as a gemini map file, PARAMETERS is currently unused."
(elpher-with-clean-buffer
- (let ((preformatted nil))
- (auto-fill-mode 1)
+ (auto-fill-mode 1)
+ (let ((preformatted nil)
+ (adaptive-fill-mode nil)) ;Prevent automatic setting of fill-prefix
(setq-local fill-column (min (window-width) elpher-gemini-max-fill-width))
(dolist (line (split-string data "\n"))
(cond
(buffer-string))))
(defun elpher-build-current-imenu-index ()
+ "Build imenu index for current elpher buffer."
(save-excursion
(goto-char (point-min))
(let ((match nil)
to the buffer."
(let* ((url (cdr (assq 'location bookmark)))
(cleaned-url (string-trim url))
- (page (elpher-page-from-url cleaned-url)))
+ (page (elpher-page-from-url cleaned-url))
+ (buffer (get-buffer-create elpher-buffer-name)))
(elpher-with-clean-buffer
(elpher-visit-page page))
- (set-buffer (get-buffer elpher-buffer-name))
+ (set-buffer buffer)
nil))
(defun elpher-bookmark-link ()
'("^\\(gopher\\|finger\\|gemini\\)://" . elpher-browse-url-elpher))
;; Patch `browse-url-browser-function' for older ones. The value of
;; that variable is `browse-url-default-browser' by default, so
- ;; that's the function that gets advised.
- (advice-add browse-url-browser-function :before-while
- (lambda (url &rest _args)
- "Handle gemini, gopher, and finger schemes using Elpher."
- (let ((scheme (downcase (car (split-string url ":" t)))))
- (if (member scheme '("gemini" "gopher" "finger"))
- ;; `elpher-go' always returns nil, which will stop the
- ;; advice chain here in a before-while
- (elpher-go url)
- ;; chain must continue, then return t.
- t)))))
+ ;; that's the function that gets advised. If the value is an alist,
+ ;; however, we don't know what to do. Better not interfere?
+ (when (and (symbolp browse-url-browser-function)
+ (fboundp browse-url-browser-function))
+ (advice-add browse-url-browser-function :before-while
+ (lambda (url &rest _args)
+ "Handle gemini, gopher, and finger schemes using Elpher."
+ (let ((scheme (downcase (car (split-string url ":" t)))))
+ (if (member scheme '("gemini" "gopher" "finger"))
+ ;; `elpher-go' always returns nil, which will stop the
+ ;; advice chain here in a before-while
+ (elpher-go url)
+ ;; chain must continue, then return t.
+ t))))))
;; Register "gemini://" as a URI scheme so `browse-url' does the right thing
(with-eval-after-load 'thingatpt
(unless (string-empty-p trimmed-host-or-url)
(let ((page (elpher-page-from-url trimmed-host-or-url
(elpher-get-default-url-scheme))))
- (switch-to-buffer elpher-buffer-name)
+ (unless (get-buffer-window elpher-buffer-name t)
+ (switch-to-buffer elpher-buffer-name))
(elpher-with-clean-buffer
(elpher-visit-page page))
nil)))) ; non-nil value is displayed by eshell
(url (read-string (format "Visit URL (default scheme %s): " (elpher-get-default-url-scheme))
(elpher-address-to-url address))))
(unless (string-empty-p (string-trim url))
- (elpher-visit-page (elpher-page-from-url url) (elpher-get-default-url-scheme)))))
+ (elpher-visit-page (elpher-page-from-url url)))))
(defun elpher-redraw ()
"Redraw current page."
(defun elpher-info-page (page)
"Display URL of PAGE in minibuffer."
- (let ((address (elpher-page-address page)))
- (message "%s" (elpher-address-to-url address))))
+ (let* ((address (elpher-page-address page))
+ (url (elpher-address-to-url address))
+ (iri (elpher-address-to-iri address)))
+ (if (equal url iri)
+ (message "%s" url)
+ (message "%s (Raw: %s)" iri url))))
(defun elpher-info-link ()
"Display information on page corresponding to link at point."
(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-build-current-imenu-index)
- (setq-local xterm-color-preserve-properties t))
+ (setq-local imenu-create-index-function #'elpher-build-current-imenu-index))
(when (fboundp 'evil-set-initial-state)
(evil-set-initial-state 'elpher-mode 'motion))