Next: , Previous: Numeric Argument In Drei, Up: Defining Drei Commands


18.5.3 Examples Of Defining Drei Commands

A common text editing task is to repeat the word at point, but for some reason, Drei does not come with a command to do this, so we need to write our own. Fortunately, Drei is extensible software, and to that end, a DREI-USER package is provided that is intended for user customizations. We're going to create a standard CLIM command named com-repeat-word in the command table editing-table. The implementation consists of cloning the current point, move it a word backward, and insert into the buffer the sequence delimited by point and our moved mark. Our command takes no arguments.

     (define-command (com-repeat-word :name t
                                      :command-table editing-table)
         ()
       (let ((mark (clone-mark *current-point*)))
         (backward-word mark *current-syntax* 1)
         (insert-sequence mark (region-to-sequence mark *current-point*))))

For *current-point* and *current-syntax*, see Special Variables.

This command facilitates the single repeat of a word, but that's it. This is not very useful - instead, we would like a command that could repeat a word an arbitrary (user-supplied) number of times. The primary way for a CLIM command to ask for user-supplied values is to use command arguments. We define a new command that takes an integer argument specifying the number of times to repeat the word at point.

     (define-command (com-repeat-word :name t
                                      :command-table editing-table)
         ((count 'integer :prompt "Number of repeats"))
       (let ((mark (clone-mark *current-point*)))
         (backward-word mark *current-syntax* 1)
         (let ((word (region-to-sequence mark *current-point*)))
           (dotimes (i count)
             (insert-sequence mark word)))))

Great - our command is now pretty full-featured. But with an editing operation as common as this, we really want it to be quickly accessible via some intuitive keystroke. We choose M-C-r. Also, it'd be nice if, instead of interactively quering us for commands, the command would just use the value of the numeric argument as the number of times to repeat. There's no way to do this with a named command (ie. when you run the command with M-x), but it's quite easy to do in a keybinding. We use the ESA set-key function:

     (set-key `(com-repeat-word ,*numeric-argument-marker*)
              'editing-table
              '((#\r :control :meta)))

Now, pressing M-C-r will result in the com-repeat-word command being run with the first argument substituted for the value of the numeric argument. Since the numeric argument will be 1 if nothing else has been specified by the user, we are guaranteed that the first argument is always an integer, and we are guaranteed that the count argument will have a sensible default, even if the user does not explicitly provide a numeric argument.