calc: Defining Simple Commands

 
 18.5.2 Defining New Simple Commands
 -----------------------------------
 
 If a ‘defmath’ form contains an ‘interactive’ clause, it defines a
 Calculator command.  Actually such a ‘defmath’ results in _two_ function
 definitions: One, a ‘calcFunc-’ function as was just described, with the
 ‘interactive’ clause removed.  Two, a ‘calc-’ function with a suitable
 ‘interactive’ clause and some sort of wrapper to make the command work
 in the Calc environment.
 
    In the simple case, the ‘interactive’ clause has the same form as for
 normal Emacs Lisp commands:
 
      (defmath increase-precision (delta)
        "Increase precision by DELTA."     ; This is the "documentation string"
        (interactive "p")                  ; Register this as a M-x-able command
        (setq calc-internal-prec (+ calc-internal-prec delta)))
 
    This expands to the pair of definitions,
 
      (defun calc-increase-precision (delta)
        "Increase precision by DELTA."
        (interactive "p")
        (calc-wrapper
         (setq calc-internal-prec (math-add calc-internal-prec delta))))
 
      (defun calcFunc-increase-precision (delta)
        "Increase precision by DELTA."
        (setq calc-internal-prec (math-add calc-internal-prec delta)))
 
 where in this case the latter function would never really be used!  Note
 that since the Calculator stores small integers as plain Lisp integers,
 the ‘math-add’ function will work just as well as the native ‘+’ even
 when the intent is to operate on native Lisp integers.
 
    The ‘calc-wrapper’ call invokes a macro which surrounds the body of
 the function with code that looks roughly like this:
 
      (let ((calc-command-flags nil))
        (unwind-protect
            (save-current-buffer
              (calc-select-buffer)
              _body of function_
              _renumber stack_
              _clear_ Working _message_)
          _realign cursor and window_
          _clear Inverse, Hyperbolic, and Keep Args flags_
          _update Emacs mode line_))
 
    The ‘calc-select-buffer’ function selects the ‘*Calculator*’ buffer
 if necessary, say, because the command was invoked from inside the
 ‘*Calc Trail*’ window.
 
    You can call, for example, ‘(calc-set-command-flag 'no-align)’ to set
 the above-mentioned command flags.  Calc routines recognize the
 following command flags:
 
 ‘renum-stack’
      Stack line numbers ‘1:’, ‘2:’, and so on must be renumbered after
      this command completes.  This is set by routines like ‘calc-push’.
 
 ‘clear-message’
      Calc should call ‘(message "")’ if this command completes normally
      (to clear a “Working...” message out of the echo area).
 
 ‘no-align’
      Do not move the cursor back to the ‘.’ top-of-stack marker.
 
 ‘position-point’
      Use the variables ‘calc-position-point-line’ and
      ‘calc-position-point-column’ to position the cursor after this
      command finishes.
 
 ‘keep-flags’
      Do not clear ‘calc-inverse-flag’, ‘calc-hyperbolic-flag’, and
      ‘calc-keep-args-flag’ at the end of this command.
 
 ‘do-edit’
      Switch to buffer ‘*Calc Edit*’ after this command.
 
 ‘hold-trail’
      Do not move trail pointer to end of trail when something is
      recorded there.
 
    Calc reserves a special prefix key, shift-‘Y’, for user-written
 extensions to Calc.  There are no built-in commands that work with this
 prefix key; you must call ‘define-key’ from Lisp (probably from inside a
 ‘calc-define’ property) to add to it.  Initially only ‘Y ?’ is defined;
 it takes help messages from a list of strings (initially ‘nil’) in the
 variable ‘calc-Y-help-msgs’.  All other undefined keys except for ‘Y’
 are reserved for use by future versions of Calc.
 
    If you are writing a Calc enhancement which you expect to give to
 others, it is best to minimize the number of ‘Y’-key sequences you use.
 In fact, if you have more than one key sequence you should consider
 defining three-key sequences with a ‘Y’, then a key that stands for your
 package, then a third key for the particular command within your
 package.
 
    Users may wish to install several Calc enhancements, and it is
 possible that several enhancements will choose to use the same key.  In
 the example below, a variable ‘inc-prec-base-key’ has been defined to
 contain the key that identifies the ‘inc-prec’ package.  Its value is
 initially ‘"P"’, but a user can change this variable if necessary
 without having to modify the file.
 
    Here is a complete file, ‘inc-prec.el’, which makes a ‘Y P I’ command
 that increases the precision, and a ‘Y P D’ command that decreases the
 precision.
 
      ;;; Increase and decrease Calc precision.  Dave Gillespie, 5/31/91.
      ;; (Include copyright or copyleft stuff here.)
 
      (defvar inc-prec-base-key "P"
        "Base key for inc-prec.el commands.")
 
      (put 'calc-define 'inc-prec '(progn
 
      (define-key calc-mode-map (format "Y%sI" inc-prec-base-key)
                  'increase-precision)
      (define-key calc-mode-map (format "Y%sD" inc-prec-base-key)
                  'decrease-precision)
 
      (setq calc-Y-help-msgs
            (cons (format "%s + Inc-prec, Dec-prec" inc-prec-base-key)
                  calc-Y-help-msgs))
 
      (defmath increase-precision (delta)
        "Increase precision by DELTA."
        (interactive "p")
        (setq calc-internal-prec (+ calc-internal-prec delta)))
 
      (defmath decrease-precision (delta)
        "Decrease precision by DELTA."
        (interactive "p")
        (setq calc-internal-prec (- calc-internal-prec delta)))
 
      ))  ; end of calc-define property
 
      (run-hooks 'calc-check-defines)