emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Interactive hat. (Patch)


From: Alan Mackenzie
Subject: Re: Interactive hat. (Patch)
Date: Mon, 13 Apr 2009 19:32:55 +0000
User-agent: Mutt/1.5.9i

Hi, Stefan!

On Thu, Mar 26, 2009 at 10:50:11PM -0400, Stefan Monnier wrote:
> > How about I take your suggestion as meaning that page "Interactive Codes"
> > should be enhanced to give the lisp equivalent for each code letter, and
> > it is made clear that the string version is a convenient abbreviation
> > which works nearly all the time, and the Lisp code is the fully general
> > version?

> That's the idea, yes.  Additionally, the equivalent Lisp code should be
> simple (a single funcall), which isn't always possible right now, IIRC.

OK, here's the patch.  In the end, I put all these lisp forms into a new
page "Non-string Interactive" because it seemed better balanced.

I think that the order of "*" and "@" in (interactive "@*") matters.
Well, it would matter if there were any commands which use them both;
there aren't in Emacs.

It's a fairly hefty patch, so any review/criticism would be welcome.



2009-04-13  Alan Mackenzie  <address@hidden>

        * elisp.texi (Top): Add menu entry for "Non-string Interactive".

        * commands.texi (Using Interactive): Amend description of string
        form of interactive form.  Rectify false statement that the order
        of "special" characters is immaterial.  Insert a `*' into the
        example.  Give a rationale for existence of string form, and imply
        a non-string form is more general.  Remove redundant definitions
        of `*', `@' and `^'.
        (Interactive Codes): Insert an introduction.  Expand the
        descriptions of `@' and `^', including details formerly in "Using
        Interactive".
        (Non-string Interactive): New page giving non-string equivalents
        for all code characters.
        (Interactive Examples): Add a space after the prompts' colons.




Index: elisp.texi
===================================================================
RCS file: /cvsroot/emacs/emacs/doc/lispref/elisp.texi,v
retrieving revision 1.34
diff -c -r1.34 elisp.texi
*** elisp.texi  9 Apr 2009 01:17:10 -0000       1.34
--- elisp.texi  13 Apr 2009 19:31:09 -0000
***************
*** 662,667 ****
--- 662,668 ----
  * Using Interactive::       General rules for @code{interactive}.
  * Interactive Codes::       The standard letter-codes for reading arguments
                                in various ways.
+ * Non-string Interactive::  Non-string equivalents of the letter-codes.
  * Interactive Examples::    Examples of how to read interactive arguments.
  
  Input Events




Index: commands.texi
===================================================================
RCS file: /cvsroot/emacs/emacs/doc/lispref/commands.texi,v
retrieving revision 1.18
diff -c -r1.18 commands.texi
*** commands.texi       4 Apr 2009 22:34:23 -0000       1.18
--- commands.texi       13 Apr 2009 19:07:23 -0000
***************
*** 113,142 ****
  the reading of arguments for an interactive call.
  
  @menu
! * Using Interactive::     General rules for @code{interactive}.
! * Interactive Codes::     The standard letter-codes for reading arguments
!                              in various ways.
! * Interactive Examples::  Examples of how to read interactive arguments.
  @end menu
  
  @node Using Interactive
  @subsection Using @code{interactive}
  @cindex arguments, interactive entry
  
!   This section describes how to write the @code{interactive} form that
! makes a Lisp function an interactively-callable command, and how to
! examine a command's @code{interactive} form.
  
  @defspec interactive arg-descriptor
  This special form declares that a function is a command, and that it
  may therefore be called interactively (via @kbd{M-x} or by entering a
  key sequence bound to it).  The argument @var{arg-descriptor} declares
  how to compute the arguments to the command when the command is called
! interactively.
  
! A command may be called from Lisp programs like any other function, but
! then the caller supplies the arguments and @var{arg-descriptor} has no
! effect.
  
  @cindex @code{interactive-form}, function property
  The @code{interactive} form must be located at top-level in the
--- 113,144 ----
  the reading of arguments for an interactive call.
  
  @menu
! * Using Interactive::           General rules for @code{interactive}.
! * Interactive Codes::           The standard letter-codes for reading 
arguments
!                                 in various ways.
! * Non-string Interactive::      Non-string equivalents of the letter-codes.
! * Interactive Examples::        Examples of how to read interactive arguments.
  @end menu
  
  @node Using Interactive
  @subsection Using @code{interactive}
  @cindex arguments, interactive entry
  
