viper.el 49.1 KB
Newer Older
1
;;; viper.el --- A full-featured Vi emulator for GNU Emacs and XEmacs,
Karl Heuer's avatar
Karl Heuer committed
2 3 4 5
;;		 a VI Plan for Emacs Rescue,
;;		 and a venomous VI PERil.
;;		 Viper Is also a Package for Emacs Rebels.

6
;; Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
7
;;   2003, 2004, 2005, 2006 Free Software Foundation, Inc.
8

9
;; Author: Michael Kifer <kifer@cs.stonybrook.edu>
10 11
;; Keywords: emulations

12
(defconst viper-version "3.13 of September 18, 2006"
Michael Kifer's avatar
Michael Kifer committed
13 14
  "The current version of Viper")

Karl Heuer's avatar
Karl Heuer committed
15 16 17 18 19 20 21 22 23 24 25 26 27
;; This file is part of GNU Emacs.

;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; GNU Emacs 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 General Public License for more details.

;; You should have received a copy of the GNU General Public License
Karl Heuer's avatar
Karl Heuer committed
28
;; along with GNU Emacs; see the file COPYING.  If not, write to the
Lute Kamstra's avatar
Lute Kamstra committed
29 30
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
Karl Heuer's avatar
Karl Heuer committed
31 32 33

;;; Commentary:

