-;;; elpher.el --- elisp gopher client
+;;; elpher.el --- Full-featured gopher client.
+
+;; Copyright (C) 2019 Tim Vaughan
+
+;; Author: Tim Vaughan <tgvaughan@gmail.com>
+;; Created: 11 April 2019
+;; Version: 1.0.0
+;; Keywords: comm gopher
+;; Homepage: https://github.com/tgvaughan/elpher
+;; Package-Requires: ((emacs "25"))
+
+;; This file is not part of GNU Emacs.
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this file. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
-;; An elisp gopher client.
+;; Elpher aims to provide a full-featured gopher client for GNU Emacs.
+;; It supports:
+
+;; - intuitive keyboard and mouse-driven browsing,
+;; - caching of visited sites (both content and cursor position),
+;; - pleasant and configurable colouring of Gopher directories,
+;; - direct visualisation of image files,
+;; - clickable web and gopher links in plain text.
+
+;; The caching mechanism works by maintaining a hierarchy of visited
+;; pages rather than a linear history, meaning that it is quick and
+;; easy to navigate this history.
+
+;; To launch Elpher, simply use 'M-x elpher'. This will open a start
+;; 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)
+
;;; Global constants
;;
'identity
(list "i\tfake\tfake\t1"
"i--------------------------------------------\tfake\tfake\t1"
- "i Elpher Gopher Client \tfake\tfake\t1"
+ "i Elpher Gopher Client \tfake\tfake\t1"
(format "i version %s\tfake\tfake\t1" elpher-version)
"i--------------------------------------------\tfake\tfake\t1"
"i\tfake\tfake\t1"
"\r\n")
"Source for elpher start page.")
+(defconst elpher-type-map
+ '((?0 elpher-get-text-node "T" elpher-text)
+ (?1 elpher-get-index-node "/" elpher-index)
+ (?g elpher-get-image-node "im" elpher-image)
+ (?p elpher-get-image-node "im" elpher-image)
+ (?I elpher-get-image-node "im" elpher-image)
+ (?4 elpher-get-node-download "B" elpher-binary)
+ (?5 elpher-get-node-download "B" elpher-binary)
+ (?9 elpher-get-node-download "B" elpher-binary)
+ (?7 elpher-get-search-node "?" elpher-search))
+ "Association list from types to getters, margin codes and index faces.")
+
;;; Customization group
;;
Otherwise, use the system browser via the BROWSE-URL function."
:type '(boolean))
+(defcustom elpher-cache-images nil
+ "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
;;
(insert " "))
(insert (make-string elpher-margin-width ?\s))))
-(defvar elpher-type-map
- '((?0 elpher-get-text-node "T" elpher-text)
- (?1 elpher-get-index-node "/" elpher-index)
- (?g elpher-get-image-node "im" elpher-image)
- (?p elpher-get-image-node "im" elpher-image)
- (?I elpher-get-image-node "im" elpher-image)
- (?4 elpher-get-node-download "B" elpher-binary)
- (?5 elpher-get-node-download "B" elpher-binary)
- (?9 elpher-get-node-download "B" elpher-binary)
- (?7 elpher-get-search-node "?" elpher-search))
- "Association list from types to getters, margin codes and index faces.")
-
(defun elpher-insert-index-record (line)
"Insert the index record corresponding to LINE into the current buffer."
(let* ((type (elt line 0))
(defun elpher-get-selector (address after)
"Retrieve selector specified by ADDRESS, then execute AFTER.
-The result is stored as a string in the variable elpher-selector-string."
+The result is stored as a string in the variable ‘elpher-selector-string’."
(setq elpher-selector-string "")
(make-network-process
:name "elpher-process"
(insert-image content))
(setq cursor-type nil)
(elpher-restore-pos))
- (progn
- (elpher-with-clean-buffer
- (insert "LOADING IMAGE..."))
- (elpher-get-selector address
- (lambda (proc event)
- (unless (string-prefix-p "deleted" event)
- (let ((image (create-image
- (encode-coding-string elpher-selector-string
- 'no-conversion)
- nil t)))
- (elpher-with-clean-buffer
- (insert-image image))
- (setq cursor-type nil)
- (elpher-restore-pos)
- (elpher-set-node-content elpher-current-node
- image)))))))))
+ (if (display-images-p)
+ (progn
+ (elpher-with-clean-buffer
+ (insert "LOADING IMAGE..."))
+ (elpher-get-selector address
+ (lambda (proc event)
+ (unless (string-prefix-p "deleted" event)
+ (let ((image (create-image
+ (encode-coding-string elpher-selector-string
+ 'no-conversion)
+ nil t)))
+ (elpher-with-clean-buffer
+ (insert-image image))
+ (setq cursor-type nil)
+ (elpher-restore-pos)
+ (if elpher-cache-images
+ (elpher-set-node-content elpher-current-node
+ image)))))))
+ (elpher-get-node-download)))))
;; Search retrieval
(let ((node (button-get button 'elpher-node)))
(if node
(elpher-visit-node (button-get button 'elpher-node)
- #'elpher-get-node-download)
+ #'elpher-get-node-download)
(message "Can only download gopher links, not general URLs.")))
(message "No link selected."))))
"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.