X-Git-Url: https://thelambdalab.xyz/gitweb/index.cgi?p=elpher.git;a=blobdiff_plain;f=elpher.el;h=ef20de034e71f891beccc6fea904db443244f512;hp=a108518ee409f369aab362f9ed3ffa170871c2f9;hb=3d2817e533e03d2d0eb9e0dd5d573083127bc055;hpb=48342f4df45b76756677c47e5205f6a4acdd370f diff --git a/elpher.el b/elpher.el index a108518..ef20de0 100644 --- a/elpher.el +++ b/elpher.el @@ -61,8 +61,8 @@ ;; Full instructions can be found in the Elpher info manual. ;; Elpher is under active development. Any suggestions for -;; improvements are welcome, and can be made on the official -;; project page, gopher://thelambdalab.xyz/elpher, or via the +;; improvements are welcome, and can be made on the official project +;; page, gopher://thelambdalab.xyz/1/projects/elpher, or via the ;; project mailing list at https://lists.sr.ht/~michel-slm/elpher. ;;; Code: @@ -82,25 +82,6 @@ (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.") - ;;; Global constants ;; @@ -647,6 +628,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 ;; @@ -681,6 +713,15 @@ ERROR can be either an error object or a string." (if (timerp elpher-network-timer) (cancel-timer elpher-network-timer))) +(defun elpher-make-network-timer (thunk) + "Creates 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." + (let ((timer (run-at-time elpher-connection-timeout nil thunk))) + (setq-local elpher-network-timer timer) + timer)) + (defun elpher-get-host-response (address default-port query-string response-processor &optional use-tls force-ipv4) "Generic function for retrieving data from ADDRESS. @@ -717,19 +758,7 @@ the host operating system and the local network capabilities.)" :hostname host :keylist (elpher-get-current-keylist address))) - (proc (if socks (socks-open-network-stream "elpher-process" nil host service) - (make-network-process :name "elpher-process" - :host host - :family (and force-ipv4 'ipv4) - :service service - :buffer nil - :nowait t - :tls-parameters - (and use-tls - (cons 'gnutls-x509pki - (apply #'gnutls-boot-parameters - gnutls-params)))))) - (timer (run-at-time elpher-connection-timeout nil + (timer (elpher-make-network-timer (lambda () (elpher-process-cleanup) (cond @@ -751,7 +780,19 @@ the host operating system and the local network capabilities.)" response-processor nil force-ipv4)) (t - (elpher-network-error address "Connection time-out."))))))) + (elpher-network-error address "Connection time-out.")))))) + (proc (if socks (socks-open-network-stream "elpher-process" nil host service) + (make-network-process :name "elpher-process" + :host host + :family (and force-ipv4 'ipv4) + :service service + :buffer nil + :nowait t + :tls-parameters + (and use-tls + (cons 'gnutls-x509pki + (apply #'gnutls-boot-parameters + gnutls-params))))))) (setq elpher-network-timer timer) (set-process-coding-system proc 'binary 'binary) (set-process-query-on-exit-flag proc nil) @@ -808,6 +849,7 @@ the host operating system and the local network capabilities.)" (if use-tls (apply #'gnutls-negotiate :process proc gnutls-params)) (funcall (process-sentinel proc) proc "open\n"))) (error + (elpher-process-cleanup) (error "Error initiating connection to server"))))) @@ -1062,34 +1104,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 @@ -1664,26 +1678,35 @@ The result is rendered using RENDERER." "(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") + "The gopher home of the Elpher project is here:\n") (elpher-insert-index-record "The Elpher Project Page" (elpher-make-gopher-address ?1 "/projects/elpher/" "thelambdalab.xyz" 70)) - (insert "\n" - "** Refer to the ") (let ((help-string "RET,mouse-1: Open Elpher info manual (if available)")) - (insert-text-button "Elpher info manual" + (insert "\n" + "The following info documentation is available:\n" + " - ") + (insert-text-button "Elpher Manual" 'face 'link 'action (lambda (_) (interactive) (info "(elpher)")) 'follow-link t - 'help-echo help-string)) - (insert " for the full documentation. **\n") + 'help-echo help-string) + (insert "\n - ") + (insert-text-button "Changes introduced by the latest release" + 'face 'link + 'action (lambda (_) + (interactive) + (info "(elpher)News")) + 'follow-link t + 'help-echo help-string)) + (insert "\n") (insert (propertize - (concat " (This should be available if you have installed Elpher using\n" - " MELPA. Otherwise you will 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))) @@ -1779,9 +1802,19 @@ record for the current elpher page." ;;;###autoload (defun elpher-bookmark-jump (bookmark) - "Go to a particular BOOKMARK." - (let* ((url (cdr (assq 'location bookmark)))) - (elpher-go url))) + "Handler used to open a bookmark using elpher. +The argument BOOKMARK is a bookmark record passed to the function. +This handler is responsible for loading the bookmark in some buffer, +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)) + (address (elpher-address-from-url cleaned-url)) + (page (elpher-make-page cleaned-url address))) + (elpher-with-clean-buffer + (elpher-visit-page page)) + (set-buffer (get-buffer elpher-buffer-name)) + nil)) (defun elpher-bookmark-link () "Bookmark the link at point. @@ -2221,7 +2254,8 @@ 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 (lambda () elpher--gemini-page-headings))) + (setq-local imenu-create-index-function (lambda () elpher--gemini-page-headings)) + (setq-local xterm-color-preserve-properties t)) (when (fboundp 'evil-set-initial-state) (evil-set-initial-state 'elpher-mode 'motion))