Update FSF's address.
[bpt/emacs.git] / lisp / emulation / viper.el
CommitLineData
be010748 1;;; viper.el --- A full-featured Vi emulator.
6c2e12f4
KH
2;; a VI Plan for Emacs Rescue,
3;; and a venomous VI PERil.
4;; Viper Is also a Package for Emacs Rebels.
b578f267
EN
5
6;; Copyright (C) 1994, 1995 Free Software Foundation, Inc.
7
6c2e12f4
KH
8;; Keywords: emulations
9;; Author: Michael Kifer <kifer@cs.sunysb.edu>
10
04090c34 11(defconst viper-version "2.82 of October 12, 1995"
27571f90
MK
12 "The current version of Viper")
13
6c2e12f4
KH
14;; This file is part of GNU Emacs.
15
16;; GNU Emacs is free software; you can redistribute it and/or modify
17;; it under the terms of the GNU General Public License as published by
18;; the Free Software Foundation; either version 2, or (at your option)
19;; any later version.
20
21;; GNU Emacs is distributed in the hope that it will be useful,
22;; but WITHOUT ANY WARRANTY; without even the implied warranty of
23;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24;; GNU General Public License for more details.
25
26;; You should have received a copy of the GNU General Public License
b578f267
EN
27;; along with GNU Emacs; see the file COPYING. If not, write to the
28;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
29;; Boston, MA 02111-1307, USA.
6c2e12f4
KH
30
31;;; Commentary:
32
33;; Viper is a full-featured Vi emulator for Emacs 19. It emulates and
34;; improves upon the standard features of Vi and, at the same time, allows
35;; full access to all Emacs facilities. Viper supports multiple undo,
36;; file name completion, command, file, and search history and it extends
37;; Vi in many other ways. Viper is highly customizable through the various
38;; hooks, user variables, and keymaps. It is implemented as a collection
39;; of minor modes and it is designed to provide full access to all Emacs
40;; major and minor modes.
41;;
42;;; History
43;;
44;; Viper is a new name for a package formerly known as VIP-19,
45;; which was a successor of VIP version 3.5 by Masahiko Sato
46;; <ms@sail.stanford.edu> and VIP version 4.2 by Aamod Sane
47;; <sane@cs.uiuc.edu>. Some ideas from vip 4.4.2 by Aamod Sane
48;; were also shamelessly plagiarized.
49;;
50;; Viper maintains some degree of compatibility with these older
51;; packages. See the documentation for customization.
52;;
53;; The main difference between Viper and these older packages are:
54;;
55;; 1. Viper emulates Vi at several levels, from almost complete conformity
56;; to a rather loose Vi-compliance.
57;;
58;; 2. Viper provides full access to all major and minor modes of Emacs
59;; without the need to type extra keys.
60;; The older versions of VIP (and other Vi emulators) do not work with
61;; some major and minor modes.
62;;
63;; 3. Viper supports vi-style undo.
64;;
65;; 4. Viper fully emulates (and improves upon) vi's replacement mode.
66;;
67;; 5. Viper has a better interface to ex, including command, variable, and
68;; file name completion.
69;;
70;; 6. Viper uses native Emacs history and completion features; it doesn't
71;; rely on other packages (such as gmhist.el and completer.el) to provide
72;; these features.
73;;
74;; 7. Viper supports Vi-style editing in the minibuffer, by allowing the
75;; user to switch from Insert state to Vi state to Replace state, etc.
76;;
77;; 8. Viper keeps history of recently inserted pieces of text and recently
78;; executed Vi-style destructive commands, such as `i', `d', etc.
79;; These pieces of text can be inserted in later insertion commands;
80;; the previous destructive commands can be re-executed.
81;;
82;; 9. Viper has Vi-style keyboard macros, which enhances the similar
83;; facility in the original Vi.
84;; First, one can execute any Emacs command while defining a
85;; macro, not just the Vi commands. Second, macros are defined in a
86;; WYSYWYG mode, using an interface to Emacs' WYSIWYG style of defining
87;; macros. Third, in Viper, one can define macros that are specific to
88;; a given buffer, a given major mode, or macros defined for all buffers.
89;; The same macro name can have several different definitions:
90;; one global, several definitions for various major modes, and
91;; definitions for specific buffers.
92;; Bffer-specific definitions override mode-specific
93;; definitions, which, in turn, override global definitions.
94;;
95;;
96;;; Installation:
97;; -------------
98;;
99;; (require 'viper)
100;;
101
102;;; Acknowledgements:
103;; -----------------
104;; Bug reports and ideas contributed by the following users
27571f90
MK
105;; have helped improve Viper and the various versions of VIP.
106;; See the on-line manual for a complete list of contributors.
6c2e12f4
KH
107;;
108;;
109;;; Notes:
110;;
111;; 1. Major modes.
112;; In most cases, Viper handles major modes correctly, i.e., they come up
113;; in the right state (either vi-state or emacs-state). For instance, text
114;; files come up in vi-state, while, say, Dired appears in emacs-state by
115;; default.
116;; However, some modes do not appear in the right mode in the beginning,
117;; usually because they neglect to follow Emacs conventions (e.g., they don't
d695b318 118;; use kill-all-local-variables when they start). Some major modes
6c2e12f4
KH
119;; may fail to come up in emacs-state if they call hooks, such as
120;; text-hook, for no good reason.
121;;
122;; As an immediate solution, you can hit C-z to bring about the right mode.
123;; An interim solution is to add an appropriate hook to the mode like this:
124;;
125;; (add-hook 'your-favorite-mode 'viper-mode)
126;; or
127;; (add-hook 'your-favorite-mode 'vip-change-state-to-emacs)
128;;
129;; whichever applies. The right thing to do, however, is to complain to the
130;; author of the respective package. (Sometimes they also neglect to equip
131;; their modes with hooks, which is one more reason for complaining.)
132;;
133;; 2. Keymap handling
134;; Because Emacs 19 has an elegant mechanism for turning minor mode keymaps
135;; on and off, implementation of Viper has been greatly simplified. Viper
136;; has several minor modes.
137;;
138;; Viper's Vi state consists of seven minor modes:
139;;
140;; vip-vi-intercept-minor-mode
141;; vip-vi-local-user-minor-mode
142;; vip-vi-global-user-minor-mode
143;; vip-vi-kbd-minor-mode
144;; vip-vi-state-modifier-minor-mode
145;; vip-vi-diehard-minor-mode
146;; vip-vi-basic-minor-mode
147;;
148;; Bindings done to the keymap of the first mode overshadow those done to
149;; the second, which, in turn, overshadows those done to the third, etc.
150;;
151;; The last vip-vi-basic-minor-mode contains most of the usual Vi bindings
152;; in its edit mode. This mode provides access to all Emacs facilities.
153;; Novice users, however, may want to set their vip-expert-level to 1
154;; in their .vip file. This will enable vip-vi-diehard-minor-mode. This
155;; minor mode's bindings make Viper simulate the usual Vi very closely.
156;; For instance, C-c will not have its standard Emacs binding
157;; and so many of the goodies of Emacs are not available.
158;;
159;; An skilled user, should set vip-expert-level to at least 3. This will
160;; enable ;; C-c and many Emacs facilities will become available.
161;; In this case, vip-vi-diehard-minor-mode is inactive.
162;;
163;; Viper gurus should have at least
164;; (setq vip-expert-level 4)
165;; in their ~/.vip files. This will unsuppress all Emacs keys that are not
166;; essential for VI-style editing.
167;; Pick-and-choose users may want to put
168;; (setq vip-expert-level 5)
169;; in ~/.vip. Viper will then leave it up to the user to set the variables
170;; vip-want-* See vip-set-expert-level for details.
171;;
172;; The very first minor mode, vip-vi-intercept-minor-mode, is of no
173;; concern for the user. It is needed to bind Viper's vital keys, such as
174;; ESC and C-z.
175;;
176;; The second mode, vip-vi-local-user-minor-mode, usually has an
177;; empty keymap. However, the user can set bindings in this keymap, which
178;; will overshadow the corresponding bindings in the other two minor
179;; modes. This is useful, for example, for setting up ZZ in gnus,
180;; rmail, mh-e, etc., to send message instead of saving it in a file.
181;; Likewise, in Dired mode, you may want to bind ZN and ZP to commands
182;; that would visit the next or the previous file in the Dired buffer.
183;; Setting local keys is tricky, so don't do it directly. Instead, use
184;; vip-add-local-keys function (see its doc).
185;;
186;; The third minor mode, vip-vi-global-user-minor-mode, is also intended
187;; for the users but, unlike vip-vi-local-user-minor-mode, its key
188;; bindings are seen in all Viper buffers. This mode keys can be done
189;; with define-key command.
190;;
191;; The fourth minor mode, vip-vi-kbd-minor-mode, is used by keyboard
192;; macros. Users are NOT supposed to modify this keymap directly.
193;;
194;; The fifth mode, vip-vi-state-modifier-minor-mode, can be used to set
195;; key bindings that are visible in some major modes but not in others.
196;;
197;; Users are allowed to modify keymaps that belong to
198;; vip-vi-local-user-minor-mode, vip-vi-global-user-minor-mode,
199;; and vip-vi-state-modifier-minor-mode only.
200;;
201;; Viper's Insert state also has seven minor modes:
202;;
203;; vip-insert-intercept-minor-mode
204;; vip-insert-local-user-minor-mode
205;; vip-insert-global-user-minor-mode
206;; vip-insert-kbd-minor-mode
207;; vip-insert-state-modifier-minor-mode
208;; vip-insert-diehard-minor-mode
209;; vip-insert-basic-minor-mode
210;;
211;; As with VI's editing modes, the first mode, vip-insert-intercept-minor-mode
212;; is used to bind vital keys that are not to be changed by the user.
213;;
214;; The next mode, vip-insert-local-user-minor-mode, is used to customize
215;; bindings in the insert state of Viper. The third mode,
216;; vip-insert-global-user-minor-mode is like
217;; vip-insert-local-user-minor-mode, except that its bindings are seen in
218;; all Viper buffers. As with vip-vi-local-user-minor-mode, its bindings
219;; should be done via the function vip-add-local-keys. Bindings for
220;; vip-insert-global-user-minor-mode can be set with the define-key command.
221;;
222;; The next minor mode, vip-insert-kbd-minor-mode,
223;; is used for keyboard VI-style macros defined with :map!.
224;;
225;; The fifth minor mode, vip-insert-state-modifier-minor-mode, is like
226;; vip-vi-state-modifier-minor-mode, except that it is used in the Insert
227;; state; it can be used to modify keys in a mode-specific fashion.
228;;
229;; The minor mode vip-insert-diehard-minor-mode is in effect when
230;; the user wants a high degree of Vi compatibility (a bad idea, really!).
231;; The last minor mode, vip-insert-basic-minor-mode, is always in effect
232;; when Viper is in insert state. It binds a small number of keys needed for
233;; Viper's operation.
234;;
235;; Finally, Viper provides minor modes for overriding bindings set by Emacs
236;; modes when Viper is in Emacs state:
237;;
238;; vip-emacs-local-user-minor-mode
239;; vip-emacs-global-user-minor-mode
240;; vip-emacs-kbd-minor-mode
241;; vip-emacs-state-modifier-minor-mode
242;;
243;; These minor modes are in effect when Viper is in Emacs state. The keymap
244;; associated with vip-emacs-global-user-minor-mode,
245;; vip-emacs-global-user-map, overrides the global and local keymaps as
246;; well as the minor mode keymaps set by other modes. The keymap of
247;; vip-emacs-local-user-minor-mode, vip-emacs-local-user-map, overrides
248;; everything, but it is used on a per buffer basis.
249;; The keymap associated with vip-emacs-state-modifier-minor-mode
250;; overrides keys on a per-major-mode basis. The mode
251;; vip-emacs-kbd-minor-mode is used to define Vi-style macros in Emacs
252;; state.
253;;
254;; 3. There is also one minor mode that is used when Viper is in its
255;; replace-state (used for commands like cw, C, etc.). This mode is
256;; called
257;;
258;; vip-replace-minor-mode
259;;
260;; and its keymap is vip-replace-map. Replace minor mode is always
261;; used in conjunction with the minor modes for insert-state, and its
262;; keymap overshadows the keymaps for insert minor modes.
263;;
264;; 4. Defining buffer-local bindings in Vi and Insert modes.
265;; As mentioned before, sometimes, it is convenient to have
266;; buffer-specific of mode-specific key bindings in Vi and insert modes.
267;; Viper provides a special function, vip-add-local-keys, to do precisely
268;; this. For instance, is you need to add couple of mode-specific bindings
269;; to Insert mode, you can put
270;;
271;; (vip-add-local-keys 'insert-state '((key1 . func1) (key2 .func2)))
272;;
273;; somewhere in a hook of this major mode. If you put something like this
274;; in your own elisp function, this will define bindings specific to the
275;; buffer that was current at the time of the call to vip-add-local-keys.
276;; The only thing to make sure here is that the major mode of this buffer
277;; is written according to Emacs conventions, which includes a call to
278;; (kill-all-local-variables). See vip-add-local-keys for more details.
279;;
280;;
281;; TO DO (volunteers?):
282;;
283;; 1. Some of the code that is inherited from VIP-3.5 is rather
284;; convoluted. Instead of vip-command-argument, keymaps should bind the
285;; actual commands. E.g., "dw" should be bound to a generic command
286;; vip-delete that will delete things based on the value of
287;; last-command-char. This would greatly simplify the logic and the code.
288;;
289;; 2. Somebody should venture to write a customization package a la
290;; options.el that would allow the user to change values of variables
291;; that meet certain specs (e.g., match a regexp) and whose doc string
292;; starts with a '*'. Then, the user should be offered to save
293;; variables that were changed. This will make user's customization job
294;; much easier.
295;;
296
297
298(require 'advice)
299(require 'cl)
300(require 'ring)
301
302(require 'viper-util)
303
304\f
305;;; Variables
306
307;; Is t until viper-mode executes for the very first time.
308;; Prevents recursive descend into startup messages.
309(defvar vip-first-time t)
310
311(defvar vip-expert-level 0
312 "User's expert level.
313The minor mode vip-vi-diehard-minor-mode is in effect when
314vip-expert-level is 1 or 2 or when vip-want-emacs-keys-in-vi is t.
315The minor mode vip-insert-diehard-minor-mode is in effect when
316vip-expert-level is 1 or 2 or if vip-want-emacs-keys-in-insert is t.
317Use `M-x vip-set-expert-level' to change this.")
318
319;; Max expert level supported by Viper. This is NOT a user option.
320;; It is here to make it hard for the user from resetting it.
321(defconst vip-max-expert-level 5)
322
323;; Contains user settings for vars affected by vip-set-expert-level function.
324;; Not a user option.
325(defvar vip-saved-user-settings nil)
326
327
328;;; Viper minor modes
329
4af0c23b 330;; This is not local in Emacs, so we make it local.
6c2e12f4
KH
331(make-variable-buffer-local 'minor-mode-map-alist)
332
6c2e12f4
KH
333;; Mode for vital things like \e, C-z.
334(vip-deflocalvar vip-vi-intercept-minor-mode nil)
335
336(vip-deflocalvar vip-vi-basic-minor-mode nil
337 "Viper's minor mode for Vi bindings.")
338
339(vip-deflocalvar vip-vi-local-user-minor-mode nil
340 "Auxiliary minor mode for user-defined local bindings in Vi state.")
341
342(vip-deflocalvar vip-vi-global-user-minor-mode nil
343 "Auxiliary minor mode for user-defined global bindings in Vi state.")
344
345(vip-deflocalvar vip-vi-state-modifier-minor-mode nil
346 "Minor mode used to make major-mode-specific modification to Vi state.")
347
348(vip-deflocalvar vip-vi-diehard-minor-mode nil
349 "This minor mode is in effect when the user wants Viper to be Vi.")
350
351(vip-deflocalvar vip-vi-kbd-minor-mode nil
4af0c23b 352 "Minor mode for Ex command macros in Vi state.
6c2e12f4
KH
353The corresponding keymap stores key bindings of Vi macros defined with
354the Ex command :map.")
355
356;; Mode for vital things like \e, C-z.
357(vip-deflocalvar vip-insert-intercept-minor-mode nil)
358
359(vip-deflocalvar vip-insert-basic-minor-mode nil
360 "Viper's minor mode for bindings in Insert mode.")
361
362(vip-deflocalvar vip-insert-local-user-minor-mode nil
363 "Auxiliary minor mode for buffer-local user-defined bindings in Insert state.
364This is a way to overshadow normal Insert mode bindings locally to certain
365designated buffers.")
366
367(vip-deflocalvar vip-insert-global-user-minor-mode nil
368 "Auxiliary minor mode for global user-defined bindings in Insert state.")
369
370(vip-deflocalvar vip-insert-state-modifier-minor-mode nil
371 "Minor mode used to make major-mode-specific modification to Insert state.")
372
373(vip-deflocalvar vip-insert-diehard-minor-mode nil
374 "Minor mode that simulates Vi very closely.
05497fc6 375Not recommended, except for the novice user.")
6c2e12f4
KH
376
377(vip-deflocalvar vip-insert-kbd-minor-mode nil
378"Minor mode for Ex command macros Insert state.
379The corresponding keymap stores key bindings of Vi macros defined with
380the Ex command :map!.")
381
382(vip-deflocalvar vip-replace-minor-mode nil
383 "Minor mode in effect in replace state (cw, C, and the like commands).")
384
385;; Mode for vital things like \C-z and \C-x)
386;; This is t, by default. So, any new buffer will have C-z defined as
387;; switch to Vi, unless we switched states in this buffer
388(vip-deflocalvar vip-emacs-intercept-minor-mode t)
389
390(vip-deflocalvar vip-emacs-local-user-minor-mode t
391 "Minor mode for local user bindings effective in Emacs state.
392Users can use it to override Emacs bindings when Viper is in its Emacs
393state.")
394
395(vip-deflocalvar vip-emacs-global-user-minor-mode t
396 "Minor mode for global user bindings in effect in Emacs state.
397Users can use it to override Emacs bindings when Viper is in its Emacs
398state.")
399
400(vip-deflocalvar vip-emacs-kbd-minor-mode t
401 "Minor mode for Vi style macros in Emacs state.
402The corresponding keymap stores key bindings of Vi macros defined with
403`vip-record-kbd-macro' command. There is no Ex-level command to do this
404interactively.")
405
406(vip-deflocalvar vip-emacs-state-modifier-minor-mode t
407 "Minor mode used to make major-mode-specific modification to Emacs state.
408For instance, a Vi purist may want to bind `dd' in Dired mode to a function
409that deletes a file.")
410
411
412
413;;; ISO characters
414
04090c34 415(vip-deflocalvar vip-automatic-iso-accents nil
6c2e12f4
KH
416 "*If non-nil, ISO accents will be turned on in insert/replace emacs states and turned off in vi-state.
417For some users, this behavior may be too primitive. In this case, use
418insert/emacs/vi state hooks.")
419
420
421;;; Emacs keys in other states.
422
423(defvar vip-want-emacs-keys-in-insert t
424 "*Set to nil if you want complete Vi compatibility in insert mode.
425Complete compatibility with Vi is not recommended for power use of Viper.")
426
427(defvar vip-want-emacs-keys-in-vi t
428 "*Set to nil if you want complete Vi compatibility in Vi mode.
429Full Vi compatibility is not recommended for power use of Viper.")
430
431
432
433;; VI-style Undo
434
435;; Used to 'undo' complex commands, such as replace and insert commands.
436(vip-deflocalvar vip-undo-needs-adjustment nil)
437(put 'vip-undo-needs-adjustment 'permanent-local t)
438
439;; A mark that Viper puts on buffer-undo-list. Marks the beginning of a
440;; complex command that must be undone atomically. If inserted, it is
441;; erased by vip-change-state-to-vi and vip-repeat.
442(defconst vip-buffer-undo-list-mark 'viper)
443
444(defvar vip-keep-point-on-undo nil
445 "*Non-nil means not to move point while undoing commands.
446This style is different from Emacs and Vi. Try it to see if
447it better fits your working style.")
448
449;; Replace mode and changing text
450
27571f90
MK
451;; Viper's own after/before change functions, which get vip-add-hook'ed to
452;; Emacs's
6c2e12f4
KH
453(vip-deflocalvar vip-after-change-functions nil "")
454(vip-deflocalvar vip-before-change-functions nil "")
455(vip-deflocalvar vip-post-command-hooks nil "")
456(vip-deflocalvar vip-pre-command-hooks nil "")
457
458;; Can be used to pass global states around for short period of time
459(vip-deflocalvar vip-intermediate-command nil "")
460
461;; Indicates that the current destructive command has started in replace mode.
462(vip-deflocalvar vip-began-as-replace nil "")
463
464(defvar vip-replace-overlay-cursor-color "Red"
4af0c23b 465 "*Cursor color to use in Replace state")
6c2e12f4
KH
466
467
468(vip-deflocalvar vip-replace-overlay nil "")
469(put 'vip-replace-overlay 'permanent-local t)
470
4af0c23b 471(if (vip-window-display-p)
6c2e12f4 472 (progn
c968bd13 473 (add-to-list 'facemenu-unlisted-faces 'vip-replace-overlay-face)
6c2e12f4
KH
474 (make-face 'vip-replace-overlay-face)
475 (or (face-differs-from-default-p 'vip-replace-overlay-face)
476 (progn
477 (if (vip-can-use-colors "darkseagreen2" "Black")
478 (progn
479 (set-face-background
480 'vip-replace-overlay-face "darkseagreen2")
481 (set-face-foreground 'vip-replace-overlay-face "Black")))
482 (set-face-underline-p 'vip-replace-overlay-face t))
483 )))
484
485(defvar vip-replace-overlay-face 'vip-replace-overlay-face
486 "*Face for highlighting replace regions on a window display.")
487
4af0c23b
KH
488(defvar vip-replace-region-end-delimiter "$"
489 "A string marking the end of replacement regions.
490It is used only with TTYs or if `vip-use-replace-region-delimiters'
491is non-nil.")
492(defvar vip-replace-region-start-delimiter ""
493 "A string marking the beginning of replacement regions.
494It is used only with TTYs or if `vip-use-replace-region-delimiters'
495is non-nil.")
496(defvar vip-use-replace-region-delimiters
497 (or (not (vip-window-display-p)) (not (vip-color-display-p)))
498 "*If non-nil, Viper will always use `vip-replace-region-end-delimiter' and
499`vip-replace-region-start-delimiter' to delimit replacement regions, even on
500color displays. By default, the delimiters are used only on TTYs or
501monochrome displays.")
502
503;; XEmacs requires glyphs
504(if vip-xemacs-p
505 (progn
506 (or (glyphp vip-replace-region-end-delimiter)
507 (setq vip-replace-region-end-delimiter
508 (make-glyph vip-replace-region-end-delimiter)))
509 (or (glyphp vip-replace-region-start-delimiter)
510 (setq vip-replace-region-start-delimiter
511 (make-glyph vip-replace-region-start-delimiter)))
512 ))
513
6c2e12f4
KH
514
515;; These are local marker that must be initialized to nil and moved with
516;; `vip-move-marker-locally'
517;;
518;; Remember the last position inside the replace region.
519(vip-deflocalvar vip-last-posn-in-replace-region nil)
520;; Remember the last position while inserting
521(vip-deflocalvar vip-last-posn-while-in-insert-state nil)
522(put 'vip-last-posn-in-replace-region 'permanent-local t)
523(put 'vip-last-posn-while-in-insert-state 'permanent-local t)
524
525(vip-deflocalvar vip-sitting-in-replace nil "")
526(put 'vip-sitting-in-replace 'permanent-local t)
527
528;; Remember the number of characters that have to be deleted in replace
529;; mode to compensate for the inserted characters.
530(vip-deflocalvar vip-replace-chars-to-delete 0 "")
531(vip-deflocalvar vip-replace-chars-deleted 0 "")
532
533;; Insertion ring and command ring
534(defvar vip-insertion-ring-size 14
535 "The size of the insertion ring.")
536;; The insertion ring.
537(defvar vip-insertion-ring nil)
538;; This is temp insertion ring. Used to do rotation for display purposes.
539;; When rotation just started, it is initialized to vip-insertion-ring.
540(defvar vip-temp-insertion-ring nil)
541(defvar vip-last-inserted-string-from-insertion-ring "")
542
543(defvar vip-command-ring-size 14
544 "The size of the command ring.")
545;; The command ring.
546(defvar vip-command-ring nil)
547;; This is temp command ring. Used to do rotation for display purposes.
548;; When rotation just started, it is initialized to vip-command-ring.
549(defvar vip-temp-command-ring nil)
550
551;; Modes and related variables
552
553;; Current mode. One of: `emacs-state', `vi-state', `insert-state'
554(vip-deflocalvar vip-current-state 'emacs-state)
555
556
557(defvar vip-toggle-key "\C-z"
558 "The key used to change states from emacs to Vi and back.
559In insert mode, this key also functions as Meta.
560Must be set in .vip file or prior to loading Viper.
561This setting cannot be changed interactively.")
562
563(defvar vip-ESC-key "\e"
564 "Key used to ESC.
565Must be set in .vip file or prior to loading Viper.
566This setting cannot be changed interactively.")
567
568(defvar vip-no-multiple-ESC t
569 "*If true, multiple ESC in Vi mode will cause bell to ring.
570\_ is then mapped to Meta.
571This is set to t on a windowing terminal and to 'twice on a dumb
572terminal (unless the user level is 1, 2, or 5). On a dumb terminal, this
573enables cursor keys and is generally more convenient, as terminals usually
574don't have a convenient Meta key.
575Setting vip-no-multiple-ESC to nil will allow as many multiple ESC,
576as is allowed by the major mode in effect.")
577
578
579(defvar vip-want-ctl-h-help nil
580 "*If t then C-h is bound to help-command in insert mode, if nil then it is
581bound to delete-backward-char.")
582
583;; Autoindent in insert
584
585;; Variable that keeps track of whether C-t has been pressed.
586(vip-deflocalvar vip-cted nil "")
587
588;; Preserve the indent value, used by C-d in insert mode.
589(vip-deflocalvar vip-current-indent 0)
590
591;; Whether to preserve the indent, used by C-d in insert mode.
592(vip-deflocalvar vip-preserve-indent nil)
593
594(defconst vip-auto-indent nil
595 "*Autoindent if t.")
596
597(defconst vip-shift-width 8
598 "*The shiftwidth variable.")
599
600;; Variables for repeating destructive commands
601
602(defconst vip-keep-point-on-repeat t
603 "*If t, don't move point when repeating previous command.
604This is useful for doing repeated changes with the '.' key.
605The user can change this to nil, if she likes when the cursor moves
606to a new place after repeating previous Vi command.")
607
608;; Remember insert point as a marker. This is a local marker that must be
609;; initialized to nil and moved with `vip-move-marker-locally'.
610(vip-deflocalvar vip-insert-point nil)
611(put 'vip-insert-point 'permanent-local t)
612
613;; This remembers the point before dabbrev-expand was called.
614;; If vip-insert-point turns out to be bigger than that, it is reset
615;; back to vip-pre-command-point.
616;; The reason this is needed is because dabbrev-expand (and possibly
617;; others) may jump to before the insertion point, delete something and
618;; then reinsert a bigger piece. For instance: bla^blo
05497fc6 619;; If dabbrev-expand is called after `blo' and ^ indicates vip-insert-point,
6c2e12f4
KH
620;; then point jumps to the beginning of `blo'. If expansion is found, `blablo'
621;; is deleted, and we have |^, where | denotes point. Next, dabbrev-expand
622;; will insert the expansion, and we get: blablo^
623;; Whatever we insert next goes before the ^, i.e., before the
624;; vip-insert-point marker. So, Viper will think that nothing was
625;; inserted. Remembering the orig position of the marker circumvents the
626;; problem.
627;; We don't know of any command, except dabbrev-expand, that has the same
628;; problem. However, the same trick can be used if such a command is
629;; discovered later.
630;;
631(vip-deflocalvar vip-pre-command-point nil)
632(put 'vip-pre-command-point 'permanent-local t) ; this is probably an overkill
633
634;; This is used for saving inserted text.
635(defvar vip-last-insertion nil)
636
637;; Remembers the last replaced region.
638(defvar vip-last-replace-region "")
639
640;; Remember com point as a marker.
641;; This is a local marker. Should be moved with `vip-move-marker-locally'
642(vip-deflocalvar vip-com-point nil)
643
644;; If non-nil, the value is a list (M-COM VAL COM REG inserted-text cmd-keys)
645;; It is used to re-execute last destructive command.
646;; M-COM is a Lisp symbol representing the function to be executed.
647;; VAL is the prefix argument that was used with that command.
648;; COM is an internal descriptor, such as ?r, ?c, ?C, which contains
649;; additional information on how the function in M-COM is to be handled.
650;; REG is the register used by command
651;; INSERTED-TEXT is text inserted by that command (in case of o, c, C, i, r
652;; commands).
653;; COMMAND-KEYS are the keys that were typed to invoke the command.
654(defvar vip-d-com nil)
655
656;; The character remembered by the Vi `r' command.
657(defvar vip-d-char nil)
658
659;; Name of register to store deleted or yanked strings
660(defvar vip-use-register nil)
661
662
663
664;; Variables for Moves and Searches
665
666;; For use by `;' command.
667(defvar vip-f-char nil)
668
669;; For use by `.' command.
670(defvar vip-F-char nil)
671
672;; For use by `;' command.
673(defvar vip-f-forward nil)
674
675;; For use by `;' command.
676(defvar vip-f-offset nil)
677
678;; Last search string
679(defvar vip-s-string "")
680
681(defvar vip-quote-string "> "
682 "String inserted at the beginning of quoted region.")
683
684;; If t, search is forward.
685(defvar vip-s-forward nil)
686
687(defconst vip-case-fold-search nil
688 "*If t, search ignores cases.")
689
690(defconst vip-re-search t
691 "*If t, search is reg-exp search, otherwise vanilla search.")
692
693(defconst vip-re-query-replace t
694 "*If t then do regexp replace, if nil then do string replace.")
695
696(defconst vip-re-replace t
697 "*If t, do regexp replace. nil means do string replace.")
698
699(vip-deflocalvar vip-ex-style-motion t
700 "*Ex-style: the commands l,h do not cross lines, etc.")
701
702(vip-deflocalvar vip-ex-style-editing-in-insert t
703 "*The keys ^H, ^? don't jump lines in insert, ESC moves cursor back, etc.
704Note: this doesn't preclude ^H and ^? from deleting characters by moving
705past the insertion point. This is a feature, not a bug. ")
706
707(vip-deflocalvar vip-delete-backwards-in-replace nil
708 "*If t, DEL key will delete characters while moving the cursor backwards.
709If nil, the cursor will move backwards without deleting anything.")
710
711(defconst vip-buffer-search-char nil
712 "*Key bound for buffer-searching.")
713
714(defconst vip-search-wrap-around-t t
715 "*If t, search wraps around.")
716
717(vip-deflocalvar vip-related-files-and-buffers-ring nil
718 "*Ring of file and buffer names that are considered to be related to the
719current buffer.
720These buffers can be cycled through via :R and :P commands.")
721(put 'vip-related-files-and-buffers-ring 'permanent-local t)
722
723;; Used to find out if we are done with searching the current buffer.
724(vip-deflocalvar vip-local-search-start-marker nil)
725;; As above, but global
726(defvar vip-search-start-marker (make-marker))
727
728;; the search overlay
729(vip-deflocalvar vip-search-overlay nil)
730
731
732(defvar vip-heading-start
15d90a40
KH
733 (concat "^\\s-*(\\s-*defun\\s-\\|" ; lisp
734 "^{\\s-*$\\|^[_a-zA-Z][^()]*[()].*{\\s-*$\\|" ; C/C++
6c2e12f4 735 "^\\s-*class.*{\\|^\\s-*struct.*{\\|^\\s-*enum.*{\\|"
15d90a40
KH
736 "^\\\\[sb][a-z]*{.*}\\s-*$\\|" ; latex
737 "^@node\\|@table\\|^@m?enu\\|^@itemize\\|^@if\\|" ; texinfo
738 "^.+:-") ; prolog
6c2e12f4
KH
739 "*Regexps for Headings. Used by \[\[ and \]\].")
740
741(defvar vip-heading-end
15d90a40
KH
742 (concat "^}\\|" ; C/C++
743 "^\\\\end{\\|" ; latex
744 "^@end \\|" ; texinfo
745 ")\n\n[ \t\n]*\\|" ; lisp
746 "\\.\\s-*$") ; prolog
6c2e12f4
KH
747 "*Regexps to end Headings/Sections. Used by \[\].")
748
749
750;; These two vars control the interaction of jumps performed by ' and `.
751;; In this new version, '' doesn't erase the marks set by ``, so one can
752;; use both kinds of jumps interchangeably and without loosing positions
753;; inside the lines.
754
755;; Remembers position of the last jump done using ``'.
756(vip-deflocalvar vip-last-jump nil)
757;; Remembers position of the last jump done using `''.
758(vip-deflocalvar vip-last-jump-ignore 0)
759
760;; Some common error messages
761
762(defconst vip-SpuriousText "Spurious text after command" "")
763(defconst vip-BadExCommand "Not an editor command" "")
764(defconst vip-InvalidCommandArgument "Invalid command argument" "")
765(defconst vip-NoPrevSearch "No previous search string" "")
766(defconst vip-EmptyRegister "`%c': Nothing in this register" "")
767(defconst vip-InvalidRegister "`%c': Invalid register" "")
768(defconst vip-EmptyTextmarker "`%c': Text marker doesn't point anywhere" "")
769(defconst vip-InvalidTextmarker "`%c': Invalid text marker" "")
770(defconst vip-InvalidViCommand "Invalid command" "")
771(defconst vip-BadAddress "Ill-formed address" "")
772(defconst vip-FirstAddrExceedsSecond "First address exceeds second" "")
773(defconst vip-NoFileSpecified "No file specified" "")
774
775
776;; History variables
777
6c2e12f4
KH
778;; History of search strings.
779(defvar vip-search-history (list ""))
780;; History of query-replace strings used as a source.
781(defvar vip-replace1-history nil)
782;; History of query-replace strings used as replacement.
783(defvar vip-replace2-history nil)
784;; History of region quoting strings.
785(defvar vip-quote-region-history (list vip-quote-string))
786;; History of Ex-style commands.
787(defvar vip-ex-history nil)
788;; History of shell commands.
789(defvar vip-shell-history nil)
790
791
792;; Last shell command. There are two of these, one for Ex (in viper-ex)
793;; and one for Vi.
794
795;; Last shell command executed with ! command.
796(defvar vip-last-shell-com nil)
797
798
799\f
800;;; Miscellaneous
801
04090c34
MK
802;; don't bark when mark is inactive
803(setq mark-even-if-inactive t)
6c2e12f4
KH
804
805(defvar vip-inhibit-startup-message nil
806 "Whether Viper startup message should be inhibited.")
807
808(defvar vip-always t
809 "t means, arrange that vi-state will be a default.")
810
91760fd6 811(defvar vip-custom-file-name (convert-standard-filename "~/.vip")
6c2e12f4
KH
812 "Viper customisation file.
813This variable must be set _before_ loading Viper.")
814
6c2e12f4
KH
815(defvar vip-spell-function 'ispell-region
816 "Spell function used by #s<move> command to spell.")
817
4af0c23b
KH
818(defvar vip-tags-file-name "TAGS"
819 "The tags file used by Viper.")
6c2e12f4
KH
820
821;; Minibuffer
822
823(defvar vip-vi-style-in-minibuffer t
824 "If t, use vi-style editing in minibuffer.
825Should be set in `~/.vip' file.")
826
827;; overlay used in the minibuffer to indicate which state it is in
828(vip-deflocalvar vip-minibuffer-overlay nil)
829
830;; Hook, specific to Viper, which is run just *before* exiting the minibuffer.
831;; Beginning with Emacs 19.26, the standard `minibuffer-exit-hook' is run
832;; *after* exiting the minibuffer
833(defvar vip-minibuffer-exit-hook nil)
834
835(vip-deflocalvar vip-vi-minibuffer-minor-mode nil
836 "Minor mode that forces Vi-style when the Minibuffer is in Vi state.")
837(vip-deflocalvar vip-insert-minibuffer-minor-mode nil
838 "Minor mode that forces Vi-style when the Minibuffer is in Insert state.")
839
04090c34
MK
840;; setup emacs-supported vi-style feel
841(setq next-line-add-newlines nil
842 require-final-newline t)
843
844(make-variable-buffer-local 'require-final-newline)
6c2e12f4
KH
845
846
847;; Mode line
848(defconst vip-vi-state-id "<V> "
849 "Mode line tag identifying the Vi mode of Viper.")
850(defconst vip-emacs-state-id "<E> "
851 "Mode line tag identifying the Emacs mode of Viper.")
852(defconst vip-insert-state-id "<I> "
853 "Mode line tag identifying the Insert mode of Viper.")
854(defconst vip-replace-state-id "<R> "
855 "Mode line tag identifying the Replace mode of Viper.")
856
857;; Viper changes the default mode-line-buffer-identification
858(setq-default mode-line-buffer-identification '(" %b"))
859
860;; Variable displaying the current Viper state in the mode line.
861(vip-deflocalvar vip-mode-string vip-emacs-state-id)
862(or (memq 'vip-mode-string global-mode-string)
863 (setq global-mode-string
864 (append '("" vip-mode-string) (cdr global-mode-string))))
865
866
04090c34 867(defvar vip-vi-state-hook nil
6c2e12f4 868 "*Hooks run just before the switch to Vi mode is completed.")
04090c34 869(defvar vip-insert-state-hook nil
6c2e12f4 870 "*Hooks run just before the switch to Insert mode is completed.")
04090c34 871(defvar vip-replace-state-hook nil
6c2e12f4 872 "*Hooks run just before the switch to Replace mode is completed.")
04090c34 873(defvar vip-emacs-state-hook nil
6c2e12f4
KH
874 "*Hooks run just before the switch to Emacs mode is completed.")
875
04090c34 876(defvar vip-load-hook nil
6c2e12f4
KH
877 "Hooks run just after loading Viper.")
878
879
880;; Generic predicates
881
882;; These test functions are shamelessly lifted from vip 4.4.2 by Aamod Sane
883
884;; generate test functions
885;; given symbol foo, foo-p is the test function, foos is the set of
886;; Viper command keys
887;; (macroexpand '(vip-test-com-defun foo))
888;; (defun foo-p (com) (consp (memq (if (< com 0) (- com) com) foos)))
889
890(defmacro vip-test-com-defun (name)
4af0c23b 891 (let* ((snm (symbol-name name))
6c2e12f4 892 (nm-p (intern (concat snm "-p")))
6c2e12f4
KH
893 (nms (intern (concat snm "s"))))
894 (` (defun (, nm-p) (com)
895 (consp (memq (if (< com 0) (- com) com) (, nms)))))))
896
897;; Variables for defining VI commands
898
4af0c23b
KH
899;; Modifying commands that can be prefixes to movement commands
900(defconst vip-prefix-commands '(?c ?d ?y ?! ?= ?# ?< ?> ?\"))
6c2e12f4
KH
901(vip-test-com-defun vip-prefix-command)
902
4af0c23b
KH
903;; Commands that are pairs eg. dd. r and R here are a hack
904(defconst vip-charpair-commands '(?c ?d ?y ?! ?= ?< ?> ?r ?R))
6c2e12f4
KH
905(vip-test-com-defun vip-charpair-command)
906
907(defconst vip-movement-commands '(?b ?B ?e ?E ?f ?F ?G ?h ?H ?j ?k ?l
908 ?H ?M ?n ?t ?T ?w ?W ?$ ?%
909 ?^ ?( ?) ?- ?+ ?| ?{ ?} ?[ ?] ?' ?`
910 ?; ?, ?0 ?? ?/
911 )
912 "Movement commands")
913(vip-test-com-defun vip-movement-command)
914
4af0c23b
KH
915;; Commands that can be repeated by .(dotted)
916(defconst vip-dotable-commands '(?c ?d ?C ?D ?> ?<))
6c2e12f4
KH
917(vip-test-com-defun vip-dotable-command)
918
4af0c23b
KH
919;; Commands that can follow a #
920(defconst vip-hash-cmds '(?c ?C ?g ?q ?S))
6c2e12f4
KH
921(vip-test-com-defun vip-hash-cmd)
922
4af0c23b
KH
923;; Commands that may have registers as prefix
924(defconst vip-regsuffix-commands '(?d ?y ?Y ?D ?p ?P ?x ?X))
6c2e12f4
KH
925(vip-test-com-defun vip-regsuffix-command)
926
927
928\f
929;;; Arrange the keymaps
930(require 'viper-keym)
931
932\f
933;;;; CODE
934
935;; changing mode
936
937;; Change state to NEW-STATE---either emacs-state, vi-state, or insert-state.
938(defun vip-change-state (new-state)
4af0c23b
KH
939 ;; Keep vip-post/pre-command-hooks fresh.
940 ;; We remove then add vip-post/pre-command-sentinel since it is very
05497fc6 941 ;; desirable that no one gets in-between
4af0c23b
KH
942 (remove-hook 'post-command-hook 'vip-post-command-sentinel)
943 (add-hook 'post-command-hook 'vip-post-command-sentinel)
944 (remove-hook 'pre-command-hook 'vip-pre-command-sentinel)
6c2e12f4
KH
945 (add-hook 'pre-command-hook 'vip-pre-command-sentinel t)
946 ;; These hooks will be added back if switching to insert/replace mode
27571f90 947 (vip-remove-hook 'vip-post-command-hooks
6c2e12f4 948 'vip-insert-state-post-command-sentinel)
27571f90 949 (vip-remove-hook 'vip-pre-command-hooks
6c2e12f4
KH
950 'vip-insert-state-pre-command-sentinel)
951 (cond ((eq new-state 'vi-state)
952 (cond ((member vip-current-state '(insert-state replace-state))
953
954 ;; move vip-last-posn-while-in-insert-state
955 ;; This is a normal hook that is executed in insert/replace
956 ;; states after each command. In Vi/Emacs state, it does
957 ;; nothing. We need to execute it here to make sure that
958 ;; the last posn was recorded when we hit ESC.
959 ;; It may be left unrecorded if the last thing done in
960 ;; insert/repl state was dabbrev-expansion or abbrev
961 ;; expansion caused by hitting ESC
962 (vip-insert-state-post-command-sentinel)
963
964 (condition-case conds
965 (progn
966 (vip-save-last-insertion
967 vip-insert-point
968 vip-last-posn-while-in-insert-state)
969 (if vip-began-as-replace
970 (setq vip-began-as-replace nil)
971 ;; repeat insert commands if numerical arg > 1
972 (save-excursion
973 (vip-repeat-insert-command))))
974 (error
975 (vip-message-conditions conds)))
976
977 (if (> (length vip-last-insertion) 0)
978 (vip-push-onto-ring vip-last-insertion
979 'vip-insertion-ring))
980
981 (if vip-ex-style-editing-in-insert
982 (or (bolp) (backward-char 1))))
983 ))
984
985 ;; insert or replace
986 ((memq new-state '(insert-state replace-state))
987 (if (memq vip-current-state '(emacs-state vi-state))
988 (vip-move-marker-locally 'vip-insert-point (point)))
989 (vip-move-marker-locally 'vip-last-posn-while-in-insert-state (point))
27571f90 990 (vip-add-hook 'vip-post-command-hooks
6c2e12f4 991 'vip-insert-state-post-command-sentinel t)
27571f90
MK
992 (vip-add-hook 'vip-pre-command-hooks
993 'vip-insert-state-pre-command-sentinel t))
6c2e12f4
KH
994 ) ; outermost cond
995
996 ;; Nothing needs to be done to switch to emacs mode! Just set some
27571f90 997 ;; variables, which is already done in vip-change-state-to-emacs!
6c2e12f4
KH
998
999 (setq vip-current-state new-state)
1000 (vip-normalize-minor-mode-map-alist)
1001 (vip-adjust-keys-for new-state)
1002 (vip-set-mode-vars-for new-state)
1003 (vip-refresh-mode-line)
1004 )
1005
1006
1007
1008(defun vip-adjust-keys-for (state)
1009 "Make necessary adjustments to keymaps before entering STATE."
1010 (cond ((memq state '(insert-state replace-state))
1011 (if vip-auto-indent
1012 (progn
1013 (define-key vip-insert-basic-map "\C-m" 'vip-autoindent)
1014 (if vip-want-emacs-keys-in-insert
1015 ;; expert
1016 (define-key vip-insert-basic-map "\C-j" nil)
1017 ;; novice
1018 (define-key vip-insert-basic-map "\C-j" 'vip-autoindent))))
1019
1020 (setq vip-insert-diehard-minor-mode
1021 (not vip-want-emacs-keys-in-insert))
1022
1023 (if vip-want-ctl-h-help
1024 (progn
1025 (define-key vip-insert-basic-map "\C-h" 'help-command)
1026 (define-key vip-replace-map "\C-h" 'help-command))
1027 (define-key vip-insert-basic-map
1028 "\C-h" 'vip-del-backward-char-in-insert)
1029 (define-key vip-replace-map
1030 "\C-h" 'vip-del-backward-char-in-replace)))
1031
1032 (t
1033 (setq vip-vi-diehard-minor-mode (not vip-want-emacs-keys-in-vi))
1034 (if vip-want-ctl-h-help
1035 (define-key vip-vi-basic-map "\C-h" 'help-command)
1036 (define-key vip-vi-basic-map "\C-h" 'vip-backward-char)))
1037 ))
1038
1039
4af0c23b
KH
1040;; Normalizes minor-mode-map-alist by putting Viper keymaps first.
1041;; This ensures that Viper bindings are in effect, regardless of which minor
1042;; modes were turned on by the user or by other packages.
27571f90 1043(defun vip-normalize-minor-mode-map-alist ()
6c2e12f4
KH
1044 (setq minor-mode-map-alist
1045 (vip-append-filter-alist
1046 (list
1047 (cons 'vip-vi-intercept-minor-mode vip-vi-intercept-map)
1048 (cons 'vip-vi-minibuffer-minor-mode vip-minibuffer-map)
1049 (cons 'vip-vi-local-user-minor-mode vip-vi-local-user-map)
1050 (cons 'vip-vi-kbd-minor-mode vip-vi-kbd-map)
1051 (cons 'vip-vi-global-user-minor-mode vip-vi-global-user-map)
1052 (cons 'vip-vi-state-modifier-minor-mode
1053 (if (keymapp
1054 (cdr (assoc major-mode vip-vi-state-modifier-alist)))
1055 (cdr (assoc major-mode vip-vi-state-modifier-alist))
1056 vip-empty-keymap))
1057 (cons 'vip-vi-diehard-minor-mode vip-vi-diehard-map)
1058 (cons 'vip-vi-basic-minor-mode vip-vi-basic-map)
1059 (cons 'vip-insert-intercept-minor-mode vip-insert-intercept-map)
1060 (cons 'vip-replace-minor-mode vip-replace-map)
1061 ;; vip-insert-minibuffer-minor-mode must come after
1062 ;; vip-replace-minor-mode
1063 (cons 'vip-insert-minibuffer-minor-mode
1064 vip-minibuffer-map)
1065 (cons 'vip-insert-local-user-minor-mode
1066 vip-insert-local-user-map)
1067 (cons 'vip-insert-kbd-minor-mode vip-insert-kbd-map)
1068 (cons 'vip-insert-global-user-minor-mode
1069 vip-insert-global-user-map)
1070 (cons 'vip-insert-state-modifier-minor-mode
1071 (if (keymapp
1072 (cdr
1073 (assoc major-mode vip-insert-state-modifier-alist)))
1074 (cdr
1075 (assoc major-mode vip-insert-state-modifier-alist))
1076 vip-empty-keymap))
1077 (cons 'vip-insert-diehard-minor-mode vip-insert-diehard-map)
1078 (cons 'vip-insert-basic-minor-mode vip-insert-basic-map)
1079 (cons 'vip-emacs-intercept-minor-mode
1080 vip-emacs-intercept-map)
1081 (cons 'vip-emacs-local-user-minor-mode
1082 vip-emacs-local-user-map)
1083 (cons 'vip-emacs-kbd-minor-mode vip-emacs-kbd-map)
1084 (cons 'vip-emacs-global-user-minor-mode
1085 vip-emacs-global-user-map)
1086 (cons 'vip-emacs-state-modifier-minor-mode
1087 (if (keymapp
1088 (cdr
1089 (assoc major-mode vip-emacs-state-modifier-alist)))
1090 (cdr
1091 (assoc major-mode vip-emacs-state-modifier-alist))
1092 vip-empty-keymap))
1093 )
1094 minor-mode-map-alist)))
1095
1096
1097
1098
1099\f
1100;; Viper mode-changing commands and utilities
1101
4af0c23b 1102;; Modifies mode-line-buffer-identification.
6c2e12f4 1103(defun vip-refresh-mode-line ()
6c2e12f4
KH
1104 (setq vip-mode-string
1105 (cond ((eq vip-current-state 'emacs-state) vip-emacs-state-id)
1106 ((eq vip-current-state 'vi-state) vip-vi-state-id)
1107 ((eq vip-current-state 'replace-state) vip-replace-state-id)
1108 ((eq vip-current-state 'insert-state) vip-insert-state-id)))
1109
1110 ;; Sets Viper mode string in global-mode-string
1111 (force-mode-line-update))
1112
1113;;;###autoload
1114(defun viper-mode ()
1115 "Turn on Viper emulation of Vi."
1116 (interactive)
1117 (if (not noninteractive)
1118 (progn
1119 (if vip-first-time ; This check is important. Without it, startup and
1120 (progn ; expert-level msgs mix up when viper-mode recurses
1121 (setq vip-first-time nil)
1122 (if (not vip-inhibit-startup-message)
1123 (save-window-excursion
1124 (setq vip-inhibit-startup-message t)
1125 (delete-other-windows)
1126 (switch-to-buffer "Viper Startup Message")
1127 (erase-buffer)
1128 (insert
1129 (substitute-command-keys
1130 "Viper Is a Package for Emacs Rebels.
1131It is also a VI Plan for Emacs Rescue and a venomous VI PERil.
1132
4af0c23b 1133Technically speaking, Viper is a Vi emulation package for GNU Emacs 19 and
6c2e12f4
KH
1134XEmacs 19. It supports virtually all of Vi and Ex functionality, extending
1135and improving upon much of it.
1136
1137 1. Viper supports Vi at several levels. Level 1 is the closest to
1138 Vi, level 5 provides the most flexibility to depart from many Vi
1139 conventions.
1140
1141 You will be asked to specify your user level in a following screen.
1142
1143 If you select user level 1 then the keys ^X, ^C, ^Z, and ^G will
1144 behave as in VI, to smooth transition to Viper for the beginners.
1145 However, to use Emacs productively, you are advised to reach user
1146 level 3 or higher.
1147
1148 If your user level is 2 or higher, ^X and ^C will invoke Emacs
1149 functions,as usual in Emacs; ^Z will toggle vi/emacs modes, and
1150 ^G will be the usual Emacs's keyboard-quit (something like ^C in VI).
1151
1152 2. Vi exit functions (e.g., :wq, ZZ) work on INDIVIDUAL files -- they
1153 do not cause Emacs to quit, except at user level 1 (a novice).
1154 3. ^X^C EXITS EMACS.
1155 4. Viper supports multiple undo: `u' will undo. Typing `.' will repeat
1156 undo. Another `u' changes direction.
1157
1158 6. Emacs Meta functions are invoked by typing `_' or `\\ ESC'.
1159 On a window system, the best way is to use the Meta-key.
1160 7. Try \\[keyboard-quit] and \\[abort-recursive-edit] repeatedly,
1161 if something funny happens. This would abort the current editing
1162 command.
1163
1164You can get more information on Viper by:
1165
1166 a. Typing `:help' in Vi state
1167 b. Printing Viper manual, found in ./etc/viper.dvi
1168 c. Printing ViperCard, the Quick Reference, found in ./etc/viperCard.dvi
1169
1170This startup message appears whenever you load Viper, unless you type `y' now."
1171 ))
1172 (goto-char (point-min))
1173 (if (y-or-n-p "Inhibit Viper startup message? ")
1174 (vip-save-setting
1175 'vip-inhibit-startup-message
1176 "Viper startup message inhibited"
1177 vip-custom-file-name t))
1178 (kill-buffer (current-buffer))))
1179 (message " ")
1180 (vip-set-expert-level 'dont-change-unless)))
1181 (vip-change-state-to-vi))))
1182
1183;;;###autoload
1184(defalias 'vip-mode 'viper-mode)
1185
1186
4af0c23b 1187;; Switch from Insert state to Vi state.
6c2e12f4 1188(defun vip-exit-insert-state ()
6c2e12f4
KH
1189 (interactive)
1190 (vip-change-state-to-vi))
1191
1192(defun vip-set-mode-vars-for (state)
1193 "Sets Viper minor mode variables to put Viper's state STATE in effect."
1194
1195 ;; Emacs state
1196 (setq vip-vi-minibuffer-minor-mode nil
1197 vip-insert-minibuffer-minor-mode nil
1198 vip-vi-intercept-minor-mode nil
1199 vip-insert-intercept-minor-mode nil
1200
1201 vip-vi-local-user-minor-mode nil
1202 vip-vi-kbd-minor-mode nil
1203 vip-vi-global-user-minor-mode nil
1204 vip-vi-state-modifier-minor-mode nil
1205 vip-vi-diehard-minor-mode nil
1206 vip-vi-basic-minor-mode nil
1207
1208 vip-replace-minor-mode nil
1209
1210 vip-insert-local-user-minor-mode nil
1211 vip-insert-kbd-minor-mode nil
1212 vip-insert-global-user-minor-mode nil
1213 vip-insert-state-modifier-minor-mode nil
1214 vip-insert-diehard-minor-mode nil
1215 vip-insert-basic-minor-mode nil
1216 vip-emacs-intercept-minor-mode t
1217 vip-emacs-local-user-minor-mode t
1218 vip-emacs-kbd-minor-mode (not (vip-is-in-minibuffer))
1219 vip-emacs-global-user-minor-mode t
1220 vip-emacs-state-modifier-minor-mode t
1221 )
1222
1223 ;; Vi state
1224 (if (eq state 'vi-state) ; adjust for vi-state
1225 (setq
1226 vip-vi-intercept-minor-mode t
1227 vip-vi-minibuffer-minor-mode (vip-is-in-minibuffer)
1228 vip-vi-local-user-minor-mode t
1229 vip-vi-kbd-minor-mode (not (vip-is-in-minibuffer))
1230 vip-vi-global-user-minor-mode t
1231 vip-vi-state-modifier-minor-mode t
1232 ;; don't let the diehard keymap block command completion
1233 ;; and other things in the minibuffer
1234 vip-vi-diehard-minor-mode (not
1235 (or vip-want-emacs-keys-in-vi
1236 (vip-is-in-minibuffer)))
1237 vip-vi-basic-minor-mode t
1238 vip-emacs-intercept-minor-mode nil
1239 vip-emacs-local-user-minor-mode nil
1240 vip-emacs-kbd-minor-mode nil
1241 vip-emacs-global-user-minor-mode nil
1242 vip-emacs-state-modifier-minor-mode nil
1243 ))
1244
1245 ;; Insert and Replace states
1246 (if (member state '(insert-state replace-state))
1247 (setq
1248 vip-insert-intercept-minor-mode t
1249 vip-replace-minor-mode (eq state 'replace-state)
1250 vip-insert-minibuffer-minor-mode (vip-is-in-minibuffer)
1251 vip-insert-local-user-minor-mode t
1252 vip-insert-kbd-minor-mode (not (vip-is-in-minibuffer))
1253 vip-insert-global-user-minor-mode t
1254 vip-insert-state-modifier-minor-mode t
1255 ;; don't let the diehard keymap block command completion
1256 ;; and other things in the minibuffer
1257 vip-insert-diehard-minor-mode (not
1258 (or vip-want-emacs-keys-in-insert
1259 (vip-is-in-minibuffer)))
1260 vip-insert-basic-minor-mode t
1261 vip-emacs-intercept-minor-mode nil
1262 vip-emacs-local-user-minor-mode nil
1263 vip-emacs-kbd-minor-mode nil
1264 vip-emacs-global-user-minor-mode nil
1265 vip-emacs-state-modifier-minor-mode nil
1266 ))
1267
1268 ;; minibuffer faces
4af0c23b 1269 (if (vip-window-display-p)
6c2e12f4
KH
1270 (setq vip-minibuffer-current-face
1271 (cond ((eq state 'emacs-state) vip-minibuffer-emacs-face)
1272 ((eq state 'vi-state) vip-minibuffer-vi-face)
1273 ((memq state '(insert-state replace-state))
1274 vip-minibuffer-insert-face))))
1275
1276 (if (vip-is-in-minibuffer)
1277 (vip-set-minibuffer-overlay))
1278 )
1279
1280;; This also takes care of the annoying incomplete lines in files.
d695b318 1281;; Also, this fixes `undo' to work vi-style for complex commands.
6c2e12f4
KH
1282(defun vip-change-state-to-vi ()
1283 "Change Viper state to Vi."
1284 (interactive)
1285 (if (and vip-first-time (not (vip-is-in-minibuffer)))
1286 (viper-mode)
1287 (if overwrite-mode (overwrite-mode nil))
1288 (if abbrev-mode (expand-abbrev))
1289 (if (and auto-fill-function (> (current-column) fill-column))
1290 (funcall auto-fill-function))
4af0c23b 1291 ;; don't leave whitespace lines around
27571f90
MK
1292 (if (and (memq last-command
1293 '(vip-autoindent
1294 vip-open-line vip-Open-line
1295 vip-replace-state-exit-cmd))
15f8998b 1296 (vip-over-whitespace-line))
4af0c23b 1297 (indent-to-left-margin))
6c2e12f4
KH
1298 (vip-add-newline-at-eob-if-necessary)
1299 (if vip-undo-needs-adjustment (vip-adjust-undo))
1300 (vip-change-state 'vi-state)
d695b318
MK
1301
1302 ;; always turn off iso-accents-mode, or else we won't be able to use the
1303 ;; keys `,',^ in Vi state, as they will do accents instead of Vi actions.
1304 (if (and (boundp 'iso-accents-mode) iso-accents-mode)
1305 (iso-accents-mode -1))
6c2e12f4
KH
1306
1307 ;; Protection against user errors in hooks
1308 (condition-case conds
04090c34 1309 (run-hooks 'vip-vi-state-hook)
6c2e12f4
KH
1310 (error
1311 (vip-message-conditions conds)))))
1312
1313(defun vip-change-state-to-insert ()
1314 "Change Viper state to Insert."
1315 (interactive)
1316 (vip-change-state 'insert-state)
1317 (if (and vip-automatic-iso-accents (fboundp 'iso-accents-mode))
1318 (iso-accents-mode 1)) ; turn iso accents on
1319
1320 ;; Protection against user errors in hooks
1321 (condition-case conds
04090c34 1322 (run-hooks 'vip-insert-state-hook)
6c2e12f4
KH
1323 (error
1324 (vip-message-conditions conds))))
1325
1326(defsubst vip-downgrade-to-insert ()
1327 (setq vip-current-state 'insert-state
1328 vip-replace-minor-mode nil)
1329 )
1330
1331
1332
1333;; Change to replace state. When the end of replacement region is reached,
1334;; replace state changes to insert state.
1335(defun vip-change-state-to-replace (&optional non-R-cmd)
1336 (vip-change-state 'replace-state)
1337 (if (and vip-automatic-iso-accents (fboundp 'iso-accents-mode))
1338 (iso-accents-mode 1)) ; turn iso accents on
1339 ;; Run insert-state-hook
1340 (condition-case conds
04090c34 1341 (run-hooks 'vip-insert-state-hook 'vip-replace-state-hook)
6c2e12f4
KH
1342 (error
1343 (vip-message-conditions conds)))
1344
1345 (if non-R-cmd
1346 (vip-start-replace)
1347 ;; 'R' is implemented using Emacs's overwrite-mode
1348 (vip-start-R-mode))
1349 )
1350
1351
1352(defun vip-change-state-to-emacs ()
1353 "Change Viper state to Emacs."
1354 (interactive)
1355 (vip-change-state 'emacs-state)
1356 (if (and vip-automatic-iso-accents (fboundp 'iso-accents-mode))
1357 (iso-accents-mode 1)) ; turn iso accents on
1358
1359 ;; Protection agains user errors in hooks
1360 (condition-case conds
04090c34 1361 (run-hooks 'vip-emacs-state-hook)
6c2e12f4
KH
1362 (error
1363 (vip-message-conditions conds))))
1364
05497fc6 1365;; escape to emacs mode temporarily
6c2e12f4
KH
1366(defun vip-escape-to-emacs (arg &optional events)
1367 "Escape to Emacs state from Vi state for one Emacs command.
1368ARG is used as the prefix value for the executed command. If
1369EVENTS is a list of events, which become the beginning of the command."
1370 (interactive "P")
1371 (vip-escape-to-state arg events 'emacs-state))
1372
05497fc6 1373;; escape to Vi mode temporarily
6c2e12f4
KH
1374(defun vip-escape-to-vi ()
1375 "Escape from Emacs state to Vi state for one Vi 1-character command.
1376This doesn't work with prefix arguments or most complex commands like
1377cw, dw, etc. But it does work with some 2-character commands,
1378like dd or dr."
1379 (interactive)
1380 (vip-escape-to-state nil nil 'vi-state))
1381
1382;; Escape to STATE mode for one Emacs command.
1383(defun vip-escape-to-state (arg events state)
1384 (let (com key prefix-arg)
1385 ;; this temporarily turns off Viper's minor mode keymaps
1386 (vip-set-mode-vars-for state)
1387 (vip-normalize-minor-mode-map-alist)
1388 (if events (vip-set-unread-command-events events))
1389
1390 ;; protect against keyboard quit and other errors
1391 (condition-case nil
1392 (progn
1393 (unwind-protect
1394 (progn
1395 (setq com (key-binding (setq key
1396 (if vip-xemacs-p
1397 (read-key-sequence nil)
1398 (read-key-sequence nil t)))))
1399 ;; In case of indirection--chase definitions.
1400 ;; Have to do it here because we execute this command under
1401 ;; different keymaps, so command-execute may not do the
1402 ;; right thing there
1403 (while (vectorp com) (setq com (key-binding com))))
1404 nil)
1405 ;; exec command in the right Viper state
1406 ;; otherwise, if we switch buffers in the escaped command,
1407 ;; Viper's mode vars will remain those of `state'. When we return
1408 ;; to the orig buffer, the bindings will be screwed up.
1409 (vip-set-mode-vars-for vip-current-state)
1410
1411 ;; this-command, last-command-char, last-command-event
1412 (setq this-command com)
1413 (if vip-xemacs-p ; XEmacs represents key sequences as vectors
1414 (setq last-command-event (vip-seq-last-elt key)
1415 last-command-char (event-to-character last-command-event))
1416 ;; Emacs represents them as sequences (str or vec)
1417 (setq last-command-event (vip-seq-last-elt key)
1418 last-command-char last-command-event))
1419
1420 (if (commandp com)
1421 (progn
1422 (setq prefix-arg arg)
1423 (command-execute com)))
1424 )
1425 (quit (ding))
1426 (error (beep 1))))
1427 (vip-set-mode-vars-for vip-current-state)) ; set state in new buffer
1428
1429(defun vip-exec-form-in-emacs (form)
1430 "Execute FORM in Emacs, temporarily disabling Viper's minor modes.
1431Similar to vip-escape-to-emacs, but accepts forms rather than keystrokes."
1432 (let ((buff (current-buffer))
1433 result)
1434 (vip-set-mode-vars-for 'emacs-state)
1435 (setq result (eval form))
1436 (if (not (equal buff (current-buffer))) ; cmd switched buffer
1437 (save-excursion
1438 (set-buffer buff)
1439 (vip-set-mode-vars-for vip-current-state)))
1440 (vip-set-mode-vars-for vip-current-state)
1441 result))
1442
6c2e12f4
KH
1443
1444;; This is needed because minor modes sometimes override essential Viper
1445;; bindings. By letting Viper know which files these modes are in, it will
1446;; arrange to reorganize minor-mode-map-alist so that things will work right.
1447(defun vip-harness-minor-mode (load-file)
1448 "Familiarize Viper with a minor mode defined in LOAD_FILE.
1449Minor modes that have their own keymaps may overshadow Viper keymaps.
1450This function is designed to make Viper aware of the packages that define
1451such minor modes.
1452Usage:
1453 (vip-harness-minor-mode load-file)
1454
1455LOAD-FILE is a name of the file where the specific minor mode is defined.
1456Suffixes such as .el or .elc should be stripped."
1457
1458 (interactive "sEnter name of the load file: ")
1459
1460 (vip-eval-after-load load-file '(vip-normalize-minor-mode-map-alist))
1461
4af0c23b
KH
1462 ;; Change the default for minor-mode-map-alist each time a harnessed minor
1463 ;; mode adds its own keymap to the a-list.
1464 (vip-eval-after-load
1465 load-file '(setq-default minor-mode-map-alist minor-mode-map-alist))
6c2e12f4
KH
1466 )
1467
6c2e12f4 1468
6c2e12f4
KH
1469(defun vip-ESC (arg)
1470 "Emulate ESC key in Emacs.
1471Prevents multiple escape keystrokes if vip-no-multiple-ESC is true. In that
1472case \@ will be bound to ESC. If vip-no-multiple-ESC is 'twice double ESC
1473would dings in vi-state. Other ESC sequences are emulated via the current
1474Emacs's major mode keymap. This is more convenient on dumb terminals and in
1475Emacs -nw, since this won't block functional keys such as up,down,
1476etc. Meta key also will work. When vip-no-multiple-ESC is nil, ESC key
1477behaves as in Emacs, any number of multiple escapes is allowed."
1478 (interactive "P")
1479 (let (char)
1480 (cond ((and (not vip-no-multiple-ESC) (eq vip-current-state 'vi-state))
1481 (setq char (vip-read-char-exclusive))
1482 (vip-escape-to-emacs arg (list ?\e char) ))
1483 ((and (eq vip-no-multiple-ESC 'twice)
1484 (eq vip-current-state 'vi-state))
1485 (setq char (vip-read-char-exclusive))
1486 (if (= char (string-to-char vip-ESC-key))
1487 (ding)
1488 (vip-escape-to-emacs arg (list ?\e char) )))
1489 (t (ding)))
1490 ))
1491
1492(defun vip-alternate-ESC (arg)
1493 "ESC key without checking for multiple keystrokes."
1494 (interactive "P")
1495 (vip-escape-to-emacs arg '(?\e)))
1496
1497\f
1498;; Intercept ESC sequences on dumb terminals.
1499;; Based on the idea contributed by Marcelino Veiga Tuimil <mveiga@dit.upm.es>
1500
1501;; Check if last key was ESC and if so try to reread it as a function key.
1502;; But only if there are characters to read during a very short time.
1503;; Returns the last event, if any.
1504(defun vip-envelop-ESC-key ()
1505 (let ((event last-input-event)
1506 (keyseq [nil])
1507 inhibit-quit)
1508 (if (vip-ESC-event-p event)
1509 (progn
1510 (if (vip-fast-keysequence-p)
1511 (progn
27571f90 1512 (let (minor-mode-map-alist)
4af0c23b
KH
1513 (vip-set-unread-command-events event)
1514 (setq keyseq
1515 (funcall
1516 (ad-get-orig-definition 'read-key-sequence) nil))
1517 ) ; let
6c2e12f4 1518 ;; If keyseq translates into something that still has ESC
27571f90 1519 ;; at the beginning, separate ESC from the rest of the seq.
4af0c23b
KH
1520 ;; In XEmacs we check for events that are keypress meta-key
1521 ;; and convert them into [escape key]
6c2e12f4
KH
1522 ;;
1523 ;; This is needed for the following reason:
1524 ;; If ESC is the first symbol, we interpret it as if the
1525 ;; user typed ESC and then quickly some other symbols.
1526 ;; If ESC is not the first one, then the key sequence
1527 ;; entered was apparently translated into a function key or
1528 ;; something (e.g., one may have
1529 ;; (define-key function-key-map "\e[192z" [f11])
1530 ;; which would translate the escape-sequence generated by
1531 ;; f11 in an xterm window into the symbolic key f11.
4af0c23b 1532 ;;
27571f90 1533 ;; If `first-key' is not an ESC event, we make it into the
4af0c23b
KH
1534 ;; last-command-event in order to pretend that this key was
1535 ;; pressed. This is needed to allow arrow keys to be bound to
1536 ;; macros. Otherwise, vip-exec-mapped-kbd-macro will think that
1537 ;; the last event was ESC and so it'll execute whatever is
1538 ;; bound to ESC. (Viper macros can't be bound to
1539 ;; ESC-sequences).
1540 (let* ((first-key (elt keyseq 0))
1541 (key-mod (event-modifiers first-key)))
1542 (cond ((vip-ESC-event-p first-key)
1543 ;; put keys following ESC on the unread list
1544 ;; and return ESC as the key-sequence
1545 (vip-set-unread-command-events (subseq keyseq 1))
1546 (setq last-input-event event
1547 keyseq (if vip-emacs-p
1548 "\e"
1549 (vector (character-to-event ?\e)))))
1550 ((and vip-xemacs-p
1551 (key-press-event-p first-key)
1552 (equal '(meta) key-mod))
1553 (vip-set-unread-command-events
1554 (vconcat (vector
1555 (character-to-event (event-key first-key)))
1556 (subseq keyseq 1)))
1557 (setq last-input-event event
1558 keyseq (vector (character-to-event ?\e))))
1559 ((eventp first-key)
1560 (setq last-command-event first-key))
1561 ))
6c2e12f4
KH
1562 ) ; end progn
1563
1564 ;; this is escape event with nothing after it
1565 ;; put in unread-command-event and then re-read
1566 (vip-set-unread-command-events event)
1567 (setq keyseq
1568 (funcall (ad-get-orig-definition 'read-key-sequence) nil))
1569 ))
1570 ;; not an escape event
1571 (setq keyseq (vector event)))
1572 keyseq))
1573
1574
1575
4af0c23b 1576(defadvice read-key-sequence (around vip-read-keyseq-ad activate)
d695b318 1577 "Harness to work for Viper. This advice is harmless---don't worry!"
6c2e12f4
KH
1578 (let (inhibit-quit event keyseq)
1579 (setq keyseq ad-do-it)
1580 (setq event (if vip-xemacs-p
1581 (elt keyseq 0) ; XEmacs returns vector of events
1582 (elt (listify-key-sequence keyseq) 0)))
1583 (if (vip-ESC-event-p event)
4af0c23b 1584 (let (unread-command-events)
6c2e12f4
KH
1585 (vip-set-unread-command-events keyseq)
1586 (if (vip-fast-keysequence-p)
1587 (let ((vip-vi-global-user-minor-mode nil)
1588 (vip-vi-local-user-minor-mode nil)
1589 (vip-replace-minor-mode nil) ; actually unnecessary
1590 (vip-insert-global-user-minor-mode nil)
1591 (vip-insert-local-user-minor-mode nil))
1592 (setq keyseq ad-do-it))
1593 (setq keyseq ad-do-it))))
1594 keyseq))
1595
4af0c23b
KH
1596(defadvice describe-key (before vip-read-keyseq-ad protect activate)
1597 "Force to read key via `read-key-sequence'."
6c2e12f4
KH
1598 (interactive (list (vip-events-to-keys
1599 (read-key-sequence "Describe key: ")))))
1600
4af0c23b
KH
1601(defadvice describe-key-briefly (before vip-read-keyseq-ad protect activate)
1602 "Force to read key via `read-key-sequence'."
6c2e12f4
KH
1603 (interactive (list (vip-events-to-keys
1604 (read-key-sequence "Describe key briefly: ")))))
1605
4af0c23b
KH
1606;; Listen to ESC key.
1607;; If a sequence of keys starting with ESC is issued with very short delays,
1608;; interpret these keys in Emacs mode, so ESC won't be interpreted as a Vi key.
6c2e12f4 1609(defun vip-intercept-ESC-key ()
4af0c23b 1610 "Function that implements ESC key in Viper emulation of Vi."
6c2e12f4
KH
1611 (interactive)
1612 (let ((cmd (or (key-binding (vip-envelop-ESC-key))
1613 '(lambda () (interactive) (error "")))))
1614
1615 ;; call the actual function to execute ESC (if no other symbols followed)
1616 ;; or the key bound to the ESC sequence (if the sequence was issued
1617 ;; with very short delay between characters.
1618 (if (eq cmd 'vip-intercept-ESC-key)
1619 (setq cmd
1620 (cond ((eq vip-current-state 'vi-state)
1621 'vip-ESC)
1622 ((eq vip-current-state 'insert-state)
1623 'vip-exit-insert-state)
1624 ((eq vip-current-state 'replace-state)
1625 'vip-replace-state-exit-cmd)
1626 (t 'vip-change-state-to-vi)
1627 )))
1628 (call-interactively cmd)))
1629
1630
1631\f
1632;; prefix argument for Vi mode
1633
1634;; In Vi mode, prefix argument is a dotted pair (NUM . COM) where NUM
1635;; represents the numeric value of the prefix argument and COM represents
1636;; command prefix such as "c", "d", "m" and "y".
1637
4af0c23b
KH
1638;; Compute numeric prefix arg value.
1639;; Invoked by CHAR. COM is the command part obtained so far.
6c2e12f4 1640(defun vip-prefix-arg-value (event com)
6c2e12f4
KH
1641 (let (value)
1642 ;; read while number
1643 (while (and (numberp event) (>= event ?0) (<= event ?9))
1644 (setq value (+ (* (if (numberp value) value 0) 10) (- event ?0)))
1645 (setq event (vip-read-event-convert-to-char)))
1646
1647 (setq prefix-arg value)
1648 (if com (setq prefix-arg (cons prefix-arg com)))
1649 (while (eq event ?U)
1650 (vip-describe-arg prefix-arg)
1651 (setq event (vip-read-event-convert-to-char)))
1652 (vip-set-unread-command-events event)))
1653
4af0c23b 1654;; Vi operator as prefix argument."
6c2e12f4 1655(defun vip-prefix-arg-com (char value com)
6c2e12f4
KH
1656 (let ((cont t))
1657 (while (and cont
1658 (memq char
1659 (list ?c ?d ?y ?! ?< ?> ?= ?# ?r ?R ?\"
1660 vip-buffer-search-char)))
1661 (if com
1662 ;; this means that we already have a command character, so we
1663 ;; construct a com list and exit while. however, if char is "
1664 ;; it is an error.
1665 (progn
1666 ;; new com is (CHAR . OLDCOM)
1667 (if (memq char '(?# ?\")) (error ""))
1668 (setq com (cons char com))
1669 (setq cont nil))
1670 ;; If com is nil we set com as char, and read more. Again, if char
1671 ;; is ", we read the name of register and store it in vip-use-register.
1672 ;; if char is !, =, or #, a complete com is formed so we exit the
1673 ;; while loop.
1674 (cond ((memq char '(?! ?=))
1675 (setq com char)
1676 (setq char (read-char))
1677 (setq cont nil))
1678 ((= char ?#)
1679 ;; read a char and encode it as com
1680 (setq com (+ 128 (read-char)))
1681 (setq char (read-char)))
1682 ((= char ?\")
1683 (let ((reg (read-char)))
1684 (if (vip-valid-register reg)
1685 (setq vip-use-register reg)
1686 (error ""))
1687 (setq char (read-char))))
1688 (t
1689 (setq com char)
1690 (setq char (vip-read-char-exclusive)))))))
1691 (if (atom com)
1692 ;; com is a single char, so we construct prefix-arg
1693 ;; and if char is ?, describe prefix arg, otherwise exit by
1694 ;; pushing the char back
1695 (progn
1696 (setq prefix-arg (cons value com))
1697 (while (= char ?U)
1698 (vip-describe-arg prefix-arg)
1699 (setq char (read-char)))
1700 (vip-set-unread-command-events char)
1701 )
1702 ;; as com is non-nil, this means that we have a command to execute
1703 (if (memq (car com) '(?r ?R))
05497fc6 1704 ;; execute appropriate region command.
6c2e12f4
KH
1705 (let ((char (car com)) (com (cdr com)))
1706 (setq prefix-arg (cons value com))
1707 (if (= char ?r) (vip-region prefix-arg)
1708 (vip-Region prefix-arg))
1709 ;; reset prefix-arg
1710 (setq prefix-arg nil))
1711 ;; otherwise, reset prefix arg and call appropriate command
1712 (setq value (if (null value) 1 value))
1713 (setq prefix-arg nil)
1714 (cond ((equal com '(?c . ?c)) (vip-line (cons value ?C)))
1715 ((equal com '(?d . ?d)) (vip-line (cons value ?D)))
1716 ((equal com '(?d . ?y)) (vip-yank-defun))
1717 ((equal com '(?y . ?y)) (vip-line (cons value ?Y)))
1718 ((equal com '(?< . ?<)) (vip-line (cons value ?<)))
1719 ((equal com '(?> . ?>)) (vip-line (cons value ?>)))
1720 ((equal com '(?! . ?!)) (vip-line (cons value ?!)))
1721 ((equal com '(?= . ?=)) (vip-line (cons value ?=)))
1722 (t (error ""))))))
1723
1724(defun vip-describe-arg (arg)
1725 (let (val com)
1726 (setq val (vip-P-val arg)
1727 com (vip-getcom arg))
1728 (if (null val)
1729 (if (null com)
1730 (message "Value is nil, and command is nil")
1731 (message "Value is nil, and command is `%c'" com))
1732 (if (null com)
1733 (message "Value is `%d', and command is nil" val)
1734 (message "Value is `%d', and command is `%c'" val com)))))
1735
1736(defun vip-digit-argument (arg)
1737 "Begin numeric argument for the next command."
1738 (interactive "P")
d695b318 1739 (vip-leave-region-active)
6c2e12f4
KH
1740 (vip-prefix-arg-value last-command-char
1741 (if (consp arg) (cdr arg) nil)))
1742
1743(defun vip-command-argument (arg)
1744 "Accept a motion command as an argument."
1745 (interactive "P")
1746 (condition-case nil
1747 (vip-prefix-arg-com
1748 last-command-char
1749 (cond ((null arg) nil)
1750 ((consp arg) (car arg))
1751 ((numberp arg) arg)
1752 (t (error vip-InvalidCommandArgument)))
1753 (cond ((null arg) nil)
1754 ((consp arg) (cdr arg))
1755 ((numberp arg) nil)
1756 (t (error vip-InvalidCommandArgument))))
1757 (quit (setq vip-use-register nil)
1758 (signal 'quit nil)))
1759 (vip-deactivate-mark))
1760
1761;; Get value part of prefix-argument ARG.
1762(defsubst vip-p-val (arg)
1763 (cond ((null arg) 1)
04090c34
MK
1764 ((consp arg)
1765 (if (or (null (car arg)) (equal (car arg) '(nil)))
1766 1 (car arg)))
6c2e12f4
KH
1767 (t arg)))
1768
1769;; Get raw value part of prefix-argument ARG.
1770(defsubst vip-P-val (arg)
1771 (cond ((consp arg) (car arg))
1772 (t arg)))
1773
1774;; Get com part of prefix-argument ARG.
1775(defsubst vip-getcom (arg)
1776 (cond ((null arg) nil)
1777 ((consp arg) (cdr arg))
1778 (t nil)))
1779
1780;; Get com part of prefix-argument ARG and modify it.
1781(defun vip-getCom (arg)
1782 (let ((com (vip-getcom arg)))
1783 (cond ((equal com ?c) ?C)
1784 ((equal com ?d) ?D)
1785 ((equal com ?y) ?Y)
1786 (t com))))
1787
1788\f
1789;; repeat last destructive command
1790
1791;; Append region to text in register REG.
1792;; START and END are buffer positions indicating what to append.
1793(defsubst vip-append-to-register (reg start end)
4af0c23b
KH
1794 (set-register reg (concat (if (stringp (get-register reg))
1795 (get-register reg) "")
6c2e12f4
KH
1796 (buffer-substring start end))))
1797
1798;; define functions to be executed
1799
1800;; invoked by C command
1801(defun vip-exec-change (m-com com)
1802 ;; handle C cmd at the eol and at eob.
1803 (if (or (and (eolp) (= vip-com-point (point)))
1804 (= vip-com-point (point-max)))
1805 (progn
1806 (insert " ")(backward-char 1)))
1807 (if (= vip-com-point (point))
1808 (vip-forward-char-carefully))
1809 (if (= com ?c)
1810 (vip-change vip-com-point (point))
1811 (vip-change-subr vip-com-point (point))))
1812
1813;; this is invoked by vip-substitute-line
1814(defun vip-exec-Change (m-com com)
1815 (save-excursion
1816 (set-mark vip-com-point)
1817 (vip-enlarge-region (mark t) (point))
1818 (if vip-use-register
1819 (progn
1820 (cond ((vip-valid-register vip-use-register '(letter digit))
1821 ;;(vip-valid-register vip-use-register '(letter)
1822 (copy-to-register
1823 vip-use-register (mark t) (point) nil))
1824 ((vip-valid-register vip-use-register '(Letter))
1825 (vip-append-to-register
1826 (downcase vip-use-register) (mark t) (point)))
1827 (t (setq vip-use-register nil)
1828 (error vip-InvalidRegister vip-use-register)))
1829 (setq vip-use-register nil)))
1830 (delete-region (mark t) (point)))
1831 (open-line 1)
1832 (if (= com ?C) (vip-change-mode-to-insert) (vip-yank-last-insertion)))
1833
1834(defun vip-exec-delete (m-com com)
1835 (if vip-use-register
1836 (progn
1837 (cond ((vip-valid-register vip-use-register '(letter digit))
1838 ;;(vip-valid-register vip-use-register '(letter))
1839 (copy-to-register
1840 vip-use-register vip-com-point (point) nil))
1841 ((vip-valid-register vip-use-register '(Letter))
1842 (vip-append-to-register
1843 (downcase vip-use-register) vip-com-point (point)))
1844 (t (setq vip-use-register nil)
1845 (error vip-InvalidRegister vip-use-register)))
1846 (setq vip-use-register nil)))
1847 (setq last-command
1848 (if (eq last-command 'd-command) 'kill-region nil))
1849 (kill-region vip-com-point (point))
1850 (setq this-command 'd-command)
1851 (if vip-ex-style-motion
1852 (if (and (eolp) (not (bolp))) (backward-char 1))))
1853
1854(defun vip-exec-Delete (m-com com)
1855 (save-excursion
1856 (set-mark vip-com-point)
1857 (vip-enlarge-region (mark t) (point))
1858 (if vip-use-register
1859 (progn
1860 (cond ((vip-valid-register vip-use-register '(letter digit))
1861 ;;(vip-valid-register vip-use-register '(letter))
1862 (copy-to-register
1863 vip-use-register (mark t) (point) nil))
1864 ((vip-valid-register vip-use-register '(Letter))
1865 (vip-append-to-register
1866 (downcase vip-use-register) (mark t) (point)))
1867 (t (setq vip-use-register nil)
1868 (error vip-InvalidRegister vip-use-register)))
1869 (setq vip-use-register nil)))
1870 (setq last-command
1871 (if (eq last-command 'D-command) 'kill-region nil))
1872 (kill-region (mark t) (point))
1873 (if (eq m-com 'vip-line) (setq this-command 'D-command)))
1874 (back-to-indentation))
1875
1876(defun vip-exec-yank (m-com com)
1877 (if vip-use-register
1878 (progn
1879 (cond ((vip-valid-register vip-use-register '(letter digit))
1880 ;; (vip-valid-register vip-use-register '(letter))
1881 (copy-to-register
1882 vip-use-register vip-com-point (point) nil))
1883 ((vip-valid-register vip-use-register '(Letter))
1884 (vip-append-to-register
1885 (downcase vip-use-register) vip-com-point (point)))
1886 (t (setq vip-use-register nil)
1887 (error vip-InvalidRegister vip-use-register)))
1888 (setq vip-use-register nil)))
1889 (setq last-command nil)
1890 (copy-region-as-kill vip-com-point (point))
1891 (goto-char vip-com-point))
1892
1893(defun vip-exec-Yank (m-com com)
1894 (save-excursion
1895 (set-mark vip-com-point)
1896 (vip-enlarge-region (mark t) (point))
1897 (if vip-use-register
1898 (progn
1899 (cond ((vip-valid-register vip-use-register '(letter digit))
6c2e12f4
KH
1900 (copy-to-register
1901 vip-use-register (mark t) (point) nil))
1902 ((vip-valid-register vip-use-register '(Letter))
1903 (vip-append-to-register
1904 (downcase vip-use-register) (mark t) (point)))
1905 (t (setq vip-use-register nil)
1906 (error vip-InvalidRegister vip-use-register)))
1907 (setq vip-use-register nil)))
1908 (setq last-command nil)
1909 (copy-region-as-kill (mark t) (point)))
04090c34 1910 (vip-deactivate-mark)
6c2e12f4
KH
1911 (goto-char vip-com-point))
1912
1913(defun vip-exec-bang (m-com com)
1914 (save-excursion
1915 (set-mark vip-com-point)
1916 (vip-enlarge-region (mark t) (point))
1917 (shell-command-on-region
1918 (mark t) (point)
1919 (if (= com ?!)
1920 (setq vip-last-shell-com
1921 (vip-read-string-with-history
1922 "!"
1923 nil
1924 'vip-shell-history
1925 (car vip-shell-history)
1926 ))
1927 vip-last-shell-com)
1928 t)))
1929
1930(defun vip-exec-equals (m-com com)
1931 (save-excursion
1932 (set-mark vip-com-point)
1933 (vip-enlarge-region (mark t) (point))
1934 (if (> (mark t) (point)) (exchange-point-and-mark))
1935 (indent-region (mark t) (point) nil)))
1936
1937(defun vip-exec-shift (m-com com)
1938 (save-excursion
1939 (set-mark vip-com-point)
1940 (vip-enlarge-region (mark t) (point))
1941 (if (> (mark t) (point)) (exchange-point-and-mark))
1942 (indent-rigidly (mark t) (point)
1943 (if (= com ?>)
1944 vip-shift-width
4af0c23b
KH
1945 (- vip-shift-width))))
1946 ;; return point to where it was before shift
1947 (goto-char vip-com-point))
6c2e12f4
KH
1948
1949;; this is needed because some commands fake com by setting it to ?r, which
1950;; denotes repeated insert command.
1951(defsubst vip-exec-dummy (m-com com)
1952 nil)
1953
1954(defun vip-exec-buffer-search (m-com com)
1955 (setq vip-s-string (buffer-substring (point) vip-com-point))
1956 (setq vip-s-forward t)
1957 (setq vip-search-history (cons vip-s-string vip-search-history))
1958 (vip-search vip-s-string vip-s-forward 1))
1959
1960(defvar vip-exec-array (make-vector 128 nil))
1961
1962;; Using a dispatch array allows adding functions like buffer search
1963;; without affecting other functions. Buffer search can now be bound
1964;; to any character.
1965
1966(aset vip-exec-array ?c 'vip-exec-change)
1967(aset vip-exec-array ?C 'vip-exec-Change)
1968(aset vip-exec-array ?d 'vip-exec-delete)
1969(aset vip-exec-array ?D 'vip-exec-Delete)
1970(aset vip-exec-array ?y 'vip-exec-yank)
1971(aset vip-exec-array ?Y 'vip-exec-Yank)
1972(aset vip-exec-array ?r 'vip-exec-dummy)
1973(aset vip-exec-array ?! 'vip-exec-bang)
1974(aset vip-exec-array ?< 'vip-exec-shift)
1975(aset vip-exec-array ?> 'vip-exec-shift)
1976(aset vip-exec-array ?= 'vip-exec-equals)
1977
1978
1979
1980;; This function is called by various movement commands to execute a
1981;; destructive command on the region specified by the movement command. For
1982;; instance, if the user types cw, then the command vip-forward-word will
1983;; call vip-execute-com to execute vip-exec-change, which eventually will
1984;; call vip-change to invoke the replace mode on the region.
1985;;
1986;; The list (M-COM VAL COM REG INSETED-TEXT COMMAND-KEYS) is set to
1987;; vip-d-com for later use by vip-repeat.
1988(defun vip-execute-com (m-com val com)
1989 (let ((reg vip-use-register))
1990 ;; this is the special command `#'
1991 (if (> com 128)
1992 (vip-special-prefix-com (- com 128))
1993 (let ((fn (aref vip-exec-array (if (< com 0) (- com) com))))
1994 (if (null fn)
1995 (error "%c: %s" com vip-InvalidViCommand)
1996 (funcall fn m-com com))))
1997 (if (vip-dotable-command-p com)
1998 (vip-set-destructive-command
1999 (list m-com val
2000 (if (memq com (list ?c ?C ?!)) (- com) com)
2001 reg nil nil)))
2002 ))
2003
2004
2005(defun vip-repeat (arg)
2006 "Re-execute last destructive command.
2007Use the info in vip-d-com, which has the form
2008\(com val ch reg inserted-text command-keys\),
2009where `com' is the command to be re-executed, `val' is the
2010argument to `com', `ch' is a flag for repeat, and `reg' is optional;
2011if it exists, it is the name of the register for `com'.
2012If the prefix argument, ARG, is non-nil, it is used instead of `val'."
2013 (interactive "P")
2014 (let ((save-point (point)) ; save point before repeating prev cmd
2015 ;; Pass along that we are repeating a destructive command
2016 ;; This tells vip-set-destructive-command not to update
2017 ;; vip-command-ring
2018 (vip-intermediate-command 'vip-repeat))
2019 (if (eq last-command 'vip-undo)
2020 ;; if the last command was vip-undo, then undo-more
2021 (vip-undo-more)
2022 ;; otherwise execute the command stored in vip-d-com. if arg is non-nil
2023 ;; its prefix value is used as new prefix value for the command.
2024 (let ((m-com (car vip-d-com))
2025 (val (vip-P-val arg))
2026 (com (nth 2 vip-d-com))
2027 (reg (nth 3 vip-d-com)))
2028 (if (null val) (setq val (nth 1 vip-d-com)))
2029 (if (null m-com) (error "No previous command to repeat."))
2030 (setq vip-use-register reg)
2031 (if (nth 4 vip-d-com) ; text inserted by command
2032 (setq vip-last-insertion (nth 4 vip-d-com)
2033 vip-d-char (nth 4 vip-d-com)))
2034 (funcall m-com (cons val com))
2035 (if (and vip-keep-point-on-repeat (< save-point (point)))
2036 (goto-char save-point)) ; go back to before repeat.
2037 (if (and (eolp) (not (bolp)))
2038 (backward-char 1))
2039 ))
2040 (if vip-undo-needs-adjustment (vip-adjust-undo)) ; take care of undo
2041 ;; If the prev cmd was rotating the command ring, this means that `.' has
2042 ;; just executed a command from that ring. So, push it on the ring again.
2043 ;; If we are just executing previous command , then don't push vip-d-com
2044 ;; because vip-d-com is not fully constructed in this case (its keys and
2045 ;; the inserted text may be nil). Besides, in this case, the command
2046 ;; executed by `.' is already on the ring.
2047 (if (eq last-command 'vip-display-current-destructive-command)
2048 (vip-push-onto-ring vip-d-com 'vip-command-ring))
2049 (vip-deactivate-mark)
2050 ))
2051
2052(defun vip-repeat-from-history ()
2053 "Repeat a destructive command from history.
2054Doesn't change vip-command-ring in any way, so `.' will work as before
2055executing this command.
2056This command is supposed to be bound to a two-character Vi macro where
2057the second character is a digit 0 to 9. The digit indicates which
2058history command to execute. `<char>0' is equivalent to `.', `<char>1'
2059invokes the command before that, etc."
2060 (interactive)
2061 (let* ((vip-intermediate-command 'repeating-display-destructive-command)
2062 (idx (cond (vip-this-kbd-macro
2063 (string-to-number
2064 (symbol-name (elt vip-this-kbd-macro 1))))
2065 (t 0)))
2066 (num idx)
2067 (vip-d-com vip-d-com))
2068
2069 (or (and (numberp num) (<= 0 num) (<= num 9))
2070 (setq idx 0
2071 num 0)
2072 (message
2073 "`vip-repeat-from-history' must be invoked as a Vi macro bound to `<key><digit>'"))
2074 (while (< 0 num)
2075 (setq vip-d-com (vip-special-ring-rotate1 vip-command-ring -1))
2076 (setq num (1- num)))
2077 (vip-repeat nil)
2078 (while (> idx num)
2079 (vip-special-ring-rotate1 vip-command-ring 1)
2080 (setq num (1+ num)))
2081 ))
2082
2083
4af0c23b 2084;; This command is invoked interactively by the key sequence #<char>
6c2e12f4 2085(defun vip-special-prefix-com (char)
6c2e12f4
KH
2086 (cond ((= char ?c)
2087 (downcase-region (min vip-com-point (point))
2088 (max vip-com-point (point))))
2089 ((= char ?C)
2090 (upcase-region (min vip-com-point (point))
2091 (max vip-com-point (point))))
2092 ((= char ?g)
2093 (push-mark vip-com-point t)
2094 (vip-global-execute))
2095 ((= char ?q)
2096 (push-mark vip-com-point t)
2097 (vip-quote-region))
2098 ((= char ?s) (funcall vip-spell-function vip-com-point (point)))
2099 (t (error "#%c: %s" char vip-InvalidViCommand))))
2100
2101\f
2102;; undoing
2103
2104(defun vip-undo ()
2105 "Undo previous change."
2106 (interactive)
2107 (message "undo!")
2108 (let ((modified (buffer-modified-p))
2109 (before-undo-pt (point-marker))
2110 (after-change-functions after-change-functions)
2111 undo-beg-posn undo-end-posn)
2112
2113 ;; no need to remove this hook, since this var has scope inside a let.
2114 (add-hook 'after-change-functions
2115 '(lambda (beg end len)
2116 (setq undo-beg-posn beg
2117 undo-end-posn (or end beg))))
2118
2119 (undo-start)
2120 (undo-more 2)
2121 (setq undo-beg-posn (or undo-beg-posn before-undo-pt)
2122 undo-end-posn (or undo-end-posn undo-beg-posn))
2123
2124 (goto-char undo-beg-posn)
2125 (sit-for 0)
2126 (if (and vip-keep-point-on-undo
2127 (pos-visible-in-window-p before-undo-pt))
2128 (progn
2129 (push-mark (point-marker) t)
2130 (vip-sit-for-short 300)
2131 (goto-char undo-end-posn)
2132 (vip-sit-for-short 300)
2133 (if (and (> (abs (- undo-beg-posn before-undo-pt)) 1)
2134 (> (abs (- undo-end-posn before-undo-pt)) 1))
2135 (goto-char before-undo-pt)
2136 (goto-char undo-beg-posn)))
2137 (push-mark before-undo-pt t))
2138 (if (and (eolp) (not (bolp))) (backward-char 1))
2139 (if (not modified) (set-buffer-modified-p t)))
2140 (setq this-command 'vip-undo))
2141
4af0c23b 2142;; Continue undoing previous changes.
6c2e12f4 2143(defun vip-undo-more ()
6c2e12f4
KH
2144 (message "undo more!")
2145 (condition-case nil
2146 (undo-more 1)
2147 (error (beep)
2148 (message "No further undo information in this buffer")))
2149 (if (and (eolp) (not (bolp))) (backward-char 1))
2150 (setq this-command 'vip-undo))
2151
2152;; The following two functions are used to set up undo properly.
2153;; In VI, unlike Emacs, if you open a line, say, and add a bunch of lines,
2154;; they are undone all at once.
2155(defun vip-adjust-undo ()
2156 (let ((inhibit-quit t)
2157 tmp tmp2)
2158 (setq vip-undo-needs-adjustment nil)
2159 (if (listp buffer-undo-list)
2160 (if (setq tmp (memq vip-buffer-undo-list-mark buffer-undo-list))
2161 (progn
2162 (setq tmp2 (cdr tmp)) ; the part after mark
2163
2164 ;; cut tail from buffer-undo-list temporarily by direct
2165 ;; manipulation with pointers in buffer-undo-list
2166 (setcdr tmp nil)
2167
2168 (setq buffer-undo-list (delq nil buffer-undo-list))
2169 (setq buffer-undo-list
2170 (delq vip-buffer-undo-list-mark buffer-undo-list))
2171 ;; restore tail of buffer-undo-list
2172 (setq buffer-undo-list (nconc buffer-undo-list tmp2)))
2173 (setq buffer-undo-list (delq nil buffer-undo-list))))))
2174
2175
2176(defun vip-set-complex-command-for-undo ()
2177 (if (listp buffer-undo-list)
2178 (if (not vip-undo-needs-adjustment)
2179 (let ((inhibit-quit t))
2180 (setq buffer-undo-list
2181 (cons vip-buffer-undo-list-mark buffer-undo-list))
2182 (setq vip-undo-needs-adjustment t)))))
2183
2184
2185
2186
2187(defun vip-display-current-destructive-command ()
2188 (let ((text (nth 4 vip-d-com))
2189 (keys (nth 5 vip-d-com))
2190 (max-text-len 30))
2191
2192 (setq this-command 'vip-display-current-destructive-command)
2193
2194 (message " `.' runs %s%s"
2195 (concat "`" (vip-array-to-string keys) "'")
2196 (vip-abbreviate-string text max-text-len
2197 " inserting `" "'" " ......."))
2198 ))
2199
2200
2201;; don't change vip-d-com if it was vip-repeat command invoked with `.'
2202;; or in some other way (non-interactively).
2203(defun vip-set-destructive-command (list)
2204 (or (eq vip-intermediate-command 'vip-repeat)
2205 (progn
2206 (setq vip-d-com list)
2207 (setcar (nthcdr 5 vip-d-com)
2208 (vip-array-to-string (this-command-keys)))
2209 (vip-push-onto-ring vip-d-com 'vip-command-ring))))
2210
2211(defun vip-prev-destructive-command (next)
2212 "Find previous destructive command in the history of destructive commands.
2213With prefix argument, find next destructive command."
2214 (interactive "P")
2215 (let (cmd vip-intermediate-command)
2216 (if (eq last-command 'vip-display-current-destructive-command)
2217 ;; repeated search through command history
2218 (setq vip-intermediate-command 'repeating-display-destructive-command)
2219 ;; first search through command history--set temp ring
2220 (setq vip-temp-command-ring (copy-list vip-command-ring)))
2221 (setq cmd (if next
2222 (vip-special-ring-rotate1 vip-temp-command-ring 1)
2223 (vip-special-ring-rotate1 vip-temp-command-ring -1)))
2224 (if (null cmd)
2225 ()
2226 (setq vip-d-com cmd))
2227 (vip-display-current-destructive-command)))
2228
2229(defun vip-next-destructive-command ()
2230 "Find next destructive command in the history of destructive commands."
2231 (interactive)
2232 (vip-prev-destructive-command 'next))
2233
2234(defun vip-insert-prev-from-insertion-ring (arg)
4af0c23b 2235 "Cycle through insertion ring in the direction of older insertions.
6c2e12f4
KH
2236Undoes previous insertion and inserts new.
2237With prefix argument, cycles in the direction of newer elements.
2238In minibuffer, this command executes whatever the invocation key is bound
2239to in the global map, instead of cycling through the insertion ring."
2240 (interactive "P")
2241 (let (vip-intermediate-command)
2242 (if (eq last-command 'vip-insert-from-insertion-ring)
2243 (progn ; repeated search through insertion history
2244 (setq vip-intermediate-command 'repeating-insertion-from-ring)
2245 (if (eq vip-current-state 'replace-state)
2246 (undo 1)
2247 (if vip-last-inserted-string-from-insertion-ring
2248 (backward-delete-char
2249 (length vip-last-inserted-string-from-insertion-ring))))
2250 )
2251 ;;first search through insertion history
2252 (setq vip-temp-insertion-ring (copy-list vip-insertion-ring)))
2253 (setq this-command 'vip-insert-from-insertion-ring)
2254 ;; so that things will be undone properly
2255 (setq buffer-undo-list (cons nil buffer-undo-list))
2256 (setq vip-last-inserted-string-from-insertion-ring
2257 (vip-special-ring-rotate1 vip-temp-insertion-ring (if arg 1 -1)))
2258
2259 ;; this change of vip-intermediate-command must come after
2260 ;; vip-special-ring-rotate1, so that the ring will rotate, but before the
2261 ;; insertion.
2262 (setq vip-intermediate-command nil)
2263 (if vip-last-inserted-string-from-insertion-ring
2264 (insert vip-last-inserted-string-from-insertion-ring))
2265 ))
2266
2267(defun vip-insert-next-from-insertion-ring ()
4af0c23b
KH
2268 "Cycle through insertion ring in the direction of older insertions.
2269Undo previous insertion and inserts new."
6c2e12f4
KH
2270 (interactive)
2271 (vip-insert-prev-from-insertion-ring 'next))
2272
2273\f
2274;; some region utilities
2275
4af0c23b 2276;; If at the last line of buffer, add \\n before eob, if newline is missing.
6c2e12f4 2277(defun vip-add-newline-at-eob-if-necessary ()
6c2e12f4
KH
2278 (save-excursion
2279 (end-of-line)
2280 ;; make sure all lines end with newline, unless in the minibuffer or
04090c34 2281 ;; when requested otherwise (require-final-newline is nil)
6c2e12f4
KH
2282 (if (and
2283 (eobp)
2284 (not (bolp))
04090c34 2285 require-final-newline
6c2e12f4
KH
2286 (not (vip-is-in-minibuffer)))
2287 (insert "\n"))))
2288
2289(defun vip-yank-defun ()
2290 (mark-defun)
2291 (copy-region-as-kill (point) (mark t)))
2292
4af0c23b 2293;; Enlarge region between BEG and END.
6c2e12f4 2294(defun vip-enlarge-region (beg end)
6c2e12f4
KH
2295 (or beg (setq beg end)) ; if beg is nil, set to end
2296 (or end (setq end beg)) ; if end is nil, set to beg
2297
2298 (if (< beg end)
2299 (progn (goto-char beg) (set-mark end))
2300 (goto-char end)
2301 (set-mark beg))
2302 (beginning-of-line)
2303 (exchange-point-and-mark)
2304 (if (or (not (eobp)) (not (bolp))) (forward-line 1))
2305 (if (not (eobp)) (beginning-of-line))
2306 (if (> beg end) (exchange-point-and-mark)))
2307
2308
4af0c23b 2309;; Quote region by each line with a user supplied string.
6c2e12f4 2310(defun vip-quote-region ()
6c2e12f4
KH
2311 (setq vip-quote-string
2312 (vip-read-string-with-history
2313 "Quote string: "
2314 nil
2315 'vip-quote-region-history
2316 vip-quote-string))
2317 (vip-enlarge-region (point) (mark t))
2318 (if (> (point) (mark t)) (exchange-point-and-mark))
2319 (insert vip-quote-string)
2320 (beginning-of-line)
2321 (forward-line 1)
2322 (while (and (< (point) (mark t)) (bolp))
2323 (insert vip-quote-string)
2324 (beginning-of-line)
2325 (forward-line 1)))
6c2e12f4
KH
2326
2327;; Tells whether BEG is on the same line as END.
2328;; If one of the args is nil, it'll return nil.
2329(defun vip-same-line (beg end)
2330 (let ((selective-display nil))
2331 (cond ((and beg end)
2332 ;; This 'if' is needed because Emacs treats the next empty line
2333 ;; as part of the previous line.
2334 (if (or (> beg (point-max)) (> end (point-max))) ; out of range
2335 ()
2336 (if (and (> end beg) (= (vip-line-pos 'start) end))
2337 (setq end (min (1+ end) (point-max))))
2338 (if (and (> beg end) (= (vip-line-pos 'start) beg))
2339 (setq beg (min (1+ beg) (point-max))))
2340 (<= (count-lines beg end) 1) ))
2341
2342 (t nil))
2343 ))
2344
2345
2346;; Check if the string ends with a newline.
2347(defun vip-end-with-a-newline-p (string)
2348 (or (string= string "")
2349 (= (vip-seq-last-elt string) ?\n)))
2350
2351(defun vip-tmp-insert-at-eob (msg)
2352 (let ((savemax (point-max)))
2353 (goto-char savemax)
2354 (insert msg)
2355 (sit-for 2)
2356 (goto-char savemax) (delete-region (point) (point-max))
2357 ))
2358
2359
2360\f
2361;;; Minibuffer business
2362
2363(defsubst vip-set-minibuffer-style ()
2364 (add-hook 'minibuffer-setup-hook 'vip-minibuffer-setup-sentinel))
2365
2366
2367(defun vip-minibuffer-setup-sentinel ()
2368 (let ((hook (if vip-vi-style-in-minibuffer
2369 'vip-change-state-to-insert
2370 'vip-change-state-to-emacs)))
2371 (funcall hook)
2372
05497fc6 2373 ;; Make sure the minibuffer overlay is kept up-to-date. In XEmacs also
6c2e12f4 2374 ;; guards against the possibility of detaching this overlay.
27571f90 2375 (vip-add-hook 'vip-post-command-hooks 'vip-move-minibuffer-overlay)
6c2e12f4
KH
2376 ))
2377
2378;; Interpret last event in the local map
2379(defun vip-exit-minibuffer ()
2380 (interactive)
2381 (let (command)
2382 (setq command (local-key-binding (char-to-string last-command-char)))
2383 (if command
2384 (command-execute command)
2385 (exit-minibuffer))))
2386
2387
2388(defun vip-set-search-face ()
4af0c23b 2389 (if (not (vip-window-display-p))
6c2e12f4
KH
2390 ()
2391 (defvar vip-search-face
2392 (progn
c968bd13 2393 (add-to-list 'facemenu-unlisted-faces 'vip-search-face)
6c2e12f4
KH
2394 (make-face 'vip-search-face)
2395 (or (face-differs-from-default-p 'vip-search-face)
2396 ;; face wasn't set in .vip or .Xdefaults
2397 (if (vip-can-use-colors "Black" "khaki")
2398 (progn
2399 (set-face-background 'vip-search-face "khaki")
2400 (set-face-foreground 'vip-search-face "Black"))
2401 (copy-face 'italic 'vip-search-face)
2402 (set-face-underline-p 'vip-search-face t)))
2403 'vip-search-face)
2404 "*Face used to flash out the search pattern.")
2405 ))
2406
2407
2408(defun vip-set-minibuffer-faces ()
4af0c23b 2409 (if (not (vip-window-display-p))
6c2e12f4
KH
2410 ()
2411 (defvar vip-minibuffer-emacs-face
2412 (progn
c968bd13 2413 (add-to-list 'facemenu-unlisted-faces 'vip-minibuffer-emacs-face)
6c2e12f4
KH
2414 (make-face 'vip-minibuffer-emacs-face)
2415 (or (face-differs-from-default-p 'vip-minibuffer-emacs-face)
2416 ;; face wasn't set in .vip or .Xdefaults
2417 (if vip-vi-style-in-minibuffer
2418 ;; emacs state is an exception in the minibuffer
2419 (if (vip-can-use-colors "darkseagreen2" "Black")
2420 (progn
2421 (set-face-background
2422 'vip-minibuffer-emacs-face "darkseagreen2")
2423 (set-face-foreground
2424 'vip-minibuffer-emacs-face "Black"))
2425 (copy-face 'highlight 'vip-minibuffer-emacs-face))
2426 ;; emacs state is the main state in the minibuffer
2427 (if (vip-can-use-colors "Black" "pink")
2428 (progn
2429 (set-face-background 'vip-minibuffer-emacs-face "pink")
2430 (set-face-foreground
2431 'vip-minibuffer-emacs-face "Black"))
2432 (copy-face 'italic 'vip-minibuffer-emacs-face))
2433 ))
2434 'vip-minibuffer-emacs-face)
2435 "Face used in the Minibuffer when it is in Emacs state.")
2436
2437 (defvar vip-minibuffer-insert-face
2438 (progn
c968bd13 2439 (add-to-list 'facemenu-unlisted-faces 'vip-minibuffer-insert-face)
6c2e12f4
KH
2440 (make-face 'vip-minibuffer-insert-face)
2441 (or (face-differs-from-default-p 'vip-minibuffer-insert-face)
2442 (if vip-vi-style-in-minibuffer
2443 (if (vip-can-use-colors "Black" "pink")
2444 (progn
2445 (set-face-background 'vip-minibuffer-insert-face "pink")
2446 (set-face-foreground
2447 'vip-minibuffer-insert-face "Black"))
2448 (copy-face 'italic 'vip-minibuffer-insert-face))
2449 ;; If Insert state is an exception
2450 (if (vip-can-use-colors "darkseagreen2" "Black")
2451 (progn
2452 (set-face-background
2453 'vip-minibuffer-insert-face "darkseagreen2")
2454 (set-face-foreground
2455 'vip-minibuffer-insert-face "Black"))
2456 (copy-face 'highlight 'vip-minibuffer-insert-face))
2457 (vip-italicize-face 'vip-minibuffer-insert-face)))
2458 'vip-minibuffer-insert-face)
2459 "Face used in the Minibuffer when it is in Insert state.")
2460
2461 (defvar vip-minibuffer-vi-face
2462 (progn
c968bd13 2463 (add-to-list 'facemenu-unlisted-faces 'vip-minibuffer-vi-face)
6c2e12f4
KH
2464 (make-face 'vip-minibuffer-vi-face)
2465 (or (face-differs-from-default-p 'vip-minibuffer-vi-face)
2466 (if vip-vi-style-in-minibuffer
2467 (if (vip-can-use-colors "Black" "grey")
2468 (progn
2469 (set-face-background 'vip-minibuffer-vi-face "grey")
2470 (set-face-foreground 'vip-minibuffer-vi-face "Black"))
2471 (copy-face 'bold 'vip-minibuffer-vi-face))
2472 (copy-face 'bold 'vip-minibuffer-vi-face)
2473 (invert-face 'vip-minibuffer-vi-face)))
2474 'vip-minibuffer-vi-face)
2475 "Face used in the Minibuffer when it is in Vi state.")
2476
2477 ;; the current face used in the minibuffer
2478 (vip-deflocalvar vip-minibuffer-current-face vip-minibuffer-emacs-face "")
2479 ))
2480
2481
2482\f
2483;;; Reading string with history
2484
2485(defun vip-read-string-with-history (prompt &optional initial
2486 history-var default keymap)
2487 ;; Reads string, prompting with PROMPT and inserting the INITIAL
2488 ;; value. Uses HISTORY-VAR. DEFAULT is the default value to accept if the
2489 ;; input is an empty string. Uses KEYMAP, if given, or the
2490 ;; minibuffer-local-map.
2491 ;; Default value is displayed until the user types something in the
2492 ;; minibuffer.
2493 (let ((minibuffer-setup-hook
2494 '(lambda ()
2495 (if (stringp initial)
2496 (progn
04090c34 2497 ;; don't wait if we have unread events or in kbd macro
d695b318 2498 (or unread-command-events
04090c34 2499 executing-kbd-macro
d695b318 2500 (sit-for 840))
6c2e12f4
KH
2501 (erase-buffer)
2502 (insert initial)))
2503 (vip-minibuffer-setup-sentinel)))
2504 (val "")
2505 (padding "")
2506 temp-msg)
2507
2508 (setq keymap (or keymap minibuffer-local-map)
2509 initial (or initial "")
2510 temp-msg (if default
2511 (format "(default: %s) " default)
2512 ""))
2513
2514 (setq vip-incomplete-ex-cmd nil)
2515 (setq val (read-from-minibuffer prompt
2516 (concat temp-msg initial val padding)
2517 keymap nil history-var))
2518 (setq minibuffer-setup-hook nil
2519 padding (vip-array-to-string (this-command-keys))
2520 temp-msg "")
4af0c23b 2521 ;; the following tries to be smart about what to put in history
6c2e12f4
KH
2522 (if (not (string= val (car (eval history-var))))
2523 (set history-var (cons val (eval history-var))))
2524 (if (or (string= (nth 0 (eval history-var)) (nth 1 (eval history-var)))
2525 (string= (nth 0 (eval history-var)) ""))
2526 (set history-var (cdr (eval history-var))))
4af0c23b
KH
2527 ;; if the user enters nothing but the prev cmd wasn't vip-ex or
2528 ;; vip-command-argument, this means that the user typed something then
2529 ;; erased. Return "" in this case, not the default---default is too
2530 ;; confusing in this case
2531 (cond ((and (string= val "")
2532 (not (memq last-command
2533 (list 'vip-ex 'vip-command-argument t))))
2534 "")
2535 ((string= val "") (or default ""))
2536 (t val))
2537 ))
6c2e12f4
KH
2538
2539
2540\f
2541;; insertion commands
2542
2543;; Called when state changes from Insert Vi command mode.
2544;; Repeats the insertion command if Insert state was entered with prefix
2545;; argument > 1.
2546(defun vip-repeat-insert-command ()
2547 (let ((i-com (car vip-d-com))
2548 (val (nth 1 vip-d-com))
2549 (char (nth 2 vip-d-com)))
2550 (if (and val (> val 1)) ; first check that val is non-nil
2551 (progn
2552 (setq vip-d-com (list i-com (1- val) ?r nil nil nil))
2553 (vip-repeat nil)
2554 (setq vip-d-com (list i-com val char nil nil nil))
2555 ))))
2556
2557(defun vip-insert (arg)
2558 "Insert before point."
2559 (interactive "P")
2560 (vip-set-complex-command-for-undo)
2561 (let ((val (vip-p-val arg))
2562 (com (vip-getcom arg)))
2563 (vip-set-destructive-command (list 'vip-insert val ?r nil nil nil))
2564 (if com
2565 (vip-loop val (vip-yank-last-insertion))
2566 (vip-change-state-to-insert))))
2567
2568(defun vip-append (arg)
2569 "Append after point."
2570 (interactive "P")
2571 (vip-set-complex-command-for-undo)
2572 (let ((val (vip-p-val arg))
2573 (com (vip-getcom arg)))
2574 (vip-set-destructive-command (list 'vip-append val ?r nil nil nil))
2575 (if (not (eolp)) (forward-char))
2576 (if (equal com ?r)
2577 (vip-loop val (vip-yank-last-insertion))
2578 (vip-change-state-to-insert))))
2579
2580(defun vip-Append (arg)
2581 "Append at end of line."
2582 (interactive "P")
2583 (vip-set-complex-command-for-undo)
2584 (let ((val (vip-p-val arg))
2585 (com (vip-getcom arg)))
2586 (vip-set-destructive-command (list 'vip-Append val ?r nil nil nil))
2587 (end-of-line)
2588 (if (equal com ?r)
2589 (vip-loop val (vip-yank-last-insertion))
2590 (vip-change-state-to-insert))))
2591
2592(defun vip-Insert (arg)
2593 "Insert before first non-white."
2594 (interactive "P")
2595 (vip-set-complex-command-for-undo)
2596 (let ((val (vip-p-val arg))
2597 (com (vip-getcom arg)))
2598 (vip-set-destructive-command (list 'vip-Insert val ?r nil nil nil))
2599 (back-to-indentation)
2600 (if (equal com ?r)
2601 (vip-loop val (vip-yank-last-insertion))
2602 (vip-change-state-to-insert))))
2603
2604(defun vip-open-line (arg)
2605 "Open line below."
2606 (interactive "P")
2607 (vip-set-complex-command-for-undo)
2608 (let ((val (vip-p-val arg))
2609 (com (vip-getcom arg)))
2610 (vip-set-destructive-command (list 'vip-open-line val ?r nil nil nil))
2611 (let ((col (current-indentation)))
2612 (if (equal com ?r)
2613 (vip-loop val
2614 (progn
2615 (end-of-line)
2616 (newline 1)
2617 (if vip-auto-indent
2618 (progn (setq vip-cted t) (indent-to col)))
2619 (vip-yank-last-insertion)))
2620 (end-of-line)
2621 (newline 1)
2622 (if vip-auto-indent (progn (setq vip-cted t) (indent-to col)))
2623 (vip-change-state-to-insert)
2624 ))))
2625
2626(defun vip-Open-line (arg)
2627 "Open line above."
2628 (interactive "P")
2629 (vip-set-complex-command-for-undo)
2630 (let ((val (vip-p-val arg))
2631 (com (vip-getcom arg)))
2632 (vip-set-destructive-command (list 'vip-Open-line val ?r nil nil nil))
2633 (let ((col (current-indentation)))
2634 (if (equal com ?r)
2635 (vip-loop val
2636 (progn
2637 (beginning-of-line)
2638 (open-line 1)
2639 (if vip-auto-indent
2640 (progn (setq vip-cted t) (indent-to col)))
2641 (vip-yank-last-insertion)))
2642 (beginning-of-line)
2643 (open-line 1)
2644 (if vip-auto-indent (progn (setq vip-cted t) (indent-to col)))
2645 (vip-change-state-to-insert)))))
2646
2647(defun vip-open-line-at-point (arg)
2648 "Open line at point."
2649 (interactive "P")
2650 (vip-set-complex-command-for-undo)
2651 (let ((val (vip-p-val arg))
2652 (com (vip-getcom arg)))
2653 (vip-set-destructive-command
2654 (list 'vip-open-line-at-point val ?r nil nil nil))
2655 (if (equal com ?r)
2656 (vip-loop val
2657 (progn
2658 (open-line 1)
2659 (vip-yank-last-insertion)))
2660 (open-line 1)
2661 (vip-change-state-to-insert))))
2662
2663(defun vip-substitute (arg)
2664 "Substitute characters."
2665 (interactive "P")
2666 (let ((val (vip-p-val arg))
2667 (com (vip-getcom arg)))
2668 (push-mark nil t)
2669 (forward-char val)
2670 (if (equal com ?r)
2671 (vip-change-subr (mark t) (point))
2672 (vip-change (mark t) (point)))
2673 (vip-set-destructive-command (list 'vip-substitute val ?r nil nil nil))
2674 ))
2675
2676(defun vip-substitute-line (arg)
2677 "Substitute lines."
2678 (interactive "p")
2679 (vip-set-complex-command-for-undo)
2680 (vip-line (cons arg ?C)))
2681
2682;; Prepare for replace
2683(defun vip-start-replace ()
2684 (setq vip-began-as-replace t
2685 vip-sitting-in-replace t
2686 vip-replace-chars-to-delete 0
2687 vip-replace-chars-deleted 0)
27571f90
MK
2688 (vip-add-hook 'vip-after-change-functions 'vip-replace-mode-spy-after t)
2689 (vip-add-hook 'vip-before-change-functions 'vip-replace-mode-spy-before t)
6c2e12f4
KH
2690 ;; this will get added repeatedly, but no harm
2691 (add-hook 'after-change-functions 'vip-after-change-sentinel t)
2692 (add-hook 'before-change-functions 'vip-before-change-sentinel t)
2693 (vip-move-marker-locally 'vip-last-posn-in-replace-region
2694 (vip-replace-start))
27571f90
MK
2695 (vip-add-hook
2696 'vip-post-command-hooks 'vip-replace-state-post-command-sentinel t)
2697 (vip-add-hook
2698 'vip-pre-command-hooks 'vip-replace-state-pre-command-sentinel t)
6c2e12f4
KH
2699 )
2700
2701;; Runs vip-after-change-functions inside after-change-functions
2702(defun vip-after-change-sentinel (beg end len)
2703 (let ((list vip-after-change-functions))
2704 (while list
2705 (funcall (car list) beg end len)
2706 (setq list (cdr list)))))
2707
2708;; Runs vip-before-change-functions inside before-change-functions
2709(defun vip-before-change-sentinel (beg end)
2710 (let ((list vip-before-change-functions))
2711 (while list
2712 (funcall (car list) beg end)
2713 (setq list (cdr list)))))
2714
27571f90 2715(defsubst vip-post-command-sentinel ()
6c2e12f4
KH
2716 (run-hooks 'vip-post-command-hooks))
2717
27571f90 2718(defsubst vip-pre-command-sentinel ()
6c2e12f4
KH
2719 (run-hooks 'vip-pre-command-hooks))
2720
2721;; Needed so that Viper will be able to figure the last inserted
2722;; chunk of text with reasonable accuracy.
27571f90 2723(defsubst vip-insert-state-post-command-sentinel ()
6c2e12f4
KH
2724 (if (and (memq vip-current-state '(insert-state replace-state))
2725 vip-insert-point
2726 (>= (point) vip-insert-point))
2727 (setq vip-last-posn-while-in-insert-state (point-marker)))
2728 (if (and (eq this-command 'dabbrev-expand)
2729 (integerp vip-pre-command-point)
2730 (> vip-insert-point vip-pre-command-point))
2731 (move-marker vip-insert-point vip-pre-command-point))
2732 )
2733
27571f90 2734(defsubst vip-insert-state-pre-command-sentinel ()
6c2e12f4
KH
2735 (if (and (eq this-command 'dabbrev-expand)
2736 (markerp vip-insert-point)
2737 (marker-position vip-insert-point))
2738 (setq vip-pre-command-point (marker-position vip-insert-point))))
2739
27571f90 2740(defsubst vip-R-state-post-command-sentinel ()
4af0c23b
KH
2741 ;; Restoring cursor color is needed despite
2742 ;; vip-replace-state-pre-command-sentinel: When you jump to another buffer in
2743 ;; another frame, the pre-command hook won't change cursor color to default
2744 ;; in that other frame. So, if the second frame cursor was red and we set
2745 ;; the point outside the replacement region, then the cursor color will
2746 ;; remain red. Restoring the default, below, prevents this.
6c2e12f4 2747 (if (and (<= (vip-replace-start) (point))
4af0c23b
KH
2748 (<= (point) (vip-replace-end)))
2749 (vip-change-cursor-color vip-replace-overlay-cursor-color)
2750 (vip-restore-cursor-color)
2751 ))
6c2e12f4 2752
4af0c23b
KH
2753;; to speed up, don't change cursor color before self-insert
2754;; and common move commands
27571f90 2755(defsubst vip-replace-state-pre-command-sentinel ()
4af0c23b
KH
2756 (or (memq this-command '(self-insert-command))
2757 (memq (vip-event-key last-command-event)
2758 '(up down left right (meta f) (meta b)
2759 (control n) (control p) (control f) (control b)))
2760 (vip-restore-cursor-color)))
6c2e12f4
KH
2761
2762(defun vip-replace-state-post-command-sentinel ()
4af0c23b
KH
2763 ;; Restoring cursor color is needed despite
2764 ;; vip-replace-state-pre-command-sentinel: When one jumps to another buffer
2765 ;; in another frame, the pre-command hook won't change cursor color to
2766 ;; default in that other frame. So, if the second frame cursor was red and
2767 ;; we set the point outside the replacement region, then the cursor color
27571f90
MK
2768 ;; will remain red. Restoring the default, below, fixes this problem.
2769 ;;
2770 ;; We optimize for self-insert-command's here, since they either don't change
2771 ;; cursor color or, if they terminate replace mode, the color will be changed
2772 ;; in vip-finish-change
2773 (or (memq this-command '(self-insert-command))
2774 (vip-restore-cursor-color))
6c2e12f4
KH
2775 (cond
2776 ((eq vip-current-state 'replace-state)
2777 ;; delete characters to compensate for inserted chars.
4af0c23b 2778 (let ((replace-boundary (vip-replace-end)))
6c2e12f4
KH
2779 (save-excursion
2780 (goto-char vip-last-posn-in-replace-region)
2781 (delete-char vip-replace-chars-to-delete)
2782 (setq vip-replace-chars-to-delete 0
2783 vip-replace-chars-deleted 0)
2784 ;; terminate replace mode if reached replace limit
2785 (if (= vip-last-posn-in-replace-region
2786 (vip-replace-end))
2787 (vip-finish-change vip-last-posn-in-replace-region)))
2788
2789 (if (and (<= (vip-replace-start) (point))
2790 (<= (point) replace-boundary))
2791 (progn
2792 ;; the state may have changed in vip-finish-change above
2793 (if (eq vip-current-state 'replace-state)
2794 (vip-change-cursor-color vip-replace-overlay-cursor-color))
2795 (setq vip-last-posn-in-replace-region (point-marker))))
2796 ))
2797
2798 (t ;; terminate replace mode if changed Viper states.
4af0c23b 2799 (vip-finish-change vip-last-posn-in-replace-region))))
6c2e12f4
KH
2800
2801
2802;; checks how many chars were deleted by the last change
2803(defun vip-replace-mode-spy-before (beg end)
4af0c23b
KH
2804 (setq vip-replace-chars-deleted
2805 (- end beg
2806 (max 0 (- end (vip-replace-end)))
2807 (max 0 (- (vip-replace-start) beg))
2808 )))
6c2e12f4
KH
2809
2810;; Invoked as an after-change-function to set up parameters of the last change
2811(defun vip-replace-mode-spy-after (beg end length)
2812 (if (memq vip-intermediate-command '(repeating-insertion-from-ring))
2813 (progn
2814 (setq vip-replace-chars-to-delete 0)
2815 (vip-move-marker-locally
2816 'vip-last-posn-in-replace-region (point)))
2817
2818 (let (beg-col end-col real-end chars-to-delete)
2819 (setq real-end (min end (vip-replace-end)))
2820 (save-excursion
2821 (goto-char beg)
2822 (setq beg-col (current-column))
2823 (goto-char real-end)
2824 (setq end-col (current-column)))
2825
2826 ;; If beg of change is outside the replacement region, then don't
2827 ;; delete anything in the repl region (set chars-to-delete to 0).
2828 ;;
2829 ;; This works fine except that we have to take special care of
2830 ;; dabbrev-expand. The problem stems from new-dabbrev.el, which
2831 ;; sometimes simply shifts the repl region rightwards, without
2832 ;; deleting an equal amount of characters.
2833 ;;
2834 ;; The reason why new-dabbrev.el causes this are this:
05497fc6 2835 ;; if one dynamically completes a partial word that starts before the
6c2e12f4
KH
2836 ;; replacement region (but ends inside)then new-dabbrev.el first
2837 ;; moves cursor backwards, to the beginning of the word to be
2838 ;; completed (say, pt A). Then it inserts the
2839 ;; completed word and then deletes the old, incomplete part.
2840 ;; Since the complete word is inserted at position before the repl
2841 ;; region, the next If-statement would have set chars-to-delete to 0
2842 ;; unless we check for the current command, which must be
2843 ;; dabbrev-expand.
2844 ;;
2845 ;; We should be able deal with these problems in a better way
2846 ;; when emacs will have overlays with sticky back ends.
2847 ;; In fact, it would be also useful to add overlays for insert
2848 ;; regions as well, since this will let us capture the situation when
2849 ;; dabbrev-expand goes back past the insertion point to find the
2850 ;; beginning of the word to be expanded.
2851 (if (or (and (<= (vip-replace-start) beg)
2852 (<= beg (vip-replace-end)))
2853 (and (= length 0) (eq this-command 'dabbrev-expand)))
2854 (setq chars-to-delete
2855 (max (- end-col beg-col) (- real-end beg) 0))
2856 (setq chars-to-delete 0))
2857
2858 ;; if beg = last change position, it means that we are within the
2859 ;; same command that does multiple changes. Moreover, it means
2860 ;; that we have two subsequent changes (insert/delete) that
2861 ;; complement each other.
2862 (if (= beg (marker-position vip-last-posn-in-replace-region))
2863 (setq vip-replace-chars-to-delete
2864 (- (+ chars-to-delete vip-replace-chars-to-delete)
2865 vip-replace-chars-deleted))
2866 (setq vip-replace-chars-to-delete chars-to-delete))
2867
2868 (vip-move-marker-locally
2869 'vip-last-posn-in-replace-region
2870 (max (if (> end (vip-replace-end)) (vip-replace-start) end)
2871 (or (marker-position vip-last-posn-in-replace-region)
2872 (vip-replace-start))
2873 ))
2874
2875 (setq vip-replace-chars-to-delete
2876 (max 0 (min vip-replace-chars-to-delete
2877 (- (vip-replace-end)
2878 vip-last-posn-in-replace-region))))
2879 )))
2880
2881
2882;; Delete stuff between posn and the end of vip-replace-overlay-marker, if
2883;; posn is within the overlay.
2884(defun vip-finish-change (posn)
27571f90
MK
2885 (vip-remove-hook 'vip-after-change-functions 'vip-replace-mode-spy-after)
2886 (vip-remove-hook 'vip-before-change-functions 'vip-replace-mode-spy-before)
2887 (vip-remove-hook 'vip-post-command-hooks
2888 'vip-replace-state-post-command-sentinel)
2889 (vip-remove-hook
2890 'vip-pre-command-hooks 'vip-replace-state-pre-command-sentinel)
6c2e12f4
KH
2891 (vip-restore-cursor-color)
2892 (setq vip-sitting-in-replace nil) ; just in case we'll need to know it
2893 (save-excursion
2894 (if (and
2895 vip-replace-overlay
2896 (>= posn (vip-replace-start))
2897 (< posn (vip-replace-end)))
2898 (delete-region posn (vip-replace-end)))
2899 )
2900
2901 (if (eq vip-current-state 'replace-state)
2902 (vip-downgrade-to-insert))
2903 ;; replace mode ended => nullify vip-last-posn-in-replace-region
2904 (vip-move-marker-locally 'vip-last-posn-in-replace-region nil)
2905 (vip-hide-replace-overlay)
2906 (vip-refresh-mode-line)
2907 (vip-put-string-on-kill-ring vip-last-replace-region)
2908 )
2909
4af0c23b 2910;; Make STRING be the first element of the kill ring.
6c2e12f4 2911(defun vip-put-string-on-kill-ring (string)
6c2e12f4
KH
2912 (setq kill-ring (cons string kill-ring))
2913 (if (> (length kill-ring) kill-ring-max)
2914 (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil))
2915 (setq kill-ring-yank-pointer kill-ring))
2916
2917(defun vip-finish-R-mode ()
27571f90
MK
2918 (vip-remove-hook 'vip-post-command-hooks 'vip-R-state-post-command-sentinel)
2919 (vip-remove-hook
2920 'vip-pre-command-hooks 'vip-replace-state-pre-command-sentinel)
6c2e12f4
KH
2921 (vip-downgrade-to-insert))
2922
2923(defun vip-start-R-mode ()
2924 ;; Leave arg as 1, not t: XEmacs insists that it must be a pos number
2925 (overwrite-mode 1)
27571f90
MK
2926 (vip-add-hook
2927 'vip-post-command-hooks 'vip-R-state-post-command-sentinel t)
2928 (vip-add-hook
2929 'vip-pre-command-hooks 'vip-replace-state-pre-command-sentinel t)
6c2e12f4
KH
2930 )
2931
2932
2933
2934(defun vip-replace-state-exit-cmd ()
2935 "Binding for keys that cause Replace state to switch to Vi or to Insert.
2936These keys are ESC, RET, and LineFeed"
2937 (interactive)
2938 (if overwrite-mode ;; If you are in replace mode invoked via 'R'
2939 (vip-finish-R-mode)
2940 (vip-finish-change vip-last-posn-in-replace-region))
2941 (let (com)
2942 (if (eq this-command 'vip-intercept-ESC-key)
2943 (setq com 'vip-exit-insert-state)
2944 (vip-set-unread-command-events last-input-char)
2945 (setq com (key-binding (read-key-sequence nil))))
2946
2947 (condition-case conds
2948 (command-execute com)
2949 (error
2950 (vip-message-conditions conds)))
2951 )
2952 (vip-hide-replace-overlay))
2953
2954
4af0c23b
KH
2955;; This is the function bound to 'R'---unlimited replace.
2956;; Similar to Emacs's own overwrite-mode.
6c2e12f4 2957(defun vip-overwrite (arg)
4af0c23b 2958 "Begin overwrite mode."
6c2e12f4
KH
2959 (interactive "P")
2960 (let ((val (vip-p-val arg))
2961 (com (vip-getcom arg)) (len))
2962 (vip-set-destructive-command (list 'vip-overwrite val ?r nil nil nil))
2963 (if com
2964 (progn
2965 ;; Viper saves inserted text in vip-last-insertion
2966 (setq len (length vip-last-insertion))
2967 (delete-char len)
2968 (vip-loop val (vip-yank-last-insertion)))
2969 (setq last-command 'vip-overwrite)
2970 (vip-set-complex-command-for-undo)
2971 (vip-set-replace-overlay (point) (vip-line-pos 'end))
2972 (vip-change-state-to-replace)
2973 )))
2974
2975\f
2976;; line commands
2977
2978(defun vip-line (arg)
2979 (let ((val (car arg))
2980 (com (cdr arg)))
2981 (vip-move-marker-locally 'vip-com-point (point))
2982 (if (not (eobp))
4af0c23b 2983 (vip-next-line-carefully (1- val)))
6c2e12f4
KH
2984 ;; this ensures that dd, cc, D, yy will do the right thing on the last
2985 ;; line of buffer when this line has no \n.
2986 (vip-add-newline-at-eob-if-necessary)
2987 (vip-execute-com 'vip-line val com))
2988 (if (and (eobp) (not (bobp))) (forward-line -1))
2989 )
2990
2991(defun vip-yank-line (arg)
2992 "Yank ARG lines (in Vi's sense)."
2993 (interactive "P")
2994 (let ((val (vip-p-val arg)))
2995 (vip-line (cons val ?Y))))
2996
2997\f
2998;; region commands
2999
3000(defun vip-region (arg)
4af0c23b 3001 "Execute command on a region."
6c2e12f4
KH
3002 (interactive "P")
3003 (let ((val (vip-P-val arg))
3004 (com (vip-getcom arg)))
3005 (vip-move-marker-locally 'vip-com-point (point))
3006 (exchange-point-and-mark)
3007 (vip-execute-com 'vip-region val com)))
3008
3009(defun vip-Region (arg)
4af0c23b 3010 "Execute command on a Region."
6c2e12f4
KH
3011 (interactive "P")
3012 (let ((val (vip-P-val arg))
3013 (com (vip-getCom arg)))
3014 (vip-move-marker-locally 'vip-com-point (point))
3015 (exchange-point-and-mark)
3016 (vip-execute-com 'vip-Region val com)))
3017
3018(defun vip-replace-char (arg)
3019 "Replace the following ARG chars by the character read."
3020 (interactive "P")
27571f90 3021 (if (and (eolp) (bolp)) (error "No character to replace here"))
6c2e12f4
KH
3022 (let ((val (vip-p-val arg))
3023 (com (vip-getcom arg)))
04090c34 3024 (vip-replace-char-subr com val)
6c2e12f4
KH
3025 (if (and (eolp) (not (bolp))) (forward-char 1))
3026 (vip-set-destructive-command
3027 (list 'vip-replace-char val ?r nil vip-d-char nil))
3028 ))
3029
04090c34
MK
3030(defun vip-replace-char-subr (com arg)
3031 (let ((take-care-of-iso-accents
3032 (and (boundp 'iso-accents-mode) vip-automatic-iso-accents))
3033 char)
3034 (setq char (if (equal com ?r)
3035 vip-d-char
3036 (read-char)))
3037 (if (and take-care-of-iso-accents (memq char '(?' ?\" ?^ ?~)))
3038 ;; get European characters
3039 (progn
3040 (iso-accents-mode 1)
3041 (vip-set-unread-command-events char)
3042 (setq char (aref (read-key-sequence nil) 0))
3043 (iso-accents-mode -1)))
3044 (delete-char arg t)
3045 (setq vip-d-char char)
3046 (vip-loop (if (> arg 0) arg (- arg))
6c2e12f4 3047 (if (eq char ?\C-m) (insert "\n") (insert char)))
04090c34 3048 (backward-char arg)))
6c2e12f4 3049
6c2e12f4
KH
3050\f
3051;; basic cursor movement. j, k, l, h commands.
3052
3053(defun vip-forward-char (arg)
3054 "Move point right ARG characters (left if ARG negative).
3055On reaching end of line, stop and signal error."
3056 (interactive "P")
d695b318 3057 (vip-leave-region-active)
6c2e12f4
KH
3058 (let ((val (vip-p-val arg))
3059 (com (vip-getcom arg)))
3060 (if com (vip-move-marker-locally 'vip-com-point (point)))
3061 (if vip-ex-style-motion
3062 (progn
3063 ;; the boundary condition check gets weird here because
3064 ;; forward-char may be the parameter of a delete, and 'dl' works
3065 ;; just like 'x' for the last char on a line, so we have to allow
3066 ;; the forward motion before the 'vip-execute-com', but, of
3067 ;; course, 'dl' doesn't work on an empty line, so we have to
3068 ;; catch that condition before 'vip-execute-com'
3069 (if (and (eolp) (bolp)) (error "") (forward-char val))
3070 (if com (vip-execute-com 'vip-forward-char val com))
3071 (if (eolp) (progn (backward-char 1) (error ""))))
3072 (forward-char val)
3073 (if com (vip-execute-com 'vip-forward-char val com)))))
3074
3075(defun vip-backward-char (arg)
3076 "Move point left ARG characters (right if ARG negative).
3077On reaching beginning of line, stop and signal error."
3078 (interactive "P")
d695b318 3079 (vip-leave-region-active)
6c2e12f4
KH
3080 (let ((val (vip-p-val arg))
3081 (com (vip-getcom arg)))
3082 (if com (vip-move-marker-locally 'vip-com-point (point)))
3083 (if vip-ex-style-motion
3084 (progn
3085 (if (bolp) (error "") (backward-char val))
3086 (if com (vip-execute-com 'vip-backward-char val com)))
3087 (backward-char val)
3088 (if com (vip-execute-com 'vip-backward-char val com)))))
3089
4af0c23b 3090;; Like forward-char, but doesn't move at end of buffer.
6c2e12f4 3091(defun vip-forward-char-carefully (&optional arg)
6c2e12f4
KH
3092 (setq arg (or arg 1))
3093 (if (>= (point-max) (+ (point) arg))
3094 (forward-char arg)
3095 (goto-char (point-max))))
3096
4af0c23b 3097;; Like backward-char, but doesn't move at end of buffer.
6c2e12f4 3098(defun vip-backward-char-carefully (&optional arg)
6c2e12f4
KH
3099 (setq arg (or arg 1))
3100 (if (<= (point-min) (- (point) arg))
3101 (backward-char arg)
3102 (goto-char (point-min))))
3103
4af0c23b
KH
3104(defun vip-next-line-carefully (arg)
3105 (condition-case nil
3106 (next-line arg)
3107 (error nil)))
3108
6c2e12f4
KH
3109
3110\f
3111;;; Word command
3112
3113;; Words are formed from alpha's and nonalphas - <sp>,\t\n are separators
3114;; for word movement. When executed with a destructive command, \n is
3115;; usually left untouched for the last word.
04090c34
MK
3116;; Viper uses syntax table to determine what is a word and what is a
3117;; separator. However, \n is always a separator. Also, if vip-syntax-preference
3118;; is 'vi, then `_' is part of the word.
6c2e12f4
KH
3119
3120;; skip only one \n
3121(defun vip-skip-separators (forward)
3122 (if forward
3123 (progn
04090c34 3124 (vip-skip-all-separators-forward 'within-line)
6c2e12f4
KH
3125 (if (looking-at "\n")
3126 (progn
3127 (forward-char)
04090c34
MK
3128 (vip-skip-all-separators-forward 'within-line))))
3129 (vip-skip-all-separators-backward 'within-line)
6c2e12f4
KH
3130 (backward-char)
3131 (if (looking-at "\n")
04090c34 3132 (vip-skip-all-separators-backward 'within-line)
6c2e12f4
KH
3133 (forward-char))))
3134
6c2e12f4
KH
3135(defun vip-forward-word-kernel (val)
3136 (while (> val 0)
04090c34
MK
3137 (cond ((vip-looking-at-alpha)
3138 (vip-skip-alpha-forward "_")
6c2e12f4 3139 (vip-skip-separators t))
04090c34 3140 ((vip-looking-at-separator)
6c2e12f4 3141 (vip-skip-separators t))
04090c34
MK
3142 ((not (vip-looking-at-alphasep))
3143 (vip-skip-nonalphasep-forward)
6c2e12f4
KH
3144 (vip-skip-separators t)))
3145 (setq val (1- val))))
3146
4af0c23b 3147;; first search backward for pat. Then skip chars backwards using aux-pat
6c2e12f4
KH
3148(defun vip-fwd-skip (pat aux-pat lim)
3149 (if (and (save-excursion
3150 (re-search-backward pat lim t))
3151 (= (point) (match-end 0)))
3152 (goto-char (match-beginning 0)))
3153 (skip-chars-backward aux-pat lim)
3154 (if (= (point) lim)
3155 (vip-forward-char-carefully))
3156 )
3157
3158
3159(defun vip-forward-word (arg)
3160 "Forward word."
3161 (interactive "P")
d695b318 3162 (vip-leave-region-active)
6c2e12f4
KH
3163 (let ((val (vip-p-val arg))
3164 (com (vip-getcom arg)))
3165 (if com (vip-move-marker-locally 'vip-com-point (point)))
3166 (vip-forward-word-kernel val)
3167 (if com (progn
4af0c23b 3168 (cond ((memq com (list ?c (- ?c)))
6c2e12f4 3169 (vip-fwd-skip "\n[ \t]*" " \t" vip-com-point))
4af0c23b
KH
3170 ;; Yank words including the whitespace, but not newline
3171 ((memq com (list ?y (- ?y)))
3172 (vip-fwd-skip "\n[ \t]*" "" vip-com-point))
6c2e12f4
KH
3173 ((vip-dotable-command-p com)
3174 (vip-fwd-skip "\n[ \t]*" "" vip-com-point)))
3175 (vip-execute-com 'vip-forward-word val com)))))
3176
3177
3178(defun vip-forward-Word (arg)
4af0c23b 3179 "Forward word delimited by white characters."
6c2e12f4 3180 (interactive "P")
d695b318 3181 (vip-leave-region-active)
6c2e12f4
KH
3182 (let ((val (vip-p-val arg))
3183 (com (vip-getcom arg)))
3184 (if com (vip-move-marker-locally 'vip-com-point (point)))
3185 (vip-loop val
3186 (progn
04090c34 3187 (vip-skip-nonseparators 'forward)
6c2e12f4
KH
3188 (vip-skip-separators t)))
3189 (if com (progn
4af0c23b 3190 (cond ((memq com (list ?c (- ?c)))
6c2e12f4 3191 (vip-fwd-skip "\n[ \t]*" " \t" vip-com-point))
4af0c23b
KH
3192 ;; Yank words including the whitespace, but not newline
3193 ((memq com (list ?y (- ?y)))
3194 (vip-fwd-skip "\n[ \t]*" "" vip-com-point))
6c2e12f4
KH
3195 ((vip-dotable-command-p com)
3196 (vip-fwd-skip "\n[ \t]*" "" vip-com-point)))
3197 (vip-execute-com 'vip-forward-Word val com)))))
3198
3199
3200;; this is a bit different from Vi, but Vi's end of word
3201;; makes no sense whatsoever
3202(defun vip-end-of-word-kernel ()
3203 (if (vip-end-of-word-p) (forward-char))
04090c34
MK
3204 (if (vip-looking-at-separator)
3205 (vip-skip-all-separators-forward))
6c2e12f4 3206
04090c34
MK
3207 (cond ((vip-looking-at-alpha) (vip-skip-alpha-forward "_"))
3208 ((not (vip-looking-at-alphasep)) (vip-skip-nonalphasep-forward)))
6c2e12f4
KH
3209 (vip-backward-char-carefully))
3210
3211(defun vip-end-of-word-p ()
04090c34
MK
3212 (or (eobp)
3213 (save-excursion
3214 (cond ((vip-looking-at-alpha)
3215 (forward-char)
3216 (not (vip-looking-at-alpha)))
3217 ((not (vip-looking-at-alphasep))
3218 (forward-char)
3219 (vip-looking-at-alphasep))))))
6c2e12f4 3220
6c2e12f4
KH
3221
3222(defun vip-end-of-word (arg &optional careful)
3223 "Move point to end of current word."
3224 (interactive "P")
d695b318 3225 (vip-leave-region-active)
6c2e12f4
KH
3226 (let ((val (vip-p-val arg))
3227 (com (vip-getcom arg)))
3228 (if com (vip-move-marker-locally 'vip-com-point (point)))
3229 (vip-loop val (vip-end-of-word-kernel))
3230 (if com
3231 (progn
3232 (forward-char)
3233 (vip-execute-com 'vip-end-of-word val com)))))
3234
3235(defun vip-end-of-Word (arg)
3236 "Forward to end of word delimited by white character."
3237 (interactive "P")
d695b318 3238 (vip-leave-region-active)
6c2e12f4
KH
3239 (let ((val (vip-p-val arg))
3240 (com (vip-getcom arg)))
3241 (if com (vip-move-marker-locally 'vip-com-point (point)))
3242 (vip-loop val
04090c34
MK
3243 (progn
3244 (vip-end-of-word-kernel)
3245 (vip-skip-nonseparators 'forward)
3246 (backward-char)))
6c2e12f4
KH
3247 (if com
3248 (progn
3249 (forward-char)
3250 (vip-execute-com 'vip-end-of-Word val com)))))
3251
3252(defun vip-backward-word-kernel (val)
3253 (while (> val 0)
3254 (backward-char)
04090c34
MK
3255 (cond ((vip-looking-at-alpha)
3256 (vip-skip-alpha-backward "_"))
3257 ((vip-looking-at-separator)
6c2e12f4
KH
3258 (forward-char)
3259 (vip-skip-separators nil)
3260 (backward-char)
04090c34
MK
3261 (cond ((vip-looking-at-alpha)
3262 (vip-skip-alpha-backward "_"))
3263 ((not (vip-looking-at-alphasep))
3264 (vip-skip-nonalphasep-backward))
6c2e12f4 3265 (t (forward-char))))
04090c34
MK
3266 ((not (vip-looking-at-alphasep))
3267 (vip-skip-nonalphasep-backward)))
6c2e12f4
KH
3268 (setq val (1- val))))
3269
3270(defun vip-backward-word (arg)
3271 "Backward word."
3272 (interactive "P")
d695b318 3273 (vip-leave-region-active)
6c2e12f4
KH
3274 (let ((val (vip-p-val arg))
3275 (com (vip-getcom arg)))
3276 (if com
3277 (let (i)
3278 (if (setq i (save-excursion (backward-char) (looking-at "\n")))
3279 (backward-char))
3280 (vip-move-marker-locally 'vip-com-point (point))
3281 (if i (forward-char))))
3282 (vip-backward-word-kernel val)
3283 (if com (vip-execute-com 'vip-backward-word val com))))
3284
3285(defun vip-backward-Word (arg)
3286 "Backward word delimited by white character."
3287 (interactive "P")
d695b318 3288 (vip-leave-region-active)
6c2e12f4
KH
3289 (let ((val (vip-p-val arg))
3290 (com (vip-getcom arg)))
3291 (if com
3292 (let (i)
3293 (if (setq i (save-excursion (backward-char) (looking-at "\n")))
3294 (backward-char))
3295 (vip-move-marker-locally 'vip-com-point (point))
3296 (if i (forward-char))))
3297 (vip-loop val
3298 (progn
3299 (vip-skip-separators nil)
04090c34 3300 (vip-skip-nonseparators 'backward)))
6c2e12f4
KH
3301 (if com (vip-execute-com 'vip-backward-Word val com))))
3302
3303
3304\f
3305;; line commands
3306
3307(defun vip-beginning-of-line (arg)
3308 "Go to beginning of line."
3309 (interactive "P")
d695b318 3310 (vip-leave-region-active)
6c2e12f4
KH
3311 (let ((val (vip-p-val arg))
3312 (com (vip-getcom arg)))
3313 (if com (vip-move-marker-locally 'vip-com-point (point)))
3314 (beginning-of-line val)
3315 (if com (vip-execute-com 'vip-beginning-of-line val com))))
3316
3317(defun vip-bol-and-skip-white (arg)
3318 "Beginning of line at first non-white character."
3319 (interactive "P")
d695b318 3320 (vip-leave-region-active)
6c2e12f4
KH
3321 (let ((val (vip-p-val arg))
3322 (com (vip-getcom arg)))
3323 (if com (vip-move-marker-locally 'vip-com-point (point)))
3324 (forward-to-indentation (1- val))
3325 (if com (vip-execute-com 'vip-bol-and-skip-white val com))))
3326
3327(defun vip-goto-eol (arg)
3328 "Go to end of line."
3329 (interactive "P")
d695b318 3330 (vip-leave-region-active)
6c2e12f4
KH
3331 (let ((val (vip-p-val arg))
3332 (com (vip-getcom arg)))
3333 (if com (vip-move-marker-locally 'vip-com-point (point)))
3334 (end-of-line val)
3335 (if com (vip-execute-com 'vip-goto-eol val com))
3336 (if vip-ex-style-motion
3337 (if (and (eolp) (not (bolp))
3338 ;; a fix for vip-change-to-eol
3339 (not (equal vip-current-state 'insert-state)))
3340 (backward-char 1)
3341 ))))
3342
3343
3344(defun vip-goto-col (arg)
3345 "Go to ARG's column."
3346 (interactive "P")
d695b318 3347 (vip-leave-region-active)
6c2e12f4
KH
3348 (let ((val (vip-p-val arg))
3349 (com (vip-getcom arg)))
3350 (save-excursion
3351 (end-of-line)
3352 (if (> val (1+ (current-column))) (error "")))
3353 (if com (vip-move-marker-locally 'vip-com-point (point)))
3354 (beginning-of-line)
3355 (forward-char (1- val))
3356 (if com (vip-execute-com 'vip-goto-col val com))))
3357
3358
3359(defun vip-next-line (arg)
3360 "Go to next line."
3361 (interactive "P")
d695b318 3362 (vip-leave-region-active)
6c2e12f4
KH
3363 (let ((val (vip-p-val arg))
3364 (com (vip-getCom arg)))
3365 (if com (vip-move-marker-locally 'vip-com-point (point)))
3366 (next-line val)
3367 (if vip-ex-style-motion
3368 (if (and (eolp) (not (bolp))) (backward-char 1)))
3369 (setq this-command 'next-line)
3370 (if com (vip-execute-com 'vip-next-line val com))))
3371
3372(defun vip-next-line-at-bol (arg)
3373 "Next line at beginning of line."
3374 (interactive "P")
d695b318 3375 (vip-leave-region-active)
6c2e12f4
KH
3376 (save-excursion
3377 (end-of-line)
3378 (if (eobp) (error "Last line in buffer")))
3379 (let ((val (vip-p-val arg))
3380 (com (vip-getCom arg)))
3381 (if com (vip-move-marker-locally 'vip-com-point (point)))
3382 (forward-line val)
3383 (back-to-indentation)
3384 (if com (vip-execute-com 'vip-next-line-at-bol val com))))
3385
3386(defun vip-previous-line (arg)
3387 "Go to previous line."
3388 (interactive "P")
d695b318 3389 (vip-leave-region-active)
6c2e12f4
KH
3390 (let ((val (vip-p-val arg))
3391 (com (vip-getCom arg)))
3392 (if com (vip-move-marker-locally 'vip-com-point (point)))
3393 (previous-line val)
3394 (if vip-ex-style-motion
3395 (if (and (eolp) (not (bolp))) (backward-char 1)))
3396 (setq this-command 'previous-line)
3397 (if com (vip-execute-com 'vip-previous-line val com))))
3398
3399
3400(defun vip-previous-line-at-bol (arg)
3401 "Previous line at beginning of line."
3402 (interactive "P")
d695b318 3403 (vip-leave-region-active)
6c2e12f4
KH
3404 (save-excursion
3405 (beginning-of-line)
3406 (if (bobp) (error "First line in buffer")))
3407 (let ((val (vip-p-val arg))
3408 (com (vip-getCom arg)))
3409 (if com (vip-move-marker-locally 'vip-com-point (point)))
3410 (forward-line (- val))
3411 (back-to-indentation)
3412 (if com (vip-execute-com 'vip-previous-line val com))))
3413
3414(defun vip-change-to-eol (arg)
3415 "Change to end of line."
3416 (interactive "P")
3417 (vip-goto-eol (cons arg ?c)))
3418
3419(defun vip-kill-line (arg)
3420 "Delete line."
3421 (interactive "P")
3422 (vip-goto-eol (cons arg ?d)))
3423
3424(defun vip-erase-line (arg)
3425 "Erase line."
3426 (interactive "P")
3427 (vip-beginning-of-line (cons arg ?d)))
3428
3429\f
4af0c23b 3430;;; Moving around
6c2e12f4
KH
3431
3432(defun vip-goto-line (arg)
3433 "Go to ARG's line. Without ARG go to end of buffer."
3434 (interactive "P")
3435 (let ((val (vip-P-val arg))
3436 (com (vip-getCom arg)))
3437 (vip-move-marker-locally 'vip-com-point (point))
3438 (vip-deactivate-mark)
3439 (push-mark nil t)
3440 (if (null val)
3441 (goto-char (point-max))
3442 (goto-char (point-min))
3443 (forward-line (1- val)))
4af0c23b
KH
3444
3445 ;; positioning is done twice: before and after command execution
6c2e12f4
KH
3446 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
3447 (back-to-indentation)
4af0c23b
KH
3448
3449 (if com (vip-execute-com 'vip-goto-line val com))
3450
3451 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
3452 (back-to-indentation)
3453 ))
6c2e12f4 3454
4af0c23b
KH
3455;; Find ARG's occurrence of CHAR on the current line.
3456;; If FORWARD then search is forward, otherwise backward. OFFSET is used to
3457;; adjust point after search.
6c2e12f4 3458(defun vip-find-char (arg char forward offset)
6c2e12f4
KH
3459 (or (char-or-string-p char) (error ""))
3460 (let ((arg (if forward arg (- arg)))
3461 (cmd (if (eq vip-intermediate-command 'vip-repeat)
3462 (nth 5 vip-d-com)
3463 (vip-array-to-string (this-command-keys))))
3464 point)
3465 (save-excursion
3466 (save-restriction
3467 (if (> arg 0)
3468 (narrow-to-region
3469 ;; forward search begins here
3470 (if (eolp) (error "Command `%s': At end of line" cmd) (point))
3471 ;; forward search ends here
3472 (progn (end-of-line) (point)))
3473 (narrow-to-region
3474 ;; backward search begins from here
3475 (if (bolp)
3476 (error "Command `%s': At beginning of line" cmd) (point))
3477 ;; backward search ends here
3478 (progn (beginning-of-line) (point))))
3479 ;; if arg > 0, point is forwarded before search.
3480 (if (> arg 0) (goto-char (1+ (point-min)))
3481 (goto-char (point-max)))
3482 (if (let ((case-fold-search nil))
3483 (search-forward (char-to-string char) nil 0 arg))
3484 (setq point (point))
3485 (error "Command `%s': `%c' not found" cmd char))))
3486 (goto-char (+ point (if (> arg 0) (if offset -2 -1) (if offset 1 0))))))
3487
3488(defun vip-find-char-forward (arg)
3489 "Find char on the line.
3490If called interactively read the char to find from the terminal, and if
3491called from vip-repeat, the char last used is used. This behaviour is
3492controlled by the sign of prefix numeric value."
3493 (interactive "P")
3494 (let ((val (vip-p-val arg))
3495 (com (vip-getcom arg)))
3496 (if (> val 0)
3497 ;; this means that the function was called interactively
3498 (setq vip-f-char (read-char)
3499 vip-f-forward t
3500 vip-f-offset nil)
3501 ;; vip-repeat --- set vip-F-char from command-keys
3502 (setq vip-F-char (if (stringp (nth 5 vip-d-com))
3503 (vip-seq-last-elt (nth 5 vip-d-com))
3504 vip-F-char)
3505 vip-f-char vip-F-char)
3506 (setq val (- val)))
3507 (if com (vip-move-marker-locally 'vip-com-point (point)))
3508 (vip-find-char val (if (> (vip-p-val arg) 0) vip-f-char vip-F-char) t nil)
3509 (setq val (- val))
3510 (if com
3511 (progn
3512 (setq vip-F-char vip-f-char) ; set new vip-F-char
3513 (forward-char)
3514 (vip-execute-com 'vip-find-char-forward val com)))))
3515
3516(defun vip-goto-char-forward (arg)
3517 "Go up to char ARG forward on line."
3518 (interactive "P")
3519 (let ((val (vip-p-val arg))
3520 (com (vip-getcom arg)))
3521 (if (> val 0)
3522 ;; this means that the function was called interactively
3523 (setq vip-f-char (read-char)
3524 vip-f-forward t
3525 vip-f-offset t)
3526 ;; vip-repeat --- set vip-F-char from command-keys
3527 (setq vip-F-char (if (stringp (nth 5 vip-d-com))
3528 (vip-seq-last-elt (nth 5 vip-d-com))
3529 vip-F-char)
3530 vip-f-char vip-F-char)
3531 (setq val (- val)))
3532 (if com (vip-move-marker-locally 'vip-com-point (point)))
3533 (vip-find-char val (if (> (vip-p-val arg) 0) vip-f-char vip-F-char) t t)
3534 (setq val (- val))
3535 (if com
3536 (progn
3537 (setq vip-F-char vip-f-char) ; set new vip-F-char
3538 (forward-char)
3539 (vip-execute-com 'vip-goto-char-forward val com)))))
3540
3541(defun vip-find-char-backward (arg)
3542 "Find char ARG on line backward."
3543 (interactive "P")
3544 (let ((val (vip-p-val arg))
3545 (com (vip-getcom arg)))
3546 (if (> val 0)
3547 ;; this means that the function was called interactively
3548 (setq vip-f-char (read-char)
3549 vip-f-forward nil
3550 vip-f-offset nil)
3551 ;; vip-repeat --- set vip-F-char from command-keys
3552 (setq vip-F-char (if (stringp (nth 5 vip-d-com))
3553 (vip-seq-last-elt (nth 5 vip-d-com))
3554 vip-F-char)
3555 vip-f-char vip-F-char)
3556 (setq val (- val)))
3557 (if com (vip-move-marker-locally 'vip-com-point (point)))
3558 (vip-find-char
3559 val (if (> (vip-p-val arg) 0) vip-f-char vip-F-char) nil nil)
3560 (setq val (- val))
3561 (if com
3562 (progn
3563 (setq vip-F-char vip-f-char) ; set new vip-F-char
3564 (vip-execute-com 'vip-find-char-backward val com)))))
3565
3566(defun vip-goto-char-backward (arg)
3567 "Go up to char ARG backward on line."
3568 (interactive "P")
3569 (let ((val (vip-p-val arg))
3570 (com (vip-getcom arg)))
3571 (if (> val 0)
3572 ;; this means that the function was called interactively
3573 (setq vip-f-char (read-char)
3574 vip-f-forward nil
3575 vip-f-offset t)
3576 ;; vip-repeat --- set vip-F-char from command-keys
3577 (setq vip-F-char (if (stringp (nth 5 vip-d-com))
3578 (vip-seq-last-elt (nth 5 vip-d-com))
3579 vip-F-char)
3580 vip-f-char vip-F-char)
3581 (setq val (- val)))
3582 (if com (vip-move-marker-locally 'vip-com-point (point)))
3583 (vip-find-char val (if (> (vip-p-val arg) 0) vip-f-char vip-F-char) nil t)
3584 (setq val (- val))
3585 (if com
3586 (progn
3587 (setq vip-F-char vip-f-char) ; set new vip-F-char
3588 (vip-execute-com 'vip-goto-char-backward val com)))))
3589
3590(defun vip-repeat-find (arg)
3591 "Repeat previous find command."
3592 (interactive "P")
3593 (let ((val (vip-p-val arg))
3594 (com (vip-getcom arg)))
3595 (vip-deactivate-mark)
3596 (if com (vip-move-marker-locally 'vip-com-point (point)))
3597 (vip-find-char val vip-f-char vip-f-forward vip-f-offset)
3598 (if com
3599 (progn
3600 (if vip-f-forward (forward-char))
3601 (vip-execute-com 'vip-repeat-find val com)))))
3602
3603(defun vip-repeat-find-opposite (arg)
3604 "Repeat previous find command in the opposite direction."
3605 (interactive "P")
3606 (let ((val (vip-p-val arg))
3607 (com (vip-getcom arg)))
3608 (vip-deactivate-mark)
3609 (if com (vip-move-marker-locally 'vip-com-point (point)))
3610 (vip-find-char val vip-f-char (not vip-f-forward) vip-f-offset)
3611 (if com
3612 (progn
3613 (if vip-f-forward (forward-char))
3614 (vip-execute-com 'vip-repeat-find-opposite val com)))))
3615
3616\f
3617;; window scrolling etc.
3618
3619(defun vip-other-window (arg)
3620 "Switch to other window."
3621 (interactive "p")
3622 (other-window arg)
3623 (or (not (eq vip-current-state 'emacs-state))
3624 (string= (buffer-name (current-buffer)) " *Minibuf-1*")
3625 (vip-change-state-to-vi)))
3626
3627(defun vip-window-top (arg)
3628 "Go to home window line."
3629 (interactive "P")
3630 (let ((val (vip-p-val arg))
3631 (com (vip-getCom arg)))
3632 (if com (vip-move-marker-locally 'vip-com-point (point)))
3633 (push-mark nil t)
3634 (move-to-window-line (1- val))
4af0c23b
KH
3635
3636 ;; positioning is done twice: before and after command execution
3637 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
3638 (back-to-indentation)
3639
3640 (if com (vip-execute-com 'vip-window-top val com))
3641
3642 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
3643 (back-to-indentation)
3644 ))
6c2e12f4
KH
3645
3646(defun vip-window-middle (arg)
3647 "Go to middle window line."
3648 (interactive "P")
3649 (let ((val (vip-p-val arg))
4af0c23b
KH
3650 (com (vip-getCom arg))
3651 lines)
6c2e12f4
KH
3652 (if com (vip-move-marker-locally 'vip-com-point (point)))
3653 (push-mark nil t)
4af0c23b
KH
3654 (if (not (pos-visible-in-window-p (point-max)))
3655 (move-to-window-line (+ (/ (1- (window-height)) 2) (1- val)))
3656 (setq lines (count-lines (window-start) (point-max)))
3657 (move-to-window-line (+ (/ lines 2) (1- val))))
3658
3659 ;; positioning is done twice: before and after command execution
3660 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
3661 (back-to-indentation)
3662
3663 (if com (vip-execute-com 'vip-window-middle val com))
3664
3665 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
3666 (back-to-indentation)
3667 ))
6c2e12f4
KH
3668
3669(defun vip-window-bottom (arg)
3670 "Go to last window line."
3671 (interactive "P")
3672 (let ((val (vip-p-val arg))
3673 (com (vip-getCom arg)))
3674 (if com (vip-move-marker-locally 'vip-com-point (point)))
3675 (push-mark nil t)
3676 (move-to-window-line (- val))
4af0c23b
KH
3677
3678 ;; positioning is done twice: before and after command execution
3679 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
3680 (back-to-indentation)
3681
3682 (if com (vip-execute-com 'vip-window-bottom val com))
3683
3684 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
3685 (back-to-indentation)
3686 ))
6c2e12f4
KH
3687
3688(defun vip-line-to-top (arg)
3689 "Put current line on the home line."
3690 (interactive "p")
3691 (recenter (1- arg)))
3692
3693(defun vip-line-to-middle (arg)
3694 "Put current line on the middle line."
3695 (interactive "p")
3696 (recenter (+ (1- arg) (/ (1- (window-height)) 2))))
3697
3698(defun vip-line-to-bottom (arg)
3699 "Put current line on the last line."
3700 (interactive "p")
3701 (recenter (- (window-height) (1+ arg))))
3702
3703\f
3704;; paren match
3705;; must correct this to only match ( to ) etc. On the other hand
3706;; it is good that paren match gets confused, because that way you
3707;; catch _all_ imbalances.
3708
3709(defun vip-paren-match (arg)
3710 "Go to the matching parenthesis."
3711 (interactive "P")
3712 (let ((com (vip-getcom arg)))
3713 (if (numberp arg)
3714 (if (or (> arg 99) (< arg 1))
3715 (error "Prefix must be between 1 and 99")
3716 (goto-char
3717 (if (> (point-max) 80000)
3718 (* (/ (point-max) 100) arg)
3719 (/ (* (point-max) arg) 100)))
3720 (back-to-indentation))
3721 (let (lim)
3722 (if (and (eolp) (not (bolp))) (forward-char -1))
3723 (save-excursion
3724 (end-of-line)
3725 (setq lim (point)))
3726 (if (re-search-forward "[][(){}]" lim t)
3727 (backward-char)
3728 (error "No matching character on line")))
3729 (cond ((looking-at "[\(\[{]")
3730 (if com (vip-move-marker-locally 'vip-com-point (point)))
3731 (forward-sexp 1)
3732 (if com
3733 (vip-execute-com 'vip-paren-match nil com)
3734 (backward-char)))
3735 ((looking-at "[])}]")
3736 (forward-char)
3737 (if com (vip-move-marker-locally 'vip-com-point (point)))
3738 (backward-sexp 1)
3739 (if com (vip-execute-com 'vip-paren-match nil com)))
3740 (t (error ""))))))
3741
3742\f
3743;; sentence ,paragraph and heading
3744
3745(defun vip-forward-sentence (arg)
3746 "Forward sentence."
3747 (interactive "P")
3748 (push-mark nil t)
3749 (let ((val (vip-p-val arg))
3750 (com (vip-getcom arg)))
3751 (if com (vip-move-marker-locally 'vip-com-point (point)))
3752 (forward-sentence val)
3753 (if com (vip-execute-com 'vip-forward-sentence nil com))))
3754
3755(defun vip-backward-sentence (arg)
3756 "Backward sentence."
3757 (interactive "P")
3758 (push-mark nil t)
3759 (let ((val (vip-p-val arg))
3760 (com (vip-getcom arg)))
3761 (if com (vip-move-marker-locally 'vip-com-point (point)))
3762 (backward-sentence val)
3763 (if com (vip-execute-com 'vip-backward-sentence nil com))))
3764
3765(defun vip-forward-paragraph (arg)
3766 "Forward paragraph."
3767 (interactive "P")
3768 (push-mark nil t)
3769 (let ((val (vip-p-val arg))
3770 (com (vip-getCom arg)))
3771 (if com (vip-move-marker-locally 'vip-com-point (point)))
3772 (forward-paragraph val)
3773 (if com (vip-execute-com 'vip-forward-paragraph nil com))))
3774
3775(defun vip-backward-paragraph (arg)
3776 "Backward paragraph."
3777 (interactive "P")
3778 (push-mark nil t)
3779 (let ((val (vip-p-val arg))
3780 (com (vip-getCom arg)))
3781 (if com (vip-move-marker-locally 'vip-com-point (point)))
3782 (backward-paragraph val)
3783 (if com (vip-execute-com 'vip-backward-paragraph nil com))))
3784
3785;; should be mode-specific etc.
3786
3787(defun vip-prev-heading (arg)
3788 (interactive "P")
3789 (let ((val (vip-p-val arg))
3790 (com (vip-getCom arg)))
3791 (if com (vip-move-marker-locally 'vip-com-point (point)))
3792 (re-search-backward vip-heading-start nil t val)
3793 (goto-char (match-beginning 0))
3794 (if com (vip-execute-com 'vip-prev-heading nil com))))
3795
3796(defun vip-heading-end (arg)
3797 (interactive "P")
3798 (let ((val (vip-p-val arg))
3799 (com (vip-getCom arg)))
3800 (if com (vip-move-marker-locally 'vip-com-point (point)))
3801 (re-search-forward vip-heading-end nil t val)
3802 (goto-char (match-beginning 0))
3803 (if com (vip-execute-com 'vip-heading-end nil com))))
3804
3805(defun vip-next-heading (arg)
3806 (interactive "P")
3807 (let ((val (vip-p-val arg))
3808 (com (vip-getCom arg)))
3809 (if com (vip-move-marker-locally 'vip-com-point (point)))
3810 (end-of-line)
3811 (re-search-forward vip-heading-start nil t val)
3812 (goto-char (match-beginning 0))
3813 (if com (vip-execute-com 'vip-next-heading nil com))))
3814
3815\f
3816;; scrolling
3817
3818(setq scroll-step 1)
3819
3820(defun vip-scroll (arg)
3821 "Scroll to next screen."
3822 (interactive "p")
3823 (if (> arg 0)
3824 (while (> arg 0)
3825 (scroll-up)
3826 (setq arg (1- arg)))
3827 (while (> 0 arg)
3828 (scroll-down)
3829 (setq arg (1+ arg)))))
3830
3831(defun vip-scroll-back (arg)
3832 "Scroll to previous screen."
3833 (interactive "p")
3834 (vip-scroll (- arg)))
3835
3836(defun vip-scroll-down (arg)
3837 "Pull down half screen."
3838 (interactive "P")
3839 (condition-case nil
3840 (if (null arg)
3841 (scroll-down (/ (window-height) 2))
3842 (scroll-down arg))
3843 (error (beep 1)
3844 (message "Beginning of buffer")
3845 (goto-char (point-min)))))
3846
3847(defun vip-scroll-down-one (arg)
3848 "Scroll up one line."
3849 (interactive "p")
3850 (scroll-down arg))
3851
3852(defun vip-scroll-up (arg)
3853 "Pull up half screen."
3854 (interactive "P")
3855 (condition-case nil
3856 (if (null arg)
3857 (scroll-up (/ (window-height) 2))
3858 (scroll-up arg))
3859 (error (beep 1)
3860 (message "End of buffer")
3861 (goto-char (point-max)))))
3862
3863(defun vip-scroll-up-one (arg)
3864 "Scroll down one line."
3865 (interactive "p")
3866 (scroll-up arg))
3867
3868\f
3869;; searching
3870
3871(defun vip-if-string (prompt)
3872 (let ((s (vip-read-string-with-history
3873 prompt
3874 nil ; no initial
3875 'vip-search-history
3876 (car vip-search-history))))
3877 (if (not (string= s ""))
3878 (setq vip-s-string s))))
3879
3880
3881(defun vip-toggle-search-style (arg)
3882 "Toggle the value of vip-case-fold-search/vip-re-search.
3883Without prefix argument, will ask which search style to toggle. With prefix
3884arg 1,toggles vip-case-fold-search; with arg 2 toggles vip-re-search.
3885
3886Although this function is bound to \\[vip-toggle-search-style], the most
3887convenient way to use it is to bind `//' to the macro
3888`1 M-x vip-toggle-search-style' and `///' to
3889`2 M-x vip-toggle-search-style'. In this way, hitting `//' quickly will
05497fc6 3890toggle case-fold-search and hitting `/' three times with toggle regexp
6c2e12f4
KH
3891search. Macros are more convenient in this case because they don't affect
3892the Emacs binding of `/'."
3893 (interactive "P")
3894 (let (msg)
3895 (cond ((or (eq arg 1)
3896 (and (null arg)
3897 (y-or-n-p (format "Search style: '%s'. Want '%s'? "
3898 (if vip-case-fold-search
3899 "case-insensitive" "case-sensitive")
3900 (if vip-case-fold-search
3901 "case-sensitive"
3902 "case-insensitive")))))
3903 (setq vip-case-fold-search (null vip-case-fold-search))
3904 (if vip-case-fold-search
3905 (setq msg "Search becomes case-insensitive")
3906 (setq msg "Search becomes case-sensitive")))
3907 ((or (eq arg 2)
3908 (and (null arg)
3909 (y-or-n-p (format "Search style: '%s'. Want '%s'? "
3910 (if vip-re-search
3911 "regexp-search" "vanilla-search")
3912 (if vip-re-search
3913 "vanilla-search"
3914 "regexp-search")))))
3915 (setq vip-re-search (null vip-re-search))
3916 (if vip-re-search
3917 (setq msg "Search becomes regexp-style")
3918 (setq msg "Search becomes vanilla-style")))
3919 (t
3920 (setq msg "Search style remains unchanged")))
3921 (prin1 msg t)))
3922
3923
3924(defun vip-search-forward (arg)
3925 "Search a string forward.
3926ARG is used to find the ARG's occurrence of the string.
3927Null string will repeat previous search."
3928 (interactive "P")
3929 (let ((val (vip-P-val arg))
3930 (com (vip-getcom arg))
3931 (old-str vip-s-string))
3932 (setq vip-s-forward t)
3933 (vip-if-string "/")
3934 ;; this is not used at present, but may be used later
3935 (if (or (not (equal old-str vip-s-string))
3936 (not (markerp vip-local-search-start-marker))
3937 (not (marker-buffer vip-local-search-start-marker)))
3938 (setq vip-local-search-start-marker (point-marker)))
3939 (vip-search vip-s-string t val)
3940 (if com
3941 (progn
3942 (vip-move-marker-locally 'vip-com-point (mark t))
3943 (vip-execute-com 'vip-search-next val com)))))
3944
3945(defun vip-search-backward (arg)
3946 "Search a string backward.
3947ARG is used to find the ARG's occurrence of the string.
3948Null string will repeat previous search."
3949 (interactive "P")
3950 (let ((val (vip-P-val arg))
3951 (com (vip-getcom arg))
3952 (old-str vip-s-string))
3953 (setq vip-s-forward nil)
3954 (vip-if-string "?")
3955 ;; this is not used at present, but may be used later
3956 (if (or (not (equal old-str vip-s-string))
3957 (not (markerp vip-local-search-start-marker))
3958 (not (marker-buffer vip-local-search-start-marker)))
3959 (setq vip-local-search-start-marker (point-marker)))
3960 (vip-search vip-s-string nil val)
3961 (if com
3962 (progn
3963 (vip-move-marker-locally 'vip-com-point (mark t))
3964 (vip-execute-com 'vip-search-next val com)))))
3965
3966
4af0c23b
KH
3967;; Search for COUNT's occurrence of STRING.
3968;; Search is forward if FORWARD is non-nil, otherwise backward.
3969;; INIT-POINT is the position where search is to start.
04090c34
MK
3970;; Arguments:
3971;; (STRING FORW COUNT &optional NO-OFFSET INIT-POINT LIMIT FAIL-IF-NOT-FOUND)
3972(defun vip-search (string forward arg
3973 &optional no-offset init-point fail-if-not-found)
6c2e12f4
KH
3974 (if (not (equal string ""))
3975 (let ((val (vip-p-val arg))
3976 (com (vip-getcom arg))
04090c34 3977 (offset (not no-offset))
6c2e12f4
KH
3978 (case-fold-search vip-case-fold-search)
3979 (start-point (or init-point (point))))
3980 (vip-deactivate-mark)
3981 (if forward
3982 (condition-case nil
3983 (progn
3984 (if offset (vip-forward-char-carefully))
3985 (if vip-re-search
3986 (progn
3987 (re-search-forward string nil nil val)
3988 (re-search-backward string))
3989 (search-forward string nil nil val)
3990 (search-backward string))
04090c34
MK
3991 ;; don't wait and don't flash in macros
3992 (or executing-kbd-macro
3993 (vip-flash-search-pattern))
6c2e12f4
KH
3994 (if (not (equal start-point (point)))
3995 (push-mark start-point t)))
3996 (search-failed
04090c34 3997 (if (and (not fail-if-not-found) vip-search-wrap-around-t)
6c2e12f4
KH
3998 (progn
3999 (message "Search wrapped around end of buffer")
4000 (goto-char (point-min))
04090c34
MK
4001 (vip-search string forward (cons 1 com) t start-point 'fail)
4002 ;; don't wait in macros
4003 (or executing-kbd-macro (sit-for 2))
4004 ;; delete the wrap-around message
4005 (message "")
6c2e12f4
KH
4006 )
4007 (goto-char start-point)
4008 (error "`%s': %s not found"
4009 string
4010 (if vip-re-search "Pattern" "String"))
4011 )))
4012 ;; backward
4013 (condition-case nil
4014 (progn
4015 (if vip-re-search
4016 (re-search-backward string nil nil val)
4017 (search-backward string nil nil val))
04090c34
MK
4018 ;; don't wait and don't flash in macros
4019 (or executing-kbd-macro
4020 (vip-flash-search-pattern))
6c2e12f4
KH
4021 (if (not (equal start-point (point)))
4022 (push-mark start-point t)))
4023 (search-failed
04090c34 4024 (if (and (not fail-if-not-found) vip-search-wrap-around-t)
6c2e12f4
KH
4025 (progn
4026 (message "Search wrapped around beginning of buffer")
4027 (goto-char (point-max))
04090c34
MK
4028 (vip-search string forward (cons 1 com) t start-point 'fail)
4029 ;; don't wait in macros
4030 (or executing-kbd-macro (sit-for 2))
4031 ;; delete the wrap-around message
4032 (message "")
6c2e12f4
KH
4033 )
4034 (goto-char start-point)
4035 (error "`%s': %s not found"
4036 string
4037 (if vip-re-search "Pattern" "String"))
4038 )))))))
4039
4040(defun vip-search-next (arg)
4041 "Repeat previous search."
4042 (interactive "P")
4043 (let ((val (vip-p-val arg))
4044 (com (vip-getcom arg)))
4045 (if (null vip-s-string) (error vip-NoPrevSearch))
4046 (vip-search vip-s-string vip-s-forward arg)
4047 (if com
4048 (progn
4049 (vip-move-marker-locally 'vip-com-point (mark t))
4050 (vip-execute-com 'vip-search-next val com)))))
4051
4052(defun vip-search-Next (arg)
4053 "Repeat previous search in the reverse direction."
4054 (interactive "P")
4055 (let ((val (vip-p-val arg))
4056 (com (vip-getcom arg)))
4057 (if (null vip-s-string) (error vip-NoPrevSearch))
4058 (vip-search vip-s-string (not vip-s-forward) arg)
4059 (if com
4060 (progn
4061 (vip-move-marker-locally 'vip-com-point (mark t))
4062 (vip-execute-com 'vip-search-Next val com)))))
4063
4064
4065;; Search contents of buffer defined by one of Viper's motion commands.
4066;; Repeatable via `n' and `N'.
4067(defun vip-buffer-search-enable (&optional c)
4068 (cond (c (setq vip-buffer-search-char c))
4069 ((null vip-buffer-search-char)
4070 (setq vip-buffer-search-char ?g)))
4071 (define-key vip-vi-basic-map
4072 (char-to-string vip-buffer-search-char) 'vip-command-argument)
4073 (aset vip-exec-array vip-buffer-search-char 'vip-exec-buffer-search)
4074 (setq vip-prefix-commands (cons vip-buffer-search-char vip-prefix-commands)))
4075
05497fc6 4076;; This is a Viper wrapper for isearch-forward.
6c2e12f4 4077(defun vip-isearch-forward (arg)
4af0c23b 4078 "Do incremental search forward."
6c2e12f4
KH
4079 (interactive "P")
4080 ;; emacs bug workaround
4081 (if (listp arg) (setq arg (car arg)))
4082 (vip-exec-form-in-emacs (list 'isearch-forward arg)))
4083
05497fc6 4084;; This is a Viper wrapper for isearch-backward."
6c2e12f4 4085(defun vip-isearch-backward (arg)
4af0c23b 4086 "Do incremental search backward."
6c2e12f4
KH
4087 (interactive "P")
4088 ;; emacs bug workaround
4089 (if (listp arg) (setq arg (car arg)))
4090 (vip-exec-form-in-emacs (list 'isearch-backward arg)))
4091
4092\f
4093;; visiting and killing files, buffers
4094
4095(defun vip-switch-to-buffer ()
4096 "Switch to buffer in the current window."
4097 (interactive)
4098 (let (buffer)
4099 (setq buffer
4100 (read-buffer
4101 (format "Switch to buffer in this window \(%s\): "
4102 (buffer-name (other-buffer (current-buffer))))))
4103 (switch-to-buffer buffer)
4104 ))
4105
4106(defun vip-switch-to-buffer-other-window ()
4107 "Switch to buffer in another window."
4108 (interactive)
4109 (let (buffer)
4110 (setq buffer
4111 (read-buffer
4112 (format "Switch to buffer in another window \(%s\): "
4113 (buffer-name (other-buffer (current-buffer))))))
4114 (switch-to-buffer-other-window buffer)
4115 ))
4116
4117(defun vip-kill-buffer ()
4118 "Kill a buffer."
4119 (interactive)
4120 (let (buffer buffer-name)
4121 (setq buffer-name
4122 (read-buffer
4123 (format "Kill buffer \(%s\): "
4124 (buffer-name (current-buffer)))))
4125 (setq buffer
4126 (if (null buffer-name)
4127 (current-buffer)
4128 (get-buffer buffer-name)))
4129 (if (null buffer) (error "`%s': No such buffer" buffer-name))
4130 (if (or (not (buffer-modified-p buffer))
4131 (y-or-n-p
4132 (format
4133 "Buffer `%s' is modified, are you sure you want to kill it? "
4134 buffer-name)))
4135 (kill-buffer buffer)
4136 (error "Buffer not killed"))))
4137
4138
4139(defvar vip-smart-suffix-list '("" "tex" "c" "cc" "el" "p")
4140 "*List of suffixes that Viper automatically tries to append to filenames ending with a `.'.
4141This is useful when you the current directory contains files with the same
4142prefix and many different suffixes. Usually, only one of the suffixes
4143represents an editable file. However, file completion will stop at the `.'
4144The smart suffix feature lets you hit RET in such a case, and Viper will
4145select the appropriate suffix.
4146
4147Suffixes are tried in the order given and the first suffix for which a
4148corresponding file exists is selected. If no file exists for any of the
4149suffixes, the user is asked to confirm.
4150
4151To turn this feature off, set this variable to nil.")
4152
4153;; Try to add suffix to files ending with a `.'
4154;; Useful when the user hits RET on a non-completed file name.
4155(defun vip-file-add-suffix ()
4156 (let ((count 0)
4157 (len (length vip-smart-suffix-list))
4158 (file (buffer-string))
4159 found key cmd suff)
4160 (goto-char (point-max))
4161 (if (and vip-smart-suffix-list (string-match "\\.$" file))
4162 (progn
4163 (while (and (not found) (< count len))
4164 (setq suff (nth count vip-smart-suffix-list)
4165 count (1+ count))
4166 (if (file-exists-p (format "%s%s" file suff))
4167 (progn
4168 (setq found t)
4169 (insert suff))))
4170
4171 (if found
4172 ()
4173 (vip-tmp-insert-at-eob " [Please complete file name]")
4174 (unwind-protect
4175 (while (not (memq cmd '(exit-minibuffer vip-exit-minibuffer)))
4176 (setq cmd
4177 (key-binding (setq key (read-key-sequence nil))))
4178 (cond ((eq cmd 'self-insert-command)
4179 (if vip-xemacs-p
4180 (insert (events-to-keys key))
4181 (insert key)))
4182 ((memq cmd '(exit-minibuffer vip-exit-minibuffer))
4183 nil)
4184 (t (command-execute cmd)))
4185 )))
4186 ))
4187 ))
4188
4189
4190;; Advice for use in find-file and read-file-name commands.
4191(defadvice exit-minibuffer (before vip-exit-minibuffer-advice activate)
4af0c23b 4192 "Run `vip-minibuffer-exit-hook' just before exiting the minibuffer."
6c2e12f4
KH
4193 (run-hooks 'vip-minibuffer-exit-hook))
4194
4195(defadvice find-file (before vip-add-suffix-advice activate)
4af0c23b 4196 "Use `read-file-name' for reading arguments."
6c2e12f4
KH
4197 (interactive (list (read-file-name "Find file: "
4198 nil default-directory))))
4199
4200(defadvice find-file-other-window (before vip-add-suffix-advice activate)
4af0c23b 4201 "Use `read-file-name' for reading arguments."
6c2e12f4
KH
4202 (interactive (list (read-file-name "Find file in other window: "
4203 nil default-directory))))
4204
6c2e12f4 4205(defadvice find-file-other-frame (before vip-add-suffix-advice activate)
4af0c23b 4206 "Use `read-file-name' for reading arguments."
6c2e12f4
KH
4207 (interactive (list (read-file-name "Find file in other frame: "
4208 nil default-directory))))
4209
4210(defadvice read-file-name (around vip-suffix-advice activate)
4af0c23b 4211 "Tell `exit-minibuffer' to run `vip-file-add-suffix' as a hook."
6c2e12f4
KH
4212 (let ((vip-minibuffer-exit-hook 'vip-file-add-suffix))
4213 ad-do-it))
4214
6c2e12f4
KH
4215
4216\f
4217;; yank and pop
4218
4219(defsubst vip-yank (text)
4220 "Yank TEXT silently. This works correctly with Emacs's yank-pop command."
4221 (insert text)
4222 (setq this-command 'yank))
4223
4224(defun vip-put-back (arg)
4225 "Put back after point/below line."
4226 (interactive "P")
4227 (let ((val (vip-p-val arg))
4228 (text (if vip-use-register
4229 (cond ((vip-valid-register vip-use-register '(digit))
4230 (current-kill (- vip-use-register ?1) 'do-not-rotate))
4231 ((vip-valid-register vip-use-register)
4232 (get-register (downcase vip-use-register)))
4233 (t (error vip-InvalidRegister vip-use-register)))
4234 (current-kill 0))))
4235 (if (null text)
4236 (if vip-use-register
4237 (let ((reg vip-use-register))
4238 (setq vip-use-register nil)
4239 (error vip-EmptyRegister reg))
4240 (error "")))
4241 (setq vip-use-register nil)
4242 (if (vip-end-with-a-newline-p text)
4243 (progn
4244 (if (eobp)
4245 (insert "\n")
4246 (forward-line 1))
4247 (beginning-of-line))
4248 (if (not (eolp)) (vip-forward-char-carefully)))
4249 (set-marker (vip-mark-marker) (point) (current-buffer))
4250 (vip-set-destructive-command
4251 (list 'vip-put-back val nil vip-use-register nil nil))
4252 (vip-loop val (vip-yank text)))
4af0c23b
KH
4253 ;; Vi puts cursor on the last char when the yanked text doesn't contain a
4254 ;; newline; it leaves the cursor at the beginning when the text contains
4255 ;; a newline
4256 (if (vip-same-line (point) (mark))
4257 (or (= (point) (mark)) (vip-backward-char-carefully))
4258 (exchange-point-and-mark)
4259 (if (bolp)
4260 (back-to-indentation)))
6c2e12f4
KH
4261 (vip-deactivate-mark))
4262
4263(defun vip-Put-back (arg)
4264 "Put back at point/above line."
4265 (interactive "P")
4266 (let ((val (vip-p-val arg))
4267 (text (if vip-use-register
4268 (cond ((vip-valid-register vip-use-register '(digit))
4269 (current-kill (- vip-use-register ?1) 'do-not-rotate))
4270 ((vip-valid-register vip-use-register)
4271 (get-register (downcase vip-use-register)))
4272 (t (error vip-InvalidRegister vip-use-register)))
4273 (current-kill 0))))
4274 (if (null text)
4275 (if vip-use-register
4276 (let ((reg vip-use-register))
4277 (setq vip-use-register nil)
4278 (error vip-EmptyRegister reg))
4279 (error "")))
4280 (setq vip-use-register nil)
4281 (if (vip-end-with-a-newline-p text) (beginning-of-line))
4282 (vip-set-destructive-command
4283 (list 'vip-Put-back val nil vip-use-register nil nil))
4284 (set-marker (vip-mark-marker) (point) (current-buffer))
4285 (vip-loop val (vip-yank text)))
4af0c23b
KH
4286 ;; Vi puts cursor on the last char when the yanked text doesn't contain a
4287 ;; newline; it leaves the cursor at the beginning when the text contains
4288 ;; a newline
4289 (if (vip-same-line (point) (mark))
4290 (or (= (point) (mark)) (vip-backward-char-carefully))
4291 (exchange-point-and-mark)
4292 (if (bolp)
4293 (back-to-indentation)))
6c2e12f4
KH
4294 (vip-deactivate-mark))
4295
4296
4af0c23b
KH
4297;; Copy region to kill-ring.
4298;; If BEG and END do not belong to the same buffer, copy empty region.
6c2e12f4 4299(defun vip-copy-region-as-kill (beg end)
6c2e12f4
KH
4300 (condition-case nil
4301 (copy-region-as-kill beg end)
4302 (error (copy-region-as-kill beg beg))))
4303
4af0c23b 4304;; Saves last inserted text for possible use by vip-repeat command.
6c2e12f4 4305(defun vip-save-last-insertion (beg end)
6c2e12f4
KH
4306 (setq vip-last-insertion (buffer-substring beg end))
4307 (or (< (length vip-d-com) 5)
4308 (setcar (nthcdr 4 vip-d-com) vip-last-insertion))
4309 (or (null vip-command-ring)
4310 (ring-empty-p vip-command-ring)
4311 (progn
4312 (setcar (nthcdr 4 (vip-current-ring-item vip-command-ring))
4313 vip-last-insertion)
4314 ;; del most recent elt, if identical to the second most-recent
4315 (vip-cleanup-ring vip-command-ring)))
4316 )
4317
4318(defsubst vip-yank-last-insertion ()
4319 "Inserts the text saved by the previous vip-save-last-insertion command."
4320 (condition-case nil
4321 (insert vip-last-insertion)
4322 (error nil)))
4323
4324
4325(defun vip-delete-char (arg)
4326 "Delete character."
4327 (interactive "P")
4328 (let ((val (vip-p-val arg)))
4329 (vip-set-destructive-command (list 'vip-delete-char val nil nil nil nil))
4330 (if (> val 1)
4331 (save-excursion
4332 (let ((here (point)))
4333 (end-of-line)
4334 (if (> val (- (point) here))
4335 (setq val (- (point) here))))))
4336 (if (and (eq val 0) (not vip-ex-style-motion)) (setq val 1))
4337 (if (and vip-ex-style-motion (eolp))
4338 (if (bolp) (error "") (setq val 0))) ; not bol---simply back 1 ch
4339 (if vip-use-register
4340 (progn
4341 (cond ((vip-valid-register vip-use-register '((Letter)))
4342 (vip-append-to-register
4343 (downcase vip-use-register) (point) (- (point) val)))
4344 ((vip-valid-register vip-use-register)
4345 (copy-to-register
4346 vip-use-register (point) (- (point) val) nil))
4347 (t (error vip-InvalidRegister vip-use-register)))
4348 (setq vip-use-register nil)))
4349 (if vip-ex-style-motion
4350 (progn
4351 (delete-char val t)
4352 (if (and (eolp) (not (bolp))) (backward-char 1)))
4353 (if (eolp)
4354 (delete-backward-char val t)
4355 (delete-char val t)))))
4356
4357(defun vip-delete-backward-char (arg)
4358 "Delete previous character. On reaching beginning of line, stop and beep."
4359 (interactive "P")
4360 (let ((val (vip-p-val arg)))
4361 (vip-set-destructive-command
4362 (list 'vip-delete-backward-char val nil nil nil nil))
4363 (if (> val 1)
4364 (save-excursion
4365 (let ((here (point)))
4366 (beginning-of-line)
4367 (if (> val (- here (point)))
4368 (setq val (- here (point)))))))
4369 (if vip-use-register
4370 (progn
4371 (cond ((vip-valid-register vip-use-register '(Letter))
4372 (vip-append-to-register
4373 (downcase vip-use-register) (point) (+ (point) val)))
4374 ((vip-valid-register vip-use-register)
4375 (copy-to-register
4376 vip-use-register (point) (+ (point) val) nil))
4377 (t (error vip-InvalidRegister vip-use-register)))
4378 (setq vip-use-register nil)))
4379 (if (bolp) (ding)
4380 (delete-backward-char val t))))
4381
4382(defun vip-del-backward-char-in-insert ()
4383 "Delete 1 char backwards while in insert mode."
4384 (interactive)
4385 (if (and vip-ex-style-editing-in-insert (bolp))
4386 (beep 1)
4387 (delete-backward-char 1 t)))
4388
4389(defun vip-del-backward-char-in-replace ()
4390 "Delete one character in replace mode.
4391If `vip-delete-backwards-in-replace' is t, then DEL key actually deletes
05497fc6 4392characters. If it is nil, then the cursor just moves backwards, similarly
6c2e12f4 4393to Vi. The variable `vip-ex-style-editing-in-insert', if t, doesn't let the
4af0c23b 4394cursor move past the beginning of line."
6c2e12f4
KH
4395 (interactive)
4396 (cond (vip-delete-backwards-in-replace
4397 (cond ((not (bolp))
4398 (delete-backward-char 1 t))
4399 (vip-ex-style-editing-in-insert
4400 (beep 1))
4401 ((bobp)
4402 (beep 1))
4403 (t
4404 (delete-backward-char 1 t))))
4405 (vip-ex-style-editing-in-insert
4406 (if (bolp)
4407 (beep 1)
4408 (backward-char 1)))
4409 (t
4410 (backward-char 1))))
4411
4412
4413\f
4414;; join lines.
4415
4416(defun vip-join-lines (arg)
4417 "Join this line to next, if ARG is nil. Otherwise, join ARG lines."
4418 (interactive "*P")
4419 (let ((val (vip-P-val arg)))
4420 (vip-set-destructive-command (list 'vip-join-lines val nil nil nil nil))
4421 (vip-loop (if (null val) 1 (1- val))
4422 (progn
4423 (end-of-line)
4424 (if (not (eobp))
4425 (progn
4426 (forward-line 1)
4427 (delete-region (point) (1- (point)))
4428 (fixup-whitespace)))))))
4429
4430\f
4431;; Replace state
4432
4433(defun vip-change (beg end)
4434 (if (markerp beg) (setq beg (marker-position beg)))
4435 (if (markerp end) (setq end (marker-position end)))
4436 ;; beg is sometimes (mark t), which may be nil
4437 (or beg (setq beg end))
4438
4439 (vip-set-complex-command-for-undo)
4440 (if vip-use-register
4441 (progn
4442 (copy-to-register vip-use-register beg end nil)
4443 (setq vip-use-register nil)))
4444 (vip-set-replace-overlay beg end)
4445 (setq last-command nil) ; separate repl text from prev kills
4446
4447 (if (= (vip-replace-start) (point-max))
4448 (error "End of buffer"))
4449
4450 (setq vip-last-replace-region
4451 (buffer-substring (vip-replace-start)
4452 (vip-replace-end)))
4453
4454 ;; protect against error while inserting "@" and other disasters
4455 ;; (e.g., read-only buff)
4456 (condition-case conds
4457 (if (vip-same-line (vip-replace-start)
4458 (vip-replace-end))
4af0c23b 4459 (progn
6c2e12f4
KH
4460 ;; tabs cause problems in replace, so untabify
4461 (goto-char (vip-replace-end))
4462 (insert-before-markers "@") ; put placeholder after the TAB
6c2e12f4 4463 (untabify (vip-replace-start) (point))
4af0c23b
KH
4464 ;; del @, don't put on kill ring
4465 (delete-backward-char 1)
4466
4467 (vip-set-replace-overlay-glyphs
4468 vip-replace-region-start-delimiter
4469 vip-replace-region-end-delimiter)
6c2e12f4
KH
4470 ;; this move takes care of the last posn in the overlay, which
4471 ;; has to be shifted because of insert. We can't simply insert
4472 ;; "$" before-markers because then overlay-start will shift the
4473 ;; beginning of the overlay in case we are replacing a single
4474 ;; character. This fixes the bug with `s' and `cl' commands.
4475 (vip-move-replace-overlay (vip-replace-start) (point))
4476 (goto-char (vip-replace-start))
4477 (vip-change-state-to-replace t))
4478 (kill-region (vip-replace-start)
4479 (vip-replace-end))
4af0c23b 4480 (vip-restore-cursor-color)
6c2e12f4
KH
4481 (vip-change-state-to-insert))
4482 (error ;; make sure that the overlay doesn't stay.
4483 ;; go back to the original point
4484 (goto-char (vip-replace-start))
4485 (vip-hide-replace-overlay)
4486 (vip-message-conditions conds))))
4487
4488
4489(defun vip-change-subr (beg end)
4490 ;; beg is sometimes (mark t), which may be nil
4491 (or beg (setq beg end))
4492
4493 (if vip-use-register
4494 (progn
4495 (copy-to-register vip-use-register beg end nil)
4496 (setq vip-use-register nil)))
4497 (kill-region beg end)
4498 (setq this-command 'vip-change)
4499 (vip-yank-last-insertion))
4500
4501(defun vip-toggle-case (arg)
4502 "Toggle character case."
4503 (interactive "P")
4504 (let ((val (vip-p-val arg)) (c))
4505 (vip-set-destructive-command (list 'vip-toggle-case val nil nil nil nil))
4506 (while (> val 0)
4507 (setq c (following-char))
4508 (delete-char 1 nil)
4509 (if (eq c (upcase c))
4510 (insert-char (downcase c) 1)
4511 (insert-char (upcase c) 1))
4af0c23b 4512 (if (eolp) (backward-char 1))
6c2e12f4
KH
4513 (setq val (1- val)))))
4514
4515\f
4516;; query replace
4517
4518(defun vip-query-replace ()
4519 "Query replace.
05497fc6 4520If a null string is supplied as the string to be replaced,
6c2e12f4
KH
4521the query replace mode will toggle between string replace
4522and regexp replace."
4523 (interactive)
4524 (let (str)
4525 (setq str (vip-read-string-with-history
4526 (if vip-re-query-replace "Query replace regexp: "
4527 "Query replace: ")
4528 nil ; no initial
4529 'vip-replace1-history
4530 (car vip-replace1-history) ; default
4531 ))
4532 (if (string= str "")
4533 (progn
4534 (setq vip-re-query-replace (not vip-re-query-replace))
4535 (message "Query replace mode changed to %s"
4536 (if vip-re-query-replace "regexp replace"
4537 "string replace")))
4538 (if vip-re-query-replace
4539 (query-replace-regexp
4540 str
4541 (vip-read-string-with-history
4542 (format "Query replace regexp `%s' with: " str)
4543 nil ; no initial
4544 'vip-replace1-history
4545 (car vip-replace1-history) ; default
4546 ))
4547 (query-replace
4548 str
4549 (vip-read-string-with-history
4550 (format "Query replace `%s' with: " str)
4551 nil ; no initial
4552 'vip-replace1-history
4553 (car vip-replace1-history) ; default
4554 ))))))
4555
4556\f
4557;; marking
4558
4559(defun vip-mark-beginning-of-buffer ()
4af0c23b 4560 "Mark beginning of buffer."
6c2e12f4
KH
4561 (interactive)
4562 (push-mark (point))
4563 (goto-char (point-min))
4564 (exchange-point-and-mark)
4565 (message "Mark set at the beginning of buffer"))
4566
4567(defun vip-mark-end-of-buffer ()
4af0c23b 4568 "Mark end of buffer."
6c2e12f4
KH
4569 (interactive)
4570 (push-mark (point))
4571 (goto-char (point-max))
4572 (exchange-point-and-mark)
4573 (message "Mark set at the end of buffer"))
4574
4575(defun vip-mark-point ()
4af0c23b 4576 "Set mark at point of buffer."
6c2e12f4
KH
4577 (interactive)
4578 (let ((char (vip-read-char-exclusive)))
4579 (cond ((and (<= ?a char) (<= char ?z))
4580 (point-to-register (1+ (- char ?a))))
4581 ((= char ?<) (vip-mark-beginning-of-buffer))
4582 ((= char ?>) (vip-mark-end-of-buffer))
4583 ((= char ?.) (vip-set-mark-if-necessary))
4584 ((= char ?,) (vip-cycle-through-mark-ring))
4585 ((= char ?D) (mark-defun))
4586 (t (error ""))
4587 )))
4588
4589;; Algorithm: If first invocation of this command save mark on ring, goto
4590;; mark, M0, and pop the most recent elt from the mark ring into mark,
4591;; making it into the new mark, M1.
4592;; Push this mark back and set mark to the original point position, p1.
4593;; So, if you hit '' or `` then you can return to p1.
4594;;
4595;; If repeated command, pop top elt from the ring into mark and
4596;; jump there. This forgets the position, p1, and puts M1 back into mark.
4597;; Then we save the current pos, which is M0, jump to M1 and pop M2 from
4598;; the ring into mark. Push M2 back on the ring and set mark to M0.
4599;; etc.
4600(defun vip-cycle-through-mark-ring ()
4601 "Visit previous locations on the mark ring.
4602One can use `` and '' to temporarily jump 1 step back."
4603 (let* ((sv-pt (point)))
4604 ;; if repeated `m,' command, pop the previously saved mark.
4605 ;; Prev saved mark is actually prev saved point. It is used if the
4606 ;; user types `` or '' and is discarded
4607 ;; from the mark ring by the next `m,' command.
4608 ;; In any case, go to the previous or previously saved mark.
4609 ;; Then push the current mark (popped off the ring) and set current
4610 ;; point to be the mark. Current pt as mark is discarded by the next
4611 ;; m, command.
4612 (if (eq last-command 'vip-cycle-through-mark-ring)
4613 ()
4614 ;; save current mark if the first iteration
4615 (setq mark-ring (delete (vip-mark-marker) mark-ring))
4616 (if (mark t)
4617 (push-mark (mark t) t)) )
4618 (pop-mark)
4619 (set-mark-command 1)
4620 ;; don't duplicate mark on the ring
4621 (setq mark-ring (delete (vip-mark-marker) mark-ring))
4622 (push-mark sv-pt t)
4623 (vip-deactivate-mark)
4624 (setq this-command 'vip-cycle-through-mark-ring)
4625 ))
4626
4627
4628(defun vip-goto-mark (arg)
4629 "Go to mark."
4630 (interactive "P")
4631 (let ((char (read-char))
4632 (com (vip-getcom arg)))
4633 (vip-goto-mark-subr char com nil)))
4634
4635(defun vip-goto-mark-and-skip-white (arg)
4636 "Go to mark and skip to first non-white character on line."
4637 (interactive "P")
4638 (let ((char (read-char))
4639 (com (vip-getCom arg)))
4640 (vip-goto-mark-subr char com t)))
4641
4642(defun vip-goto-mark-subr (char com skip-white)
4643 (if (eobp)
4644 (if (bobp)
4645 (error "Empty buffer")
4646 (backward-char 1)))
4647 (cond ((vip-valid-register char '(letter))
4648 (let* ((buff (current-buffer))
4649 (reg (1+ (- char ?a)))
4650 (text-marker (get-register reg)))
4651 (if com (vip-move-marker-locally 'vip-com-point (point)))
4652 (if (not (vip-valid-marker text-marker))
27571f90 4653 (error (format vip-EmptyTextmarker char)))
6c2e12f4
KH
4654 (if (and (vip-same-line (point) vip-last-jump)
4655 (= (point) vip-last-jump-ignore))
4656 (push-mark vip-last-jump t)
4657 (push-mark nil t)) ; no msg
4658 (vip-register-to-point reg)
4659 (setq vip-last-jump (point-marker))
4660 (cond (skip-white
4661 (back-to-indentation)
4662 (setq vip-last-jump-ignore (point))))
4663 (if com
4664 (if (equal buff (current-buffer))
4665 (vip-execute-com (if skip-white
4666 'vip-goto-mark-and-skip-white
4667 'vip-goto-mark)
4668 nil com)
4669 (switch-to-buffer buff)
4670 (goto-char vip-com-point)
4671 (vip-change-state-to-vi)
4672 (error "")))))
4673 ((and (not skip-white) (= char ?`))
4674 (if com (vip-move-marker-locally 'vip-com-point (point)))
4675 (if (and (vip-same-line (point) vip-last-jump)
4676 (= (point) vip-last-jump-ignore))
4677 (goto-char vip-last-jump))
4678 (if (= (point) (mark t)) (pop-mark))
4679 (exchange-point-and-mark)
4680 (setq vip-last-jump (point-marker)
4681 vip-last-jump-ignore 0)
4682 (if com (vip-execute-com 'vip-goto-mark nil com)))
4683 ((and skip-white (= char ?'))
4684 (if com (vip-move-marker-locally 'vip-com-point (point)))
4685 (if (and (vip-same-line (point) vip-last-jump)
4686 (= (point) vip-last-jump-ignore))
4687 (goto-char vip-last-jump))
4688 (if (= (point) (mark t)) (pop-mark))
4689 (exchange-point-and-mark)
4690 (setq vip-last-jump (point))
4691 (back-to-indentation)
4692 (setq vip-last-jump-ignore (point))
4693 (if com (vip-execute-com 'vip-goto-mark-and-skip-white nil com)))
4694 (t (error vip-InvalidTextmarker char))))
4695
4696(defun vip-insert-tab ()
4697 (interactive)
4698 (insert-tab))
4699
4700(defun vip-exchange-point-and-mark ()
4701 (interactive)
4702 (exchange-point-and-mark)
4703 (back-to-indentation))
4704
4705;; Input Mode Indentation
4706
4707(defun vip-forward-indent ()
4708 "Indent forward -- `C-t' in Vi."
4709 (interactive)
4710 (setq vip-cted t)
4711 (indent-to (+ (current-column) vip-shift-width)))
4712
4713(defun vip-backward-indent ()
4714 "Backtab, C-d in VI"
4715 (interactive)
4716 (if vip-cted
4717 (let ((p (point)) (c (current-column)) bol (indent t))
4718 (if (vip-looking-back "[0^]")
4719 (progn
4720 (if (= ?^ (preceding-char)) (setq vip-preserve-indent t))
4721 (delete-backward-char 1)
4722 (setq p (point))
4723 (setq indent nil)))
4724 (save-excursion
4725 (beginning-of-line)
4726 (setq bol (point)))
4727 (if (re-search-backward "[^ \t]" bol 1) (forward-char))
4728 (delete-region (point) p)
4729 (if indent
4730 (indent-to (- c vip-shift-width)))
4731 (if (or (bolp) (vip-looking-back "[^ \t]"))
4732 (setq vip-cted nil)))))
4733
4734(defun vip-autoindent ()
4735 "Auto Indentation, Vi-style."
4736 (interactive)
4737 (let ((col (current-indentation)))
4738 (if (not vip-preserve-indent)
4739 (setq vip-current-indent col)
4740 (setq vip-preserve-indent nil))
4af0c23b 4741 ;; don't leave whitespace lines around
27571f90
MK
4742 (if (memq last-command
4743 '(vip-autoindent
4744 vip-open-line vip-Open-line
4745 vip-replace-state-exit-cmd))
4af0c23b 4746 (indent-to-left-margin))
6c2e12f4
KH
4747 (newline 1)
4748 (if vip-auto-indent
4749 (progn
4750 (setq vip-cted t)
4751 (indent-to vip-current-indent)))))
4752
4753
4754;; Viewing registers
4755
4756(defun vip-ket-function (arg)
4757 "Function called by \], the ket. View registers and call \]\]."
4758 (interactive "P")
4759 (let ((reg (read-char)))
4760 (cond ((vip-valid-register reg '(letter Letter))
4761 (view-register (downcase reg)))
4762 ((vip-valid-register reg '(digit))
4763 (let ((text (current-kill (- reg ?1) 'do-not-rotate)))
4764 (save-excursion
4765 (set-buffer (get-buffer-create "*Output*"))
4766 (delete-region (point-min) (point-max))
4767 (insert (format "Register %c contains the string:\n" reg))
4768 (insert text)
4769 (goto-char (point-min)))
4770 (display-buffer "*Output*")))
4771 ((= ?\] reg)
4772 (vip-next-heading arg))
4773 (t (error
4774 vip-InvalidRegister reg)))))
4775
4776(defun vip-brac-function (arg)
4777 "Function called by \[, the brac. View textmarkers and call \[\["
4778 (interactive "P")
4779 (let ((reg (read-char)))
4780 (cond ((= ?\[ reg)
4781 (vip-prev-heading arg))
4782 ((= ?\] reg)
4783 (vip-heading-end arg))
4784 ((vip-valid-register reg '(letter))
4785 (let* ((val (get-register (1+ (- reg ?a))))
4786 (buf (if (not val)
4787 (error
4788 (format vip-EmptyTextmarker reg))
4789 (marker-buffer val)))
4790 (pos (marker-position val))
4791 line-no text (s pos) (e pos))
4792 (save-excursion
4793 (set-buffer (get-buffer-create "*Output*"))
4794 (delete-region (point-min) (point-max))
4795 (if (and buf pos)
4796 (progn
4797 (save-excursion
4798 (set-buffer buf)
4799 (setq line-no (1+ (count-lines (point-min) val)))
4800 (goto-char pos)
4801 (beginning-of-line)
4802 (if (re-search-backward "[^ \t]" nil t)
4803 (progn
4804 (beginning-of-line)
4805 (setq s (point))))
4806 (goto-char pos)
4807 (forward-line 1)
4808 (if (re-search-forward "[^ \t]" nil t)
4809 (progn
4810 (end-of-line)
4811 (setq e (point))))
4812 (setq text (buffer-substring s e))
4813 (setq text (format "%s<%c>%s"
4814 (substring text 0 (- pos s))
4815 reg (substring text (- pos s)))))
4816 (insert
4817 (format
4818 "Textmarker `%c' is in buffer `%s' at line %d.\n"
4819 reg (buffer-name buf) line-no))
4820 (insert (format "Here is some text around %c:\n\n %s"
4821 reg text)))
4822 (insert (format vip-EmptyTextmarker reg)))
4823 (goto-char (point-min)))
4824 (display-buffer "*Output*")))
4825 (t (error vip-InvalidTextmarker reg)))))
4826
4827
4828\f
4829;; commands in insertion mode
4830
4831(defun vip-delete-backward-word (arg)
4832 "Delete previous word."
4833 (interactive "p")
4834 (save-excursion
4835 (push-mark nil t)
4836 (backward-word arg)
4837 (delete-region (point) (mark t))
4838 (pop-mark)))
4839
4840
4841(defun vip-set-expert-level (&optional dont-change-unless)
4842 "Sets the expert level for a Viper user.
4843Can be called interactively to change (temporarily or permanently) the
4844current expert level.
4845
4846The optional argument DONT-CHANGE-UNLESS if not nil, says that
4847the level should not be changed, unless its current value is
4848meaningless (i.e., not one of 1,2,3,4,5).
4849
4850User level determines the setting of Viper variables that are most
4851sensitive for VI-style look-and-feel."
4852
4853 (interactive)
4854
4855 (if (not (numberp vip-expert-level)) (setq vip-expert-level 0))
4856
4857 (save-window-excursion
4858 (delete-other-windows)
4859 ;; if 0 < vip-expert-level < vip-max-expert-level
4860 ;; & dont-change-unless = t -- use it; else ask
4861 (vip-ask-level dont-change-unless))
4862
4863 (setq vip-always t
4864 vip-ex-style-motion t
4865 vip-ex-style-editing-in-insert t
4866 vip-want-ctl-h-help nil)
4867
4868 (cond
4869 ;; a novice or a beginner
4870 ((eq vip-expert-level 1)
4871 (global-set-key vip-toggle-key ;; in emacs-state
4af0c23b 4872 (if (vip-window-display-p)
6c2e12f4
KH
4873 'vip-iconify
4874 'suspend-emacs))
4875 (setq vip-no-multiple-ESC t
4876 vip-re-search t
4877 vip-vi-style-in-minibuffer t
4878 vip-search-wrap-around-t t
4879 vip-want-emacs-keys-in-vi nil
4880 vip-want-emacs-keys-in-insert nil))
4881
4882 ;; an intermediate to guru
4883 ((and (> vip-expert-level 1) (< vip-expert-level 5))
4af0c23b 4884 (setq vip-no-multiple-ESC (if (vip-window-display-p) t 'twice)
6c2e12f4
KH
4885 vip-want-emacs-keys-in-vi t
4886 vip-want-emacs-keys-in-insert (> vip-expert-level 2))
4887
4888 (if (eq vip-expert-level 4) ; respect user's ex-style motions
4889 ; and vip-no-multiple-ESC
4890 (progn
4891 (setq-default vip-ex-style-editing-in-insert
4892 (cdr (assoc 'vip-ex-style-editing-in-insert
4893 vip-saved-user-settings))
4894 vip-ex-style-motion
4895 (cdr (assoc 'vip-ex-style-motion
4896 vip-saved-user-settings)))
4897 (setq vip-ex-style-motion
4898 (cdr (assoc 'vip-ex-style-motion vip-saved-user-settings))
4899 vip-ex-style-editing-in-insert
4900 (cdr (assoc 'vip-ex-style-editing-in-insert
4901 vip-saved-user-settings))
4902 vip-re-search
4903 (cdr (assoc 'vip-re-search vip-saved-user-settings))
4904 vip-no-multiple-ESC
4905 (cdr (assoc 'vip-no-multiple-ESC
4906 vip-saved-user-settings))))))
4907
4908 ;; A wizard
4909 ;; Ideally, if 5 is selected, a buffer should pop up to let the
4910 ;; user toggle variable values.
4911 (t (setq-default vip-ex-style-editing-in-insert
4912 (cdr (assoc 'vip-ex-style-editing-in-insert
4913 vip-saved-user-settings))
4914 vip-ex-style-motion
4915 (cdr (assoc 'vip-ex-style-motion
4916 vip-saved-user-settings)))
4917 (setq vip-want-ctl-h-help
4918 (cdr (assoc 'vip-want-ctl-h-help vip-saved-user-settings))
4919 vip-always
4920 (cdr (assoc 'vip-always vip-saved-user-settings))
4921 vip-no-multiple-ESC
4922 (cdr (assoc 'vip-no-multiple-ESC vip-saved-user-settings))
4923 vip-ex-style-motion
4924 (cdr (assoc 'vip-ex-style-motion vip-saved-user-settings))
4925 vip-ex-style-editing-in-insert
4926 (cdr (assoc 'vip-ex-style-editing-in-insert
4927 vip-saved-user-settings))
4928 vip-re-search
4929 (cdr (assoc 'vip-re-search vip-saved-user-settings))
4930 vip-want-emacs-keys-in-vi
4931 (cdr (assoc 'vip-want-emacs-keys-in-vi
4932 vip-saved-user-settings))
4933 vip-want-emacs-keys-in-insert
4934 (cdr (assoc 'vip-want-emacs-keys-in-insert
4935 vip-saved-user-settings)))))
4936 (vip-set-mode-vars-for vip-current-state)
4937 (if (or vip-always
4938 (and (> vip-expert-level 0) (> 5 vip-expert-level)))
4939 (vip-set-hooks)))
4940
4af0c23b 4941;; Ask user expert level.
6c2e12f4 4942(defun vip-ask-level (dont-change-unless)
6c2e12f4
KH
4943 (let ((ask-buffer " *vip-ask-level*")
4944 level-changed repeated)
4945 (save-window-excursion
4946 (switch-to-buffer ask-buffer)
4947
4948 (or (eq this-command 'vip-set-expert-level)
4949 (and
4950 (<= vip-expert-level vip-max-expert-level)
4951 (>= vip-expert-level 1))
4952 (progn
4953 (insert "
4954
4955 *** Important Notice for VIP users***
4956
4957 This is VIPER
4958
4959@joke
4960Viper Is a Package for Emacs Rebels,
4961a VI Plan for Emacs Rescue,
4962and a venomous VI PERil.
4963@end joke
4964
4965Technically speaking, Viper is a new Vi emulator that replaces
4966the old VIP package.
4967
4968Viper emulates Vi much better than VIP. It also significantly
4969extends and improves upon Vi in many useful ways.
4970
4971Although many VIP settings in your ~/.vip are compatible with Viper,
4972you may have to change some of them. Please refer to the documentation,
4973which can be obtained by executing
4974
4975:help
4976
4977when Viper is in Vi state.
4978
4979If you will be so lucky as to find a bug, report it via the command
4980
4981:submitReport
4982
4983Type any key to continue... ")
4984
4985 (read-char)
4986 (erase-buffer)))
4987
4988 (while (or (> vip-expert-level vip-max-expert-level)
4989 (< vip-expert-level 1)
4990 (null dont-change-unless))
4991 (erase-buffer)
4992 (if repeated
4993 (progn
4994 (message "Invalid user level")
4995 (beep 1))
4996 (setq repeated t))
4997 (setq dont-change-unless t
4998 level-changed t)
4999 (insert "
5000Please specify your level of familiarity with the venomous VI PERil
5001(and the VI Plan for Emacs Rescue).
5002You can change it at any time by typing `M-x vip-set-expert-level RET'
5003
5004 1 -- BEGINNER: Almost all Emacs features are suppressed.
5005 Feels almost like straight Vi. File name completion and
5006 command history in the minibuffer are thrown in as a bonus.
5007 To use Emacs productively, you must reach level 3 or higher.
5008 2 -- MASTER: C-c now has its standard Emacs meaning in Vi command state,
5009 so most Emacs commands can be used when Viper is in Vi state.
5010 Good progress---you are well on the way to level 3!
5011 3 -- GRAND MASTER: Like 3, but most Emacs commands are available also
5012 in Viper's insert state.
5013 4 -- GURU: Like 3, but user settings are respected for vip-no-multiple-ESC,
5014 vip-re-search, vip-ex-style-motion, & vip-ex-style-editing-in-insert
5015 variables. Adjust these settings to your taste.
5016 5 -- WIZARD: Like 4, but user settings are also respected for vip-always,
5017 vip-want-ctl-h-help, vip-want-emacs-keys-in-vi, and
5018 vip-want-emacs-keys-in-insert. Adjust these to your taste.
5019
5020Please, specify your level now: ")
5021
5022 (setq vip-expert-level (- (vip-read-char-exclusive) ?0))
5023 ) ; end while
5024
5025 ;; tell the user if level was changed
5026 (and level-changed
5027 (progn
5028 (insert
5029 (format "\n\n\n\n\n\t\tYou have selected user level %d"
5030 vip-expert-level))
5031 (if (y-or-n-p "Do you wish to make this change permanent? ")
5032 ;; save the setting for vip-expert-level
5033 (vip-save-setting
5034 'vip-expert-level
5035 (format "Saving user level %d ..." vip-expert-level)
5036 vip-custom-file-name))
5037 ))
5038 (bury-buffer) ; remove ask-buffer from screen
5039 (message "")
5040 )))
5041
5042
5043(defun viper-version ()
5044 (interactive)
5045 (message "Viper version is %s" viper-version))
5046
5047(defalias 'vip-version 'viper-version)
5048
5049(defun vip-nil ()
5050 (interactive)
5051 (beep 1))
5052
5053
5054;; Returns t, if the string before point matches the regexp STR.
5055(defsubst vip-looking-back (str)
5056 (and (save-excursion (re-search-backward str nil t))
5057 (= (point) (match-end 0))))
5058
5059
5060
5061;; if ENFORCE-BUFFER is not nil, error if CHAR is a marker in another buffer
5062(defun vip-register-to-point (char &optional enforce-buffer)
5063 "Like jump-to-register, but switches to another buffer in another window."
5064 (interactive "cViper register to point: ")
5065 (let ((val (get-register char)))
5066 (cond
5067 ((and (fboundp 'frame-configuration-p)
5068 (frame-configuration-p val))
5069 (set-frame-configuration val))
5070 ((window-configuration-p val)
5071 (set-window-configuration val))
5072 ((vip-valid-marker val)
5073 (if (and enforce-buffer
5074 (not (equal (current-buffer) (marker-buffer val))))
5075 (error (concat vip-EmptyTextmarker " in this buffer")
5076 (1- (+ char ?a))))
5077 (pop-to-buffer (marker-buffer val))
5078 (goto-char val))
5079 ((and (consp val) (eq (car val) 'file))
5080 (find-file (cdr val)))
5081 (t
5082 (error vip-EmptyTextmarker (1- (+ char ?a)))))))
5083
5084
5085(defun vip-save-kill-buffer ()
5086 "Save then kill current buffer. "
5087 (interactive)
5088 (if (< vip-expert-level 2)
5089 (save-buffers-kill-emacs)
5090 (save-buffer)
5091 (kill-buffer (current-buffer))))
5092
5093
5094\f
5095;;; Bug Report
5096
5097(defun vip-submit-report ()
5098 "Submit bug report on Viper."
5099 (interactive)
5100 (let ((reporter-prompt-for-summary-p t)
4af0c23b 5101 (vip-device-type (vip-device-type))
6c2e12f4
KH
5102 color-display-p frame-parameters
5103 minibuffer-emacs-face minibuffer-vi-face minibuffer-insert-face
5104 varlist salutation window-config)
5105
5106 ;; If mode info is needed, add variable to `let' and then set it below,
5107 ;; like we did with color-display-p.
4af0c23b
KH
5108 (setq color-display-p (if (vip-window-display-p)
5109 (vip-color-display-p)
6c2e12f4 5110 'non-x)
4af0c23b 5111 minibuffer-vi-face (if (vip-window-display-p)
6c2e12f4
KH
5112 (vip-get-face vip-minibuffer-vi-face)
5113 'non-x)
4af0c23b 5114 minibuffer-insert-face (if (vip-window-display-p)
6c2e12f4
KH
5115 (vip-get-face vip-minibuffer-insert-face)
5116 'non-x)
4af0c23b 5117 minibuffer-emacs-face (if (vip-window-display-p)
6c2e12f4
KH
5118 (vip-get-face vip-minibuffer-emacs-face)
5119 'non-x)
4af0c23b
KH
5120 frame-parameters (if (fboundp 'frame-parameters)
5121 (frame-parameters (selected-frame))))
6c2e12f4
KH
5122
5123 (setq varlist (list 'vip-vi-minibuffer-minor-mode
5124 'vip-insert-minibuffer-minor-mode
5125 'vip-vi-intercept-minor-mode
5126 'vip-vi-local-user-minor-mode
5127 'vip-vi-kbd-minor-mode
5128 'vip-vi-global-user-minor-mode
5129 'vip-vi-state-modifier-minor-mode
5130 'vip-vi-diehard-minor-mode
5131 'vip-vi-basic-minor-mode
5132 'vip-replace-minor-mode
5133 'vip-insert-intercept-minor-mode
5134 'vip-insert-local-user-minor-mode
5135 'vip-insert-kbd-minor-mode
5136 'vip-insert-global-user-minor-mode
5137 'vip-insert-state-modifier-minor-mode
5138 'vip-insert-diehard-minor-mode
5139 'vip-insert-basic-minor-mode
5140 'vip-emacs-intercept-minor-mode
5141 'vip-emacs-local-user-minor-mode
5142 'vip-emacs-kbd-minor-mode
5143 'vip-emacs-global-user-minor-mode
5144 'vip-emacs-state-modifier-minor-mode
5145 'vip-automatic-iso-accents
5146 'vip-want-emacs-keys-in-insert
5147 'vip-want-emacs-keys-in-vi
5148 'vip-keep-point-on-undo
5149 'vip-no-multiple-ESC
5150 'vip-ESC-key
5151 'vip-want-ctl-h-help
5152 'vip-ex-style-editing-in-insert
5153 'vip-delete-backwards-in-replace
5154 'vip-vi-style-in-minibuffer
04090c34
MK
5155 'vip-vi-state-hook
5156 'vip-insert-state-hook
5157 'vip-replace-state-hook
5158 'vip-emacs-state-hook
6c2e12f4
KH
5159 'ex-cycle-other-window
5160 'ex-cycle-through-non-files
5161 'vip-expert-level
5162 'major-mode
4af0c23b 5163 'vip-device-type
6c2e12f4
KH
5164 'color-display-p
5165 'frame-parameters
5166 'minibuffer-vi-face
5167 'minibuffer-insert-face
5168 'minibuffer-emacs-face
5169 ))
5170 (setq salutation "
5171Congratulations! You may have unearthed a bug in Viper!
5172Please mail a concise, accurate summary of the problem to the address above.
5173
5174-------------------------------------------------------------------")
5175 (setq window-config (current-window-configuration))
5176 (with-output-to-temp-buffer " *vip-info*"
5177 (switch-to-buffer " *vip-info*")
5178 (delete-other-windows)
5179 (princ "
5180PLEASE FOLLOW THESE PROCEDURES
5181------------------------------
5182
5183Before reporting a bug, please verify that it is related to Viper, and is
5184not cause by other packages you are using.
5185
5186Don't report compilation warnings, unless you are certain that there is a
5187problem. These warnings are normal and unavoidable.
5188
5189Please note that users should not modify variables and keymaps other than
5190those advertised in the manual. Such `customization' is likely to crash
5191Viper, as it would any other improperly customized Emacs package.
5192
5193If you are reporting an error message received while executing one of the
5194Viper commands, type:
5195
5196 M-x set-variable <Return> debug-on-error <Return> t <Return>
5197
5198Then reproduce the error. The above command will cause Emacs to produce a
5199back trace of the execution that leads to the error. Please include this
5200trace in your bug report.
5201
5202If you believe that one of Viper's commands goes into an infinite loop
5203\(e.g., Emacs freezes\), type:
5204
5205 M-x set-variable <Return> debug-on-quit <Return> t <Return>
5206
5207Then reproduce the problem. Wait for a few seconds, then type C-g to abort
5208the current command. Include the resulting back trace in the bug report.
5209
5210Mail anyway (y or n)? ")
5211 (if (y-or-n-p "Mail anyway? ")
5212 ()
5213 (set-window-configuration window-config)
5214 (error "Bug report aborted")))
5215
5216 (require 'reporter)
5217 (set-window-configuration window-config)
5218
5219 (reporter-submit-bug-report "kifer@cs.sunysb.edu"
5220 (vip-version)
5221 varlist
5222 nil 'delete-other-windows
5223 salutation)
5224 ))
5225
5226
5227
5228
4af0c23b 5229;; Smoothes out the difference between Emacs' unread-command-events
6c2e12f4
KH
5230;; and XEmacs unread-command-event. Arg is a character, an event, a list of
5231;; events or a sequence of keys.
6c2e12f4 5232;;
4af0c23b
KH
5233;; Due to the way unread-command-events in Emacs (not XEmacs), a non-event
5234;; symbol in unread-command-events list may cause Emacs to turn this symbol
5235;; into an event. Below, we delete nil from event lists, since nil is the most
5236;; common symbol that might appear in this wrong context.
6c2e12f4
KH
5237(defun vip-set-unread-command-events (arg)
5238 (if vip-emacs-p
4af0c23b
KH
5239 (setq
5240 unread-command-events
5241 (let ((new-events
5242 (cond ((eventp arg) (list arg))
5243 ((listp arg) arg)
5244 ((sequencep arg)
5245 (listify-key-sequence arg))
5246 (t (error
5247 "vip-set-unread-command-events: Invalid argument, %S"
5248 arg)))))
5249 (if (not (eventp nil))
5250 (setq new-events (delq nil new-events)))
5251 (append new-events unread-command-events)))
6c2e12f4 5252 ;; XEmacs
4af0c23b
KH
5253 (setq
5254 unread-command-events
5255 (append
5256 (cond ((numberp arg) (list (character-to-event arg)))
5257 ((eventp arg) (list arg))
5258 ((stringp arg) (mapcar 'character-to-event arg))
5259 ((vectorp arg) (append arg nil)) ; turn into list
27571f90 5260 ((listp arg) (vip-eventify-list-xemacs arg))
4af0c23b
KH
5261 (t (error
5262 "vip-set-unread-command-events: Invalid argument, %S" arg)))
5263 unread-command-events))))
27571f90
MK
5264
5265;; list is assumed to be a list of events of characters
5266(defun vip-eventify-list-xemacs (lis)
5267 (mapcar
5268 (function (lambda (elt)
5269 (cond ((numberp elt) (character-to-event elt))
5270 ((eventp elt) elt)
5271 (t (error
5272 "vip-eventify-list-xemacs: can't convert to event, %S"
5273 elt)))))
5274 lis))
5275
6c2e12f4
KH
5276
5277\f
5278;;; Bring in the rest of the files
5279(require 'viper-mous)
5280(require 'viper-macs)
5281(require 'viper-ex)
5282
5283
5284\f
5285;; The following is provided for compatibility with older VIP's
5286
5287(defalias 'vip-change-mode-to-vi 'vip-change-state-to-vi)
5288(defalias 'vip-change-mode-to-insert 'vip-change-state-to-insert)
5289(defalias 'vip-change-mode-to-emacs 'vip-change-state-to-emacs)
6c2e12f4
KH
5290
5291
5292\f
4af0c23b
KH
5293;;; Load .vip and set up hooks
5294
5295;; This hook designed to enable Vi-style editing in comint-based modes."
5296(defun vip-comint-mode-hook ()
04090c34 5297 (setq require-final-newline nil)
6c2e12f4
KH
5298 (setq vip-ex-style-editing-in-insert nil
5299 vip-ex-style-motion nil)
5300 (vip-add-local-keys 'vi-state
5301 '(("\C-m" . comint-send-input) ; return
5302 ("\C-d" . comint-delchar-or-maybe-eof))) ; \C-d
5303 (vip-add-local-keys 'insert-state
5304 '(("\C-m" . comint-send-input) ; return
5305 ("\C-d" . comint-delchar-or-maybe-eof))) ; \C-d
5306 )
5307
5308
04090c34 5309;; This sets major mode hooks to make them come up in vi-state.
6c2e12f4
KH
5310(defun vip-set-hooks ()
5311
5312 ;; It is of course a misnomer to call viper-mode a `major mode'.
5313 ;; However, this has the effect that if the user didn't specify the
5314 ;; default mode, new buffers that fall back on the default will come up
5315 ;; in Fundamental Mode and Vi state.
5316 (setq default-major-mode 'viper-mode)
5317
4af0c23b 5318 ;; The following major modes should come up in vi-state
6c2e12f4 5319 (defadvice fundamental-mode (after vip-fundamental-mode-ad activate)
4af0c23b 5320 "Run `vip-change-state-to-vi' on entry."
6c2e12f4 5321 (vip-change-state-to-vi))
4af0c23b
KH
5322
5323 (defvar help-mode-hook nil)
5324 (add-hook 'help-mode-hook 'viper-mode)
6c2e12f4 5325
6c2e12f4
KH
5326 (defvar emacs-lisp-mode-hook nil)
5327 (add-hook 'emacs-lisp-mode-hook 'viper-mode)
5328
d695b318
MK
5329 (defvar html-mode-hook nil)
5330 (add-hook 'html-mode-hook 'viper-mode)
5331
6c2e12f4
KH
5332 (defvar lisp-mode-hook nil)
5333 (add-hook 'lisp-mode-hook 'viper-mode)
5334
5335 (defvar bibtex-mode-hook nil)
5336 (add-hook 'bibtex-mode-hook 'viper-mode)
5337
5338 (defvar cc-mode-hook nil)
5339 (add-hook 'cc-mode-hook 'viper-mode)
5340
5341 (defvar c-mode-hook nil)
5342 (add-hook 'c-mode-hook 'viper-mode)
5343
5344 (defvar c++-mode-hook nil)
5345 (add-hook 'c++-mode-hook 'viper-mode)
5346
5347 (defvar lisp-interaction-mode-hook nil)
5348 (add-hook 'lisp-interaction-mode-hook 'viper-mode)
5349
5350 (defvar text-mode-hook nil)
5351 (add-hook 'text-mode-hook 'viper-mode)
5352
5353 (add-hook 'completion-list-mode-hook 'viper-mode)
5354 (add-hook 'compilation-mode-hook 'viper-mode)
5355
5356 (defvar emerge-startup-hook nil)
5357 (add-hook 'emerge-startup-hook 'vip-change-state-to-emacs)
5358 ;; Run vip-change-state-to-vi after quitting emerge.
4af0c23b
KH
5359 (vip-eval-after-load
5360 "emerge"
5361 '(defadvice emerge-quit (after vip-emerge-advice activate)
5362 "Run `vip-change-state-to-vi' after quitting emerge."
5363 (vip-change-state-to-vi)))
6c2e12f4
KH
5364 ;; In case Emerge was loaded before Viper.
5365 (defadvice emerge-quit (after vip-emerge-advice activate)
4af0c23b
KH
5366 "Run `vip-change-state-to-vi' after quitting emerge."
5367 (vip-change-state-to-vi))
6c2e12f4 5368
4af0c23b
KH
5369 (vip-eval-after-load
5370 "asm-mode"
5371 '(defadvice asm-mode (after vip-asm-mode-ad activate)
5372 "Run `vip-change-state-to-vi' on entry."
5373 (vip-change-state-to-vi)))
6c2e12f4
KH
5374
5375 ;; passwd.el sets up its own buffer, which turns up in Vi mode,
27571f90 5376 ;; thus overriding the local map. We don't need Vi mode here.
6c2e12f4
KH
5377 (vip-eval-after-load
5378 "passwd"
5379 '(defadvice read-passwd-1 (before vip-passwd-ad activate)
4af0c23b 5380 "Switch to emacs state while reading password."
6c2e12f4
KH
5381 (vip-change-state-to-emacs)))
5382
4af0c23b
KH
5383 ;; Emacs shell, ange-ftp, and comint-based modes
5384 (defvar comint-mode-hook nil)
5385 (add-hook 'comint-mode-hook 'vip-change-state-to-insert)
5386 (add-hook 'comint-mode-hook 'vip-comint-mode-hook)
6c2e12f4
KH
5387
5388 ;; Shell scripts
5389 (defvar sh-mode-hook nil)
5390 (add-hook 'sh-mode-hook 'viper-mode)
5391
5392 ;; Dired
5393 ;; This is only necessary when the user uses vip-modify-major-mode
5394 (add-hook 'dired-mode-hook 'vip-change-state-to-emacs)
5395
d695b318
MK
5396 (if vip-emacs-p
5397 (progn
5398 (defvar view-mode-hook nil
5399 "View hook. Run after view mode.")
5400 (add-hook 'view-mode-hook 'vip-change-state-to-emacs))
5401 (defadvice view-minor-mode (after vip-view-ad activate)
5402 "Switch to Emacs state in View mode."
5403 (vip-change-state-to-emacs))
5404 (defvar view-hook nil
5405 "View hook. Run after view mode.")
5406 (add-hook 'view-hook 'vip-change-state-to-emacs))
6c2e12f4
KH
5407
5408 ;; For VM users.
5409 ;; Put summary and other VM buffers in Emacs state.
5410 (defvar vm-mode-hooks nil
5411 "This hook is run after vm is started.")
5412 (defvar vm-summary-mode-hooks nil
5413 "This hook is run after vm switches to summary mode.")
5414 (add-hook 'vm-mode-hooks 'vip-change-state-to-emacs)
5415 (add-hook 'vm-summary-mode-hooks 'vip-change-state-to-emacs)
5416
5417 ;; For RMAIL users.
5418 ;; Put buf in Emacs state after edit.
5419 (vip-eval-after-load
5420 "rmailedit"
5421 '(defadvice rmail-cease-edit (after vip-rmail-advice activate)
4af0c23b 5422 "Switch to emacs state when done editing message."
6c2e12f4
KH
5423 (vip-change-state-to-emacs)))
5424 ;; In case RMAIL was loaded before Viper.
5425 (defadvice rmail-cease-edit (after vip-rmail-advice activate)
4af0c23b
KH
5426 "Switch to emacs state when done editing message."
5427 (vip-change-state-to-emacs))
6c2e12f4
KH
5428 ) ; vip-set-hooks
5429
d695b318
MK
5430;; Set some useful macros
5431;; These must be before we load .vip, so the user can unrecord them.
5432
5433;; repeat the 2nd previous command without rotating the command history
5434(vip-record-kbd-macro
5435 (vector vip-repeat-from-history-key '\1) 'vi-state
5436 [(meta x) v i p - r e p e a t - f r o m - h i s t o r y return] 't)
5437;; repeat the 3d previous command without rotating the command history
5438(vip-record-kbd-macro
5439 (vector vip-repeat-from-history-key '\2) 'vi-state
5440 [(meta x) v i p - r e p e a t - f r o m - h i s t o r y return] 't)
5441
5442;; toggle case sensitivity in search
5443(vip-record-kbd-macro
5444 "//" 'vi-state
5445 [1 (meta x) v i p - t o g g l e - s e a r c h - s t y l e return] 't)
05497fc6 5446;; toggle regexp/vanilla search
d695b318
MK
5447(vip-record-kbd-macro
5448 "///" 'vi-state
5449 [2 (meta x) v i p - t o g g l e - s e a r c h - s t y l e return] 't)
5450
6c2e12f4
KH
5451
5452;; ~/.vip is loaded if it exists
5453(if (and (file-exists-p vip-custom-file-name)
5454 (not noninteractive))
5455 (load vip-custom-file-name))
5456
5457;; VIP compatibility: merge whatever the user has in vip-mode-map into
5458;; Viper's basic map.
5459(vip-add-keymap vip-mode-map vip-vi-global-user-map)
5460
5461\f
5462;; Applying Viper customization -- runs after (load .vip)
5463
05497fc6 5464;; Save user settings or Viper defaults for vars controlled by vip-expert-level
6c2e12f4
KH
5465(setq vip-saved-user-settings
5466 (list (cons 'vip-want-ctl-h-help vip-want-ctl-h-help)
5467 (cons 'vip-always vip-always)
5468 (cons 'vip-no-multiple-ESC vip-no-multiple-ESC)
5469 (cons 'vip-ex-style-motion vip-ex-style-motion)
5470 (cons 'vip-ex-style-editing-in-insert
5471 vip-ex-style-editing-in-insert)
5472 (cons 'vip-want-emacs-keys-in-vi vip-want-emacs-keys-in-vi)
5473 (cons 'vip-want-emacs-keys-in-insert vip-want-emacs-keys-in-insert)
5474 (cons 'vip-re-search vip-re-search)))
5475
5476
5477(vip-set-minibuffer-style)
5478(vip-set-minibuffer-faces)
5479(vip-set-search-face)
d695b318
MK
5480(if vip-buffer-search-char
5481 (vip-buffer-search-enable))
04090c34 5482(vip-update-alphanumeric-class)
6c2e12f4
KH
5483
5484;;; Familiarize Viper with some minor modes that have their own keymaps
5485(vip-harness-minor-mode "compile")
5486(vip-harness-minor-mode "outline")
5487(vip-harness-minor-mode "allout")
5488(vip-harness-minor-mode "xref")
5489(vip-harness-minor-mode "lmenu")
5490(vip-harness-minor-mode "vc")
5491(vip-harness-minor-mode "ltx-math") ; LaTeX-math-mode in AUC-TeX
4af0c23b 5492(vip-harness-minor-mode "latex") ; which is in one of these two files
d695b318
MK
5493(vip-harness-minor-mode "cyrillic")
5494(vip-harness-minor-mode "russian")
5495(vip-harness-minor-mode "view-less")
6c2e12f4
KH
5496
5497
5498;; Intercept maps could go in viper-keym.el
5499;; We keep them here in case someone redefines them in ~/.vip
5500
5501(define-key vip-vi-intercept-map vip-ESC-key 'vip-intercept-ESC-key)
5502(define-key vip-insert-intercept-map vip-ESC-key 'vip-intercept-ESC-key)
5503
5504;; This is taken care of by vip-insert-global-user-map.
5505;;(define-key vip-replace-map vip-ESC-key 'vip-intercept-ESC-key)
5506
5507(define-key vip-insert-intercept-map vip-toggle-key 'vip-alternate-ESC)
5508;; The default vip-toggle-key is \C-z; for the novice, it suspends or
5509;; iconifies Emacs
5510(define-key vip-vi-intercept-map vip-toggle-key
5511 '(lambda () (interactive)
5512 (if (and (< vip-expert-level 2) (equal vip-toggle-key "\C-z"))
4af0c23b 5513 (if (vip-window-display-p) (vip-iconify) (suspend-emacs))
6c2e12f4
KH
5514 (vip-change-state-to-emacs))))
5515
5516(define-key vip-emacs-intercept-map vip-toggle-key 'vip-change-state-to-vi)
5517
5518
5519(if (or vip-always
5520 (and (< vip-expert-level 5) (> vip-expert-level 0)))
5521 (vip-set-hooks))
5522
5523;; Let all minor modes take effect after loading
5524;; this may not be enough, so we also set default minor-mode-alist.
5525;; Without setting the default, new buffers that come up in emacs mode have
5526;; minor-mode-map-alist = nil, unless we call vip-change-state-*
5527(if (eq vip-current-state 'emacs-state)
5528 (progn
5529 (vip-change-state-to-emacs)
5530 (setq-default minor-mode-map-alist minor-mode-map-alist)
5531 ))
5532
6c2e12f4 5533
04090c34 5534(run-hooks 'vip-load-hook) ; the last chance to change something
6c2e12f4
KH
5535
5536(provide 'viper)
5537(provide 'vip19)
5538(provide 'vip)
5539
5540;;; viper.el ends here