!   This section describes how to write and examine the @dfn{interactive
! form}.  This form makes a Lisp function an interactively-callable
! command, and tells the interpreter how to call it.
  
  @defspec interactive arg-descriptor
  This special form declares that a function is a command, and that it
  may therefore be called interactively (via @kbd{M-x} or by entering a
  key sequence bound to it).  The argument @var{arg-descriptor} declares
  how to compute the arguments to the command when the command is called
! interactively, and sometimes directs the interpreter to perform
! auxiliary actions such as checking the buffer is writable.
  
! A command may be called from Lisp programs like any other function,
! but then the caller supplies the arguments and @var{arg-descriptor} is
! ignored.
  
  @cindex @code{interactive-form}, function property
  The @code{interactive} form must be located at top-level in the
***************
*** 166,187 ****
  or more arguments.
  
  @item
! It may be a string; its contents are a sequence of elements separated
! by newlines, one for each address@hidden elements actually
! supply two parameters.}.  Each element consists of a code character
! (@pxref{ Interactive Codes}) optionally followed by a prompt (which
! some code characters use and some ignore).  Here is an example:
  
  @smallexample
! (interactive "P\nbFrobnicate buffer: ")
  @end smallexample
  
  @noindent
! The code letter @samp{P} sets the command's first argument to the raw
! command prefix (@pxref{Prefix Command Arguments}).  @samp{bFrobnicate
! buffer: } prompts the user with @samp{Frobnicate buffer: } to enter
! the name of an existing buffer, which becomes the second and final
! argument.
  
  @c Emacs 19 feature
  The prompt string can use @samp{%} to include previous argument values
--- 168,213 ----
  or more arguments.
  
  @item
! It may be a string; the string's contents are:
! 
! @itemize @minus
! @item
! Zero or more of the ``special'' code characters @samp{*}, @samp{@@},
! @samp{^}, which direct Emacs to perform auxiliary functions
! (@pxref{Interactive Codes}) before getting the command's arguments.
! They are processed in the order they appear.  They are directly
! followed by
! @item
! a sequence of elements separated by newlines, one for each
! address@hidden elements actually supply two arguments.}.
! Each element consists of a code character (@pxref{ Interactive Codes})
! optionally followed by a prompt (which some code characters use and
! some ignore).  The prompt typically ends with @samp{: }.
! @end itemize
! 
! Here is an example:
  
  @smallexample
! (interactive "*P\nbFrobnicate buffer: ")
  @end smallexample
  
  @noindent
! The @samp{*} checks that the buffer is writable, signaling an error if
! it's read-only.  The code letter @samp{P} sets the command's first
! argument to the raw command prefix (@pxref{Prefix Command Arguments}).
! @samp{bFrobnicate buffer: } prompts the user with @samp{Frobnicate
! buffer: } to enter the name of an existing buffer, which becomes the
! second and final argument.
! 
! There are more examples in @xref{Interactive Examples}.
! 
! The string form of the argument is used more often than a general lisp
! expression, since it's more convenient.  However, sometimes you'll
! have to write a non-string lisp form (see below) since the string form
! can't always do what you need.  For your convenience, a non-string
! equivalent of each code character is given in @ref{Non-string
! Interactive}.
! 
  
  @c Emacs 19 feature
  The prompt string can use @samp{%} to include previous argument values
***************
*** 196,229 ****
  @end group
  @end smallexample
  
- @cindex @samp{*} in @code{interactive}
- @cindex read-only buffers in interactive
- If @samp{*} appears at the beginning of the string, then an error is
- signaled if the buffer is read-only.
- 
- @cindex @samp{@@} in @code{interactive}
- @c Emacs 19 feature
- If @samp{@@} appears at the beginning of the string, and if the key
- sequence used to invoke the command includes any mouse events, then
- the window associated with the first of those events is selected
- before the command is run.
- 
- @cindex @samp{^} in @code{interactive}
- @cindex shift-selection, and @code{interactive} spec
- If @samp{^} appears at the beginning of the string, and if the command
- was invoked through @dfn{shift-translation}, set the mark and activate
- the region temporarily, or extend an already active region, before the
- command is run.  If the command was invoked without shift-translation,
- and the region is temporarily active, deactivate the region before the
- command is run.  Shift-translation is controlled on the user level by
- @code{shift-select-mode}; see @ref{Shift Selection,,, emacs, The GNU
- Emacs Manual}.
- 
- You can use @samp{*}, @samp{@@}, and @code{^} together; the order does
- not matter.  Actual reading of arguments is controlled by the rest of
- the prompt string (starting with the first character that is not
- @samp{*}, @samp{@@}, or @samp{^}).
- 
  @item
  It may be a Lisp expression that is not a string; then it should be a
  form that is evaluated to get a list of arguments to pass to the
