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