š¾ Archived View for tilde.pink āŗ ~jsv āŗ gemlog āŗ fun_with_elpher.gmi captured on 2022-03-01 at 15:39:44. Gemini links have been rewritten to link to archived content
ā”ļø Next capture (2023-01-29)
-=-=-=-=-=-=-
As a newcomer to the gopher/gemini world, Iām still exploring it, trying to find the corners I have never visited before, finding old articles and so onā¦ And Iām trying various clients as well. I really like Lagrange, and I use it on my android tablet, but on desktop I find myself appreciating Elpher more and more. One reason is that as a emacs user I like it when I can do something without leaving emacs. And the otherā¦ well, itās more fun. I always liked those interactive environments like lisp or forth systems, when I can tinker with things as I go. I havenāt had the opportunity to use them much in recent years, and my lisp-fu is a bit rusty, but I still enjoy it. Some idea comes to my mind and I can try it instantly. The resulting code might be not the most elegant that I ever written, and I do not test it against all the edge cases, the idea itself might be bad, nobody else in the world might need this functionalityā¦ but who cares but myself?
Some examples.
Not that long ago, there was a discussion about āUp Buttonā in gemini clients:
Up Buttons for exploring capsules
Elpher has āelpher-go-currentā command that allows to edit current url easily enough, but itās not quite the same thing.
Implementing the same thing is not hard, although gopher always wants special treatment:
(defun my-elpher-go-up () "Tries to guess the address of the parent page and goes there." (interactive) (let ((address (copy-seq (elpher-page-address elpher-current-page)))) (if (string-equal (url-type address) "gopher") (when (string-match "\\(/.\\)\\(.*\\)/.+" #1=(url-filename address)) (setf #1# (format "/1%s" (match-string 2 #1#)))) (when (string-match "\\(.*\\)/.+" #1=(url-filename address)) (setf #1# (match-string 1 #1#)))) (elpher-go (elpher-address-to-url address))))
Itās more than a bit hacky, and not very smart, resulting sometimes in addresses that not open but it works most of the time, and other āup buttonā implementations that Iāve seen are not much more reliable. Itās good enough for me so far.
Often enough, people who have a gemini capsule, have a gopher hole on the same host as well. So, as a variation of the same theme:
(defun my-elpher-switch-protocol () "Tries switching between gemini and gopher versions of the same site" (interactive) (let* ((address (elpher-page-address elpher-current-page)) (new-path (if (string-match "\\(/~.*?\\(?:/\\|$\\)\\)" #1=(url-filename address)) (match-string 1 #1#) "/"))) (elpher-go (format (if (string-equal (url-type address) "gemini") "gopher://%s/1%s" "gemini://%s%s") (url-host address) new-path))))
This works surprisingly well, and it led me to interesting places much more often than I expected.
Elpher supports client certificates, both ephemeral and permanent, but it doesnāt store long-term association between capsules and certs. It stores the current cert in a buffer-local variable and it lasts as long as the buffer exists, if you close it, youāll have to select the certificate once again.
Iām lazy, and the simplest solution that comes to my mind is to write an advice function that selects the certificate for me on the sites that I visit often:
(defvar my-elpher-certificate-alist '(("astrobotany" . "my-bonanist-cert") ("/station\\|spellbinding" . "jsv"))) (defun my-elpher-current-url () "Returns an url for the current elpher page" (elpher-address-to-url (elpher-page-address elpher-current-page))) (defun my-elpher-consult-certificate-alist () (when-let (matching-cert (alist-get (my-elpher-current-url) my-elpher-certificate-alist nil nil #'string-match-p)) (elpher-get-existing-certificate matching-cert))) (add-function :before-until (symbol-function 'elpher-choose-client-certificate) #'my-elpher-consult-certificate-alist)
āelpher-choose-client-certificateā is a complex function that can do a lot of things but in the end it sets the certificate, so when I know what cert I want, I can simply set in myself and do not call the rest.
So, now I can go spellbinding anytime and it will recognize me. But itās not very playable in elpher, as elpher caches everything and spellbindingās cgi links are not meant to be cached. Well, I can make an exception for them:
(defvar my-elpher-cache-exceptions '("game/cgi")) (defun my-maybe-cache-content (cache-fn address content) (funcall cache-fn address (if (find (elpher-address-to-url address) my-elpher-cache-exceptions :test (lambda (s r) (string-match-p r s))) nil content))) (add-function :around (symbol-function 'elpher-cache-content) #'my-maybe-cache-content)
And now I can play spellbinding in emacs without problems.
See? Itās fun! For some definition of fun, at least š