viper: Key Bindings

 
 3.2 Key Bindings
 ================
 
 Viper lets you define hot keys, i.e., you can associate keyboard keys
 such as F1, Help, PgDn, etc., with Emacs Lisp functions (that may
 already exist or that you will write).  Each key has a “preferred form”
 in Emacs.  For instance, the Up key’s preferred form is [up], the Help
 key’s preferred form is [help], and the Undo key has the preferred form
 [f14].  You can find out the preferred form of a key by typing ‘M-x
 describe-key-briefly’ and then typing the key you want to know about.
 
    Under the X Window System, every keyboard key emits its preferred
 form, so you can just type
 
      (global-set-key [f11] 'calendar)                        ; L1, Stop
      (global-set-key [f14] 'undo)                            ; L4, Undo
 
 to bind L1 (a key that exists on some SUN workstations) so it will
 invoke the Emacs Calendar and to bind L4 so it will undo changes.
 However, on a dumb terminal or in an Xterm window, even the standard
 arrow keys may not emit the right signals for Emacs to understand.  To
 let Emacs know about those keys, you will have to find out which key
 sequences they emit by typing ‘C-q’ and then the key (you should switch
 to Emacs state first).  Then you can bind those sequences to their
 preferred forms using ‘input-decode-map’ as follows:
 
      (cond ((string= (getenv "TERM") "xterm")
      (define-key input-decode-map "\e[192z" [f11])    ; L1
      (define-key input-decode-map "\e[195z" [f14])    ; L4, Undo
 
    The above illustrates how to do this for Xterm.  On VT100, you would
 have to replace "xterm" with "vt100" and also change the key sequences
 (the same key may emit different sequences on different types of
 terminals).
 
    The above keys are global, so they are overwritten by the local maps
 defined by the major modes and by Viper itself.  Therefore, if you wish
 to change a binding set by a major mode or by Viper, read this.
 
    Viper users who wish to specify their own key bindings should be
 concerned only with the following three keymaps:
 ‘viper-vi-global-user-map’ for Vi state commands,
 ‘viper-insert-global-user-map’ for Insert state commands, and
 ‘viper-emacs-global-user-map’ for Emacs state commands (note: customized
 bindings for Emacs state made to ‘viper-emacs-global-user-map’ are _not_
 inherited by Insert state).
 
    For more information on Viper keymaps, see the header of the file
 ‘viper.el’.  If you wish to change a Viper binding, you can use the
 ‘define-key’ command, to modify ‘viper-vi-global-user-map’,
 ‘viper-insert-global-user-map’, and ‘viper-emacs-global-user-map’, as
 explained below.  Each of these key maps affects the corresponding Viper
 state.  The keymap ‘viper-insert-global-user-map’ also affects Viper’s
 Replace state.
 
 If you want to bind a key, say ‘C-v’, to the function that scrolls page
 down and to make ‘0’ display information on the current buffer, putting
 this in your Viper customization file will do the trick in Vi state:
      (define-key viper-vi-global-user-map "\C-v" 'scroll-down)
 To set a key globally,
      (define-key viper-emacs-global-user-map "\C-c m" 'smail)
      (define-key viper-vi-global-user-map "0" 'viper-info-on-file)
 Note, however, that this binding may be overwritten by other keymaps,
 since the global keymap has the lowest priority.  To make sure that
 nothing will override a binding in Emacs state, you can write this:
      (define-key viper-emacs-global-user-map "\C-c m" 'smail)
 To customize the binding for ‘C-h’ in Insert state:
      (define-key viper-insert-global-user-map "\C-h"
        'my-del-backwards-function)
 
    Each Emacs command key calls some Lisp function.  If you have enabled
 the Help, (SeeRudimentary Changes) ‘C-h k’ will show you the
 function for each specific key; ‘C-h b’ will show all bindings, and ‘C-h
 m’ will provide information on the major mode in effect.  If Help is not
 enabled, you can still get help in Vi state by prefixing the above
 commands with ‘\’, e.g., ‘\ C-h k’ (or you can use the Help menu in the
 menu bar, if Emacs runs under X).
 
    Viper users can also change bindings on a per major mode basis.  As
 with global bindings, this can be done separately for each of the three
 main Viper states.  To this end, Viper provides the function
 ‘viper-modify-major-mode’.
 
    To modify keys in Emacs state for ‘my-favorite-major-mode’, the user
 needs to create a sparse keymap, say, ‘my-fancy-map’, bind whatever keys
 necessary in that keymap, and put
 
      (viper-modify-major-mode 'dired-mode 'emacs-state my-fancy-map)
 
 in your Viper customization file.  To do the same in Vi and Insert
 states, you should use ‘vi-state’ and ‘insert-state’.  Changes in Insert
 state are also in effect in Replace state.  For instance, suppose that
 the user wants to use ‘dd’ in Vi state under Dired mode to delete files,
 ‘u’ to unmark files, etc.  The following code in the Viper customization
 file will then do the job:
 
      (setq my-dired-modifier-map (make-sparse-keymap))
      (define-key my-dired-modifier-map "dd" 'dired-flag-file-deletion)
      (define-key my-dired-modifier-map "u" 'dired-unmark)
      (viper-modify-major-mode 'dired-mode 'vi-state my-dired-modifier-map)
 
    A Vi purist may want to modify Emacs state under Dired mode so that
 ‘k’, ‘l’, etc., will move around in directory buffers, as in Vi.
 Although this is not recommended, as these keys are bound to useful
 Dired functions, the trick can be accomplished via the following code:
 
      (setq my-dired-vi-purist-map (make-sparse-keymap))
      (define-key my-dired-vi-purist-map "k" 'viper-previous-line)
      (define-key my-dired-vi-purist-map "l" 'viper-forward-char)
      (viper-modify-major-mode 'dired-mode
                               'emacs-state my-dired-vi-purist-map)
 
    Yet another way to customize key bindings in a major mode is to edit
 the list ‘viper-major-mode-modifier-list’ using the customization
 widget.  (This variable is in the Viper-misc customization group.)  The
 elements of this list are triples of the form: (major-mode viper-state
 keymap), where the keymap contains bindings that are supposed to be
 active in the given major mode and the given viper-state.
 
    Effects similar to key binding changes can be achieved by defining Vi
 keyboard macros using the Ex commands ‘:map’ and ‘:map!’.  The
 difference is that multi-key Vi macros do not override the keys they are
 bound to, unless these keys are typed in quick succession.  So, with
 macros, one can use the normal keys alongside with the macros.  If
 per-mode modifications are needed, the user can try both ways and see
 which one is more convenient.  SeeVi Macros, for details.
 
    Note: in major modes that come up in _Emacs state_ by default, the
 aforesaid modifications may not take place immediately (but only after
 the buffer switches to some other Viper state and then back to Emacs
 state).  To avoid this, one should add ‘viper-change-state-to-emacs’ to
 an appropriate hook of that major mode.  (Check the function
 ‘viper-set-hooks’ in ‘viper.el’ for examples.)  However, if you did not
 set ‘viper-always’ to ‘nil’, chances are that you won’t need to perform
 the above procedure, because Viper will take care of most useful
 defaults.
 
    Finally, Viper has a facility that lets the user define per-buffer
 bindings, i.e., bindings that are in effect in some specific buffers
 only.  Unlike per-mode bindings described above, per-buffer bindings can
 be defined based on considerations other than the major mode.  This is
 done via the function ‘viper-add-local-keys’, which lets one specify
 bindings that should be in effect in the current buffer only and for a
 specific Viper state.  For instance,
      (viper-add-local-keys 'vi-state '(("ZZ" . TeX-command-master)
                                       ("ZQ" . viper-save-kill-buffer)))
 redefines ‘ZZ’ to invoke ‘TeX-command-master’ in ‘vi-state’ and ‘ZQ’ to
 save-then-kill the current buffer.  These bindings take effect only in
 the buffer where this command is executed.  The typical use of this
 function is to execute the above expression from within a function that
 is included in a hook to some major mode.  For instance, the above
 expression could be called from a function, ‘my-tex-init’, which may be
 added to ‘tex-mode-hook’ as follows:
      (add-hook 'tex-mode-hook 'my-tex-init)
 When TeX mode starts, the hook is executed and the above Lisp expression
 is evaluated.  Then, the bindings for ‘ZZ’ and ‘ZQ’ are changed in Vi
 command mode for all buffers in TeX mode.
 
    Another useful application is to bind ‘ZZ’ to ‘send-mail’ in the Mail
 mode buffers (the specifics of this depend on which mail package you are
 using, ‘rmail’, ‘mh-e’, ‘vm’, etc.  For instance, here is how to do this
 for ‘mh-e’, the Emacs interface to MH:
      (defun mh-add-vi-keys ()
        "Set up ZZ for MH-e and XMH."
        (viper-add-local-keys 'vi-state '(("ZZ" . mh-send-letter))))
      (add-hook 'mh-letter-mode-hook 'mh-add-vi-keys)
 
    You can also use ‘viper-add-local-keys’ to set per buffer bindings in
 Insert state and Emacs state by passing as a parameter the symbols
 ‘insert-state’ and ‘emacs-state’, respectively.  As with global
 bindings, customized local bindings done to Emacs state are not
 inherited by Insert state.
 
    On rare occasions, local keys may be added by mistake.  Usually this
 is done indirectly, by invoking a major mode that adds local keys (e.g.,
 ‘shell-mode’ redefines <RET>).  In such a case, exiting the wrong major
 mode won’t rid you from unwanted local keys, since these keys are local
 to Viper state and the current buffer, not to the major mode.  In such
 situations, the remedy is to type ‘M-x viper-zap-local-keys’.
 
    So much about Viper-specific bindings.  SeeCustomization
 (emacs)Customization, and the Emacs quick reference card for the general
 info on key bindings in Emacs.