1 ;;; geiser-connection.el -- talking to a scheme process
3 ;; Copyright (C) 2009, 2010 Jose Antonio Ortega Ruiz
5 ;; This program is free software; you can redistribute it and/or
6 ;; modify it under the terms of the Modified BSD License. You should
7 ;; have received a copy of the license along with this program. If
8 ;; not, see <http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5>.
10 ;; Start date: Sat Feb 07, 2009 21:11
14 ;; Connection datatype and functions for managing request queues
15 ;; between emacs and inferior guile processes.
18 (require 'geiser-syntax
)
19 (require 'geiser-base
)
20 (require 'geiser-impl
)
25 ;;; Buffer connections:
27 (make-variable-buffer-local
28 (defvar geiser-con--connection nil
))
30 (defun geiser-con--get-connection (buffer/proc
)
31 (if (processp buffer
/proc
)
32 (geiser-con--get-connection (process-buffer buffer
/proc
))
33 (with-current-buffer buffer
/proc geiser-con--connection
)))
38 (defun geiser-con--make-request (con str cont
&optional sender-buffer
)
39 (list :geiser-connection-request
40 (cons :id
(geiser-con--connection-inc-count con
))
42 (cons :continuation cont
)
43 (cons :buffer
(or sender-buffer
(current-buffer)))
44 (cons :connection con
)))
46 (defsubst geiser-con--request-p
(req)
47 (and (listp req
) (eq (car req
) :geiser-connection-request
)))
49 (defsubst geiser-con--request-id
(req)
50 (cdr (assoc :id req
)))
52 (defsubst geiser-con--request-string
(req)
53 (cdr (assoc :string req
)))
55 (defsubst geiser-con--request-continuation
(req)
56 (cdr (assoc :continuation req
)))
58 (defsubst geiser-con--request-buffer
(req)
59 (cdr (assoc :buffer req
)))
61 (defsubst geiser-con--request-connection
(req)
62 (cdr (assoc :connection req
)))
64 (defsubst geiser-con--request-deactivate
(req)
65 (setcdr (assoc :continuation req
) nil
))
67 (defsubst geiser-con--request-deactivated-p
(req)
68 (null (cdr (assoc :continuation req
))))
71 ;;; Connection datatype:
73 (defun geiser-con--combined-prompt (prompt debug
)
74 (format "\\(%s%s\\)" prompt
(if debug
(format "\\|%s" debug
) "")))
76 (defun geiser-con--make-connection (proc prompt debug-prompt
)
77 (list :geiser-connection
78 (cons :tq
(tq-create proc
))
79 (cons :eot
(format "\0\n%s"
80 (geiser-con--combined-prompt prompt debug-prompt
)))
82 (cons :debug-prompt debug-prompt
)
84 (cons :completed
(make-hash-table :weakness
'value
))))
86 (defun geiser-con--connection-swap-proc (con proc
)
87 (let* ((this-proc (geiser-con--connection-process con
))
88 (this-filter (process-filter this-proc
))
89 (this-buffer (process-buffer this-proc
))
90 (filter (process-filter proc
))
91 (buffer (process-buffer proc
))
92 (tq (geiser-con--connection-tq con
)))
93 (set-process-filter this-proc filter
)
94 (set-process-buffer this-proc buffer
)
95 (set-process-filter proc this-filter
)
96 (set-process-buffer proc this-buffer
)
97 (setcdr tq
(cons proc
(tq-buffer tq
)))
100 (defsubst geiser-con--connection-p
(c)
101 (and (listp c
) (eq (car c
) :geiser-connection
)))
103 (defsubst geiser-con--connection-process
(c)
104 (tq-process (cdr (assoc :tq c
))))
106 (defsubst geiser-con--connection-tq
(c)
109 (defsubst geiser-con--connection-eot
(c)
110 (cdr (assoc :eot c
)))
112 (defsubst geiser-con--connection-prompt
(c)
113 (cdr (assoc :prompt c
)))
115 (defsubst geiser-con--connection-debug-prompt
(c)
116 (cdr (assoc :debug-prompt c
)))
118 (defsubst geiser-con--connection-completed
(c r
)
119 (geiser-con--request-deactivate r
)
120 (puthash (geiser-con--request-id r
) r
(cdr (assoc :completed c
))))
122 (defsubst geiser-con--connection-completed-p
(c id
)
123 (gethash id
(cdr (assoc :completed c
))))
125 (defun geiser-con--connection-inc-count (c)
126 (let* ((cnt (assoc :count c
))
127 (new (1+ (cdr cnt
))))
131 (defun geiser-con--has-entered-debugger (con answer
)
132 (let ((dp (geiser-con--connection-debug-prompt con
)))
133 (and (stringp dp
) (string-match dp answer
))))
135 (defun geiser-con--connection-close (con)
136 (let ((tq (geiser-con--connection-tq con
)))
137 (and tq
(tq-close tq
))))
139 (defvar geiser-con--startup-prompt nil
)
140 (defun geiser-con--startup-prompt (p s
)
141 (setq geiser-con--startup-prompt
142 (concat geiser-con--startup-prompt s
))
145 (defun geiser-con--open-connection (host port prompt debug-prompt
)
146 (setq geiser-con--startup-prompt
"")
147 (let* ((name (format "geiser-con@%s:%s" host port
))
148 (proc (open-network-stream name nil host port
)))
149 (set-process-filter proc
'geiser-con--startup-prompt
)
151 (error (format "Timeout connecting to %s:%s" host port
)))
152 (while (not (string-match prompt geiser-con--startup-prompt
))
153 (accept-process-output proc
0.05)))
154 (geiser-con--make-connection proc prompt debug-prompt
)))
157 ;;; Requests handling:
159 (defun geiser-con--req-form (req answer
)
160 (let ((con (geiser-con--request-connection req
)))
161 (if (geiser-con--has-entered-debugger con answer
)
162 `((error (key . geiser-debugger
))
165 (car (read-from-string answer
))
166 (error `((error (key . geiser-con-error
))
167 (output .
,(format "%s\n(%s)"
169 (error-message-string err
)))))))))
171 (defun geiser-con--process-completed-request (req answer
)
172 (let ((cont (geiser-con--request-continuation req
))
173 (id (geiser-con--request-id req
))
174 (rstr (geiser-con--request-string req
))
175 (form (geiser-con--req-form req answer
))
176 (buffer (or (geiser-con--request-buffer req
) (current-buffer)))
177 (con (geiser-con--request-connection req
)))
179 (geiser-log--warn "<%s> Droping result for request %S: %s"
182 (with-current-buffer buffer
184 (geiser-log--info "<%s>: processed" id
))
185 (error (geiser-log--error
186 "<%s>: continuation failed %S \n\t%s" id rstr cerr
))))
187 (geiser-con--connection-completed con req
)))
189 (defun geiser-con--connection-add-request (c r
)
190 (tq-enqueue (geiser-con--connection-tq c
)
191 (geiser-con--request-string r
)
192 (geiser-con--connection-eot c
)
194 'geiser-con--process-completed-request
198 ;;; Message sending interface:
200 (defun geiser-con--send-string (con str cont
&optional sbuf
)
201 (let ((req (geiser-con--make-request con str cont sbuf
)))
202 (geiser-con--connection-add-request con req
)
205 (defvar geiser-connection-timeout
30000
206 "Time limit, in msecs, blocking on synchronous evaluation requests")
208 (defun geiser-con--send-string/wait
(con str cont
&optional timeout sbuf
)
210 (let ((proc (and con
(geiser-con--connection-process con
))))
211 (unless proc
(error "Geiser connection not active"))
212 (let* ((req (geiser-con--send-string con str cont sbuf
))
213 (id (geiser-con--request-id req
))
214 (timeout (/ (or timeout geiser-connection-timeout
) 1000.0)))
215 (with-timeout (timeout (geiser-con--request-deactivate req
))
217 (while (and (geiser-con--connection-process con
)
218 (not (geiser-con--connection-completed-p con id
)))
219 (accept-process-output proc
(/ timeout
10)))
220 (error (geiser-con--request-deactivate req
))))))))
223 (provide 'geiser-connection
)