X-Git-Url: https://thelambdalab.xyz/gitweb/index.cgi?p=elpher.git;a=blobdiff_plain;f=elpher.el;h=694d8af99d067279480bfaba28d9cc56c1e2e7cf;hp=8c07b850e44098f5f410a1ca04cf9957b7fb8a1a;hb=0d68c92d0ad990230c9c018c1f6d43ef63d052c3;hpb=498e89300cdbaa25b0209567371fbec06bf42400 diff --git a/elpher.el b/elpher.el index 8c07b85..694d8af 100644 --- a/elpher.el +++ b/elpher.el @@ -1,26 +1,11 @@ ;;; elpher.el --- A friendly gopher and gemini client -*- lexical-binding: t -*- -;; Copyright (C) 2021 Jens Östlund -;; Copyright (C) 2021 F. Jason Park -;; Copyright (C) 2021 Christopher Brannon -;; Copyright (C) 2021 Omar Polo -;; Copyright (C) 2021 Noodles! -;; Copyright (C) 2021 Abhiseck Paira -;; Copyright (C) 2020-2021 Alex Schroeder -;; Copyright (C) 2020 Zhiwei Chen -;; Copyright (C) 2020 condy0919 -;; Copyright (C) 2020 Alexis -;; Copyright (C) 2020 Étienne Deparis -;; Copyright (C) 2020 Simon Nicolussi -;; Copyright (C) 2020 Michel Alexandre Salim -;; Copyright (C) 2020 Koushk Roy -;; Copyright (C) 2020 Vee -;; Copyright (C) 2020 Simon South -;; Copyright (C) 2019-2021 Tim Vaughan +;; Copyright (C) 2019-2022 Tim Vaughan +;; Copyright (C) 2020-2022 Elpher contributors (See info manual for full list) ;; Author: Tim Vaughan ;; Created: 11 April 2019 -;; Version: 3.2.2 +;; Version: 3.3.2 ;; Keywords: comm gopher ;; Homepage: https://thelambdalab.xyz/elpher ;; Package-Requires: ((emacs "27.1")) @@ -85,7 +70,7 @@ ;;; Global constants ;; -(defconst elpher-version "3.2.2" +(defconst elpher-version "3.3.2" "Current version of elpher.") (defconst elpher-margin-width 6 @@ -127,11 +112,12 @@ (declare-function org-link-store-props "ol") (declare-function org-link-set-parameters "ol") (defvar ansi-color-context) + (defvar xterm-color--current-fg) + (defvar xterm-color--current-bg) (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 @@ -165,8 +151,8 @@ plain text without user input." (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 @@ -439,7 +425,17 @@ For gopher addresses this is a combination of the selector type and selector." (defun elpher-address-host (address) "Retrieve host from ADDRESS object." - (url-host address)) + (let ((host-pre (url-host address))) + ;; The following strips out square brackets which sometimes enclose IPv6 + ;; addresses. Doing this here rather than at the parsing stage may seem + ;; weird, but this lets us way we avoid having to muck with both URL parsing + ;; and reconstruction. It's also more efficient, as this method is not + ;; called during page rendering. + (if (and (> (length host-pre) 2) + (eq (elt host-pre 0) ?\[) + (eq (elt host-pre (- (length host-pre) 1)) ?\])) + (substring host-pre 1 (- (length host-pre) 1)) + host-pre))) (defun elpher-address-user (address) "Retrieve user from ADDRESS object." @@ -644,7 +640,9 @@ previously-visited pages,unless NO-HISTORY is non-nil." ;; 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) @@ -1175,14 +1173,16 @@ If ADDRESS is not supplied or nil the record is rendered as an (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 @@ -1520,21 +1520,20 @@ treatment that a separate function is warranted." (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))))) + (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. @@ -1566,7 +1565,6 @@ This function uses Emacs' auto-fill to wrap text sensibly to a maximum width defined by `elpher-gemini-max-fill-width'." (string-match (rx (: line-start - (* (any " \t")) (optional (group (or (: "*" (+ (any " \t"))) (: ">" (* (any " \t")))))))) @@ -1584,20 +1582,18 @@ width defined by `elpher-gemini-max-fill-width'." (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)) (newline))) (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 @@ -1622,6 +1618,7 @@ width defined by `elpher-gemini-max-fill-width'." (buffer-string)))) (defun elpher-build-current-imenu-index () + "Build imenu index for current elpher buffer." (save-excursion (goto-char (point-min)) (let ((match nil) @@ -1920,10 +1917,11 @@ then making that buffer the current buffer. It should not switch 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 () @@ -2101,17 +2099,20 @@ supports the old protocol elpher, where the link is self-contained." '("^\\(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 @@ -2158,7 +2159,8 @@ When run interactively HOST-OR-URL is read from the minibuffer." (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 @@ -2170,7 +2172,7 @@ When run interactively HOST-OR-URL is read from the minibuffer." (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." @@ -2278,8 +2280,12 @@ When run interactively HOST-OR-URL is read from the minibuffer." (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." @@ -2409,8 +2415,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-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))