[mcclim-devel] specialized command-parsers

Christophe Rhodes csr21 at cam.ac.uk
Fri Apr 21 16:25:38 UTC 2006


Christophe Rhodes <csr21 at cam.ac.uk> writes:

> My current attempt at writing a command parser (no attempt at partial
> parsing or unparsing yet) is
>
> (defun esa-command-parser (command-table stream)
>   (let ((command-name nil)
>         (command-args nil))
>     (with-delimiter-gestures (*command-name-delimiters* :override t)
>       ;; While reading the command name we want use the history of the
>       ;; (accept 'command ...) that's calling this function.
>       (setq command-name (accept `(command-name :command-table ,command-table)
>                                   :stream stream :prompt nil :history nil))
>       (let ((delimiter (read-gesture :stream stream :peek-p t)))
>       ;; Let argument parsing function see activation gestures.
>       (when (and delimiter (delimiter-gesture-p delimiter))
>         (read-gesture :stream stream))))
>     (with-delimiter-gestures (*command-argument-delimiters* :override t)
>       (let* ((info (gethash command-name climi::*command-parser-table*))
>              (required-args (climi::required-args info))
>              (keyword-args (climi::keyword-args info)))
>         (let (result)
>           ;; only required args for now.
>           (dolist (arg required-args (cons command-name (nreverse result)))
>             (destructuring-bind (name ptype &rest args) arg
>               (declare (ignore name))
>               ;; clear the stream somehow
>               #+nil
>               (setf (stream-cursor-position stream) (values 0 0))
>               #+nil
>               (replace-input stream "")
>               (push (apply #'accept 
>                            (eval ptype) :stream stream 
>                            ;; FIXME: probably wrong evaluation for ARGS
>                            args)
>                     result))))))))
>
> Quite apart from the apparent impossibility of writing a command
> parser portable across CLIM implementations, this doesn't work in
> several ways.  It doesn't handle keyword arguments, the evaluation of
> the arguments in the call to ACCEPT for arguments is wrong (see the
> spec for DEFINE-COMMAND for the evaluation rules...), and, most
> importantly, I find myself unable to clear the stream.  Setting the
> stream cursor position doesn't work, because stream is an input
> stream; I don't know why REPLACE-INPUT doesn't work, but it gives me
> an error.  ERASE-INPUT-BUFFER is unimplemented.

My current version, which I've built up by trial and error, almost
works (I've appended it below).  In fact it basically works except
when the user types SPC at a point where (I think) there is more than
one possibility, but only if the user has previously pressed
backspace; in those conditions, the "Extended Command: " prompt from
below is deleted.  That is, in my example where I have
com-new-find-file and com-newline-and-indent, the sequence
  M-x N e SPC
works as I want it to, while
  M-x N e DEL e SPC
causes the prompt to disappear.  I'm mystified by this.

(defun esa-command-parser (command-table stream)
  (let ((command-name nil)
        (command-args nil))
    (with-delimiter-gestures (*command-name-delimiters* :override t)
      ;; While reading the command name we want use the history of the
      ;; (accept 'command ...) that's calling this function.
      (setq command-name (accept `(command-name :command-table ,command-table)
                                  :stream stream :prompt "Extended Command: " 
                                 :prompt-mode :raw :history nil))
      (let ((delimiter (read-gesture :stream stream :peek-p t)))
      ;; Let argument parsing function see activation gestures.
      (when (and delimiter (delimiter-gesture-p delimiter))
        (read-gesture :stream stream))))
    (with-delimiter-gestures (*command-argument-delimiters* :override t)
      (let* ((info (gethash command-name climi::*command-parser-table*))
             (required-args (climi::required-args info))
             (keyword-args (climi::keyword-args info)))
        (let (result)
          ;; only required args for now.
          (dolist (arg required-args (cons command-name (nreverse result)))
            (destructuring-bind (name ptype &rest args) arg
              (declare (ignore name))
              ;; clear the stream somehow
              (replace-input stream "" :rescan nil)
              #+nil (reset-scan-pointer stream)
              #+nil (window-clear (encapsulating-stream-stream stream))
              #+nil (setf (stream-insertion-pointer stream) 0)
              #+nil (setf (stream-scan-pointer stream) 0)
              #+nil (replace-input stream "")
              #+nil (reset-scan-pointer stream)
              (push (apply #'accept 
                           (eval ptype) :stream stream 
                           ;; FIXME: probably wrong evaluation for ARGS
                           args)
                    result))))))))

Cheers,

Christophe



More information about the mcclim-devel mailing list