diff options
Diffstat (limited to 'elisp/geiser-connection.el')
-rw-r--r-- | elisp/geiser-connection.el | 242 |
1 files changed, 122 insertions, 120 deletions
diff --git a/elisp/geiser-connection.el b/elisp/geiser-connection.el index dfdb21d..dc669aa 100644 --- a/elisp/geiser-connection.el +++ b/elisp/geiser-connection.el @@ -17,6 +17,7 @@ (require 'geiser-log) (require 'geiser-syntax) (require 'geiser-base) +(require 'geiser-impl) (require 'comint) (require 'advice) @@ -35,12 +36,13 @@ ;;; Request datatype: -(defun geiser-con--make-request (str cont &optional sender-buffer) +(defun geiser-con--make-request (con str cont &optional sender-buffer) (list :geiser-connection-request - (cons :id (random)) + (cons :id (geiser-con--connection-inc-count con)) (cons :string str) (cons :continuation cont) - (cons :buffer (or sender-buffer (current-buffer))))) + (cons :buffer (or sender-buffer (current-buffer))) + (cons :connection con))) (defsubst geiser-con--request-p (req) (and (listp req) (eq (car req) :geiser-connection-request))) @@ -57,6 +59,9 @@ (defsubst geiser-con--request-buffer (req) (cdr (assoc :buffer req))) +(defsubst geiser-con--request-connection (req) + (cdr (assoc :connection req))) + (defsubst geiser-con--request-deactivate (req) (setcdr (assoc :continuation req) nil)) @@ -70,9 +75,23 @@ (list :geiser-connection (cons :requests (list)) (cons :current nil) + (cons :count 0) (cons :completed (make-hash-table :weakness 'value)) (cons :buffer buffer) - (cons :timer nil))) + (cons :reply (geiser-con--make-reply-buffer buffer)))) + +(defvar geiser-con--eot-regexp nil) +(geiser-impl--register-local-variable + 'geiser-con--eot-regexp 'eot-regexp nil + "A regular expression used to detect end of transmissions. +By default, Geiser uses the prompt regexp.") + +(defun geiser-con--make-reply-buffer (buffer) + (let ((name (concat " geiser-con-reply: " (buffer-name buffer))) + (eot (with-current-buffer buffer geiser-con--eot-regexp))) + (with-current-buffer (get-buffer-create name) + (setq geiser-con--eot-regexp eot) + (current-buffer)))) (defsubst geiser-con--connection-p (c) (and (listp c) (eq (car c) :geiser-connection))) @@ -89,11 +108,18 @@ (defsubst geiser-con--connection-current-request (c) (cdr (assoc :current c))) +(defsubst geiser-con--connection-reply-buffer (c) + (cdr (assoc :reply c))) + +(defsubst geiser-con--connection-completed (c r) + (geiser-con--request-deactivate r) + (puthash (geiser-con--request-id r) r (cdr (assoc :completed c)))) + (defun geiser-con--connection-clean-current-request (c) (let* ((cell (assoc :current c)) (req (cdr cell))) (when req - (puthash (geiser-con--request-id req) req (cdr (assoc :completed c))) + (geiser-con--connection-completed c req) (setcdr cell nil)))) (defun geiser-con--connection-add-request (c r) @@ -104,22 +130,23 @@ (gethash id (cdr (assoc :completed c)))) (defun geiser-con--connection-pop-request (c) - (let ((reqs (assoc :requests c)) - (current (assoc :current c))) - (setcdr current (prog1 (cadr reqs) (setcdr reqs (cddr reqs)))) - (if (and (cdr current) - (geiser-con--request-deactivated-p (cdr current))) + (let* ((reqs (assoc :requests c)) + (current (assoc :current c)) + (old-current (cdr current)) + (new-current (cadr reqs)) + (new-reqs (cddr reqs))) + (when old-current (geiser-con--connection-completed c old-current)) + (setcdr reqs new-reqs) + (if (and new-current + (geiser-con--request-deactivated-p new-current)) (geiser-con--connection-pop-request c) - (cdr current)))) - -(defun geiser-con--connection-start-timer (c) - (let ((cell (assoc :timer c))) - (when (cdr cell) (cancel-timer (cdr cell))) - (setcdr cell (run-at-time t 0.5 'geiser-con--process-next c)))) + (setcdr current new-current)))) -(defun geiser-con--connection-cancel-timer (c) - (let ((cell (assoc :timer c))) - (when (cdr cell) (cancel-timer (cdr cell))))) +(defun geiser-con--connection-inc-count (c) + (let* ((cnt (assoc :count c)) + (new (1+ (cdr cnt)))) + (setcdr cnt new) + new)) ;;; Connection setup: @@ -132,60 +159,55 @@ (make-variable-buffer-local (defvar geiser-con--debugging-preamble-regexp nil)) -(defun geiser-con--is-debugging () - (and geiser-con--debugging-prompt-regexp - geiser-con--debugging-inhibits-eval - comint-last-prompt-overlay - (string-match-p geiser-con--debugging-prompt-regexp - (buffer-substring (overlay-start - comint-last-prompt-overlay) - (overlay-end - comint-last-prompt-overlay))))) - -(defsubst geiser-con--has-entered-debugger () - (and geiser-con--debugging-prompt-regexp - (re-search-backward geiser-con--debugging-prompt-regexp nil t) - (or (null geiser-con--debugging-preamble-regexp) - (save-excursion - (re-search-backward geiser-con--debugging-preamble-regexp nil t))))) - -(defun geiser-con--cleanup-connection (c) - (geiser-con--connection-cancel-timer c)) +(defun geiser-con--is-debugging (&optional con) + (with-current-buffer (or (and con (geiser-con--connection-buffer con)) + (current-buffer)) + (and geiser-con--debugging-prompt-regexp + geiser-con--debugging-inhibits-eval + comint-last-prompt-overlay + (string-match-p geiser-con--debugging-prompt-regexp + (buffer-substring (overlay-start + comint-last-prompt-overlay) + (overlay-end + comint-last-prompt-overlay)))))) + +(defsubst geiser-con--has-entered-debugger (con) + (with-current-buffer (geiser-con--connection-buffer con) + (and geiser-con--debugging-prompt-regexp + (re-search-backward geiser-con--debugging-prompt-regexp nil t) + (or (null geiser-con--debugging-preamble-regexp) + (save-excursion + (re-search-backward geiser-con--debugging-preamble-regexp + nil t)))))) + +(defun geiser-con--connection-teardown () + (when geiser-con--connection + (kill-buffer + (geiser-con--connection-reply-buffer geiser-con--connection)))) (defun geiser-con--setup-connection (buffer prompt-regexp &optional debug-prompt-regexp debug-preamble-regexp) (with-current-buffer buffer - (when geiser-con--connection - (geiser-con--cleanup-connection geiser-con--connection)) + (geiser-con--connection-teardown) (setq geiser-con--debugging-prompt-regexp debug-prompt-regexp) (setq geiser-con--debugging-preamble-regexp debug-preamble-regexp) (setq geiser-con--connection (geiser-con--make-connection buffer)) - (geiser-con--setup-comint prompt-regexp debug-prompt-regexp) - (geiser-con--connection-start-timer geiser-con--connection) - (message "Geiser REPL up and running!"))) - -(defun geiser-con--setup-comint (prompt-regexp debug-prompt-regexp) - (set (make-local-variable 'comint-redirect-insert-matching-regexp) - (not (null debug-prompt-regexp))) - (set (make-local-variable 'comint-redirect-finished-regexp) - (if debug-prompt-regexp - (format "\\(%s\\)\\|\\(%s\\)" prompt-regexp debug-prompt-regexp) - prompt-regexp)) - (setq comint-prompt-regexp comint-redirect-finished-regexp) - (add-hook 'comint-redirect-hook 'geiser-con--comint-redirect-hook nil t)) + (set (make-local-variable 'comint-redirect-insert-matching-regexp) t) + (setq comint-prompt-regexp + (if debug-prompt-regexp + (format "\\(%s\\)\\|\\(%s\\)" prompt-regexp debug-prompt-regexp) + prompt-regexp)) + (add-hook 'comint-redirect-hook 'geiser-con--comint-redirect-hook nil t))) ;;; Requests handling: -(defsubst geiser-con--comint-buffer () - (get-buffer-create " *geiser connection retort*")) - -(defun geiser-con--comint-buffer-form () - (with-current-buffer (geiser-con--comint-buffer) +(defun geiser-con--comint-buffer-form (con) + (with-current-buffer (geiser-con--connection-reply-buffer con) (goto-char (point-max)) - (if (geiser-con--has-entered-debugger) + (if (geiser-con--has-entered-debugger con) `((error (key . geiser-debugger)) (output . ,(buffer-substring (point-min) (point)))) (condition-case nil @@ -201,56 +223,52 @@ (defun geiser-con--process-next (con) (when (not (geiser-con--connection-current-request con)) (let* ((buffer (geiser-con--connection-buffer con)) - (debug-prompt (with-current-buffer buffer - geiser-con--debugging-prompt-regexp)) - (debug-preamble (with-current-buffer buffer - geiser-con--debugging-preamble-regexp)) (req (geiser-con--connection-pop-request con)) (str (and req (geiser-con--request-string req))) - (cbuf (geiser-con--comint-buffer))) - (if (not (buffer-live-p buffer)) - (geiser-con--connection-cancel-timer con) - (when (and buffer req str) - (with-current-buffer cbuf - (setq comint-redirect-echo-input nil) - (setq geiser-con--debugging-prompt-regexp debug-prompt) - (setq geiser-con--debugging-preamble-regexp debug-preamble) - (delete-region (point-min) (point-max))) - (set-buffer buffer) - (if (geiser-con--is-debugging) - (geiser-con--request-deactivate req) - (geiser-log--info "<%s>: %s" (geiser-con--request-id req) str) - (comint-redirect-send-command (format "%s" str) cbuf nil t))))))) + (rbuffer (geiser-con--connection-reply-buffer con))) + (when (and buffer (buffer-live-p buffer) req str) + (with-current-buffer rbuffer + (delete-region (point-min) (point-max))) + (set-buffer buffer) + (if (geiser-con--is-debugging) + (geiser-con--connection-completed con req) + (geiser-log--info "<%s>: %s" (geiser-con--request-id req) str) + (comint-redirect-send-command (format "%s" str) rbuffer nil t)))))) (defun geiser-con--process-completed-request (req) - (let ((cont (geiser-con--request-continuation req)) - (id (geiser-con--request-id req)) - (rstr (geiser-con--request-string req)) - (buffer (geiser-con--request-buffer req))) + (let* ((cont (geiser-con--request-continuation req)) + (id (geiser-con--request-id req)) + (rstr (geiser-con--request-string req)) + (buffer (geiser-con--request-buffer req)) + (con (geiser-con--request-connection req)) + (form (geiser-con--comint-buffer-form con))) (if (not cont) - (geiser-log--warn "<%s> Droping result for request %S (%s)" - id rstr req) + (geiser-log--warn "<%s> Droping result for request %S: %s" + id rstr form) (condition-case cerr (with-current-buffer (or buffer (current-buffer)) - (funcall cont (geiser-con--comint-buffer-form)) + (funcall cont form) + (geiser-con--request-deactivate req) (geiser-log--info "<%s>: processed" id)) (error (geiser-log--error - "<%s>: continuation failed %S \n\t%s" id rstr cerr)))))) + "<%s>: continuation failed %S \n\t%s" id rstr cerr)))) + (geiser-con--connection-clean-current-request con))) (defun geiser-con--comint-redirect-hook () (if (not geiser-con--connection) (geiser-log--error "No connection in buffer") (let ((req (geiser-con--connection-current-request geiser-con--connection))) - (if (not req) (geiser-log--error "No current request") - (geiser-con--process-completed-request req) - (geiser-con--connection-clean-current-request - geiser-con--connection))))) + (if (not req) + (geiser-log--error "No current request") + (geiser-con--process-completed-request req))))) (defadvice comint-redirect-setup (after geiser-con--advice (output-buffer comint-buffer finished-regexp &optional echo)) (with-current-buffer comint-buffer + (when geiser-con--eot-regexp + (setq comint-redirect-finished-regexp geiser-con--eot-regexp)) (when geiser-con--connection (setq mode-line-process nil)))) (ad-activate 'comint-redirect-setup) @@ -259,43 +277,27 @@ (defconst geiser-con--error-message "Geiser connection not active") -(defun geiser-con--send-string (buffer/proc str cont &optional sender-buffer) - (save-current-buffer - (let ((con (geiser-con--get-connection buffer/proc))) - (unless con (error geiser-con--error-message)) - (let ((req (geiser-con--make-request str cont sender-buffer))) - (geiser-con--connection-add-request con req) - (geiser-con--process-next con) - req)))) - (defvar geiser-connection-timeout 30000 "Time limit, in msecs, blocking on synchronous evaluation requests") -(defun geiser-con--send-string/wait (buffer/proc str cont - &optional timeout sbuf) +(defun geiser-con--send-string/wait (b/p str cont &optional timeout sbuf) (save-current-buffer - (let ((con (geiser-con--get-connection buffer/proc))) - (unless (geiser-con--connection-process con) - (error geiser-con--error-message)) - (with-current-buffer (geiser-con--connection-buffer con) - (when (geiser-con--is-debugging) - (error "Geiser REPL is in debug mode"))) - (let* ((req (geiser-con--send-string buffer/proc str cont sbuf)) - (id (and req (geiser-con--request-id req))) - (time (or timeout geiser-connection-timeout)) - (step 100) - (waitsecs (/ step 1000.0))) - (when id + (let* ((con (geiser-con--get-connection b/p)) + (proc (and con (geiser-con--connection-process con)))) + (unless proc (error geiser-con--error-message)) + (when (geiser-con--is-debugging con) (error "REPL is in debug mode")) + (let* ((req (geiser-con--make-request con str cont sbuf)) + (id (geiser-con--request-id req)) + (timeout (/ (or timeout geiser-connection-timeout) 1000.0)) + (waitsecs 0.1)) + (geiser-con--connection-add-request con req) + (with-timeout (timeout (geiser-con--request-deactivate req)) (condition-case nil - (while (and (> time 0) - (geiser-con--connection-process con) + (while (and (geiser-con--connection-process con) (not (geiser-con--connection-completed-p con id))) - (accept-process-output nil waitsecs) - (setq time (- time step))) - (error (setq time 0))) - (or (> time 0) - (geiser-con--request-deactivate req) - nil)))))) + (geiser-con--process-next con) + (accept-process-output proc waitsecs nil t)) + (error (geiser-con--request-deactivate req)))))))) (provide 'geiser-connection) |