Switched to using insert-text-button.
[elpher.git] / elopher.el
1 ;;; elopher.el --- gopher client
2
3 ;;; Commentary:
4
5 ;; Simple gopher client in elisp.
6
7 ;;; Code:
8
9 ;; (defvar elopher-mode-map nil "Keymap for gopher client.")
10 ;; (define-key elopher-mode-map (kbd "p") 'elopher-quit)
11
12 ;; (define-derived-mode elopher-mode special-mode "elopher"
13 ;;   "Major mode for elopher, an elisp gopher client.")
14
15 ;; (global-set-key (kbd "C-c C-b") 'eval-buffer)
16
17 (defvar elopher-type-margin-width 5)
18
19 (defvar elopher-history '())
20
21 (defun elopher-type-margin (&optional type-name)
22   (if type-name
23       (insert (propertize
24                (format (concat "%" (number-to-string elopher-type-margin-width) "s")
25                        (concat "[" type-name "] "))
26                'face '(foreground-color . "yellow")))
27     (insert (make-string elopher-type-margin-width ?\s))))
28
29 (defun elopher-follow-index-link (button)
30   (apply #'elopher-get-index (button-get button 'link-address)))
31
32 (defun elopher-follow-text-link (button)
33   (apply #'elopher-get-text (button-get button 'link-address)))
34
35 (defun elopher-process-record (line)
36   (let* ((type (elt line 0))
37          (fields (split-string (substring line 1) "\t"))
38          (display-string (elt fields 0))
39          (selector (elt fields 1))
40          (hostname (elt fields 2))
41          (port (elt fields 3))
42          (address (list selector hostname port)))
43     (pcase type
44       (?i (elopher-type-margin)
45           (insert (propertize display-string
46                               'face '(foreground-color. "white"))))
47       (?0 (elopher-type-margin "T")
48           (insert-text-button display-string
49                               'face '(foreground-color . "gray")
50                               'link-address address
51                               'action #'elopher-follow-text-link
52                               'follow-link t))
53       (?1 (elopher-type-margin "/")
54           (insert-text-button display-string
55                               'face '(foreground-color . "cyan")
56                               'link-address address
57                               'action #'elopher-follow-index-link
58                               'follow-link t)))
59     (insert "\n")))
60
61 (defvar elopher-incomplete-record "")
62
63 (defun elopher-process-complete-records (string)
64   (let* ((til-now (string-join (list elopher-incomplete-record string)))
65          (lines (split-string til-now "\r\n")))
66     (dotimes (idx (length lines))
67       (if (< idx (- (length lines) 1))
68           (elopher-process-record (elt lines idx))
69         (setq elopher-incomplete-record (elt lines idx))))))
70
71 (defun elopher-index-filter (proc string)
72   (with-current-buffer (get-buffer "*elopher*")
73     (let ((marker (process-mark proc)))
74       (if (not (marker-position marker))
75           (set-marker marker 0 (current-buffer)))
76       (save-excursion
77         (goto-char marker)
78         (elopher-process-complete-records string)
79         (set-marker marker (point))))))
80     
81 (defun elopher-get-index (selector host port)
82   (switch-to-buffer "*elopher*")
83   (erase-buffer)
84   (setq elopher-incomplete-record "")
85   (make-network-process
86    :name "elopher-process"
87    :host host
88    :service (if port port 70)
89    :filter #'elopher-index-filter)
90   (process-send-string "elopher-process" (concat selector "\n")))
91
92 (defun elopher-text-filter (proc string)
93   (with-current-buffer (get-buffer "*elopher*")
94     (let ((marker (process-mark proc)))
95       (if (not (marker-position marker))
96           (set-marker marker 0 (current-buffer)))
97       (save-excursion
98         (goto-char marker)
99         (dolist (line (split-string string "\r"))
100           (insert line))
101         (set-marker marker (point))))))
102
103 (defun elopher-get-text (selector host port)
104   (switch-to-buffer "*elopher*")
105   (erase-buffer)
106   (setq elopher-incomplete-record "")
107   (make-network-process
108    :name "elopher-process"
109    :host host
110    :service port
111    :filter #'elopher-text-filter)
112   (process-send-string "elopher-process" (concat selector "\n")))
113
114 (defun elopher ()
115   "Start gopher client."
116   (interactive)
117   (elopher-get-index "" (read-from-minibuffer "Gopher host: ") 70))
118
119 ;; (elopher-get-index "" "cosmic.voyage" 70)
120 ;; (elopher-get-index "" "gopher.floodgap.com" 70)
121
122 ;;; elopher.el ends here