Merged from emacs@sv.gnu.org
[emacs.git] / lisp / emulation / viper-cmd.el
blob645f4f26eaf180bf98cf0b75b9ff560f20ac0187
1 ;;; viper-cmd.el --- Vi command support for Viper
3 ;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4 ;; 2005, 2006 Free Software Foundation, Inc.
6 ;; Author: Michael Kifer <kifer@cs.stonybrook.edu>
8 ;; This file is part of GNU Emacs.
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; any later version.
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 ;; Boston, MA 02110-1301, USA.
25 ;;; Commentary:
27 ;;; Code:
29 (provide 'viper-cmd)
30 (require 'advice)
32 ;; Compiler pacifier
33 (defvar viper-minibuffer-current-face)
34 (defvar viper-minibuffer-insert-face)
35 (defvar viper-minibuffer-vi-face)
36 (defvar viper-minibuffer-emacs-face)
37 (defvar viper-always)
38 (defvar viper-mode-string)
39 (defvar viper-custom-file-name)
40 (defvar viper--key-maps)
41 (defvar viper--intercept-key-maps)
42 (defvar iso-accents-mode)
43 (defvar quail-mode)
44 (defvar quail-current-str)
45 (defvar zmacs-region-stays)
46 (defvar mark-even-if-inactive)
47 (defvar init-message)
48 (defvar initial)
50 ;; loading happens only in non-interactive compilation
51 ;; in order to spare non-viperized emacs from being viperized
52 (if noninteractive
53 (eval-when-compile
54 (let ((load-path (cons (expand-file-name ".") load-path)))
55 (or (featurep 'viper-util)
56 (load "viper-util.el" nil nil 'nosuffix))
57 (or (featurep 'viper-keym)
58 (load "viper-keym.el" nil nil 'nosuffix))
59 (or (featurep 'viper-mous)
60 (load "viper-mous.el" nil nil 'nosuffix))
61 (or (featurep 'viper-macs)
62 (load "viper-macs.el" nil nil 'nosuffix))
63 (or (featurep 'viper-ex)
64 (load "viper-ex.el" nil nil 'nosuffix))
65 )))
66 ;; end pacifier
69 (require 'viper-util)
70 (require 'viper-keym)
71 (require 'viper-mous)
72 (require 'viper-macs)
73 (require 'viper-ex)
77 ;; Generic predicates
79 ;; These test functions are shamelessly lifted from vip 4.4.2 by Aamod Sane
81 ;; generate test functions
82 ;; given symbol foo, foo-p is the test function, foos is the set of
83 ;; Viper command keys
84 ;; (macroexpand '(viper-test-com-defun foo))
85 ;; (defun foo-p (com) (consp (memq com foos)))
87 (defmacro viper-test-com-defun (name)
88 (let* ((snm (symbol-name name))
89 (nm-p (intern (concat snm "-p")))
90 (nms (intern (concat snm "s"))))
91 `(defun ,nm-p (com)
92 (consp (viper-memq-char com ,nms)
93 ))))
95 ;; Variables for defining VI commands
97 ;; Modifying commands that can be prefixes to movement commands
98 (defvar viper-prefix-commands '(?c ?d ?y ?! ?= ?# ?< ?> ?\"))
99 ;; define viper-prefix-command-p
100 (viper-test-com-defun viper-prefix-command)
102 ;; Commands that are pairs eg. dd. r and R here are a hack
103 (defconst viper-charpair-commands '(?c ?d ?y ?! ?= ?< ?> ?r ?R))
104 ;; define viper-charpair-command-p
105 (viper-test-com-defun viper-charpair-command)
107 (defconst viper-movement-commands '(?b ?B ?e ?E ?f ?F ?G ?h ?H ?j ?k ?l
108 ?H ?M ?L ?n ?t ?T ?w ?W ?$ ?%
109 ?^ ?( ?) ?- ?+ ?| ?{ ?} ?[ ?] ?' ?`
110 ?\; ?, ?0 ?? ?/ ?\ ?\C-m
111 space return
112 delete backspace
114 "Movement commands")
115 ;; define viper-movement-command-p
116 (viper-test-com-defun viper-movement-command)
118 ;; Vi digit commands
119 (defconst viper-digit-commands '(?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9))
121 ;; define viper-digit-command-p
122 (viper-test-com-defun viper-digit-command)
124 ;; Commands that can be repeated by . (dotted)
125 (defconst viper-dotable-commands '(?c ?d ?C ?s ?S ?D ?> ?<))
126 ;; define viper-dotable-command-p
127 (viper-test-com-defun viper-dotable-command)
129 ;; Commands that can follow a #
130 (defconst viper-hash-commands '(?c ?C ?g ?q ?s))
131 ;; define viper-hash-command-p
132 (viper-test-com-defun viper-hash-command)
134 ;; Commands that may have registers as prefix
135 (defconst viper-regsuffix-commands '(?d ?y ?Y ?D ?p ?P ?x ?X))
136 ;; define viper-regsuffix-command-p
137 (viper-test-com-defun viper-regsuffix-command)
139 (defconst viper-vi-commands (append viper-movement-commands
140 viper-digit-commands
141 viper-dotable-commands
142 viper-charpair-commands
143 viper-hash-commands
144 viper-prefix-commands
145 viper-regsuffix-commands)
146 "The list of all commands in Vi-state.")
147 ;; define viper-vi-command-p
148 (viper-test-com-defun viper-vi-command)
150 ;; Where viper saves mark. This mark is resurrected by m^
151 (defvar viper-saved-mark nil)
153 ;; Contains user settings for vars affected by viper-set-expert-level function.
154 ;; Not a user option.
155 (defvar viper-saved-user-settings nil)
159 ;;; CODE
161 ;; sentinels
163 ;; Runs viper-after-change-functions inside after-change-functions
164 (defun viper-after-change-sentinel (beg end len)
165 (run-hook-with-args 'viper-after-change-functions beg end len))
167 ;; Runs viper-before-change-functions inside before-change-functions
168 (defun viper-before-change-sentinel (beg end)
169 (run-hook-with-args 'viper-before-change-functions beg end))
171 (defsubst viper-post-command-sentinel ()
172 (run-hooks 'viper-post-command-hooks)
173 (if (eq viper-current-state 'vi-state)
174 (viper-restore-cursor-color 'after-insert-mode)))
176 (defsubst viper-pre-command-sentinel ()
177 (run-hooks 'viper-pre-command-hooks))
179 ;; Needed so that Viper will be able to figure the last inserted
180 ;; chunk of text with reasonable accuracy.
181 (defsubst viper-insert-state-post-command-sentinel ()
182 (if (and (memq viper-current-state '(insert-state replace-state))
183 viper-insert-point
184 (>= (point) viper-insert-point))
185 (setq viper-last-posn-while-in-insert-state (point-marker)))
186 (or (viper-overlay-p viper-replace-overlay)
187 (progn
188 (viper-set-replace-overlay (point-min) (point-min))
189 (viper-hide-replace-overlay)))
190 (if (eq viper-current-state 'insert-state)
191 (let ((has-saved-cursor-color-in-insert-mode
192 (stringp (viper-get-saved-cursor-color-in-insert-mode))))
193 (or has-saved-cursor-color-in-insert-mode
194 (string= (viper-get-cursor-color) viper-insert-state-cursor-color)
195 ;; save current color, if not already saved
196 (viper-save-cursor-color 'before-insert-mode))
197 ;; set insert mode cursor color
198 (viper-change-cursor-color viper-insert-state-cursor-color)))
199 (if (eq viper-current-state 'emacs-state)
200 (let ((has-saved-cursor-color-in-emacs-mode
201 (stringp (viper-get-saved-cursor-color-in-emacs-mode))))
202 (or has-saved-cursor-color-in-emacs-mode
203 (string= (viper-get-cursor-color) viper-emacs-state-cursor-color)
204 ;; save current color, if not already saved
205 (viper-save-cursor-color 'before-emacs-mode))
206 ;; set emacs mode cursor color
207 (viper-change-cursor-color viper-emacs-state-cursor-color)))
209 (if (and (memq this-command '(dabbrev-expand hippie-expand))
210 (integerp viper-pre-command-point)
211 (markerp viper-insert-point)
212 (marker-position viper-insert-point)
213 (> viper-insert-point viper-pre-command-point))
214 (viper-move-marker-locally viper-insert-point viper-pre-command-point))
217 (defsubst viper-preserve-cursor-color ()
218 (or (memq this-command '(self-insert-command
219 viper-del-backward-char-in-insert
220 viper-del-backward-char-in-replace
221 viper-delete-backward-char
222 viper-join-lines
223 viper-delete-char))
224 (memq (viper-event-key last-command-event)
225 '(up down left right (meta f) (meta b)
226 (control n) (control p) (control f) (control b)))))
228 (defsubst viper-insert-state-pre-command-sentinel ()
229 (or (viper-preserve-cursor-color)
230 (viper-restore-cursor-color 'after-insert-mode))
231 (if (and (memq this-command '(dabbrev-expand hippie-expand))
232 (markerp viper-insert-point)
233 (marker-position viper-insert-point))
234 (setq viper-pre-command-point (marker-position viper-insert-point))))
236 (defsubst viper-R-state-post-command-sentinel ()
237 ;; Restoring cursor color is needed despite
238 ;; viper-replace-state-pre-command-sentinel: When you jump to another buffer
239 ;; in another frame, the pre-command hook won't change cursor color to
240 ;; default in that other frame. So, if the second frame cursor was red and
241 ;; we set the point outside the replacement region, then the cursor color
242 ;; will remain red. Restoring the default, below, prevents this.
243 (if (and (<= (viper-replace-start) (point))
244 (<= (point) (viper-replace-end)))
245 (viper-change-cursor-color viper-replace-overlay-cursor-color)
246 (viper-restore-cursor-color 'after-replace-mode)
249 ;; to speed up, don't change cursor color before self-insert
250 ;; and common move commands
251 (defsubst viper-replace-state-pre-command-sentinel ()
252 (or (viper-preserve-cursor-color)
253 (viper-restore-cursor-color 'after-replace-mode)))
256 ;; Make sure we don't delete more than needed.
257 ;; This is executed at viper-last-posn-in-replace-region
258 (defsubst viper-trim-replace-chars-to-delete-if-necessary ()
259 (setq viper-replace-chars-to-delete
260 (max 0
261 (min viper-replace-chars-to-delete
262 ;; Don't delete more than to the end of repl overlay
263 (viper-chars-in-region
264 (viper-replace-end) viper-last-posn-in-replace-region)
265 ;; point is viper-last-posn-in-replace-region now
266 ;; So, this limits deletion to the end of line
267 (viper-chars-in-region (point) (viper-line-pos 'end))
268 ))))
271 (defun viper-replace-state-post-command-sentinel ()
272 ;; Restoring cursor color is needed despite
273 ;; viper-replace-state-pre-command-sentinel: When one jumps to another buffer
274 ;; in another frame, the pre-command hook won't change cursor color to
275 ;; default in that other frame. So, if the second frame cursor was red and
276 ;; we set the point outside the replacement region, then the cursor color
277 ;; will remain red. Restoring the default, below, fixes this problem.
279 ;; We optimize for some commands, like self-insert-command,
280 ;; viper-delete-backward-char, etc., since they either don't change
281 ;; cursor color or, if they terminate replace mode, the color will be changed
282 ;; in viper-finish-change
283 (or (viper-preserve-cursor-color)
284 (viper-restore-cursor-color 'after-replace-mode))
285 (cond
286 ((eq viper-current-state 'replace-state)
287 ;; delete characters to compensate for inserted chars.
288 (let ((replace-boundary (viper-replace-end)))
289 (save-excursion
290 (goto-char viper-last-posn-in-replace-region)
291 (viper-trim-replace-chars-to-delete-if-necessary)
292 (delete-char viper-replace-chars-to-delete)
293 (setq viper-replace-chars-to-delete 0)
294 ;; terminate replace mode if reached replace limit
295 (if (= viper-last-posn-in-replace-region (viper-replace-end))
296 (viper-finish-change)))
298 (if (viper-pos-within-region
299 (point) (viper-replace-start) replace-boundary)
300 (progn
301 ;; the state may have changed in viper-finish-change above
302 (if (eq viper-current-state 'replace-state)
303 (viper-change-cursor-color viper-replace-overlay-cursor-color))
304 (setq viper-last-posn-in-replace-region (point-marker))))
306 ;; terminate replace mode if changed Viper states.
307 (t (viper-finish-change))))
310 ;; changing mode
312 ;; Change state to NEW-STATE---either emacs-state, vi-state, or insert-state.
313 (defun viper-change-state (new-state)
314 ;; Keep viper-post/pre-command-hooks fresh.
315 ;; We remove then add viper-post/pre-command-sentinel since it is very
316 ;; desirable that viper-pre-command-sentinel is the last hook and
317 ;; viper-post-command-sentinel is the first hook.
319 (viper-cond-compile-for-xemacs-or-emacs
320 ;; xemacs
321 (progn
322 (make-local-hook 'viper-after-change-functions)
323 (make-local-hook 'viper-before-change-functions)
324 (make-local-hook 'viper-post-command-hooks)
325 (make-local-hook 'viper-pre-command-hooks))
326 nil ; emacs
329 (remove-hook 'post-command-hook 'viper-post-command-sentinel)
330 (add-hook 'post-command-hook 'viper-post-command-sentinel)
331 (remove-hook 'pre-command-hook 'viper-pre-command-sentinel)
332 (add-hook 'pre-command-hook 'viper-pre-command-sentinel t)
333 ;; These hooks will be added back if switching to insert/replace mode
334 (remove-hook 'viper-post-command-hooks
335 'viper-insert-state-post-command-sentinel 'local)
336 (remove-hook 'viper-pre-command-hooks
337 'viper-insert-state-pre-command-sentinel 'local)
338 (setq viper-intermediate-command nil)
339 (cond ((eq new-state 'vi-state)
340 (cond ((member viper-current-state '(insert-state replace-state))
342 ;; move viper-last-posn-while-in-insert-state
343 ;; This is a normal hook that is executed in insert/replace
344 ;; states after each command. In Vi/Emacs state, it does
345 ;; nothing. We need to execute it here to make sure that
346 ;; the last posn was recorded when we hit ESC.
347 ;; It may be left unrecorded if the last thing done in
348 ;; insert/repl state was dabbrev-expansion or abbrev
349 ;; expansion caused by hitting ESC
350 (viper-insert-state-post-command-sentinel)
352 (condition-case conds
353 (progn
354 (viper-save-last-insertion
355 viper-insert-point
356 viper-last-posn-while-in-insert-state)
357 (if viper-began-as-replace
358 (setq viper-began-as-replace nil)
359 ;; repeat insert commands if numerical arg > 1
360 (save-excursion
361 (viper-repeat-insert-command))))
362 (error
363 (viper-message-conditions conds)))
365 (if (> (length viper-last-insertion) 0)
366 (viper-push-onto-ring viper-last-insertion
367 'viper-insertion-ring))
369 (if viper-ESC-moves-cursor-back
370 (or (bolp) (viper-beginning-of-field) (backward-char 1))))
373 ;; insert or replace
374 ((memq new-state '(insert-state replace-state))
375 (if (memq viper-current-state '(emacs-state vi-state))
376 (viper-move-marker-locally 'viper-insert-point (point)))
377 (viper-move-marker-locally
378 'viper-last-posn-while-in-insert-state (point))
379 (add-hook 'viper-post-command-hooks
380 'viper-insert-state-post-command-sentinel t 'local)
381 (add-hook 'viper-pre-command-hooks
382 'viper-insert-state-pre-command-sentinel t 'local))
383 ) ; outermost cond
385 ;; Nothing needs to be done to switch to emacs mode! Just set some
386 ;; variables, which is already done in viper-change-state-to-emacs!
388 ;; ISO accents
389 ;; always turn off iso-accents-mode in vi-state, or else we won't be able to
390 ;; use the keys `,',^ , as they will do accents instead of Vi actions.
391 (cond ((eq new-state 'vi-state) (viper-set-iso-accents-mode nil));accents off
392 (viper-automatic-iso-accents (viper-set-iso-accents-mode t));accents on
393 (t (viper-set-iso-accents-mode nil)))
394 ;; Always turn off quail mode in vi state
395 (cond ((eq new-state 'vi-state) (viper-set-input-method nil)) ;intl input off
396 (viper-special-input-method (viper-set-input-method t)) ;intl input on
397 (t (viper-set-input-method nil)))
399 (setq viper-current-state new-state)
401 (viper-update-syntax-classes)
402 (viper-normalize-minor-mode-map-alist)
403 (viper-adjust-keys-for new-state)
404 (viper-set-mode-vars-for new-state)
405 (viper-refresh-mode-line)
410 (defun viper-adjust-keys-for (state)
411 "Make necessary adjustments to keymaps before entering STATE."
412 (cond ((memq state '(insert-state replace-state))
413 (if viper-auto-indent
414 (progn
415 (define-key viper-insert-basic-map "\C-m" 'viper-autoindent)
416 (if viper-want-emacs-keys-in-insert
417 ;; expert
418 (define-key viper-insert-basic-map "\C-j" nil)
419 ;; novice
420 (define-key viper-insert-basic-map "\C-j" 'viper-autoindent)))
421 (define-key viper-insert-basic-map "\C-m" nil)
422 (define-key viper-insert-basic-map "\C-j" nil))
424 (setq viper-insert-diehard-minor-mode
425 (not viper-want-emacs-keys-in-insert))
427 (if viper-want-ctl-h-help
428 (progn
429 (define-key viper-insert-basic-map "\C-h" 'help-command)
430 (define-key viper-replace-map "\C-h" 'help-command))
431 (define-key viper-insert-basic-map
432 "\C-h" 'viper-del-backward-char-in-insert)
433 (define-key viper-replace-map
434 "\C-h" 'viper-del-backward-char-in-replace))
435 ;; In XEmacs, C-h overrides backspace, so we make sure it doesn't.
436 (define-key viper-insert-basic-map
437 [backspace] 'viper-del-backward-char-in-insert)
438 (define-key viper-replace-map
439 [backspace] 'viper-del-backward-char-in-replace)
440 ) ; end insert/replace case
441 (t ; Vi state
442 (setq viper-vi-diehard-minor-mode (not viper-want-emacs-keys-in-vi))
443 (if viper-want-ctl-h-help
444 (define-key viper-vi-basic-map "\C-h" 'help-command)
445 (define-key viper-vi-basic-map "\C-h" 'viper-backward-char))
446 ;; In XEmacs, C-h overrides backspace, so we make sure it doesn't.
447 (define-key viper-vi-basic-map [backspace] 'viper-backward-char))
451 ;; Normalizes minor-mode-map-alist by putting Viper keymaps first.
452 ;; This ensures that Viper bindings are in effect, regardless of which minor
453 ;; modes were turned on by the user or by other packages.
454 (defun viper-normalize-minor-mode-map-alist ()
455 (setq viper--intercept-key-maps
456 (list
457 (cons 'viper-vi-intercept-minor-mode viper-vi-intercept-map)
458 (cons 'viper-insert-intercept-minor-mode viper-insert-intercept-map)
459 (cons 'viper-emacs-intercept-minor-mode viper-emacs-intercept-map)
461 (setq viper--key-maps
462 (list (cons 'viper-vi-minibuffer-minor-mode viper-minibuffer-map)
463 (cons 'viper-vi-local-user-minor-mode viper-vi-local-user-map)
464 (cons 'viper-vi-kbd-minor-mode viper-vi-kbd-map)
465 (cons 'viper-vi-global-user-minor-mode viper-vi-global-user-map)
466 (cons 'viper-vi-state-modifier-minor-mode
467 (if (keymapp
468 (cdr (assoc major-mode viper-vi-state-modifier-alist)))
469 (cdr (assoc major-mode viper-vi-state-modifier-alist))
470 viper-empty-keymap))
471 (cons 'viper-vi-diehard-minor-mode viper-vi-diehard-map)
472 (cons 'viper-vi-basic-minor-mode viper-vi-basic-map)
473 (cons 'viper-replace-minor-mode viper-replace-map)
474 ;; viper-insert-minibuffer-minor-mode must come after
475 ;; viper-replace-minor-mode
476 (cons 'viper-insert-minibuffer-minor-mode
477 viper-minibuffer-map)
478 (cons 'viper-insert-local-user-minor-mode
479 viper-insert-local-user-map)
480 (cons 'viper-insert-kbd-minor-mode viper-insert-kbd-map)
481 (cons 'viper-insert-global-user-minor-mode
482 viper-insert-global-user-map)
483 (cons 'viper-insert-state-modifier-minor-mode
484 (if (keymapp
485 (cdr (assoc major-mode
486 viper-insert-state-modifier-alist)))
487 (cdr (assoc major-mode
488 viper-insert-state-modifier-alist))
489 viper-empty-keymap))
490 (cons 'viper-insert-diehard-minor-mode viper-insert-diehard-map)
491 (cons 'viper-insert-basic-minor-mode viper-insert-basic-map)
492 (cons 'viper-emacs-local-user-minor-mode
493 viper-emacs-local-user-map)
494 (cons 'viper-emacs-kbd-minor-mode viper-emacs-kbd-map)
495 (cons 'viper-emacs-global-user-minor-mode
496 viper-emacs-global-user-map)
497 (cons 'viper-emacs-state-modifier-minor-mode
498 (if (keymapp
499 (cdr
500 (assoc major-mode viper-emacs-state-modifier-alist)))
501 (cdr
502 (assoc major-mode viper-emacs-state-modifier-alist))
503 viper-empty-keymap))
506 ;; This var is not local in Emacs, so we make it local. It must be local
507 ;; because although the stack of minor modes can be the same for all buffers,
508 ;; the associated *keymaps* can be different. In Viper,
509 ;; viper-vi-local-user-map, viper-insert-local-user-map, and others can have
510 ;; different keymaps for different buffers. Also, the keymaps associated
511 ;; with viper-vi/insert-state-modifier-minor-mode can be different.
512 ;; ***This is needed only in case emulation-mode-map-alists is not defined.
513 ;; In emacs with emulation-mode-map-alists, nothing needs to be done
514 (unless
515 (and (fboundp 'add-to-ordered-list) (boundp 'emulation-mode-map-alists))
516 (set (make-local-variable 'minor-mode-map-alist)
517 (viper-append-filter-alist
518 (append viper--intercept-key-maps viper--key-maps)
519 minor-mode-map-alist)))
524 ;; Viper mode-changing commands and utilities
526 ;; Modifies mode-line-buffer-identification.
527 (defun viper-refresh-mode-line ()
528 (set (make-local-variable 'viper-mode-string)
529 (cond ((eq viper-current-state 'emacs-state) viper-emacs-state-id)
530 ((eq viper-current-state 'vi-state) viper-vi-state-id)
531 ((eq viper-current-state 'replace-state) viper-replace-state-id)
532 ((eq viper-current-state 'insert-state) viper-insert-state-id)))
534 ;; Sets Viper mode string in global-mode-string
535 (force-mode-line-update))
538 ;; Switch from Insert state to Vi state.
539 (defun viper-exit-insert-state ()
540 (interactive)
541 (viper-change-state-to-vi))
543 (defun viper-set-mode-vars-for (state)
544 "Sets Viper minor mode variables to put Viper's state STATE in effect."
546 ;; Emacs state
547 (setq viper-vi-minibuffer-minor-mode nil
548 viper-insert-minibuffer-minor-mode nil
549 viper-vi-intercept-minor-mode nil
550 viper-insert-intercept-minor-mode nil
552 viper-vi-local-user-minor-mode nil
553 viper-vi-kbd-minor-mode nil
554 viper-vi-global-user-minor-mode nil
555 viper-vi-state-modifier-minor-mode nil
556 viper-vi-diehard-minor-mode nil
557 viper-vi-basic-minor-mode nil
559 viper-replace-minor-mode nil
561 viper-insert-local-user-minor-mode nil
562 viper-insert-kbd-minor-mode nil
563 viper-insert-global-user-minor-mode nil
564 viper-insert-state-modifier-minor-mode nil
565 viper-insert-diehard-minor-mode nil
566 viper-insert-basic-minor-mode nil
567 viper-emacs-intercept-minor-mode t
568 viper-emacs-local-user-minor-mode t
569 viper-emacs-kbd-minor-mode (not (viper-is-in-minibuffer))
570 viper-emacs-global-user-minor-mode t
571 viper-emacs-state-modifier-minor-mode t
574 ;; Vi state
575 (if (eq state 'vi-state) ; adjust for vi-state
576 (setq
577 viper-vi-intercept-minor-mode t
578 viper-vi-minibuffer-minor-mode (viper-is-in-minibuffer)
579 viper-vi-local-user-minor-mode t
580 viper-vi-kbd-minor-mode (not (viper-is-in-minibuffer))
581 viper-vi-global-user-minor-mode t
582 viper-vi-state-modifier-minor-mode t
583 ;; don't let the diehard keymap block command completion
584 ;; and other things in the minibuffer
585 viper-vi-diehard-minor-mode (not
586 (or viper-want-emacs-keys-in-vi
587 (viper-is-in-minibuffer)))
588 viper-vi-basic-minor-mode t
589 viper-emacs-intercept-minor-mode nil
590 viper-emacs-local-user-minor-mode nil
591 viper-emacs-kbd-minor-mode nil
592 viper-emacs-global-user-minor-mode nil
593 viper-emacs-state-modifier-minor-mode nil
596 ;; Insert and Replace states
597 (if (member state '(insert-state replace-state))
598 (setq
599 viper-insert-intercept-minor-mode t
600 viper-replace-minor-mode (eq state 'replace-state)
601 viper-insert-minibuffer-minor-mode (viper-is-in-minibuffer)
602 viper-insert-local-user-minor-mode t
603 viper-insert-kbd-minor-mode (not (viper-is-in-minibuffer))
604 viper-insert-global-user-minor-mode t
605 viper-insert-state-modifier-minor-mode t
606 ;; don't let the diehard keymap block command completion
607 ;; and other things in the minibuffer
608 viper-insert-diehard-minor-mode (not
610 viper-want-emacs-keys-in-insert
611 (viper-is-in-minibuffer)))
612 viper-insert-basic-minor-mode t
613 viper-emacs-intercept-minor-mode nil
614 viper-emacs-local-user-minor-mode nil
615 viper-emacs-kbd-minor-mode nil
616 viper-emacs-global-user-minor-mode nil
617 viper-emacs-state-modifier-minor-mode nil
620 ;; minibuffer faces
621 (if (viper-has-face-support-p)
622 (setq viper-minibuffer-current-face
623 (cond ((eq state 'emacs-state) viper-minibuffer-emacs-face)
624 ((eq state 'vi-state) viper-minibuffer-vi-face)
625 ((memq state '(insert-state replace-state))
626 viper-minibuffer-insert-face))))
628 (if (viper-is-in-minibuffer)
629 (viper-set-minibuffer-overlay))
632 ;; This also takes care of the annoying incomplete lines in files.
633 ;; Also, this fixes `undo' to work vi-style for complex commands.
634 (defun viper-change-state-to-vi ()
635 "Change Viper state to Vi."
636 (interactive)
637 (if (and viper-first-time (not (viper-is-in-minibuffer)))
638 (viper-mode)
639 (if overwrite-mode (overwrite-mode -1))
640 (or (viper-overlay-p viper-replace-overlay)
641 (viper-set-replace-overlay (point-min) (point-min)))
642 (viper-hide-replace-overlay)
643 (if abbrev-mode (expand-abbrev))
644 (if (and auto-fill-function (> (current-column) fill-column))
645 (funcall auto-fill-function))
646 ;; don't leave whitespace lines around
647 (if (and (memq last-command
648 '(viper-autoindent
649 viper-open-line viper-Open-line
650 viper-replace-state-exit-cmd))
651 (viper-over-whitespace-line))
652 (indent-to-left-margin))
653 (viper-add-newline-at-eob-if-necessary)
654 (viper-adjust-undo)
656 (if (eq viper-current-state 'emacs-state)
657 (viper-restore-cursor-color 'after-emacs-mode)
658 (viper-restore-cursor-color 'after-insert-mode))
660 (viper-change-state 'vi-state)
662 ;; Protect against user errors in hooks
663 (condition-case conds
664 (run-hooks 'viper-vi-state-hook)
665 (error
666 (viper-message-conditions conds)))))
668 (defun viper-change-state-to-insert ()
669 "Change Viper state to Insert."
670 (interactive)
671 (viper-change-state 'insert-state)
673 (or (viper-overlay-p viper-replace-overlay)
674 (viper-set-replace-overlay (point-min) (point-min)))
675 (viper-hide-replace-overlay)
677 (let ((has-saved-cursor-color-in-insert-mode
678 (stringp (viper-get-saved-cursor-color-in-insert-mode))))
679 (or has-saved-cursor-color-in-insert-mode
680 (string= (viper-get-cursor-color) viper-insert-state-cursor-color)
681 (viper-save-cursor-color 'before-insert-mode))
682 (viper-change-cursor-color viper-insert-state-cursor-color))
684 ;; Protect against user errors in hooks
685 (condition-case conds
686 (run-hooks 'viper-insert-state-hook)
687 (error
688 (viper-message-conditions conds))))
690 (defsubst viper-downgrade-to-insert ()
691 ;; Protect against user errors in hooks
692 (condition-case conds
693 (run-hooks 'viper-insert-state-hook)
694 (error
695 (viper-message-conditions conds)))
696 (setq viper-current-state 'insert-state
697 viper-replace-minor-mode nil))
701 ;; Change to replace state. When the end of replacement region is reached,
702 ;; replace state changes to insert state.
703 (defun viper-change-state-to-replace (&optional non-R-cmd)
704 (viper-change-state 'replace-state)
705 ;; Run insert-state-hook
706 (condition-case conds
707 (run-hooks 'viper-insert-state-hook 'viper-replace-state-hook)
708 (error
709 (viper-message-conditions conds)))
711 (if non-R-cmd
712 (viper-start-replace)
713 ;; 'R' is implemented using Emacs's overwrite-mode
714 (viper-start-R-mode))
718 (defun viper-change-state-to-emacs ()
719 "Change Viper state to Emacs."
720 (interactive)
721 (or (viper-overlay-p viper-replace-overlay)
722 (viper-set-replace-overlay (point-min) (point-min)))
723 (viper-hide-replace-overlay)
725 (let ((has-saved-cursor-color-in-emacs-mode
726 (stringp (viper-get-saved-cursor-color-in-emacs-mode))))
727 (or has-saved-cursor-color-in-emacs-mode
728 (string= (viper-get-cursor-color) viper-emacs-state-cursor-color)
729 (viper-save-cursor-color 'before-emacs-mode))
730 (viper-change-cursor-color viper-emacs-state-cursor-color))
732 (viper-change-state 'emacs-state)
734 ;; Protect against user errors in hooks
735 (condition-case conds
736 (run-hooks 'viper-emacs-state-hook)
737 (error
738 (viper-message-conditions conds))))
740 ;; escape to emacs mode termporarily
741 (defun viper-escape-to-emacs (arg &optional events)
742 "Escape to Emacs state from Vi state for one Emacs command.
743 ARG is used as the prefix value for the executed command. If
744 EVENTS is a list of events, which become the beginning of the command."
745 (interactive "P")
746 (if (viper= last-command-char ?\\)
747 (message "Switched to EMACS state for the next command..."))
748 (viper-escape-to-state arg events 'emacs-state))
750 ;; escape to Vi mode termporarily
751 (defun viper-escape-to-vi (arg)
752 "Escape from Emacs state to Vi state for one Vi 1-character command.
753 If the Vi command that the user types has a prefix argument, e.g., `d2w', then
754 Vi's prefix argument will be used. Otherwise, the prefix argument passed to
755 `viper-escape-to-vi' is used."
756 (interactive "P")
757 (message "Switched to VI state for the next command...")
758 (viper-escape-to-state arg nil 'vi-state))
760 ;; Escape to STATE mode for one Emacs command.
761 (defun viper-escape-to-state (arg events state)
762 ;;(let (com key prefix-arg)
763 (let (com key)
764 ;; this temporarily turns off Viper's minor mode keymaps
765 (viper-set-mode-vars-for state)
766 (viper-normalize-minor-mode-map-alist)
767 (if events (viper-set-unread-command-events events))
769 ;; protect against keyboard quit and other errors
770 (condition-case nil
771 (let (viper-vi-kbd-minor-mode
772 viper-insert-kbd-minor-mode
773 viper-emacs-kbd-minor-mode)
774 (unwind-protect
775 (progn
776 (setq com
777 (key-binding (setq key (viper-read-key-sequence nil))))
778 ;; In case of binding indirection--chase definitions.
779 ;; Have to do it here because we execute this command under
780 ;; different keymaps, so command-execute may not do the
781 ;; right thing there
782 (while (vectorp com) (setq com (key-binding com))))
783 nil)
784 ;; Execute command com in the original Viper state, not in state
785 ;; `state'. Otherwise, if we switch buffers while executing the
786 ;; escaped to command, Viper's mode vars will remain those of
787 ;; `state'. When we return to the orig buffer, the bindings will be
788 ;; screwed up.
789 (viper-set-mode-vars-for viper-current-state)
791 ;; this-command, last-command-char, last-command-event
792 (setq this-command com)
793 (viper-cond-compile-for-xemacs-or-emacs
794 ;; XEmacs represents key sequences as vectors
795 (setq last-command-event
796 (viper-copy-event (viper-seq-last-elt key))
797 last-command-char (event-to-character last-command-event))
798 ;; Emacs represents them as sequences (str or vec)
799 (setq last-command-event
800 (viper-copy-event (viper-seq-last-elt key))
801 last-command-char last-command-event)
804 (if (commandp com)
805 ;; pretend that current state is the state we excaped to
806 (let ((viper-current-state state))
807 (setq prefix-arg (or prefix-arg arg))
808 (command-execute com)))
810 (quit (ding))
811 (error (beep 1))))
812 ;; set state in the new buffer
813 (viper-set-mode-vars-for viper-current-state))
815 ;; This is used in order to allow reading characters according to the input
816 ;; method. The character is read in emacs and inserted into the buffer.
817 ;; If an input method is in effect, this might
818 ;; cause several characters to be combined into one.
819 ;; Also takes care of the iso-accents mode
820 (defun viper-special-read-and-insert-char ()
821 (viper-set-mode-vars-for 'emacs-state)
822 (viper-normalize-minor-mode-map-alist)
823 (if viper-special-input-method
824 (viper-set-input-method t))
825 (if viper-automatic-iso-accents
826 (viper-set-iso-accents-mode t))
827 (condition-case nil
828 (let (viper-vi-kbd-minor-mode
829 viper-insert-kbd-minor-mode
830 viper-emacs-kbd-minor-mode
832 (cond ((and viper-special-input-method
833 viper-emacs-p
834 (fboundp 'quail-input-method))
835 ;; (let ...) is used to restore unread-command-events to the
836 ;; original state. We don't want anything left in there after
837 ;; key translation. (Such left-overs are possible if the user
838 ;; types a regular key.)
839 (let (unread-command-events)
840 ;; The next cmd and viper-set-unread-command-events
841 ;; are intended to prevent the input method
842 ;; from swallowing ^M, ^Q and other special characters
843 (setq ch (read-char-exclusive))
844 ;; replace ^M with the newline
845 (if (eq ch ?\C-m) (setq ch ?\n))
846 ;; Make sure ^V and ^Q work as quotation chars
847 (if (memq ch '(?\C-v ?\C-q))
848 (setq ch (read-char-exclusive)))
849 (viper-set-unread-command-events ch)
850 (quail-input-method nil)
852 (if (and ch (string= quail-current-str ""))
853 (insert ch)
854 (insert quail-current-str))
855 (setq ch (or ch
856 (aref quail-current-str
857 (1- (length quail-current-str)))))
859 ((and viper-special-input-method
860 viper-xemacs-p
861 (fboundp 'quail-start-translation))
862 ;; same as above but for XEmacs, which doesn't have
863 ;; quail-input-method
864 (let (unread-command-events)
865 (setq ch (read-char-exclusive))
866 ;; replace ^M with the newline
867 (if (eq ch ?\C-m) (setq ch ?\n))
868 ;; Make sure ^V and ^Q work as quotation chars
869 (if (memq ch '(?\C-v ?\C-q))
870 (setq ch (read-char-exclusive)))
871 (viper-set-unread-command-events ch)
872 (quail-start-translation nil)
874 (if (and ch (string= quail-current-str ""))
875 (insert ch)
876 (insert quail-current-str))
877 (setq ch (or ch
878 (aref quail-current-str
879 (1- (length quail-current-str)))))
881 ((and (boundp 'iso-accents-mode) iso-accents-mode)
882 (setq ch (aref (read-key-sequence nil) 0))
883 ;; replace ^M with the newline
884 (if (eq ch ?\C-m) (setq ch ?\n))
885 ;; Make sure ^V and ^Q work as quotation chars
886 (if (memq ch '(?\C-v ?\C-q))
887 (setq ch (aref (read-key-sequence nil) 0)))
888 (insert ch))
890 (setq ch (read-char-exclusive))
891 ;; replace ^M with the newline
892 (if (eq ch ?\C-m) (setq ch ?\n))
893 ;; Make sure ^V and ^Q work as quotation chars
894 (if (memq ch '(?\C-v ?\C-q))
895 (setq ch (read-char-exclusive)))
896 (insert ch))
898 (setq last-command-event
899 (viper-copy-event (if viper-xemacs-p
900 (character-to-event ch) ch)))
901 ) ; let
902 (error nil)
903 ) ; condition-case
905 (viper-set-input-method nil)
906 (viper-set-iso-accents-mode nil)
907 (viper-set-mode-vars-for viper-current-state)
911 (defun viper-exec-form-in-vi (form)
912 "Execute FORM in Vi state, regardless of the Ccurrent Vi state."
913 (let ((buff (current-buffer))
914 result)
915 (viper-set-mode-vars-for 'vi-state)
917 (condition-case nil
918 (let (viper-vi-kbd-minor-mode) ; execute without kbd macros
919 (setq result (eval form))
921 (error
922 (signal 'quit nil)))
924 (if (not (equal buff (current-buffer))) ; cmd switched buffer
925 (save-excursion
926 (set-buffer buff)
927 (viper-set-mode-vars-for viper-current-state)))
928 (viper-set-mode-vars-for viper-current-state)
929 result))
931 (defun viper-exec-form-in-emacs (form)
932 "Execute FORM in Emacs, temporarily disabling Viper's minor modes.
933 Similar to viper-escape-to-emacs, but accepts forms rather than keystrokes."
934 (let ((buff (current-buffer))
935 result)
936 (viper-set-mode-vars-for 'emacs-state)
937 (setq result (eval form))
938 (if (not (equal buff (current-buffer))) ; cmd switched buffer
939 (save-excursion
940 (set-buffer buff)
941 (viper-set-mode-vars-for viper-current-state)))
942 (viper-set-mode-vars-for viper-current-state)
943 result))
945 ;; This executes the last kbd event in emacs mode. Is used when we want to
946 ;; interpret certain keys directly in emacs (as, for example, in comint mode).
947 (defun viper-exec-key-in-emacs (arg)
948 (interactive "P")
949 (viper-escape-to-emacs arg last-command-event))
952 ;; This is needed because minor modes sometimes override essential Viper
953 ;; bindings. By letting Viper know which files these modes are in, it will
954 ;; arrange to reorganize minor-mode-map-alist so that things will work right.
955 (defun viper-harness-minor-mode (load-file)
956 "Familiarize Viper with a minor mode defined in LOAD_FILE.
957 Minor modes that have their own keymaps may overshadow Viper keymaps.
958 This function is designed to make Viper aware of the packages that define
959 such minor modes.
960 Usage:
961 (viper-harness-minor-mode load-file)
963 LOAD-FILE is a name of the file where the specific minor mode is defined.
964 Suffixes such as .el or .elc should be stripped."
966 (interactive "sEnter name of the load file: ")
968 (eval-after-load load-file '(viper-normalize-minor-mode-map-alist))
970 ;; Change the default for minor-mode-map-alist each time a harnessed minor
971 ;; mode adds its own keymap to the a-list.
972 (unless
973 (and (fboundp 'add-to-ordered-list) (boundp 'emulation-mode-map-alists))
974 (eval-after-load
975 load-file '(setq-default minor-mode-map-alist minor-mode-map-alist)))
979 (defun viper-ESC (arg)
980 "Emulate ESC key in Emacs.
981 Prevents multiple escape keystrokes if viper-no-multiple-ESC is true.
982 If viper-no-multiple-ESC is 'twice double ESC would ding in vi-state.
983 Other ESC sequences are emulated via the current Emacs's major mode
984 keymap. This is more convenient on TTYs, since this won't block
985 function keys such as up,down, etc. ESC will also will also work as
986 a Meta key in this case. When viper-no-multiple-ESC is nil, ESC functions
987 as a Meta key and any number of multiple escapes is allowed."
988 (interactive "P")
989 (let (char)
990 (cond ((and (not viper-no-multiple-ESC) (eq viper-current-state 'vi-state))
991 (setq char (viper-read-char-exclusive))
992 (viper-escape-to-emacs arg (list ?\e char) ))
993 ((and (eq viper-no-multiple-ESC 'twice)
994 (eq viper-current-state 'vi-state))
995 (setq char (viper-read-char-exclusive))
996 (if (= char (string-to-char viper-ESC-key))
997 (ding)
998 (viper-escape-to-emacs arg (list ?\e char) )))
999 (t (ding)))
1002 (defun viper-alternate-Meta-key (arg)
1003 "Simulate Emacs Meta key."
1004 (interactive "P")
1005 (sit-for 1) (message "ESC-")
1006 (viper-escape-to-emacs arg '(?\e)))
1008 (defun viper-toggle-key-action ()
1009 "Action bound to `viper-toggle-key'."
1010 (interactive)
1011 (if (and (< viper-expert-level 2) (equal viper-toggle-key "\C-z"))
1012 (if (viper-window-display-p)
1013 (viper-iconify)
1014 (suspend-emacs))
1015 (viper-change-state-to-emacs)))
1018 ;; Intercept ESC sequences on dumb terminals.
1019 ;; Based on the idea contributed by Marcelino Veiga Tuimil <mveiga@dit.upm.es>
1021 ;; Check if last key was ESC and if so try to reread it as a function key.
1022 ;; But only if there are characters to read during a very short time.
1023 ;; Returns the last event, if any.
1024 (defun viper-envelop-ESC-key ()
1025 (let ((event last-input-event)
1026 (keyseq [nil])
1027 (inhibit-quit t))
1028 (if (viper-ESC-event-p event)
1029 (progn
1030 ;; Emacs 22.50.8 introduced a bug, which makes even a single ESC into
1031 ;; a fast keyseq. To guard against this, we added a check if there
1032 ;; are other events as well
1033 (if (and (viper-fast-keysequence-p) unread-command-events)
1034 (progn
1035 (let (minor-mode-map-alist emulation-mode-map-alists)
1036 (viper-set-unread-command-events event)
1037 (setq keyseq (read-key-sequence nil 'continue-echo))
1038 ) ; let
1039 ;; If keyseq translates into something that still has ESC
1040 ;; at the beginning, separate ESC from the rest of the seq.
1041 ;; In XEmacs we check for events that are keypress meta-key
1042 ;; and convert them into [escape key]
1044 ;; This is needed for the following reason:
1045 ;; If ESC is the first symbol, we interpret it as if the
1046 ;; user typed ESC and then quickly some other symbols.
1047 ;; If ESC is not the first one, then the key sequence
1048 ;; entered was apparently translated into a function key or
1049 ;; something (e.g., one may have
1050 ;; (define-key function-key-map "\e[192z" [f11])
1051 ;; which would translate the escape-sequence generated by
1052 ;; f11 in an xterm window into the symbolic key f11.
1054 ;; If `first-key' is not an ESC event, we make it into the
1055 ;; last-command-event in order to pretend that this key was
1056 ;; pressed. This is needed to allow arrow keys to be bound to
1057 ;; macros. Otherwise, viper-exec-mapped-kbd-macro will think
1058 ;; that the last event was ESC and so it'll execute whatever is
1059 ;; bound to ESC. (Viper macros can't be bound to
1060 ;; ESC-sequences).
1061 (let* ((first-key (elt keyseq 0))
1062 (key-mod (event-modifiers first-key)))
1063 (cond ((and (viper-ESC-event-p first-key)
1064 (not viper-translate-all-ESC-keysequences))
1065 ;; put keys following ESC on the unread list
1066 ;; and return ESC as the key-sequence
1067 (viper-set-unread-command-events (viper-subseq keyseq 1))
1068 (setq last-input-event event
1069 keyseq (if viper-emacs-p
1070 "\e"
1071 (vector (character-to-event ?\e)))))
1072 ((and viper-xemacs-p
1073 (key-press-event-p first-key)
1074 (equal '(meta) key-mod))
1075 (viper-set-unread-command-events
1076 (vconcat (vector
1077 (character-to-event (event-key first-key)))
1078 (viper-subseq keyseq 1)))
1079 (setq last-input-event event
1080 keyseq (vector (character-to-event ?\e))))
1081 ((eventp first-key)
1082 (setq last-command-event
1083 (viper-copy-event first-key)))
1085 ) ; end progn
1087 ;; this is escape event with nothing after it
1088 ;; put in unread-command-event and then re-read
1089 (viper-set-unread-command-events event)
1090 (setq keyseq (read-key-sequence nil))
1092 ;; not an escape event
1093 (setq keyseq (vector event)))
1094 keyseq))
1098 ;; Listen to ESC key.
1099 ;; If a sequence of keys starting with ESC is issued with very short delays,
1100 ;; interpret these keys in Emacs mode, so ESC won't be interpreted as a Vi key.
1101 (defun viper-intercept-ESC-key ()
1102 "Function that implements ESC key in Viper emulation of Vi."
1103 (interactive)
1104 (let ((cmd (or (key-binding (viper-envelop-ESC-key))
1105 '(lambda () (interactive) (error "")))))
1107 ;; call the actual function to execute ESC (if no other symbols followed)
1108 ;; or the key bound to the ESC sequence (if the sequence was issued
1109 ;; with very short delay between characters).
1110 (if (eq cmd 'viper-intercept-ESC-key)
1111 (setq cmd
1112 (cond ((eq viper-current-state 'vi-state)
1113 'viper-ESC)
1114 ((eq viper-current-state 'insert-state)
1115 'viper-exit-insert-state)
1116 ((eq viper-current-state 'replace-state)
1117 'viper-replace-state-exit-cmd)
1118 (t 'viper-change-state-to-vi)
1120 (call-interactively cmd)))
1125 ;; prefix argument for Vi mode
1127 ;; In Vi mode, prefix argument is a dotted pair (NUM . COM) where NUM
1128 ;; represents the numeric value of the prefix argument and COM represents
1129 ;; command prefix such as "c", "d", "m" and "y".
1131 ;; Get value part of prefix-argument ARG.
1132 (defsubst viper-p-val (arg)
1133 (cond ((null arg) 1)
1134 ((consp arg)
1135 (if (or (null (car arg)) (equal (car arg) '(nil)))
1136 1 (car arg)))
1137 (t arg)))
1139 ;; Get raw value part of prefix-argument ARG.
1140 (defsubst viper-P-val (arg)
1141 (cond ((consp arg) (car arg))
1142 (t arg)))
1144 ;; Get com part of prefix-argument ARG.
1145 (defsubst viper-getcom (arg)
1146 (cond ((null arg) nil)
1147 ((consp arg) (cdr arg))
1148 (t nil)))
1150 ;; Get com part of prefix-argument ARG and modify it.
1151 (defun viper-getCom (arg)
1152 (let ((com (viper-getcom arg)))
1153 (cond ((viper= com ?c) ?c)
1154 ;; Previously, ?c was being converted to ?C, but this prevented
1155 ;; multiline replace regions.
1156 ;;((viper= com ?c) ?C)
1157 ((viper= com ?d) ?D)
1158 ((viper= com ?y) ?Y)
1159 (t com))))
1162 ;; Compute numeric prefix arg value.
1163 ;; Invoked by EVENT-CHAR. COM is the command part obtained so far.
1164 (defun viper-prefix-arg-value (event-char com)
1165 (let ((viper-intermediate-command 'viper-digit-argument)
1166 value func)
1167 ;; read while number
1168 (while (and (viper-characterp event-char)
1169 (>= event-char ?0) (<= event-char ?9))
1170 (setq value (+ (* (if (integerp value) value 0) 10) (- event-char ?0)))
1171 (setq event-char (viper-read-event-convert-to-char)))
1173 (setq prefix-arg value)
1174 (if com (setq prefix-arg (cons prefix-arg com)))
1175 (while (eq event-char ?U)
1176 (viper-describe-arg prefix-arg)
1177 (setq event-char (viper-read-event-convert-to-char)))
1179 (if (or com (and (not (eq viper-current-state 'vi-state))
1180 ;; make sure it is a Vi command
1181 (viper-characterp event-char)
1182 (viper-vi-command-p event-char)
1184 ;; If appears to be one of the vi commands,
1185 ;; then execute it with funcall and clear prefix-arg in order to not
1186 ;; confuse subsequent commands
1187 (progn
1188 ;; last-command-char is the char we want emacs to think was typed
1189 ;; last. If com is not nil, the viper-digit-argument command was
1190 ;; called from within viper-prefix-arg command, such as `d', `w',
1191 ;; etc., i.e., the user typed, say, d2. In this case, `com' would be
1192 ;; `d', `w', etc. If viper-digit-argument was invoked by
1193 ;; viper-escape-to-vi (which is indicated by the fact that the
1194 ;; current state is not vi-state), then `event-char' represents the
1195 ;; vi command to be executed (e.g., `d', `w', etc). Again,
1196 ;; last-command-char must make emacs believe that this is the command
1197 ;; we typed.
1198 (cond ((eq event-char 'return) (setq event-char ?\C-m))
1199 ((eq event-char 'delete) (setq event-char ?\C-?))
1200 ((eq event-char 'backspace) (setq event-char ?\C-h))
1201 ((eq event-char 'space) (setq event-char ?\ )))
1202 (setq last-command-char (or com event-char))
1203 (setq func (viper-exec-form-in-vi
1204 `(key-binding (char-to-string ,event-char))))
1205 (funcall func prefix-arg)
1206 (setq prefix-arg nil))
1207 ;; some other command -- let emacs do it in its own way
1208 (viper-set-unread-command-events event-char))
1212 ;; Vi operator as prefix argument."
1213 (defun viper-prefix-arg-com (char value com)
1214 (let ((cont t)
1215 cmd-info
1216 cmd-to-exec-at-end)
1217 (while (and cont
1218 (viper-memq-char char
1219 (list ?c ?d ?y ?! ?< ?> ?= ?# ?r ?R ?\"
1220 viper-buffer-search-char)))
1221 (if com
1222 ;; this means that we already have a command character, so we
1223 ;; construct a com list and exit while. however, if char is "
1224 ;; it is an error.
1225 (progn
1226 ;; new com is (CHAR . OLDCOM)
1227 (if (viper-memq-char char '(?# ?\")) (error ""))
1228 (setq com (cons char com))
1229 (setq cont nil))
1230 ;; If com is nil we set com as char, and read more. Again, if char is
1231 ;; ", we read the name of register and store it in viper-use-register.
1232 ;; if char is !, =, or #, a complete com is formed so we exit the while
1233 ;; loop.
1234 (cond ((viper-memq-char char '(?! ?=))
1235 (setq com char)
1236 (setq char (read-char))
1237 (setq cont nil))
1238 ((viper= char ?#)
1239 ;; read a char and encode it as com
1240 (setq com (+ 128 (read-char)))
1241 (setq char (read-char)))
1242 ((viper= char ?\")
1243 (let ((reg (read-char)))
1244 (if (viper-valid-register reg)
1245 (setq viper-use-register reg)
1246 (error ""))
1247 (setq char (read-char))))
1249 (setq com char)
1250 (setq char (read-char))))))
1252 (if (atom com)
1253 ;; `com' is a single char, so we construct the command argument
1254 ;; and if `char' is `?', we describe the arg; otherwise
1255 ;; we prepare the command that will be executed at the end.
1256 (progn
1257 (setq cmd-info (cons value com))
1258 (while (viper= char ?U)
1259 (viper-describe-arg cmd-info)
1260 (setq char (read-char)))
1261 ;; `char' is a movement cmd, a digit arg cmd, or a register cmd---so we
1262 ;; execute it at the very end
1263 (or (viper-movement-command-p char)
1264 (viper-digit-command-p char)
1265 (viper-regsuffix-command-p char)
1266 (viper= char ?!) ; bang command
1267 (error ""))
1268 (setq cmd-to-exec-at-end
1269 (viper-exec-form-in-vi
1270 `(key-binding (char-to-string ,char)))))
1272 ;; as com is non-nil, this means that we have a command to execute
1273 (if (viper-memq-char (car com) '(?r ?R))
1274 ;; execute apropriate region command.
1275 (let ((char (car com)) (com (cdr com)))
1276 (setq prefix-arg (cons value com))
1277 (if (viper= char ?r)
1278 (viper-region prefix-arg)
1279 (viper-Region prefix-arg))
1280 ;; reset prefix-arg
1281 (setq prefix-arg nil))
1282 ;; otherwise, reset prefix arg and call appropriate command
1283 (setq value (if (null value) 1 value))
1284 (setq prefix-arg nil)
1285 (cond
1286 ;; If we change ?C to ?c here, then cc will enter replacement mode
1287 ;; rather than deleting lines. However, it will affect 1 less line than
1288 ;; normal. We decided to not use replacement mode here and follow Vi,
1289 ;; since replacement mode on n full lines can be achieved with nC.
1290 ((equal com '(?c . ?c)) (viper-line (cons value ?C)))
1291 ((equal com '(?d . ?d)) (viper-line (cons value ?D)))
1292 ((equal com '(?d . ?y)) (viper-yank-defun))
1293 ((equal com '(?y . ?y)) (viper-line (cons value ?Y)))
1294 ((equal com '(?< . ?<)) (viper-line (cons value ?<)))
1295 ((equal com '(?> . ?>)) (viper-line (cons value ?>)))
1296 ((equal com '(?! . ?!)) (viper-line (cons value ?!)))
1297 ((equal com '(?= . ?=)) (viper-line (cons value ?=)))
1298 (t (error "")))))
1300 (if cmd-to-exec-at-end
1301 (progn
1302 (setq last-command-char char)
1303 (setq last-command-event
1304 (viper-copy-event
1305 (if viper-xemacs-p (character-to-event char) char)))
1306 (condition-case nil
1307 (funcall cmd-to-exec-at-end cmd-info)
1308 (error
1309 (error "")))))
1312 (defun viper-describe-arg (arg)
1313 (let (val com)
1314 (setq val (viper-P-val arg)
1315 com (viper-getcom arg))
1316 (if (null val)
1317 (if (null com)
1318 (message "Value is nil, and command is nil")
1319 (message "Value is nil, and command is `%c'" com))
1320 (if (null com)
1321 (message "Value is `%d', and command is nil" val)
1322 (message "Value is `%d', and command is `%c'" val com)))))
1324 (defun viper-digit-argument (arg)
1325 "Begin numeric argument for the next command."
1326 (interactive "P")
1327 (viper-leave-region-active)
1328 (viper-prefix-arg-value
1329 last-command-char (if (consp arg) (cdr arg) nil)))
1331 (defun viper-command-argument (arg)
1332 "Accept a motion command as an argument."
1333 (interactive "P")
1334 (let ((viper-intermediate-command 'viper-command-argument))
1335 (condition-case nil
1336 (viper-prefix-arg-com
1337 last-command-char
1338 (cond ((null arg) nil)
1339 ((consp arg) (car arg))
1340 ((integerp arg) arg)
1341 (t (error viper-InvalidCommandArgument)))
1342 (cond ((null arg) nil)
1343 ((consp arg) (cdr arg))
1344 ((integerp arg) nil)
1345 (t (error viper-InvalidCommandArgument))))
1346 (quit (setq viper-use-register nil)
1347 (signal 'quit nil)))
1348 (viper-deactivate-mark)))
1351 ;; repeat last destructive command
1353 ;; Append region to text in register REG.
1354 ;; START and END are buffer positions indicating what to append.
1355 (defsubst viper-append-to-register (reg start end)
1356 (set-register reg (concat (if (stringp (get-register reg))
1357 (get-register reg) "")
1358 (buffer-substring start end))))
1360 ;; Saves last inserted text for possible use by viper-repeat command.
1361 (defun viper-save-last-insertion (beg end)
1362 (condition-case nil
1363 (setq viper-last-insertion (buffer-substring beg end))
1364 (error
1365 ;; beg or end marker are somehow screwed up
1366 (setq viper-last-insertion nil)))
1367 (setq viper-last-insertion (buffer-substring beg end))
1368 (or (< (length viper-d-com) 5)
1369 (setcar (nthcdr 4 viper-d-com) viper-last-insertion))
1370 (or (null viper-command-ring)
1371 (ring-empty-p viper-command-ring)
1372 (progn
1373 (setcar (nthcdr 4 (viper-current-ring-item viper-command-ring))
1374 viper-last-insertion)
1375 ;; del most recent elt, if identical to the second most-recent
1376 (viper-cleanup-ring viper-command-ring)))
1379 (defsubst viper-yank-last-insertion ()
1380 "Inserts the text saved by the previous viper-save-last-insertion command."
1381 (condition-case nil
1382 (insert viper-last-insertion)
1383 (error nil)))
1386 ;; define functions to be executed
1388 ;; invoked by the `C' command
1389 (defun viper-exec-change (m-com com)
1390 (or (and (markerp viper-com-point) (marker-position viper-com-point))
1391 (set-marker viper-com-point (point) (current-buffer)))
1392 ;; handle C cmd at the eol and at eob.
1393 (if (or (and (eolp) (= viper-com-point (point)))
1394 (= viper-com-point (point-max)))
1395 (progn
1396 (insert " ")(backward-char 1)))
1397 (if (= viper-com-point (point))
1398 (viper-forward-char-carefully))
1399 (set-mark viper-com-point)
1400 (if (eq m-com 'viper-next-line-at-bol)
1401 (viper-enlarge-region (mark t) (point)))
1402 (if (< (point) (mark t))
1403 (exchange-point-and-mark))
1404 (if (eq (preceding-char) ?\n)
1405 (viper-backward-char-carefully)) ; give back the newline
1406 (if (eq viper-intermediate-command 'viper-repeat)
1407 (viper-change-subr (mark t) (point))
1408 (viper-change (mark t) (point))
1411 ;; this is invoked by viper-substitute-line
1412 (defun viper-exec-Change (m-com com)
1413 (save-excursion
1414 (set-mark viper-com-point)
1415 (viper-enlarge-region (mark t) (point))
1416 (if viper-use-register
1417 (progn
1418 (cond ((viper-valid-register viper-use-register '(letter digit))
1419 (copy-to-register
1420 viper-use-register (mark t) (point) nil))
1421 ((viper-valid-register viper-use-register '(Letter))
1422 (viper-append-to-register
1423 (downcase viper-use-register) (mark t) (point)))
1424 (t (setq viper-use-register nil)
1425 (error viper-InvalidRegister viper-use-register)))
1426 (setq viper-use-register nil)))
1427 (delete-region (mark t) (point)))
1428 (open-line 1)
1429 (if (eq viper-intermediate-command 'viper-repeat)
1430 (viper-yank-last-insertion)
1431 (viper-change-state-to-insert)
1434 (defun viper-exec-delete (m-com com)
1435 (or (and (markerp viper-com-point) (marker-position viper-com-point))
1436 (set-marker viper-com-point (point) (current-buffer)))
1437 (let (chars-deleted)
1438 (if viper-use-register
1439 (progn
1440 (cond ((viper-valid-register viper-use-register '(letter digit))
1441 (copy-to-register
1442 viper-use-register viper-com-point (point) nil))
1443 ((viper-valid-register viper-use-register '(Letter))
1444 (viper-append-to-register
1445 (downcase viper-use-register) viper-com-point (point)))
1446 (t (setq viper-use-register nil)
1447 (error viper-InvalidRegister viper-use-register)))
1448 (setq viper-use-register nil)))
1449 (setq last-command
1450 (if (eq last-command 'd-command) 'kill-region nil))
1451 (setq chars-deleted (abs (- (point) viper-com-point)))
1452 (if (> chars-deleted viper-change-notification-threshold)
1453 (unless (viper-is-in-minibuffer)
1454 (message "Deleted %d characters" chars-deleted)))
1455 (kill-region viper-com-point (point))
1456 (setq this-command 'd-command)
1457 (if viper-ex-style-motion
1458 (if (and (eolp) (not (bolp))) (backward-char 1)))))
1460 (defun viper-exec-Delete (m-com com)
1461 (save-excursion
1462 (set-mark viper-com-point)
1463 (viper-enlarge-region (mark t) (point))
1464 (let (lines-deleted)
1465 (if viper-use-register
1466 (progn
1467 (cond ((viper-valid-register viper-use-register '(letter digit))
1468 (copy-to-register
1469 viper-use-register (mark t) (point) nil))
1470 ((viper-valid-register viper-use-register '(Letter))
1471 (viper-append-to-register
1472 (downcase viper-use-register) (mark t) (point)))
1473 (t (setq viper-use-register nil)
1474 (error viper-InvalidRegister viper-use-register)))
1475 (setq viper-use-register nil)))
1476 (setq last-command
1477 (if (eq last-command 'D-command) 'kill-region nil))
1478 (setq lines-deleted (count-lines (point) viper-com-point))
1479 (if (> lines-deleted viper-change-notification-threshold)
1480 (unless (viper-is-in-minibuffer)
1481 (message "Deleted %d lines" lines-deleted)))
1482 (kill-region (mark t) (point))
1483 (if (eq m-com 'viper-line) (setq this-command 'D-command)))
1484 (back-to-indentation)))
1486 ;; save region
1487 (defun viper-exec-yank (m-com com)
1488 (or (and (markerp viper-com-point) (marker-position viper-com-point))
1489 (set-marker viper-com-point (point) (current-buffer)))
1490 (let (chars-saved)
1491 (if viper-use-register
1492 (progn
1493 (cond ((viper-valid-register viper-use-register '(letter digit))
1494 (copy-to-register
1495 viper-use-register viper-com-point (point) nil))
1496 ((viper-valid-register viper-use-register '(Letter))
1497 (viper-append-to-register
1498 (downcase viper-use-register) viper-com-point (point)))
1499 (t (setq viper-use-register nil)
1500 (error viper-InvalidRegister viper-use-register)))
1501 (setq viper-use-register nil)))
1502 (setq last-command nil)
1503 (copy-region-as-kill viper-com-point (point))
1504 (setq chars-saved (abs (- (point) viper-com-point)))
1505 (if (> chars-saved viper-change-notification-threshold)
1506 (unless (viper-is-in-minibuffer)
1507 (message "Saved %d characters" chars-saved)))
1508 (goto-char viper-com-point)))
1510 ;; save lines
1511 (defun viper-exec-Yank (m-com com)
1512 (save-excursion
1513 (set-mark viper-com-point)
1514 (viper-enlarge-region (mark t) (point))
1515 (let (lines-saved)
1516 (if viper-use-register
1517 (progn
1518 (cond ((viper-valid-register viper-use-register '(letter digit))
1519 (copy-to-register
1520 viper-use-register (mark t) (point) nil))
1521 ((viper-valid-register viper-use-register '(Letter))
1522 (viper-append-to-register
1523 (downcase viper-use-register) (mark t) (point)))
1524 (t (setq viper-use-register nil)
1525 (error viper-InvalidRegister viper-use-register)))
1526 (setq viper-use-register nil)))
1527 (setq last-command nil)
1528 (copy-region-as-kill (mark t) (point))
1529 (setq lines-saved (count-lines (mark t) (point)))
1530 (if (> lines-saved viper-change-notification-threshold)
1531 (unless (viper-is-in-minibuffer)
1532 (message "Saved %d lines" lines-saved)))))
1533 (viper-deactivate-mark)
1534 (goto-char viper-com-point))
1536 (defun viper-exec-bang (m-com com)
1537 (save-excursion
1538 (set-mark viper-com-point)
1539 (viper-enlarge-region (mark t) (point))
1540 (exchange-point-and-mark)
1541 (shell-command-on-region
1542 (mark t) (point)
1543 (if (viper= com ?!)
1544 (setq viper-last-shell-com
1545 (viper-read-string-with-history
1548 'viper-shell-history
1549 (car viper-shell-history)
1551 viper-last-shell-com)
1552 t)))
1554 (defun viper-exec-equals (m-com com)
1555 (save-excursion
1556 (set-mark viper-com-point)
1557 (viper-enlarge-region (mark t) (point))
1558 (if (> (mark t) (point)) (exchange-point-and-mark))
1559 (indent-region (mark t) (point) nil)))
1561 (defun viper-exec-shift (m-com com)
1562 (save-excursion
1563 (set-mark viper-com-point)
1564 (viper-enlarge-region (mark t) (point))
1565 (if (> (mark t) (point)) (exchange-point-and-mark))
1566 (indent-rigidly (mark t) (point)
1567 (if (viper= com ?>)
1568 viper-shift-width
1569 (- viper-shift-width))))
1570 ;; return point to where it was before shift
1571 (goto-char viper-com-point))
1573 ;; this is needed because some commands fake com by setting it to ?r, which
1574 ;; denotes repeated insert command.
1575 (defsubst viper-exec-dummy (m-com com)
1576 nil)
1578 (defun viper-exec-buffer-search (m-com com)
1579 (setq viper-s-string
1580 (regexp-quote (buffer-substring (point) viper-com-point)))
1581 (setq viper-s-forward t)
1582 (setq viper-search-history (cons viper-s-string viper-search-history))
1583 (setq viper-intermediate-command 'viper-exec-buffer-search)
1584 (viper-search viper-s-string viper-s-forward 1))
1586 (defvar viper-exec-array (make-vector 128 nil))
1588 ;; Using a dispatch array allows adding functions like buffer search
1589 ;; without affecting other functions. Buffer search can now be bound
1590 ;; to any character.
1592 (aset viper-exec-array ?c 'viper-exec-change)
1593 (aset viper-exec-array ?C 'viper-exec-Change)
1594 (aset viper-exec-array ?d 'viper-exec-delete)
1595 (aset viper-exec-array ?D 'viper-exec-Delete)
1596 (aset viper-exec-array ?y 'viper-exec-yank)
1597 (aset viper-exec-array ?Y 'viper-exec-Yank)
1598 (aset viper-exec-array ?r 'viper-exec-dummy)
1599 (aset viper-exec-array ?! 'viper-exec-bang)
1600 (aset viper-exec-array ?< 'viper-exec-shift)
1601 (aset viper-exec-array ?> 'viper-exec-shift)
1602 (aset viper-exec-array ?= 'viper-exec-equals)
1606 ;; This function is called by various movement commands to execute a
1607 ;; destructive command on the region specified by the movement command. For
1608 ;; instance, if the user types cw, then the command viper-forward-word will
1609 ;; call viper-execute-com to execute viper-exec-change, which eventually will
1610 ;; call viper-change to invoke the replace mode on the region.
1612 ;; The var viper-d-com is set to (M-COM VAL COM REG INSETED-TEXT COMMAND-KEYS)
1613 ;; via a call to viper-set-destructive-command, for later use by viper-repeat.
1614 (defun viper-execute-com (m-com val com)
1615 (let ((reg viper-use-register))
1616 ;; this is the special command `#'
1617 (if (> com 128)
1618 (viper-special-prefix-com (- com 128))
1619 (let ((fn (aref viper-exec-array com)))
1620 (if (null fn)
1621 (error "%c: %s" com viper-InvalidViCommand)
1622 (funcall fn m-com com))))
1623 (if (viper-dotable-command-p com)
1624 (viper-set-destructive-command
1625 (list m-com val com reg nil nil)))
1629 (defun viper-repeat (arg)
1630 "Re-execute last destructive command.
1631 Use the info in viper-d-com, which has the form
1632 \(com val ch reg inserted-text command-keys\),
1633 where `com' is the command to be re-executed, `val' is the
1634 argument to `com', `ch' is a flag for repeat, and `reg' is optional;
1635 if it exists, it is the name of the register for `com'.
1636 If the prefix argument, ARG, is non-nil, it is used instead of `val'."
1637 (interactive "P")
1638 (let ((save-point (point)) ; save point before repeating prev cmd
1639 ;; Pass along that we are repeating a destructive command
1640 ;; This tells viper-set-destructive-command not to update
1641 ;; viper-command-ring
1642 (viper-intermediate-command 'viper-repeat))
1643 (if (eq last-command 'viper-undo)
1644 ;; if the last command was viper-undo, then undo-more
1645 (viper-undo-more)
1646 ;; otherwise execute the command stored in viper-d-com. if arg is
1647 ;; non-nil its prefix value is used as new prefix value for the command.
1648 (let ((m-com (car viper-d-com))
1649 (val (viper-P-val arg))
1650 (com (nth 2 viper-d-com))
1651 (reg (nth 3 viper-d-com)))
1652 (if (null val) (setq val (nth 1 viper-d-com)))
1653 (if (null m-com) (error "No previous command to repeat"))
1654 (setq viper-use-register reg)
1655 (if (nth 4 viper-d-com) ; text inserted by command
1656 (setq viper-last-insertion (nth 4 viper-d-com)
1657 viper-d-char (nth 4 viper-d-com)))
1658 (funcall m-com (cons val com))
1659 (cond ((and (< save-point (point)) viper-keep-point-on-repeat)
1660 (goto-char save-point)) ; go back to before repeat.
1661 ((and (< save-point (point)) viper-ex-style-editing)
1662 (or (bolp) (backward-char 1))))
1663 (if (and (eolp) (not (bolp)))
1664 (backward-char 1))
1666 (viper-adjust-undo) ; take care of undo
1667 ;; If the prev cmd was rotating the command ring, this means that `.' has
1668 ;; just executed a command from that ring. So, push it on the ring again.
1669 ;; If we are just executing previous command , then don't push viper-d-com
1670 ;; because viper-d-com is not fully constructed in this case (its keys and
1671 ;; the inserted text may be nil). Besides, in this case, the command
1672 ;; executed by `.' is already on the ring.
1673 (if (eq last-command 'viper-display-current-destructive-command)
1674 (viper-push-onto-ring viper-d-com 'viper-command-ring))
1675 (viper-deactivate-mark)
1678 (defun viper-repeat-from-history ()
1679 "Repeat a destructive command from history.
1680 Doesn't change viper-command-ring in any way, so `.' will work as before
1681 executing this command.
1682 This command is supposed to be bound to a two-character Vi macro where
1683 the second character is a digit 0 to 9. The digit indicates which
1684 history command to execute. `<char>0' is equivalent to `.', `<char>1'
1685 invokes the command before that, etc."
1686 (interactive)
1687 (let* ((viper-intermediate-command 'repeating-display-destructive-command)
1688 (idx (cond (viper-this-kbd-macro
1689 (string-to-number
1690 (symbol-name (elt viper-this-kbd-macro 1))))
1691 (t 0)))
1692 (num idx)
1693 (viper-d-com viper-d-com))
1695 (or (and (numberp num) (<= 0 num) (<= num 9))
1696 (progn
1697 (setq idx 0
1698 num 0)
1699 (message
1700 "`viper-repeat-from-history' must be invoked as a Vi macro bound to `<key><digit>'")))
1701 (while (< 0 num)
1702 (setq viper-d-com (viper-special-ring-rotate1 viper-command-ring -1))
1703 (setq num (1- num)))
1704 (viper-repeat nil)
1705 (while (> idx num)
1706 (viper-special-ring-rotate1 viper-command-ring 1)
1707 (setq num (1+ num)))
1711 ;; The hash-command. It is invoked interactively by the key sequence #<char>.
1712 ;; The chars that can follow `#' are determined by viper-hash-command-p
1713 (defun viper-special-prefix-com (char)
1714 (cond ((viper= char ?c)
1715 (downcase-region (min viper-com-point (point))
1716 (max viper-com-point (point))))
1717 ((viper= char ?C)
1718 (upcase-region (min viper-com-point (point))
1719 (max viper-com-point (point))))
1720 ((viper= char ?g)
1721 (push-mark viper-com-point t)
1722 (viper-global-execute))
1723 ((viper= char ?q)
1724 (push-mark viper-com-point t)
1725 (viper-quote-region))
1726 ((viper= char ?s)
1727 (funcall viper-spell-function viper-com-point (point)))
1728 (t (error "#%c: %s" char viper-InvalidViCommand))))
1731 ;; undoing
1733 (defun viper-undo ()
1734 "Undo previous change."
1735 (interactive)
1736 (message "undo!")
1737 (let ((modified (buffer-modified-p))
1738 (before-undo-pt (point-marker))
1739 (after-change-functions after-change-functions)
1740 undo-beg-posn undo-end-posn)
1742 ;; no need to remove this hook, since this var has scope inside a let.
1743 (add-hook 'after-change-functions
1744 '(lambda (beg end len)
1745 (setq undo-beg-posn beg
1746 undo-end-posn (or end beg))))
1748 (undo-start)
1749 (undo-more 2)
1750 (setq undo-beg-posn (or undo-beg-posn before-undo-pt)
1751 undo-end-posn (or undo-end-posn undo-beg-posn))
1753 (goto-char undo-beg-posn)
1754 (sit-for 0)
1755 (if (and viper-keep-point-on-undo
1756 (pos-visible-in-window-p before-undo-pt))
1757 (progn
1758 (push-mark (point-marker) t)
1759 (viper-sit-for-short 300)
1760 (goto-char undo-end-posn)
1761 (viper-sit-for-short 300)
1762 (if (and (> (viper-chars-in-region undo-beg-posn before-undo-pt) 1)
1763 (> (viper-chars-in-region undo-end-posn before-undo-pt) 1))
1764 (goto-char before-undo-pt)
1765 (goto-char undo-beg-posn)))
1766 (push-mark before-undo-pt t))
1767 (if (and (eolp) (not (bolp))) (backward-char 1))
1768 (if (not modified) (set-buffer-modified-p t)))
1769 (setq this-command 'viper-undo))
1771 ;; Continue undoing previous changes.
1772 (defun viper-undo-more ()
1773 (message "undo more!")
1774 (condition-case nil
1775 (undo-more 1)
1776 (error (beep)
1777 (message "No further undo information in this buffer")))
1778 (if (and (eolp) (not (bolp))) (backward-char 1))
1779 (setq this-command 'viper-undo))
1781 ;; The following two functions are used to set up undo properly.
1782 ;; In VI, unlike Emacs, if you open a line, say, and add a bunch of lines,
1783 ;; they are undone all at once.
1784 (defun viper-adjust-undo ()
1785 (if viper-undo-needs-adjustment
1786 (let ((inhibit-quit t)
1787 tmp tmp2)
1788 (setq viper-undo-needs-adjustment nil)
1789 (if (listp buffer-undo-list)
1790 (if (setq tmp (memq viper-buffer-undo-list-mark buffer-undo-list))
1791 (progn
1792 (setq tmp2 (cdr tmp)) ; the part after mark
1794 ;; cut tail from buffer-undo-list temporarily by direct
1795 ;; manipulation with pointers in buffer-undo-list
1796 (setcdr tmp nil)
1798 (setq buffer-undo-list (delq nil buffer-undo-list))
1799 (setq buffer-undo-list
1800 (delq viper-buffer-undo-list-mark buffer-undo-list))
1801 ;; restore tail of buffer-undo-list
1802 (setq buffer-undo-list (nconc buffer-undo-list tmp2)))
1803 (setq buffer-undo-list (delq nil buffer-undo-list)))))
1807 (defun viper-set-complex-command-for-undo ()
1808 (if (listp buffer-undo-list)
1809 (if (not viper-undo-needs-adjustment)
1810 (let ((inhibit-quit t))
1811 (setq buffer-undo-list
1812 (cons viper-buffer-undo-list-mark buffer-undo-list))
1813 (setq viper-undo-needs-adjustment t)))))
1818 (defun viper-display-current-destructive-command ()
1819 (let ((text (nth 4 viper-d-com))
1820 (keys (nth 5 viper-d-com))
1821 (max-text-len 30))
1823 (setq this-command 'viper-display-current-destructive-command)
1825 (message " `.' runs %s%s"
1826 (concat "`" (viper-array-to-string keys) "'")
1827 (viper-abbreviate-string
1828 (viper-cond-compile-for-xemacs-or-emacs
1829 (replace-in-string ; xemacs
1830 (cond ((characterp text) (char-to-string text))
1831 ((stringp text) text)
1832 (t ""))
1833 "\n" "^J")
1834 text ; emacs
1836 max-text-len
1837 " inserting `" "'" " ......."))
1841 ;; don't change viper-d-com if it was viper-repeat command invoked with `.'
1842 ;; or in some other way (non-interactively).
1843 (defun viper-set-destructive-command (list)
1844 (or (eq viper-intermediate-command 'viper-repeat)
1845 (progn
1846 (setq viper-d-com list)
1847 (setcar (nthcdr 5 viper-d-com)
1848 (viper-array-to-string (if (arrayp viper-this-command-keys)
1849 viper-this-command-keys
1850 (this-command-keys))))
1851 (viper-push-onto-ring viper-d-com 'viper-command-ring)))
1852 (setq viper-this-command-keys nil))
1855 (defun viper-prev-destructive-command (next)
1856 "Find previous destructive command in the history of destructive commands.
1857 With prefix argument, find next destructive command."
1858 (interactive "P")
1859 (let (cmd viper-intermediate-command)
1860 (if (eq last-command 'viper-display-current-destructive-command)
1861 ;; repeated search through command history
1862 (setq viper-intermediate-command
1863 'repeating-display-destructive-command)
1864 ;; first search through command history--set temp ring
1865 (setq viper-temp-command-ring (copy-list viper-command-ring)))
1866 (setq cmd (if next
1867 (viper-special-ring-rotate1 viper-temp-command-ring 1)
1868 (viper-special-ring-rotate1 viper-temp-command-ring -1)))
1869 (if (null cmd)
1871 (setq viper-d-com cmd))
1872 (viper-display-current-destructive-command)))
1875 (defun viper-next-destructive-command ()
1876 "Find next destructive command in the history of destructive commands."
1877 (interactive)
1878 (viper-prev-destructive-command 'next))
1881 (defun viper-insert-prev-from-insertion-ring (arg)
1882 "Cycle through insertion ring in the direction of older insertions.
1883 Undoes previous insertion and inserts new.
1884 With prefix argument, cycles in the direction of newer elements.
1885 In minibuffer, this command executes whatever the invocation key is bound
1886 to in the global map, instead of cycling through the insertion ring."
1887 (interactive "P")
1888 (let (viper-intermediate-command)
1889 (if (eq last-command 'viper-insert-from-insertion-ring)
1890 (progn ; repeated search through insertion history
1891 (setq viper-intermediate-command 'repeating-insertion-from-ring)
1892 (if (eq viper-current-state 'replace-state)
1893 (undo 1)
1894 (if viper-last-inserted-string-from-insertion-ring
1895 (backward-delete-char
1896 (length viper-last-inserted-string-from-insertion-ring))))
1898 ;;first search through insertion history
1899 (setq viper-temp-insertion-ring (copy-list viper-insertion-ring)))
1900 (setq this-command 'viper-insert-from-insertion-ring)
1901 ;; so that things will be undone properly
1902 (setq buffer-undo-list (cons nil buffer-undo-list))
1903 (setq viper-last-inserted-string-from-insertion-ring
1904 (viper-special-ring-rotate1 viper-temp-insertion-ring (if arg 1 -1)))
1906 ;; this change of viper-intermediate-command must come after
1907 ;; viper-special-ring-rotate1, so that the ring will rotate, but before the
1908 ;; insertion.
1909 (setq viper-intermediate-command nil)
1910 (if viper-last-inserted-string-from-insertion-ring
1911 (insert viper-last-inserted-string-from-insertion-ring))
1914 (defun viper-insert-next-from-insertion-ring ()
1915 "Cycle through insertion ring in the direction of older insertions.
1916 Undo previous insertion and inserts new."
1917 (interactive)
1918 (viper-insert-prev-from-insertion-ring 'next))
1922 ;; some region utilities
1924 ;; If at the last line of buffer, add \\n before eob, if newline is missing.
1925 (defun viper-add-newline-at-eob-if-necessary ()
1926 (save-excursion
1927 (end-of-line)
1928 ;; make sure all lines end with newline, unless in the minibuffer or
1929 ;; when requested otherwise (require-final-newline is nil)
1930 (if (and (eobp)
1931 (not (bolp))
1932 require-final-newline
1933 (not (viper-is-in-minibuffer))
1934 (not buffer-read-only))
1935 (insert "\n"))))
1937 (defun viper-yank-defun ()
1938 (mark-defun)
1939 (copy-region-as-kill (point) (mark t)))
1941 ;; Enlarge region between BEG and END.
1942 (defun viper-enlarge-region (beg end)
1943 (or beg (setq beg end)) ; if beg is nil, set to end
1944 (or end (setq end beg)) ; if end is nil, set to beg
1946 (if (< beg end)
1947 (progn (goto-char beg) (set-mark end))
1948 (goto-char end)
1949 (set-mark beg))
1950 (beginning-of-line)
1951 (exchange-point-and-mark)
1952 (if (or (not (eobp)) (not (bolp))) (forward-line 1))
1953 (if (not (eobp)) (beginning-of-line))
1954 (if (> beg end) (exchange-point-and-mark)))
1957 ;; Quote region by each line with a user supplied string.
1958 (defun viper-quote-region ()
1959 (let ((quote-str viper-quote-string)
1960 (donot-change-dafault t))
1961 (setq quote-str
1962 (viper-read-string-with-history
1963 "Quote string: "
1965 'viper-quote-region-history
1966 (cond ((string-match "tex.*-mode" (symbol-name major-mode)) "%%")
1967 ((string-match "java.*-mode" (symbol-name major-mode)) "//")
1968 ((string-match "perl.*-mode" (symbol-name major-mode)) "#")
1969 ((string-match "lisp.*-mode" (symbol-name major-mode)) ";;")
1970 ((memq major-mode '(c-mode cc-mode c++-mode)) "//")
1971 ((memq major-mode '(sh-mode shell-mode)) "#")
1972 (t (setq donot-change-dafault nil)
1973 quote-str))))
1974 (or donot-change-dafault
1975 (setq viper-quote-string quote-str))
1976 (viper-enlarge-region (point) (mark t))
1977 (if (> (point) (mark t)) (exchange-point-and-mark))
1978 (insert quote-str)
1979 (beginning-of-line)
1980 (forward-line 1)
1981 (while (and (< (point) (mark t)) (bolp))
1982 (insert quote-str)
1983 (beginning-of-line)
1984 (forward-line 1))))
1986 ;; Tells whether BEG is on the same line as END.
1987 ;; If one of the args is nil, it'll return nil.
1988 (defun viper-same-line (beg end)
1989 (let ((selective-display nil)
1990 (incr 0)
1991 temp)
1992 (if (and beg end (> beg end))
1993 (setq temp beg
1994 beg end
1995 end temp))
1996 (if (and beg end)
1997 (cond ((or (> beg (point-max)) (> end (point-max))) ; out of range
1998 nil)
2000 ;; This 'if' is needed because Emacs treats the next empty line
2001 ;; as part of the previous line.
2002 (if (= (viper-line-pos 'start) end)
2003 (setq incr 1))
2004 (<= (+ incr (count-lines beg end)) 1))))
2008 ;; Check if the string ends with a newline.
2009 (defun viper-end-with-a-newline-p (string)
2010 (or (string= string "")
2011 (= (viper-seq-last-elt string) ?\n)))
2013 (defun viper-tmp-insert-at-eob (msg)
2014 (let ((savemax (point-max)))
2015 (goto-char savemax)
2016 (insert msg)
2017 (sit-for 2)
2018 (goto-char savemax) (delete-region (point) (point-max))
2023 ;;; Minibuffer business
2025 (defsubst viper-set-minibuffer-style ()
2026 (add-hook 'minibuffer-setup-hook 'viper-minibuffer-setup-sentinel)
2027 (add-hook 'post-command-hook 'viper-minibuffer-post-command-hook))
2030 (defun viper-minibuffer-setup-sentinel ()
2031 (let ((hook (if viper-vi-style-in-minibuffer
2032 'viper-change-state-to-insert
2033 'viper-change-state-to-emacs)))
2034 ;; making buffer-local variables so that normal buffers won't affect the
2035 ;; minibuffer and vice versa. Otherwise, command arguments will affect
2036 ;; minibuffer ops and insertions from the minibuffer will change those in
2037 ;; the normal buffers
2038 (make-local-variable 'viper-d-com)
2039 (make-local-variable 'viper-last-insertion)
2040 (make-local-variable 'viper-command-ring)
2041 (setq viper-d-com nil
2042 viper-last-insertion nil
2043 viper-command-ring nil)
2044 (funcall hook)
2047 ;; Thie is a temp hook that uses free variables init-message and initial.
2048 ;; A dirty feature, but it is the simplest way to have it do the right thing.
2049 ;; The INIT-MESSAGE and INITIAL vars come from the scope set by
2050 ;; viper-read-string-with-history
2051 (defun viper-minibuffer-standard-hook ()
2052 (if (stringp init-message)
2053 (viper-tmp-insert-at-eob init-message))
2054 (if (stringp initial)
2055 (progn
2056 ;; don't wait if we have unread events or in kbd macro
2057 (or unread-command-events
2058 executing-kbd-macro
2059 (sit-for 840))
2060 (if (fboundp 'minibuffer-prompt-end)
2061 (delete-region (minibuffer-prompt-end) (point-max))
2062 (erase-buffer))
2063 (insert initial))))
2065 (defsubst viper-minibuffer-real-start ()
2066 (if (fboundp 'minibuffer-prompt-end)
2067 (minibuffer-prompt-end)
2068 (point-min)))
2070 (defun viper-minibuffer-post-command-hook()
2071 (when (active-minibuffer-window)
2072 (when (< (point) (viper-minibuffer-real-start))
2073 (goto-char (viper-minibuffer-real-start)))))
2076 ;; Interpret last event in the local map first; if fails, use exit-minibuffer.
2077 ;; Run viper-minibuffer-exit-hook before exiting.
2078 (defun viper-exit-minibuffer ()
2079 "Exit minibuffer Viper way."
2080 (interactive)
2081 (let (command)
2082 (setq command (local-key-binding (char-to-string last-command-char)))
2083 (run-hooks 'viper-minibuffer-exit-hook)
2084 (if command
2085 (command-execute command)
2086 (exit-minibuffer))))
2089 (defcustom viper-smart-suffix-list
2090 '("" "tex" "c" "cc" "C" "java" "el" "html" "htm" "xml"
2091 "pl" "flr" "P" "p" "h" "H")
2092 "*List of suffixes that Viper tries to append to filenames ending with a `.'.
2093 This is useful when the current directory contains files with the same
2094 prefix and many different suffixes. Usually, only one of the suffixes
2095 represents an editable file. However, file completion will stop at the `.'
2096 The smart suffix feature lets you hit RET in such a case, and Viper will
2097 select the appropriate suffix.
2099 Suffixes are tried in the order given and the first suffix for which a
2100 corresponding file exists is selected. If no file exists for any of the
2101 suffixes, the user is asked to confirm.
2103 To turn this feature off, set this variable to nil."
2104 :type '(repeat string)
2105 :group 'viper-misc)
2108 ;; Try to add a suitable suffix to files whose name ends with a `.'
2109 ;; Useful when the user hits RET on a non-completed file name.
2110 ;; Used as a minibuffer exit hook in read-file-name
2111 (defun viper-file-add-suffix ()
2112 (let ((count 0)
2113 (len (length viper-smart-suffix-list))
2114 (file (buffer-substring-no-properties
2115 (viper-minibuffer-real-start) (point-max)))
2116 found key cmd suff)
2117 (goto-char (point-max))
2118 (if (and viper-smart-suffix-list (string-match "\\.$" file))
2119 (progn
2120 (while (and (not found) (< count len))
2121 (setq suff (nth count viper-smart-suffix-list)
2122 count (1+ count))
2123 (if (file-exists-p
2124 (format "%s%s" (substitute-in-file-name file) suff))
2125 (progn
2126 (setq found t)
2127 (insert suff))))
2129 (if found
2131 (viper-tmp-insert-at-eob " [Please complete file name]")
2132 (unwind-protect
2133 (while (not (memq cmd
2134 '(exit-minibuffer viper-exit-minibuffer)))
2135 (setq cmd
2136 (key-binding (setq key (read-key-sequence nil))))
2137 (cond ((eq cmd 'self-insert-command)
2138 (viper-cond-compile-for-xemacs-or-emacs
2139 (insert (events-to-keys key)) ; xemacs
2140 (insert key) ; emacs
2142 ((memq cmd '(exit-minibuffer viper-exit-minibuffer))
2143 nil)
2144 (t (command-execute cmd)))
2146 ))))
2149 (defun viper-minibuffer-trim-tail ()
2150 "Delete junk at the end of the first line of the minibuffer input.
2151 Remove this function from `viper-minibuffer-exit-hook', if this causes
2152 problems."
2153 (if (viper-is-in-minibuffer)
2154 (let ((inhibit-field-text-motion t))
2155 (goto-char (viper-minibuffer-real-start))
2156 (end-of-line)
2157 (delete-region (point) (point-max)))))
2160 ;;; Reading string with history
2162 (defun viper-read-string-with-history (prompt &optional initial
2163 history-var default keymap
2164 init-message)
2165 ;; Read string, prompting with PROMPT and inserting the INITIAL
2166 ;; value. Uses HISTORY-VAR. DEFAULT is the default value to accept if the
2167 ;; input is an empty string.
2168 ;; Default value is displayed until the user types something in the
2169 ;; minibuffer.
2170 ;; KEYMAP is used, if given, instead of minibuffer-local-map.
2171 ;; INIT-MESSAGE is the message temporarily displayed after entering the
2172 ;; minibuffer.
2173 (let ((minibuffer-setup-hook
2174 ;; stolen from add-hook
2175 (let ((old
2176 (if (boundp 'minibuffer-setup-hook)
2177 minibuffer-setup-hook
2178 nil)))
2179 (cons
2180 'viper-minibuffer-standard-hook
2181 (if (or (not (listp old)) (eq (car old) 'lambda))
2182 (list old) old))))
2183 (val "")
2184 (padding "")
2185 temp-msg)
2187 (setq keymap (or keymap minibuffer-local-map)
2188 initial (or initial "")
2189 temp-msg (if default
2190 (format "(default %s) " default)
2191 ""))
2193 (setq viper-incomplete-ex-cmd nil)
2194 (setq val (read-from-minibuffer prompt
2195 (concat temp-msg initial val padding)
2196 keymap nil history-var))
2197 (setq minibuffer-setup-hook nil
2198 padding (viper-array-to-string (this-command-keys))
2199 temp-msg "")
2200 ;; the following tries to be smart about what to put in history
2201 (if (not (string= val (car (eval history-var))))
2202 (set history-var (cons val (eval history-var))))
2203 (if (or (string= (nth 0 (eval history-var)) (nth 1 (eval history-var)))
2204 (string= (nth 0 (eval history-var)) ""))
2205 (set history-var (cdr (eval history-var))))
2206 ;; If the user enters nothing but the prev cmd wasn't viper-ex,
2207 ;; viper-command-argument, or `! shell-command', this probably means
2208 ;; that the user typed something then erased. Return "" in this case, not
2209 ;; the default---the default is too confusing in this case.
2210 (cond ((and (string= val "")
2211 (not (string= prompt "!")) ; was a `! shell-command'
2212 (not (memq last-command
2213 '(viper-ex
2214 viper-command-argument
2218 ((string= val "") (or default ""))
2219 (t val))
2224 ;; insertion commands
2226 ;; Called when state changes from Insert Vi command mode.
2227 ;; Repeats the insertion command if Insert state was entered with prefix
2228 ;; argument > 1.
2229 (defun viper-repeat-insert-command ()
2230 (let ((i-com (car viper-d-com))
2231 (val (nth 1 viper-d-com))
2232 (char (nth 2 viper-d-com)))
2233 (if (and val (> val 1)) ; first check that val is non-nil
2234 (progn
2235 (setq viper-d-com (list i-com (1- val) ?r nil nil nil))
2236 (viper-repeat nil)
2237 (setq viper-d-com (list i-com val char nil nil nil))
2238 ))))
2240 (defun viper-insert (arg)
2241 "Insert before point."
2242 (interactive "P")
2243 (viper-set-complex-command-for-undo)
2244 (let ((val (viper-p-val arg))
2245 ;;(com (viper-getcom arg))
2247 (viper-set-destructive-command (list 'viper-insert val ?r nil nil nil))
2248 (if (eq viper-intermediate-command 'viper-repeat)
2249 (viper-loop val (viper-yank-last-insertion))
2250 (viper-change-state-to-insert))))
2252 (defun viper-append (arg)
2253 "Append after point."
2254 (interactive "P")
2255 (viper-set-complex-command-for-undo)
2256 (let ((val (viper-p-val arg))
2257 ;;(com (viper-getcom arg))
2259 (viper-set-destructive-command (list 'viper-append val ?r nil nil nil))
2260 (if (not (eolp)) (forward-char))
2261 (if (eq viper-intermediate-command 'viper-repeat)
2262 (viper-loop val (viper-yank-last-insertion))
2263 (viper-change-state-to-insert))))
2265 (defun viper-Append (arg)
2266 "Append at end of line."
2267 (interactive "P")
2268 (viper-set-complex-command-for-undo)
2269 (let ((val (viper-p-val arg))
2270 ;;(com (viper-getcom arg))
2272 (viper-set-destructive-command (list 'viper-Append val ?r nil nil nil))
2273 (end-of-line)
2274 (if (eq viper-intermediate-command 'viper-repeat)
2275 (viper-loop val (viper-yank-last-insertion))
2276 (viper-change-state-to-insert))))
2278 (defun viper-Insert (arg)
2279 "Insert before first non-white."
2280 (interactive "P")
2281 (viper-set-complex-command-for-undo)
2282 (let ((val (viper-p-val arg))
2283 ;;(com (viper-getcom arg))
2285 (viper-set-destructive-command (list 'viper-Insert val ?r nil nil nil))
2286 (back-to-indentation)
2287 (if (eq viper-intermediate-command 'viper-repeat)
2288 (viper-loop val (viper-yank-last-insertion))
2289 (viper-change-state-to-insert))))
2291 (defun viper-open-line (arg)
2292 "Open line below."
2293 (interactive "P")
2294 (viper-set-complex-command-for-undo)
2295 (let ((val (viper-p-val arg))
2296 ;;(com (viper-getcom arg))
2298 (viper-set-destructive-command (list 'viper-open-line val ?r nil nil nil))
2299 (let ((col (current-indentation)))
2300 (if (eq viper-intermediate-command 'viper-repeat)
2301 (viper-loop val
2302 (end-of-line)
2303 (newline 1)
2304 (viper-indent-line col)
2305 (viper-yank-last-insertion))
2306 (end-of-line)
2307 (newline 1)
2308 (viper-indent-line col)
2309 (viper-change-state-to-insert)))))
2311 (defun viper-Open-line (arg)
2312 "Open line above."
2313 (interactive "P")
2314 (viper-set-complex-command-for-undo)
2315 (let ((val (viper-p-val arg))
2316 ;;(com (viper-getcom arg))
2318 (viper-set-destructive-command (list 'viper-Open-line val ?r nil nil nil))
2319 (let ((col (current-indentation)))
2320 (if (eq viper-intermediate-command 'viper-repeat)
2321 (viper-loop val
2322 (beginning-of-line)
2323 (open-line 1)
2324 (viper-indent-line col)
2325 (viper-yank-last-insertion))
2326 (beginning-of-line)
2327 (open-line 1)
2328 (viper-indent-line col)
2329 (viper-change-state-to-insert)))))
2331 (defun viper-open-line-at-point (arg)
2332 "Open line at point."
2333 (interactive "P")
2334 (viper-set-complex-command-for-undo)
2335 (let ((val (viper-p-val arg))
2336 ;;(com (viper-getcom arg))
2338 (viper-set-destructive-command
2339 (list 'viper-open-line-at-point val ?r nil nil nil))
2340 (if (eq viper-intermediate-command 'viper-repeat)
2341 (viper-loop val
2342 (open-line 1)
2343 (viper-yank-last-insertion))
2344 (open-line 1)
2345 (viper-change-state-to-insert))))
2347 ;; bound to s
2348 (defun viper-substitute (arg)
2349 "Substitute characters."
2350 (interactive "P")
2351 (let ((val (viper-p-val arg))
2352 ;;(com (viper-getcom arg))
2354 (push-mark nil t)
2355 (forward-char val)
2356 (if (eq viper-intermediate-command 'viper-repeat)
2357 (viper-change-subr (mark t) (point))
2358 (viper-change (mark t) (point)))
2359 ;; com is set to ?r when we repeat this comand with dot
2360 (viper-set-destructive-command (list 'viper-substitute val ?r nil nil nil))
2363 ;; Command bound to S
2364 (defun viper-substitute-line (arg)
2365 "Substitute lines."
2366 (interactive "p")
2367 (viper-set-complex-command-for-undo)
2368 (viper-line (cons arg ?C)))
2370 ;; Prepare for replace
2371 (defun viper-start-replace ()
2372 (setq viper-began-as-replace t
2373 viper-sitting-in-replace t
2374 viper-replace-chars-to-delete 0)
2375 (add-hook
2376 'viper-after-change-functions 'viper-replace-mode-spy-after t 'local)
2377 (add-hook
2378 'viper-before-change-functions 'viper-replace-mode-spy-before t 'local)
2379 ;; this will get added repeatedly, but no harm
2380 (add-hook 'after-change-functions 'viper-after-change-sentinel t)
2381 (add-hook 'before-change-functions 'viper-before-change-sentinel t)
2382 (viper-move-marker-locally
2383 'viper-last-posn-in-replace-region (viper-replace-start))
2384 (add-hook
2385 'viper-post-command-hooks 'viper-replace-state-post-command-sentinel
2386 t 'local)
2387 (add-hook
2388 'viper-pre-command-hooks 'viper-replace-state-pre-command-sentinel t 'local)
2389 ;; guard against a smartie who switched from R-replace to normal replace
2390 (remove-hook
2391 'viper-post-command-hooks 'viper-R-state-post-command-sentinel 'local)
2392 (if overwrite-mode (overwrite-mode -1))
2396 (defun viper-replace-mode-spy-before (beg end)
2397 (setq viper-replace-region-chars-deleted (viper-chars-in-region beg end))
2400 ;; Invoked as an after-change-function to calculate how many chars have to be
2401 ;; deleted. This function may be called several times within a single command,
2402 ;; if this command performs several separate buffer changes. Therefore, if
2403 ;; adds up the number of chars inserted and subtracts the number of chars
2404 ;; deleted.
2405 (defun viper-replace-mode-spy-after (beg end length)
2406 (if (memq viper-intermediate-command
2407 '(dabbrev-expand hippie-expand repeating-insertion-from-ring))
2408 ;; Take special care of text insertion from insertion ring inside
2409 ;; replacement overlays.
2410 (progn
2411 (setq viper-replace-chars-to-delete 0)
2412 (viper-move-marker-locally
2413 'viper-last-posn-in-replace-region (point)))
2415 (let* ((real-end (min end (viper-replace-end)))
2416 (column-shift (- (save-excursion (goto-char real-end)
2417 (current-column))
2418 (save-excursion (goto-char beg)
2419 (current-column))))
2420 (chars-deleted 0))
2422 (if (> length 0)
2423 (setq chars-deleted viper-replace-region-chars-deleted))
2424 (setq viper-replace-region-chars-deleted 0)
2425 (setq viper-replace-chars-to-delete
2426 (+ viper-replace-chars-to-delete
2428 ;; if column shift is bigger, due to a TAB insertion, take
2429 ;; column-shift instead of the number of inserted chars
2430 (max (viper-chars-in-region beg real-end)
2431 ;; This test accounts for Chinese/Japanese/... chars,
2432 ;; which occupy 2 columns instead of one. If we use
2433 ;; column-shift here, we may delete two chars instead of
2434 ;; one when the user types one Chinese character.
2435 ;; Deleting two would be OK, if they were European chars,
2436 ;; but it is not OK if they are Chinese chars.
2437 ;; Since it is hard to
2438 ;; figure out which characters are being deleted in any
2439 ;; given region, we decided to treat Eastern and European
2440 ;; characters equally, even though Eastern chars may
2441 ;; occupy more columns.
2442 (if (memq this-command '(self-insert-command
2443 quoted-insert viper-insert-tab))
2444 column-shift
2446 ;; the number of deleted chars
2447 chars-deleted)))
2449 (viper-move-marker-locally
2450 'viper-last-posn-in-replace-region
2451 (max (if (> end (viper-replace-end)) (viper-replace-end) end)
2452 (or (marker-position viper-last-posn-in-replace-region)
2453 (viper-replace-start))
2459 ;; Delete stuff between viper-last-posn-in-replace-region and the end of
2460 ;; viper-replace-overlay-marker, if viper-last-posn-in-replace-region is within
2461 ;; the overlay and current point is before the end of the overlay.
2462 ;; Don't delete anything if current point is past the end of the overlay.
2463 (defun viper-finish-change ()
2464 (remove-hook
2465 'viper-after-change-functions 'viper-replace-mode-spy-after 'local)
2466 (remove-hook
2467 'viper-before-change-functions 'viper-replace-mode-spy-before 'local)
2468 (remove-hook
2469 'viper-post-command-hooks 'viper-replace-state-post-command-sentinel 'local)
2470 (remove-hook
2471 'viper-pre-command-hooks 'viper-replace-state-pre-command-sentinel 'local)
2472 (viper-restore-cursor-color 'after-replace-mode)
2473 (setq viper-sitting-in-replace nil) ; just in case we'll need to know it
2474 (save-excursion
2475 (if (and viper-replace-overlay
2476 (viper-pos-within-region viper-last-posn-in-replace-region
2477 (viper-replace-start)
2478 (viper-replace-end))
2479 (< (point) (viper-replace-end)))
2480 (delete-region
2481 viper-last-posn-in-replace-region (viper-replace-end))))
2483 (if (eq viper-current-state 'replace-state)
2484 (viper-downgrade-to-insert))
2485 ;; replace mode ended => nullify viper-last-posn-in-replace-region
2486 (viper-move-marker-locally 'viper-last-posn-in-replace-region nil)
2487 (viper-hide-replace-overlay)
2488 (viper-refresh-mode-line)
2489 (viper-put-string-on-kill-ring viper-last-replace-region)
2492 ;; Make STRING be the first element of the kill ring.
2493 (defun viper-put-string-on-kill-ring (string)
2494 (setq kill-ring (cons string kill-ring))
2495 (if (> (length kill-ring) kill-ring-max)
2496 (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil))
2497 (setq kill-ring-yank-pointer kill-ring))
2499 (defun viper-finish-R-mode ()
2500 (remove-hook
2501 'viper-post-command-hooks 'viper-R-state-post-command-sentinel 'local)
2502 (remove-hook
2503 'viper-pre-command-hooks 'viper-replace-state-pre-command-sentinel 'local)
2504 (viper-downgrade-to-insert))
2506 (defun viper-start-R-mode ()
2507 ;; Leave arg as 1, not t: XEmacs insists that it must be a pos number
2508 (overwrite-mode 1)
2509 (add-hook
2510 'viper-post-command-hooks 'viper-R-state-post-command-sentinel t 'local)
2511 (add-hook
2512 'viper-pre-command-hooks 'viper-replace-state-pre-command-sentinel t 'local)
2513 ;; guard against a smartie who switched from R-replace to normal replace
2514 (remove-hook
2515 'viper-post-command-hooks 'viper-replace-state-post-command-sentinel 'local)
2520 (defun viper-replace-state-exit-cmd ()
2521 "Binding for keys that cause Replace state to switch to Vi or to Insert.
2522 These keys are ESC, RET, and LineFeed"
2523 (interactive)
2524 (if overwrite-mode ; if in replace mode invoked via 'R'
2525 (viper-finish-R-mode)
2526 (viper-finish-change))
2527 (let (com)
2528 (if (eq this-command 'viper-intercept-ESC-key)
2529 (setq com 'viper-exit-insert-state)
2530 (viper-set-unread-command-events last-input-char)
2531 (setq com (key-binding (viper-read-key-sequence nil))))
2533 (condition-case conds
2534 (command-execute com)
2535 (error
2536 (viper-message-conditions conds)))
2538 (viper-hide-replace-overlay))
2541 (defun viper-replace-state-carriage-return ()
2542 "Carriage return in Viper replace state."
2543 (interactive)
2544 ;; If Emacs start supporting overlay maps, as it currently supports
2545 ;; text-property maps, we could do away with viper-replace-minor-mode and
2546 ;; just have keymap attached to replace overlay. Then the "if part" of this
2547 ;; statement can be deleted.
2548 (if (or (< (point) (viper-replace-start))
2549 (> (point) (viper-replace-end)))
2550 (let (viper-replace-minor-mode com)
2551 (viper-set-unread-command-events last-input-char)
2552 (setq com (key-binding (read-key-sequence nil)))
2553 (condition-case conds
2554 (command-execute com)
2555 (error
2556 (viper-message-conditions conds))))
2557 (if (not viper-allow-multiline-replace-regions)
2558 (viper-replace-state-exit-cmd)
2559 (if (viper-same-line (point) (viper-replace-end))
2560 (viper-replace-state-exit-cmd)
2561 ;; delete the rest of line
2562 (delete-region (point) (viper-line-pos 'end))
2563 (save-excursion
2564 (end-of-line)
2565 (if (eobp) (error "Last line in buffer")))
2566 ;; skip to the next line
2567 (forward-line 1)
2568 (back-to-indentation)
2569 ))))
2572 ;; This is the function bound to 'R'---unlimited replace.
2573 ;; Similar to Emacs's own overwrite-mode.
2574 (defun viper-overwrite (arg)
2575 "Begin overwrite mode."
2576 (interactive "P")
2577 (let ((val (viper-p-val arg))
2578 ;;(com (viper-getcom arg))
2579 (len))
2580 (viper-set-destructive-command (list 'viper-overwrite val ?r nil nil nil))
2581 (if (eq viper-intermediate-command 'viper-repeat)
2582 (progn
2583 ;; Viper saves inserted text in viper-last-insertion
2584 (setq len (length viper-last-insertion))
2585 (delete-char (min len (- (point-max) (point) 1)))
2586 (viper-loop val (viper-yank-last-insertion)))
2587 (setq last-command 'viper-overwrite)
2588 (viper-set-complex-command-for-undo)
2589 (viper-set-replace-overlay (point) (viper-line-pos 'end))
2590 (viper-change-state-to-replace)
2594 ;; line commands
2596 (defun viper-line (arg)
2597 (let ((val (car arg))
2598 (com (cdr arg)))
2599 (viper-move-marker-locally 'viper-com-point (point))
2600 (if (not (eobp))
2601 (viper-next-line-carefully (1- val)))
2602 ;; the following ensures that dd, cc, D, yy will do the right thing on the
2603 ;; last line of buffer when this line has no \n.
2604 (viper-add-newline-at-eob-if-necessary)
2605 (viper-execute-com 'viper-line val com))
2606 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
2609 (defun viper-yank-line (arg)
2610 "Yank ARG lines (in Vi's sense)."
2611 (interactive "P")
2612 (let ((val (viper-p-val arg)))
2613 (viper-line (cons val ?Y))))
2616 ;; region commands
2618 (defun viper-region (arg)
2619 "Execute command on a region."
2620 (interactive "P")
2621 (let ((val (viper-P-val arg))
2622 (com (viper-getcom arg)))
2623 (viper-move-marker-locally 'viper-com-point (point))
2624 (exchange-point-and-mark)
2625 (viper-execute-com 'viper-region val com)))
2627 (defun viper-Region (arg)
2628 "Execute command on a Region."
2629 (interactive "P")
2630 (let ((val (viper-P-val arg))
2631 (com (viper-getCom arg)))
2632 (viper-move-marker-locally 'viper-com-point (point))
2633 (exchange-point-and-mark)
2634 (viper-execute-com 'viper-Region val com)))
2636 (defun viper-replace-char (arg)
2637 "Replace the following ARG chars by the character read."
2638 (interactive "P")
2639 (if (and (eolp) (bolp)) (error "No character to replace here"))
2640 (let ((val (viper-p-val arg))
2641 (com (viper-getcom arg)))
2642 (viper-replace-char-subr com val)
2643 (if (and (eolp) (not (bolp))) (forward-char 1))
2644 (setq viper-this-command-keys
2645 (format "%sr" (if (integerp arg) arg "")))
2646 (viper-set-destructive-command
2647 (list 'viper-replace-char val ?r nil viper-d-char nil))
2650 (defun viper-replace-char-subr (com arg)
2651 (let ((inhibit-quit t)
2652 char)
2653 (viper-set-complex-command-for-undo)
2654 (or (eq viper-intermediate-command 'viper-repeat)
2655 (viper-special-read-and-insert-char))
2657 (delete-char 1 t)
2658 (setq char (if com viper-d-char (viper-char-at-pos 'backward)))
2660 (if com (insert char))
2662 (setq viper-d-char char)
2664 (viper-loop (1- (if (> arg 0) arg (- arg)))
2665 (delete-char 1 t)
2666 (insert char))
2668 (viper-adjust-undo)
2669 (backward-char arg)
2673 ;; basic cursor movement. j, k, l, h commands.
2675 (defun viper-forward-char (arg)
2676 "Move point right ARG characters (left if ARG negative).
2677 On reaching end of line, stop and signal error."
2678 (interactive "P")
2679 (viper-leave-region-active)
2680 (let ((val (viper-p-val arg))
2681 (com (viper-getcom arg)))
2682 (if com (viper-move-marker-locally 'viper-com-point (point)))
2683 (if viper-ex-style-motion
2684 (progn
2685 ;; the boundary condition check gets weird here because
2686 ;; forward-char may be the parameter of a delete, and 'dl' works
2687 ;; just like 'x' for the last char on a line, so we have to allow
2688 ;; the forward motion before the 'viper-execute-com', but, of
2689 ;; course, 'dl' doesn't work on an empty line, so we have to
2690 ;; catch that condition before 'viper-execute-com'
2691 (if (and (eolp) (bolp)) (error "") (forward-char val))
2692 (if com (viper-execute-com 'viper-forward-char val com))
2693 (if (eolp) (progn (backward-char 1) (error ""))))
2694 (forward-char val)
2695 (if com (viper-execute-com 'viper-forward-char val com)))))
2698 (defun viper-backward-char (arg)
2699 "Move point left ARG characters (right if ARG negative).
2700 On reaching beginning of line, stop and signal error."
2701 (interactive "P")
2702 (viper-leave-region-active)
2703 (let ((val (viper-p-val arg))
2704 (com (viper-getcom arg)))
2705 (if com (viper-move-marker-locally 'viper-com-point (point)))
2706 (if viper-ex-style-motion
2707 (progn
2708 (if (bolp) (error "") (backward-char val))
2709 (if com (viper-execute-com 'viper-backward-char val com)))
2710 (backward-char val)
2711 (if com (viper-execute-com 'viper-backward-char val com)))))
2714 ;; Like forward-char, but doesn't move at end of buffer.
2715 ;; Returns distance traveled
2716 ;; (positive or 0, if arg positive; negative if arg negative).
2717 (defun viper-forward-char-carefully (&optional arg)
2718 (setq arg (or arg 1))
2719 (let ((pt (point)))
2720 (condition-case nil
2721 (forward-char arg)
2722 (error nil))
2723 (if (< (point) pt) ; arg was negative
2724 (- (viper-chars-in-region pt (point)))
2725 (viper-chars-in-region pt (point)))))
2728 ;; Like backward-char, but doesn't move at beg of buffer.
2729 ;; Returns distance traveled
2730 ;; (negative or 0, if arg positive; positive if arg negative).
2731 (defun viper-backward-char-carefully (&optional arg)
2732 (setq arg (or arg 1))
2733 (let ((pt (point)))
2734 (condition-case nil
2735 (backward-char arg)
2736 (error nil))
2737 (if (> (point) pt) ; arg was negative
2738 (viper-chars-in-region pt (point))
2739 (- (viper-chars-in-region pt (point))))))
2741 (defun viper-next-line-carefully (arg)
2742 (condition-case nil
2743 (next-line arg)
2744 (error nil)))
2748 ;;; Word command
2750 ;; Words are formed from alpha's and nonalphas - <sp>,\t\n are separators for
2751 ;; word movement. When executed with a destructive command, \n is usually left
2752 ;; untouched for the last word. Viper uses syntax table to determine what is a
2753 ;; word and what is a separator. However, \n is always a separator. Also, if
2754 ;; viper-syntax-preference is 'vi, then `_' is part of the word.
2756 ;; skip only one \n
2757 (defun viper-skip-separators (forward)
2758 (if forward
2759 (progn
2760 (viper-skip-all-separators-forward 'within-line)
2761 (if (looking-at "\n")
2762 (progn
2763 (forward-char)
2764 (viper-skip-all-separators-forward 'within-line))))
2765 ;; check for eob and white space before it. move off of eob
2766 (if (and (eobp) (save-excursion
2767 (viper-backward-char-carefully)
2768 (viper-looking-at-separator)))
2769 (viper-backward-char-carefully))
2770 (viper-skip-all-separators-backward 'within-line)
2771 (viper-backward-char-carefully)
2772 (if (looking-at "\n")
2773 (viper-skip-all-separators-backward 'within-line)
2774 (or (viper-looking-at-separator) (forward-char)))))
2777 (defun viper-forward-word-kernel (val)
2778 (while (> val 0)
2779 (cond ((viper-looking-at-alpha)
2780 (viper-skip-alpha-forward "_")
2781 (viper-skip-separators t))
2782 ((viper-looking-at-separator)
2783 (viper-skip-separators t))
2784 ((not (viper-looking-at-alphasep))
2785 (viper-skip-nonalphasep-forward)
2786 (viper-skip-separators t)))
2787 (setq val (1- val))))
2789 ;; first skip non-newline separators backward, then skip \n. Then, if TWICE is
2790 ;; non-nil, skip non-\n back again, but don't overshoot the limit LIM.
2791 (defun viper-separator-skipback-special (twice lim)
2792 (let ((prev-char (viper-char-at-pos 'backward))
2793 (saved-point (point)))
2794 ;; skip non-newline separators backward
2795 (while (and (not (viper-memq-char prev-char '(nil \n)))
2796 (< lim (point))
2797 ;; must be non-newline separator
2798 (if (eq viper-syntax-preference 'strict-vi)
2799 (viper-memq-char prev-char '(?\ ?\t))
2800 (viper-memq-char (char-syntax prev-char) '(?\ ?-))))
2801 (viper-backward-char-carefully)
2802 (setq prev-char (viper-char-at-pos 'backward)))
2804 (if (and (< lim (point)) (eq prev-char ?\n))
2805 (backward-char)
2806 ;; If we skipped to the next word and the prefix of this line doesn't
2807 ;; consist of separators preceded by a newline, then don't skip backwards
2808 ;; at all.
2809 (goto-char saved-point))
2810 (setq prev-char (viper-char-at-pos 'backward))
2812 ;; skip again, but make sure we don't overshoot the limit
2813 (if twice
2814 (while (and (not (viper-memq-char prev-char '(nil \n)))
2815 (< lim (point))
2816 ;; must be non-newline separator
2817 (if (eq viper-syntax-preference 'strict-vi)
2818 (viper-memq-char prev-char '(?\ ?\t))
2819 (viper-memq-char (char-syntax prev-char) '(?\ ?-))))
2820 (viper-backward-char-carefully)
2821 (setq prev-char (viper-char-at-pos 'backward))))
2823 (if (= (point) lim)
2824 (viper-forward-char-carefully))
2828 (defun viper-forward-word (arg)
2829 "Forward word."
2830 (interactive "P")
2831 (viper-leave-region-active)
2832 (let ((val (viper-p-val arg))
2833 (com (viper-getcom arg)))
2834 (if com (viper-move-marker-locally 'viper-com-point (point)))
2835 (viper-forward-word-kernel val)
2836 (if com
2837 (progn
2838 (cond ((viper-char-equal com ?c)
2839 (viper-separator-skipback-special 'twice viper-com-point))
2840 ;; Yank words including the whitespace, but not newline
2841 ((viper-char-equal com ?y)
2842 (viper-separator-skipback-special nil viper-com-point))
2843 ((viper-dotable-command-p com)
2844 (viper-separator-skipback-special nil viper-com-point)))
2845 (viper-execute-com 'viper-forward-word val com)))
2849 (defun viper-forward-Word (arg)
2850 "Forward word delimited by white characters."
2851 (interactive "P")
2852 (viper-leave-region-active)
2853 (let ((val (viper-p-val arg))
2854 (com (viper-getcom arg)))
2855 (if com (viper-move-marker-locally 'viper-com-point (point)))
2856 (viper-loop val
2857 (viper-skip-nonseparators 'forward)
2858 (viper-skip-separators t))
2859 (if com (progn
2860 (cond ((viper-char-equal com ?c)
2861 (viper-separator-skipback-special 'twice viper-com-point))
2862 ;; Yank words including the whitespace, but not newline
2863 ((viper-char-equal com ?y)
2864 (viper-separator-skipback-special nil viper-com-point))
2865 ((viper-dotable-command-p com)
2866 (viper-separator-skipback-special nil viper-com-point)))
2867 (viper-execute-com 'viper-forward-Word val com)))))
2870 ;; this is a bit different from Vi, but Vi's end of word
2871 ;; makes no sense whatsoever
2872 (defun viper-end-of-word-kernel ()
2873 (if (viper-end-of-word-p) (forward-char))
2874 (if (viper-looking-at-separator)
2875 (viper-skip-all-separators-forward))
2877 (cond ((viper-looking-at-alpha) (viper-skip-alpha-forward "_"))
2878 ((not (viper-looking-at-alphasep)) (viper-skip-nonalphasep-forward)))
2879 (viper-backward-char-carefully))
2881 (defun viper-end-of-word-p ()
2882 (or (eobp)
2883 (save-excursion
2884 (cond ((viper-looking-at-alpha)
2885 (forward-char)
2886 (not (viper-looking-at-alpha)))
2887 ((not (viper-looking-at-alphasep))
2888 (forward-char)
2889 (viper-looking-at-alphasep))))))
2892 (defun viper-end-of-word (arg &optional careful)
2893 "Move point to end of current word."
2894 (interactive "P")
2895 (viper-leave-region-active)
2896 (let ((val (viper-p-val arg))
2897 (com (viper-getcom arg)))
2898 (if com (viper-move-marker-locally 'viper-com-point (point)))
2899 (viper-loop val (viper-end-of-word-kernel))
2900 (if com
2901 (progn
2902 (forward-char)
2903 (viper-execute-com 'viper-end-of-word val com)))))
2905 (defun viper-end-of-Word (arg)
2906 "Forward to end of word delimited by white character."
2907 (interactive "P")
2908 (viper-leave-region-active)
2909 (let ((val (viper-p-val arg))
2910 (com (viper-getcom arg)))
2911 (if com (viper-move-marker-locally 'viper-com-point (point)))
2912 (viper-loop val
2913 (viper-end-of-word-kernel)
2914 (viper-skip-nonseparators 'forward)
2915 (backward-char))
2916 (if com
2917 (progn
2918 (forward-char)
2919 (viper-execute-com 'viper-end-of-Word val com)))))
2921 (defun viper-backward-word-kernel (val)
2922 (while (> val 0)
2923 (viper-backward-char-carefully)
2924 (cond ((viper-looking-at-alpha)
2925 (viper-skip-alpha-backward "_"))
2926 ((viper-looking-at-separator)
2927 (forward-char)
2928 (viper-skip-separators nil)
2929 (viper-backward-char-carefully)
2930 (cond ((viper-looking-at-alpha)
2931 (viper-skip-alpha-backward "_"))
2932 ((not (viper-looking-at-alphasep))
2933 (viper-skip-nonalphasep-backward))
2934 ((bobp)) ; could still be at separator, but at beg of buffer
2935 (t (forward-char))))
2936 ((not (viper-looking-at-alphasep))
2937 (viper-skip-nonalphasep-backward)))
2938 (setq val (1- val))))
2940 (defun viper-backward-word (arg)
2941 "Backward word."
2942 (interactive "P")
2943 (viper-leave-region-active)
2944 (let ((val (viper-p-val arg))
2945 (com (viper-getcom arg)))
2946 (if com
2947 (let (i)
2948 (if (setq i (save-excursion (backward-char) (looking-at "\n")))
2949 (backward-char))
2950 (viper-move-marker-locally 'viper-com-point (point))
2951 (if i (forward-char))))
2952 (viper-backward-word-kernel val)
2953 (if com (viper-execute-com 'viper-backward-word val com))))
2955 (defun viper-backward-Word (arg)
2956 "Backward word delimited by white character."
2957 (interactive "P")
2958 (viper-leave-region-active)
2959 (let ((val (viper-p-val arg))
2960 (com (viper-getcom arg)))
2961 (if com
2962 (let (i)
2963 (if (setq i (save-excursion (backward-char) (looking-at "\n")))
2964 (backward-char))
2965 (viper-move-marker-locally 'viper-com-point (point))
2966 (if i (forward-char))))
2967 (viper-loop val
2968 (viper-skip-separators nil) ; nil means backward here
2969 (viper-skip-nonseparators 'backward))
2970 (if com (viper-execute-com 'viper-backward-Word val com))))
2974 ;; line commands
2976 (defun viper-beginning-of-line (arg)
2977 "Go to beginning of line."
2978 (interactive "P")
2979 (viper-leave-region-active)
2980 (let ((val (viper-p-val arg))
2981 (com (viper-getcom arg)))
2982 (if com (viper-move-marker-locally 'viper-com-point (point)))
2983 (beginning-of-line val)
2984 (if com (viper-execute-com 'viper-beginning-of-line val com))))
2986 (defun viper-bol-and-skip-white (arg)
2987 "Beginning of line at first non-white character."
2988 (interactive "P")
2989 (viper-leave-region-active)
2990 (let ((val (viper-p-val arg))
2991 (com (viper-getcom arg)))
2992 (if com (viper-move-marker-locally 'viper-com-point (point)))
2993 (forward-to-indentation (1- val))
2994 (if com (viper-execute-com 'viper-bol-and-skip-white val com))))
2996 (defun viper-goto-eol (arg)
2997 "Go to end of line."
2998 (interactive "P")
2999 (viper-leave-region-active)
3000 (let ((val (viper-p-val arg))
3001 (com (viper-getcom arg)))
3002 (if com (viper-move-marker-locally 'viper-com-point (point)))
3003 (end-of-line val)
3004 (if com (viper-execute-com 'viper-goto-eol val com))
3005 (if viper-ex-style-motion
3006 (if (and (eolp) (not (bolp))
3007 ;; a fix for viper-change-to-eol
3008 (not (equal viper-current-state 'insert-state)))
3009 (backward-char 1)
3010 ))))
3013 (defun viper-goto-col (arg)
3014 "Go to ARG's column."
3015 (interactive "P")
3016 (viper-leave-region-active)
3017 (let ((val (viper-p-val arg))
3018 (com (viper-getcom arg))
3019 line-len)
3020 (setq line-len
3021 (viper-chars-in-region
3022 (viper-line-pos 'start) (viper-line-pos 'end)))
3023 (if com (viper-move-marker-locally 'viper-com-point (point)))
3024 (beginning-of-line)
3025 (forward-char (1- (min line-len val)))
3026 (while (> (current-column) (1- val))
3027 (backward-char 1))
3028 (if com (viper-execute-com 'viper-goto-col val com))
3029 (save-excursion
3030 (end-of-line)
3031 (if (> val (current-column)) (error "")))
3035 (defun viper-next-line (arg)
3036 "Go to next line."
3037 (interactive "P")
3038 (viper-leave-region-active)
3039 (let ((val (viper-p-val arg))
3040 (com (viper-getCom arg)))
3041 (if com (viper-move-marker-locally 'viper-com-point (point)))
3042 (next-line val)
3043 (if viper-ex-style-motion
3044 (if (and (eolp) (not (bolp))) (backward-char 1)))
3045 (setq this-command 'next-line)
3046 (if com (viper-execute-com 'viper-next-line val com))))
3048 (defun viper-next-line-at-bol (arg)
3049 "Next line at beginning of line."
3050 (interactive "P")
3051 (viper-leave-region-active)
3052 (save-excursion
3053 (end-of-line)
3054 (if (eobp) (error "Last line in buffer")))
3055 (let ((val (viper-p-val arg))
3056 (com (viper-getCom arg)))
3057 (if com (viper-move-marker-locally 'viper-com-point (point)))
3058 (forward-line val)
3059 (back-to-indentation)
3060 (if com (viper-execute-com 'viper-next-line-at-bol val com))))
3063 (defun viper-previous-line (arg)
3064 "Go to previous line."
3065 (interactive "P")
3066 (viper-leave-region-active)
3067 (let ((val (viper-p-val arg))
3068 (com (viper-getCom arg)))
3069 (if com (viper-move-marker-locally 'viper-com-point (point)))
3070 (previous-line val)
3071 (if viper-ex-style-motion
3072 (if (and (eolp) (not (bolp))) (backward-char 1)))
3073 (setq this-command 'previous-line)
3074 (if com (viper-execute-com 'viper-previous-line val com))))
3077 (defun viper-previous-line-at-bol (arg)
3078 "Previous line at beginning of line."
3079 (interactive "P")
3080 (viper-leave-region-active)
3081 (save-excursion
3082 (beginning-of-line)
3083 (if (bobp) (error "First line in buffer")))
3084 (let ((val (viper-p-val arg))
3085 (com (viper-getCom arg)))
3086 (if com (viper-move-marker-locally 'viper-com-point (point)))
3087 (forward-line (- val))
3088 (back-to-indentation)
3089 (if com (viper-execute-com 'viper-previous-line val com))))
3091 (defun viper-change-to-eol (arg)
3092 "Change to end of line."
3093 (interactive "P")
3094 (viper-goto-eol (cons arg ?c)))
3096 (defun viper-kill-line (arg)
3097 "Delete line."
3098 (interactive "P")
3099 (viper-goto-eol (cons arg ?d)))
3101 (defun viper-erase-line (arg)
3102 "Erase line."
3103 (interactive "P")
3104 (viper-beginning-of-line (cons arg ?d)))
3107 ;;; Moving around
3109 (defun viper-goto-line (arg)
3110 "Go to ARG's line. Without ARG go to end of buffer."
3111 (interactive "P")
3112 (let ((val (viper-P-val arg))
3113 (com (viper-getCom arg)))
3114 (viper-move-marker-locally 'viper-com-point (point))
3115 (viper-deactivate-mark)
3116 (push-mark nil t)
3117 (if (null val)
3118 (goto-char (point-max))
3119 (goto-char (point-min))
3120 (forward-line (1- val)))
3122 ;; positioning is done twice: before and after command execution
3123 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
3124 (back-to-indentation)
3126 (if com (viper-execute-com 'viper-goto-line val com))
3128 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
3129 (back-to-indentation)
3132 ;; Find ARG's occurrence of CHAR on the current line.
3133 ;; If FORWARD then search is forward, otherwise backward. OFFSET is used to
3134 ;; adjust point after search.
3135 (defun viper-find-char (arg char forward offset)
3136 (or (char-or-string-p char) (error ""))
3137 (let ((arg (if forward arg (- arg)))
3138 (cmd (if (eq viper-intermediate-command 'viper-repeat)
3139 (nth 5 viper-d-com)
3140 (viper-array-to-string (this-command-keys))))
3141 point region-beg region-end)
3142 (save-excursion
3143 (save-restriction
3144 (if (> arg 0) ; forward
3145 (progn
3146 (setq region-beg (point))
3147 (if viper-allow-multiline-replace-regions
3148 (viper-forward-paragraph 1)
3149 (end-of-line))
3150 (setq region-end (point)))
3151 (setq region-end (point))
3152 (if viper-allow-multiline-replace-regions
3153 (viper-backward-paragraph 1)
3154 (beginning-of-line))
3155 (setq region-beg (point)))
3156 (if (or (and (< arg 0)
3157 (< (- region-end region-beg)
3158 (if viper-allow-multiline-replace-regions
3159 2 1))
3160 (bolp))
3161 (and (> arg 0)
3162 (< (- region-end region-beg)
3163 (if viper-allow-multiline-replace-regions
3164 3 2))
3165 (eolp)))
3166 (error "Command `%s': At %s of %s"
3168 (if (> arg 0) "end" "beginning")
3169 (if viper-allow-multiline-replace-regions
3170 "paragraph" "line")))
3171 (narrow-to-region region-beg region-end)
3172 ;; if arg > 0, point is forwarded before search.
3173 (if (> arg 0) (goto-char (1+ (point-min)))
3174 (goto-char (point-max)))
3175 (if (let ((case-fold-search nil))
3176 (search-forward (char-to-string char) nil 0 arg))
3177 (setq point (point))
3178 (error "Command `%s': `%c' not found" cmd char))))
3179 (goto-char point)
3180 (if (> arg 0)
3181 (backward-char (if offset 2 1))
3182 (forward-char (if offset 1 0)))))
3184 (defun viper-find-char-forward (arg)
3185 "Find char on the line.
3186 If called interactively read the char to find from the terminal, and if
3187 called from viper-repeat, the char last used is used. This behavior is
3188 controlled by the sign of prefix numeric value."
3189 (interactive "P")
3190 (let ((val (viper-p-val arg))
3191 (com (viper-getcom arg))
3192 (cmd-representation (nth 5 viper-d-com)))
3193 (if (> val 0)
3194 ;; this means that the function was called interactively
3195 (setq viper-f-char (read-char)
3196 viper-f-forward t
3197 viper-f-offset nil)
3198 ;; viper-repeat --- set viper-F-char from command-keys
3199 (setq viper-F-char (if (stringp cmd-representation)
3200 (viper-seq-last-elt cmd-representation)
3201 viper-F-char)
3202 viper-f-char viper-F-char)
3203 (setq val (- val)))
3204 (if com (viper-move-marker-locally 'viper-com-point (point)))
3205 (viper-find-char
3206 val (if (> (viper-p-val arg) 0) viper-f-char viper-F-char) t nil)
3207 (setq val (- val))
3208 (if com
3209 (progn
3210 (setq viper-F-char viper-f-char) ; set new viper-F-char
3211 (forward-char)
3212 (viper-execute-com 'viper-find-char-forward val com)))))
3214 (defun viper-goto-char-forward (arg)
3215 "Go up to char ARG forward on line."
3216 (interactive "P")
3217 (let ((val (viper-p-val arg))
3218 (com (viper-getcom arg))
3219 (cmd-representation (nth 5 viper-d-com)))
3220 (if (> val 0)
3221 ;; this means that the function was called interactively
3222 (setq viper-f-char (read-char)
3223 viper-f-forward t
3224 viper-f-offset t)
3225 ;; viper-repeat --- set viper-F-char from command-keys
3226 (setq viper-F-char (if (stringp cmd-representation)
3227 (viper-seq-last-elt cmd-representation)
3228 viper-F-char)
3229 viper-f-char viper-F-char)
3230 (setq val (- val)))
3231 (if com (viper-move-marker-locally 'viper-com-point (point)))
3232 (viper-find-char
3233 val (if (> (viper-p-val arg) 0) viper-f-char viper-F-char) t t)
3234 (setq val (- val))
3235 (if com
3236 (progn
3237 (setq viper-F-char viper-f-char) ; set new viper-F-char
3238 (forward-char)
3239 (viper-execute-com 'viper-goto-char-forward val com)))))
3241 (defun viper-find-char-backward (arg)
3242 "Find char ARG on line backward."
3243 (interactive "P")
3244 (let ((val (viper-p-val arg))
3245 (com (viper-getcom arg))
3246 (cmd-representation (nth 5 viper-d-com)))
3247 (if (> val 0)
3248 ;; this means that the function was called interactively
3249 (setq viper-f-char (read-char)
3250 viper-f-forward nil
3251 viper-f-offset nil)
3252 ;; viper-repeat --- set viper-F-char from command-keys
3253 (setq viper-F-char (if (stringp cmd-representation)
3254 (viper-seq-last-elt cmd-representation)
3255 viper-F-char)
3256 viper-f-char viper-F-char)
3257 (setq val (- val)))
3258 (if com (viper-move-marker-locally 'viper-com-point (point)))
3259 (viper-find-char
3260 val (if (> (viper-p-val arg) 0) viper-f-char viper-F-char) nil nil)
3261 (setq val (- val))
3262 (if com
3263 (progn
3264 (setq viper-F-char viper-f-char) ; set new viper-F-char
3265 (viper-execute-com 'viper-find-char-backward val com)))))
3267 (defun viper-goto-char-backward (arg)
3268 "Go up to char ARG backward on line."
3269 (interactive "P")
3270 (let ((val (viper-p-val arg))
3271 (com (viper-getcom arg))
3272 (cmd-representation (nth 5 viper-d-com)))
3273 (if (> val 0)
3274 ;; this means that the function was called interactively
3275 (setq viper-f-char (read-char)
3276 viper-f-forward nil
3277 viper-f-offset t)
3278 ;; viper-repeat --- set viper-F-char from command-keys
3279 (setq viper-F-char (if (stringp cmd-representation)
3280 (viper-seq-last-elt cmd-representation)
3281 viper-F-char)
3282 viper-f-char viper-F-char)
3283 (setq val (- val)))
3284 (if com (viper-move-marker-locally 'viper-com-point (point)))
3285 (viper-find-char
3286 val (if (> (viper-p-val arg) 0) viper-f-char viper-F-char) nil t)
3287 (setq val (- val))
3288 (if com
3289 (progn
3290 (setq viper-F-char viper-f-char) ; set new viper-F-char
3291 (viper-execute-com 'viper-goto-char-backward val com)))))
3293 (defun viper-repeat-find (arg)
3294 "Repeat previous find command."
3295 (interactive "P")
3296 (let ((val (viper-p-val arg))
3297 (com (viper-getcom arg)))
3298 (viper-deactivate-mark)
3299 (if com (viper-move-marker-locally 'viper-com-point (point)))
3300 (viper-find-char val viper-f-char viper-f-forward viper-f-offset)
3301 (if com
3302 (progn
3303 (if viper-f-forward (forward-char))
3304 (viper-execute-com 'viper-repeat-find val com)))))
3306 (defun viper-repeat-find-opposite (arg)
3307 "Repeat previous find command in the opposite direction."
3308 (interactive "P")
3309 (let ((val (viper-p-val arg))
3310 (com (viper-getcom arg)))
3311 (viper-deactivate-mark)
3312 (if com (viper-move-marker-locally 'viper-com-point (point)))
3313 (viper-find-char val viper-f-char (not viper-f-forward) viper-f-offset)
3314 (if com
3315 (progn
3316 (if viper-f-forward (forward-char))
3317 (viper-execute-com 'viper-repeat-find-opposite val com)))))
3320 ;; window scrolling etc.
3322 (defun viper-window-top (arg)
3323 "Go to home window line."
3324 (interactive "P")
3325 (let ((val (viper-p-val arg))
3326 (com (viper-getCom arg)))
3327 (viper-leave-region-active)
3328 (if com (viper-move-marker-locally 'viper-com-point (point)))
3329 (push-mark nil t)
3330 (move-to-window-line (1- val))
3332 ;; positioning is done twice: before and after command execution
3333 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
3334 (back-to-indentation)
3336 (if com (viper-execute-com 'viper-window-top val com))
3338 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
3339 (back-to-indentation)
3342 (defun viper-window-middle (arg)
3343 "Go to middle window line."
3344 (interactive "P")
3345 (let ((val (viper-p-val arg))
3346 (com (viper-getCom arg)))
3347 (viper-leave-region-active)
3348 (if com (viper-move-marker-locally 'viper-com-point (point)))
3349 (push-mark nil t)
3350 (move-to-window-line (+ (/ (1- (window-height)) 2) (1- val)))
3352 ;; positioning is done twice: before and after command execution
3353 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
3354 (back-to-indentation)
3356 (if com (viper-execute-com 'viper-window-middle val com))
3358 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
3359 (back-to-indentation)
3362 (defun viper-window-bottom (arg)
3363 "Go to last window line."
3364 (interactive "P")
3365 (let ((val (viper-p-val arg))
3366 (com (viper-getCom arg)))
3367 (viper-leave-region-active)
3368 (if com (viper-move-marker-locally 'viper-com-point (point)))
3369 (push-mark nil t)
3370 (move-to-window-line (- val))
3372 ;; positioning is done twice: before and after command execution
3373 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
3374 (back-to-indentation)
3376 (if com (viper-execute-com 'viper-window-bottom val com))
3378 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
3379 (back-to-indentation)
3382 (defun viper-line-to-top (arg)
3383 "Put current line on the home line."
3384 (interactive "p")
3385 (recenter (1- arg)))
3387 (defun viper-line-to-middle (arg)
3388 "Put current line on the middle line."
3389 (interactive "p")
3390 (recenter (+ (1- arg) (/ (1- (window-height)) 2))))
3392 (defun viper-line-to-bottom (arg)
3393 "Put current line on the last line."
3394 (interactive "p")
3395 (recenter (- (window-height) (1+ arg))))
3397 ;; If point is within viper-search-scroll-threshold of window top or bottom,
3398 ;; scroll up or down 1/7 of window height, depending on whether we are at the
3399 ;; bottom or at the top of the window. This function is called by viper-search
3400 ;; (which is called from viper-search-forward/backward/next). If the value of
3401 ;; viper-search-scroll-threshold is negative - don't scroll.
3402 (defun viper-adjust-window ()
3403 (let ((win-height (viper-cond-compile-for-xemacs-or-emacs
3404 (window-displayed-height) ; xemacs
3405 ;; emacs
3406 (1- (window-height)) ; adjust for modeline
3408 (pt (point))
3409 at-top-p at-bottom-p
3410 min-scroll direction)
3411 (save-excursion
3412 (move-to-window-line 0) ; top
3413 (setq at-top-p
3414 (<= (count-lines pt (point))
3415 viper-search-scroll-threshold))
3416 (move-to-window-line -1) ; bottom
3417 (setq at-bottom-p
3418 (<= (count-lines pt (point)) viper-search-scroll-threshold))
3420 (cond (at-top-p (setq min-scroll (1- viper-search-scroll-threshold)
3421 direction 1))
3422 (at-bottom-p (setq min-scroll (1+ viper-search-scroll-threshold)
3423 direction -1)))
3424 (if min-scroll
3425 (recenter
3426 (* (max min-scroll (/ win-height 7)) direction)))
3430 ;; paren match
3431 ;; must correct this to only match ( to ) etc. On the other hand
3432 ;; it is good that paren match gets confused, because that way you
3433 ;; catch _all_ imbalances.
3435 (defun viper-paren-match (arg)
3436 "Go to the matching parenthesis."
3437 (interactive "P")
3438 (viper-leave-region-active)
3439 (let ((com (viper-getcom arg))
3440 (parse-sexp-ignore-comments viper-parse-sexp-ignore-comments)
3441 anchor-point)
3442 (if (integerp arg)
3443 (if (or (> arg 99) (< arg 1))
3444 (error "Prefix must be between 1 and 99")
3445 (goto-char
3446 (if (> (point-max) 80000)
3447 (* (/ (point-max) 100) arg)
3448 (/ (* (point-max) arg) 100)))
3449 (back-to-indentation))
3450 (let (beg-lim end-lim)
3451 (if (and (eolp) (not (bolp))) (forward-char -1))
3452 (if (not (looking-at "[][(){}]"))
3453 (setq anchor-point (point)))
3454 (save-excursion
3455 (beginning-of-line)
3456 (setq beg-lim (point))
3457 (end-of-line)
3458 (setq end-lim (point)))
3459 (cond ((re-search-forward "[][(){}]" end-lim t)
3460 (backward-char) )
3461 ((re-search-backward "[][(){}]" beg-lim t))
3463 (error "No matching character on line"))))
3464 (cond ((looking-at "[\(\[{]")
3465 (if com (viper-move-marker-locally 'viper-com-point (point)))
3466 (forward-sexp 1)
3467 (if com
3468 (viper-execute-com 'viper-paren-match nil com)
3469 (backward-char)))
3470 (anchor-point
3471 (if com
3472 (progn
3473 (viper-move-marker-locally 'viper-com-point anchor-point)
3474 (forward-char 1)
3475 (viper-execute-com 'viper-paren-match nil com)
3477 ((looking-at "[])}]")
3478 (forward-char)
3479 (if com (viper-move-marker-locally 'viper-com-point (point)))
3480 (backward-sexp 1)
3481 (if com (viper-execute-com 'viper-paren-match nil com)))
3482 (t (error ""))))))
3484 (defun viper-toggle-parse-sexp-ignore-comments ()
3485 (interactive)
3486 (setq viper-parse-sexp-ignore-comments
3487 (not viper-parse-sexp-ignore-comments))
3488 (princ (format
3489 "From now on, `%%' will %signore parentheses inside comment fields"
3490 (if viper-parse-sexp-ignore-comments "" "NOT "))))
3493 ;; sentence, paragraph and heading
3495 (defun viper-forward-sentence (arg)
3496 "Forward sentence."
3497 (interactive "P")
3498 (or (eq last-command this-command)
3499 (push-mark nil t))
3500 (let ((val (viper-p-val arg))
3501 (com (viper-getcom arg)))
3502 (if com (viper-move-marker-locally 'viper-com-point (point)))
3503 (forward-sentence val)
3504 (if com (viper-execute-com 'viper-forward-sentence nil com))))
3506 (defun viper-backward-sentence (arg)
3507 "Backward sentence."
3508 (interactive "P")
3509 (or (eq last-command this-command)
3510 (push-mark nil t))
3511 (let ((val (viper-p-val arg))
3512 (com (viper-getcom arg)))
3513 (if com (viper-move-marker-locally 'viper-com-point (point)))
3514 (backward-sentence val)
3515 (if com (viper-execute-com 'viper-backward-sentence nil com))))
3517 (defun viper-forward-paragraph (arg)
3518 "Forward paragraph."
3519 (interactive "P")
3520 (or (eq last-command this-command)
3521 (push-mark nil t))
3522 (let ((val (viper-p-val arg))
3523 ;; if you want d} operate on whole lines, change viper-getcom to
3524 ;; viper-getCom below
3525 (com (viper-getcom arg)))
3526 (if com (viper-move-marker-locally 'viper-com-point (point)))
3527 (forward-paragraph val)
3528 (if com
3529 (progn
3530 (backward-char 1)
3531 (viper-execute-com 'viper-forward-paragraph nil com)))))
3533 (defun viper-backward-paragraph (arg)
3534 "Backward paragraph."
3535 (interactive "P")
3536 (or (eq last-command this-command)
3537 (push-mark nil t))
3538 (let ((val (viper-p-val arg))
3539 ;; if you want d{ operate on whole lines, change viper-getcom to
3540 ;; viper-getCom below
3541 (com (viper-getcom arg)))
3542 (if com (viper-move-marker-locally 'viper-com-point (point)))
3543 (backward-paragraph val)
3544 (if com
3545 (progn
3546 (forward-char 1)
3547 (viper-execute-com 'viper-backward-paragraph nil com)
3548 (backward-char 1)))))
3550 ;; should be mode-specific
3551 (defun viper-prev-heading (arg)
3552 (interactive "P")
3553 (let ((val (viper-p-val arg))
3554 (com (viper-getCom arg)))
3555 (if com (viper-move-marker-locally 'viper-com-point (point)))
3556 (re-search-backward viper-heading-start nil t val)
3557 (goto-char (match-beginning 0))
3558 (if com (viper-execute-com 'viper-prev-heading nil com))))
3560 (defun viper-heading-end (arg)
3561 (interactive "P")
3562 (let ((val (viper-p-val arg))
3563 (com (viper-getCom arg)))
3564 (if com (viper-move-marker-locally 'viper-com-point (point)))
3565 (re-search-forward viper-heading-end nil t val)
3566 (goto-char (match-beginning 0))
3567 (if com (viper-execute-com 'viper-heading-end nil com))))
3569 (defun viper-next-heading (arg)
3570 (interactive "P")
3571 (let ((val (viper-p-val arg))
3572 (com (viper-getCom arg)))
3573 (if com (viper-move-marker-locally 'viper-com-point (point)))
3574 (end-of-line)
3575 (re-search-forward viper-heading-start nil t val)
3576 (goto-char (match-beginning 0))
3577 (if com (viper-execute-com 'viper-next-heading nil com))))
3580 ;; scrolling
3582 (defun viper-scroll-screen (arg)
3583 "Scroll to next screen."
3584 (interactive "p")
3585 (condition-case nil
3586 (if (> arg 0)
3587 (while (> arg 0)
3588 (scroll-up)
3589 (setq arg (1- arg)))
3590 (while (> 0 arg)
3591 (scroll-down)
3592 (setq arg (1+ arg))))
3593 (error (beep 1)
3594 (if (> arg 0)
3595 (progn
3596 (message "End of buffer")
3597 (goto-char (point-max)))
3598 (message "Beginning of buffer")
3599 (goto-char (point-min))))
3602 (defun viper-scroll-screen-back (arg)
3603 "Scroll to previous screen."
3604 (interactive "p")
3605 (viper-scroll-screen (- arg)))
3607 (defun viper-scroll-down (arg)
3608 "Pull down half screen."
3609 (interactive "P")
3610 (condition-case nil
3611 (if (null arg)
3612 (scroll-down (/ (window-height) 2))
3613 (scroll-down arg))
3614 (error (beep 1)
3615 (message "Beginning of buffer")
3616 (goto-char (point-min)))))
3618 (defun viper-scroll-down-one (arg)
3619 "Scroll up one line."
3620 (interactive "p")
3621 (scroll-down arg))
3623 (defun viper-scroll-up (arg)
3624 "Pull up half screen."
3625 (interactive "P")
3626 (condition-case nil
3627 (if (null arg)
3628 (scroll-up (/ (window-height) 2))
3629 (scroll-up arg))
3630 (error (beep 1)
3631 (message "End of buffer")
3632 (goto-char (point-max)))))
3634 (defun viper-scroll-up-one (arg)
3635 "Scroll down one line."
3636 (interactive "p")
3637 (scroll-up arg))
3640 ;; searching
3642 (defun viper-if-string (prompt)
3643 (if (memq viper-intermediate-command
3644 '(viper-command-argument viper-digit-argument viper-repeat))
3645 (setq viper-this-command-keys (this-command-keys)))
3646 (let ((s (viper-read-string-with-history
3647 prompt
3648 nil ; no initial
3649 'viper-search-history
3650 (car viper-search-history))))
3651 (if (not (string= s ""))
3652 (setq viper-s-string s))))
3655 (defun viper-toggle-search-style (arg)
3656 "Toggle the value of viper-case-fold-search/viper-re-search.
3657 Without prefix argument, will ask which search style to toggle. With prefix
3658 arg 1,toggles viper-case-fold-search; with arg 2 toggles viper-re-search.
3660 Although this function is bound to \\[viper-toggle-search-style], the most
3661 convenient way to use it is to bind `//' to the macro
3662 `1 M-x viper-toggle-search-style' and `///' to
3663 `2 M-x viper-toggle-search-style'. In this way, hitting `//' quickly will
3664 toggle case-fold-search and hitting `/' three times witth toggle regexp
3665 search. Macros are more convenient in this case because they don't affect
3666 the Emacs binding of `/'."
3667 (interactive "P")
3668 (let (msg)
3669 (cond ((or (eq arg 1)
3670 (and (null arg)
3671 (y-or-n-p (format "Search style: '%s'. Want '%s'? "
3672 (if viper-case-fold-search
3673 "case-insensitive" "case-sensitive")
3674 (if viper-case-fold-search
3675 "case-sensitive"
3676 "case-insensitive")))))
3677 (setq viper-case-fold-search (null viper-case-fold-search))
3678 (if viper-case-fold-search
3679 (setq msg "Search becomes case-insensitive")
3680 (setq msg "Search becomes case-sensitive")))
3681 ((or (eq arg 2)
3682 (and (null arg)
3683 (y-or-n-p (format "Search style: '%s'. Want '%s'? "
3684 (if viper-re-search
3685 "regexp-search" "vanilla-search")
3686 (if viper-re-search
3687 "vanilla-search"
3688 "regexp-search")))))
3689 (setq viper-re-search (null viper-re-search))
3690 (if viper-re-search
3691 (setq msg "Search becomes regexp-style")
3692 (setq msg "Search becomes vanilla-style")))
3694 (setq msg "Search style remains unchanged")))
3695 (princ msg t)))
3697 (defun viper-set-searchstyle-toggling-macros (unset &optional major-mode)
3698 "Set the macros for toggling the search style in Viper's vi-state.
3699 The macro that toggles case sensitivity is bound to `//', and the one that
3700 toggles regexp search is bound to `///'.
3701 With a prefix argument, this function unsets the macros.
3702 If MAJOR-MODE is set, set the macros only in that major mode."
3703 (interactive "P")
3704 (let (scope)
3705 (if (and major-mode (symbolp major-mode))
3706 (setq scope major-mode)
3707 (setq scope 't))
3708 (or noninteractive
3709 (if (not unset)
3710 (progn
3711 ;; toggle case sensitivity in search
3712 (viper-record-kbd-macro
3713 "//" 'vi-state
3714 [1 (meta x) v i p e r - t o g g l e - s e a r c h - s t y l e return]
3715 scope)
3716 ;; toggle regexp/vanila search
3717 (viper-record-kbd-macro
3718 "///" 'vi-state
3719 [2 (meta x) v i p e r - t o g g l e - s e a r c h - s t y l e return]
3720 scope)
3721 (if (interactive-p)
3722 (message
3723 "// and /// now toggle case-sensitivity and regexp search")))
3724 (viper-unrecord-kbd-macro "//" 'vi-state)
3725 (sit-for 2)
3726 (viper-unrecord-kbd-macro "///" 'vi-state)))
3730 (defun viper-set-parsing-style-toggling-macro (unset)
3731 "Set `%%%' to be a macro that toggles whether comment fields should be parsed for matching parentheses.
3732 This is used in conjunction with the `%' command.
3734 With a prefix argument, unsets the macro."
3735 (interactive "P")
3736 (or noninteractive
3737 (if (not unset)
3738 (progn
3739 ;; Make %%% toggle parsing comments for matching parentheses
3740 (viper-record-kbd-macro
3741 "%%%" 'vi-state
3742 [(meta x) v i p e r - t o g g l e - p a r s e - s e x p - i g n o r e - c o m m e n t s return]
3744 (if (interactive-p)
3745 (message
3746 "%%%%%% now toggles whether comments should be parsed for matching parentheses")))
3747 (viper-unrecord-kbd-macro "%%%" 'vi-state))))
3750 (defun viper-set-emacs-state-searchstyle-macros (unset &optional arg-majormode)
3751 "Set the macros for toggling the search style in Viper's emacs-state.
3752 The macro that toggles case sensitivity is bound to `//', and the one that
3753 toggles regexp search is bound to `///'.
3754 With a prefix argument, this function unsets the macros.
3755 If the optional prefix argument is non-nil and specifies a valid major mode,
3756 this sets the macros only in the macros in that major mode. Otherwise,
3757 the macros are set in the current major mode.
3758 \(When unsetting the macros, the second argument has no effect.\)"
3759 (interactive "P")
3760 (or noninteractive
3761 (if (not unset)
3762 (progn
3763 ;; toggle case sensitivity in search
3764 (viper-record-kbd-macro
3765 "//" 'emacs-state
3766 [1 (meta x) v i p e r - t o g g l e - s e a r c h - s t y l e return]
3767 (or arg-majormode major-mode))
3768 ;; toggle regexp/vanila search
3769 (viper-record-kbd-macro
3770 "///" 'emacs-state
3771 [2 (meta x) v i p e r - t o g g l e - s e a r c h - s t y l e return]
3772 (or arg-majormode major-mode))
3773 (if (interactive-p)
3774 (message
3775 "// and /// now toggle case-sensitivity and regexp search.")))
3776 (viper-unrecord-kbd-macro "//" 'emacs-state)
3777 (sit-for 2)
3778 (viper-unrecord-kbd-macro "///" 'emacs-state))))
3781 (defun viper-search-forward (arg)
3782 "Search a string forward.
3783 ARG is used to find the ARG's occurrence of the string.
3784 Null string will repeat previous search."
3785 (interactive "P")
3786 (let ((val (viper-P-val arg))
3787 (com (viper-getcom arg))
3788 (old-str viper-s-string)
3789 debug-on-error)
3790 (setq viper-s-forward t)
3791 (viper-if-string "/")
3792 ;; this is not used at present, but may be used later
3793 (if (or (not (equal old-str viper-s-string))
3794 (not (markerp viper-local-search-start-marker))
3795 (not (marker-buffer viper-local-search-start-marker)))
3796 (setq viper-local-search-start-marker (point-marker)))
3797 (viper-search viper-s-string t val)
3798 (if com
3799 (progn
3800 (viper-move-marker-locally 'viper-com-point (mark t))
3801 (viper-execute-com 'viper-search-next val com)))
3804 (defun viper-search-backward (arg)
3805 "Search a string backward.
3806 ARG is used to find the ARG's occurrence of the string.
3807 Null string will repeat previous search."
3808 (interactive "P")
3809 (let ((val (viper-P-val arg))
3810 (com (viper-getcom arg))
3811 (old-str viper-s-string)
3812 debug-on-error)
3813 (setq viper-s-forward nil)
3814 (viper-if-string "?")
3815 ;; this is not used at present, but may be used later
3816 (if (or (not (equal old-str viper-s-string))
3817 (not (markerp viper-local-search-start-marker))
3818 (not (marker-buffer viper-local-search-start-marker)))
3819 (setq viper-local-search-start-marker (point-marker)))
3820 (viper-search viper-s-string nil val)
3821 (if com
3822 (progn
3823 (viper-move-marker-locally 'viper-com-point (mark t))
3824 (viper-execute-com 'viper-search-next val com)))))
3827 ;; Search for COUNT's occurrence of STRING.
3828 ;; Search is forward if FORWARD is non-nil, otherwise backward.
3829 ;; INIT-POINT is the position where search is to start.
3830 ;; Arguments:
3831 ;; (STRING FORW COUNT &optional NO-OFFSET INIT-POINT LIMIT FAIL-IF-NOT-FOUND)
3832 (defun viper-search (string forward arg
3833 &optional no-offset init-point fail-if-not-found)
3834 (if (not (equal string ""))
3835 (let ((val (viper-p-val arg))
3836 (com (viper-getcom arg))
3837 (offset (not no-offset))
3838 (case-fold-search viper-case-fold-search)
3839 (start-point (or init-point (point))))
3840 (viper-deactivate-mark)
3841 (if forward
3842 (condition-case nil
3843 (progn
3844 (if offset (viper-forward-char-carefully))
3845 (if viper-re-search
3846 (progn
3847 (re-search-forward string nil nil val)
3848 (re-search-backward string))
3849 (search-forward string nil nil val)
3850 (search-backward string))
3851 (if (not (equal start-point (point)))
3852 (push-mark start-point t)))
3853 (search-failed
3854 (if (and (not fail-if-not-found) viper-search-wrap-around-t)
3855 (progn
3856 (message "Search wrapped around BOTTOM of buffer")
3857 (goto-char (point-min))
3858 (viper-search string forward (cons 1 com) t start-point 'fail)
3859 ;; don't wait in macros
3860 (or executing-kbd-macro
3861 (memq viper-intermediate-command
3862 '(viper-repeat
3863 viper-digit-argument
3864 viper-command-argument))
3865 (sit-for 2))
3866 ;; delete the wrap-around message
3867 (message "")
3869 (goto-char start-point)
3870 (error "`%s': %s not found"
3871 string
3872 (if viper-re-search "Pattern" "String"))
3874 ;; backward
3875 (condition-case nil
3876 (progn
3877 (if viper-re-search
3878 (re-search-backward string nil nil val)
3879 (search-backward string nil nil val))
3880 (if (not (equal start-point (point)))
3881 (push-mark start-point t)))
3882 (search-failed
3883 (if (and (not fail-if-not-found) viper-search-wrap-around-t)
3884 (progn
3885 (message "Search wrapped around TOP of buffer")
3886 (goto-char (point-max))
3887 (viper-search string forward (cons 1 com) t start-point 'fail)
3888 ;; don't wait in macros
3889 (or executing-kbd-macro
3890 (memq viper-intermediate-command
3891 '(viper-repeat
3892 viper-digit-argument
3893 viper-command-argument))
3894 (sit-for 2))
3895 ;; delete the wrap-around message
3896 (message "")
3898 (goto-char start-point)
3899 (error "`%s': %s not found"
3900 string
3901 (if viper-re-search "Pattern" "String"))
3902 ))))
3903 ;; pull up or down if at top/bottom of window
3904 (viper-adjust-window)
3905 ;; highlight the result of search
3906 ;; don't wait and don't highlight in macros
3907 (or executing-kbd-macro
3908 (memq viper-intermediate-command
3909 '(viper-repeat viper-digit-argument viper-command-argument))
3910 (viper-flash-search-pattern))
3913 (defun viper-search-next (arg)
3914 "Repeat previous search."
3915 (interactive "P")
3916 (let ((val (viper-p-val arg))
3917 (com (viper-getcom arg))
3918 debug-on-error)
3919 (if (null viper-s-string) (error viper-NoPrevSearch))
3920 (viper-search viper-s-string viper-s-forward arg)
3921 (if com
3922 (progn
3923 (viper-move-marker-locally 'viper-com-point (mark t))
3924 (viper-execute-com 'viper-search-next val com)))))
3926 (defun viper-search-Next (arg)
3927 "Repeat previous search in the reverse direction."
3928 (interactive "P")
3929 (let ((val (viper-p-val arg))
3930 (com (viper-getcom arg))
3931 debug-on-error)
3932 (if (null viper-s-string) (error viper-NoPrevSearch))
3933 (viper-search viper-s-string (not viper-s-forward) arg)
3934 (if com
3935 (progn
3936 (viper-move-marker-locally 'viper-com-point (mark t))
3937 (viper-execute-com 'viper-search-Next val com)))))
3940 ;; Search contents of buffer defined by one of Viper's motion commands.
3941 ;; Repeatable via `n' and `N'.
3942 (defun viper-buffer-search-enable (&optional c)
3943 (cond (c (setq viper-buffer-search-char c))
3944 ((null viper-buffer-search-char)
3945 (setq viper-buffer-search-char ?g)))
3946 (define-key viper-vi-basic-map
3947 (cond ((viper-characterp viper-buffer-search-char)
3948 (char-to-string viper-buffer-search-char))
3949 (t (error "viper-buffer-search-char: wrong value type, %S"
3950 viper-buffer-search-char)))
3951 'viper-command-argument)
3952 (aset viper-exec-array viper-buffer-search-char 'viper-exec-buffer-search)
3953 (setq viper-prefix-commands
3954 (cons viper-buffer-search-char viper-prefix-commands)))
3956 ;; This is a Viper wraper for isearch-forward.
3957 (defun viper-isearch-forward (arg)
3958 "Do incremental search forward."
3959 (interactive "P")
3960 ;; emacs bug workaround
3961 (if (listp arg) (setq arg (car arg)))
3962 (viper-exec-form-in-emacs (list 'isearch-forward arg)))
3964 ;; This is a Viper wraper for isearch-backward."
3965 (defun viper-isearch-backward (arg)
3966 "Do incremental search backward."
3967 (interactive "P")
3968 ;; emacs bug workaround
3969 (if (listp arg) (setq arg (car arg)))
3970 (viper-exec-form-in-emacs (list 'isearch-backward arg)))
3973 ;; visiting and killing files, buffers
3975 (defun viper-switch-to-buffer ()
3976 "Switch to buffer in the current window."
3977 (interactive)
3978 (let ((other-buffer (other-buffer (current-buffer)))
3979 buffer)
3980 (setq buffer
3981 (funcall viper-read-buffer-function
3982 "Switch to buffer in this window: " other-buffer))
3983 (switch-to-buffer buffer)))
3985 (defun viper-switch-to-buffer-other-window ()
3986 "Switch to buffer in another window."
3987 (interactive)
3988 (let ((other-buffer (other-buffer (current-buffer)))
3989 buffer)
3990 (setq buffer
3991 (funcall viper-read-buffer-function
3992 "Switch to buffer in another window: " other-buffer))
3993 (switch-to-buffer-other-window buffer)))
3995 (defun viper-kill-buffer ()
3996 "Kill a buffer."
3997 (interactive)
3998 (let (buffer buffer-name)
3999 (setq buffer-name
4000 (funcall viper-read-buffer-function
4001 (format "Kill buffer \(%s\): "
4002 (buffer-name (current-buffer)))))
4003 (setq buffer
4004 (if (null buffer-name)
4005 (current-buffer)
4006 (get-buffer buffer-name)))
4007 (if (null buffer) (error "`%s': No such buffer" buffer-name))
4008 (if (or (not (buffer-modified-p buffer))
4009 (y-or-n-p
4010 (format
4011 "Buffer `%s' is modified, are you sure you want to kill it? "
4012 buffer-name)))
4013 (kill-buffer buffer)
4014 (error "Buffer not killed"))))
4018 ;; yank and pop
4020 (defsubst viper-yank (text)
4021 "Yank TEXT silently. This works correctly with Emacs's yank-pop command."
4022 (insert text)
4023 (setq this-command 'yank))
4025 (defun viper-put-back (arg)
4026 "Put back after point/below line."
4027 (interactive "P")
4028 (let ((val (viper-p-val arg))
4029 (text (if viper-use-register
4030 (cond ((viper-valid-register viper-use-register '(digit))
4031 (current-kill
4032 (- viper-use-register ?1) 'do-not-rotate))
4033 ((viper-valid-register viper-use-register)
4034 (get-register (downcase viper-use-register)))
4035 (t (error viper-InvalidRegister viper-use-register)))
4036 (current-kill 0)))
4037 sv-point chars-inserted lines-inserted)
4038 (if (null text)
4039 (if viper-use-register
4040 (let ((reg viper-use-register))
4041 (setq viper-use-register nil)
4042 (error viper-EmptyRegister reg))
4043 (error "")))
4044 (setq viper-use-register nil)
4045 (if (viper-end-with-a-newline-p text)
4046 (progn
4047 (end-of-line)
4048 (if (eobp)
4049 (insert "\n")
4050 (forward-line 1))
4051 (beginning-of-line))
4052 (if (not (eolp)) (viper-forward-char-carefully)))
4053 (set-marker (viper-mark-marker) (point) (current-buffer))
4054 (viper-set-destructive-command
4055 (list 'viper-put-back val nil viper-use-register nil nil))
4056 (setq sv-point (point))
4057 (viper-loop val (viper-yank text))
4058 (setq chars-inserted (abs (- (point) sv-point))
4059 lines-inserted (abs (count-lines (point) sv-point)))
4060 (if (or (> chars-inserted viper-change-notification-threshold)
4061 (> lines-inserted viper-change-notification-threshold))
4062 (unless (viper-is-in-minibuffer)
4063 (message "Inserted %d character(s), %d line(s)"
4064 chars-inserted lines-inserted))))
4065 ;; Vi puts cursor on the last char when the yanked text doesn't contain a
4066 ;; newline; it leaves the cursor at the beginning when the text contains
4067 ;; a newline
4068 (if (viper-same-line (point) (mark))
4069 (or (= (point) (mark)) (viper-backward-char-carefully))
4070 (exchange-point-and-mark)
4071 (if (bolp)
4072 (back-to-indentation)))
4073 (viper-deactivate-mark))
4075 (defun viper-Put-back (arg)
4076 "Put back at point/above line."
4077 (interactive "P")
4078 (let ((val (viper-p-val arg))
4079 (text (if viper-use-register
4080 (cond ((viper-valid-register viper-use-register '(digit))
4081 (current-kill
4082 (- viper-use-register ?1) 'do-not-rotate))
4083 ((viper-valid-register viper-use-register)
4084 (get-register (downcase viper-use-register)))
4085 (t (error viper-InvalidRegister viper-use-register)))
4086 (current-kill 0)))
4087 sv-point chars-inserted lines-inserted)
4088 (if (null text)
4089 (if viper-use-register
4090 (let ((reg viper-use-register))
4091 (setq viper-use-register nil)
4092 (error viper-EmptyRegister reg))
4093 (error "")))
4094 (setq viper-use-register nil)
4095 (if (viper-end-with-a-newline-p text) (beginning-of-line))
4096 (viper-set-destructive-command
4097 (list 'viper-Put-back val nil viper-use-register nil nil))
4098 (set-marker (viper-mark-marker) (point) (current-buffer))
4099 (setq sv-point (point))
4100 (viper-loop val (viper-yank text))
4101 (setq chars-inserted (abs (- (point) sv-point))
4102 lines-inserted (abs (count-lines (point) sv-point)))
4103 (if (or (> chars-inserted viper-change-notification-threshold)
4104 (> lines-inserted viper-change-notification-threshold))
4105 (unless (viper-is-in-minibuffer)
4106 (message "Inserted %d character(s), %d line(s)"
4107 chars-inserted lines-inserted))))
4108 ;; Vi puts cursor on the last char when the yanked text doesn't contain a
4109 ;; newline; it leaves the cursor at the beginning when the text contains
4110 ;; a newline
4111 (if (viper-same-line (point) (mark))
4112 (or (= (point) (mark)) (viper-backward-char-carefully))
4113 (exchange-point-and-mark)
4114 (if (bolp)
4115 (back-to-indentation)))
4116 (viper-deactivate-mark))
4119 ;; Copy region to kill-ring.
4120 ;; If BEG and END do not belong to the same buffer, copy empty region.
4121 (defun viper-copy-region-as-kill (beg end)
4122 (condition-case nil
4123 (copy-region-as-kill beg end)
4124 (error (copy-region-as-kill beg beg))))
4127 (defun viper-delete-char (arg)
4128 "Delete next character."
4129 (interactive "P")
4130 (let ((val (viper-p-val arg))
4131 end-del-pos)
4132 (viper-set-destructive-command
4133 (list 'viper-delete-char val nil nil nil nil))
4134 (if (and viper-ex-style-editing
4135 (> val (viper-chars-in-region (point) (viper-line-pos 'end))))
4136 (setq val (viper-chars-in-region (point) (viper-line-pos 'end))))
4137 (if (and viper-ex-style-motion (eolp))
4138 (if (bolp) (error "") (setq val 0))) ; not bol---simply back 1 ch
4139 (save-excursion
4140 (viper-forward-char-carefully val)
4141 (setq end-del-pos (point)))
4142 (if viper-use-register
4143 (progn
4144 (cond ((viper-valid-register viper-use-register '((Letter)))
4145 (viper-append-to-register
4146 (downcase viper-use-register) (point) end-del-pos))
4147 ((viper-valid-register viper-use-register)
4148 (copy-to-register
4149 viper-use-register (point) end-del-pos nil))
4150 (t (error viper-InvalidRegister viper-use-register)))
4151 (setq viper-use-register nil)))
4153 (delete-char val t)
4154 (if viper-ex-style-motion
4155 (if (and (eolp) (not (bolp))) (backward-char 1)))
4158 (defun viper-delete-backward-char (arg)
4159 "Delete previous character. On reaching beginning of line, stop and beep."
4160 (interactive "P")
4161 (let ((val (viper-p-val arg))
4162 end-del-pos)
4163 (viper-set-destructive-command
4164 (list 'viper-delete-backward-char val nil nil nil nil))
4165 (if (and
4166 viper-ex-style-editing
4167 (> val (viper-chars-in-region (viper-line-pos 'start) (point))))
4168 (setq val (viper-chars-in-region (viper-line-pos 'start) (point))))
4169 (save-excursion
4170 (viper-backward-char-carefully val)
4171 (setq end-del-pos (point)))
4172 (if viper-use-register
4173 (progn
4174 (cond ((viper-valid-register viper-use-register '(Letter))
4175 (viper-append-to-register
4176 (downcase viper-use-register) end-del-pos (point)))
4177 ((viper-valid-register viper-use-register)
4178 (copy-to-register
4179 viper-use-register end-del-pos (point) nil))
4180 (t (error viper-InvalidRegister viper-use-register)))
4181 (setq viper-use-register nil)))
4182 (if (and (bolp) viper-ex-style-editing)
4183 (ding))
4184 (delete-backward-char val t)))
4187 (defun viper-del-backward-char-in-insert ()
4188 "Delete 1 char backwards while in insert mode."
4189 (interactive)
4190 (if (and viper-ex-style-editing (bolp))
4191 (beep 1)
4192 ;; don't put on kill ring
4193 (delete-backward-char 1 nil)))
4196 (defun viper-del-backward-char-in-replace ()
4197 "Delete one character in replace mode.
4198 If `viper-delete-backwards-in-replace' is t, then DEL key actually deletes
4199 charecters. If it is nil, then the cursor just moves backwards, similarly
4200 to Vi. The variable `viper-ex-style-editing', if t, doesn't let the
4201 cursor move past the beginning of line."
4202 (interactive)
4203 (cond (viper-delete-backwards-in-replace
4204 (cond ((not (bolp))
4205 ;; don't put on kill ring
4206 (delete-backward-char 1 nil))
4207 (viper-ex-style-editing
4208 (beep 1))
4209 ((bobp)
4210 (beep 1))
4212 ;; don't put on kill ring
4213 (delete-backward-char 1 nil))))
4214 (viper-ex-style-editing
4215 (if (bolp)
4216 (beep 1)
4217 (backward-char 1)))
4219 (backward-char 1))))
4223 ;; join lines.
4225 (defun viper-join-lines (arg)
4226 "Join this line to next, if ARG is nil. Otherwise, join ARG lines."
4227 (interactive "*P")
4228 (let ((val (viper-P-val arg)))
4229 (viper-set-destructive-command
4230 (list 'viper-join-lines val nil nil nil nil))
4231 (viper-loop (if (null val) 1 (1- val))
4232 (end-of-line)
4233 (if (not (eobp))
4234 (progn
4235 (forward-line 1)
4236 (delete-region (point) (1- (point)))
4237 (fixup-whitespace)
4238 ;; fixup-whitespace sometimes does not leave space
4239 ;; between objects, so we insert it as in Vi
4240 (or (looking-at " ")
4241 (insert " ")
4242 (backward-char 1))
4243 )))))
4246 ;; Replace state
4248 (defun viper-change (beg end)
4249 (if (markerp beg) (setq beg (marker-position beg)))
4250 (if (markerp end) (setq end (marker-position end)))
4251 ;; beg is sometimes (mark t), which may be nil
4252 (or beg (setq beg end))
4254 (viper-set-complex-command-for-undo)
4255 (if viper-use-register
4256 (progn
4257 (copy-to-register viper-use-register beg end nil)
4258 (setq viper-use-register nil)))
4259 (viper-set-replace-overlay beg end)
4260 (setq last-command nil) ; separate repl text from prev kills
4262 (if (= (viper-replace-start) (point-max))
4263 (error "End of buffer"))
4265 (setq viper-last-replace-region
4266 (buffer-substring (viper-replace-start)
4267 (viper-replace-end)))
4269 ;; protect against error while inserting "@" and other disasters
4270 ;; (e.g., read-only buff)
4271 (condition-case conds
4272 (if (or viper-allow-multiline-replace-regions
4273 (viper-same-line (viper-replace-start)
4274 (viper-replace-end)))
4275 (progn
4276 ;; tabs cause problems in replace, so untabify
4277 (goto-char (viper-replace-end))
4278 (insert-before-markers "@") ; put placeholder after the TAB
4279 (untabify (viper-replace-start) (point))
4280 ;; del @, don't put on kill ring
4281 (delete-backward-char 1)
4283 (viper-set-replace-overlay-glyphs
4284 viper-replace-region-start-delimiter
4285 viper-replace-region-end-delimiter)
4286 ;; this move takes care of the last posn in the overlay, which
4287 ;; has to be shifted because of insert. We can't simply insert
4288 ;; "$" before-markers because then overlay-start will shift the
4289 ;; beginning of the overlay in case we are replacing a single
4290 ;; character. This fixes the bug with `s' and `cl' commands.
4291 (viper-move-replace-overlay (viper-replace-start) (point))
4292 (goto-char (viper-replace-start))
4293 (viper-change-state-to-replace t))
4294 (kill-region (viper-replace-start)
4295 (viper-replace-end))
4296 (viper-hide-replace-overlay)
4297 (viper-change-state-to-insert))
4298 (error ;; make sure that the overlay doesn't stay.
4299 ;; go back to the original point
4300 (goto-char (viper-replace-start))
4301 (viper-hide-replace-overlay)
4302 (viper-message-conditions conds))))
4305 (defun viper-change-subr (beg end)
4306 ;; beg is sometimes (mark t), which may be nil
4307 (or beg (setq beg end))
4308 (if viper-use-register
4309 (progn
4310 (copy-to-register viper-use-register beg end nil)
4311 (setq viper-use-register nil)))
4312 (kill-region beg end)
4313 (setq this-command 'viper-change)
4314 (viper-yank-last-insertion))
4316 (defun viper-toggle-case (arg)
4317 "Toggle character case."
4318 (interactive "P")
4319 (let ((val (viper-p-val arg)) (c))
4320 (viper-set-destructive-command
4321 (list 'viper-toggle-case val nil nil nil nil))
4322 (while (> val 0)
4323 (setq c (following-char))
4324 (delete-char 1 nil)
4325 (if (eq c (upcase c))
4326 (insert-char (downcase c) 1)
4327 (insert-char (upcase c) 1))
4328 (if (eolp) (backward-char 1))
4329 (setq val (1- val)))))
4332 ;; query replace
4334 (defun viper-query-replace ()
4335 "Query replace.
4336 If a null string is suplied as the string to be replaced,
4337 the query replace mode will toggle between string replace
4338 and regexp replace."
4339 (interactive)
4340 (let (str)
4341 (setq str (viper-read-string-with-history
4342 (if viper-re-query-replace "Query replace regexp: "
4343 "Query replace: ")
4344 nil ; no initial
4345 'viper-replace1-history
4346 (car viper-replace1-history) ; default
4348 (if (string= str "")
4349 (progn
4350 (setq viper-re-query-replace (not viper-re-query-replace))
4351 (message "Query replace mode changed to %s"
4352 (if viper-re-query-replace "regexp replace"
4353 "string replace")))
4354 (if viper-re-query-replace
4355 (query-replace-regexp
4357 (viper-read-string-with-history
4358 (format "Query replace regexp `%s' with: " str)
4359 nil ; no initial
4360 'viper-replace1-history
4361 (car viper-replace1-history) ; default
4363 (query-replace
4365 (viper-read-string-with-history
4366 (format "Query replace `%s' with: " str)
4367 nil ; no initial
4368 'viper-replace1-history
4369 (car viper-replace1-history) ; default
4370 ))))))
4373 ;; marking
4375 (defun viper-mark-beginning-of-buffer ()
4376 "Mark beginning of buffer."
4377 (interactive)
4378 (push-mark (point))
4379 (goto-char (point-min))
4380 (exchange-point-and-mark)
4381 (message "Mark set at the beginning of buffer"))
4383 (defun viper-mark-end-of-buffer ()
4384 "Mark end of buffer."
4385 (interactive)
4386 (push-mark (point))
4387 (goto-char (point-max))
4388 (exchange-point-and-mark)
4389 (message "Mark set at the end of buffer"))
4391 (defun viper-mark-point ()
4392 "Set mark at point of buffer."
4393 (interactive)
4394 (let ((char (read-char)))
4395 (cond ((and (<= ?a char) (<= char ?z))
4396 (point-to-register (viper-int-to-char (1+ (- char ?a)))))
4397 ((viper= char ?<) (viper-mark-beginning-of-buffer))
4398 ((viper= char ?>) (viper-mark-end-of-buffer))
4399 ((viper= char ?.) (viper-set-mark-if-necessary))
4400 ((viper= char ?,) (viper-cycle-through-mark-ring))
4401 ((viper= char ?^) (push-mark viper-saved-mark t t))
4402 ((viper= char ?D) (mark-defun))
4403 (t (error ""))
4406 ;; Algorithm: If first invocation of this command save mark on ring, goto
4407 ;; mark, M0, and pop the most recent elt from the mark ring into mark,
4408 ;; making it into the new mark, M1.
4409 ;; Push this mark back and set mark to the original point position, p1.
4410 ;; So, if you hit '' or `` then you can return to p1.
4412 ;; If repeated command, pop top elt from the ring into mark and
4413 ;; jump there. This forgets the position, p1, and puts M1 back into mark.
4414 ;; Then we save the current pos, which is M0, jump to M1 and pop M2 from
4415 ;; the ring into mark. Push M2 back on the ring and set mark to M0.
4416 ;; etc.
4417 (defun viper-cycle-through-mark-ring ()
4418 "Visit previous locations on the mark ring.
4419 One can use `` and '' to temporarily jump 1 step back."
4420 (let* ((sv-pt (point)))
4421 ;; if repeated `m,' command, pop the previously saved mark.
4422 ;; Prev saved mark is actually prev saved point. It is used if the
4423 ;; user types `` or '' and is discarded
4424 ;; from the mark ring by the next `m,' command.
4425 ;; In any case, go to the previous or previously saved mark.
4426 ;; Then push the current mark (popped off the ring) and set current
4427 ;; point to be the mark. Current pt as mark is discarded by the next
4428 ;; m, command.
4429 (if (eq last-command 'viper-cycle-through-mark-ring)
4431 ;; save current mark if the first iteration
4432 (setq mark-ring (delete (viper-mark-marker) mark-ring))
4433 (if (mark t)
4434 (push-mark (mark t) t)) )
4435 (pop-mark)
4436 (set-mark-command 1)
4437 ;; don't duplicate mark on the ring
4438 (setq mark-ring (delete (viper-mark-marker) mark-ring))
4439 (push-mark sv-pt t)
4440 (viper-deactivate-mark)
4441 (setq this-command 'viper-cycle-through-mark-ring)
4445 (defun viper-goto-mark (arg)
4446 "Go to mark."
4447 (interactive "P")
4448 (let ((char (read-char))
4449 (com (viper-getcom arg)))
4450 (viper-goto-mark-subr char com nil)))
4452 (defun viper-goto-mark-and-skip-white (arg)
4453 "Go to mark and skip to first non-white character on line."
4454 (interactive "P")
4455 (let ((char (read-char))
4456 (com (viper-getCom arg)))
4457 (viper-goto-mark-subr char com t)))
4459 (defun viper-goto-mark-subr (char com skip-white)
4460 (if (eobp)
4461 (if (bobp)
4462 (error "Empty buffer")
4463 (backward-char 1)))
4464 (cond ((viper-valid-register char '(letter))
4465 (let* ((buff (current-buffer))
4466 (reg (viper-int-to-char (1+ (- char ?a))))
4467 (text-marker (get-register reg)))
4468 ;; If marker points to file that had markers set (and those markers
4469 ;; were saved (as e.g., in session.el), then restore those markers
4470 (if (and (consp text-marker)
4471 (eq (car text-marker) 'file-query)
4472 (or (find-buffer-visiting (nth 1 text-marker))
4473 (y-or-n-p (format "Visit file %s again? "
4474 (nth 1 text-marker)))))
4475 (save-excursion
4476 (find-file (nth 1 text-marker))
4477 (when (and (<= (nth 2 text-marker) (point-max))
4478 (<= (point-min) (nth 2 text-marker)))
4479 (setq text-marker (copy-marker (nth 2 text-marker)))
4480 (set-register reg text-marker))))
4481 (if com (viper-move-marker-locally 'viper-com-point (point)))
4482 (if (not (viper-valid-marker text-marker))
4483 (error viper-EmptyTextmarker char))
4484 (if (and (viper-same-line (point) viper-last-jump)
4485 (= (point) viper-last-jump-ignore))
4486 (push-mark viper-last-jump t)
4487 (push-mark nil t)) ; no msg
4488 (viper-register-to-point reg)
4489 (setq viper-last-jump (point-marker))
4490 (cond (skip-white
4491 (back-to-indentation)
4492 (setq viper-last-jump-ignore (point))))
4493 (if com
4494 (if (equal buff (current-buffer))
4495 (viper-execute-com (if skip-white
4496 'viper-goto-mark-and-skip-white
4497 'viper-goto-mark)
4498 nil com)
4499 (switch-to-buffer buff)
4500 (goto-char viper-com-point)
4501 (viper-change-state-to-vi)
4502 (error "")))))
4503 ((and (not skip-white) (viper= char ?`))
4504 (if com (viper-move-marker-locally 'viper-com-point (point)))
4505 (if (and (viper-same-line (point) viper-last-jump)
4506 (= (point) viper-last-jump-ignore))
4507 (goto-char viper-last-jump))
4508 (if (null (mark t)) (error "Mark is not set in this buffer"))
4509 (if (= (point) (mark t)) (pop-mark))
4510 (exchange-point-and-mark)
4511 (setq viper-last-jump (point-marker)
4512 viper-last-jump-ignore 0)
4513 (if com (viper-execute-com 'viper-goto-mark nil com)))
4514 ((and skip-white (viper= char ?'))
4515 (if com (viper-move-marker-locally 'viper-com-point (point)))
4516 (if (and (viper-same-line (point) viper-last-jump)
4517 (= (point) viper-last-jump-ignore))
4518 (goto-char viper-last-jump))
4519 (if (= (point) (mark t)) (pop-mark))
4520 (exchange-point-and-mark)
4521 (setq viper-last-jump (point))
4522 (back-to-indentation)
4523 (setq viper-last-jump-ignore (point))
4524 (if com (viper-execute-com 'viper-goto-mark-and-skip-white nil com)))
4525 (t (error viper-InvalidTextmarker char))))
4527 (defun viper-insert-tab ()
4528 (interactive)
4529 (insert-tab))
4531 (defun viper-exchange-point-and-mark ()
4532 (interactive)
4533 (exchange-point-and-mark)
4534 (back-to-indentation))
4536 ;; Input Mode Indentation
4538 ;; Returns t, if the string before point matches the regexp STR.
4539 (defsubst viper-looking-back (str)
4540 (and (save-excursion (re-search-backward str nil t))
4541 (= (point) (match-end 0))))
4544 (defun viper-forward-indent ()
4545 "Indent forward -- `C-t' in Vi."
4546 (interactive)
4547 (setq viper-cted t)
4548 (indent-to (+ (current-column) viper-shift-width)))
4550 (defun viper-backward-indent ()
4551 "Backtab, C-d in VI"
4552 (interactive)
4553 (if viper-cted
4554 (let ((p (point)) (c (current-column)) bol (indent t))
4555 (if (viper-looking-back "[0^]")
4556 (progn
4557 (if (eq ?^ (preceding-char))
4558 (setq viper-preserve-indent t))
4559 (delete-backward-char 1)
4560 (setq p (point))
4561 (setq indent nil)))
4562 (save-excursion
4563 (beginning-of-line)
4564 (setq bol (point)))
4565 (if (re-search-backward "[^ \t]" bol 1) (forward-char))
4566 (delete-region (point) p)
4567 (if indent
4568 (indent-to (- c viper-shift-width)))
4569 (if (or (bolp) (viper-looking-back "[^ \t]"))
4570 (setq viper-cted nil)))))
4572 ;; do smart indent
4573 (defun viper-indent-line (col)
4574 (if viper-auto-indent
4575 (progn
4576 (setq viper-cted t)
4577 (if (and viper-electric-mode
4578 (not (memq major-mode '(fundamental-mode
4579 text-mode
4580 paragraph-indent-text-mode))))
4581 (indent-according-to-mode)
4582 (indent-to col)))))
4585 (defun viper-autoindent ()
4586 "Auto Indentation, Vi-style."
4587 (interactive)
4588 (let ((col (current-indentation)))
4589 (if abbrev-mode (expand-abbrev))
4590 (if viper-preserve-indent
4591 (setq viper-preserve-indent nil)
4592 (setq viper-current-indent col))
4593 ;; don't leave whitespace lines around
4594 (if (memq last-command
4595 '(viper-autoindent
4596 viper-open-line viper-Open-line
4597 viper-replace-state-exit-cmd))
4598 (indent-to-left-margin))
4599 ;; use \n instead of newline, or else <Return> will move the insert point
4600 ;;(newline 1)
4601 (insert "\n")
4602 (viper-indent-line viper-current-indent)
4606 ;; Viewing registers
4608 (defun viper-ket-function (arg)
4609 "Function called by \], the ket. View registers and call \]\]."
4610 (interactive "P")
4611 (let ((reg (read-char)))
4612 (cond ((viper-valid-register reg '(letter Letter))
4613 (view-register (downcase reg)))
4614 ((viper-valid-register reg '(digit))
4615 (let ((text (current-kill (- reg ?1) 'do-not-rotate)))
4616 (with-output-to-temp-buffer " *viper-info*"
4617 (princ (format "Register %c contains the string:\n" reg))
4618 (princ text))
4620 ((viper= ?\] reg)
4621 (viper-next-heading arg))
4622 (t (error
4623 viper-InvalidRegister reg)))))
4625 (defun viper-brac-function (arg)
4626 "Function called by \[, the brac. View textmarkers and call \[\["
4627 (interactive "P")
4628 (let ((reg (read-char)))
4629 (cond ((viper= ?\[ reg)
4630 (viper-prev-heading arg))
4631 ((viper= ?\] reg)
4632 (viper-heading-end arg))
4633 ((viper-valid-register reg '(letter))
4634 (let* ((val (get-register (viper-int-to-char (1+ (- reg ?a)))))
4635 (buf (if (not (markerp val))
4636 (error viper-EmptyTextmarker reg)
4637 (marker-buffer val)))
4638 (pos (marker-position val))
4639 line-no text (s pos) (e pos))
4640 (with-output-to-temp-buffer " *viper-info*"
4641 (if (and buf pos)
4642 (progn
4643 (save-excursion
4644 (set-buffer buf)
4645 (setq line-no (1+ (count-lines (point-min) val)))
4646 (goto-char pos)
4647 (beginning-of-line)
4648 (if (re-search-backward "[^ \t]" nil t)
4649 (progn
4650 (beginning-of-line)
4651 (setq s (point))))
4652 (goto-char pos)
4653 (forward-line 1)
4654 (if (re-search-forward "[^ \t]" nil t)
4655 (progn
4656 (end-of-line)
4657 (setq e (point))))
4658 (setq text (buffer-substring s e))
4659 (setq text (format "%s<%c>%s"
4660 (substring text 0 (- pos s))
4661 reg (substring text (- pos s)))))
4662 (princ
4663 (format
4664 "Textmarker `%c' is in buffer `%s' at line %d.\n"
4665 reg (buffer-name buf) line-no))
4666 (princ (format "Here is some text around %c:\n\n %s"
4667 reg text)))
4668 (princ (format viper-EmptyTextmarker reg))))
4670 (t (error viper-InvalidTextmarker reg)))))
4674 (defun viper-delete-backward-word (arg)
4675 "Delete previous word."
4676 (interactive "p")
4677 (save-excursion
4678 (push-mark nil t)
4679 (backward-word arg)
4680 (delete-region (point) (mark t))
4681 (pop-mark)))
4685 ;; Get viper standard value of SYMBOL. If symbol is customized, get its
4686 ;; standard value. Otherwise, get the value saved in the alist STORAGE. If
4687 ;; STORAGE is nil, use viper-saved-user-settings.
4688 (defun viper-standard-value (symbol &optional storage)
4689 (or (eval (car (get symbol 'customized-value)))
4690 (eval (car (get symbol 'saved-value)))
4691 (nth 1 (assoc symbol (or storage viper-saved-user-settings)))))
4695 (defun viper-set-expert-level (&optional dont-change-unless)
4696 "Sets the expert level for a Viper user.
4697 Can be called interactively to change (temporarily or permanently) the
4698 current expert level.
4700 The optional argument DONT-CHANGE-UNLESS, if not nil, says that
4701 the level should not be changed, unless its current value is
4702 meaningless (i.e., not one of 1,2,3,4,5).
4704 User level determines the setting of Viper variables that are most
4705 sensitive for VI-style look-and-feel."
4707 (interactive)
4709 (if (not (natnump viper-expert-level)) (setq viper-expert-level 0))
4711 (save-window-excursion
4712 (delete-other-windows)
4713 ;; if 0 < viper-expert-level < viper-max-expert-level
4714 ;; & dont-change-unless = t -- use it; else ask
4715 (viper-ask-level dont-change-unless))
4717 (setq viper-always t
4718 viper-ex-style-motion t
4719 viper-ex-style-editing t
4720 viper-want-ctl-h-help nil)
4722 (cond ((eq viper-expert-level 1) ; novice or beginner
4723 (global-set-key ; in emacs-state
4724 viper-toggle-key
4725 (if (viper-window-display-p) 'viper-iconify 'suspend-emacs))
4726 (setq viper-no-multiple-ESC t
4727 viper-re-search t
4728 viper-vi-style-in-minibuffer t
4729 viper-search-wrap-around-t t
4730 viper-electric-mode nil
4731 viper-want-emacs-keys-in-vi nil
4732 viper-want-emacs-keys-in-insert nil))
4734 ((and (> viper-expert-level 1) (< viper-expert-level 5))
4735 ;; intermediate to guru
4736 (setq viper-no-multiple-ESC (if (viper-window-display-p)
4737 t 'twice)
4738 viper-electric-mode t
4739 viper-want-emacs-keys-in-vi t
4740 viper-want-emacs-keys-in-insert (> viper-expert-level 2))
4742 (if (eq viper-expert-level 4) ; respect user's ex-style motion
4743 ; and viper-no-multiple-ESC
4744 (progn
4745 (setq-default
4746 viper-ex-style-editing
4747 (viper-standard-value 'viper-ex-style-editing)
4748 viper-ex-style-motion
4749 (viper-standard-value 'viper-ex-style-motion))
4750 (setq viper-ex-style-motion
4751 (viper-standard-value 'viper-ex-style-motion)
4752 viper-ex-style-editing
4753 (viper-standard-value 'viper-ex-style-editing)
4754 viper-re-search
4755 (viper-standard-value 'viper-re-search)
4756 viper-no-multiple-ESC
4757 (viper-standard-value 'viper-no-multiple-ESC)))))
4759 ;; A wizard!!
4760 ;; Ideally, if 5 is selected, a buffer should pop up to let the
4761 ;; user toggle the values of variables.
4762 (t (setq-default viper-ex-style-editing
4763 (viper-standard-value 'viper-ex-style-editing)
4764 viper-ex-style-motion
4765 (viper-standard-value 'viper-ex-style-motion))
4766 (setq viper-want-ctl-h-help
4767 (viper-standard-value 'viper-want-ctl-h-help)
4768 viper-always
4769 (viper-standard-value 'viper-always)
4770 viper-no-multiple-ESC
4771 (viper-standard-value 'viper-no-multiple-ESC)
4772 viper-ex-style-motion
4773 (viper-standard-value 'viper-ex-style-motion)
4774 viper-ex-style-editing
4775 (viper-standard-value 'viper-ex-style-editing)
4776 viper-re-search
4777 (viper-standard-value 'viper-re-search)
4778 viper-electric-mode
4779 (viper-standard-value 'viper-electric-mode)
4780 viper-want-emacs-keys-in-vi
4781 (viper-standard-value 'viper-want-emacs-keys-in-vi)
4782 viper-want-emacs-keys-in-insert
4783 (viper-standard-value 'viper-want-emacs-keys-in-insert))))
4785 (viper-set-mode-vars-for viper-current-state)
4786 (if (or viper-always
4787 (and (> viper-expert-level 0) (> 5 viper-expert-level)))
4788 (viper-set-hooks)))
4791 ;; Ask user expert level.
4792 (defun viper-ask-level (dont-change-unless)
4793 (let ((ask-buffer " *viper-ask-level*")
4794 level-changed repeated)
4795 (save-window-excursion
4796 (switch-to-buffer ask-buffer)
4798 (while (or (> viper-expert-level viper-max-expert-level)
4799 (< viper-expert-level 1)
4800 (null dont-change-unless))
4801 (erase-buffer)
4802 (if repeated
4803 (progn
4804 (message "Invalid user level")
4805 (beep 1))
4806 (setq repeated t))
4807 (setq dont-change-unless t
4808 level-changed t)
4809 (insert "
4810 Please specify your level of familiarity with the venomous VI PERil
4811 \(and the VI Plan for Emacs Rescue).
4812 You can change it at any time by typing `M-x viper-set-expert-level RET'
4814 1 -- BEGINNER: Almost all Emacs features are suppressed.
4815 Feels almost like straight Vi. File name completion and
4816 command history in the minibuffer are thrown in as a bonus.
4817 To use Emacs productively, you must reach level 3 or higher.
4818 2 -- MASTER: C-c now has its standard Emacs meaning in Vi command state,
4819 so most Emacs commands can be used when Viper is in Vi state.
4820 Good progress---you are well on the way to level 3!
4821 3 -- GRAND MASTER: Like 2, but most Emacs commands are available also
4822 in Viper's insert state.
4823 4 -- GURU: Like 3, but user settings are respected for viper-no-multiple-ESC,
4824 viper-ex-style-motion, viper-ex-style-editing, and
4825 viper-re-search variables. Adjust these settings to your taste.
4826 5 -- WIZARD: Like 4, but user settings are also respected for viper-always,
4827 viper-electric-mode, viper-want-ctl-h-help, viper-want-emacs-keys-in-vi,
4828 and viper-want-emacs-keys-in-insert. Adjust these to your taste.
4830 Please, specify your level now: ")
4832 (setq viper-expert-level (- (viper-read-char-exclusive) ?0))
4833 ) ; end while
4835 ;; tell the user if level was changed
4836 (and level-changed
4837 (progn
4838 (insert
4839 (format "\n\n\n\n\n\t\tYou have selected user level %d"
4840 viper-expert-level))
4841 (if (y-or-n-p "Do you wish to make this change permanent? ")
4842 ;; save the setting for viper-expert-level
4843 (viper-save-setting
4844 'viper-expert-level
4845 (format "Saving user level %d ..." viper-expert-level)
4846 viper-custom-file-name))
4848 (bury-buffer) ; remove ask-buffer from screen
4849 (message "")
4853 (defun viper-nil ()
4854 (interactive)
4855 (beep 1))
4858 ;; if ENFORCE-BUFFER is not nil, error if CHAR is a marker in another buffer
4859 (defun viper-register-to-point (char &optional enforce-buffer)
4860 "Like jump-to-register, but switches to another buffer in another window."
4861 (interactive "cViper register to point: ")
4862 (let ((val (get-register char)))
4863 (cond
4864 ((and (fboundp 'frame-configuration-p)
4865 (frame-configuration-p val))
4866 (set-frame-configuration val))
4867 ((window-configuration-p val)
4868 (set-window-configuration val))
4869 ((viper-valid-marker val)
4870 (if (and enforce-buffer
4871 (not (equal (current-buffer) (marker-buffer val))))
4872 (error (concat viper-EmptyTextmarker " in this buffer")
4873 (viper-int-to-char (1- (+ char ?a)))))
4874 (pop-to-buffer (marker-buffer val))
4875 (goto-char val))
4876 ((and (consp val) (eq (car val) 'file))
4877 (find-file (cdr val)))
4879 (error viper-EmptyTextmarker (viper-int-to-char (1- (+ char ?a))))))))
4882 (defun viper-save-kill-buffer ()
4883 "Save then kill current buffer."
4884 (interactive)
4885 (if (< viper-expert-level 2)
4886 (save-buffers-kill-emacs)
4887 (save-buffer)
4888 (kill-buffer (current-buffer))))
4892 ;;; Bug Report
4894 (defun viper-submit-report ()
4895 "Submit bug report on Viper."
4896 (interactive)
4897 (let ((reporter-prompt-for-summary-p t)
4898 (viper-device-type (viper-device-type))
4899 color-display-p frame-parameters
4900 minibuffer-emacs-face minibuffer-vi-face minibuffer-insert-face
4901 varlist salutation window-config)
4903 ;; If mode info is needed, add variable to `let' and then set it below,
4904 ;; like we did with color-display-p.
4905 (setq color-display-p (if (viper-window-display-p)
4906 (viper-color-display-p)
4907 'non-x)
4908 minibuffer-vi-face (if (viper-has-face-support-p)
4909 (viper-get-face viper-minibuffer-vi-face)
4910 'non-x)
4911 minibuffer-insert-face (if (viper-has-face-support-p)
4912 (viper-get-face
4913 viper-minibuffer-insert-face)
4914 'non-x)
4915 minibuffer-emacs-face (if (viper-has-face-support-p)
4916 (viper-get-face
4917 viper-minibuffer-emacs-face)
4918 'non-x)
4919 frame-parameters (if (fboundp 'frame-parameters)
4920 (frame-parameters (selected-frame))))
4922 (setq varlist (list 'viper-vi-minibuffer-minor-mode
4923 'viper-insert-minibuffer-minor-mode
4924 'viper-vi-intercept-minor-mode
4925 'viper-vi-local-user-minor-mode
4926 'viper-vi-kbd-minor-mode
4927 'viper-vi-global-user-minor-mode
4928 'viper-vi-state-modifier-minor-mode
4929 'viper-vi-diehard-minor-mode
4930 'viper-vi-basic-minor-mode
4931 'viper-replace-minor-mode
4932 'viper-insert-intercept-minor-mode
4933 'viper-insert-local-user-minor-mode
4934 'viper-insert-kbd-minor-mode
4935 'viper-insert-global-user-minor-mode
4936 'viper-insert-state-modifier-minor-mode
4937 'viper-insert-diehard-minor-mode
4938 'viper-insert-basic-minor-mode
4939 'viper-emacs-intercept-minor-mode
4940 'viper-emacs-local-user-minor-mode
4941 'viper-emacs-kbd-minor-mode
4942 'viper-emacs-global-user-minor-mode
4943 'viper-emacs-state-modifier-minor-mode
4944 'viper-automatic-iso-accents
4945 'viper-special-input-method
4946 'viper-want-emacs-keys-in-insert
4947 'viper-want-emacs-keys-in-vi
4948 'viper-keep-point-on-undo
4949 'viper-no-multiple-ESC
4950 'viper-electric-mode
4951 'viper-ESC-key
4952 'viper-want-ctl-h-help
4953 'viper-ex-style-editing
4954 'viper-delete-backwards-in-replace
4955 'viper-vi-style-in-minibuffer
4956 'viper-vi-state-hook
4957 'viper-insert-state-hook
4958 'viper-replace-state-hook
4959 'viper-emacs-state-hook
4960 'ex-cycle-other-window
4961 'ex-cycle-through-non-files
4962 'viper-expert-level
4963 'major-mode
4964 'viper-device-type
4965 'color-display-p
4966 'frame-parameters
4967 'minibuffer-vi-face
4968 'minibuffer-insert-face
4969 'minibuffer-emacs-face
4971 (setq salutation "
4972 Congratulations! You may have unearthed a bug in Viper!
4973 Please mail a concise, accurate summary of the problem to the address above.
4975 -------------------------------------------------------------------")
4976 (setq window-config (current-window-configuration))
4977 (with-output-to-temp-buffer " *viper-info*"
4978 (switch-to-buffer " *viper-info*")
4979 (delete-other-windows)
4980 (princ "
4981 PLEASE FOLLOW THESE PROCEDURES
4982 ------------------------------
4984 Before reporting a bug, please verify that it is related to Viper, and is
4985 not cause by other packages you are using.
4987 Don't report compilation warnings, unless you are certain that there is a
4988 problem. These warnings are normal and unavoidable.
4990 Please note that users should not modify variables and keymaps other than
4991 those advertised in the manual. Such `customization' is likely to crash
4992 Viper, as it would any other improperly customized Emacs package.
4994 If you are reporting an error message received while executing one of the
4995 Viper commands, type:
4997 M-x set-variable <Return> debug-on-error <Return> t <Return>
4999 Then reproduce the error. The above command will cause Emacs to produce a
5000 back trace of the execution that leads to the error. Please include this
5001 trace in your bug report.
5003 If you believe that one of Viper's commands goes into an infinite loop
5004 \(e.g., Emacs freezes\), type:
5006 M-x set-variable <Return> debug-on-quit <Return> t <Return>
5008 Then reproduce the problem. Wait for a few seconds, then type C-g to abort
5009 the current command. Include the resulting back trace in the bug report.
5011 Mail anyway (y or n)? ")
5012 (if (y-or-n-p "Mail anyway? ")
5014 (set-window-configuration window-config)
5015 (error "Bug report aborted")))
5017 (require 'reporter)
5018 (set-window-configuration window-config)
5020 (reporter-submit-bug-report "kifer@cs.stonybrook.edu"
5021 (viper-version)
5022 varlist
5023 nil 'delete-other-windows
5024 salutation)
5030 ;; arch-tag: 739a6450-5fda-44d0-88b0-325053d888c2
5031 ;;; viper-cmd.el ends here