;; - caching of visited sites (both content and cursor position),
;; - pleasant and configurable colouring of Gopher directories,
;; - direct visualisation of image files,
+;; - (m)enu key support, similar to Emacs' info browser,
;; - clickable web and gopher links in plain text.
;; The caching mechanism works by maintaining a hierarchy of visited
;; page containing information on key bindings and suggested starting
;; points for your gopher exploration.
+;; Faces, caching options and start page can be configured via
+;; the Elpher customization group in Applications.
+
;;; Code:
(provide 'elpher)
"i\tfake\tfake\t1"
"i - tab/shift-tab: next/prev directory entry on current page\tfake\tfake\t1"
"i - RET/mouse-1: open directory entry under cursor\tfake\tfake\t1"
+ "i - m: select a directory entry by name (autocompletes)\tfake\tfake\t1"
"i - u: return to parent directory entry\tfake\tfake\t1"
"i - g: go to a particular page\tfake\tfake\t1"
"i - r: redraw current page (using cached contents if available)\tfake\tfake\t1"
"A gopher client."
:group 'applications)
+;; Face customizations
+
(defface elpher-index
'((((background dark)) :foreground "deep sky blue")
(((background light)) :foreground "blue"))
'((t :foreground "blue"))
"Face used for brackets around margin key.")
+;; Other customizations
+
(defcustom elpher-open-urls-with-eww nil
"If non-nil, open URL selectors using eww.
Otherwise, use the system browser via the BROWSE-URL function."
"If non-nil, cache images in memory in the same way as other content."
:type '(boolean))
+(defcustom elpher-start-address nil
+ "If nil, the default start directory is shown when Elpher is started.
+Otherwise, a list containing the selector, host and port of a directory to
+use as the start page."
+ :type '(list string string integer))
+
+
;;; Model
;;
(defun elpher-insert-index (string)
"Insert the index corresponding to STRING into the current buffer."
- (dolist (line (split-string string "\r\n"))
+ ;; Should be able to split directly on CRLF, but some non-conformant
+ ;; LF-only servers sadly exist, hence the following.
+ (dolist (line (split-string (replace-regexp-in-string "\r" "" string) "\n"))
(unless (= (length line) 0)
(elpher-insert-index-record line))))
'help-echo (format "mouse-1, RET: open %s on %s port %s"
selector host port)))
(pcase type
- (?i (elpher-insert-margin) ; Information
+ (?i (elpher-insert-margin) ;; Information
(insert (propertize display-string
'face 'elpher-info)))
- (?h (elpher-insert-margin "W") ; Web link
+ (?h (elpher-insert-margin "W") ;; Web link
(let ((url (elt (split-string selector "URL:") 1)))
(insert-text-button display-string
'face 'elpher-url
'action #'elpher-click-url
'follow-link t
'help-echo (format "mouse-1, RET: open url %s" url))))
- (?.) ; Occurs at end of index, can safely ignore.
+ (?.) ;; Occurs at end of index, can safely ignore.
(tp (elpher-insert-margin (concat (char-to-string tp) "?"))
(insert (propertize display-string
'face 'elpher-unknown-face)))))
(message "Can only download gopher links, not general URLs.")))
(message "No link selected."))))
+(defun elpher-build-link-map ()
+ "Build alist mapping link names to destination nodes in current buffer."
+ (let ((link-map nil)
+ (b (next-button (point-min) t)))
+ (while b
+ (add-to-list 'link-map (cons (button-label b) b))
+ (setq b (next-button (button-start b))))
+ link-map))
+
+(defun elpher-menu ()
+ "Select a directory entry by name. Similar to the info browser (m)enu command."
+ (interactive)
+ (let* ((link-map (elpher-build-link-map)))
+ (if link-map
+ (let ((key (let ((completion-ignore-case t))
+ (completing-read "Directory entry/link (tab to autocomplete): " link-map nil t))))
+ (if (and key (> (length key) 0))
+ (let ((b (cdr (assoc key link-map))))
+ (goto-char (button-start b))
+ (button-activate b)))))))
+
;;; Mode and keymap
;;
(define-key map (kbd "R") 'elpher-reload)
(define-key map (kbd "w") 'elpher-view-raw)
(define-key map (kbd "d") 'elpher-download)
+ (define-key map (kbd "m") 'elpher-menu)
(when (fboundp 'evil-define-key)
(evil-define-key 'normal map
(kbd "TAB") 'elpher-next-link
(kbd "r") 'elpher-redraw
(kbd "R") 'elpher-reload
(kbd "w") 'elpher-view-raw
- (kbd "d") 'elpher-download))
+ (kbd "d") 'elpher-download
+ (kbd "m") 'elpher-menu))
map)
"Keymap for gopher client.")
"Start elpher with default landing page."
(interactive)
(setq elpher-current-node nil)
- (let ((start-node (elpher-make-node nil nil #'elpher-get-index-node)))
+ (let ((start-node (elpher-make-node nil
+ elpher-start-address
+ #'elpher-get-index-node)))
(elpher-visit-node start-node))
"Started Elpher.") ; Otherwise (elpher) evaluates to start page string.