--- orig/lisp/ChangeLog
+++ mod/lisp/ChangeLog
@@ -1,3 +1,15 @@
+2006-04-11 Michael Olson
+
+ * emacs-lisp/tq.el (tq-queue-head-question): New accessor
+ function.
+ (tq-queue-head-regexp, tq-queue-head-closure, tq-queue-head-fn):
+ Update for modified queue structure.
+ (tq-queue-add): Accept `question' argument.
+ (tq-queue-pop): If a question is pending, send it.
+ (tq-enqueue): Accept new optional argument `delay-question'. If
+ this is non-nil, and at least one other question is pending a
+ response, queue the question rather than sending it immediately.
+
2006-04-10 Bill Wohler
* custom.el (defcustom, custom-handle-keyword): Add
--- orig/lisp/emacs-lisp/tq.el
+++ mod/lisp/emacs-lisp/tq.el
@@ -27,18 +27,51 @@
;;; Commentary:
-;; manages receiving a stream asynchronously,
-;; parsing it into transactions, and then calling
-;; handler functions
+;; This file manages receiving a stream either asynchronously or
+;; (optionally) synchronously, parsing it into transactions, and then
+;; calling the associated handler function upon the completion of each
+;; transaction.
;; Our basic structure is the queue/process/buffer triple. Each entry
-;; of the queue is a regexp/closure/function triple. We buffer
-;; bytes from the process until we see the regexp at the head of the
-;; queue. Then we call the function with the closure and the
-;; collected bytes.
+;; of the queue part is a list of question, regexp, closure, and
+;; function that is consed to the last element.
+
+;; A transaction queue may be created by calling `tq-create'.
+
+;; A request may be added to the queue by calling `tq-enqueue'. If
+;; the `delay-question' argument is non-nil, we will wait to send the
+;; question to the process until it has finished sending other input.
+;; Otherwise, once a request is enqueued, we send the given question
+;; immediately to the process.
+
+;; We then buffer bytes from the process until we see the regexp that
+;; was provided in the call to `tq-enqueue'. Then we call the
+;; provided function with the closure and the collected bytes. If we
+;; have indicated that the question from the next transaction was not
+;; sent immediately, send it at this point, awaiting the response.
;;; Code:
+;;; Accessors
+
+;; This part looks like (queue . (process . buffer))
+(defun tq-queue (tq) (car tq))
+(defun tq-process (tq) (car (cdr tq)))
+(defun tq-buffer (tq) (cdr (cdr tq)))
+
+;; The structure of `queue' is as follows
+;; ((question regexp closure . fn)
+;; )
+(defun tq-queue-head-question (tq) (car (car (tq-queue tq))))
+(defun tq-queue-head-regexp (tq) (car (cdr (car (tq-queue tq)))))
+(defun tq-queue-head-closure (tq) (car (cdr (cdr (car (tq-queue tq))))))
+(defun tq-queue-head-fn (tq) (cdr (cdr (cdr (car (tq-queue tq))))))
+
+;; Determine whether queue is empty
+(defun tq-queue-empty (tq) (not (tq-queue tq)))
+
+;;; Core functionality
+
;;;###autoload
(defun tq-create (process)
"Create and return a transaction queue communicating with PROCESS.
@@ -54,33 +87,34 @@
(tq-filter ',tq string)))
tq))
-;;; accessors
-(defun tq-queue (tq) (car tq))
-(defun tq-process (tq) (car (cdr tq)))
-(defun tq-buffer (tq) (cdr (cdr tq)))
-
-(defun tq-queue-add (tq re closure fn)
+(defun tq-queue-add (tq question re closure fn)
(setcar tq (nconc (tq-queue tq)
- (cons (cons re (cons closure fn)) nil)))
+ (cons (cons question (cons re (cons closure fn))) nil)))
'ok)
-(defun tq-queue-head-regexp (tq) (car (car (tq-queue tq))))
-(defun tq-queue-head-fn (tq) (cdr (cdr (car (tq-queue tq)))))
-(defun tq-queue-head-closure (tq) (car (cdr (car (tq-queue tq)))))
-(defun tq-queue-empty (tq) (not (tq-queue tq)))
-(defun tq-queue-pop (tq) (setcar tq (cdr (car tq))) (null (car tq)))
+(defun tq-queue-pop (tq)
+ (setcar tq (cdr (car tq)))
+ (let ((question (tq-queue-head-question tq)))
+ (when question
+ (process-send-string (tq-process tq) question)))
+ (null (car tq)))
-
-;;; must add to queue before sending!
-(defun tq-enqueue (tq question regexp closure fn)
+(defun tq-enqueue (tq question regexp closure fn &optional delay-question)
"Add a transaction to transaction queue TQ.
This sends the string QUESTION to the process that TQ communicates with.
When the corresponding answer comes back, we call FN
with two arguments: CLOSURE, and the answer to the question.
REGEXP is a regular expression to match the entire answer;
-that's how we tell where the answer ends."
- (tq-queue-add tq regexp closure fn)
- (process-send-string (tq-process tq) question))
+that's how we tell where the answer ends.
+
+If DELAY-QUESTION is non-nil, delay sending this question until
+the process has finished replying to any previous questions.
+This produces more reliable results with some processes."
+ (let ((sendp (or (not delay-question)
+ (not (tq-queue-head-question tq)))))
+ (tq-queue-add tq (unless sendp question) regexp closure fn)
+ (when sendp
+ (process-send-string (tq-process tq) question))))
(defun tq-close (tq)
"Shut down transaction queue TQ, terminating the process."