Update of /project/climacs/cvsroot/esa
In directory clnet:/tmp/cvs-serv31073
Modified Files:
esa.asd esa.lisp packages.lisp
Added Files:
esa-command-parser.lisp
Log Message:
New command parser.
Make it the default for frames running esa-top-level.
Use the prompt argument to esa-top-level to determing
com-extended-command's prompt.
export esa:esa-command-parser and esa:esa-partial-command-parser.
rewrite some other bits of the top-level loop to use the partial command
parser where appropriate.
--- /project/climacs/cvsroot/esa/esa.asd 2006/05/10 09:38:57 1.4
+++ /project/climacs/cvsroot/esa/esa.asd 2006/05/10 09:52:05 1.5
@@ -4,4 +4,5 @@
(:file "colors" :depends-on ("packages"))
(:file "esa" :depends-on ("colors" "packages"))
(:file "esa-buffer" :depends-on ("packages" "esa"))
- (:file "esa-io" :depends-on ("packages" "esa"))))
+ (:file "esa-io" :depends-on ("packages" "esa"))
+ (:file "esa-command-parser" :depends-on ("packages" "esa"))))
--- /project/climacs/cvsroot/esa/esa.lisp 2006/05/10 09:41:42 1.14
+++ /project/climacs/cvsroot/esa/esa.lisp 2006/05/10 09:52:05 1.15
@@ -440,6 +440,12 @@
(setf command (list command)))
(setf command (substitute-numeric-argument-marker command numarg))
(setf command (substitute-numeric-argument-p command numargp))
+ (when (member *unsupplied-argument-marker* command :test #'eq)
+ (setq command
+ (funcall
+ *partial-command-parser*
+ (frame-command-table frame)
+ (frame-standard-input frame) command 0)))
(execute-frame-command frame command)
(return)))
(t nil))))))
@@ -449,10 +455,10 @@
(let ((command (command-menu-item-value object)))
(unless (listp command)
(setq command (list command)))
- (when (and (typep (frame-standard-input frame) 'interactor-pane)
- (member *unsupplied-argument-marker* command :test #'eq))
+ (when (member *unsupplied-argument-marker* command :test #'eq)
(setq command
- (command-line-read-remaining-arguments-for-partial-command
+ (funcall
+ *partial-command-parser*
(frame-command-table frame) (frame-standard-input frame)
command 0)))
(execute-frame-command frame command)))))
@@ -467,6 +473,8 @@
;; FIXME: I'm not sure that we want to do this for commands sent
;; from other threads; we almost certainly don't want to do it twice
;; in such cases...
+ ;;
+ ;; FIXME: also, um, throwing away the arguments is likely to be bad.
(setf (previous-command (car (windows frame)))
(if (consp command)
(car command)
@@ -486,15 +494,26 @@
;;;
;;; Top level
+(defvar *extended-command-prompt*)
+
(defun esa-top-level (frame &key
- command-parser command-unparser
- partial-command-parser prompt)
- (declare (ignore command-parser command-unparser partial-command-parser prompt))
+ (command-parser 'esa-command-parser)
+ ;; FIXME: maybe customize this? Under what
+ ;; circumstances would it be used? Maybe try
+ ;; turning the clim listener into an ESA?
+ (command-unparser 'command-line-command-unparser)
+ (partial-command-parser 'esa-partial-command-parser)
+ (prompt "Extended Command: "))
+ (declare (ignore prompt))
(with-slots (windows) frame
(let ((*standard-output* (car windows))
(*standard-input* (frame-standard-input frame))
(*print-pretty* nil)
(*abort-gestures* `((:keyboard #\g ,(make-modifier-state :control))))
+ (*command-parser* command-parser)
+ (*command-unparser* command-unparser)
+ (*partial-command-parser* partial-command-parser)
+ (*extended-command-prompt* prompt)
(*pointer-documentation-output*
(frame-pointer-documentation-output frame)))
(unless (eq (frame-state frame) :enabled)
@@ -632,23 +651,25 @@
(set-key 'com-quit 'global-esa-table '((#\x :control) (#\c :control)))
(define-command (com-extended-command
+ ;; FIXME: I don't think it makes any sense for
+ ;; Extended Command to be named.
:name t
:command-table global-esa-table)
()
"Prompt for a command name and arguments, then run it."
(let ((item (handler-case
- (accept
- `(command :command-table ,(find-applicable-command-table *application-frame*))
- :prompt "Extended Command")
- ((or command-not-accessible command-not-present) ()
- (beep)
+ (accept
+ `(command :command-table ,(find-applicable-command-table *application-frame*))
+ ;; this gets erased immediately anyway
+ :prompt "" :prompt-mode :raw)
+ ((or command-not-accessible command-not-present) ()
+ (beep)
(display-message "No such command")
(return-from com-extended-command nil)))))
(execute-frame-command *application-frame* item)))
(set-key 'com-extended-command 'global-esa-table '((#\x :meta)))
-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Help
--- /project/climacs/cvsroot/esa/packages.lisp 2006/05/02 18:01:49 1.3
+++ /project/climacs/cvsroot/esa/packages.lisp 2006/05/10 09:52:05 1.4
@@ -13,7 +13,9 @@
#:describe-command-to-stream
#:gesture-name
#:set-key
- #:find-applicable-command-table))
+ #:find-applicable-command-table
+ #:esa-command-parser
+ #:esa-partial-command-parser))
(defpackage :esa-buffer
(:use :clim-lisp :clim :esa)
--- /project/climacs/cvsroot/esa/esa-command-parser.lisp 2006/05/10 09:52:05 NONE
+++ /project/climacs/cvsroot/esa/esa-command-parser.lisp 2006/05/10 09:52:05 1.1
;;; -*- Mode: Lisp; Package: ESA -*-
;;; (c) copyright 2006 by
;;; Christophe Rhodes (c.rhodes(a)gold.ac.uk)
;;; This library is free software; you can redistribute it and/or
;;; modify it under the terms of the GNU Library General Public
;;; License as published by the Free Software Foundation; either
;;; version 2 of the License, or (at your option) any later version.
;;;
;;; This library is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;;; Library General Public License for more details.
;;;
;;; You should have received a copy of the GNU Library General Public
;;; License along with this library; if not, write to the
;;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;;; Boston, MA 02111-1307 USA.
(in-package :esa)
(defun esa-parse-one-arg (stream name ptype accept-args
&optional (default *unsupplied-argument-marker*))
(declare (ignore name))
;; this conditional doesn't feel entirely happy. The issue is that
;; we could be called either recursively from an outer call to
;; (accept 'command), in which case we want our inner accept to
;; occur on the minibuffer stream not the input-editing-stream, or
;; from the toplevel when handed a partial command. Maybe the
;; toplevel should establish an input editing context for partial
;; commands anyway? Then ESA-PARSE-ONE-ARG would always be called
;; with an input-editing-stream.
(let ((stream (if (encapsulating-stream-p stream)
(encapsulating-stream-stream stream)
stream)))
(apply #'accept (eval ptype)
:stream stream
(append
(unless (eq default *unsupplied-argument-marker*)
;; adjust to taste.
`(:default ,default :insert-default nil :display-default t))
;; This is fucking nuts. FIXME: the clim spec says
;; ":GESTURE is not evaluated at all". Um, but how are
;; you meant to tell if a keyword argument is :GESTURE,
;; then? The following does not actually allow variable
;; keys: anyone who writes (DEFINE-COMMAND FOO ((BAR
;; 'PATHNAME *RANDOM-ARG* ""))) and expects it to work
;; deserves to lose.
;;
;; FIXME: this will do the wrong thing on malformed accept
;; arguments, such improper lists or those with an odd
;; number of keyword arguments. I doubt that
;; DEFINE-COMMAND is checking the syntax, so we probably
;; should.
(loop for (key val) on accept-args by #'cddr
unless (eq key :gesture)
collect key and collect (eval val))))))
(defun esa-command-parser (command-table stream)
(let ((command-name nil))
(flet ((maybe-clear-input ()
(let ((gesture (read-gesture :stream stream
:peek-p t :timeout 0)))
(when (and gesture (or (delimiter-gesture-p gesture)
(activation-gesture-p gesture)))
(read-gesture :stream stream)))))
(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.
;;
;; FIXME: does this :history nil actually achieve the above?
(setq command-name (accept `(command-name :command-table ,command-table)
:stream (encapsulating-stream-stream stream)
:prompt *extended-command-prompt*
:prompt-mode :raw :history nil))
(maybe-clear-input))
(with-delimiter-gestures (*command-argument-delimiters* :override t)
;; FIXME, except we can't: use of CLIM-INTERNALS.
(let* ((info (gethash command-name climi::*command-parser-table*))
(required-args (climi::required-args info))
(keyword-args (climi::keyword-args info)))
(declare (ignore keyword-args))
(let (result)
;; only required args for now.
(dolist (arg required-args (cons command-name (nreverse result)))
(destructuring-bind (name ptype &rest args) arg
(push (esa-parse-one-arg stream name ptype args) result)
(maybe-clear-input)))))))))
(defun esa-partial-command-parser (command-table stream command position)
(declare (ignore command-table position))
(let ((command-name (car command))
(command-args (cdr command)))
(flet ((maybe-clear-input ()
(let ((gesture (read-gesture :stream stream
:peek-p t :timeout 0)))
(when (and gesture (or (delimiter-gesture-p gesture)
(activation-gesture-p gesture)))
(read-gesture :stream stream)))))
(with-delimiter-gestures (*command-argument-delimiters* :override t)
;; FIXME, except we can't: use of CLIM-INTERNALS.
(let* ((info (gethash command-name climi::*command-parser-table*))
(required-args (climi::required-args info))
(keyword-args (climi::keyword-args info)))
;; keyword arguments not yet supported
(declare (ignore keyword-args))
(let (result)
;; only required args for now.
(do ((required-args required-args (cdr required-args))
(arg (car required-args) (car required-args))
(command-args command-args (cdr command-args))
(command-arg (car command-args) (car command-args)))
((null required-args) (cons command-name (nreverse result)))
(destructuring-bind (name ptype &rest args) arg
(push (esa-parse-one-arg stream name ptype args command-arg)
result)
(maybe-clear-input)))))))))