X-Git-Url: https://thelambdalab.xyz/gitweb/index.cgi?p=elpher.git;a=blobdiff_plain;f=elpher.el;h=e508c6195b8d70e3c1c0b74c0de2054b7a872c18;hp=8113c533bf002018a46b2ea1fb8cf53ebb275c88;hb=ca32cd8d0df5a6041ee4a2920309b8adc0b63d2e;hpb=46dac5a84b17c972b4479ccb0b288ae531c247a0 diff --git a/elpher.el b/elpher.el index 8113c53..e508c61 100644 --- a/elpher.el +++ b/elpher.el @@ -1,10 +1,10 @@ -;;; elpher.el --- A friendly gopher client -*- lexical-binding:t -*- +;;; elpher.el --- A friendly gopher and gemini client -*- lexical-binding:t -*- ;; Copyright (C) 2019 Tim Vaughan ;; Author: Tim Vaughan ;; Created: 11 April 2019 -;; Version: 2.7.4 +;; Version: 2.7.5 ;; Keywords: comm gopher ;; Homepage: http://thelambdalab.xyz/elpher ;; Package-Requires: ((emacs "26")) @@ -26,8 +26,8 @@ ;;; 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 and gemini +;; client for GNU Emacs. It supports: ;; - intuitive keyboard and mouse-driven browsing, ;; - out-of-the-box compatibility with evil-mode, @@ -36,7 +36,7 @@ ;; - pleasant and configurable colouring of Gopher directories, ;; - direct visualisation of image files, ;; - a simple bookmark management system, -;; - connections using TLS encryption, +;; - gopher connections using TLS encryption, ;; - the fledgling Gemini protocol, ;; - the greybeard Finger protocol. @@ -70,7 +70,7 @@ ;;; Global constants ;; -(defconst elpher-version "2.7.4" +(defconst elpher-version "2.7.5" "Current version of elpher.") (defconst elpher-margin-width 6 @@ -265,6 +265,7 @@ The basic attributes include: TYPE, SELECTOR, HOST and PORT. If the optional attribute TLS is non-nil, the address will be marked as requiring gopher-over-TLS." (cond + ((equal type ?i) nil) ((and (equal type ?h) (string-prefix-p "URL:" selector)) (elpher-address-from-url (elt (split-string selector "URL:") 1))) @@ -546,9 +547,12 @@ to ADDRESS." (error "Cannot retrieve gopher selector: port number > 65536")) (condition-case nil (let* ((kill-buffer-query-functions nil) + (gnutls-verify-error nil) ; We use the NSM for verification (port (elpher-address-port address)) (host (elpher-address-host address)) (selector-string-parts nil) + (bytes-received 0) + (hkbytes-received 0) (proc (open-network-stream "elpher-process" nil (if force-ipv4 (dns-query host) host) @@ -579,7 +583,21 @@ to ADDRESS." (set-process-coding-system proc 'binary) (set-process-filter proc (lambda (_proc string) - (cancel-timer timer) + (when timer + (cancel-timer timer) + (setq timer nil)) + (setq bytes-received (+ bytes-received (length string))) + (let ((new-hkbytes-received (/ bytes-received 102400))) + (when (> new-hkbytes-received hkbytes-received) + (setq hkbytes-received new-hkbytes-received) + (with-current-buffer "*elpher*" + (let ((inhibit-read-only t)) + (goto-char (point-min)) + (beginning-of-line 2) + (delete-region (point) (point-max)) + (insert "(" + (number-to-string (/ hkbytes-received 10.0)) + " MB read)"))))) (setq selector-string-parts (cons string selector-string-parts)))) (set-process-sentinel proc @@ -594,7 +612,9 @@ to ADDRESS." (concat (elpher-gopher-address-selector address) "\r\n")))) (t - (cancel-timer timer) + (when timer + (cancel-timer timer) + (setq timer nil)) (funcall renderer (apply #'concat (reverse selector-string-parts))) (elpher-restore-pos))) @@ -614,7 +634,7 @@ once they are retrieved from the gopher server." (insert content) (elpher-restore-pos)) (elpher-with-clean-buffer - (insert "LOADING... (use 'u' to cancel)")) + (insert "LOADING... (use 'u' to cancel)\n")) (condition-case the-error (elpher-get-selector address renderer) (error @@ -680,7 +700,7 @@ If ADDRESS is not supplied or nil the record is rendered as an 'follow-link t 'help-echo (elpher-page-button-help page))) (pcase type - ((or '(gopher ?i) 'nil) ;; Information + ('nil ;; Information (elpher-insert-margin) (let ((propertized-display-string (propertize display-string 'face 'elpher-info))) @@ -856,9 +876,12 @@ to ADDRESS." (error "Cannot establish gemini connection: port number > 65536")) (condition-case nil (let* ((kill-buffer-query-functions nil) + (gnutls-verify-error nil) ; We use the NSM for verification (port (elpher-address-port address)) (host (elpher-address-host address)) (response-string-parts nil) + (bytes-received 0) + (hkbytes-received 0) (proc (open-network-stream "elpher-process" nil (if force-ipv4 (dns-query host) host) @@ -879,6 +902,18 @@ to ADDRESS." (when timer (cancel-timer timer) (setq timer nil)) + (setq bytes-received (+ bytes-received (length string))) + (let ((new-hkbytes-received (/ bytes-received 102400))) + (when (> new-hkbytes-received hkbytes-received) + (setq hkbytes-received new-hkbytes-received) + (with-current-buffer "*elpher*" + (let ((inhibit-read-only t)) + (goto-char (point-min)) + (beginning-of-line 2) + (delete-region (point) (point-max)) + (insert "(" + (number-to-string (/ hkbytes-received 10.0)) + " MB read)"))))) (setq response-string-parts (cons string response-string-parts)))) (set-process-sentinel proc @@ -904,7 +939,7 @@ to ADDRESS." renderer) (elpher-restore-pos))) (error - (elpher-network-error address the-error)))))) + (elpher-network-error address the-error)))))) (error (error "Error initiating connection to server"))))) @@ -921,7 +956,7 @@ that the response was malformed." (meta (string-trim (substring header 2)))) (list code meta body)) (error "Malformed response: No response status found in header %s" header))) - (error "Malformed response: No CRLF-delimited header found")))) + (error "Malformed response: No CRLF-delimited header found in response %s" response)))) (defun elpher-process-gemini-response (response-string renderer) "Process the gemini response RESPONSE-STRING and pass the result to RENDERER." @@ -975,7 +1010,7 @@ that the response was malformed." (insert content) (elpher-restore-pos)) (elpher-with-clean-buffer - (insert "LOADING GEMINI... (use 'u' to cancel)")) + (insert "LOADING GEMINI... (use 'u' to cancel)\n")) (setq elpher-gemini-redirect-chain nil) (elpher-get-gemini-response address renderer)) (error @@ -1014,7 +1049,7 @@ that the response was malformed." ((pred (string-prefix-p "image/")) (elpher-render-image body)) (_other - (error "Unsupported MIME type %S" mime-type)))))) + (elpher-render-download body)))))) (defun elpher-gemini-get-link-url (link-line) "Extract the url portion of LINK-LINE, a gemini map file link line. @@ -1143,7 +1178,7 @@ by HEADER-LINE." (insert content) (elpher-restore-pos)) (elpher-with-clean-buffer - (insert "LOADING... (use 'u' to cancel)")) + (insert "LOADING... (use 'u' to cancel)\n")) (condition-case the-error (let* ((kill-buffer-query-functions nil) (user (let ((filename (elpher-address-filename address))) @@ -1173,7 +1208,9 @@ by HEADER-LINE." (set-process-coding-system proc 'binary) (set-process-filter proc (lambda (_proc string) - (cancel-timer timer) + (when timer + (cancel-timer timer) + (setq timer nil)) (setq selector-string-parts (cons string selector-string-parts)))) (set-process-sentinel proc @@ -1187,7 +1224,9 @@ by HEADER-LINE." proc (concat user "\r\n")))) (t - (cancel-timer timer) + (when timer + (cancel-timer timer) + (setq timer nil)) (funcall renderer (apply #'concat (reverse selector-string-parts))) (elpher-restore-pos))))))) @@ -1235,7 +1274,7 @@ by HEADER-LINE." (error "Command not supported for start page")) (elpher-with-clean-buffer (insert " --------------------------------------------\n" - " Elpher Gopher Client \n" + " Elpher Gopher and Gemini Client \n" " version " elpher-version "\n" " --------------------------------------------\n" "\n" @@ -1246,7 +1285,7 @@ by HEADER-LINE." " - 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" @@ -1259,13 +1298,17 @@ by HEADER-LINE." " - T: toggle TLS gopher mode\n" " - .: display the raw server response for the current page\n" "\n" - "Start your exploration of gopher space:\n") + "Start your exploration of gopher space and gemini:\n") (elpher-insert-index-record "Floodgap Systems Gopher Server" (elpher-make-gopher-address ?1 "" "gopher.floodgap.com" 70)) + (elpher-insert-index-record "Project Gemini home page" + (elpher-address-from-url "gemini://gemini.circumlunar.space/")) (insert "\n" - "Alternatively, select the following item and enter some search terms:\n") - (elpher-insert-index-record "Veronica-2 Gopher Search Engine" + "Alternatively, select a search engine and enter some search terms:\n") + (elpher-insert-index-record "Gopher Search Engine (Veronica-2)" (elpher-make-gopher-address ?7 "/v2/vs" "gopher.floodgap.com" 70)) + (elpher-insert-index-record "Gemini Search Engine (GUS)" + (elpher-address-from-url "gemini://gus.guru/search")) (insert "\n" "This page contains your bookmarked sites (also visit with B):\n") (elpher-insert-index-record "Your Bookmarks" 'bookmarks) @@ -1656,6 +1699,7 @@ When run interactively HOST-OR-URL is read from the minibuffer." (let ((map (make-sparse-keymap))) (define-key map (kbd "TAB") 'elpher-next-link) (define-key map (kbd "") 'elpher-prev-link) + (define-key map (kbd "C-M-i") 'elpher-prev-link) (define-key map (kbd "u") 'elpher-back) (define-key map [mouse-3] 'elpher-back) (define-key map (kbd "O") 'elpher-root-dir)