(rmail-mime-feature): Doc and custom fix.
[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)
962 cmd-info mv-or-digit-cmd)
963 (while (and cont
964 (memq char
965 (list ?c ?d ?y ?! ?< ?> ?= ?# ?r ?R ?\"
966 vip-buffer-search-char)))
967 (if com
968 ;; this means that we already have a command character, so we
969 ;; construct a com list and exit while. however, if char is "
970 ;; it is an error.
971 (progn
972 ;; new com is (CHAR . OLDCOM)
973 (if (memq char '(?# ?\")) (error ""))
974 (setq com (cons char com))
975 (setq cont nil))
976 ;; If com is nil we set com as char, and read more. Again, if char
977 ;; is ", we read the name of register and store it in vip-use-register.
978 ;; if char is !, =, or #, a complete com is formed so we exit the
979 ;; while loop.
980 (cond ((memq char '(?! ?=))
981 (setq com char)
982 (setq char (read-char))
983 (setq cont nil))
984 ((= char ?#)
985 ;; read a char and encode it as com
986 (setq com (+ 128 (read-char)))
987 (setq char (read-char)))
988 ((= char ?\")
989 (let ((reg (read-char)))
990 (if (vip-valid-register reg)
991 (setq vip-use-register reg)
992 (error ""))
993 (setq char (read-char))))
994 (t
995 (setq com char)
996 (setq char (read-char))))))
997
998 (if (atom com)
999 ;; `com' is a single char, so we construct the command argument
1000 ;; and if `char' is `?', we describe the arg; otherwise
1001 ;; we prepare the command that will be executed at the end.
1002 (progn
1003 (setq cmd-info (cons value com))
1004 (while (= char ?U)
1005 (vip-describe-arg cmd-info)
1006 (setq char (read-char)))
1007 ;; `char' is a movement cmd, a digit arg cmd, or a register cmd---so we
1008 ;; execute it at the very end
1009 (or (vip-movement-command-p char)
1010 (vip-digit-command-p char)
1011 (vip-regsuffix-command-p char)
1012 (error ""))
1013 (setq mv-or-digit-cmd
1014 (vip-exec-form-in-vi
1015 (` (key-binding (char-to-string (, char)))))))
1016
1017 ;; as com is non-nil, this means that we have a command to execute
1018 (if (memq (car com) '(?r ?R))
1019 ;; execute apropriate region command.
1020 (let ((char (car com)) (com (cdr com)))
1021 (setq prefix-arg (cons value com))
1022 (if (= char ?r) (vip-region prefix-arg)
1023 (vip-Region prefix-arg))
1024 ;; reset prefix-arg
1025 (setq prefix-arg nil))
1026 ;; otherwise, reset prefix arg and call appropriate command
1027 (setq value (if (null value) 1 value))
1028 (setq prefix-arg nil)
1029 (cond ((equal com '(?c . ?c)) (vip-line (cons value ?C)))
1030 ((equal com '(?d . ?d)) (vip-line (cons value ?D)))
1031 ((equal com '(?d . ?y)) (vip-yank-defun))
1032 ((equal com '(?y . ?y)) (vip-line (cons value ?Y)))
1033 ((equal com '(?< . ?<)) (vip-line (cons value ?<)))
1034 ((equal com '(?> . ?>)) (vip-line (cons value ?>)))
1035 ((equal com '(?! . ?!)) (vip-line (cons value ?!)))
1036 ((equal com '(?= . ?=)) (vip-line (cons value ?=)))
1037 (t (error "")))))
1038
1039 (if mv-or-digit-cmd
1040 (progn
1041 (setq last-command-char char)
1042 (setq last-command-event
1043 (vip-copy-event
1044 (if vip-xemacs-p (character-to-event char) char)))
1045 (condition-case nil
1046 (funcall mv-or-digit-cmd cmd-info)
1047 (error
1048 (error "")))))
1049 ))
1050
1051(defun vip-describe-arg (arg)
1052 (let (val com)
1053 (setq val (vip-P-val arg)
1054 com (vip-getcom arg))
1055 (if (null val)
1056 (if (null com)
1057 (message "Value is nil, and command is nil")
1058 (message "Value is nil, and command is `%c'" com))
1059 (if (null com)
1060 (message "Value is `%d', and command is nil" val)
1061 (message "Value is `%d', and command is `%c'" val com)))))
1062
1063(defun vip-digit-argument (arg)
1064 "Begin numeric argument for the next command."
1065 (interactive "P")
1066 (vip-leave-region-active)
1067 (vip-prefix-arg-value
1068 last-command-char (if (consp arg) (cdr arg) nil)))
1069
1070(defun vip-command-argument (arg)
1071 "Accept a motion command as an argument."
1072 (interactive "P")
1073 (let ((vip-inside-command-argument-action t))
1074 (condition-case nil
1075 (vip-prefix-arg-com
1076 last-command-char
1077 (cond ((null arg) nil)
1078 ((consp arg) (car arg))
1079 ((integerp arg) arg)
1080 (t (error vip-InvalidCommandArgument)))
1081 (cond ((null arg) nil)
1082 ((consp arg) (cdr arg))
1083 ((integerp arg) nil)
1084 (t (error vip-InvalidCommandArgument))))
1085 (quit (setq vip-use-register nil)
1086 (signal 'quit nil)))
1087 (vip-deactivate-mark)))
1088
1089\f
1090;; repeat last destructive command
1091
1092;; Append region to text in register REG.
1093;; START and END are buffer positions indicating what to append.
1094(defsubst vip-append-to-register (reg start end)
1095 (set-register reg (concat (if (stringp (get-register reg))
1096 (get-register reg) "")
1097 (buffer-substring start end))))
1098
1099;; Saves last inserted text for possible use by vip-repeat command.
1100(defun vip-save-last-insertion (beg end)
1101 (setq vip-last-insertion (buffer-substring beg end))
1102 (or (< (length vip-d-com) 5)
1103 (setcar (nthcdr 4 vip-d-com) vip-last-insertion))
1104 (or (null vip-command-ring)
1105 (ring-empty-p vip-command-ring)
1106 (progn
1107 (setcar (nthcdr 4 (vip-current-ring-item vip-command-ring))
1108 vip-last-insertion)
1109 ;; del most recent elt, if identical to the second most-recent
1110 (vip-cleanup-ring vip-command-ring)))
1111 )
1112
1113(defsubst vip-yank-last-insertion ()
1114 "Inserts the text saved by the previous vip-save-last-insertion command."
1115 (condition-case nil
1116 (insert vip-last-insertion)
1117 (error nil)))
1118
1119
1120;; define functions to be executed
1121
1122;; invoked by the `C' command
1123(defun vip-exec-change (m-com com)
1124 (or (and (markerp vip-com-point) (marker-position vip-com-point))
1125 (set-marker vip-com-point (point) (current-buffer)))
1126 ;; handle C cmd at the eol and at eob.
1127 (if (or (and (eolp) (= vip-com-point (point)))
1128 (= vip-com-point (point-max)))
1129 (progn
1130 (insert " ")(backward-char 1)))
1131 (if (= vip-com-point (point))
1132 (vip-forward-char-carefully))
1133 (if (= com ?c)
1134 (vip-change vip-com-point (point))
1135 (vip-change-subr vip-com-point (point))))
1136
1137;; this is invoked by vip-substitute-line
1138(defun vip-exec-Change (m-com com)
1139 (save-excursion
1140 (set-mark vip-com-point)
1141 (vip-enlarge-region (mark t) (point))
1142 (if vip-use-register
1143 (progn
1144 (cond ((vip-valid-register vip-use-register '(letter digit))
1145 ;;(vip-valid-register vip-use-register '(letter)
1146 (copy-to-register
1147 vip-use-register (mark t) (point) nil))
1148 ((vip-valid-register vip-use-register '(Letter))
1149 (vip-append-to-register
1150 (downcase vip-use-register) (mark t) (point)))
1151 (t (setq vip-use-register nil)
1152 (error vip-InvalidRegister vip-use-register)))
1153 (setq vip-use-register nil)))
1154 (delete-region (mark t) (point)))
1155 (open-line 1)
1156 (if (= com ?C) (vip-change-mode-to-insert) (vip-yank-last-insertion)))
1157
1158(defun vip-exec-delete (m-com com)
1159 (or (and (markerp vip-com-point) (marker-position vip-com-point))
1160 (set-marker vip-com-point (point) (current-buffer)))
1161 (if vip-use-register
1162 (progn
1163 (cond ((vip-valid-register vip-use-register '(letter digit))
1164 ;;(vip-valid-register vip-use-register '(letter))
1165 (copy-to-register
1166 vip-use-register vip-com-point (point) nil))
1167 ((vip-valid-register vip-use-register '(Letter))
1168 (vip-append-to-register
1169 (downcase vip-use-register) vip-com-point (point)))
1170 (t (setq vip-use-register nil)
1171 (error vip-InvalidRegister vip-use-register)))
1172 (setq vip-use-register nil)))
1173 (setq last-command
1174 (if (eq last-command 'd-command) 'kill-region nil))
1175 (kill-region vip-com-point (point))
1176 (setq this-command 'd-command)
1177 (if vip-ex-style-motion
1178 (if (and (eolp) (not (bolp))) (backward-char 1))))
1179
1180(defun vip-exec-Delete (m-com com)
1181 (save-excursion
1182 (set-mark vip-com-point)
1183 (vip-enlarge-region (mark t) (point))
1184 (if vip-use-register
1185 (progn
1186 (cond ((vip-valid-register vip-use-register '(letter digit))
1187 ;;(vip-valid-register vip-use-register '(letter))
1188 (copy-to-register
1189 vip-use-register (mark t) (point) nil))
1190 ((vip-valid-register vip-use-register '(Letter))
1191 (vip-append-to-register
1192 (downcase vip-use-register) (mark t) (point)))
1193 (t (setq vip-use-register nil)
1194 (error vip-InvalidRegister vip-use-register)))
1195 (setq vip-use-register nil)))
1196 (setq last-command
1197 (if (eq last-command 'D-command) 'kill-region nil))
1198 (kill-region (mark t) (point))
1199 (if (eq m-com 'vip-line) (setq this-command 'D-command)))
1200 (back-to-indentation))
1201
1202(defun vip-exec-yank (m-com com)
1203 (or (and (markerp vip-com-point) (marker-position vip-com-point))
1204 (set-marker vip-com-point (point) (current-buffer)))
1205 (if vip-use-register
1206 (progn
1207 (cond ((vip-valid-register vip-use-register '(letter digit))
1208 ;; (vip-valid-register vip-use-register '(letter))
1209 (copy-to-register
1210 vip-use-register vip-com-point (point) nil))
1211 ((vip-valid-register vip-use-register '(Letter))
1212 (vip-append-to-register
1213 (downcase vip-use-register) vip-com-point (point)))
1214 (t (setq vip-use-register nil)
1215 (error vip-InvalidRegister vip-use-register)))
1216 (setq vip-use-register nil)))
1217 (setq last-command nil)
1218 (copy-region-as-kill vip-com-point (point))
1219 (goto-char vip-com-point))
1220
1221(defun vip-exec-Yank (m-com com)
1222 (save-excursion
1223 (set-mark vip-com-point)
1224 (vip-enlarge-region (mark t) (point))
1225 (if vip-use-register
1226 (progn
1227 (cond ((vip-valid-register vip-use-register '(letter digit))
1228 (copy-to-register
1229 vip-use-register (mark t) (point) nil))
1230 ((vip-valid-register vip-use-register '(Letter))
1231 (vip-append-to-register
1232 (downcase vip-use-register) (mark t) (point)))
1233 (t (setq vip-use-register nil)
1234 (error vip-InvalidRegister vip-use-register)))
1235 (setq vip-use-register nil)))
1236 (setq last-command nil)
1237 (copy-region-as-kill (mark t) (point)))
1238 (vip-deactivate-mark)
1239 (goto-char vip-com-point))
1240
1241(defun vip-exec-bang (m-com com)
1242 (save-excursion
1243 (set-mark vip-com-point)
1244 (vip-enlarge-region (mark t) (point))
1245 (shell-command-on-region
1246 (mark t) (point)
1247 (if (= com ?!)
1248 (setq vip-last-shell-com
1249 (vip-read-string-with-history
1250 "!"
1251 nil
1252 'vip-shell-history
1253 (car vip-shell-history)
1254 ))
1255 vip-last-shell-com)
1256 t)))
1257
1258(defun vip-exec-equals (m-com com)
1259 (save-excursion
1260 (set-mark vip-com-point)
1261 (vip-enlarge-region (mark t) (point))
1262 (if (> (mark t) (point)) (exchange-point-and-mark))
1263 (indent-region (mark t) (point) nil)))
1264
1265(defun vip-exec-shift (m-com com)
1266 (save-excursion
1267 (set-mark vip-com-point)
1268 (vip-enlarge-region (mark t) (point))
1269 (if (> (mark t) (point)) (exchange-point-and-mark))
1270 (indent-rigidly (mark t) (point)
1271 (if (= com ?>)
1272 vip-shift-width
1273 (- vip-shift-width))))
1274 ;; return point to where it was before shift
1275 (goto-char vip-com-point))
1276
1277;; this is needed because some commands fake com by setting it to ?r, which
1278;; denotes repeated insert command.
1279(defsubst vip-exec-dummy (m-com com)
1280 nil)
1281
1282(defun vip-exec-buffer-search (m-com com)
1283 (setq vip-s-string (buffer-substring (point) vip-com-point))
1284 (setq vip-s-forward t)
1285 (setq vip-search-history (cons vip-s-string vip-search-history))
1286 (vip-search vip-s-string vip-s-forward 1))
1287
1288(defvar vip-exec-array (make-vector 128 nil))
1289
1290;; Using a dispatch array allows adding functions like buffer search
1291;; without affecting other functions. Buffer search can now be bound
1292;; to any character.
1293
1294(aset vip-exec-array ?c 'vip-exec-change)
1295(aset vip-exec-array ?C 'vip-exec-Change)
1296(aset vip-exec-array ?d 'vip-exec-delete)
1297(aset vip-exec-array ?D 'vip-exec-Delete)
1298(aset vip-exec-array ?y 'vip-exec-yank)
1299(aset vip-exec-array ?Y 'vip-exec-Yank)
1300(aset vip-exec-array ?r 'vip-exec-dummy)
1301(aset vip-exec-array ?! 'vip-exec-bang)
1302(aset vip-exec-array ?< 'vip-exec-shift)
1303(aset vip-exec-array ?> 'vip-exec-shift)
1304(aset vip-exec-array ?= 'vip-exec-equals)
1305
1306
1307
1308;; This function is called by various movement commands to execute a
1309;; destructive command on the region specified by the movement command. For
1310;; instance, if the user types cw, then the command vip-forward-word will
1311;; call vip-execute-com to execute vip-exec-change, which eventually will
1312;; call vip-change to invoke the replace mode on the region.
1313;;
1314;; The list (M-COM VAL COM REG INSETED-TEXT COMMAND-KEYS) is set to
1315;; vip-d-com for later use by vip-repeat.
1316(defun vip-execute-com (m-com val com)
1317 (let ((reg vip-use-register))
1318 ;; this is the special command `#'
1319 (if (> com 128)
1320 (vip-special-prefix-com (- com 128))
1321 (let ((fn (aref vip-exec-array (if (< com 0) (- com) com))))
1322 (if (null fn)
1323 (error "%c: %s" com vip-InvalidViCommand)
1324 (funcall fn m-com com))))
1325 (if (vip-dotable-command-p com)
1326 (vip-set-destructive-command
1327 (list m-com val
1328 (if (memq com (list ?c ?C ?!)) (- com) com)
1329 reg nil nil)))
1330 ))
1331
1332
1333(defun vip-repeat (arg)
1334 "Re-execute last destructive command.
1335Use the info in vip-d-com, which has the form
1336\(com val ch reg inserted-text command-keys\),
1337where `com' is the command to be re-executed, `val' is the
1338argument to `com', `ch' is a flag for repeat, and `reg' is optional;
1339if it exists, it is the name of the register for `com'.
1340If the prefix argument, ARG, is non-nil, it is used instead of `val'."
1341 (interactive "P")
1342 (let ((save-point (point)) ; save point before repeating prev cmd
1343 ;; Pass along that we are repeating a destructive command
1344 ;; This tells vip-set-destructive-command not to update
1345 ;; vip-command-ring
1346 (vip-intermediate-command 'vip-repeat))
1347 (if (eq last-command 'vip-undo)
1348 ;; if the last command was vip-undo, then undo-more
1349 (vip-undo-more)
1350 ;; otherwise execute the command stored in vip-d-com. if arg is non-nil
1351 ;; its prefix value is used as new prefix value for the command.
1352 (let ((m-com (car vip-d-com))
1353 (val (vip-P-val arg))
1354 (com (nth 2 vip-d-com))
1355 (reg (nth 3 vip-d-com)))
1356 (if (null val) (setq val (nth 1 vip-d-com)))
1357 (if (null m-com) (error "No previous command to repeat."))
1358 (setq vip-use-register reg)
1359 (if (nth 4 vip-d-com) ; text inserted by command
1360 (setq vip-last-insertion (nth 4 vip-d-com)
1361 vip-d-char (nth 4 vip-d-com)))
1362 (funcall m-com (cons val com))
1e70790f
MK
1363 (cond ((and (< save-point (point)) vip-keep-point-on-repeat)
1364 (goto-char save-point)) ; go back to before repeat.
1365 ((and (< save-point (point)) vip-ex-style-editing-in-insert)
1366 (or (bolp) (backward-char 1))))
d5e52f99
MK
1367 (if (and (eolp) (not (bolp)))
1368 (backward-char 1))
1369 ))
1370 (if vip-undo-needs-adjustment (vip-adjust-undo)) ; take care of undo
1371 ;; If the prev cmd was rotating the command ring, this means that `.' has
1372 ;; just executed a command from that ring. So, push it on the ring again.
1373 ;; If we are just executing previous command , then don't push vip-d-com
1374 ;; because vip-d-com is not fully constructed in this case (its keys and
1375 ;; the inserted text may be nil). Besides, in this case, the command
1376 ;; executed by `.' is already on the ring.
1377 (if (eq last-command 'vip-display-current-destructive-command)
1378 (vip-push-onto-ring vip-d-com 'vip-command-ring))
1379 (vip-deactivate-mark)
1380 ))
1381
1382(defun vip-repeat-from-history ()
1383 "Repeat a destructive command from history.
1384Doesn't change vip-command-ring in any way, so `.' will work as before
1385executing this command.
1386This command is supposed to be bound to a two-character Vi macro where
1387the second character is a digit 0 to 9. The digit indicates which
1388history command to execute. `<char>0' is equivalent to `.', `<char>1'
1389invokes the command before that, etc."
1390 (interactive)
1391 (let* ((vip-intermediate-command 'repeating-display-destructive-command)
1392 (idx (cond (vip-this-kbd-macro
1393 (string-to-number
1394 (symbol-name (elt vip-this-kbd-macro 1))))
1395 (t 0)))
1396 (num idx)
1397 (vip-d-com vip-d-com))
1398
1399 (or (and (numberp num) (<= 0 num) (<= num 9))
1400 (progn
1401 (setq idx 0
1402 num 0)
1403 (message
1404 "`vip-repeat-from-history' must be invoked as a Vi macro bound to `<key><digit>'")))
1405 (while (< 0 num)
1406 (setq vip-d-com (vip-special-ring-rotate1 vip-command-ring -1))
1407 (setq num (1- num)))
1408 (vip-repeat nil)
1409 (while (> idx num)
1410 (vip-special-ring-rotate1 vip-command-ring 1)
1411 (setq num (1+ num)))
1412 ))
1413
1414
1415;; The hash-command. It is invoked interactively by the key sequence #<char>.
1416;; The chars that can follow `#' are determined by vip-hash-command-p
1417(defun vip-special-prefix-com (char)
1418 (cond ((= char ?c)
1419 (downcase-region (min vip-com-point (point))
1420 (max vip-com-point (point))))
1421 ((= char ?C)
1422 (upcase-region (min vip-com-point (point))
1423 (max vip-com-point (point))))
1424 ((= char ?g)
1425 (push-mark vip-com-point t)
1426 (vip-global-execute))
1427 ((= char ?q)
1428 (push-mark vip-com-point t)
1429 (vip-quote-region))
1430 ((= char ?s) (funcall vip-spell-function vip-com-point (point)))
1431 (t (error "#%c: %s" char vip-InvalidViCommand))))
1432
1433\f
1434;; undoing
1435
1436(defun vip-undo ()
1437 "Undo previous change."
1438 (interactive)
1439 (message "undo!")
1440 (let ((modified (buffer-modified-p))
1441 (before-undo-pt (point-marker))
1442 (after-change-functions after-change-functions)
1443 undo-beg-posn undo-end-posn)
1444
1445 ;; no need to remove this hook, since this var has scope inside a let.
1446 (add-hook 'after-change-functions
1447 '(lambda (beg end len)
1448 (setq undo-beg-posn beg
1449 undo-end-posn (or end beg))))
1450
1451 (undo-start)
1452 (undo-more 2)
1453 (setq undo-beg-posn (or undo-beg-posn before-undo-pt)
1454 undo-end-posn (or undo-end-posn undo-beg-posn))
1455
1456 (goto-char undo-beg-posn)
1457 (sit-for 0)
1458 (if (and vip-keep-point-on-undo
1459 (pos-visible-in-window-p before-undo-pt))
1460 (progn
1461 (push-mark (point-marker) t)
1462 (vip-sit-for-short 300)
1463 (goto-char undo-end-posn)
1464 (vip-sit-for-short 300)
1465 (if (and (> (abs (- undo-beg-posn before-undo-pt)) 1)
1466 (> (abs (- undo-end-posn before-undo-pt)) 1))
1467 (goto-char before-undo-pt)
1468 (goto-char undo-beg-posn)))
1469 (push-mark before-undo-pt t))
1470 (if (and (eolp) (not (bolp))) (backward-char 1))
1471 (if (not modified) (set-buffer-modified-p t)))
1472 (setq this-command 'vip-undo))
1473
1474;; Continue undoing previous changes.
1475(defun vip-undo-more ()
1476 (message "undo more!")
1477 (condition-case nil
1478 (undo-more 1)
1479 (error (beep)
1480 (message "No further undo information in this buffer")))
1481 (if (and (eolp) (not (bolp))) (backward-char 1))
1482 (setq this-command 'vip-undo))
1483
1484;; The following two functions are used to set up undo properly.
1485;; In VI, unlike Emacs, if you open a line, say, and add a bunch of lines,
1486;; they are undone all at once.
1487(defun vip-adjust-undo ()
1488 (let ((inhibit-quit t)
1489 tmp tmp2)
1490 (setq vip-undo-needs-adjustment nil)
1491 (if (listp buffer-undo-list)
1492 (if (setq tmp (memq vip-buffer-undo-list-mark buffer-undo-list))
1493 (progn
1494 (setq tmp2 (cdr tmp)) ; the part after mark
1495
1496 ;; cut tail from buffer-undo-list temporarily by direct
1497 ;; manipulation with pointers in buffer-undo-list
1498 (setcdr tmp nil)
1499
1500 (setq buffer-undo-list (delq nil buffer-undo-list))
1501 (setq buffer-undo-list
1502 (delq vip-buffer-undo-list-mark buffer-undo-list))
1503 ;; restore tail of buffer-undo-list
1504 (setq buffer-undo-list (nconc buffer-undo-list tmp2)))
1505 (setq buffer-undo-list (delq nil buffer-undo-list))))))
1506
1507
1508(defun vip-set-complex-command-for-undo ()
1509 (if (listp buffer-undo-list)
1510 (if (not vip-undo-needs-adjustment)
1511 (let ((inhibit-quit t))
1512 (setq buffer-undo-list
1513 (cons vip-buffer-undo-list-mark buffer-undo-list))
1514 (setq vip-undo-needs-adjustment t)))))
1515
1516
1517
1518
1519(defun vip-display-current-destructive-command ()
1520 (let ((text (nth 4 vip-d-com))
1521 (keys (nth 5 vip-d-com))
1522 (max-text-len 30))
1523
1524 (setq this-command 'vip-display-current-destructive-command)
1525
1526 (message " `.' runs %s%s"
1527 (concat "`" (vip-array-to-string keys) "'")
1528 (vip-abbreviate-string text max-text-len
1529 " inserting `" "'" " ......."))
1530 ))
1531
1532
1533;; don't change vip-d-com if it was vip-repeat command invoked with `.'
1534;; or in some other way (non-interactively).
1535(defun vip-set-destructive-command (list)
1536 (or (eq vip-intermediate-command 'vip-repeat)
1537 (progn
1538 (setq vip-d-com list)
1539 (setcar (nthcdr 5 vip-d-com)
1540 (vip-array-to-string (this-command-keys)))
1541 (vip-push-onto-ring vip-d-com 'vip-command-ring))))
1542
1543(defun vip-prev-destructive-command (next)
1544 "Find previous destructive command in the history of destructive commands.
1545With prefix argument, find next destructive command."
1546 (interactive "P")
1547 (let (cmd vip-intermediate-command)
1548 (if (eq last-command 'vip-display-current-destructive-command)
1549 ;; repeated search through command history
1550 (setq vip-intermediate-command 'repeating-display-destructive-command)
1551 ;; first search through command history--set temp ring
1552 (setq vip-temp-command-ring (copy-list vip-command-ring)))
1553 (setq cmd (if next
1554 (vip-special-ring-rotate1 vip-temp-command-ring 1)
1555 (vip-special-ring-rotate1 vip-temp-command-ring -1)))
1556 (if (null cmd)
1557 ()
1558 (setq vip-d-com cmd))
1559 (vip-display-current-destructive-command)))
1560
1561(defun vip-next-destructive-command ()
1562 "Find next destructive command in the history of destructive commands."
1563 (interactive)
1564 (vip-prev-destructive-command 'next))
1565
1566(defun vip-insert-prev-from-insertion-ring (arg)
1567 "Cycle through insertion ring in the direction of older insertions.
1568Undoes previous insertion and inserts new.
1569With prefix argument, cycles in the direction of newer elements.
1570In minibuffer, this command executes whatever the invocation key is bound
1571to in the global map, instead of cycling through the insertion ring."
1572 (interactive "P")
1573 (let (vip-intermediate-command)
1574 (if (eq last-command 'vip-insert-from-insertion-ring)
1575 (progn ; repeated search through insertion history
1576 (setq vip-intermediate-command 'repeating-insertion-from-ring)
1577 (if (eq vip-current-state 'replace-state)
1578 (undo 1)
1579 (if vip-last-inserted-string-from-insertion-ring
1580 (backward-delete-char
1581 (length vip-last-inserted-string-from-insertion-ring))))
1582 )
1583 ;;first search through insertion history
1584 (setq vip-temp-insertion-ring (copy-list vip-insertion-ring)))
1585 (setq this-command 'vip-insert-from-insertion-ring)
1586 ;; so that things will be undone properly
1587 (setq buffer-undo-list (cons nil buffer-undo-list))
1588 (setq vip-last-inserted-string-from-insertion-ring
1589 (vip-special-ring-rotate1 vip-temp-insertion-ring (if arg 1 -1)))
1590
1591 ;; this change of vip-intermediate-command must come after
1592 ;; vip-special-ring-rotate1, so that the ring will rotate, but before the
1593 ;; insertion.
1594 (setq vip-intermediate-command nil)
1595 (if vip-last-inserted-string-from-insertion-ring
1596 (insert vip-last-inserted-string-from-insertion-ring))
1597 ))
1598
1599(defun vip-insert-next-from-insertion-ring ()
1600 "Cycle through insertion ring in the direction of older insertions.
1601Undo previous insertion and inserts new."
1602 (interactive)
1603 (vip-insert-prev-from-insertion-ring 'next))
1604
1605\f
1606;; some region utilities
1607
1608;; If at the last line of buffer, add \\n before eob, if newline is missing.
1609(defun vip-add-newline-at-eob-if-necessary ()
1610 (save-excursion
1611 (end-of-line)
1612 ;; make sure all lines end with newline, unless in the minibuffer or
1613 ;; when requested otherwise (require-final-newline is nil)
1614 (if (and (eobp)
1615 (not (bolp))
1616 require-final-newline
1617 (not (vip-is-in-minibuffer))
1618 (not buffer-read-only))
1619 (insert "\n"))))
1620
1621(defun vip-yank-defun ()
1622 (mark-defun)
1623 (copy-region-as-kill (point) (mark t)))
1624
1625;; Enlarge region between BEG and END.
1626(defun vip-enlarge-region (beg end)
1627 (or beg (setq beg end)) ; if beg is nil, set to end
1628 (or end (setq end beg)) ; if end is nil, set to beg
1629
1630 (if (< beg end)
1631 (progn (goto-char beg) (set-mark end))
1632 (goto-char end)
1633 (set-mark beg))
1634 (beginning-of-line)
1635 (exchange-point-and-mark)
1636 (if (or (not (eobp)) (not (bolp))) (forward-line 1))
1637 (if (not (eobp)) (beginning-of-line))
1638 (if (> beg end) (exchange-point-and-mark)))
1639
1640
1641;; Quote region by each line with a user supplied string.
1642(defun vip-quote-region ()
1643 (setq vip-quote-string
1644 (vip-read-string-with-history
1645 "Quote string: "
1646 nil
1647 'vip-quote-region-history
1648 vip-quote-string))
1649 (vip-enlarge-region (point) (mark t))
1650 (if (> (point) (mark t)) (exchange-point-and-mark))
1651 (insert vip-quote-string)
1652 (beginning-of-line)
1653 (forward-line 1)
1654 (while (and (< (point) (mark t)) (bolp))
1655 (insert vip-quote-string)
1656 (beginning-of-line)
1657 (forward-line 1)))
1658
1659;; Tells whether BEG is on the same line as END.
1660;; If one of the args is nil, it'll return nil.
1661(defun vip-same-line (beg end)
1662 (let ((selective-display nil)
1663 (incr 0)
1664 temp)
1665 (if (and beg end (> beg end))
1666 (setq temp beg
1667 beg end
1668 end temp))
1669 (if (and beg end)
1670 (cond ((or (> beg (point-max)) (> end (point-max))) ; out of range
1671 nil)
1672 (t
1673 ;; This 'if' is needed because Emacs treats the next empty line
1674 ;; as part of the previous line.
1675 (if (= (vip-line-pos 'start) end)
1676 (setq incr 1))
1677 (<= (+ incr (count-lines beg end)) 1))))
1678 ))
1679
1680
1681;; Check if the string ends with a newline.
1682(defun vip-end-with-a-newline-p (string)
1683 (or (string= string "")
1684 (= (vip-seq-last-elt string) ?\n)))
1685
1686(defun vip-tmp-insert-at-eob (msg)
1687 (let ((savemax (point-max)))
1688 (goto-char savemax)
1689 (insert msg)
1690 (sit-for 2)
1691 (goto-char savemax) (delete-region (point) (point-max))
1692 ))
1693
1694
1695\f
1696;;; Minibuffer business
1697
1698(defsubst vip-set-minibuffer-style ()
1699 (add-hook 'minibuffer-setup-hook 'vip-minibuffer-setup-sentinel))
1700
1701
1702(defun vip-minibuffer-setup-sentinel ()
1703 (let ((hook (if vip-vi-style-in-minibuffer
1704 'vip-change-state-to-insert
1705 'vip-change-state-to-emacs)))
1706 (funcall hook)
1707 ))
1708
1709;; Interpret last event in the local map
1710(defun vip-exit-minibuffer ()
1711 (interactive)
1712 (let (command)
1713 (setq command (local-key-binding (char-to-string last-command-char)))
1714 (if command
1715 (command-execute command)
1716 (exit-minibuffer))))
1717
1718\f
1719;;; Reading string with history
1720
1721(defun vip-read-string-with-history (prompt &optional initial
1722 history-var default keymap)
1723 ;; Read string, prompting with PROMPT and inserting the INITIAL
1724 ;; value. Uses HISTORY-VAR. DEFAULT is the default value to accept if the
1725 ;; input is an empty string. Use KEYMAP, if given, or the
1726 ;; minibuffer-local-map.
1727 ;; Default value is displayed until the user types something in the
1728 ;; minibuffer.
1729 (let ((minibuffer-setup-hook
1730 '(lambda ()
1731 (if (stringp initial)
1732 (progn
1733 ;; don't wait if we have unread events or in kbd macro
1734 (or unread-command-events
1735 executing-kbd-macro
1736 (sit-for 840))
1737 (erase-buffer)
1738 (insert initial)))
1739 (vip-minibuffer-setup-sentinel)))
1740 (val "")
1741 (padding "")
1742 temp-msg)
1743
1744 (setq keymap (or keymap minibuffer-local-map)
1745 initial (or initial "")
1746 temp-msg (if default
1747 (format "(default: %s) " default)
1748 ""))
1749
1750 (setq vip-incomplete-ex-cmd nil)
1751 (setq val (read-from-minibuffer prompt
1752 (concat temp-msg initial val padding)
1753 keymap nil history-var))
1754 (setq minibuffer-setup-hook nil
1755 padding (vip-array-to-string (this-command-keys))
1756 temp-msg "")
1757 ;; the following tries to be smart about what to put in history
1758 (if (not (string= val (car (eval history-var))))
1759 (set history-var (cons val (eval history-var))))
1760 (if (or (string= (nth 0 (eval history-var)) (nth 1 (eval history-var)))
1761 (string= (nth 0 (eval history-var)) ""))
1762 (set history-var (cdr (eval history-var))))
1763 ;; If the user enters nothing but the prev cmd wasn't vip-ex,
1764 ;; vip-command-argument, or `! shell-command', this probably means
1765 ;; that the user typed something then erased. Return "" in this case, not
1766 ;; the default---the default is too confusing in this case.
1767 (cond ((and (string= val "")
1768 (not (string= prompt "!")) ; was a `! shell-command'
1769 (not (memq last-command
1770 '(vip-ex
1771 vip-command-argument
1772 t)
1773 )))
1774 "")
1775 ((string= val "") (or default ""))
1776 (t val))
1777 ))
1778
1779
1780\f
1781;; insertion commands
1782
1783;; Called when state changes from Insert Vi command mode.
1784;; Repeats the insertion command if Insert state was entered with prefix
1785;; argument > 1.
1786(defun vip-repeat-insert-command ()
1787 (let ((i-com (car vip-d-com))
1788 (val (nth 1 vip-d-com))
1789 (char (nth 2 vip-d-com)))
1790 (if (and val (> val 1)) ; first check that val is non-nil
1791 (progn
1792 (setq vip-d-com (list i-com (1- val) ?r nil nil nil))
1793 (vip-repeat nil)
1794 (setq vip-d-com (list i-com val char nil nil nil))
1795 ))))
1796
1797(defun vip-insert (arg)
1798 "Insert before point."
1799 (interactive "P")
1800 (vip-set-complex-command-for-undo)
1801 (let ((val (vip-p-val arg))
1802 (com (vip-getcom arg)))
1803 (vip-set-destructive-command (list 'vip-insert val ?r nil nil nil))
1804 (if com
1805 (vip-loop val (vip-yank-last-insertion))
1806 (vip-change-state-to-insert))))
1807
1808(defun vip-append (arg)
1809 "Append after point."
1810 (interactive "P")
1811 (vip-set-complex-command-for-undo)
1812 (let ((val (vip-p-val arg))
1813 (com (vip-getcom arg)))
1814 (vip-set-destructive-command (list 'vip-append val ?r nil nil nil))
1815 (if (not (eolp)) (forward-char))
1816 (if (equal com ?r)
1817 (vip-loop val (vip-yank-last-insertion))
1818 (vip-change-state-to-insert))))
1819
1820(defun vip-Append (arg)
1821 "Append at end of line."
1822 (interactive "P")
1823 (vip-set-complex-command-for-undo)
1824 (let ((val (vip-p-val arg))
1825 (com (vip-getcom arg)))
1826 (vip-set-destructive-command (list 'vip-Append val ?r nil nil nil))
1827 (end-of-line)
1828 (if (equal com ?r)
1829 (vip-loop val (vip-yank-last-insertion))
1830 (vip-change-state-to-insert))))
1831
1832(defun vip-Insert (arg)
1833 "Insert before first non-white."
1834 (interactive "P")
1835 (vip-set-complex-command-for-undo)
1836 (let ((val (vip-p-val arg))
1837 (com (vip-getcom arg)))
1838 (vip-set-destructive-command (list 'vip-Insert val ?r nil nil nil))
1839 (back-to-indentation)
1840 (if (equal com ?r)
1841 (vip-loop val (vip-yank-last-insertion))
1842 (vip-change-state-to-insert))))
1843
1844(defun vip-open-line (arg)
1845 "Open line below."
1846 (interactive "P")
1847 (vip-set-complex-command-for-undo)
1848 (let ((val (vip-p-val arg))
1849 (com (vip-getcom arg)))
1850 (vip-set-destructive-command (list 'vip-open-line val ?r nil nil nil))
1851 (let ((col (current-indentation)))
1852 (if (equal com ?r)
1853 (vip-loop val
1854 (progn
1855 (end-of-line)
1856 (newline 1)
1857 (if vip-auto-indent
1858 (progn
1859 (setq vip-cted t)
1860 (if vip-electric-mode
1861 (indent-according-to-mode)
1862 (indent-to col))
1863 ))
1864 (vip-yank-last-insertion)))
1865 (end-of-line)
1866 (newline 1)
1867 (if vip-auto-indent
1868 (progn
1869 (setq vip-cted t)
1870 (if vip-electric-mode
1871 (indent-according-to-mode)
1872 (indent-to col))))
1873 (vip-change-state-to-insert)))))
1874
1875(defun vip-Open-line (arg)
1876 "Open line above."
1877 (interactive "P")
1878 (vip-set-complex-command-for-undo)
1879 (let ((val (vip-p-val arg))
1880 (com (vip-getcom arg)))
1881 (vip-set-destructive-command (list 'vip-Open-line val ?r nil nil nil))
1882 (let ((col (current-indentation)))
1883 (if (equal com ?r)
1884 (vip-loop val
1885 (progn
1886 (beginning-of-line)
1887 (open-line 1)
1888 (if vip-auto-indent
1889 (progn
1890 (setq vip-cted t)
1891 (if vip-electric-mode
1892 (indent-according-to-mode)
1893 (indent-to col))
1894 ))
1895 (vip-yank-last-insertion)))
1896 (beginning-of-line)
1897 (open-line 1)
1898 (if vip-auto-indent
1899 (progn
1900 (setq vip-cted t)
1901 (if vip-electric-mode
1902 (indent-according-to-mode)
1903 (indent-to col))
1904 ))
1905 (vip-change-state-to-insert)))))
1906
1907(defun vip-open-line-at-point (arg)
1908 "Open line at point."
1909 (interactive "P")
1910 (vip-set-complex-command-for-undo)
1911 (let ((val (vip-p-val arg))
1912 (com (vip-getcom arg)))
1913 (vip-set-destructive-command
1914 (list 'vip-open-line-at-point val ?r nil nil nil))
1915 (if (equal com ?r)
1916 (vip-loop val
1917 (progn
1918 (open-line 1)
1919 (vip-yank-last-insertion)))
1920 (open-line 1)
1921 (vip-change-state-to-insert))))
1922
1923(defun vip-substitute (arg)
1924 "Substitute characters."
1925 (interactive "P")
1926 (let ((val (vip-p-val arg))
1927 (com (vip-getcom arg)))
1928 (push-mark nil t)
1929 (forward-char val)
1930 (if (equal com ?r)
1931 (vip-change-subr (mark t) (point))
1932 (vip-change (mark t) (point)))
1933 (vip-set-destructive-command (list 'vip-substitute val ?r nil nil nil))
1934 ))
1935
1936(defun vip-substitute-line (arg)
1937 "Substitute lines."
1938 (interactive "p")
1939 (vip-set-complex-command-for-undo)
1940 (vip-line (cons arg ?C)))
1941
1942;; Prepare for replace
1943(defun vip-start-replace ()
1944 (setq vip-began-as-replace t
1945 vip-sitting-in-replace t
1946 vip-replace-chars-to-delete 0
1947 vip-replace-chars-deleted 0)
1948 (vip-add-hook 'vip-after-change-functions 'vip-replace-mode-spy-after t)
1949 (vip-add-hook 'vip-before-change-functions 'vip-replace-mode-spy-before t)
1950 ;; this will get added repeatedly, but no harm
1951 (add-hook 'after-change-functions 'vip-after-change-sentinel t)
1952 (add-hook 'before-change-functions 'vip-before-change-sentinel t)
1953 (vip-move-marker-locally 'vip-last-posn-in-replace-region
1954 (vip-replace-start))
1955 (vip-add-hook
1956 'vip-post-command-hooks 'vip-replace-state-post-command-sentinel t)
1957 (vip-add-hook
1958 'vip-pre-command-hooks 'vip-replace-state-pre-command-sentinel t)
1959 ;; guard against a smartie who switched from R-replace to normal replace
1960 (vip-remove-hook
1961 'vip-post-command-hooks 'vip-R-state-post-command-sentinel)
1962 (if overwrite-mode (overwrite-mode nil))
1963 )
1964
1965
1966;; checks how many chars were deleted by the last change
1967(defun vip-replace-mode-spy-before (beg end)
1968 (setq vip-replace-chars-deleted
1969 (- end beg
1970 (max 0 (- end (vip-replace-end)))
1971 (max 0 (- (vip-replace-start) beg))
1972 )))
1973
1974;; Invoked as an after-change-function to set up parameters of the last change
1975(defun vip-replace-mode-spy-after (beg end length)
1976 (if (memq vip-intermediate-command '(repeating-insertion-from-ring))
1977 (progn
1978 (setq vip-replace-chars-to-delete 0)
1979 (vip-move-marker-locally
1980 'vip-last-posn-in-replace-region (point)))
1981
1982 (let (beg-col end-col real-end chars-to-delete)
1983 (setq real-end (min end (vip-replace-end)))
1984 (save-excursion
1985 (goto-char beg)
1986 (setq beg-col (current-column))
1987 (goto-char real-end)
1988 (setq end-col (current-column)))
1989
1990 ;; If beg of change is outside the replacement region, then don't
1991 ;; delete anything in the repl region (set chars-to-delete to 0).
1992 ;;
1993 ;; This works fine except that we have to take special care of
1994 ;; dabbrev-expand. The problem stems from new-dabbrev.el, which
1995 ;; sometimes simply shifts the repl region rightwards, without
1996 ;; deleting an equal amount of characters.
1997 ;;
1998 ;; The reason why new-dabbrev.el causes this are this:
1999 ;; if one dinamically completes a partial word that starts before the
2000 ;; replacement region (but ends inside) then new-dabbrev.el first
2001 ;; moves cursor backwards, to the beginning of the word to be
2002 ;; completed (say, pt A). Then it inserts the
2003 ;; completed word and then deletes the old, incomplete part.
2004 ;; Since the complete word is inserted at position before the repl
2005 ;; region, the next If-statement would have set chars-to-delete to 0
2006 ;; unless we check for the current command, which must be
2007 ;; dabbrev-expand.
2008 ;;
2009 ;; In fact, it might be also useful to have overlays for insert
2010 ;; regions as well, since this will let us capture the situation when
2011 ;; dabbrev-expand goes back past the insertion point to find the
2012 ;; beginning of the word to be expanded.
2013 (if (or (and (<= (vip-replace-start) beg)
2014 (<= beg (vip-replace-end)))
2015 (and (= length 0) (eq this-command 'dabbrev-expand)))
2016 (setq chars-to-delete
2017 (max (- end-col beg-col) (- real-end beg) 0))
2018 (setq chars-to-delete 0))
2019
2020 ;; if beg = last change position, it means that we are within the
2021 ;; same command that does multiple changes. Moreover, it means
2022 ;; that we have two subsequent changes (insert/delete) that
2023 ;; complement each other.
2024 (if (= beg (marker-position vip-last-posn-in-replace-region))
2025 (setq vip-replace-chars-to-delete
2026 (- (+ chars-to-delete vip-replace-chars-to-delete)
2027 vip-replace-chars-deleted))
2028 (setq vip-replace-chars-to-delete chars-to-delete))
2029
2030 (vip-move-marker-locally
2031 'vip-last-posn-in-replace-region
2032 (max (if (> end (vip-replace-end)) (vip-replace-start) end)
2033 (or (marker-position vip-last-posn-in-replace-region)
2034 (vip-replace-start))
2035 ))
2036
2037 (setq vip-replace-chars-to-delete
2038 (max 0
2039 (min vip-replace-chars-to-delete
2040 (- (vip-replace-end) vip-last-posn-in-replace-region)
2041 (- (vip-line-pos 'end) vip-last-posn-in-replace-region)
2042 )))
2043 )))
2044
2045
2046;; Delete stuff between posn and the end of vip-replace-overlay-marker, if
2047;; posn is within the overlay.
2048(defun vip-finish-change (posn)
2049 (vip-remove-hook 'vip-after-change-functions 'vip-replace-mode-spy-after)
2050 (vip-remove-hook 'vip-before-change-functions 'vip-replace-mode-spy-before)
2051 (vip-remove-hook 'vip-post-command-hooks
2052 'vip-replace-state-post-command-sentinel)
2053 (vip-remove-hook
2054 'vip-pre-command-hooks 'vip-replace-state-pre-command-sentinel)
2055 (vip-restore-cursor-color-after-replace)
2056 (setq vip-sitting-in-replace nil) ; just in case we'll need to know it
2057 (save-excursion
2058 (if (and
2059 vip-replace-overlay
2060 (>= posn (vip-replace-start))
2061 (< posn (vip-replace-end)))
2062 (delete-region posn (vip-replace-end)))
2063 )
2064
2065 (if (eq vip-current-state 'replace-state)
2066 (vip-downgrade-to-insert))
2067 ;; replace mode ended => nullify vip-last-posn-in-replace-region
2068 (vip-move-marker-locally 'vip-last-posn-in-replace-region nil)
2069 (vip-hide-replace-overlay)
2070 (vip-refresh-mode-line)
2071 (vip-put-string-on-kill-ring vip-last-replace-region)
2072 )
2073
2074;; Make STRING be the first element of the kill ring.
2075(defun vip-put-string-on-kill-ring (string)
2076 (setq kill-ring (cons string kill-ring))
2077 (if (> (length kill-ring) kill-ring-max)
2078 (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil))
2079 (setq kill-ring-yank-pointer kill-ring))
2080
2081(defun vip-finish-R-mode ()
2082 (vip-remove-hook 'vip-post-command-hooks 'vip-R-state-post-command-sentinel)
2083 (vip-remove-hook
2084 'vip-pre-command-hooks 'vip-replace-state-pre-command-sentinel)
2085 (vip-downgrade-to-insert))
2086
2087(defun vip-start-R-mode ()
2088 ;; Leave arg as 1, not t: XEmacs insists that it must be a pos number
2089 (overwrite-mode 1)
2090 (vip-add-hook
2091 'vip-post-command-hooks 'vip-R-state-post-command-sentinel t)
2092 (vip-add-hook
2093 'vip-pre-command-hooks 'vip-replace-state-pre-command-sentinel t)
2094 ;; guard against a smartie who switched from R-replace to normal replace
2095 (vip-remove-hook
2096 'vip-post-command-hooks 'vip-replace-state-post-command-sentinel)
2097 )
2098
2099
2100
2101(defun vip-replace-state-exit-cmd ()
2102 "Binding for keys that cause Replace state to switch to Vi or to Insert.
2103These keys are ESC, RET, and LineFeed"
2104 (interactive)
2105 (if overwrite-mode ;; If you are in replace mode invoked via 'R'
2106 (vip-finish-R-mode)
2107 (vip-finish-change vip-last-posn-in-replace-region))
2108 (let (com)
2109 (if (eq this-command 'vip-intercept-ESC-key)
2110 (setq com 'vip-exit-insert-state)
2111 (vip-set-unread-command-events last-input-char)
2112 (setq com (key-binding (read-key-sequence nil))))
2113
2114 (condition-case conds
2115 (command-execute com)
2116 (error
2117 (vip-message-conditions conds)))
2118 )
2119 (vip-hide-replace-overlay))
2120
2121(defun vip-replace-state-carriage-return ()
2122 "Implements carriage return in Viper replace state."
2123 (interactive)
2124 ;; If Emacs start supporting overlay maps, as it currently supports
2125 ;; text-property maps, we could do away with vip-replace-minor-mode and
2126 ;; just have keymap attached to replace overlay. Then the "if part" of this
2127 ;; statement can be deleted.
2128 (if (or (< (point) (vip-replace-start))
2129 (> (point) (vip-replace-end)))
2130 (let (vip-replace-minor-mode com)
2131 (vip-set-unread-command-events last-input-char)
2132 (setq com (key-binding (read-key-sequence nil)))
2133 (condition-case conds
2134 (command-execute com)
2135 (error
2136 (vip-message-conditions conds))))
2137 (if (not vip-allow-multiline-replace-regions)
2138 (vip-replace-state-exit-cmd)
2139 (if (vip-same-line (point) (vip-replace-end))
2140 (vip-replace-state-exit-cmd)
2141 (vip-kill-line nil)
2142 (vip-next-line-at-bol nil)))))
2143
2144
2145;; This is the function bound to 'R'---unlimited replace.
2146;; Similar to Emacs's own overwrite-mode.
2147(defun vip-overwrite (arg)
2148 "Begin overwrite mode."
2149 (interactive "P")
2150 (let ((val (vip-p-val arg))
2151 (com (vip-getcom arg)) (len))
2152 (vip-set-destructive-command (list 'vip-overwrite val ?r nil nil nil))
2153 (if com
2154 (progn
2155 ;; Viper saves inserted text in vip-last-insertion
2156 (setq len (length vip-last-insertion))
2157 (delete-char len)
2158 (vip-loop val (vip-yank-last-insertion)))
2159 (setq last-command 'vip-overwrite)
2160 (vip-set-complex-command-for-undo)
2161 (vip-set-replace-overlay (point) (vip-line-pos 'end))
2162 (vip-change-state-to-replace)
2163 )))
2164
2165\f
2166;; line commands
2167
2168(defun vip-line (arg)
2169 (let ((val (car arg))
2170 (com (cdr arg)))
2171 (vip-move-marker-locally 'vip-com-point (point))
2172 (if (not (eobp))
2173 (vip-next-line-carefully (1- val)))
2174 ;; this ensures that dd, cc, D, yy will do the right thing on the last
2175 ;; line of buffer when this line has no \n.
2176 (vip-add-newline-at-eob-if-necessary)
2177 (vip-execute-com 'vip-line val com))
2178 (if (and (eobp) (not (bobp))) (forward-line -1))
2179 )
2180
2181(defun vip-yank-line (arg)
2182 "Yank ARG lines (in Vi's sense)."
2183 (interactive "P")
2184 (let ((val (vip-p-val arg)))
2185 (vip-line (cons val ?Y))))
2186
2187\f
2188;; region commands
2189
2190(defun vip-region (arg)
2191 "Execute command on a region."
2192 (interactive "P")
2193 (let ((val (vip-P-val arg))
2194 (com (vip-getcom arg)))
2195 (vip-move-marker-locally 'vip-com-point (point))
2196 (exchange-point-and-mark)
2197 (vip-execute-com 'vip-region val com)))
2198
2199(defun vip-Region (arg)
2200 "Execute command on a Region."
2201 (interactive "P")
2202 (let ((val (vip-P-val arg))
2203 (com (vip-getCom arg)))
2204 (vip-move-marker-locally 'vip-com-point (point))
2205 (exchange-point-and-mark)
2206 (vip-execute-com 'vip-Region val com)))
2207
2208(defun vip-replace-char (arg)
2209 "Replace the following ARG chars by the character read."
2210 (interactive "P")
2211 (if (and (eolp) (bolp)) (error "No character to replace here"))
2212 (let ((val (vip-p-val arg))
2213 (com (vip-getcom arg)))
2214 (vip-replace-char-subr com val)
2215 (if (and (eolp) (not (bolp))) (forward-char 1))
2216 (vip-set-destructive-command
2217 (list 'vip-replace-char val ?r nil vip-d-char nil))
2218 ))
2219
2220(defun vip-replace-char-subr (com arg)
2221 (let ((take-care-of-iso-accents
2222 (and (boundp 'iso-accents-mode) vip-automatic-iso-accents))
2223 char)
2224 (setq char (if (equal com ?r)
2225 vip-d-char
2226 (read-char)))
2227 (if (and take-care-of-iso-accents (memq char '(?' ?\" ?^ ?~)))
2228 ;; get European characters
2229 (progn
2230 (iso-accents-mode 1)
2231 (vip-set-unread-command-events char)
2232 (setq char (aref (read-key-sequence nil) 0))
2233 (iso-accents-mode -1)))
2234 (delete-char arg t)
2235 (setq vip-d-char char)
2236 (vip-loop (if (> arg 0) arg (- arg))
2237 (if (eq char ?\C-m) (insert "\n") (insert char)))
2238 (backward-char arg)))
2239
2240\f
2241;; basic cursor movement. j, k, l, h commands.
2242
2243(defun vip-forward-char (arg)
2244 "Move point right ARG characters (left if ARG negative).
2245On reaching end of line, stop and signal error."
2246 (interactive "P")
2247 (vip-leave-region-active)
2248 (let ((val (vip-p-val arg))
2249 (com (vip-getcom arg)))
2250 (if com (vip-move-marker-locally 'vip-com-point (point)))
2251 (if vip-ex-style-motion
2252 (progn
2253 ;; the boundary condition check gets weird here because
2254 ;; forward-char may be the parameter of a delete, and 'dl' works
2255 ;; just like 'x' for the last char on a line, so we have to allow
2256 ;; the forward motion before the 'vip-execute-com', but, of
2257 ;; course, 'dl' doesn't work on an empty line, so we have to
2258 ;; catch that condition before 'vip-execute-com'
2259 (if (and (eolp) (bolp)) (error "") (forward-char val))
2260 (if com (vip-execute-com 'vip-forward-char val com))
2261 (if (eolp) (progn (backward-char 1) (error ""))))
2262 (forward-char val)
2263 (if com (vip-execute-com 'vip-forward-char val com)))))
2264
2265(defun vip-backward-char (arg)
2266 "Move point left ARG characters (right if ARG negative).
2267On reaching beginning of line, stop and signal error."
2268 (interactive "P")
2269 (vip-leave-region-active)
2270 (let ((val (vip-p-val arg))
2271 (com (vip-getcom arg)))
2272 (if com (vip-move-marker-locally 'vip-com-point (point)))
2273 (if vip-ex-style-motion
2274 (progn
2275 (if (bolp) (error "") (backward-char val))
2276 (if com (vip-execute-com 'vip-backward-char val com)))
2277 (backward-char val)
2278 (if com (vip-execute-com 'vip-backward-char val com)))))
2279
2280;; Like forward-char, but doesn't move at end of buffer.
2281(defun vip-forward-char-carefully (&optional arg)
2282 (setq arg (or arg 1))
2283 (if (>= (point-max) (+ (point) arg))
2284 (forward-char arg)
2285 (goto-char (point-max))))
2286
2287;; Like backward-char, but doesn't move at end of buffer.
2288(defun vip-backward-char-carefully (&optional arg)
2289 (setq arg (or arg 1))
2290 (if (<= (point-min) (- (point) arg))
2291 (backward-char arg)
2292 (goto-char (point-min))))
2293
2294(defun vip-next-line-carefully (arg)
2295 (condition-case nil
2296 (next-line arg)
2297 (error nil)))
2298
2299
2300\f
2301;;; Word command
2302
2303;; Words are formed from alpha's and nonalphas - <sp>,\t\n are separators
2304;; for word movement. When executed with a destructive command, \n is
2305;; usually left untouched for the last word.
2306;; Viper uses syntax table to determine what is a word and what is a
2307;; separator. However, \n is always a separator. Also, if vip-syntax-preference
2308;; is 'vi, then `_' is part of the word.
2309
2310;; skip only one \n
2311(defun vip-skip-separators (forward)
2312 (if forward
2313 (progn
2314 (vip-skip-all-separators-forward 'within-line)
2315 (if (looking-at "\n")
2316 (progn
2317 (forward-char)
2318 (vip-skip-all-separators-forward 'within-line))))
2319 (vip-skip-all-separators-backward 'within-line)
2320 (backward-char)
2321 (if (looking-at "\n")
2322 (vip-skip-all-separators-backward 'within-line)
2323 (forward-char))))
2324
2325(defun vip-forward-word-kernel (val)
2326 (while (> val 0)
2327 (cond ((vip-looking-at-alpha)
2328 (vip-skip-alpha-forward "_")
2329 (vip-skip-separators t))
2330 ((vip-looking-at-separator)
2331 (vip-skip-separators t))
2332 ((not (vip-looking-at-alphasep))
2333 (vip-skip-nonalphasep-forward)
2334 (vip-skip-separators t)))
2335 (setq val (1- val))))
2336
2337;; first search backward for pat. Then skip chars backwards using aux-pat
2338(defun vip-fwd-skip (pat aux-pat lim)
2339 (if (and (save-excursion
2340 (re-search-backward pat lim t))
2341 (= (point) (match-end 0)))
2342 (goto-char (match-beginning 0)))
2343 (skip-chars-backward aux-pat lim)
2344 (if (= (point) lim)
2345 (vip-forward-char-carefully))
2346 )
2347
2348
2349(defun vip-forward-word (arg)
2350 "Forward word."
2351 (interactive "P")
2352 (vip-leave-region-active)
2353 (let ((val (vip-p-val arg))
2354 (com (vip-getcom arg)))
2355 (if com (vip-move-marker-locally 'vip-com-point (point)))
2356 (vip-forward-word-kernel val)
2357 (if com (progn
2358 (cond ((memq com (list ?c (- ?c)))
2359 (vip-fwd-skip "\n[ \t]*" " \t" vip-com-point))
2360 ;; Yank words including the whitespace, but not newline
2361 ((memq com (list ?y (- ?y)))
2362 (vip-fwd-skip "\n[ \t]*" "" vip-com-point))
2363 ((vip-dotable-command-p com)
2364 (vip-fwd-skip "\n[ \t]*" "" vip-com-point)))
2365 (vip-execute-com 'vip-forward-word val com)))))
2366
2367
2368(defun vip-forward-Word (arg)
2369 "Forward word delimited by white characters."
2370 (interactive "P")
2371 (vip-leave-region-active)
2372 (let ((val (vip-p-val arg))
2373 (com (vip-getcom arg)))
2374 (if com (vip-move-marker-locally 'vip-com-point (point)))
2375 (vip-loop val
2376 (progn
2377 (vip-skip-nonseparators 'forward)
2378 (vip-skip-separators t)))
2379 (if com (progn
2380 (cond ((memq com (list ?c (- ?c)))
2381 (vip-fwd-skip "\n[ \t]*" " \t" vip-com-point))
2382 ;; Yank words including the whitespace, but not newline
2383 ((memq com (list ?y (- ?y)))
2384 (vip-fwd-skip "\n[ \t]*" "" vip-com-point))
2385 ((vip-dotable-command-p com)
2386 (vip-fwd-skip "\n[ \t]*" "" vip-com-point)))
2387 (vip-execute-com 'vip-forward-Word val com)))))
2388
2389
2390;; this is a bit different from Vi, but Vi's end of word
2391;; makes no sense whatsoever
2392(defun vip-end-of-word-kernel ()
2393 (if (vip-end-of-word-p) (forward-char))
2394 (if (vip-looking-at-separator)
2395 (vip-skip-all-separators-forward))
2396
2397 (cond ((vip-looking-at-alpha) (vip-skip-alpha-forward "_"))
2398 ((not (vip-looking-at-alphasep)) (vip-skip-nonalphasep-forward)))
2399 (vip-backward-char-carefully))
2400
2401(defun vip-end-of-word-p ()
2402 (or (eobp)
2403 (save-excursion
2404 (cond ((vip-looking-at-alpha)
2405 (forward-char)
2406 (not (vip-looking-at-alpha)))
2407 ((not (vip-looking-at-alphasep))
2408 (forward-char)
2409 (vip-looking-at-alphasep))))))
2410
2411
2412(defun vip-end-of-word (arg &optional careful)
2413 "Move point to end of current word."
2414 (interactive "P")
2415 (vip-leave-region-active)
2416 (let ((val (vip-p-val arg))
2417 (com (vip-getcom arg)))
2418 (if com (vip-move-marker-locally 'vip-com-point (point)))
2419 (vip-loop val (vip-end-of-word-kernel))
2420 (if com
2421 (progn
2422 (forward-char)
2423 (vip-execute-com 'vip-end-of-word val com)))))
2424
2425(defun vip-end-of-Word (arg)
2426 "Forward to end of word delimited by white character."
2427 (interactive "P")
2428 (vip-leave-region-active)
2429 (let ((val (vip-p-val arg))
2430 (com (vip-getcom arg)))
2431 (if com (vip-move-marker-locally 'vip-com-point (point)))
2432 (vip-loop val
2433 (progn
2434 (vip-end-of-word-kernel)
2435 (vip-skip-nonseparators 'forward)
2436 (backward-char)))
2437 (if com
2438 (progn
2439 (forward-char)
2440 (vip-execute-com 'vip-end-of-Word val com)))))
2441
2442(defun vip-backward-word-kernel (val)
2443 (while (> val 0)
2444 (backward-char)
2445 (cond ((vip-looking-at-alpha)
2446 (vip-skip-alpha-backward "_"))
2447 ((vip-looking-at-separator)
2448 (forward-char)
2449 (vip-skip-separators nil)
2450 (backward-char)
2451 (cond ((vip-looking-at-alpha)
2452 (vip-skip-alpha-backward "_"))
2453 ((not (vip-looking-at-alphasep))
2454 (vip-skip-nonalphasep-backward))
2455 (t (forward-char))))
2456 ((not (vip-looking-at-alphasep))
2457 (vip-skip-nonalphasep-backward)))
2458 (setq val (1- val))))
2459
2460(defun vip-backward-word (arg)
2461 "Backward word."
2462 (interactive "P")
2463 (vip-leave-region-active)
2464 (let ((val (vip-p-val arg))
2465 (com (vip-getcom arg)))
2466 (if com
2467 (let (i)
2468 (if (setq i (save-excursion (backward-char) (looking-at "\n")))
2469 (backward-char))
2470 (vip-move-marker-locally 'vip-com-point (point))
2471 (if i (forward-char))))
2472 (vip-backward-word-kernel val)
2473 (if com (vip-execute-com 'vip-backward-word val com))))
2474
2475(defun vip-backward-Word (arg)
2476 "Backward word delimited by white character."
2477 (interactive "P")
2478 (vip-leave-region-active)
2479 (let ((val (vip-p-val arg))
2480 (com (vip-getcom arg)))
2481 (if com
2482 (let (i)
2483 (if (setq i (save-excursion (backward-char) (looking-at "\n")))
2484 (backward-char))
2485 (vip-move-marker-locally 'vip-com-point (point))
2486 (if i (forward-char))))
2487 (vip-loop val
2488 (progn
2489 (vip-skip-separators nil)
2490 (vip-skip-nonseparators 'backward)))
2491 (if com (vip-execute-com 'vip-backward-Word val com))))
2492
2493
2494\f
2495;; line commands
2496
2497(defun vip-beginning-of-line (arg)
2498 "Go to beginning of line."
2499 (interactive "P")
2500 (vip-leave-region-active)
2501 (let ((val (vip-p-val arg))
2502 (com (vip-getcom arg)))
2503 (if com (vip-move-marker-locally 'vip-com-point (point)))
2504 (beginning-of-line val)
2505 (if com (vip-execute-com 'vip-beginning-of-line val com))))
2506
2507(defun vip-bol-and-skip-white (arg)
2508 "Beginning of line at first non-white character."
2509 (interactive "P")
2510 (vip-leave-region-active)
2511 (let ((val (vip-p-val arg))
2512 (com (vip-getcom arg)))
2513 (if com (vip-move-marker-locally 'vip-com-point (point)))
2514 (forward-to-indentation (1- val))
2515 (if com (vip-execute-com 'vip-bol-and-skip-white val com))))
2516
2517(defun vip-goto-eol (arg)
2518 "Go to end of line."
2519 (interactive "P")
2520 (vip-leave-region-active)
2521 (let ((val (vip-p-val arg))
2522 (com (vip-getcom arg)))
2523 (if com (vip-move-marker-locally 'vip-com-point (point)))
2524 (end-of-line val)
2525 (if com (vip-execute-com 'vip-goto-eol val com))
2526 (if vip-ex-style-motion
2527 (if (and (eolp) (not (bolp))
2528 ;; a fix for vip-change-to-eol
2529 (not (equal vip-current-state 'insert-state)))
2530 (backward-char 1)
2531 ))))
2532
2533
2534(defun vip-goto-col (arg)
2535 "Go to ARG's column."
2536 (interactive "P")
2537 (vip-leave-region-active)
2538 (let ((val (vip-p-val arg))
2539 (com (vip-getcom arg))
2540 line-len)
2541 (setq line-len (- (vip-line-pos 'end) (vip-line-pos 'start)))
2542 (if com (vip-move-marker-locally 'vip-com-point (point)))
2543 (beginning-of-line)
2544 (forward-char (1- (min line-len val)))
2545 (while (> (current-column) (1- val))
2546 (backward-char 1))
2547 (if com (vip-execute-com 'vip-goto-col val com))
2548 (save-excursion
2549 (end-of-line)
2550 (if (> val (current-column)) (error "")))
2551 ))
2552
2553
2554(defun vip-next-line (arg)
2555 "Go to next line."
2556 (interactive "P")
2557 (vip-leave-region-active)
2558 (let ((val (vip-p-val arg))
2559 (com (vip-getCom arg)))
2560 (if com (vip-move-marker-locally 'vip-com-point (point)))
2561 (next-line val)
2562 (if vip-ex-style-motion
2563 (if (and (eolp) (not (bolp))) (backward-char 1)))
2564 (setq this-command 'next-line)
2565 (if com (vip-execute-com 'vip-next-line val com))))
2566
2567(defun vip-next-line-at-bol (arg)
2568 "Next line at beginning of line."
2569 (interactive "P")
2570 (vip-leave-region-active)
2571 (save-excursion
2572 (end-of-line)
2573 (if (eobp) (error "Last line in buffer")))
2574 (let ((val (vip-p-val arg))
2575 (com (vip-getCom arg)))
2576 (if com (vip-move-marker-locally 'vip-com-point (point)))
2577 (forward-line val)
2578 (back-to-indentation)
2579 (if com (vip-execute-com 'vip-next-line-at-bol val com))))
2580
2581(defun vip-previous-line (arg)
2582 "Go to previous line."
2583 (interactive "P")
2584 (vip-leave-region-active)
2585 (let ((val (vip-p-val arg))
2586 (com (vip-getCom arg)))
2587 (if com (vip-move-marker-locally 'vip-com-point (point)))
2588 (previous-line val)
2589 (if vip-ex-style-motion
2590 (if (and (eolp) (not (bolp))) (backward-char 1)))
2591 (setq this-command 'previous-line)
2592 (if com (vip-execute-com 'vip-previous-line val com))))
2593
2594
2595(defun vip-previous-line-at-bol (arg)
2596 "Previous line at beginning of line."
2597 (interactive "P")
2598 (vip-leave-region-active)
2599 (save-excursion
2600 (beginning-of-line)
2601 (if (bobp) (error "First line in buffer")))
2602 (let ((val (vip-p-val arg))
2603 (com (vip-getCom arg)))
2604 (if com (vip-move-marker-locally 'vip-com-point (point)))
2605 (forward-line (- val))
2606 (back-to-indentation)
2607 (if com (vip-execute-com 'vip-previous-line val com))))
2608
2609(defun vip-change-to-eol (arg)
2610 "Change to end of line."
2611 (interactive "P")
2612 (vip-goto-eol (cons arg ?c)))
2613
2614(defun vip-kill-line (arg)
2615 "Delete line."
2616 (interactive "P")
2617 (vip-goto-eol (cons arg ?d)))
2618
2619(defun vip-erase-line (arg)
2620 "Erase line."
2621 (interactive "P")
2622 (vip-beginning-of-line (cons arg ?d)))
2623
2624\f
2625;;; Moving around
2626
2627(defun vip-goto-line (arg)
2628 "Go to ARG's line. Without ARG go to end of buffer."
2629 (interactive "P")
2630 (let ((val (vip-P-val arg))
2631 (com (vip-getCom arg)))
2632 (vip-move-marker-locally 'vip-com-point (point))
2633 (vip-deactivate-mark)
2634 (push-mark nil t)
2635 (if (null val)
2636 (goto-char (point-max))
2637 (goto-char (point-min))
2638 (forward-line (1- val)))
2639
2640 ;; positioning is done twice: before and after command execution
2641 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
2642 (back-to-indentation)
2643
2644 (if com (vip-execute-com 'vip-goto-line val com))
2645
2646 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
2647 (back-to-indentation)
2648 ))
2649
2650;; Find ARG's occurrence of CHAR on the current line.
2651;; If FORWARD then search is forward, otherwise backward. OFFSET is used to
2652;; adjust point after search.
2653(defun vip-find-char (arg char forward offset)
2654 (or (char-or-string-p char) (error ""))
2655 (let ((arg (if forward arg (- arg)))
2656 (cmd (if (eq vip-intermediate-command 'vip-repeat)
2657 (nth 5 vip-d-com)
2658 (vip-array-to-string (this-command-keys))))
2659 point)
2660 (save-excursion
2661 (save-restriction
2662 (if (> arg 0)
2663 (narrow-to-region
2664 ;; forward search begins here
2665 (if (eolp) (error "Command `%s': At end of line" cmd) (point))
2666 ;; forward search ends here
2667 (progn (end-of-line) (point)))
2668 (narrow-to-region
2669 ;; backward search begins from here
2670 (if (bolp)
2671 (error "Command `%s': At beginning of line" cmd) (point))
2672 ;; backward search ends here
2673 (progn (beginning-of-line) (point))))
2674 ;; if arg > 0, point is forwarded before search.
2675 (if (> arg 0) (goto-char (1+ (point-min)))
2676 (goto-char (point-max)))
2677 (if (let ((case-fold-search nil))
2678 (search-forward (char-to-string char) nil 0 arg))
2679 (setq point (point))
2680 (error "Command `%s': `%c' not found" cmd char))))
2681 (goto-char (+ point (if (> arg 0) (if offset -2 -1) (if offset 1 0))))))
2682
2683(defun vip-find-char-forward (arg)
2684 "Find char on the line.
2685If called interactively read the char to find from the terminal, and if
2686called from vip-repeat, the char last used is used. This behaviour is
2687controlled by the sign of prefix numeric value."
2688 (interactive "P")
2689 (let ((val (vip-p-val arg))
2690 (com (vip-getcom arg))
2691 (cmd-representation (nth 5 vip-d-com)))
2692 (if (> val 0)
2693 ;; this means that the function was called interactively
2694 (setq vip-f-char (read-char)
2695 vip-f-forward t
2696 vip-f-offset nil)
2697 ;; vip-repeat --- set vip-F-char from command-keys
2698 (setq vip-F-char (if (stringp cmd-representation)
2699 (vip-seq-last-elt cmd-representation)
2700 vip-F-char)
2701 vip-f-char vip-F-char)
2702 (setq val (- val)))
2703 (if com (vip-move-marker-locally 'vip-com-point (point)))
2704 (vip-find-char val (if (> (vip-p-val arg) 0) vip-f-char vip-F-char) t nil)
2705 (setq val (- val))
2706 (if com
2707 (progn
2708 (setq vip-F-char vip-f-char) ; set new vip-F-char
2709 (forward-char)
2710 (vip-execute-com 'vip-find-char-forward val com)))))
2711
2712(defun vip-goto-char-forward (arg)
2713 "Go up to char ARG forward on line."
2714 (interactive "P")
2715 (let ((val (vip-p-val arg))
2716 (com (vip-getcom arg))
2717 (cmd-representation (nth 5 vip-d-com)))
2718 (if (> val 0)
2719 ;; this means that the function was called interactively
2720 (setq vip-f-char (read-char)
2721 vip-f-forward t
2722 vip-f-offset t)
2723 ;; vip-repeat --- set vip-F-char from command-keys
2724 (setq vip-F-char (if (stringp cmd-representation)
2725 (vip-seq-last-elt cmd-representation)
2726 vip-F-char)
2727 vip-f-char vip-F-char)
2728 (setq val (- val)))
2729 (if com (vip-move-marker-locally 'vip-com-point (point)))
2730 (vip-find-char val (if (> (vip-p-val arg) 0) vip-f-char vip-F-char) t t)
2731 (setq val (- val))
2732 (if com
2733 (progn
2734 (setq vip-F-char vip-f-char) ; set new vip-F-char
2735 (forward-char)
2736 (vip-execute-com 'vip-goto-char-forward val com)))))
2737
2738(defun vip-find-char-backward (arg)
2739 "Find char ARG on line backward."
2740 (interactive "P")
2741 (let ((val (vip-p-val arg))
2742 (com (vip-getcom arg))
2743 (cmd-representation (nth 5 vip-d-com)))
2744 (if (> val 0)
2745 ;; this means that the function was called interactively
2746 (setq vip-f-char (read-char)
2747 vip-f-forward nil
2748 vip-f-offset nil)
2749 ;; vip-repeat --- set vip-F-char from command-keys
2750 (setq vip-F-char (if (stringp cmd-representation)
2751 (vip-seq-last-elt cmd-representation)
2752 vip-F-char)
2753 vip-f-char vip-F-char)
2754 (setq val (- val)))
2755 (if com (vip-move-marker-locally 'vip-com-point (point)))
2756 (vip-find-char
2757 val (if (> (vip-p-val arg) 0) vip-f-char vip-F-char) nil nil)
2758 (setq val (- val))
2759 (if com
2760 (progn
2761 (setq vip-F-char vip-f-char) ; set new vip-F-char
2762 (vip-execute-com 'vip-find-char-backward val com)))))
2763
2764(defun vip-goto-char-backward (arg)
2765 "Go up to char ARG backward on line."
2766 (interactive "P")
2767 (let ((val (vip-p-val arg))
2768 (com (vip-getcom arg))
2769 (cmd-representation (nth 5 vip-d-com)))
2770 (if (> val 0)
2771 ;; this means that the function was called interactively
2772 (setq vip-f-char (read-char)
2773 vip-f-forward nil
2774 vip-f-offset t)
2775 ;; vip-repeat --- set vip-F-char from command-keys
2776 (setq vip-F-char (if (stringp cmd-representation)
2777 (vip-seq-last-elt cmd-representation)
2778 vip-F-char)
2779 vip-f-char vip-F-char)
2780 (setq val (- val)))
2781 (if com (vip-move-marker-locally 'vip-com-point (point)))
2782 (vip-find-char val (if (> (vip-p-val arg) 0) vip-f-char vip-F-char) nil t)
2783 (setq val (- val))
2784 (if com
2785 (progn
2786 (setq vip-F-char vip-f-char) ; set new vip-F-char
2787 (vip-execute-com 'vip-goto-char-backward val com)))))
2788
2789(defun vip-repeat-find (arg)
2790 "Repeat previous find command."
2791 (interactive "P")
2792 (let ((val (vip-p-val arg))
2793 (com (vip-getcom arg)))
2794 (vip-deactivate-mark)
2795 (if com (vip-move-marker-locally 'vip-com-point (point)))
2796 (vip-find-char val vip-f-char vip-f-forward vip-f-offset)
2797 (if com
2798 (progn
2799 (if vip-f-forward (forward-char))
2800 (vip-execute-com 'vip-repeat-find val com)))))
2801
2802(defun vip-repeat-find-opposite (arg)
2803 "Repeat previous find command in the opposite direction."
2804 (interactive "P")
2805 (let ((val (vip-p-val arg))
2806 (com (vip-getcom arg)))
2807 (vip-deactivate-mark)
2808 (if com (vip-move-marker-locally 'vip-com-point (point)))
2809 (vip-find-char val vip-f-char (not vip-f-forward) vip-f-offset)
2810 (if com
2811 (progn
2812 (if vip-f-forward (forward-char))
2813 (vip-execute-com 'vip-repeat-find-opposite val com)))))
2814
2815\f
2816;; window scrolling etc.
2817
2818(defun vip-other-window (arg)
2819 "Switch to other window."
2820 (interactive "p")
2821 (other-window arg)
2822 (or (not (eq vip-current-state 'emacs-state))
2823 (string= (buffer-name (current-buffer)) " *Minibuf-1*")
2824 (vip-change-state-to-vi)))
2825
2826(defun vip-window-top (arg)
2827 "Go to home window line."
2828 (interactive "P")
2829 (let ((val (vip-p-val arg))
2830 (com (vip-getCom arg)))
2831 (if com (vip-move-marker-locally 'vip-com-point (point)))
2832 (push-mark nil t)
2833 (move-to-window-line (1- val))
2834
2835 ;; positioning is done twice: before and after command execution
2836 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
2837 (back-to-indentation)
2838
2839 (if com (vip-execute-com 'vip-window-top val com))
2840
2841 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
2842 (back-to-indentation)
2843 ))
2844
2845(defun vip-window-middle (arg)
2846 "Go to middle window line."
2847 (interactive "P")
2848 (let ((val (vip-p-val arg))
2849 (com (vip-getCom arg))
2850 lines)
2851 (if com (vip-move-marker-locally 'vip-com-point (point)))
2852 (push-mark nil t)
2853 (if (not (pos-visible-in-window-p (point-max)))
2854 (move-to-window-line (+ (/ (1- (window-height)) 2) (1- val)))
2855 (setq lines (count-lines (window-start) (point-max)))
2856 (move-to-window-line (+ (/ lines 2) (1- val))))
2857
2858 ;; positioning is done twice: before and after command execution
2859 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
2860 (back-to-indentation)
2861
2862 (if com (vip-execute-com 'vip-window-middle val com))
2863
2864 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
2865 (back-to-indentation)
2866 ))
2867
2868(defun vip-window-bottom (arg)
2869 "Go to last window line."
2870 (interactive "P")
2871 (let ((val (vip-p-val arg))
2872 (com (vip-getCom arg)))
2873 (if com (vip-move-marker-locally 'vip-com-point (point)))
2874 (push-mark nil t)
2875 (move-to-window-line (- val))
2876
2877 ;; positioning is done twice: before and after command execution
2878 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
2879 (back-to-indentation)
2880
2881 (if com (vip-execute-com 'vip-window-bottom val com))
2882
2883 (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
2884 (back-to-indentation)
2885 ))
2886
2887(defun vip-line-to-top (arg)
2888 "Put current line on the home line."
2889 (interactive "p")
2890 (recenter (1- arg)))
2891
2892(defun vip-line-to-middle (arg)
2893 "Put current line on the middle line."
2894 (interactive "p")
2895 (recenter (+ (1- arg) (/ (1- (window-height)) 2))))
2896
2897(defun vip-line-to-bottom (arg)
2898 "Put current line on the last line."
2899 (interactive "p")
2900 (recenter (- (window-height) (1+ arg))))
2901
2902;; If point is within vip-search-scroll-threshold of window top or bottom,
2903;; scroll up or down 1/7 of window height, depending on whether we are at the
2904;; bottom or at the top of the window. This function is called by vip-search
2905;; (which is called from vip-search-forward/backward/next). If the value of
2906;; vip-search-scroll-threshold is negative - don't scroll.
2907(defun vip-adjust-window ()
2908 (let ((win-height (if vip-emacs-p
2909 (1- (window-height)) ; adjust for modeline
2910 (window-displayed-height)))
2911 (pt (point))
2912 at-top-p at-bottom-p
2913 min-scroll direction)
2914 (save-excursion
2915 (move-to-window-line 0) ; top
2916 (setq at-top-p
2917 (<= (count-lines pt (point))
2918 vip-search-scroll-threshold))
2919 (move-to-window-line -1) ; bottom
2920 (setq at-bottom-p
2921 (<= (count-lines pt (point)) vip-search-scroll-threshold))
2922 )
2923 (cond (at-top-p (setq min-scroll (1- vip-search-scroll-threshold)
2924 direction 1))
2925 (at-bottom-p (setq min-scroll (1+ vip-search-scroll-threshold)
2926 direction -1)))
2927 (if min-scroll
2928 (recenter
2929 (* (max min-scroll (/ win-height 7)) direction)))
2930 ))
2931
2932\f
2933;; paren match
2934;; must correct this to only match ( to ) etc. On the other hand
2935;; it is good that paren match gets confused, because that way you
2936;; catch _all_ imbalances.
2937
2938(defun vip-paren-match (arg)
2939 "Go to the matching parenthesis."
2940 (interactive "P")
2941 (vip-leave-region-active)
2942 (let ((com (vip-getcom arg))
2943 (parse-sexp-ignore-comments vip-parse-sexp-ignore-comments)
2944 anchor-point)
2945 (if (integerp arg)
2946 (if (or (> arg 99) (< arg 1))
2947 (error "Prefix must be between 1 and 99")
2948 (goto-char
2949 (if (> (point-max) 80000)
2950 (* (/ (point-max) 100) arg)
2951 (/ (* (point-max) arg) 100)))
2952 (back-to-indentation))
2953 (let (beg-lim end-lim)
2954 (if (and (eolp) (not (bolp))) (forward-char -1))
2955 (if (not (looking-at "[][(){}]"))
2956 (setq anchor-point (point)))
2957 (save-excursion
2958 (beginning-of-line)
2959 (setq beg-lim (point))
2960 (end-of-line)
2961 (setq end-lim (point)))
2962 (cond ((re-search-forward "[][(){}]" end-lim t)
2963 (backward-char) )
2964 ((re-search-backward "[][(){}]" beg-lim t))
2965 (t
2966 (error "No matching character on line"))))
2967 (cond ((looking-at "[\(\[{]")
2968 (if com (vip-move-marker-locally 'vip-com-point (point)))
2969 (forward-sexp 1)
2970 (if com
2971 (vip-execute-com 'vip-paren-match nil com)
2972 (backward-char)))
2973 (anchor-point
2974 (if com
2975 (progn
2976 (vip-move-marker-locally 'vip-com-point anchor-point)
2977 (forward-char 1)
2978 (vip-execute-com 'vip-paren-match nil com)
2979 )))
2980 ((looking-at "[])}]")
2981 (forward-char)
2982 (if com (vip-move-marker-locally 'vip-com-point (point)))
2983 (backward-sexp 1)
2984 (if com (vip-execute-com 'vip-paren-match nil com)))
2985 (t (error ""))))))
2986
2987(defun vip-toggle-parse-sexp-ignore-comments ()
2988 (interactive)
2989 (setq vip-parse-sexp-ignore-comments (not vip-parse-sexp-ignore-comments))
1e70790f
MK
2990 (princ (format
2991 "From now on, `%%' will %signore parentheses inside comment fields"
2992 (if vip-parse-sexp-ignore-comments "" "NOT "))))
d5e52f99
MK
2993
2994\f
2995;; sentence ,paragraph and heading
2996
2997(defun vip-forward-sentence (arg)
2998 "Forward sentence."
2999 (interactive "P")
3000 (push-mark nil t)
3001 (let ((val (vip-p-val arg))
3002 (com (vip-getcom arg)))
3003 (if com (vip-move-marker-locally 'vip-com-point (point)))
3004 (forward-sentence val)
3005 (if com (vip-execute-com 'vip-forward-sentence nil com))))
3006
3007(defun vip-backward-sentence (arg)
3008 "Backward sentence."
3009 (interactive "P")
3010 (push-mark nil t)
3011 (let ((val (vip-p-val arg))
3012 (com (vip-getcom arg)))
3013 (if com (vip-move-marker-locally 'vip-com-point (point)))
3014 (backward-sentence val)
3015 (if com (vip-execute-com 'vip-backward-sentence nil com))))
3016
3017(defun vip-forward-paragraph (arg)
3018 "Forward paragraph."
3019 (interactive "P")
3020 (push-mark nil t)
3021 (let ((val (vip-p-val arg))
3022 (com (vip-getCom arg)))
3023 (if com (vip-move-marker-locally 'vip-com-point (point)))
3024 (forward-paragraph val)
3025 (if com
3026 (progn
3027 (backward-char 1)
3028 (vip-execute-com 'vip-forward-paragraph nil com)))))
3029
3030(defun vip-backward-paragraph (arg)
3031 "Backward paragraph."
3032 (interactive "P")
3033 (push-mark nil t)
3034 (let ((val (vip-p-val arg))
3035 (com (vip-getCom arg)))
3036 (if com (vip-move-marker-locally 'vip-com-point (point)))
3037 (backward-paragraph val)
3038 (if com
3039 (progn
3040 (forward-char 1)
3041 (vip-execute-com 'vip-backward-paragraph nil com)
3042 (backward-char 1)))))
3043
3044;; should be mode-specific etc.
3045
3046(defun vip-prev-heading (arg)
3047 (interactive "P")
3048 (let ((val (vip-p-val arg))
3049 (com (vip-getCom arg)))
3050 (if com (vip-move-marker-locally 'vip-com-point (point)))
3051 (re-search-backward vip-heading-start nil t val)
3052 (goto-char (match-beginning 0))
3053 (if com (vip-execute-com 'vip-prev-heading nil com))))
3054
3055(defun vip-heading-end (arg)
3056 (interactive "P")
3057 (let ((val (vip-p-val arg))
3058 (com (vip-getCom arg)))
3059 (if com (vip-move-marker-locally 'vip-com-point (point)))
3060 (re-search-forward vip-heading-end nil t val)
3061 (goto-char (match-beginning 0))
3062 (if com (vip-execute-com 'vip-heading-end nil com))))
3063
3064(defun vip-next-heading (arg)
3065 (interactive "P")
3066 (let ((val (vip-p-val arg))
3067 (com (vip-getCom arg)))
3068 (if com (vip-move-marker-locally 'vip-com-point (point)))
3069 (end-of-line)
3070 (re-search-forward vip-heading-start nil t val)
3071 (goto-char (match-beginning 0))
3072 (if com (vip-execute-com 'vip-next-heading nil com))))
3073
3074\f
3075;; scrolling
3076
d5e52f99
MK
3077(defun vip-scroll-screen (arg)
3078 "Scroll to next screen."
3079 (interactive "p")
3080 (condition-case nil
3081 (if (> arg 0)
3082 (while (> arg 0)
3083 (scroll-up)
3084 (setq arg (1- arg)))
3085 (while (> 0 arg)
3086 (scroll-down)
3087 (setq arg (1+ arg))))
3088 (error (beep 1)
3089 (if (> arg 0)
3090 (progn
3091 (message "End of buffer")
3092 (goto-char (point-max)))
3093 (message "Beginning of buffer")
3094 (goto-char (point-min))))
3095 ))
3096
3097(defun vip-scroll-screen-back (arg)
3098 "Scroll to previous screen."
3099 (interactive "p")
3100 (vip-scroll-screen (- arg)))
3101
3102(defun vip-scroll-down (arg)
3103 "Pull down half screen."
3104 (interactive "P")
3105 (condition-case nil
3106 (if (null arg)
3107 (scroll-down (/ (window-height) 2))
3108 (scroll-down arg))
3109 (error (beep 1)
3110 (message "Beginning of buffer")
3111 (goto-char (point-min)))))
3112
3113(defun vip-scroll-down-one (arg)
3114 "Scroll up one line."
3115 (interactive "p")
3116 (scroll-down arg))
3117
3118(defun vip-scroll-up (arg)
3119 "Pull up half screen."
3120 (interactive "P")
3121 (condition-case nil
3122 (if (null arg)
3123 (scroll-up (/ (window-height) 2))
3124 (scroll-up arg))
3125 (error (beep 1)
3126 (message "End of buffer")
3127 (goto-char (point-max)))))
3128
3129(defun vip-scroll-up-one (arg)
3130 "Scroll down one line."
3131 (interactive "p")
3132 (scroll-up arg))
3133
3134\f
3135;; searching
3136
3137(defun vip-if-string (prompt)
3138 (let ((s (vip-read-string-with-history
3139 prompt
3140 nil ; no initial
3141 'vip-search-history
3142 (car vip-search-history))))
3143 (if (not (string= s ""))
3144 (setq vip-s-string s))))
3145
3146
3147(defun vip-toggle-search-style (arg)
3148 "Toggle the value of vip-case-fold-search/vip-re-search.
3149Without prefix argument, will ask which search style to toggle. With prefix
3150arg 1,toggles vip-case-fold-search; with arg 2 toggles vip-re-search.
3151
3152Although this function is bound to \\[vip-toggle-search-style], the most
3153convenient way to use it is to bind `//' to the macro
3154`1 M-x vip-toggle-search-style' and `///' to
3155`2 M-x vip-toggle-search-style'. In this way, hitting `//' quickly will
3156toggle case-fold-search and hitting `/' three times witth toggle regexp
3157search. Macros are more convenient in this case because they don't affect
3158the Emacs binding of `/'."
3159 (interactive "P")
3160 (let (msg)
3161 (cond ((or (eq arg 1)
3162 (and (null arg)
3163 (y-or-n-p (format "Search style: '%s'. Want '%s'? "
3164 (if vip-case-fold-search
3165 "case-insensitive" "case-sensitive")
3166 (if vip-case-fold-search
3167 "case-sensitive"
3168 "case-insensitive")))))
3169 (setq vip-case-fold-search (null vip-case-fold-search))
3170 (if vip-case-fold-search
3171 (setq msg "Search becomes case-insensitive")
3172 (setq msg "Search becomes case-sensitive")))
3173 ((or (eq arg 2)
3174 (and (null arg)
3175 (y-or-n-p (format "Search style: '%s'. Want '%s'? "
3176 (if vip-re-search
3177 "regexp-search" "vanilla-search")
3178 (if vip-re-search
3179 "vanilla-search"
3180 "regexp-search")))))
3181 (setq vip-re-search (null vip-re-search))
3182 (if vip-re-search
3183 (setq msg "Search becomes regexp-style")
3184 (setq msg "Search becomes vanilla-style")))
3185 (t
3186 (setq msg "Search style remains unchanged")))
1e70790f 3187 (princ msg t)))
d5e52f99 3188
5489c3d3 3189(defun vip-set-searchstyle-toggling-macros (unset)
d5e52f99
MK
3190 "Set the macros for toggling the search style in Viper's vi-state.
3191The macro that toggles case sensitivity is bound to `//', and the one that
3192toggles regexp search is bound to `///'.
3193With a prefix argument, this function unsets the macros. "
3194 (interactive "P")
3195 (or noninteractive
3196 (if (not unset)
3197 (progn
3198 ;; toggle case sensitivity in search
3199 (vip-record-kbd-macro
3200 "//" 'vi-state
3201 [1 (meta x) v i p - t o g g l e - s e a r c h - s t y l e return]
3202 't)
3203 ;; toggle regexp/vanila search
3204 (vip-record-kbd-macro
3205 "///" 'vi-state
3206 [2 (meta x) v i p - t o g g l e - s e a r c h - s t y l e return]
3207 't)
3208 (if (interactive-p)
3209 (message
1e70790f 3210 "// and /// now toggle case-sensitivity and regexp search")))
d5e52f99
MK
3211 (vip-unrecord-kbd-macro "//" 'vi-state)
3212 (sit-for 2)
3213 (vip-unrecord-kbd-macro "///" 'vi-state))))
3214
1e70790f
MK
3215
3216(defun vip-set-parsing-style-toggling-macro (unset)
3217 "Set `%%%' to be a macro that toggles whether comment fields should be parsed for matching parentheses.
3218This is used in conjunction with the `%' command.
3219
3220With a prefix argument, unsets the macro."
3221 (interactive "P")
3222 (or noninteractive
3223 (if (not unset)
3224 (progn
3225 ;; Make %%% toggle parsing comments for matching parentheses
3226 (vip-record-kbd-macro
3227 "%%%" 'vi-state
3228 [(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]
3229 't)
3230 (if (interactive-p)
3231 (message
3232 "%%%%%% now toggles whether comments should be parsed for matching parentheses")))
3233 (vip-unrecord-kbd-macro "%%%" 'vi-state))))
3234
3235
5489c3d3 3236(defun vip-set-emacs-state-searchstyle-macros (unset &optional arg-majormode)
d5e52f99
MK
3237 "Set the macros for toggling the search style in Viper's emacs-state.
3238The macro that toggles case sensitivity is bound to `//', and the one that
3239toggles regexp search is bound to `///'.
3240With a prefix argument, this function unsets the macros.
3241If the optional prefix argument is non-nil and specifies a valid major mode,
3242this sets the macros only in the macros in that major mode. Otherwise,
3243the macros are set in the current major mode.
3244\(When unsetting the macros, the second argument has no effect.\)"
3245 (interactive "P")
3246 (or noninteractive
3247 (if (not unset)
3248 (progn
3249 ;; toggle case sensitivity in search
3250 (vip-record-kbd-macro
3251 "//" 'emacs-state
3252 [1 (meta x) v i p - t o g g l e - s e a r c h - s t y l e return]
3253 (or arg-majormode major-mode))
3254 ;; toggle regexp/vanila search
3255 (vip-record-kbd-macro
3256 "///" 'emacs-state
3257 [2 (meta x) v i p - t o g g l e - s e a r c h - s t y l e return]
3258 (or arg-majormode major-mode))
3259 (if (interactive-p)
3260 (message
3261 "// and /// now toggle case-sensitivity and regexp search.")))
3262 (vip-unrecord-kbd-macro "//" 'emacs-state)
3263 (sit-for 2)
3264 (vip-unrecord-kbd-macro "///" 'emacs-state))))
3265
3266
3267(defun vip-search-forward (arg)
3268 "Search a string forward.
3269ARG is used to find the ARG's occurrence of the string.
3270Null string will repeat previous search."
3271 (interactive "P")
3272 (let ((val (vip-P-val arg))
3273 (com (vip-getcom arg))
3274 (old-str vip-s-string))
3275 (setq vip-s-forward t)
3276 (vip-if-string "/")
3277 ;; this is not used at present, but may be used later
3278 (if (or (not (equal old-str vip-s-string))
3279 (not (markerp vip-local-search-start-marker))
3280 (not (marker-buffer vip-local-search-start-marker)))
3281 (setq vip-local-search-start-marker (point-marker)))
3282 (vip-search vip-s-string t val)
3283 (if com
3284 (progn
3285 (vip-move-marker-locally 'vip-com-point (mark t))
3286 (vip-execute-com 'vip-search-next val com)))))
3287
3288(defun vip-search-backward (arg)
3289 "Search a string backward.
3290ARG is used to find the ARG's occurrence of the string.
3291Null string will repeat previous search."
3292 (interactive "P")
3293 (let ((val (vip-P-val arg))
3294 (com (vip-getcom arg))
3295 (old-str vip-s-string))
3296 (setq vip-s-forward nil)
3297 (vip-if-string "?")
3298 ;; this is not used at present, but may be used later
3299 (if (or (not (equal old-str vip-s-string))
3300 (not (markerp vip-local-search-start-marker))
3301 (not (marker-buffer vip-local-search-start-marker)))
3302 (setq vip-local-search-start-marker (point-marker)))
3303 (vip-search vip-s-string nil val)
3304 (if com
3305 (progn
3306 (vip-move-marker-locally 'vip-com-point (mark t))
3307 (vip-execute-com 'vip-search-next val com)))))
3308
3309
3310;; Search for COUNT's occurrence of STRING.
3311;; Search is forward if FORWARD is non-nil, otherwise backward.
3312;; INIT-POINT is the position where search is to start.
3313;; Arguments:
3314;; (STRING FORW COUNT &optional NO-OFFSET INIT-POINT LIMIT FAIL-IF-NOT-FOUND)
3315(defun vip-search (string forward arg
3316 &optional no-offset init-point fail-if-not-found)
3317 (if (not (equal string ""))
3318 (let ((val (vip-p-val arg))
3319 (com (vip-getcom arg))
3320 (offset (not no-offset))
3321 (case-fold-search vip-case-fold-search)
3322 (start-point (or init-point (point))))
3323 (vip-deactivate-mark)
3324 (if forward
3325 (condition-case nil
3326 (progn
3327 (if offset (vip-forward-char-carefully))
3328 (if vip-re-search
3329 (progn
3330 (re-search-forward string nil nil val)
3331 (re-search-backward string))
3332 (search-forward string nil nil val)
3333 (search-backward string))
3334 (if (not (equal start-point (point)))
3335 (push-mark start-point t)))
3336 (search-failed
3337 (if (and (not fail-if-not-found) vip-search-wrap-around-t)
3338 (progn
3339 (message "Search wrapped around BOTTOM of buffer")
3340 (goto-char (point-min))
3341 (vip-search string forward (cons 1 com) t start-point 'fail)
3342 ;; don't wait in macros
3343 (or executing-kbd-macro (sit-for 2))
3344 ;; delete the wrap-around message
3345 (message "")
3346 )
3347 (goto-char start-point)
3348 (error "`%s': %s not found"
3349 string
3350 (if vip-re-search "Pattern" "String"))
3351 )))
3352 ;; backward
3353 (condition-case nil
3354 (progn
3355 (if vip-re-search
3356 (re-search-backward string nil nil val)
3357 (search-backward string nil nil val))
3358 (if (not (equal start-point (point)))
3359 (push-mark start-point t)))
3360 (search-failed
3361 (if (and (not fail-if-not-found) vip-search-wrap-around-t)
3362 (progn
3363 (message "Search wrapped around TOP of buffer")
3364 (goto-char (point-max))
3365 (vip-search string forward (cons 1 com) t start-point 'fail)
3366 ;; don't wait in macros
3367 (or executing-kbd-macro (sit-for 2))
3368 ;; delete the wrap-around message
3369 (message "")
3370 )
3371 (goto-char start-point)
3372 (error "`%s': %s not found"
3373 string
3374 (if vip-re-search "Pattern" "String"))
3375 ))))
3376 ;; pull up or down if at top/bottom of window
3377 (vip-adjust-window)
3378 ;; highlight the result of search
3379 ;; don't wait and don't highlight in macros
3380 (or executing-kbd-macro
3381 vip-inside-command-argument-action
3382 (vip-flash-search-pattern))
3383 )))
3384
3385(defun vip-search-next (arg)
3386 "Repeat previous search."
3387 (interactive "P")
3388 (let ((val (vip-p-val arg))
3389 (com (vip-getcom arg)))
3390 (if (null vip-s-string) (error vip-NoPrevSearch))
3391 (vip-search vip-s-string vip-s-forward arg)
3392 (if com
3393 (progn
3394 (vip-move-marker-locally 'vip-com-point (mark t))
3395 (vip-execute-com 'vip-search-next val com)))))
3396
3397(defun vip-search-Next (arg)
3398 "Repeat previous search in the reverse direction."
3399 (interactive "P")
3400 (let ((val (vip-p-val arg))
3401 (com (vip-getcom arg)))
3402 (if (null vip-s-string) (error vip-NoPrevSearch))
3403 (vip-search vip-s-string (not vip-s-forward) arg)
3404 (if com
3405 (progn
3406 (vip-move-marker-locally 'vip-com-point (mark t))
3407 (vip-execute-com 'vip-search-Next val com)))))
3408
3409
3410;; Search contents of buffer defined by one of Viper's motion commands.
3411;; Repeatable via `n' and `N'.
3412(defun vip-buffer-search-enable (&optional c)
3413 (cond (c (setq vip-buffer-search-char c))
3414 ((null vip-buffer-search-char)
3415 (setq vip-buffer-search-char ?g)))
3416 (define-key vip-vi-basic-map
3417 (char-to-string vip-buffer-search-char) 'vip-command-argument)
3418 (aset vip-exec-array vip-buffer-search-char 'vip-exec-buffer-search)
3419 (setq vip-prefix-commands (cons vip-buffer-search-char vip-prefix-commands)))
3420
3421;; This is a Viper wraper for isearch-forward.
3422(defun vip-isearch-forward (arg)
3423 "Do incremental search forward."
3424 (interactive "P")
3425 ;; emacs bug workaround
3426 (if (listp arg) (setq arg (car arg)))
3427 (vip-exec-form-in-emacs (list 'isearch-forward arg)))
3428
3429;; This is a Viper wraper for isearch-backward."
3430(defun vip-isearch-backward (arg)
3431 "Do incremental search backward."
3432 (interactive "P")
3433 ;; emacs bug workaround
3434 (if (listp arg) (setq arg (car arg)))
3435 (vip-exec-form-in-emacs (list 'isearch-backward arg)))
3436
3437\f
3438;; visiting and killing files, buffers
3439
3440(defun vip-switch-to-buffer ()
3441 "Switch to buffer in the current window."
3442 (interactive)
3443 (let (buffer)
3444 (setq buffer
3445 (read-buffer
3446 (format "Switch to buffer in this window \(%s\): "
3447 (buffer-name (other-buffer (current-buffer))))))
3448 (switch-to-buffer buffer)
3449 ))
3450
3451(defun vip-switch-to-buffer-other-window ()
3452 "Switch to buffer in another window."
3453 (interactive)
3454 (let (buffer)
3455 (setq buffer
3456 (read-buffer
3457 (format "Switch to buffer in another window \(%s\): "
3458 (buffer-name (other-buffer (current-buffer))))))
3459 (switch-to-buffer-other-window buffer)
3460 ))
3461
3462(defun vip-kill-buffer ()
3463 "Kill a buffer."
3464 (interactive)
3465 (let (buffer buffer-name)
3466 (setq buffer-name
3467 (read-buffer
3468 (format "Kill buffer \(%s\): "
3469 (buffer-name (current-buffer)))))
3470 (setq buffer
3471 (if (null buffer-name)
3472 (current-buffer)
3473 (get-buffer buffer-name)))
3474 (if (null buffer) (error "`%s': No such buffer" buffer-name))
3475 (if (or (not (buffer-modified-p buffer))
3476 (y-or-n-p
3477 (format
3478 "Buffer `%s' is modified, are you sure you want to kill it? "
3479 buffer-name)))
3480 (kill-buffer buffer)
3481 (error "Buffer not killed"))))
3482
3483
1e70790f 3484(defcustom vip-smart-suffix-list
d5e52f99
MK
3485 '("" "tex" "c" "cc" "C" "el" "java" "html" "htm" "pl" "P" "p")
3486 "*List of suffixes that Viper automatically tries to append to filenames ending with a `.'.
3487This is useful when you the current directory contains files with the same
3488prefix and many different suffixes. Usually, only one of the suffixes
3489represents an editable file. However, file completion will stop at the `.'
3490The smart suffix feature lets you hit RET in such a case, and Viper will
3491select the appropriate suffix.
3492
3493Suffixes are tried in the order given and the first suffix for which a
3494corresponding file exists is selected. If no file exists for any of the
3495suffixes, the user is asked to confirm.
3496
1e70790f
MK
3497To turn this feature off, set this variable to nil."
3498 :type '(set string)
3499 :group 'viper)
d5e52f99
MK
3500
3501;; Try to add suffix to files ending with a `.'
3502;; Useful when the user hits RET on a non-completed file name.
3503(defun vip-file-add-suffix ()
3504 (let ((count 0)
3505 (len (length vip-smart-suffix-list))
3506 (file (buffer-string))
3507 found key cmd suff)
3508 (goto-char (point-max))
3509 (if (and vip-smart-suffix-list (string-match "\\.$" file))
3510 (progn
3511 (while (and (not found) (< count len))
3512 (setq suff (nth count vip-smart-suffix-list)
3513 count (1+ count))
3514 (if (file-exists-p (format "%s%s" file suff))
3515 (progn
3516 (setq found t)
3517 (insert suff))))
3518
3519 (if found
3520 ()
3521 (vip-tmp-insert-at-eob " [Please complete file name]")
3522 (unwind-protect
3523 (while (not (memq cmd '(exit-minibuffer vip-exit-minibuffer)))
3524 (setq cmd
3525 (key-binding (setq key (read-key-sequence nil))))
3526 (cond ((eq cmd 'self-insert-command)
3527 (if vip-xemacs-p
3528 (insert (events-to-keys key))
3529 (insert key)))
3530 ((memq cmd '(exit-minibuffer vip-exit-minibuffer))
3531 nil)
3532 (t (command-execute cmd)))
3533 )))
3534 ))
3535 ))
3536
3537
d5e52f99
MK
3538
3539\f
3540;; yank and pop
3541
3542(defsubst vip-yank (text)
3543 "Yank TEXT silently. This works correctly with Emacs's yank-pop command."
3544 (insert text)
3545 (setq this-command 'yank))
3546
3547(defun vip-put-back (arg)
3548 "Put back after point/below line."
3549 (interactive "P")
3550 (let ((val (vip-p-val arg))
3551 (text (if vip-use-register
3552 (cond ((vip-valid-register vip-use-register '(digit))
3553 (current-kill (- vip-use-register ?1) 'do-not-rotate))
3554 ((vip-valid-register vip-use-register)
3555 (get-register (downcase vip-use-register)))
3556 (t (error vip-InvalidRegister vip-use-register)))
3557 (current-kill 0))))
3558 (if (null text)
3559 (if vip-use-register
3560 (let ((reg vip-use-register))
3561 (setq vip-use-register nil)
3562 (error vip-EmptyRegister reg))
3563 (error "")))
3564 (setq vip-use-register nil)
3565 (if (vip-end-with-a-newline-p text)
3566 (progn
3567 (end-of-line)
3568 (if (eobp)
3569 (insert "\n")
3570 (forward-line 1))
3571 (beginning-of-line))
3572 (if (not (eolp)) (vip-forward-char-carefully)))
3573 (set-marker (vip-mark-marker) (point) (current-buffer))
3574 (vip-set-destructive-command
3575 (list 'vip-put-back val nil vip-use-register nil nil))
3576 (vip-loop val (vip-yank text)))
3577 ;; Vi puts cursor on the last char when the yanked text doesn't contain a
3578 ;; newline; it leaves the cursor at the beginning when the text contains
3579 ;; a newline
3580 (if (vip-same-line (point) (mark))
3581 (or (= (point) (mark)) (vip-backward-char-carefully))
3582 (exchange-point-and-mark)
3583 (if (bolp)
3584 (back-to-indentation)))
3585 (vip-deactivate-mark))
3586
3587(defun vip-Put-back (arg)
3588 "Put back at point/above line."
3589 (interactive "P")
3590 (let ((val (vip-p-val arg))
3591 (text (if vip-use-register
3592 (cond ((vip-valid-register vip-use-register '(digit))
3593 (current-kill (- vip-use-register ?1) 'do-not-rotate))
3594 ((vip-valid-register vip-use-register)
3595 (get-register (downcase vip-use-register)))
3596 (t (error vip-InvalidRegister vip-use-register)))
3597 (current-kill 0))))
3598 (if (null text)
3599 (if vip-use-register
3600 (let ((reg vip-use-register))
3601 (setq vip-use-register nil)
3602 (error vip-EmptyRegister reg))
3603 (error "")))
3604 (setq vip-use-register nil)
3605 (if (vip-end-with-a-newline-p text) (beginning-of-line))
3606 (vip-set-destructive-command
3607 (list 'vip-Put-back val nil vip-use-register nil nil))
3608 (set-marker (vip-mark-marker) (point) (current-buffer))
3609 (vip-loop val (vip-yank text)))
3610 ;; Vi puts cursor on the last char when the yanked text doesn't contain a
3611 ;; newline; it leaves the cursor at the beginning when the text contains
3612 ;; a newline
3613 (if (vip-same-line (point) (mark))
3614 (or (= (point) (mark)) (vip-backward-char-carefully))
3615 (exchange-point-and-mark)
3616 (if (bolp)
3617 (back-to-indentation)))
3618 (vip-deactivate-mark))
3619
3620
3621;; Copy region to kill-ring.
3622;; If BEG and END do not belong to the same buffer, copy empty region.
3623(defun vip-copy-region-as-kill (beg end)
3624 (condition-case nil
3625 (copy-region-as-kill beg end)
3626 (error (copy-region-as-kill beg beg))))
3627
3628
3629(defun vip-delete-char (arg)
3630 "Delete character."
3631 (interactive "P")
3632 (let ((val (vip-p-val arg)))
3633 (vip-set-destructive-command (list 'vip-delete-char val nil nil nil nil))
3634 (if (> val 1)
3635 (save-excursion
3636 (let ((here (point)))
3637 (end-of-line)
3638 (if (> val (- (point) here))
3639 (setq val (- (point) here))))))
3640 (if (and (eq val 0) (not vip-ex-style-motion)) (setq val 1))
3641 (if (and vip-ex-style-motion (eolp))
3642 (if (bolp) (error "") (setq val 0))) ; not bol---simply back 1 ch
3643 (if vip-use-register
3644 (progn
3645 (cond ((vip-valid-register vip-use-register '((Letter)))
3646 (vip-append-to-register
3647 (downcase vip-use-register) (point) (- (point) val)))
3648 ((vip-valid-register vip-use-register)
3649 (copy-to-register
3650 vip-use-register (point) (- (point) val) nil))
3651 (t (error vip-InvalidRegister vip-use-register)))
3652 (setq vip-use-register nil)))
3653 (if vip-ex-style-motion
3654 (progn
3655 (delete-char val t)
3656 (if (and (eolp) (not (bolp))) (backward-char 1)))
3657 (if (eolp)
3658 (delete-backward-char val t)
3659 (delete-char val t)))))
3660
3661(defun vip-delete-backward-char (arg)
3662 "Delete previous character. On reaching beginning of line, stop and beep."
3663 (interactive "P")
3664 (let ((val (vip-p-val arg)))
3665 (vip-set-destructive-command
3666 (list 'vip-delete-backward-char val nil nil nil nil))
3667 (if (> val 1)
3668 (save-excursion
3669 (let ((here (point)))
3670 (beginning-of-line)
3671 (if (> val (- here (point)))
3672 (setq val (- here (point)))))))
3673 (if vip-use-register
3674 (progn
3675 (cond ((vip-valid-register vip-use-register '(Letter))
3676 (vip-append-to-register
3677 (downcase vip-use-register) (point) (+ (point) val)))
3678 ((vip-valid-register vip-use-register)
3679 (copy-to-register
3680 vip-use-register (point) (+ (point) val) nil))
3681 (t (error vip-InvalidRegister vip-use-register)))
3682 (setq vip-use-register nil)))
3683 (if (bolp) (ding)
3684 (delete-backward-char val t))))
3685
3686(defun vip-del-backward-char-in-insert ()
3687 "Delete 1 char backwards while in insert mode."
3688 (interactive)
3689 (if (and vip-ex-style-editing-in-insert (bolp))
3690 (beep 1)
3691 (delete-backward-char 1 t)))
3692
3693(defun vip-del-backward-char-in-replace ()
3694 "Delete one character in replace mode.
3695If `vip-delete-backwards-in-replace' is t, then DEL key actually deletes
3696charecters. If it is nil, then the cursor just moves backwards, similarly
3697to Vi. The variable `vip-ex-style-editing-in-insert', if t, doesn't let the
3698cursor move past the beginning of line."
3699 (interactive)
3700 (cond (vip-delete-backwards-in-replace
3701 (cond ((not (bolp))
3702 (delete-backward-char 1 t))
3703 (vip-ex-style-editing-in-insert
3704 (beep 1))
3705 ((bobp)
3706 (beep 1))
3707 (t
3708 (delete-backward-char 1 t))))
3709 (vip-ex-style-editing-in-insert
3710 (if (bolp)
3711 (beep 1)
3712 (backward-char 1)))
3713 (t
3714 (backward-char 1))))
3715
3716
3717\f
3718;; join lines.
3719
3720(defun vip-join-lines (arg)
3721 "Join this line to next, if ARG is nil. Otherwise, join ARG lines."
3722 (interactive "*P")
3723 (let ((val (vip-P-val arg)))
3724 (vip-set-destructive-command (list 'vip-join-lines val nil nil nil nil))
3725 (vip-loop (if (null val) 1 (1- val))
3726 (progn
3727 (end-of-line)
3728 (if (not (eobp))
3729 (progn
3730 (forward-line 1)
3731 (delete-region (point) (1- (point)))
1e70790f
MK
3732 (fixup-whitespace)
3733 ;; fixup-whitespace sometimes does not leave space
3734 ;; between objects, so we insert it as in Vi
3735 (or (looking-at " ")
3736 (insert " ")
3737 (backward-char 1))
3738 ))))))
d5e52f99
MK
3739
3740\f
3741;; Replace state
3742
3743(defun vip-change (beg end)
3744 (if (markerp beg) (setq beg (marker-position beg)))
3745 (if (markerp end) (setq end (marker-position end)))
3746 ;; beg is sometimes (mark t), which may be nil
3747 (or beg (setq beg end))
3748
3749 (vip-set-complex-command-for-undo)
3750 (if vip-use-register
3751 (progn
3752 (copy-to-register vip-use-register beg end nil)
3753 (setq vip-use-register nil)))
3754 (vip-set-replace-overlay beg end)
3755 (setq last-command nil) ; separate repl text from prev kills
3756
3757 (if (= (vip-replace-start) (point-max))
3758 (error "End of buffer"))
3759
3760 (setq vip-last-replace-region
3761 (buffer-substring (vip-replace-start)
3762 (vip-replace-end)))
3763
3764 ;; protect against error while inserting "@" and other disasters
3765 ;; (e.g., read-only buff)
3766 (condition-case conds
3767 (if (or vip-allow-multiline-replace-regions
3768 (vip-same-line (vip-replace-start)
3769 (vip-replace-end)))
3770 (progn
3771 ;; tabs cause problems in replace, so untabify
3772 (goto-char (vip-replace-end))
3773 (insert-before-markers "@") ; put placeholder after the TAB
3774 (untabify (vip-replace-start) (point))
3775 ;; del @, don't put on kill ring
3776 (delete-backward-char 1)
3777
3778 (vip-set-replace-overlay-glyphs
3779 vip-replace-region-start-delimiter
3780 vip-replace-region-end-delimiter)
3781 ;; this move takes care of the last posn in the overlay, which
3782 ;; has to be shifted because of insert. We can't simply insert
3783 ;; "$" before-markers because then overlay-start will shift the
3784 ;; beginning of the overlay in case we are replacing a single
3785 ;; character. This fixes the bug with `s' and `cl' commands.
3786 (vip-move-replace-overlay (vip-replace-start) (point))
3787 (goto-char (vip-replace-start))
3788 (vip-change-state-to-replace t))
3789 (kill-region (vip-replace-start)
3790 (vip-replace-end))
3791 (vip-hide-replace-overlay)
3792 (vip-change-state-to-insert))
3793 (error ;; make sure that the overlay doesn't stay.
3794 ;; go back to the original point
3795 (goto-char (vip-replace-start))
3796 (vip-hide-replace-overlay)
3797 (vip-message-conditions conds))))
3798
3799
3800(defun vip-change-subr (beg end)
3801 ;; beg is sometimes (mark t), which may be nil
3802 (or beg (setq beg end))
3803
3804 (if vip-use-register
3805 (progn
3806 (copy-to-register vip-use-register beg end nil)
3807 (setq vip-use-register nil)))
3808 (kill-region beg end)
3809 (setq this-command 'vip-change)
3810 (vip-yank-last-insertion))
3811
3812(defun vip-toggle-case (arg)
3813 "Toggle character case."
3814 (interactive "P")
3815 (let ((val (vip-p-val arg)) (c))
3816 (vip-set-destructive-command (list 'vip-toggle-case val nil nil nil nil))
3817 (while (> val 0)
3818 (setq c (following-char))
3819 (delete-char 1 nil)
3820 (if (eq c (upcase c))
3821 (insert-char (downcase c) 1)
3822 (insert-char (upcase c) 1))
3823 (if (eolp) (backward-char 1))
3824 (setq val (1- val)))))
3825
3826\f
3827;; query replace
3828
3829(defun vip-query-replace ()
3830 "Query replace.
3831If a null string is suplied as the string to be replaced,
3832the query replace mode will toggle between string replace
3833and regexp replace."
3834 (interactive)
3835 (let (str)
3836 (setq str (vip-read-string-with-history
3837 (if vip-re-query-replace "Query replace regexp: "
3838 "Query replace: ")
3839 nil ; no initial
3840 'vip-replace1-history
3841 (car vip-replace1-history) ; default
3842 ))
3843 (if (string= str "")
3844 (progn
3845 (setq vip-re-query-replace (not vip-re-query-replace))
3846 (message "Query replace mode changed to %s"
3847 (if vip-re-query-replace "regexp replace"
3848 "string replace")))
3849 (if vip-re-query-replace
3850 (query-replace-regexp
3851 str
3852 (vip-read-string-with-history
3853 (format "Query replace regexp `%s' with: " str)
3854 nil ; no initial
3855 'vip-replace1-history
3856 (car vip-replace1-history) ; default
3857 ))
3858 (query-replace
3859 str
3860 (vip-read-string-with-history
3861 (format "Query replace `%s' with: " str)
3862 nil ; no initial
3863 'vip-replace1-history
3864 (car vip-replace1-history) ; default
3865 ))))))
3866
3867\f
3868;; marking
3869
3870(defun vip-mark-beginning-of-buffer ()
3871 "Mark beginning of buffer."
3872 (interactive)
3873 (push-mark (point))
3874 (goto-char (point-min))
3875 (exchange-point-and-mark)
3876 (message "Mark set at the beginning of buffer"))
3877
3878(defun vip-mark-end-of-buffer ()
3879 "Mark end of buffer."
3880 (interactive)
3881 (push-mark (point))
3882 (goto-char (point-max))
3883 (exchange-point-and-mark)
3884 (message "Mark set at the end of buffer"))
3885
3886(defun vip-mark-point ()
3887 "Set mark at point of buffer."
3888 (interactive)
3889 (let ((char (read-char)))
3890 (cond ((and (<= ?a char) (<= char ?z))
3891 (point-to-register (1+ (- char ?a))))
3892 ((= char ?<) (vip-mark-beginning-of-buffer))
3893 ((= char ?>) (vip-mark-end-of-buffer))
3894 ((= char ?.) (vip-set-mark-if-necessary))
3895 ((= char ?,) (vip-cycle-through-mark-ring))
3896 ((= char ?D) (mark-defun))
3897 (t (error ""))
3898 )))
3899
3900;; Algorithm: If first invocation of this command save mark on ring, goto
3901;; mark, M0, and pop the most recent elt from the mark ring into mark,
3902;; making it into the new mark, M1.
3903;; Push this mark back and set mark to the original point position, p1.
3904;; So, if you hit '' or `` then you can return to p1.
3905;;
3906;; If repeated command, pop top elt from the ring into mark and
3907;; jump there. This forgets the position, p1, and puts M1 back into mark.
3908;; Then we save the current pos, which is M0, jump to M1 and pop M2 from
3909;; the ring into mark. Push M2 back on the ring and set mark to M0.
3910;; etc.
3911(defun vip-cycle-through-mark-ring ()
3912 "Visit previous locations on the mark ring.
3913One can use `` and '' to temporarily jump 1 step back."
3914 (let* ((sv-pt (point)))
3915 ;; if repeated `m,' command, pop the previously saved mark.
3916 ;; Prev saved mark is actually prev saved point. It is used if the
3917 ;; user types `` or '' and is discarded
3918 ;; from the mark ring by the next `m,' command.
3919 ;; In any case, go to the previous or previously saved mark.
3920 ;; Then push the current mark (popped off the ring) and set current
3921 ;; point to be the mark. Current pt as mark is discarded by the next
3922 ;; m, command.
3923 (if (eq last-command 'vip-cycle-through-mark-ring)
3924 ()
3925 ;; save current mark if the first iteration
3926 (setq mark-ring (delete (vip-mark-marker) mark-ring))
3927 (if (mark t)
3928 (push-mark (mark t) t)) )
3929 (pop-mark)
3930 (set-mark-command 1)
3931 ;; don't duplicate mark on the ring
3932 (setq mark-ring (delete (vip-mark-marker) mark-ring))
3933 (push-mark sv-pt t)
3934 (vip-deactivate-mark)
3935 (setq this-command 'vip-cycle-through-mark-ring)
3936 ))
3937
3938
3939(defun vip-goto-mark (arg)
3940 "Go to mark."
3941 (interactive "P")
3942 (let ((char (read-char))
3943 (com (vip-getcom arg)))
3944 (vip-goto-mark-subr char com nil)))
3945
3946(defun vip-goto-mark-and-skip-white (arg)
3947 "Go to mark and skip to first non-white character on line."
3948 (interactive "P")
3949 (let ((char (read-char))
3950 (com (vip-getCom arg)))
3951 (vip-goto-mark-subr char com t)))
3952
3953(defun vip-goto-mark-subr (char com skip-white)
3954 (if (eobp)
3955 (if (bobp)
3956 (error "Empty buffer")
3957 (backward-char 1)))
3958 (cond ((vip-valid-register char '(letter))
3959 (let* ((buff (current-buffer))
3960 (reg (1+ (- char ?a)))
3961 (text-marker (get-register reg)))
3962 (if com (vip-move-marker-locally 'vip-com-point (point)))
3963 (if (not (vip-valid-marker text-marker))
3964 (error vip-EmptyTextmarker char))
3965 (if (and (vip-same-line (point) vip-last-jump)
3966 (= (point) vip-last-jump-ignore))
3967 (push-mark vip-last-jump t)
3968 (push-mark nil t)) ; no msg
3969 (vip-register-to-point reg)
3970 (setq vip-last-jump (point-marker))
3971 (cond (skip-white
3972 (back-to-indentation)
3973 (setq vip-last-jump-ignore (point))))
3974 (if com
3975 (if (equal buff (current-buffer))
3976 (vip-execute-com (if skip-white
3977 'vip-goto-mark-and-skip-white
3978 'vip-goto-mark)
3979 nil com)
3980 (switch-to-buffer buff)
3981 (goto-char vip-com-point)
3982 (vip-change-state-to-vi)
3983 (error "")))))
3984 ((and (not skip-white) (= char ?`))
3985 (if com (vip-move-marker-locally 'vip-com-point (point)))
3986 (if (and (vip-same-line (point) vip-last-jump)
3987 (= (point) vip-last-jump-ignore))
3988 (goto-char vip-last-jump))
3989 (if (null (mark t)) (error "Mark is not set in this buffer"))
3990 (if (= (point) (mark t)) (pop-mark))
3991 (exchange-point-and-mark)
3992 (setq vip-last-jump (point-marker)
3993 vip-last-jump-ignore 0)
3994 (if com (vip-execute-com 'vip-goto-mark nil com)))
3995 ((and skip-white (= char ?'))
3996 (if com (vip-move-marker-locally 'vip-com-point (point)))
3997 (if (and (vip-same-line (point) vip-last-jump)
3998 (= (point) vip-last-jump-ignore))
3999 (goto-char vip-last-jump))
4000 (if (= (point) (mark t)) (pop-mark))
4001 (exchange-point-and-mark)
4002 (setq vip-last-jump (point))
4003 (back-to-indentation)
4004 (setq vip-last-jump-ignore (point))
4005 (if com (vip-execute-com 'vip-goto-mark-and-skip-white nil com)))
4006 (t (error vip-InvalidTextmarker char))))
4007
4008(defun vip-insert-tab ()
4009 (interactive)
4010 (insert-tab))
4011
4012(defun vip-exchange-point-and-mark ()
4013 (interactive)
4014 (exchange-point-and-mark)
4015 (back-to-indentation))
4016
4017;; Input Mode Indentation
4018
4019;; Returns t, if the string before point matches the regexp STR.
4020(defsubst vip-looking-back (str)
4021 (and (save-excursion (re-search-backward str nil t))
4022 (= (point) (match-end 0))))
4023
4024
4025(defun vip-forward-indent ()
4026 "Indent forward -- `C-t' in Vi."
4027 (interactive)
4028 (setq vip-cted t)
4029 (indent-to (+ (current-column) vip-shift-width)))
4030
4031(defun vip-backward-indent ()
4032 "Backtab, C-d in VI"
4033 (interactive)
4034 (if vip-cted
4035 (let ((p (point)) (c (current-column)) bol (indent t))
4036 (if (vip-looking-back "[0^]")
4037 (progn
4038 (if (eq ?^ (preceding-char))
4039 (setq vip-preserve-indent t))
4040 (delete-backward-char 1)
4041 (setq p (point))
4042 (setq indent nil)))
4043 (save-excursion
4044 (beginning-of-line)
4045 (setq bol (point)))
4046 (if (re-search-backward "[^ \t]" bol 1) (forward-char))
4047 (delete-region (point) p)
4048 (if indent
4049 (indent-to (- c vip-shift-width)))
4050 (if (or (bolp) (vip-looking-back "[^ \t]"))
4051 (setq vip-cted nil)))))
4052
4053(defun vip-autoindent ()
4054 "Auto Indentation, Vi-style."
4055 (interactive)
4056 (let ((col (current-indentation)))
4057 (if abbrev-mode (expand-abbrev))
4058 (if vip-preserve-indent
4059 (setq vip-preserve-indent nil)
4060 (setq vip-current-indent col))
4061 ;; don't leave whitespace lines around
4062 (if (memq last-command
4063 '(vip-autoindent
4064 vip-open-line vip-Open-line
4065 vip-replace-state-exit-cmd))
4066 (indent-to-left-margin))
4067 ;; use \n instead of newline, or else <Return> will move the insert point
4068 ;;(newline 1)
4069 (insert "\n")
4070 (if vip-auto-indent
4071 (progn
4072 (setq vip-cted t)
e36a387d
MK
4073 (if (and vip-electric-mode
4074 (not (eq major-mode 'fundamental-mode)))
d5e52f99
MK
4075 (indent-according-to-mode)
4076 (indent-to vip-current-indent))
4077 ))
4078 ))
4079
4080
4081;; Viewing registers
4082
4083(defun vip-ket-function (arg)
4084 "Function called by \], the ket. View registers and call \]\]."
4085 (interactive "P")
4086 (let ((reg (read-char)))
4087 (cond ((vip-valid-register reg '(letter Letter))
4088 (view-register (downcase reg)))
4089 ((vip-valid-register reg '(digit))
4090 (let ((text (current-kill (- reg ?1) 'do-not-rotate)))
4091 (save-excursion
4092 (set-buffer (get-buffer-create "*Output*"))
4093 (delete-region (point-min) (point-max))
4094 (insert (format "Register %c contains the string:\n" reg))
4095 (insert text)
4096 (goto-char (point-min)))
4097 (display-buffer "*Output*")))
4098 ((= ?\] reg)
4099 (vip-next-heading arg))
4100 (t (error
4101 vip-InvalidRegister reg)))))
4102
4103(defun vip-brac-function (arg)
4104 "Function called by \[, the brac. View textmarkers and call \[\["
4105 (interactive "P")
4106 (let ((reg (read-char)))
4107 (cond ((= ?\[ reg)
4108 (vip-prev-heading arg))
4109 ((= ?\] reg)
4110 (vip-heading-end arg))
4111 ((vip-valid-register reg '(letter))
4112 (let* ((val (get-register (1+ (- reg ?a))))
4113 (buf (if (not val)
4114 (error vip-EmptyTextmarker reg)
4115 (marker-buffer val)))
4116 (pos (marker-position val))
4117 line-no text (s pos) (e pos))
4118 (save-excursion
4119 (set-buffer (get-buffer-create "*Output*"))
4120 (delete-region (point-min) (point-max))
4121 (if (and buf pos)
4122 (progn
4123 (save-excursion
4124 (set-buffer buf)
4125 (setq line-no (1+ (count-lines (point-min) val)))
4126 (goto-char pos)
4127 (beginning-of-line)
4128 (if (re-search-backward "[^ \t]" nil t)
4129 (progn
4130 (beginning-of-line)
4131 (setq s (point))))
4132 (goto-char pos)
4133 (forward-line 1)
4134 (if (re-search-forward "[^ \t]" nil t)
4135 (progn
4136 (end-of-line)
4137 (setq e (point))))
4138 (setq text (buffer-substring s e))
4139 (setq text (format "%s<%c>%s"
4140 (substring text 0 (- pos s))
4141 reg (substring text (- pos s)))))
4142 (insert
4143 (format
4144 "Textmarker `%c' is in buffer `%s' at line %d.\n"
4145 reg (buffer-name buf) line-no))
4146 (insert (format "Here is some text around %c:\n\n %s"
4147 reg text)))
4148 (insert (format vip-EmptyTextmarker reg)))
4149 (goto-char (point-min)))
4150 (display-buffer "*Output*")))
4151 (t (error vip-InvalidTextmarker reg)))))
4152
4153
4154\f
4155;; commands in insertion mode
4156
4157(defun vip-delete-backward-word (arg)
4158 "Delete previous word."
4159 (interactive "p")
4160 (save-excursion
4161 (push-mark nil t)
4162 (backward-word arg)
4163 (delete-region (point) (mark t))
4164 (pop-mark)))
4165
4166
1e70790f 4167(defun viper-set-expert-level (&optional dont-change-unless)
d5e52f99
MK
4168 "Sets the expert level for a Viper user.
4169Can be called interactively to change (temporarily or permanently) the
4170current expert level.
4171
e36a387d 4172The optional argument DONT-CHANGE-UNLESS, if not nil, says that
d5e52f99
MK
4173the level should not be changed, unless its current value is
4174meaningless (i.e., not one of 1,2,3,4,5).
4175
4176User level determines the setting of Viper variables that are most
4177sensitive for VI-style look-and-feel."
4178
4179 (interactive)
4180
1e70790f 4181 (if (not (natnump viper-expert-level)) (setq viper-expert-level 0))
d5e52f99
MK
4182
4183 (save-window-excursion
4184 (delete-other-windows)
1e70790f 4185 ;; if 0 < viper-expert-level < viper-max-expert-level
d5e52f99
MK
4186 ;; & dont-change-unless = t -- use it; else ask
4187 (vip-ask-level dont-change-unless))
4188
e36a387d 4189 (setq viper-always t
d5e52f99
MK
4190 vip-ex-style-motion t
4191 vip-ex-style-editing-in-insert t
4192 vip-want-ctl-h-help nil)
4193
1e70790f 4194 (cond ((eq viper-expert-level 1) ; novice or beginner
d5e52f99
MK
4195 (global-set-key ; in emacs-state
4196 vip-toggle-key
4197 (if (vip-window-display-p) 'vip-iconify 'suspend-emacs))
4198 (setq vip-no-multiple-ESC t
4199 vip-re-search t
4200 vip-vi-style-in-minibuffer t
4201 vip-search-wrap-around-t t
e36a387d 4202 vip-electric-mode nil
d5e52f99
MK
4203 vip-want-emacs-keys-in-vi nil
4204 vip-want-emacs-keys-in-insert nil))
4205
1e70790f 4206 ((and (> viper-expert-level 1) (< viper-expert-level 5))
d5e52f99 4207 ;; intermediate to guru
e36a387d
MK
4208 (setq vip-no-multiple-ESC (if (vip-window-display-p)
4209 t 'twice)
4210 vip-electric-mode t
d5e52f99 4211 vip-want-emacs-keys-in-vi t
1e70790f 4212 vip-want-emacs-keys-in-insert (> viper-expert-level 2))
d5e52f99 4213
1e70790f 4214 (if (eq viper-expert-level 4) ; respect user's ex-style motion
d5e52f99
MK
4215 ; and vip-no-multiple-ESC
4216 (progn
1e70790f
MK
4217 (setq-default
4218 vip-ex-style-editing-in-insert
4219 (viper-standard-value 'vip-ex-style-editing-in-insert)
4220 vip-ex-style-motion
4221 (viper-standard-value 'vip-ex-style-motion))
d5e52f99 4222 (setq vip-ex-style-motion
1e70790f 4223 (viper-standard-value 'vip-ex-style-motion)
d5e52f99 4224 vip-ex-style-editing-in-insert
1e70790f 4225 (viper-standard-value 'vip-ex-style-editing-in-insert)
d5e52f99 4226 vip-re-search
1e70790f 4227 (viper-standard-value 'vip-re-search)
d5e52f99 4228 vip-no-multiple-ESC
1e70790f
MK
4229 (viper-standard-value 'vip-no-multiple-ESC)))))
4230
d5e52f99
MK
4231 ;; A wizard!!
4232 ;; Ideally, if 5 is selected, a buffer should pop up to let the
4233 ;; user toggle the values of variables.
4234 (t (setq-default vip-ex-style-editing-in-insert
1e70790f 4235 (viper-standard-value 'vip-ex-style-editing-in-insert)
d5e52f99 4236 vip-ex-style-motion
1e70790f 4237 (viper-standard-value 'vip-ex-style-motion))
d5e52f99 4238 (setq vip-want-ctl-h-help
1e70790f 4239 (viper-standard-value 'vip-want-ctl-h-help)
e36a387d 4240 viper-always
1e70790f 4241 (viper-standard-value 'viper-always)
d5e52f99 4242 vip-no-multiple-ESC
1e70790f 4243 (viper-standard-value 'vip-no-multiple-ESC)
d5e52f99 4244 vip-ex-style-motion
1e70790f 4245 (viper-standard-value 'vip-ex-style-motion)
d5e52f99 4246 vip-ex-style-editing-in-insert
1e70790f 4247 (viper-standard-value 'vip-ex-style-editing-in-insert)
d5e52f99 4248 vip-re-search
1e70790f 4249 (viper-standard-value 'vip-re-search)
e36a387d 4250 vip-electric-mode
1e70790f 4251 (viper-standard-value 'vip-electric-mode)
d5e52f99 4252 vip-want-emacs-keys-in-vi
1e70790f 4253 (viper-standard-value 'vip-want-emacs-keys-in-vi)
d5e52f99 4254 vip-want-emacs-keys-in-insert
1e70790f
MK
4255 (viper-standard-value 'vip-want-emacs-keys-in-insert))))
4256
d5e52f99 4257 (vip-set-mode-vars-for vip-current-state)
e36a387d 4258 (if (or viper-always
1e70790f 4259 (and (> viper-expert-level 0) (> 5 viper-expert-level)))
d5e52f99
MK
4260 (vip-set-hooks)))
4261
4262;; Ask user expert level.
4263(defun vip-ask-level (dont-change-unless)
4264 (let ((ask-buffer " *vip-ask-level*")
4265 level-changed repeated)
4266 (save-window-excursion
4267 (switch-to-buffer ask-buffer)
4268
1e70790f
MK
4269 (while (or (> viper-expert-level viper-max-expert-level)
4270 (< viper-expert-level 1)
d5e52f99
MK
4271 (null dont-change-unless))
4272 (erase-buffer)
4273 (if repeated
4274 (progn
4275 (message "Invalid user level")
4276 (beep 1))
4277 (setq repeated t))
4278 (setq dont-change-unless t
4279 level-changed t)
4280 (insert "
4281Please specify your level of familiarity with the venomous VI PERil
4282(and the VI Plan for Emacs Rescue).
1e70790f 4283You can change it at any time by typing `M-x viper-set-expert-level RET'
d5e52f99
MK
4284
4285 1 -- BEGINNER: Almost all Emacs features are suppressed.
4286 Feels almost like straight Vi. File name completion and
4287 command history in the minibuffer are thrown in as a bonus.
4288 To use Emacs productively, you must reach level 3 or higher.
4289 2 -- MASTER: C-c now has its standard Emacs meaning in Vi command state,
4290 so most Emacs commands can be used when Viper is in Vi state.
4291 Good progress---you are well on the way to level 3!
4292 3 -- GRAND MASTER: Like 3, but most Emacs commands are available also
4293 in Viper's insert state.
4294 4 -- GURU: Like 3, but user settings are respected for vip-no-multiple-ESC,
4295 vip-re-search, vip-ex-style-motion, & vip-ex-style-editing-in-insert
4296 variables. Adjust these settings to your taste.
e36a387d
MK
4297 5 -- WIZARD: Like 4, but user settings are also respected for viper-always,
4298 vip-electric-mode, vip-want-ctl-h-help, vip-want-emacs-keys-in-vi,
4299 and vip-want-emacs-keys-in-insert. Adjust these to your taste.
d5e52f99
MK
4300
4301Please, specify your level now: ")
4302
1e70790f 4303 (setq viper-expert-level (- (vip-read-char-exclusive) ?0))
d5e52f99
MK
4304 ) ; end while
4305
4306 ;; tell the user if level was changed
4307 (and level-changed
4308 (progn
4309 (insert
4310 (format "\n\n\n\n\n\t\tYou have selected user level %d"
1e70790f 4311 viper-expert-level))
d5e52f99 4312 (if (y-or-n-p "Do you wish to make this change permanent? ")
1e70790f 4313 ;; save the setting for viper-expert-level
d5e52f99 4314 (vip-save-setting
1e70790f
MK
4315 'viper-expert-level
4316 (format "Saving user level %d ..." viper-expert-level)
d5e52f99
MK
4317 vip-custom-file-name))
4318 ))
4319 (bury-buffer) ; remove ask-buffer from screen
4320 (message "")
4321 )))
4322
4323
4324(defun vip-nil ()
4325 (interactive)
4326 (beep 1))
4327
4328
4329;; if ENFORCE-BUFFER is not nil, error if CHAR is a marker in another buffer
4330(defun vip-register-to-point (char &optional enforce-buffer)
4331 "Like jump-to-register, but switches to another buffer in another window."
4332 (interactive "cViper register to point: ")
4333 (let ((val (get-register char)))
4334 (cond
4335 ((and (fboundp 'frame-configuration-p)
4336 (frame-configuration-p val))
4337 (set-frame-configuration val))
4338 ((window-configuration-p val)
4339 (set-window-configuration val))
4340 ((vip-valid-marker val)
4341 (if (and enforce-buffer
4342 (not (equal (current-buffer) (marker-buffer val))))
4343 (error (concat vip-EmptyTextmarker " in this buffer")
4344 (1- (+ char ?a))))
4345 (pop-to-buffer (marker-buffer val))
4346 (goto-char val))
4347 ((and (consp val) (eq (car val) 'file))
4348 (find-file (cdr val)))
4349 (t
4350 (error vip-EmptyTextmarker (1- (+ char ?a)))))))
4351
4352
4353(defun vip-save-kill-buffer ()
4354 "Save then kill current buffer. "
4355 (interactive)
1e70790f 4356 (if (< viper-expert-level 2)
d5e52f99
MK
4357 (save-buffers-kill-emacs)
4358 (save-buffer)
4359 (kill-buffer (current-buffer))))
4360
4361
4362\f
4363;;; Bug Report
4364
4365(defun vip-submit-report ()
4366 "Submit bug report on Viper."
4367 (interactive)
4368 (let ((reporter-prompt-for-summary-p t)
4369 (vip-device-type (vip-device-type))
4370 color-display-p frame-parameters
4371 minibuffer-emacs-face minibuffer-vi-face minibuffer-insert-face
4372 varlist salutation window-config)
4373
4374 ;; If mode info is needed, add variable to `let' and then set it below,
4375 ;; like we did with color-display-p.
4376 (setq color-display-p (if (vip-window-display-p)
4377 (vip-color-display-p)
4378 'non-x)
4379 minibuffer-vi-face (if (vip-has-face-support-p)
4380 (vip-get-face vip-minibuffer-vi-face)
4381 'non-x)
4382 minibuffer-insert-face (if (vip-has-face-support-p)
4383 (vip-get-face vip-minibuffer-insert-face)
4384 'non-x)
4385 minibuffer-emacs-face (if (vip-has-face-support-p)
4386 (vip-get-face vip-minibuffer-emacs-face)
4387 'non-x)
4388 frame-parameters (if (fboundp 'frame-parameters)
4389 (frame-parameters (selected-frame))))
4390
4391 (setq varlist (list 'vip-vi-minibuffer-minor-mode
4392 'vip-insert-minibuffer-minor-mode
4393 'vip-vi-intercept-minor-mode
4394 'vip-vi-local-user-minor-mode
4395 'vip-vi-kbd-minor-mode
4396 'vip-vi-global-user-minor-mode
4397 'vip-vi-state-modifier-minor-mode
4398 'vip-vi-diehard-minor-mode
4399 'vip-vi-basic-minor-mode
4400 'vip-replace-minor-mode
4401 'vip-insert-intercept-minor-mode
4402 'vip-insert-local-user-minor-mode
4403 'vip-insert-kbd-minor-mode
4404 'vip-insert-global-user-minor-mode
4405 'vip-insert-state-modifier-minor-mode
4406 'vip-insert-diehard-minor-mode
4407 'vip-insert-basic-minor-mode
4408 'vip-emacs-intercept-minor-mode
4409 'vip-emacs-local-user-minor-mode
4410 'vip-emacs-kbd-minor-mode
4411 'vip-emacs-global-user-minor-mode
4412 'vip-emacs-state-modifier-minor-mode
4413 'vip-automatic-iso-accents
4414 'vip-want-emacs-keys-in-insert
4415 'vip-want-emacs-keys-in-vi
4416 'vip-keep-point-on-undo
4417 'vip-no-multiple-ESC
e36a387d 4418 'vip-electric-mode
d5e52f99
MK
4419 'vip-ESC-key
4420 'vip-want-ctl-h-help
4421 'vip-ex-style-editing-in-insert
4422 'vip-delete-backwards-in-replace
4423 'vip-vi-style-in-minibuffer
4424 'vip-vi-state-hook
4425 'vip-insert-state-hook
4426 'vip-replace-state-hook
4427 'vip-emacs-state-hook
4428 'ex-cycle-other-window
4429 'ex-cycle-through-non-files
1e70790f 4430 'viper-expert-level
d5e52f99
MK
4431 'major-mode
4432 'vip-device-type
4433 'color-display-p
4434 'frame-parameters
4435 'minibuffer-vi-face
4436 'minibuffer-insert-face
4437 'minibuffer-emacs-face
4438 ))
4439 (setq salutation "
4440Congratulations! You may have unearthed a bug in Viper!
4441Please mail a concise, accurate summary of the problem to the address above.
4442
4443-------------------------------------------------------------------")
4444 (setq window-config (current-window-configuration))
4445 (with-output-to-temp-buffer " *vip-info*"
4446 (switch-to-buffer " *vip-info*")
4447 (delete-other-windows)
4448 (princ "
4449PLEASE FOLLOW THESE PROCEDURES
4450------------------------------
4451
4452Before reporting a bug, please verify that it is related to Viper, and is
4453not cause by other packages you are using.
4454
4455Don't report compilation warnings, unless you are certain that there is a
4456problem. These warnings are normal and unavoidable.
4457
4458Please note that users should not modify variables and keymaps other than
4459those advertised in the manual. Such `customization' is likely to crash
4460Viper, as it would any other improperly customized Emacs package.
4461
4462If you are reporting an error message received while executing one of the
4463Viper commands, type:
4464
4465 M-x set-variable <Return> debug-on-error <Return> t <Return>
4466
4467Then reproduce the error. The above command will cause Emacs to produce a
4468back trace of the execution that leads to the error. Please include this
4469trace in your bug report.
4470
4471If you believe that one of Viper's commands goes into an infinite loop
4472\(e.g., Emacs freezes\), type:
4473
4474 M-x set-variable <Return> debug-on-quit <Return> t <Return>
4475
4476Then reproduce the problem. Wait for a few seconds, then type C-g to abort
4477the current command. Include the resulting back trace in the bug report.
4478
4479Mail anyway (y or n)? ")
4480 (if (y-or-n-p "Mail anyway? ")
4481 ()
4482 (set-window-configuration window-config)
4483 (error "Bug report aborted")))
4484
4485 (require 'reporter)
4486 (set-window-configuration window-config)
4487
4488 (reporter-submit-bug-report "kifer@cs.sunysb.edu"
4489 (vip-version)
4490 varlist
4491 nil 'delete-other-windows
4492 salutation)
4493 ))
4494
4495
4496
4497
4498;; Smoothes out the difference between Emacs' unread-command-events
4499;; and XEmacs unread-command-event. Arg is a character, an event, a list of
4500;; events or a sequence of keys.
4501;;
4502;; Due to the way unread-command-events in Emacs (not XEmacs), a non-event
4503;; symbol in unread-command-events list may cause Emacs to turn this symbol
4504;; into an event. Below, we delete nil from event lists, since nil is the most
4505;; common symbol that might appear in this wrong context.
4506(defun vip-set-unread-command-events (arg)
4507 (if vip-emacs-p
4508 (setq
4509 unread-command-events
4510 (let ((new-events
4511 (cond ((eventp arg) (list arg))
4512 ((listp arg) arg)
4513 ((sequencep arg)
4514 (listify-key-sequence arg))
4515 (t (error
4516 "vip-set-unread-command-events: Invalid argument, %S"
4517 arg)))))
4518 (if (not (eventp nil))
4519 (setq new-events (delq nil new-events)))
4520 (append new-events unread-command-events)))
4521 ;; XEmacs
4522 (setq
4523 unread-command-events
4524 (append
4525 (cond ((vip-characterp arg) (list (character-to-event arg)))
4526 ((eventp arg) (list arg))
4527 ((stringp arg) (mapcar 'character-to-event arg))
4528 ((vectorp arg) (append arg nil)) ; turn into list
4529 ((listp arg) (vip-eventify-list-xemacs arg))
4530 (t (error
4531 "vip-set-unread-command-events: Invalid argument, %S" arg)))
4532 unread-command-events))))
4533
4534;; list is assumed to be a list of events of characters
4535(defun vip-eventify-list-xemacs (lis)
4536 (mapcar
4537 (function (lambda (elt)
4538 (cond ((vip-characterp elt) (character-to-event elt))
4539 ((eventp elt) elt)
4540 (t (error
4541 "vip-eventify-list-xemacs: can't convert to event, %S"
4542 elt)))))
4543 lis))
4544
4545
4546
4547;;; viper-cmd.el ends here