Michael Kifer's avatar
Michael Kifer committed
34
;; Viper is a full-featured Vi emulator for Emacs and XEmacs.  It emulates and
Karl Heuer's avatar
Karl Heuer committed
35 36 37
;; improves upon the standard features of Vi and, at the same time, allows
;; full access to all Emacs facilities.  Viper supports multiple undo,
;; file name completion, command, file, and search history and it extends
Michael Kifer's avatar
Michael Kifer committed
38
;; Vi in many other ways.  Viper is highly customizable through the various
Karl Heuer's avatar
Karl Heuer committed
39 40 41 42
;; hooks, user variables, and keymaps.  It is implemented as a collection
;; of minor modes and it is designed to provide full access to all Emacs
;; major and minor modes.
;;
43
;;; History:
Karl Heuer's avatar
Karl Heuer committed
44 45 46 47
;;
;; Viper is a new name for a package formerly known as VIP-19,
;; which was a successor of VIP version 3.5 by Masahiko Sato
;; <ms@sail.stanford.edu> and VIP version 4.2 by Aamod Sane
Michael Kifer's avatar
Michael Kifer committed
48
;; <sane@cs.uiuc.edu>.  Some ideas from vip 4.4.2 by Aamod Sane
Karl Heuer's avatar
Karl Heuer committed
49 50 51
;; were also shamelessly plagiarized.
;;
;; Viper maintains some degree of compatibility with these older
Michael Kifer's avatar
Michael Kifer committed
52
;; packages.  See the documentation for customization.
Karl Heuer's avatar
Karl Heuer committed
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
;;
;; The main difference between Viper and these older packages are:
;;
;; 1. Viper emulates Vi at several levels, from almost complete conformity
;;    to a rather loose Vi-compliance.
;;
;; 2. Viper provides full access to all major and minor modes of Emacs
;;    without the need to type extra keys.
;;    The older versions of VIP (and other Vi emulators) do not work with
;;    some major and minor modes.
;;
;; 3. Viper supports vi-style undo.
;;
;; 4. Viper fully emulates (and improves upon) vi's replacement mode.
;;
;; 5. Viper has a better interface to ex, including command, variable, and
;;    file name completion.
;;
;; 6. Viper uses native Emacs history and completion features; it doesn't
;;    rely on other packages (such as gmhist.el and completer.el) to provide
;;    these features.
;;
;; 7. Viper supports Vi-style editing in the minibuffer, by allowing the
;;    user to switch from Insert state to Vi state to Replace state, etc.
;;
;; 8. Viper keeps history of recently inserted pieces of text and recently
;;    executed Vi-style destructive commands, such as `i', `d', etc.
;;    These pieces of text can be inserted in later insertion commands;
;;    the previous destructive commands can be re-executed.
;;
;; 9. Viper has Vi-style keyboard macros, which enhances the similar
;;    facility in the original Vi.
;;    First, one can execute any Emacs command while defining a
Michael Kifer's avatar
Michael Kifer committed
86
;;    macro, not just the Vi commands.  Second, macros are defined in a
Karl Heuer's avatar
Karl Heuer committed
87
;;    WYSYWYG mode, using an interface to Emacs' WYSIWYG style of defining
Michael Kifer's avatar
Michael Kifer committed
88
;;    macros.  Third, in Viper, one can define macros that are specific to
Karl Heuer's avatar
Karl Heuer committed
89 90 91 92
;;    a given buffer, a given major mode, or macros defined for all buffers.
;;    The same macro name can have several different definitions:
;;    one global, several definitions for various major modes, and
;;    definitions for specific buffers.
Karl Heuer's avatar
Karl Heuer committed
93
;;    Buffer-specific definitions override mode-specific
Karl Heuer's avatar
Karl Heuer committed
94 95 96 97 98 99 100 101 102 103 104
;;    definitions, which, in turn, override global definitions.
;;
;;
;;; Installation:
;;  -------------
;;
;;  (require 'viper)
;;

;;; Acknowledgements:
;;  -----------------
Karl Heuer's avatar
Karl Heuer committed
105 106
;;  Bug reports and ideas contributed by many users have helped
;;  improve Viper and the various versions of VIP.
107
;;  See the on-line manual for a complete list of contributors.
Karl Heuer's avatar
Karl Heuer committed
108 109 110 111 112 113
;;
;;
;;; Notes:
;;
;; 1. Major modes.
;; In most cases, Viper handles major modes correctly, i.e., they come up
Michael Kifer's avatar
Michael Kifer committed
114
;; in the right state (either  vi-state or emacs-state).  For instance, text
Karl Heuer's avatar
Karl Heuer committed
115
;; files come up in vi-state, while, say, Dired appears in emacs-state by
116
;; default.
Karl Heuer's avatar
Karl Heuer committed
117 118
;; However, some modes do not appear in the right mode in the beginning,
;; usually because they neglect to follow Emacs conventions (e.g., they don't
Michael Kifer's avatar
Michael Kifer committed
119
;; use kill-all-local-variables when they start).  Some major modes
Karl Heuer's avatar
Karl Heuer committed
120
;; may fail to come up in emacs-state if they call hooks, such as
121 122
;; text-hook, for no good reason.
;;
Karl Heuer's avatar
Karl Heuer committed
123 124
;; As an immediate solution, you can hit C-z to bring about the right mode.
;; An interim solution is to add an appropriate hook to the mode like this:
125
;;
Karl Heuer's avatar
Karl Heuer committed
126
;;     (add-hook 'your-favorite-mode 'viper-mode)
127
;; or
Michael Kifer's avatar
Michael Kifer committed
128
;;     (add-hook 'your-favorite-mode 'viper-change-state-to-emacs)
129
;;
Michael Kifer's avatar
Michael Kifer committed
130
;; whichever applies.  The right thing to do, however, is to complain to the
Karl Heuer's avatar
Karl Heuer committed
131 132
;; author of the respective package. (Sometimes they also neglect to equip
;; their  modes with hooks, which is one more reason for complaining.)
133
;;
Karl Heuer's avatar
Karl Heuer committed
134
;; 2. Keymap handling
Michael Kifer's avatar
Michael Kifer committed
135 136
;;    Each Viper state (insert, vi, replace) is implemented as a collection of
;;    several minor modes, each with its own keymap.
Karl Heuer's avatar
Karl Heuer committed
137 138 139
;;
;; Viper's  Vi state consists of seven minor modes:
;;
Michael Kifer's avatar
Michael Kifer committed
140 141 142 143 144 145 146
;;  viper-vi-intercept-minor-mode
;;  viper-vi-local-user-minor-mode
;;  viper-vi-global-user-minor-mode
;;  viper-vi-kbd-minor-mode
;;  viper-vi-state-modifier-minor-mode
;;  viper-vi-diehard-minor-mode
;;  viper-vi-basic-minor-mode
Karl Heuer's avatar
Karl Heuer committed
147 148 149 150
;;
;;  Bindings done to the keymap of the first mode overshadow those done to
;;  the second, which, in turn, overshadows those done to the third, etc.
;;
Michael Kifer's avatar
Michael Kifer committed
151
;;  The last viper-vi-basic-minor-mode contains most of the usual Vi bindings
Michael Kifer's avatar
Michael Kifer committed
152
;;  in its edit mode.  This mode provides access to all Emacs facilities.
Michael Kifer's avatar
Michael Kifer committed
153
;;  Novice users, however, may want to set their viper-expert-level to 1
Michael Kifer's avatar
Michael Kifer committed
154
;;  in their .viper file.  This will enable viper-vi-diehard-minor-mode.  This
Karl Heuer's avatar
Karl Heuer committed
155 156 157 158
;;  minor mode's bindings make Viper simulate the usual Vi very closely.
;;  For instance,  C-c will not have its standard Emacs binding
;;  and so many of the goodies of Emacs are not available.
;;
Michael Kifer's avatar
Michael Kifer committed
159
;;  A skilled user should set viper-expert-level to at least 3.  This will
Karl Heuer's avatar
Karl Heuer committed
160
;;  enable `C-c' and many Emacs facilities will become available.
Michael Kifer's avatar
Michael Kifer committed
161
;;  In this case, viper-vi-diehard-minor-mode is inactive.
Karl Heuer's avatar
Karl Heuer committed
162 163
;;
;;  Viper gurus should have at least
Michael Kifer's avatar
Michael Kifer committed
164
;;      (setq viper-expert-level 4)
Michael Kifer's avatar
Michael Kifer committed
165
;;  in their ~/.viper files.  This will unsuppress all Emacs keys that are not
Karl Heuer's avatar
Karl Heuer committed
166 167
;;  essential for VI-style editing.
;;  Pick-and-choose users may want to put
Michael Kifer's avatar
Michael Kifer committed
168
;;      (setq viper-expert-level 5)
Michael Kifer's avatar
Michael Kifer committed
169
;;  in ~/.viper.  Viper will then leave it up to the user to set the variables
Michael Kifer's avatar
Michael Kifer committed
170
;;  viper-want-*  See viper-set-expert-level for details.
Karl Heuer's avatar
Karl Heuer committed
171
;;
Michael Kifer's avatar
Michael Kifer committed
172
;;  The very first minor mode, viper-vi-intercept-minor-mode, is of no
Michael Kifer's avatar
Michael Kifer committed
173
;;  concern for the user.  It is needed to bind Viper's vital keys, such as
Karl Heuer's avatar
Karl Heuer committed
174 175
;;  ESC and C-z.
;;
Michael Kifer's avatar
Michael Kifer committed
176
;;  The second mode,  viper-vi-local-user-minor-mode, usually has an
Michael Kifer's avatar
Michael Kifer committed
177
;;  empty keymap.  However, the user can set bindings in this keymap, which
Karl Heuer's avatar
Karl Heuer committed
178
;;  will overshadow the corresponding bindings in the other two minor
Michael Kifer's avatar
Michael Kifer committed
179
;;  modes.  This is useful, for example, for setting up ZZ in gnus,
Karl Heuer's avatar
Karl Heuer committed
180 181 182
;;  rmail, mh-e, etc., to send  message instead of saving it in a file.
;;  Likewise, in Dired mode, you may want to bind ZN and ZP to commands
;;  that would visit the next or the previous file in the Dired buffer.
Michael Kifer's avatar
Michael Kifer committed
183
;;  Setting local keys is tricky, so don't do it directly.  Instead, use
Michael Kifer's avatar
Michael Kifer committed
184
;;  viper-add-local-keys function (see its doc).
Karl Heuer's avatar
Karl Heuer committed
185
;;
Michael Kifer's avatar
Michael Kifer committed
186 187
;;  The third minor mode, viper-vi-global-user-minor-mode, is also intended
;;  for the users but, unlike viper-vi-local-user-minor-mode, its key
Michael Kifer's avatar
Michael Kifer committed
188
;;  bindings are seen in all Viper buffers.  This mode keys can be done
Karl Heuer's avatar
Karl Heuer committed
189 190
;;  with define-key command.
;;
Michael Kifer's avatar
Michael Kifer committed
191
;;  The fourth minor mode, viper-vi-kbd-minor-mode, is used by keyboard
Michael Kifer's avatar
Michael Kifer committed
192
;;  macros.  Users are NOT supposed to modify this keymap directly.
Karl Heuer's avatar
Karl Heuer committed
193
;;
Michael Kifer's avatar
Michael Kifer committed
194
;;  The fifth mode, viper-vi-state-modifier-minor-mode, can be used to set
Karl Heuer's avatar
Karl Heuer committed
195 196 197
;;  key bindings that are visible in some major modes but not in others.
;;
;;  Users are allowed to modify keymaps that belong to
Michael Kifer's avatar
Michael Kifer committed
198 199
;;  viper-vi-local-user-minor-mode, viper-vi-global-user-minor-mode,
;;  and viper-vi-state-modifier-minor-mode only.
Karl Heuer's avatar
Karl Heuer committed
200 201 202
;;
;;  Viper's Insert state also has seven minor modes:
;;
Michael Kifer's avatar
Michael Kifer committed
203 204 205 206 207 208 209
;;      viper-insert-intercept-minor-mode
;;  	viper-insert-local-user-minor-mode
;;  	viper-insert-global-user-minor-mode
;;  	viper-insert-kbd-minor-mode
;;      viper-insert-state-modifier-minor-mode
;;  	viper-insert-diehard-minor-mode
;;  	viper-insert-basic-minor-mode
Karl Heuer's avatar
Karl Heuer committed
210
;;
Michael Kifer's avatar
Michael Kifer committed
211 212 213
;;  As with VI's editing modes, the first mode,
;;  viper-insert-intercept-minor-mode is used to bind vital keys that are not
;;  to be changed by the user.
Karl Heuer's avatar
Karl Heuer committed
214
;;
Michael Kifer's avatar
Michael Kifer committed
215
;;  The next mode, viper-insert-local-user-minor-mode, is used to customize
Michael Kifer's avatar
Michael Kifer committed
216
;;  bindings in the insert state of Viper.  The third mode,
Michael Kifer's avatar
Michael Kifer committed
217 218
;;  viper-insert-global-user-minor-mode is like
;;  viper-insert-local-user-minor-mode, except that its bindings are seen in
Michael Kifer's avatar
Michael Kifer committed
219 220
;;  all Viper buffers.  As with viper-vi-local-user-minor-mode, its bindings
;;  should be done via the function viper-add-local-keys.  Bindings for
Michael Kifer's avatar
Michael Kifer committed
221
;;  viper-insert-global-user-minor-mode can be set with the define-key command.
Karl Heuer's avatar
Karl Heuer committed
222
;;
Michael Kifer's avatar
Michael Kifer committed
223
;;  The next minor mode, viper-insert-kbd-minor-mode,
224
;;  is used for keyboard VI-style macros defined with :map!.
Karl Heuer's avatar
Karl Heuer committed
225
;;
Michael Kifer's avatar
Michael Kifer committed
226 227
;;  The fifth minor mode, viper-insert-state-modifier-minor-mode, is like
;;  viper-vi-state-modifier-minor-mode, except that it is used in the Insert
228
;;  state; it can be used to modify keys in a mode-specific fashion.
Karl Heuer's avatar
Karl Heuer committed
229
;;
Michael Kifer's avatar
Michael Kifer committed
230
;;  The minor mode viper-insert-diehard-minor-mode is in effect when
Karl Heuer's avatar
Karl Heuer committed
231
;;  the user wants a high degree of Vi compatibility (a bad idea, really!).
Michael Kifer's avatar
Michael Kifer committed
232
;;  The last minor mode, viper-insert-basic-minor-mode, is always in effect
Michael Kifer's avatar
Michael Kifer committed
233
;;  when Viper is in insert state.  It binds a small number of keys needed for
234
;;  Viper's operation.
Karl Heuer's avatar
Karl Heuer committed
235 236 237 238
;;
;;  Finally, Viper provides minor modes for overriding bindings set by Emacs
;;  modes when Viper is in Emacs state:
;;
Michael Kifer's avatar
Michael Kifer committed
239 240 241 242
;; 	viper-emacs-local-user-minor-mode
;;  	viper-emacs-global-user-minor-mode
;;      viper-emacs-kbd-minor-mode
;;      viper-emacs-state-modifier-minor-mode
Karl Heuer's avatar
Karl Heuer committed
243
;;
Michael Kifer's avatar
Michael Kifer committed
244
;;  These minor modes are in effect when Viper is in Emacs state.  The keymap
Michael Kifer's avatar
Michael Kifer committed
245 246
;;  associated with viper-emacs-global-user-minor-mode,
;;  viper-emacs-global-user-map, overrides the global and local keymaps as
Michael Kifer's avatar
Michael Kifer committed
247
;;  well as the minor mode keymaps set by other modes.  The keymap of
Michael Kifer's avatar
Michael Kifer committed
248
;;  viper-emacs-local-user-minor-mode, viper-emacs-local-user-map, overrides
Karl Heuer's avatar
Karl Heuer committed
249
;;  everything, but it is used on a per buffer basis.
Michael Kifer's avatar
Michael Kifer committed
250
;;  The keymap associated with viper-emacs-state-modifier-minor-mode
Michael Kifer's avatar
Michael Kifer committed
251
;;  overrides keys on a per-major-mode basis.  The mode
Michael Kifer's avatar
Michael Kifer committed
252
;;  viper-emacs-kbd-minor-mode is used to define Vi-style macros in Emacs
Karl Heuer's avatar
Karl Heuer committed
253 254 255
;;  state.
;;
;;  3. There is also one minor mode that is used when Viper is in its
Michael Kifer's avatar
Michael Kifer committed
256
;;     replace-state (used for commands like cw, C, etc.).  This mode is
Karl Heuer's avatar
Karl Heuer committed
257 258
;;     called
;;
Michael Kifer's avatar
Michael Kifer committed
259
;;       viper-replace-minor-mode
Karl Heuer's avatar
Karl Heuer committed
260
;;
Michael Kifer's avatar
Michael Kifer committed
261
;;     and its keymap is viper-replace-map.  Replace minor mode is always
Karl Heuer's avatar
Karl Heuer committed
262 263 264
;;     used in conjunction with the minor modes for insert-state, and its
;;     keymap overshadows the keymaps for insert minor modes.
;;
265
;;  4. Defining buffer-local bindings in Vi and Insert modes.
Karl Heuer's avatar
Karl Heuer committed
266 267
;;  As mentioned before, sometimes, it is convenient to have
;;  buffer-specific of mode-specific key bindings in Vi and insert modes.
Michael Kifer's avatar
Michael Kifer committed
268
;;  Viper provides a special function, viper-add-local-keys, to do precisely
Michael Kifer's avatar
Michael Kifer committed
269
;;  this.  For instance, is you need to add couple of mode-specific bindings
270
;;  to Insert mode, you can put
Karl Heuer's avatar
Karl Heuer committed
271
;;
272
;;       (viper-add-local-keys 'insert-state '((key1 . func1) (key2 .func2)))
Karl Heuer's avatar
Karl Heuer committed
273
;;
Michael Kifer's avatar
Michael Kifer committed
274
;;  somewhere in a hook of this major mode.  If you put something like this
Karl Heuer's avatar
Karl Heuer committed
275
;;  in your own elisp function, this will define bindings specific to the
Michael Kifer's avatar
Michael Kifer committed
276
;;  buffer that was current at the time of the call to viper-add-local-keys.
Karl Heuer's avatar
Karl Heuer committed
277 278
;;  The only thing to make sure here is that the major mode of this buffer
;;  is written according to Emacs conventions, which includes a call to
Michael Kifer's avatar
Michael Kifer committed
279
;;  (kill-all-local-variables).  See viper-add-local-keys for more details.
Karl Heuer's avatar
Karl Heuer committed
280 281 282 283 284
;;
;;
;;  TO DO (volunteers?):
;;
;; 1. Some of the code that is inherited from VIP-3.5 is rather
Michael Kifer's avatar
Michael Kifer committed
285 286
;;    convoluted.  Instead of viper-command-argument, keymaps should bind the
;;    actual commands.  E.g., "dw" should be bound to a generic command
Michael Kifer's avatar
Michael Kifer committed
287
;;    viper-delete that will delete things based on the value of
Michael Kifer's avatar
Michael Kifer committed
288
;;    last-command-char.  This would greatly simplify the logic and the code.
Karl Heuer's avatar
Karl Heuer committed
289 290 291 292
;;
;; 2. Somebody should venture to write a customization package a la
;;    options.el that would allow the user to change values of variables
;;    that meet certain specs (e.g., match a regexp) and whose doc string
Michael Kifer's avatar
Michael Kifer committed
293 294
;;    starts with a '*'.  Then, the user should be offered to save
;;    variables that were changed.  This will make user's customization job
Karl Heuer's avatar
Karl Heuer committed
295 296 297
;;    much easier.
;;

298
;;; Code:
Karl Heuer's avatar
Karl Heuer committed
299 300 301 302 303

(require 'advice)
(require 'cl)
(require 'ring)

Michael Kifer's avatar
Michael Kifer committed
304 305
;; compiler pacifier
(defvar mark-even-if-inactive)
Michael Kifer's avatar
Michael Kifer committed
306
(defvar quail-mode)
Michael Kifer's avatar
Michael Kifer committed
307
(defvar viper-expert-level)
Michael Kifer's avatar
Michael Kifer committed
308 309
(defvar viper-mode-string)
(defvar viper-major-mode-modifier-list)
Karl Heuer's avatar
Karl Heuer committed
310

Michael Kifer's avatar
Michael Kifer committed
311 312 313 314 315
;; loading happens only in non-interactive compilation
;; in order to spare non-viperized emacs from being viperized
(if noninteractive
    (eval-when-compile
      (let ((load-path (cons (expand-file-name ".") load-path)))
Michael Kifer's avatar
Michael Kifer committed
316 317
	(or (featurep 'viper-init)
	    (load "viper-init.el" nil nil 'nosuffix))
Michael Kifer's avatar
Michael Kifer committed
318 319 320 321
	(or (featurep 'viper-cmd)
	    (load "viper-cmd.el" nil nil 'nosuffix))
	)))
;; end pacifier
Karl Heuer's avatar
Karl Heuer committed
322

Richard M. Stallman's avatar
Richard M. Stallman committed
323
(require 'viper-init)
324
(require 'viper-keym)
Richard M. Stallman's avatar
Richard M. Stallman committed
325

Michael Kifer's avatar
Michael Kifer committed
326
;; better be defined before Viper custom group.
Michael Kifer's avatar
Michael Kifer committed
327
(defvar viper-custom-file-name (convert-standard-filename "~/.viper")
Michael Kifer's avatar
Michael Kifer committed
328 329 330 331 332
  "Viper customisation file.
If set by the user, this must be done _before_ Viper is loaded in `~/.emacs'.")

(defgroup viper nil
  "Vi emulation within Emacs.
Michael Kifer's avatar
Michael Kifer committed
333
NOTE: Viper customization should be saved in `viper-custom-file-name', which
Michael Kifer's avatar
Michael Kifer committed
334
defaults to `~/.viper'."
Michael Kifer's avatar
Michael Kifer committed
335
  :prefix "viper-"
Michael Kifer's avatar
Michael Kifer committed
336 337
  :group 'emulations)

Michael Kifer's avatar
Michael Kifer committed
338
(require 'viper-cmd)
Karl Heuer's avatar
Karl Heuer committed
339

Michael Kifer's avatar
Michael Kifer committed
340 341 342 343 344 345
(defgroup viper-misc nil
  "Miscellaneous Viper customization."
  :prefix "viper-"
  :group 'viper)


Michael Kifer's avatar
Michael Kifer committed
346
(defcustom viper-always t
Michael Kifer's avatar
Michael Kifer committed
347 348 349
  "Non-nil means, arrange for vi-state to be a default when appropriate.
This is different from `viper-mode' variable in that `viper-mode' determines
whether to use Viper in the first place, while `viper-always', if nil, lets
Michael Kifer's avatar
Michael Kifer committed
350 351 352
user decide when to invoke Viper in a major mode."
  :type 'boolean
  :tag "Always Invoke Viper"
Michael Kifer's avatar
Michael Kifer committed
353
  :group 'viper-misc)
Michael Kifer's avatar
Michael Kifer committed
354 355 356 357

;; Non-viper variables that need to be saved in case the user decides to
;; de-viperize emacs.
(defvar viper-saved-non-viper-variables nil)
358

Michael Kifer's avatar
Michael Kifer committed
359 360 361
(defcustom viper-mode (cond (noninteractive nil)
			    (t 'ask))
  "To Viperize or not to Viperize.
Michael Kifer's avatar
Michael Kifer committed
362
If t, viperize emacs.  If nil -- don't.  If `ask', ask the user.
Michael Kifer's avatar
Michael Kifer committed
363
This variable is used primatily when Viper is being loaded.
Karl Heuer's avatar
Karl Heuer committed
364

Michael Kifer's avatar
Michael Kifer committed
365
Must be set in `~/.emacs' before Viper is loaded.
Michael Kifer's avatar
Michael Kifer committed
366 367
DO NOT set this variable interactively, unless you are using the customization
widget."
Michael Kifer's avatar
Michael Kifer committed
368 369
  :type '(choice (const nil) (const t) (const ask))
  :tag "Set Viper Mode on Loading"
Michael Kifer's avatar
Michael Kifer committed
370
  :group 'viper-misc)
Michael Kifer's avatar
Michael Kifer committed
371

Michael Kifer's avatar
Michael Kifer committed
372 373 374
(defcustom viper-vi-state-mode-list
  '(fundamental-mode
    makefile-mode
375

Michael Kifer's avatar
Michael Kifer committed
376 377
    awk-mode
    m4-mode
Michael Kifer's avatar
Michael Kifer committed
378 379 380 381
    xrdb-mode
    winmgr-mode
    autoconf-mode
    cvs-edit-mode
382

Michael Kifer's avatar
Michael Kifer committed
383 384
    html-mode html-helper-mode
    emacs-lisp-mode lisp-mode lisp-interaction-mode
385 386

    jde-mode java-mode
Michael Kifer's avatar
Michael Kifer committed
387
    cc-mode c-mode c++-mode objc-mode
Michael Kifer's avatar
Michael Kifer committed
388 389 390 391 392
    fortran-mode f90-mode
    basic-mode
    bat-mode
    asm-mode
    prolog-mode
Michael Kifer's avatar
Michael Kifer committed
393
    flora-mode
394
    sql-mode
Michael Kifer's avatar
Michael Kifer committed
395 396 397

    text-mode indented-text-mode
    tex-mode latex-mode bibtex-mode
398
    ps-mode
399

400
    ;; completion-list-mode
401
    diff-mode
402
    idl-mode
403

404 405
    perl-mode
    cperl-mode
Michael Kifer's avatar
Michael Kifer committed
406 407 408
    javascript-mode
    tcl-mode
    python-mode
409

Michael Kifer's avatar
Michael Kifer committed
410
    sh-mode ksh-mode csh-mode
411

Michael Kifer's avatar
Michael Kifer committed
412 413 414 415
    gnus-article-mode
    mh-show-mode
    )
  "Major modes that require Vi command state."
416
  :type '(repeat symbol)
Michael Kifer's avatar
Michael Kifer committed
417
  :group 'viper-misc)
Michael Kifer's avatar
Michael Kifer committed
418

Michael Kifer's avatar
Michael Kifer committed
419 420 421 422 423 424 425
(defcustom viper-emacs-state-mode-list
  '(custom-mode

    dired-mode
    efs-mode
    tar-mode

426 427
    browse-kill-ring-mode
    recentf-mode
428
    recentf-dialog-mode
429 430
    occur-mode

Michael Kifer's avatar
Michael Kifer committed
431 432 433
    mh-folder-mode
    gnus-group-mode
    gnus-summary-mode
434

435 436 437
    completion-list-mode
    help-mode

Michael Kifer's avatar
Michael Kifer committed
438 439
    Info-mode
    Buffer-menu-mode
Michael Kifer's avatar
Michael Kifer committed
440
    compilation-mode
441

442 443
    rcirc-mode

444 445
    jde-javadoc-checker-report-mode

Michael Kifer's avatar
Michael Kifer committed
446 447 448 449 450 451
    view-mode
    vm-mode
    vm-summary-mode)
  "*A list of major modes that should come up in Emacs state.
Normally, Viper would bring buffers up in Emacs state, unless the corresponding
major mode has been placed on `viper-vi-state-mode-list' or
Michael Kifer's avatar
Michael Kifer committed
452 453
`viper-insert-state-mode-list'.  So, don't place a new mode on this list,
unless it is coming up in a wrong Viper state."
Michael Kifer's avatar
Michael Kifer committed
454 455 456 457
  :type '(repeat symbol)
  :group 'viper-misc)

(defcustom viper-insert-state-mode-list
458 459
  '(internal-ange-ftp-mode
    comint-mode
460
    inferior-emacs-lisp-mode
461
    erc-mode
462 463
    eshell-mode
    shell-mode)
Michael Kifer's avatar
Michael Kifer committed
464 465 466 467 468 469 470 471 472
  "*A list of major modes that should come up in Vi Insert state."
  :type '(repeat symbol)
  :group 'viper-misc)


;; used to set viper-major-mode-modifier-list in defcustom
(defun viper-apply-major-mode-modifiers (&optional symbol value)
  (if symbol
      (set symbol value))
Michael Kifer's avatar
Michael Kifer committed
473 474 475
  (mapcar (lambda (triple)
	    (viper-modify-major-mode
	     (nth 0 triple) (nth 1 triple) (eval (nth 2 triple))))
Michael Kifer's avatar
Michael Kifer committed
476 477
	  viper-major-mode-modifier-list))

478
;; We change standard bindings in some major modes, making them slightly
479
;; different than in "normal" vi/insert/emacs states
Michael Kifer's avatar
Michael Kifer committed
480 481 482 483 484
(defcustom viper-major-mode-modifier-list
  '((help-mode emacs-state viper-slash-and-colon-map)
    (comint-mode insert-state viper-comint-mode-modifier-map)
    (comint-mode vi-state viper-comint-mode-modifier-map)
    (shell-mode insert-state viper-comint-mode-modifier-map)
485
    (inferior-emacs-lisp-mode insert-state viper-comint-mode-modifier-map)
Michael Kifer's avatar
Michael Kifer committed
486 487 488 489 490 491 492 493
    (shell-mode vi-state viper-comint-mode-modifier-map)
    (ange-ftp-shell-mode insert-state viper-comint-mode-modifier-map)
    (ange-ftp-shell-mode vi-state viper-comint-mode-modifier-map)
    (internal-ange-ftp-mode insert-state viper-comint-mode-modifier-map)
    (internal-ange-ftp-mode vi-state viper-comint-mode-modifier-map)
    (dired-mode emacs-state viper-dired-modifier-map)
    (tar-mode emacs-state viper-slash-and-colon-map)
    (mh-folder-mode emacs-state viper-slash-and-colon-map)
494 495
    (gnus-group-mode emacs-state viper-gnus-modifier-map)
    (gnus-summary-mode emacs-state viper-gnus-modifier-map)
Michael Kifer's avatar
Michael Kifer committed
496 497
    (Info-mode emacs-state viper-slash-and-colon-map)
    (Buffer-menu-mode emacs-state viper-slash-and-colon-map)
498 499
    (erc-mode insert-state viper-comint-mode-modifier-map)
    (erc-mode vi-state viper-comint-mode-modifier-map)
Michael Kifer's avatar
Michael Kifer committed
500 501 502
    )
  "List specifying how to modify the various major modes to enable some Viperisms.
The list has the structure: ((mode viper-state keymap) (mode viper-state
Michael Kifer's avatar
Michael Kifer committed
503 504
keymap) ...).  If `mode' is on the list, the `kemap' will be made active (on
the minor-mode-map-alist) in the specified viper state.
Michael Kifer's avatar
Michael Kifer committed
505 506 507
If you change this list, have to restart emacs for the change to take effect.
However, if you did the change through the customization widget, then emacs
needs to be restarted only if you deleted a triple mode-state-keymap from the
Michael Kifer's avatar
Michael Kifer committed
508
list.  No need to restart emacs in case of insertion or modification of an
Michael Kifer's avatar
Michael Kifer committed
509 510 511 512 513 514 515 516 517 518 519
existing triple."
  :type '(repeat
	  (list symbol
		(choice (const emacs-state)
			(const vi-state)
			(const insert-state))
		symbol))
  :set 'viper-apply-major-mode-modifiers
  :group 'viper-misc)


Michael Kifer's avatar
Michael Kifer committed
520

Michael Kifer's avatar
Michael Kifer committed
521

Michael Kifer's avatar
Michael Kifer committed
522

Michael Kifer's avatar
Michael Kifer committed
523
;;;###autoload
Michael Kifer's avatar
Michael Kifer committed
524
(defun toggle-viper-mode ()
Michael Kifer's avatar
Michael Kifer committed
525
  "Toggle Viper on/off.
Michael Kifer's avatar
Michael Kifer committed
526
If Viper is enabled, turn it off.  Otherwise, turn it on."
Michael Kifer's avatar
Michael Kifer committed
527 528 529 530 531
  (interactive)
  (if (eq viper-mode t)
      (viper-go-away)
    (setq viper-mode nil)
    (viper-mode)))
Karl Heuer's avatar
Karl Heuer committed
532

Michael Kifer's avatar
Michael Kifer committed
533 534
;;;###autoload
(defun viper-mode ()
535
  "Turn on Viper emulation of Vi in Emacs. See Info node `(viper)Viper'."
Michael Kifer's avatar
Michael Kifer committed
536 537 538 539 540 541
  (interactive)
  (if (not noninteractive)
      (progn
	;; if the user requested viper-mode explicitly
	(if viper-mode
	    ()
Michael Kifer's avatar
Michael Kifer committed
542
	  (setq viper-mode t)
Michael Kifer's avatar
Michael Kifer committed
543 544
	  (load-library "viper"))

545
	(if viper-first-time ; Important check.  Prevents mix-up of startup
Michael Kifer's avatar
Michael Kifer committed
546
	    (progn	     ; and expert-level msgs when viper-mode recurses
Michael Kifer's avatar
Michael Kifer committed
547 548
	      (setq viper-first-time nil)
	      (if (not viper-inhibit-startup-message)
Michael Kifer's avatar
Michael Kifer committed
549
		  (save-window-excursion
Michael Kifer's avatar
Michael Kifer committed
550
		    (setq viper-inhibit-startup-message t)
Michael Kifer's avatar
Michael Kifer committed
551 552 553 554 555
		    (delete-other-windows)
		    (switch-to-buffer "Viper Startup Message")
		    (erase-buffer)
		    (insert
		     (substitute-command-keys
Michael Kifer's avatar
Michael Kifer committed
556 557
		      "Viper Is a Package for Emacs Rebels,
a VI Plan for Emacs Rescue, and a venomous VI PERil.
Michael Kifer's avatar
Michael Kifer committed
558

Michael Kifer's avatar
Michael Kifer committed
559 560
Incidentally, Viper emulates Vi under GNU Emacs 20 and XEmacs 20.
It supports all of what is good in Vi and Ex, while extending
Michael Kifer's avatar
Michael Kifer committed
561 562
and improving upon much of it.

Michael Kifer's avatar
Michael Kifer committed
563
   1. Viper supports Vi at several levels.  Level 1 is the closest to Vi,
Michael Kifer's avatar
Michael Kifer committed
564
      level 5 provides the most flexibility to depart from many Vi conventions.
565

Michael Kifer's avatar
Michael Kifer committed
566
      You will be asked to specify your user level in a following screen.
567

Michael Kifer's avatar
Michael Kifer committed
568
      If you select user level 1 then the keys ^X, ^C, ^Z, and ^G will behave
Michael Kifer's avatar
Michael Kifer committed
569
      as in VI, to smooth transition to Viper for the beginners.  However, to
570 571
      use Emacs productively, you are advised to reach user level 3 or higher.

Michael Kifer's avatar
Michael Kifer committed
572 573
      At user level 2 or higher, ^X and ^C have Emacs, not Vi, bindings;
      ^Z toggles Vi/Emacs states; ^G is Emacs' keyboard-quit (like ^C in Vi).
574

Michael Kifer's avatar
Michael Kifer committed
575
   2. Vi exit functions (e.g., :wq, ZZ) work on INDIVIDUAL files -- they
Michael Kifer's avatar
Michael Kifer committed
576
      do not cause Emacs to quit, except at user level 1 (for a novice).
Michael Kifer's avatar
Michael Kifer committed
577
   3. ^X^C EXITS EMACS.
Michael Kifer's avatar
Michael Kifer committed
578 579
   4. Viper supports multiple undo: `u' will undo.  Typing `.' will repeat
      undo.  Another `u' changes direction.
580

Michael Kifer's avatar
Michael Kifer committed
581 582
   6. Emacs Meta key is `C-\\' (in all modes) or `\\ ESC' (in Vi command mode).
      On a window system, the best way is to use the Meta-key on your keyboard.
Michael Kifer's avatar
Michael Kifer committed
583
   7. Try \\[keyboard-quit] and \\[abort-recursive-edit] repeatedly,if
584 585
      something funny happens.  This would abort the current editing command.

Michael Kifer's avatar
Michael Kifer committed
586
For more information on Viper:
Michael Kifer's avatar
Michael Kifer committed
587

Michael Kifer's avatar
Michael Kifer committed
588 589 590 591 592
   a. Type `:help' in Vi command mode
   b. Print Viper manual, found in ./etc/viper.dvi
   c. Print the Quick Reference, found in ./etc/viperCard.dvi

To submit a bug report or to contact the author, type :submitReport in Vi
Michael Kifer's avatar
Michael Kifer committed
593
command mode.  To shoo Viper away and return to pure Emacs (horror!), type:
Michael Kifer's avatar
Michael Kifer committed
594 595

   M-x viper-go-away
596

Michael Kifer's avatar
Michael Kifer committed
597 598 599 600
This startup message appears whenever you load Viper, unless you type `y' now."
		      ))
		    (goto-char (point-min))
		    (if (y-or-n-p "Inhibit Viper startup message? ")
Michael Kifer's avatar
Michael Kifer committed
601 602
			(viper-save-setting
			 'viper-inhibit-startup-message
Michael Kifer's avatar
Michael Kifer committed
603
			 "Viper startup message inhibited"
Michael Kifer's avatar
Michael Kifer committed
604
			 viper-custom-file-name t))
Michael Kifer's avatar
Michael Kifer committed
605 606 607 608 609
		    ;;(kill-buffer (current-buffer))
		    (message
		     "The last message is in buffer `Viper Startup Message'")
		    (sit-for 4)
		    ))
Michael Kifer's avatar
Michael Kifer committed
610
	      (viper-set-expert-level 'dont-change-unless)))
Michael Kifer's avatar
Michael Kifer committed
611

612 613
	(if (eq major-mode 'viper-mode)
	    (setq major-mode 'fundamental-mode))
614

Michael Kifer's avatar
Michael Kifer committed
615 616
	(or (memq major-mode viper-emacs-state-mode-list) ; don't switch to Vi
	    (memq major-mode viper-insert-state-mode-list) ; don't switch
617 618
	    (viper-change-state-to-vi))
	)))
619

620 621 622 623 624 625 626 627 628 629

;; Apply a little heuristic to invoke vi state on major-modes
;; that are not listed in viper-vi-state-mode-list
(defun this-major-mode-requires-vi-state (mode)
  (cond ((memq mode viper-vi-state-mode-list) t)
	((memq mode viper-emacs-state-mode-list) nil)
	((memq mode viper-insert-state-mode-list) nil)
	(t (and (eq (key-binding "a") 'self-insert-command)
		(eq (key-binding " ") 'self-insert-command)))))

Karl Heuer's avatar
Karl Heuer committed
630

631
;; This hook designed to enable Vi-style editing in comint-based modes."
Michael Kifer's avatar
Michael Kifer committed
632
(defun viper-comint-mode-hook ()
633 634
  (set (make-local-variable 'require-final-newline) nil)
  (setq viper-ex-style-editing nil
Michael Kifer's avatar
Michael Kifer committed
635 636
	viper-ex-style-motion nil)
  (viper-change-state-to-insert))
Michael Kifer's avatar
Michael Kifer committed
637

Karl Heuer's avatar
Karl Heuer committed
638

Michael Kifer's avatar
Michael Kifer committed
639 640 641 642 643 644
;; remove viper hooks from SYMBOL
(defun viper-remove-hooks (symbol)
  (cond ((not (boundp symbol)) nil)
	((not (listp (eval symbol))) nil)
	((string-match "-hook" (symbol-name symbol))
	 (remove-hook symbol 'viper-mode)
Michael Kifer's avatar
Michael Kifer committed
645 646 647
	 (remove-hook symbol 'viper-change-state-to-emacs)
	 (remove-hook symbol 'viper-change-state-to-insert)
	 (remove-hook symbol 'viper-change-state-to-vi)
Michael Kifer's avatar
Michael Kifer committed
648 649 650 651 652
	 )))

;; Remove local value in all existing buffers
;; This doesn't delocalize vars (which would have been desirable)
(defun viper-delocalize-var (symbol)
Michael Kifer's avatar
Michael Kifer committed
653 654 655
  (mapcar (lambda (buf) (save-excursion
			  (set-buffer buf)
			  (kill-local-variable symbol)))
Michael Kifer's avatar
Michael Kifer committed
656 657 658 659 660
	  (buffer-list)))


(defun viper-go-away ()
  "De-Viperize Emacs.
Michael Kifer's avatar
Michael Kifer committed
661 662
This function tries to do as good a job as possible.  However, it may undo some
user customization, unrelated to Viper.  For instance, if the user advised
Michael Kifer's avatar
Michael Kifer committed
663 664
`read-file-name', `describe-key', and some others, then this advice will be
undone.
665
It also can't undo some Viper settings."
Michael Kifer's avatar
Michael Kifer committed
666 667 668 669 670
  (interactive)

  ;; restore non-viper vars
  (setq-default
   next-line-add-newlines
671 672
   (viper-standard-value
    'next-line-add-newlines viper-saved-non-viper-variables)
Michael Kifer's avatar
Michael Kifer committed
673
   require-final-newline
674 675
   (viper-standard-value
    'require-final-newline viper-saved-non-viper-variables)
Michael Kifer's avatar
Michael Kifer committed
676
   scroll-step
677
   (viper-standard-value 'scroll-step viper-saved-non-viper-variables)
Michael Kifer's avatar
Michael Kifer committed
678 679
   mode-line-buffer-identification
   (viper-standard-value
Michael Kifer's avatar
Michael Kifer committed
680 681
    'mode-line-buffer-identification viper-saved-non-viper-variables)
   global-mode-string
Michael Kifer's avatar
Michael Kifer committed
682
   (delq 'viper-mode-string global-mode-string))
Michael Kifer's avatar
Michael Kifer committed
683

Michael Kifer's avatar
Michael Kifer committed
684
  (if viper-emacs-p
Michael Kifer's avatar
Michael Kifer committed
685 686 687 688
      (setq-default
       mark-even-if-inactive
       (viper-standard-value
	'mark-even-if-inactive viper-saved-non-viper-variables)))
Michael Kifer's avatar
Michael Kifer committed
689

690
  ;; Ideally, we would like to be able to de-localize local variables
691 692 693
  (unless
      (and (fboundp 'add-to-ordered-list) (boundp 'emulation-mode-map-alists))
    (viper-delocalize-var 'minor-mode-map-alist))
Michael Kifer's avatar
Michael Kifer committed
694
  (viper-delocalize-var 'require-final-newline)
695
  (if viper-xemacs-p (viper-delocalize-var 'bar-cursor))
Michael Kifer's avatar
Michael Kifer committed
696

697

Michael Kifer's avatar
Michael Kifer committed
698
  ;; deactivate all advices done by Viper.
Michael Kifer's avatar
Michael Kifer committed
699
  (ad-deactivate-regexp "viper-")
Michael Kifer's avatar
Michael Kifer committed
700 701 702

  (setq viper-mode nil)

703 704 705 706 707 708
  (when (and (fboundp 'add-to-ordered-list) (boundp 'emulation-mode-map-alists))
    (setq emulation-mode-map-alists
	  (delq 'viper--intercept-key-maps
		(delq 'viper--key-maps emulation-mode-map-alists))
	  ))

Michael Kifer's avatar
Michael Kifer committed
709 710 711 712
  (viper-delocalize-var 'viper-vi-minibuffer-minor-mode)
  (viper-delocalize-var 'viper-insert-minibuffer-minor-mode)
  (viper-delocalize-var 'viper-vi-intercept-minor-mode)
  (viper-delocalize-var 'viper-insert-intercept-minor-mode)
713

Michael Kifer's avatar
Michael Kifer committed
714 715 716 717 718 719
  (viper-delocalize-var 'viper-vi-local-user-minor-mode)
  (viper-delocalize-var 'viper-vi-kbd-minor-mode)
  (viper-delocalize-var 'viper-vi-global-user-minor-mode)
  (viper-delocalize-var 'viper-vi-state-modifier-minor-mode)
  (viper-delocalize-var 'viper-vi-diehard-minor-mode)
  (viper-delocalize-var 'viper-vi-basic-minor-mode)
720

Michael Kifer's avatar
Michael Kifer committed
721
  (viper-delocalize-var 'viper-replace-minor-mode)
722

Michael Kifer's avatar
Michael Kifer committed
723 724 725 726 727 728
  (viper-delocalize-var 'viper-insert-local-user-minor-mode)
  (viper-delocalize-var 'viper-insert-kbd-minor-mode)
  (viper-delocalize-var 'viper-insert-global-user-minor-mode)
  (viper-delocalize-var 'viper-insert-state-modifier-minor-mode)
  (viper-delocalize-var 'viper-insert-diehard-minor-mode)
  (viper-delocalize-var 'viper-insert-basic-minor-mode)
729

Michael Kifer's avatar
Michael Kifer committed
730 731 732 733 734 735
  (viper-delocalize-var 'viper-emacs-intercept-minor-mode)
  (viper-delocalize-var 'viper-emacs-local-user-minor-mode)
  (viper-delocalize-var 'viper-emacs-kbd-minor-mode)
  (viper-delocalize-var 'viper-emacs-global-user-minor-mode)
  (viper-delocalize-var 'viper-emacs-state-modifier-minor-mode)

Michael Kifer's avatar
Michael Kifer committed
736 737 738
  (viper-delocalize-var 'viper-current-state)
  (viper-delocalize-var 'viper-mode-string)

Michael Kifer's avatar
Michael Kifer committed
739 740 741 742
  (setq-default viper-vi-minibuffer-minor-mode	       nil
		viper-insert-minibuffer-minor-mode     nil
		viper-vi-intercept-minor-mode	       nil
		viper-insert-intercept-minor-mode      nil
743

Michael Kifer's avatar
Michael Kifer committed
744 745 746 747 748 749
		viper-vi-local-user-minor-mode         nil
		viper-vi-kbd-minor-mode        	       nil
		viper-vi-global-user-minor-mode        nil
		viper-vi-state-modifier-minor-mode     nil
		viper-vi-diehard-minor-mode            nil
		viper-vi-basic-minor-mode              nil
750

Michael Kifer's avatar
Michael Kifer committed
751
		viper-replace-minor-mode 	       nil
752

Michael Kifer's avatar
Michael Kifer committed
753 754 755 756 757 758 759 760 761 762 763 764
		viper-insert-local-user-minor-mode     nil
		viper-insert-kbd-minor-mode            nil
		viper-insert-global-user-minor-mode    nil
		viper-insert-state-modifier-minor-mode nil
		viper-insert-diehard-minor-mode        nil
		viper-insert-basic-minor-mode          nil

		viper-emacs-intercept-minor-mode       nil
		viper-emacs-local-user-minor-mode      nil
		viper-emacs-kbd-minor-mode             nil
		viper-emacs-global-user-minor-mode     nil
		viper-emacs-state-modifier-minor-mode  nil
Michael Kifer's avatar
Michael Kifer committed
765 766 767

		viper-current-state		       'emacs-state
		viper-mode-string		       viper-emacs-state-id
Michael Kifer's avatar
Michael Kifer committed
768 769 770 771
		)

  ;; remove all hooks set by viper
  (mapatoms 'viper-remove-hooks)
Michael Kifer's avatar
Michael Kifer committed
772
  (remove-hook 'comint-mode-hook 'viper-comint-mode-hook)
773
  (remove-hook 'erc-mode-hook 'viper-comint-mode-hook)
Michael Kifer's avatar
Michael Kifer committed
774
  (remove-hook 'minibuffer-setup-hook 'viper-minibuffer-setup-sentinel)
Michael Kifer's avatar
Michael Kifer committed
775
  (remove-hook 'change-major-mode-hook 'viper-major-mode-change-sentinel)
776
  (remove-hook 'post-command-hook 'viper-minibuffer-post-command-hook)
Michael Kifer's avatar
Michael Kifer committed
777 778 779 780

  ;; unbind Viper mouse bindings
  (viper-unbind-mouse-search-key)
  (viper-unbind-mouse-insert-key)
Michael Kifer's avatar
Michael Kifer committed
781 782 783 784 785 786
  ;; In emacs, we have to advice handle-switch-frame
  ;; This advice is undone earlier, when all advices matchine "viper-" are
  ;; deactivated.
  (if viper-xemacs-p
      (remove-hook 'mouse-leave-frame-hook 'viper-remember-current-frame))
  ) ; end viper-go-away
Michael Kifer's avatar
Michael Kifer committed
787 788


Michael Kifer's avatar
Michael Kifer committed
789 790 791 792 793 794 795
;; list of buffers that just changed their major mode
;; used in a hack that triggers vi command mode whenever needed
(defvar viper-new-major-mode-buffer-list nil)

;; set appropriate Viper state in buffers that changed major mode
(defun set-viper-state-in-major-mode ()
  (mapcar
Michael Kifer's avatar
Michael Kifer committed
796 797 798
   (lambda (buf)
     (if (viper-buffer-live-p buf)
	 (with-current-buffer buf
799
	   (cond ((and (this-major-mode-requires-vi-state major-mode)
Michael Kifer's avatar
Michael Kifer committed
800 801 802 803 804 805 806 807 808 809 810 811 812
		       (eq viper-current-state 'emacs-state))
		  (viper-mode))
		 ((memq major-mode viper-emacs-state-mode-list)
		  ;; not checking (eq viper-current-state 'emacs-state)
		  ;; because viper-current-state could have gotten it by
		  ;; default.  We need viper-change-state-to-emacs here to have
		  ;; the keymaps take effect.
		  (viper-change-state-to-emacs))
		 ((and (memq major-mode viper-insert-state-mode-list)
		       (not (eq viper-current-state 'insert-state)))
		  (viper-change-state-to-insert))
		 )) ; with-current-buffer
       )) ; function
Michael Kifer's avatar
Michael Kifer committed
813 814 815 816 817 818 819 820 821 822 823
   viper-new-major-mode-buffer-list)
  ;; clear the list of bufs that changed major mode
  (setq viper-new-major-mode-buffer-list nil)
  ;; change the global value of hook
  (remove-hook 'viper-post-command-hooks 'set-viper-state-in-major-mode))

;; sets up post-command-hook to turn viper-mode, if the current mode is
;; fundamental
(defun viper-major-mode-change-sentinel ()
  (save-match-data
    (or (string-match "\*Minibuf-" (buffer-name))
824
	(setq viper-new-major-mode-buffer-list
Michael Kifer's avatar
Michael Kifer committed
825 826 827 828
	      (cons (current-buffer) viper-new-major-mode-buffer-list))))
  ;; change the global value of hook
  (add-hook 'viper-post-command-hooks 'set-viper-state-in-major-mode t))

Michael Kifer's avatar
Michael Kifer committed
829 830


831
;; This sets major mode hooks to make them come up in vi-state.
Michael Kifer's avatar
Michael Kifer committed
832
(defun viper-set-hooks ()
Karl Heuer's avatar
Karl Heuer committed
833 834 835 836
  ;; It is of course a misnomer to call viper-mode a `major mode'.
  ;; However, this has the effect that if the user didn't specify the
  ;; default mode, new buffers that fall back on the default will come up
  ;; in Fundamental Mode and Vi state.
837 838
  ;; When viper-mode is executed in such a case, it will set the major mode
  ;; back to fundamental-mode.
Michael Kifer's avatar
Michael Kifer committed
839 840
  (if (eq default-major-mode 'fundamental-mode)
      (setq default-major-mode 'viper-mode))
841

Michael Kifer's avatar
Michael Kifer committed
842 843
  (add-hook 'change-major-mode-hook 'viper-major-mode-change-sentinel)
  (add-hook 'find-file-hooks 'set-viper-state-in-major-mode)
Michael Kifer's avatar
Michael Kifer committed
844

Michael Kifer's avatar
Michael Kifer committed
845
  ;; keep this because many modes we don't know about use this hook
Michael Kifer's avatar
Michael Kifer committed
846
  (defvar text-mode-hook)
Karl Heuer's avatar
Karl Heuer committed
847
  (add-hook 'text-mode-hook 'viper-mode)
848

Michael Kifer's avatar
Michael Kifer committed
849
  (defvar emerge-startup-hook)
Michael Kifer's avatar
Michael Kifer committed
850
  (add-hook 'emerge-startup-hook 'viper-change-state-to-emacs)
Michael Kifer's avatar
Michael Kifer committed
851

852 853 854 855 856 857
  ;; Zap bad bindings in flyspell-mouse-map, which prevent ESC from working
  ;; over misspelled words (due to the overlay keymaps)
  (defvar flyspell-mode-hook)
  (add-hook 'flyspell-mode-hook
	    '(lambda ()
	       (define-key flyspell-mouse-map viper-ESC-key nil)))
858 859 860 861
  ;; if viper is started from .emacs, it might be impossible to get certain
  ;; info about the display and windows until emacs initialization is complete
  ;; So do it via the window-setup-hook
  (add-hook 'window-setup-hook
862 863 864 865 866
  	    '(lambda ()
	       (modify-frame-parameters
		(selected-frame)
		(list (cons 'viper-vi-state-cursor-color
			    (viper-get-cursor-color))))))
867

Michael Kifer's avatar
Michael Kifer committed
868 869
  ;; Tell vc-diff to put *vc* in Vi mode
  (if (featurep 'vc)
Michael Kifer's avatar
Michael Kifer committed
870
      (defadvice vc-diff (after viper-vc-ad activate)
Michael Kifer's avatar
Michael Kifer committed
871
	"Force Vi state in VC diff buffer."
Michael Kifer's avatar
Michael Kifer committed
872 873
	(viper-change-state-to-vi))
    (eval-after-load
Michael Kifer's avatar
Michael Kifer committed
874
     "vc"
Michael Kifer's avatar
Michael Kifer committed
875
     '(defadvice vc-diff (after viper-vc-ad activate)
Michael Kifer's avatar
Michael Kifer committed
876
	"Force Vi state in VC diff buffer."
Michael Kifer's avatar
Michael Kifer committed
877
	(viper-change-state-to-vi))))
878

Michael Kifer's avatar
Michael Kifer committed
879
  (eval-after-load
880
   "emerge"
Michael Kifer's avatar
Michael Kifer committed
881 882 883
   '(defadvice emerge-quit (after viper-emerge-advice activate)
      "Run `viper-change-state-to-vi' after quitting emerge."
      (viper-change-state-to-vi)))
Karl Heuer's avatar
Karl Heuer committed
884
  ;; In case Emerge was loaded before Viper.
Michael Kifer's avatar
Michael Kifer committed
885 886 887
  (defadvice emerge-quit (after viper-emerge-advice activate)
    "Run `viper-change-state-to-vi' after quitting emerge."
    (viper-change-state-to-vi))