--- 222,227 ----
***************
*** 290,297 ****
  @cindex codes, interactive, description of
  @cindex characters for interactive codes
  
!   The code character descriptions below contain a number of key words,
! defined here as follows:
  
  @table @b
  @item Completion
--- 288,299 ----
  @cindex codes, interactive, description of
  @cindex characters for interactive codes
  
!   This page describes the @dfn{code characters}, the letters and
! punctuation marks contained in the string form of the argument to
! @code{interactive} (@pxref{Using Interactive}).
! 
!   The descriptions below contain a number of key words, defined here
! as follows:
  
  @table @b
  @item Completion
***************
*** 329,350 ****
  @end table
  
  @cindex reading interactive arguments
!   Here are the code character descriptions for use with @code{interactive}:
  
  @table @samp
  @item *
  Signal an error if the current buffer is read-only.  Special.
  
  @item @@
! Select the window mentioned in the first mouse event in the key
  sequence that invoked this command.  Special.
  
  @item ^
! If the command was invoked through shift-translation, set the mark and
! activate the region temporarily, or extend an already active region,
! before the command is run.  If the command was invoked without
! shift-translation, and the region is temporarily active, deactivate
! the region before the command is run.  Special.
  
  @item a
  A function name (i.e., a symbol satisfying @code{fboundp}).  Existing,
--- 331,368 ----
  @end table
  
  @cindex reading interactive arguments
!   Here are the code character descriptions for use with
! @code{interactive}.  Non-string equivalents of these codes can be
! found in @ref{Non-string Interactive}.
  
  @table @samp
+ @cindex @samp{*} in @code{interactive}
+ @cindex read-only buffers in interactive
  @item *
  Signal an error if the current buffer is read-only.  Special.
  
+ @cindex @samp{@@} in @code{interactive}
  @item @@
! If the key sequence that invokes the command contains a mouse event,
! select the window mentioned in the first mouse event in the key
  sequence that invoked this command.  Special.
  
+ @cindex @samp{^} in @code{interactive}
+ @cindex shift-selection, and @code{interactive} spec
  @item ^
! This is intended for movement commands.  If the command was invoked
! through shift-translation, set the mark and activate the region
! temporarily, or extend an already active region, before the command is
! run.  If the command was invoked without shift-translation, and the
! region is temporarily active, deactivate the region before the command
! is run.  Shift-translation is controlled on the user level by
! @code{shift-select-mode}; @xref{Shift Selection,,, emacs, The GNU
! Emacs Manual}. @footnote{Note that the code character @samp{^} was
! introduced in Emacs 23 and will cause an error if used in earlier
! Emacs versions.  If you want to use @samp{^} yet your command needs to
! run in an earlier version of Emacs, you should write the interactive
! spec as a non-string form instead.  (@pxref{Non-string Interactive})}
! Special.
  
  @item a
  A function name (i.e., a symbol satisfying @code{fboundp}).  Existing,
***************
*** 356,363 ****
  Prompt.
  
  @item B
! A buffer name.  The buffer need not exist.  By default, uses the name of
! a recently used buffer other than the current buffer.  Completion,
  Default, Prompt.
  
  @item c
--- 374,381 ----
  Prompt.
  
  @item B
! A buffer name.  The buffer need not exist.  By default, uses the name
! of a recently used buffer other than the current buffer.  Completion,
  Default, Prompt.
  
  @item c
***************
*** 504,509 ****
--- 522,771 ----
  argument value.  Completion, Existing, Prompt.
  @end table
  
+ @node Non-string Interactive
+ @comment  node-name,  next,  previous,  up
+ @subsection Non-string Equivalents of Interactive Code Characters
+ 
+ This page sketches non-string equivalents for each of the code
+ characters used in the string version of the interactive form.  These
+ should help you when you when you need to build the functionality of
+ the code characters into a non-string interactive form.  The semantics
+ of a non-string interactive form is defined in @ref{Using Interactive}
+ and the individual code characters are defined in @ref{Interactive
+ Codes}.
+ 
+ @table @asis
+ @item @samp{*} - check buffer is writable
+ @lisp
+ (interactive (progn (barf-if-buffer-readonly) nil))
+ @c There's funny stuff in callint.c; if the interactive string
+ @c consists of one other element besides '*', and that element isn't
+ @c 'p', 'P', or 'r', it is processed first before calling `barf-if-..'.
+ @c I don't know why this is so.  (ACM, 2009-04-10).
+ @end lisp
+ 
+ @item @samp{@@} - Select window of mouse event
+ @lisp
+ (interactive
+  (let ((events (this-command-keys-vector))
+        e w
+        (i 0))
+    (while (and (< i (length events))
+                (not (consp (setq e (aref events i)))))
+      (setq i (1+ i)))
+    (when (consp e)
+      (setq w (car (cadr e)))
+      (if (windowp w)
+          (if (and (window-minibuffer-p w)
+                   (> (minibuffer-depth) 0))
+              (error "Attempt to select silly inactive minibuffer window")))
+      (run-hooks mouse-leave-buffer-hook)
+      (select-window w))
+    nil))
+ @end lisp
+ Note that this form only works when the @var{keys} parameter to
+ @code{call-interactively} is @code{nil} (which it almost always is).
+ 
+ @item @samp{^} - shift-translation
+ @lisp
+ (interactive
+  (progn (if (fboundp 'handle-shift-selection)
+             (handle-shift-selection))
+         nil))
+ @end lisp
+ 
+ @item @samp{a} - function name
+ @lisp
+ (interactive (list (completing-read "Function: " obarray 'fboundp t)))
+ @end lisp
+ 
+ @item @samp{b} - existing buffer
+ @lisp
+ (interactive (list (read-buffer "Buffer: " (current-buffer) t)))
+ @end lisp
+ 
+ @item @samp{B} - buffer
+ @lisp
+ (interactive (list (read-buffer "Buffer: " (other-buffer))))
+ @end lisp
+ 
+ @item @samp{c} - character
+ @lisp
+ (interactive
+  (let ((prompt "Char: "))
+    (put-text-property 0 (length prompt) 'face 'minibuffer-prompt prompt)
+    (list (read-char prompt))))
+ @end lisp
+ 
+ @item @samp{C} - command
+ @lisp
+ (interactive (list (completing-read "Command: " obarray 'commandp t)))
+ @end lisp
+ 
+ @item @samp{d} - point
+ @lisp
+ (interactive (list (point)))
+ @end lisp
+ 
+ @item @samp{D} - existing directory
+ @lisp
+ (interactive
+  (list (read-file-name "Directory: "
+                        nil default-directory t nil 'file-directory-p)))
+ @end lisp
+ 
+ @item @samp{e} - mouse event
+ @lisp
+ (interactive
+  (let* ((events (this-command-keys-vector))
+         e
+         (i 0))
+    (while (and (< i (length events))
+                (not (consp (setq e (aref events i)))))
+      (setq i (1+ i)))
+    (and (consp e) (list e))))
+ @end lisp
+ Note that this form only works when the @var{keys} parameter to
+ @code{call-interactively} is @code{nil} (which it almost always is).
+ 
+ @item @samp{f} - existing file
+ @lisp
+ (interactive (list (read-file-name "File name: " nil nil t)))
+ @end lisp
+ 
+ @item @samp{F} - file
+ @lisp
+ (interactive (list (read-file-name "File name: ")))
+ @end lisp
+ 
+ @item @samp{G} - file or directory
+ @lisp
+ (interactive (list (read-file-name "F or d name: " nil nil nil "")))
+ @end lisp
+ 
+ @item @samp{i} - nil
+ @lisp
+ (interactive '(nil))
+ @end lisp
+ 
+ @item @samp{k} - key sequence (with case conversion)
+ @lisp
+ (interactive
+  (let ((prompt "Key binding: ")
+        (ks) last-event)
+    (put-text-property 0 (length prompt) 'face 'minibuffer-prompt prompt)
+    (setq ks (read-key-sequence prompt)
+          last-event (aref ks (1- (length ks))))
+    (if (consp last-event) (setq last-event (car last-event)))
+    (setq my-up-event
+          (and (symbolp last-event)
+               (memq 'down (get last-event 'event-symbol-elements))
+               (vector (read-event))))
+    (list ks)))
+ @end lisp
+ Note how @code{my-up-event} gets set to the mouse up event, if any.
+ You can use this for the @samp{U} equivalent (see below).
+ 
+ @item @samp{K} - key sequence (no case conversion)
+ @lisp
+ (interactive
+  (let ((prompt "Key binding: ")
+        (ks) last-event)
+    (put-text-property 0 (length prompt) 'face 'minibuffer-prompt prompt)
+    (setq ks (read-key-sequence prompt nil t)
+          last-event (aref ks (1- (length ks))))
+    (if (consp last-event) (setq last-event (car last-event)))
+    (setq my-up-event
+          (and (symbolp last-event)
+               (memq 'down (get last-event 'event-symbol-elements))
+               (vector (read-event))))
+    (list ks)))
+ @end lisp
+ Note how @code{my-up-event} gets set to the mouse up event, if any.
+ You can use this for the @samp{U} equivalent (see below).
+ 
+ @item @samp{m} - mark
+ @lisp
+ (interactive (list (mark)))
+ @end lisp
+ 
+ @item @samp{M} - text (with current input method)
+ @lisp
+ (interactive (list (read-string "Text: " nil nil nil t)))
+ @end lisp
+ 
+ @item @samp{n} - number
+ @lisp
+ (interactive (list (read-number "Number: ")))
+ @end lisp
+ 
+ @item @samp{N} - numeric prefix or read number
+ @lisp
+ (interactive
+  (list (if current-prefix-arg
+            (prefix-numeric-value current-prefix-arg)
+          (read-number "Number: "))))
+ @end lisp
+ 
+ @item @samp{p} - numeric prefix
+ @lisp
+ (interactive (list (prefix-numeric-value current-prefix-arg)))
+ @end lisp
+ 
+ @item @samp{P} - raw prefix
+ @lisp
+ (interactive (list current-prefix-arg))
+ @end lisp
+ 
+ @item @samp{r} - region
+ @lisp
+ (interactive (list (region-beginning) (region-end)))
+ @end lisp
+ 
+ @item @samp{s} - text (without input method)
+ @lisp
+ (interactive (list (read-string "Text: " nil nil nil t)))
+ @end lisp
+ 
+ @item @samp{S} - symbol
+ @lisp
+ (interactive (list (intern (read-string "Symbol: "))))
+ @end lisp
+ 
+ @item @samp{U} - mouse up event
+ @lisp
+ (interactive (list my-up-event))
+ @end lisp
+ @code{my-up-event} is set by the lisp for @samp{k} or @samp{K}.  You
+ should declare and maintain this variable in your own code.
+ 
+ @item @samp{v} - user option
+ @lisp
+ (interactive (list (read-variable "Option: ")))
+ @end lisp
+ 
+ @item @samp{x} - lisp expression
+ @lisp
+ (interactive (list (read-minibuffer "Lisp expression: ")))
+ @end lisp
+ 
+ @item @samp{X} - lisp expression, evaluated
+ @lisp
+ (interactive (list (eval-minibuffer "Lisp expression: ")))
+ @end lisp
+ 
+ @item @samp{z} - coding system (or nil)
+ @lisp
+ (interactive (list (read-coding-system "Coding system: ")))
+ @end lisp
+ 
+ @item @samp{Z} - with prefix arg, coding system else nil
+ @lisp
+ (interactive (list (and current-prefix-arg
+                         (read-non-nil-coding-system "Coding system: "))))
+ @end lisp
+ @end table
+ 
  @node Interactive Examples
  @comment  node-name,  next,  previous,  up
  @subsection Examples of Using @code{interactive}
***************
*** 530,537 ****
  @end group
  
  @group
! (defun foo3 (n)             ; @address@hidden takes one argument,}
!     (interactive "nCount:") ;   @r{which is read with the Minibuffer.}
      (forward-word (* 2 n)))
       @result{} foo3
  @end group
--- 792,799 ----
  @end group
  
  @group
! (defun foo3 (n)              ; @address@hidden takes one argument,}
!     (interactive "nCount: ") ;   @r{which is read with the Minibuffer.}
      (forward-word (* 2 n)))
       @result{} foo3
  @end group
***************
*** 541,547 ****
    "Select three existing buffers.
  Put them into three windows, selecting the last one."
  @end group
!     (interactive "bBuffer1:\nbBuffer2:\nbBuffer3:")
      (delete-other-windows)
      (split-window (selected-window) 8)
      (switch-to-buffer b1)
--- 803,809 ----
    "Select three existing buffers.
  Put them into three windows, selecting the last one."
  @end group
!     (interactive "bBuffer1: \nbBuffer2: \nbBuffer3: ")
      (delete-other-windows)
      (split-window (selected-window) 8)
      (switch-to-buffer b1)



>         Stefan

-- 
Alan Mackenzie (Nuremberg, Germany).




reply via email to

[Prev in Thread] Current Thread [Next in Thread]