comparison lisp/emulation/viper-cmd.el @ 19462:a3240ad2e954

new version
author Michael Kifer <kifer@cs.stonybrook.edu>
date Fri, 22 Aug 1997 03:15:57 +0000
parents 58c50205001d
children 22c1e47f66e1
comparison
equal deleted inserted replaced
19461:6b67f20dd710 19462:a3240ad2e954
14 (defvar viper-minibuffer-emacs-face) 14 (defvar viper-minibuffer-emacs-face)
15 (defvar viper-always) 15 (defvar viper-always)
16 (defvar viper-mode-string) 16 (defvar viper-mode-string)
17 (defvar viper-custom-file-name) 17 (defvar viper-custom-file-name)
18 (defvar iso-accents-mode) 18 (defvar iso-accents-mode)
19 (defvar quail-mode)
20 (defvar quail-current-str)
19 (defvar zmacs-region-stays) 21 (defvar zmacs-region-stays)
20 (defvar mark-even-if-inactive) 22 (defvar mark-even-if-inactive)
21 23
22 ;; loading happens only in non-interactive compilation 24 ;; loading happens only in non-interactive compilation
23 ;; in order to spare non-viperized emacs from being viperized 25 ;; in order to spare non-viperized emacs from being viperized
215 ((eq viper-current-state 'replace-state) 217 ((eq viper-current-state 'replace-state)
216 ;; delete characters to compensate for inserted chars. 218 ;; delete characters to compensate for inserted chars.
217 (let ((replace-boundary (viper-replace-end))) 219 (let ((replace-boundary (viper-replace-end)))
218 (save-excursion 220 (save-excursion
219 (goto-char viper-last-posn-in-replace-region) 221 (goto-char viper-last-posn-in-replace-region)
222 (viper-trim-replace-chars-to-delete-if-necessary)
220 (delete-char viper-replace-chars-to-delete) 223 (delete-char viper-replace-chars-to-delete)
221 (setq viper-replace-chars-to-delete 0 224 (setq viper-replace-chars-to-delete 0)
222 viper-replace-chars-deleted 0)
223 ;; terminate replace mode if reached replace limit 225 ;; terminate replace mode if reached replace limit
224 (if (= viper-last-posn-in-replace-region 226 (if (= viper-last-posn-in-replace-region (viper-replace-end))
225 (viper-replace-end)) 227 (viper-finish-change)))
226 (viper-finish-change viper-last-posn-in-replace-region)))
227 228
228 (if (and (<= (viper-replace-start) (point)) 229 (if (viper-pos-within-region
229 (<= (point) replace-boundary)) 230 (point) (viper-replace-start) replace-boundary)
230 (progn 231 (progn
231 ;; the state may have changed in viper-finish-change above 232 ;; the state may have changed in viper-finish-change above
232 (if (eq viper-current-state 'replace-state) 233 (if (eq viper-current-state 'replace-state)
233 (viper-change-cursor-color viper-replace-overlay-cursor-color)) 234 (viper-change-cursor-color viper-replace-overlay-cursor-color))
234 (setq viper-last-posn-in-replace-region (point-marker)))) 235 (setq viper-last-posn-in-replace-region (point-marker))))
235 )) 236 ))
236 237 ;; terminate replace mode if changed Viper states.
237 (t ;; terminate replace mode if changed Viper states. 238 (t (viper-finish-change))))
238 (viper-finish-change viper-last-posn-in-replace-region))))
239 239
240 240
241 ;; changing mode 241 ;; changing mode
242 242
243 ;; Change state to NEW-STATE---either emacs-state, vi-state, or insert-state. 243 ;; Change state to NEW-STATE---either emacs-state, vi-state, or insert-state.
284 284
285 (if (> (length viper-last-insertion) 0) 285 (if (> (length viper-last-insertion) 0)
286 (viper-push-onto-ring viper-last-insertion 286 (viper-push-onto-ring viper-last-insertion
287 'viper-insertion-ring)) 287 'viper-insertion-ring))
288 288
289 (if viper-ex-style-editing-in-insert 289 (if viper-ex-style-editing
290 (or (bolp) (backward-char 1)))) 290 (or (bolp) (backward-char 1))))
291 )) 291 ))
292 292
293 ;; insert or replace 293 ;; insert or replace
294 ((memq new-state '(insert-state replace-state)) 294 ((memq new-state '(insert-state replace-state))
303 ) ; outermost cond 303 ) ; outermost cond
304 304
305 ;; Nothing needs to be done to switch to emacs mode! Just set some 305 ;; Nothing needs to be done to switch to emacs mode! Just set some
306 ;; variables, which is already done in viper-change-state-to-emacs! 306 ;; variables, which is already done in viper-change-state-to-emacs!
307 307
308 ;; ISO accents
309 ;; always turn off iso-accents-mode in vi-state, or else we won't be able to
310 ;; use the keys `,',^ , as they will do accents instead of Vi actions.
311 (cond ((eq new-state 'vi-state) (viper-set-iso-accents-mode nil));accents off
312 (viper-automatic-iso-accents (viper-set-iso-accents-mode t));accents on
313 (t (viper-set-iso-accents-mode nil)))
314 ;; Always turn off quail mode in vi state
315 (cond ((eq new-state 'vi-state) (viper-set-input-method nil)) ;intl input off
316 (viper-special-input-method (viper-set-input-method t)) ;intl input on
317 (t (viper-set-input-method nil)))
318
308 (setq viper-current-state new-state) 319 (setq viper-current-state new-state)
320
321 (viper-update-syntax-classes)
309 (viper-normalize-minor-mode-map-alist) 322 (viper-normalize-minor-mode-map-alist)
310 (viper-adjust-keys-for new-state) 323 (viper-adjust-keys-for new-state)
311 (viper-set-mode-vars-for new-state) 324 (viper-set-mode-vars-for new-state)
312 (viper-refresh-mode-line) 325 (viper-refresh-mode-line)
313 ) 326 )
331 (setq viper-insert-diehard-minor-mode 344 (setq viper-insert-diehard-minor-mode
332 (not viper-want-emacs-keys-in-insert)) 345 (not viper-want-emacs-keys-in-insert))
333 346
334 (if viper-want-ctl-h-help 347 (if viper-want-ctl-h-help
335 (progn 348 (progn
349 (define-key viper-insert-basic-map [backspace] 'help-command)
350 (define-key viper-replace-map [backspace] 'help-command)
336 (define-key viper-insert-basic-map [(control h)] 'help-command) 351 (define-key viper-insert-basic-map [(control h)] 'help-command)
337 (define-key viper-replace-map [(control h)] 'help-command)) 352 (define-key viper-replace-map [(control h)] 'help-command))
353 (define-key viper-insert-basic-map
354 [backspace] 'viper-del-backward-char-in-insert)
355 (define-key viper-replace-map
356 [backspace] 'viper-del-backward-char-in-replace)
338 (define-key viper-insert-basic-map 357 (define-key viper-insert-basic-map
339 [(control h)] 'viper-del-backward-char-in-insert) 358 [(control h)] 'viper-del-backward-char-in-insert)
340 (define-key viper-replace-map 359 (define-key viper-replace-map
341 [(control h)] 'viper-del-backward-char-in-replace))) 360 [(control h)] 'viper-del-backward-char-in-replace)))
342 361
343 (t ; Vi state 362 (t ; Vi state
344 (setq viper-vi-diehard-minor-mode (not viper-want-emacs-keys-in-vi)) 363 (setq viper-vi-diehard-minor-mode (not viper-want-emacs-keys-in-vi))
345 (if viper-want-ctl-h-help 364 (if viper-want-ctl-h-help
346 (define-key viper-vi-basic-map [(control h)] 'help-command) 365 (progn
366 (define-key viper-vi-basic-map [backspace] 'help-command)
367 (define-key viper-vi-basic-map [(control h)] 'help-command))
368 (define-key viper-vi-basic-map [backspace] 'viper-backward-char)
347 (define-key viper-vi-basic-map [(control h)] 'viper-backward-char))) 369 (define-key viper-vi-basic-map [(control h)] 'viper-backward-char)))
348 )) 370 ))
349 371
350 372
351 ;; Normalizes minor-mode-map-alist by putting Viper keymaps first. 373 ;; Normalizes minor-mode-map-alist by putting Viper keymaps first.
535 viper-open-line viper-Open-line 557 viper-open-line viper-Open-line
536 viper-replace-state-exit-cmd)) 558 viper-replace-state-exit-cmd))
537 (viper-over-whitespace-line)) 559 (viper-over-whitespace-line))
538 (indent-to-left-margin)) 560 (indent-to-left-margin))
539 (viper-add-newline-at-eob-if-necessary) 561 (viper-add-newline-at-eob-if-necessary)
540 (if viper-undo-needs-adjustment (viper-adjust-undo)) 562 (viper-adjust-undo)
541 (viper-change-state 'vi-state) 563 (viper-change-state 'vi-state)
542
543 ;; always turn off iso-accents-mode, or else we won't be able to use the
544 ;; keys `,',^ in Vi state, as they will do accents instead of Vi actions.
545 (if (and (boundp 'iso-accents-mode) iso-accents-mode)
546 (iso-accents-mode -1))
547 564
548 (viper-restore-cursor-color-after-insert) 565 (viper-restore-cursor-color-after-insert)
549 566
550 ;; Protection against user errors in hooks 567 ;; Protect against user errors in hooks
551 (condition-case conds 568 (condition-case conds
552 (run-hooks 'viper-vi-state-hook) 569 (run-hooks 'viper-vi-state-hook)
553 (error 570 (error
554 (viper-message-conditions conds))))) 571 (viper-message-conditions conds)))))
555 572
556 (defun viper-change-state-to-insert () 573 (defun viper-change-state-to-insert ()
557 "Change Viper state to Insert." 574 "Change Viper state to Insert."
558 (interactive) 575 (interactive)
559 (viper-change-state 'insert-state) 576 (viper-change-state 'insert-state)
560 (if (and viper-automatic-iso-accents (fboundp 'iso-accents-mode))
561 (iso-accents-mode 1)) ; turn iso accents on
562 577
563 (or (stringp viper-saved-cursor-color) 578 (or (stringp viper-saved-cursor-color)
564 (string= (viper-get-cursor-color) viper-insert-state-cursor-color) 579 (string= (viper-get-cursor-color) viper-insert-state-cursor-color)
565 (setq viper-saved-cursor-color (viper-get-cursor-color))) 580 (setq viper-saved-cursor-color (viper-get-cursor-color)))
566 ;; Commented out, because if viper-change-state-to-insert is executed 581 ;; Commented out, because if viper-change-state-to-insert is executed
567 ;; non-interactively then the old cursor color may get lost. Same old Emacs 582 ;; non-interactively then the old cursor color may get lost. Same old Emacs
568 ;; bug related to local variables? 583 ;; bug related to local variables?
569 ;;;(if (stringp viper-saved-cursor-color) 584 ;;;(if (stringp viper-saved-cursor-color)
570 ;;; (viper-change-cursor-color viper-insert-state-cursor-color)) 585 ;;; (viper-change-cursor-color viper-insert-state-cursor-color))
571 ;; Protection against user errors in hooks 586
587 ;; Protect against user errors in hooks
572 (condition-case conds 588 (condition-case conds
573 (run-hooks 'viper-insert-state-hook) 589 (run-hooks 'viper-insert-state-hook)
574 (error 590 (error
575 (viper-message-conditions conds)))) 591 (viper-message-conditions conds))))
576 592
582 598
583 ;; Change to replace state. When the end of replacement region is reached, 599 ;; Change to replace state. When the end of replacement region is reached,
584 ;; replace state changes to insert state. 600 ;; replace state changes to insert state.
585 (defun viper-change-state-to-replace (&optional non-R-cmd) 601 (defun viper-change-state-to-replace (&optional non-R-cmd)
586 (viper-change-state 'replace-state) 602 (viper-change-state 'replace-state)
587 (if (and viper-automatic-iso-accents (fboundp 'iso-accents-mode))
588 (iso-accents-mode 1)) ; turn iso accents on
589 ;; Run insert-state-hook 603 ;; Run insert-state-hook
590 (condition-case conds 604 (condition-case conds
591 (run-hooks 'viper-insert-state-hook 'viper-replace-state-hook) 605 (run-hooks 'viper-insert-state-hook 'viper-replace-state-hook)
592 (error 606 (error
593 (viper-message-conditions conds))) 607 (viper-message-conditions conds)))
601 615
602 (defun viper-change-state-to-emacs () 616 (defun viper-change-state-to-emacs ()
603 "Change Viper state to Emacs." 617 "Change Viper state to Emacs."
604 (interactive) 618 (interactive)
605 (viper-change-state 'emacs-state) 619 (viper-change-state 'emacs-state)
606 (if (and viper-automatic-iso-accents (fboundp 'iso-accents-mode)) 620
607 (iso-accents-mode 1)) ; turn iso accents on 621 ;; Protect agains user errors in hooks
608
609 ;; Protection agains user errors in hooks
610 (condition-case conds 622 (condition-case conds
611 (run-hooks 'viper-emacs-state-hook) 623 (run-hooks 'viper-emacs-state-hook)
612 (error 624 (error
613 (viper-message-conditions conds)))) 625 (viper-message-conditions conds))))
614 626
1393 (setq viper-last-insertion (nth 4 viper-d-com) 1405 (setq viper-last-insertion (nth 4 viper-d-com)
1394 viper-d-char (nth 4 viper-d-com))) 1406 viper-d-char (nth 4 viper-d-com)))
1395 (funcall m-com (cons val com)) 1407 (funcall m-com (cons val com))
1396 (cond ((and (< save-point (point)) viper-keep-point-on-repeat) 1408 (cond ((and (< save-point (point)) viper-keep-point-on-repeat)
1397 (goto-char save-point)) ; go back to before repeat. 1409 (goto-char save-point)) ; go back to before repeat.
1398 ((and (< save-point (point)) viper-ex-style-editing-in-insert) 1410 ((and (< save-point (point)) viper-ex-style-editing)
1399 (or (bolp) (backward-char 1)))) 1411 (or (bolp) (backward-char 1))))
1400 (if (and (eolp) (not (bolp))) 1412 (if (and (eolp) (not (bolp)))
1401 (backward-char 1)) 1413 (backward-char 1))
1402 )) 1414 ))
1403 (if viper-undo-needs-adjustment (viper-adjust-undo)) ; take care of undo 1415 (viper-adjust-undo) ; take care of undo
1404 ;; If the prev cmd was rotating the command ring, this means that `.' has 1416 ;; If the prev cmd was rotating the command ring, this means that `.' has
1405 ;; just executed a command from that ring. So, push it on the ring again. 1417 ;; just executed a command from that ring. So, push it on the ring again.
1406 ;; If we are just executing previous command , then don't push viper-d-com 1418 ;; If we are just executing previous command , then don't push viper-d-com
1407 ;; because viper-d-com is not fully constructed in this case (its keys and 1419 ;; because viper-d-com is not fully constructed in this case (its keys and
1408 ;; the inserted text may be nil). Besides, in this case, the command 1420 ;; the inserted text may be nil). Besides, in this case, the command
1493 (progn 1505 (progn
1494 (push-mark (point-marker) t) 1506 (push-mark (point-marker) t)
1495 (viper-sit-for-short 300) 1507 (viper-sit-for-short 300)
1496 (goto-char undo-end-posn) 1508 (goto-char undo-end-posn)
1497 (viper-sit-for-short 300) 1509 (viper-sit-for-short 300)
1498 (if (and (> (abs (- undo-beg-posn before-undo-pt)) 1) 1510 (if (and (> (viper-chars-in-region undo-beg-posn before-undo-pt) 1)
1499 (> (abs (- undo-end-posn before-undo-pt)) 1)) 1511 (> (viper-chars-in-region undo-end-posn before-undo-pt) 1))
1500 (goto-char before-undo-pt) 1512 (goto-char before-undo-pt)
1501 (goto-char undo-beg-posn))) 1513 (goto-char undo-beg-posn)))
1502 (push-mark before-undo-pt t)) 1514 (push-mark before-undo-pt t))
1503 (if (and (eolp) (not (bolp))) (backward-char 1)) 1515 (if (and (eolp) (not (bolp))) (backward-char 1))
1504 (if (not modified) (set-buffer-modified-p t))) 1516 (if (not modified) (set-buffer-modified-p t)))
1516 1528
1517 ;; The following two functions are used to set up undo properly. 1529 ;; The following two functions are used to set up undo properly.
1518 ;; In VI, unlike Emacs, if you open a line, say, and add a bunch of lines, 1530 ;; In VI, unlike Emacs, if you open a line, say, and add a bunch of lines,
1519 ;; they are undone all at once. 1531 ;; they are undone all at once.
1520 (defun viper-adjust-undo () 1532 (defun viper-adjust-undo ()
1521 (let ((inhibit-quit t) 1533 (if viper-undo-needs-adjustment
1522 tmp tmp2) 1534 (let ((inhibit-quit t)
1523 (setq viper-undo-needs-adjustment nil) 1535 tmp tmp2)
1524 (if (listp buffer-undo-list) 1536 (setq viper-undo-needs-adjustment nil)
1525 (if (setq tmp (memq viper-buffer-undo-list-mark buffer-undo-list)) 1537 (if (listp buffer-undo-list)
1526 (progn 1538 (if (setq tmp (memq viper-buffer-undo-list-mark buffer-undo-list))
1527 (setq tmp2 (cdr tmp)) ; the part after mark 1539 (progn
1528 1540 (setq tmp2 (cdr tmp)) ; the part after mark
1529 ;; cut tail from buffer-undo-list temporarily by direct 1541
1530 ;; manipulation with pointers in buffer-undo-list 1542 ;; cut tail from buffer-undo-list temporarily by direct
1531 (setcdr tmp nil) 1543 ;; manipulation with pointers in buffer-undo-list
1532 1544 (setcdr tmp nil)
1533 (setq buffer-undo-list (delq nil buffer-undo-list)) 1545
1534 (setq buffer-undo-list 1546 (setq buffer-undo-list (delq nil buffer-undo-list))
1535 (delq viper-buffer-undo-list-mark buffer-undo-list)) 1547 (setq buffer-undo-list
1536 ;; restore tail of buffer-undo-list 1548 (delq viper-buffer-undo-list-mark buffer-undo-list))
1537 (setq buffer-undo-list (nconc buffer-undo-list tmp2))) 1549 ;; restore tail of buffer-undo-list
1538 (setq buffer-undo-list (delq nil buffer-undo-list)))))) 1550 (setq buffer-undo-list (nconc buffer-undo-list tmp2)))
1551 (setq buffer-undo-list (delq nil buffer-undo-list)))))
1552 ))
1539 1553
1540 1554
1541 (defun viper-set-complex-command-for-undo () 1555 (defun viper-set-complex-command-for-undo ()
1542 (if (listp buffer-undo-list) 1556 (if (listp buffer-undo-list)
1543 (if (not viper-undo-needs-adjustment) 1557 (if (not viper-undo-needs-adjustment)
1558 1572
1559 (message " `.' runs %s%s" 1573 (message " `.' runs %s%s"
1560 (concat "`" (viper-array-to-string keys) "'") 1574 (concat "`" (viper-array-to-string keys) "'")
1561 (viper-abbreviate-string 1575 (viper-abbreviate-string
1562 (if viper-xemacs-p 1576 (if viper-xemacs-p
1563 (replace-in-string text "\n" "^J") 1577 (replace-in-string
1578 (cond ((characterp text) (char-to-string text))
1579 ((stringp text) text)
1580 (t ""))
1581 "\n" "^J")
1564 text) 1582 text)
1565 max-text-len 1583 max-text-len
1566 " inserting `" "'" " .......")) 1584 " inserting `" "'" " ......."))
1567 )) 1585 ))
1568 1586
1890 (com (viper-getcom arg))) 1908 (com (viper-getcom arg)))
1891 (viper-set-destructive-command (list 'viper-open-line val ?r nil nil nil)) 1909 (viper-set-destructive-command (list 'viper-open-line val ?r nil nil nil))
1892 (let ((col (current-indentation))) 1910 (let ((col (current-indentation)))
1893 (if (equal com ?r) 1911 (if (equal com ?r)
1894 (viper-loop val 1912 (viper-loop val
1895 (progn
1896 (end-of-line) 1913 (end-of-line)
1897 (newline 1) 1914 (newline 1)
1898 (if viper-auto-indent 1915 (if viper-auto-indent
1899 (progn 1916 (progn
1900 (setq viper-cted t) 1917 (setq viper-cted t)
1901 (if viper-electric-mode 1918 (if viper-electric-mode
1902 (indent-according-to-mode) 1919 (indent-according-to-mode)
1903 (indent-to col)) 1920 (indent-to col))
1904 )) 1921 ))
1905 (viper-yank-last-insertion))) 1922 (viper-yank-last-insertion))
1906 (end-of-line) 1923 (end-of-line)
1907 (newline 1) 1924 (newline 1)
1908 (if viper-auto-indent 1925 (if viper-auto-indent
1909 (progn 1926 (progn
1910 (setq viper-cted t) 1927 (setq viper-cted t)
1921 (com (viper-getcom arg))) 1938 (com (viper-getcom arg)))
1922 (viper-set-destructive-command (list 'viper-Open-line val ?r nil nil nil)) 1939 (viper-set-destructive-command (list 'viper-Open-line val ?r nil nil nil))
1923 (let ((col (current-indentation))) 1940 (let ((col (current-indentation)))
1924 (if (equal com ?r) 1941 (if (equal com ?r)
1925 (viper-loop val 1942 (viper-loop val
1926 (progn
1927 (beginning-of-line) 1943 (beginning-of-line)
1928 (open-line 1) 1944 (open-line 1)
1929 (if viper-auto-indent 1945 (if viper-auto-indent
1930 (progn 1946 (progn
1931 (setq viper-cted t) 1947 (setq viper-cted t)
1932 (if viper-electric-mode 1948 (if viper-electric-mode
1933 (indent-according-to-mode) 1949 (indent-according-to-mode)
1934 (indent-to col)) 1950 (indent-to col))
1935 )) 1951 ))
1936 (viper-yank-last-insertion))) 1952 (viper-yank-last-insertion))
1937 (beginning-of-line) 1953 (beginning-of-line)
1938 (open-line 1) 1954 (open-line 1)
1939 (if viper-auto-indent 1955 (if viper-auto-indent
1940 (progn 1956 (progn
1941 (setq viper-cted t) 1957 (setq viper-cted t)
1953 (com (viper-getcom arg))) 1969 (com (viper-getcom arg)))
1954 (viper-set-destructive-command 1970 (viper-set-destructive-command
1955 (list 'viper-open-line-at-point val ?r nil nil nil)) 1971 (list 'viper-open-line-at-point val ?r nil nil nil))
1956 (if (equal com ?r) 1972 (if (equal com ?r)
1957 (viper-loop val 1973 (viper-loop val
1958 (progn
1959 (open-line 1) 1974 (open-line 1)
1960 (viper-yank-last-insertion))) 1975 (viper-yank-last-insertion))
1961 (open-line 1) 1976 (open-line 1)
1962 (viper-change-state-to-insert)))) 1977 (viper-change-state-to-insert))))
1963 1978
1964 (defun viper-substitute (arg) 1979 (defun viper-substitute (arg)
1965 "Substitute characters." 1980 "Substitute characters."
1983 1998
1984 ;; Prepare for replace 1999 ;; Prepare for replace
1985 (defun viper-start-replace () 2000 (defun viper-start-replace ()
1986 (setq viper-began-as-replace t 2001 (setq viper-began-as-replace t
1987 viper-sitting-in-replace t 2002 viper-sitting-in-replace t
1988 viper-replace-chars-to-delete 0 2003 viper-replace-chars-to-delete 0)
1989 viper-replace-chars-deleted 0)
1990 (viper-add-hook 2004 (viper-add-hook
1991 'viper-after-change-functions 'viper-replace-mode-spy-after t) 2005 'viper-after-change-functions 'viper-replace-mode-spy-after t)
1992 (viper-add-hook 2006 (viper-add-hook
1993 'viper-before-change-functions 'viper-replace-mode-spy-before t) 2007 'viper-before-change-functions 'viper-replace-mode-spy-before t)
1994 ;; this will get added repeatedly, but no harm 2008 ;; this will get added repeatedly, but no harm
2005 'viper-post-command-hooks 'viper-R-state-post-command-sentinel) 2019 'viper-post-command-hooks 'viper-R-state-post-command-sentinel)
2006 (if overwrite-mode (overwrite-mode nil)) 2020 (if overwrite-mode (overwrite-mode nil))
2007 ) 2021 )
2008 2022
2009 2023
2010 ;; checks how many chars were deleted by the last change
2011 (defun viper-replace-mode-spy-before (beg end) 2024 (defun viper-replace-mode-spy-before (beg end)
2012 (setq viper-replace-chars-deleted 2025 (setq viper-replace-region-chars-deleted (viper-chars-in-region beg end))
2013 (- end beg 2026 )
2014 (max 0 (- end (viper-replace-end))) 2027
2015 (max 0 (- (viper-replace-start) beg)) 2028 ;; Invoked as an after-change-function to calculate how many chars have to be
2016 ))) 2029 ;; deleted. This function may be called several times within a single command,
2017 2030 ;; if this command performs several separate buffer changes. Therefore, if adds
2018 ;; Invoked as an after-change-function to set up parameters of the last change 2031 ;; up the number of chars inserted and subtracts the number of chars deleted.
2019 (defun viper-replace-mode-spy-after (beg end length) 2032 (defun viper-replace-mode-spy-after (beg end length)
2020 (if (memq viper-intermediate-command '(repeating-insertion-from-ring)) 2033 (if (memq viper-intermediate-command
2034 '(dabbrev-expand repeating-insertion-from-ring))
2035 ;; Take special care of text insertion from insertion ring inside
2036 ;; replacement overlays.
2021 (progn 2037 (progn
2022 (setq viper-replace-chars-to-delete 0) 2038 (setq viper-replace-chars-to-delete 0)
2023 (viper-move-marker-locally 2039 (viper-move-marker-locally
2024 'viper-last-posn-in-replace-region (point))) 2040 'viper-last-posn-in-replace-region (point)))
2025 2041
2026 (let (beg-col end-col real-end chars-to-delete) 2042 (let* ((real-end (min end (viper-replace-end)))
2027 (setq real-end (min end (viper-replace-end))) 2043 (column-shift (- (save-excursion (goto-char real-end)
2028 (save-excursion 2044 (current-column))
2029 (goto-char beg) 2045 (save-excursion (goto-char beg)
2030 (setq beg-col (current-column)) 2046 (current-column))))
2031 (goto-char real-end) 2047 (chars-deleted 0))
2032 (setq end-col (current-column))) 2048
2033 2049 (if (> length 0)
2034 ;; If beg of change is outside the replacement region, then don't 2050 (setq chars-deleted viper-replace-region-chars-deleted))
2035 ;; delete anything in the repl region (set chars-to-delete to 0). 2051 (setq viper-replace-region-chars-deleted 0)
2036 ;; 2052 (setq viper-replace-chars-to-delete
2037 ;; This works fine except that we have to take special care of 2053 (+ viper-replace-chars-to-delete
2038 ;; dabbrev-expand. The problem stems from new-dabbrev.el, which 2054 (-
2039 ;; sometimes simply shifts the repl region rightwards, without 2055 ;; if column shift is bigger, due to a TAB insertion, take
2040 ;; deleting an equal amount of characters. 2056 ;; column-shift instead of the number of inserted chars
2041 ;; 2057 (max (viper-chars-in-region beg real-end)
2042 ;; The reason why new-dabbrev.el causes this are this: 2058 ;; This test accounts for Chinese/Japanese/... chars,
2043 ;; if one dinamically completes a partial word that starts before the 2059 ;; which occupy 2 columns instead of one. If we use
2044 ;; replacement region (but ends inside) then new-dabbrev.el first 2060 ;; column-shift here, we may delete two chars instead of
2045 ;; moves cursor backwards, to the beginning of the word to be 2061 ;; one when the user types one Chinese character. Deleting
2046 ;; completed (say, pt A). Then it inserts the 2062 ;; two would be OK, if they were European chars, but it is
2047 ;; completed word and then deletes the old, incomplete part. 2063 ;; not OK if they are Chinese chars. Since it is hard to
2048 ;; Since the complete word is inserted at position before the repl 2064 ;; figure out which characters are being deleted in any
2049 ;; region, the next If-statement would have set chars-to-delete to 0 2065 ;; given region, we decided to treat Eastern and European
2050 ;; unless we check for the current command, which must be 2066 ;; characters equally, even though Eastern chars may
2051 ;; dabbrev-expand. 2067 ;; occupy more columns.
2052 ;; 2068 (if (memq this-command '(self-insert-command
2053 ;; In fact, it might be also useful to have overlays for insert 2069 quoted-insert viper-insert-tab))
2054 ;; regions as well, since this will let us capture the situation when 2070 column-shift
2055 ;; dabbrev-expand goes back past the insertion point to find the 2071 0))
2056 ;; beginning of the word to be expanded. 2072 ;; the number of deleted chars
2057 (if (or (and (<= (viper-replace-start) beg) 2073 chars-deleted)))
2058 (<= beg (viper-replace-end))) 2074
2059 (and (= length 0) (eq this-command 'dabbrev-expand)))
2060 (setq chars-to-delete
2061 (max (- end-col beg-col) (- real-end beg) 0))
2062 (setq chars-to-delete 0))
2063
2064 ;; if beg = last change position, it means that we are within the
2065 ;; same command that does multiple changes. Moreover, it means
2066 ;; that we have two subsequent changes (insert/delete) that
2067 ;; complement each other.
2068 (if (= beg (marker-position viper-last-posn-in-replace-region))
2069 (setq viper-replace-chars-to-delete
2070 (- (+ chars-to-delete viper-replace-chars-to-delete)
2071 viper-replace-chars-deleted))
2072 (setq viper-replace-chars-to-delete chars-to-delete))
2073
2074 (viper-move-marker-locally 2075 (viper-move-marker-locally
2075 'viper-last-posn-in-replace-region 2076 'viper-last-posn-in-replace-region
2076 (max (if (> end (viper-replace-end)) (viper-replace-start) end) 2077 (max (if (> end (viper-replace-end)) (viper-replace-end) end)
2077 (or (marker-position viper-last-posn-in-replace-region) 2078 (or (marker-position viper-last-posn-in-replace-region)
2078 (viper-replace-start)) 2079 (viper-replace-start))
2079 )) 2080 ))
2080 2081
2081 (setq viper-replace-chars-to-delete
2082 (max 0
2083 (min viper-replace-chars-to-delete
2084 (- (viper-replace-end) viper-last-posn-in-replace-region)
2085 (- (viper-line-pos 'end)
2086 viper-last-posn-in-replace-region)
2087 )))
2088 ))) 2082 )))
2089 2083
2090 2084 ;; Make sure we don't delete more than needed.
2091 ;; Delete stuff between posn and the end of viper-replace-overlay-marker, if 2085 ;; This is executed at viper-last-posn-in-replace-region
2092 ;; posn is within the overlay. 2086 (defsubst viper-trim-replace-chars-to-delete-if-necessary ()
2093 (defun viper-finish-change (posn) 2087 (setq viper-replace-chars-to-delete
2088 (max 0
2089 (min viper-replace-chars-to-delete
2090 ;; Don't delete more than to the end of repl overlay
2091 (viper-chars-in-region
2092 (viper-replace-end) viper-last-posn-in-replace-region)
2093 ;; point is viper-last-posn-in-replace-region now
2094 ;; So, this limits deletion to the end of line
2095 (viper-chars-in-region (point) (viper-line-pos 'end))
2096 ))))
2097
2098
2099 ;; Delete stuff between viper-last-posn-in-replace-region and the end of
2100 ;; viper-replace-overlay-marker, if viper-last-posn-in-replace-region is within
2101 ;; the overlay and current point is before the end of the overlay.
2102 ;; Don't delete anything if current point is past the end of the overlay.
2103 (defun viper-finish-change ()
2094 (viper-remove-hook 2104 (viper-remove-hook
2095 'viper-after-change-functions 'viper-replace-mode-spy-after) 2105 'viper-after-change-functions 'viper-replace-mode-spy-after)
2096 (viper-remove-hook 2106 (viper-remove-hook
2097 'viper-before-change-functions 'viper-replace-mode-spy-before) 2107 'viper-before-change-functions 'viper-replace-mode-spy-before)
2098 (viper-remove-hook 2108 (viper-remove-hook
2100 (viper-remove-hook 2110 (viper-remove-hook
2101 'viper-pre-command-hooks 'viper-replace-state-pre-command-sentinel) 2111 'viper-pre-command-hooks 'viper-replace-state-pre-command-sentinel)
2102 (viper-restore-cursor-color-after-replace) 2112 (viper-restore-cursor-color-after-replace)
2103 (setq viper-sitting-in-replace nil) ; just in case we'll need to know it 2113 (setq viper-sitting-in-replace nil) ; just in case we'll need to know it
2104 (save-excursion 2114 (save-excursion
2105 (if (and 2115 (if (and viper-replace-overlay
2106 viper-replace-overlay 2116 (viper-pos-within-region viper-last-posn-in-replace-region
2107 (>= posn (viper-replace-start)) 2117 (viper-replace-start)
2108 (< posn (viper-replace-end))) 2118 (viper-replace-end))
2109 (delete-region posn (viper-replace-end))) 2119 (< (point) (viper-replace-end)))
2110 ) 2120 (delete-region
2121 viper-last-posn-in-replace-region (viper-replace-end))))
2111 2122
2112 (if (eq viper-current-state 'replace-state) 2123 (if (eq viper-current-state 'replace-state)
2113 (viper-downgrade-to-insert)) 2124 (viper-downgrade-to-insert))
2114 ;; replace mode ended => nullify viper-last-posn-in-replace-region 2125 ;; replace mode ended => nullify viper-last-posn-in-replace-region
2115 (viper-move-marker-locally 'viper-last-posn-in-replace-region nil) 2126 (viper-move-marker-locally 'viper-last-posn-in-replace-region nil)
2148 2159
2149 (defun viper-replace-state-exit-cmd () 2160 (defun viper-replace-state-exit-cmd ()
2150 "Binding for keys that cause Replace state to switch to Vi or to Insert. 2161 "Binding for keys that cause Replace state to switch to Vi or to Insert.
2151 These keys are ESC, RET, and LineFeed" 2162 These keys are ESC, RET, and LineFeed"
2152 (interactive) 2163 (interactive)
2153 (if overwrite-mode ;; If you are in replace mode invoked via 'R' 2164 (if overwrite-mode ; if in replace mode invoked via 'R'
2154 (viper-finish-R-mode) 2165 (viper-finish-R-mode)
2155 (viper-finish-change viper-last-posn-in-replace-region)) 2166 (viper-finish-change))
2156 (let (com) 2167 (let (com)
2157 (if (eq this-command 'viper-intercept-ESC-key) 2168 (if (eq this-command 'viper-intercept-ESC-key)
2158 (setq com 'viper-exit-insert-state) 2169 (setq com 'viper-exit-insert-state)
2159 (viper-set-unread-command-events last-input-char) 2170 (viper-set-unread-command-events last-input-char)
2160 (setq com (key-binding (read-key-sequence nil)))) 2171 (setq com (key-binding (read-key-sequence nil))))
2267 (if (and (eolp) (bolp)) (error "No character to replace here")) 2278 (if (and (eolp) (bolp)) (error "No character to replace here"))
2268 (let ((val (viper-p-val arg)) 2279 (let ((val (viper-p-val arg))
2269 (com (viper-getcom arg))) 2280 (com (viper-getcom arg)))
2270 (viper-replace-char-subr com val) 2281 (viper-replace-char-subr com val)
2271 (if (and (eolp) (not (bolp))) (forward-char 1)) 2282 (if (and (eolp) (not (bolp))) (forward-char 1))
2283 (setq viper-this-command-keys
2284 (format "%sr" (if (integerp arg) arg "")))
2272 (viper-set-destructive-command 2285 (viper-set-destructive-command
2273 (list 'viper-replace-char val ?r nil viper-d-char nil)) 2286 (list 'viper-replace-char val ?r nil viper-d-char nil))
2274 )) 2287 ))
2275 2288
2276 (defun viper-replace-char-subr (com arg) 2289 (defun viper-replace-char-subr (com arg)
2277 (let ((take-care-of-iso-accents 2290 (let (char)
2278 (and (boundp 'iso-accents-mode) viper-automatic-iso-accents))
2279 char)
2280 (setq char (if (equal com ?r) 2291 (setq char (if (equal com ?r)
2281 viper-d-char 2292 viper-d-char
2282 (read-char))) 2293 (read-char)))
2283 (if (and take-care-of-iso-accents (memq char '(?' ?\" ?^ ?~))) 2294 (let (inhibit-quit) ; preserve consistency of undo-list and iso-accents
2284 ;; get European characters 2295 (if (and viper-automatic-iso-accents (memq char '(?' ?\" ?^ ?~)))
2285 (progn 2296 ;; get European characters
2286 (iso-accents-mode 1) 2297 (progn
2287 (viper-set-unread-command-events char) 2298 (viper-set-iso-accents-mode t)
2288 (setq char (aref (read-key-sequence nil) 0)) 2299 (viper-set-unread-command-events char)
2289 (iso-accents-mode -1))) 2300 (setq char (aref (read-key-sequence nil) 0))
2290 (delete-char arg t) 2301 (viper-set-iso-accents-mode nil)))
2291 (setq viper-d-char char) 2302 (viper-set-complex-command-for-undo)
2292 (viper-loop (if (> arg 0) arg (- arg)) 2303 (if (eq char ?\C-m) (setq char ?\n))
2293 (if (eq char ?\C-m) (insert "\n") (insert char))) 2304 (if (and viper-special-input-method (fboundp 'quail-start-translation))
2294 (backward-char arg))) 2305 ;; get Intl. characters
2306 (progn
2307 (viper-set-input-method t)
2308 (setq last-command-event
2309 (viper-copy-event
2310 (if viper-xemacs-p (character-to-event char) char)))
2311 (delete-char 1 t)
2312 (condition-case nil
2313 (if com
2314 (insert char)
2315 (if viper-emacs-p
2316 (quail-start-translation 1)
2317 (quail-start-translation)))
2318 (error))
2319 ;; quail translation failed
2320 (if (and (not (stringp quail-current-str))
2321 (not (viper-characterp quail-current-str)))
2322 (progn
2323 (viper-adjust-undo)
2324 (undo-start)
2325 (undo-more 1)
2326 (viper-set-input-method nil)
2327 (error "Composing character failed, changes undone")))
2328 ;; quail translation seems ok
2329 (or com
2330 ;;(setq char quail-current-str))
2331 (setq char (viper-char-at-pos 'backward)))
2332 (setq viper-d-char char)
2333 (viper-loop (1- (if (> arg 0) arg (- arg)))
2334 (delete-char 1 t)
2335 (insert char))
2336 (viper-set-input-method nil))
2337 (delete-char arg t)
2338 (setq viper-d-char char)
2339 (viper-loop (if (> arg 0) arg (- arg))
2340 (insert char)))
2341 (viper-adjust-undo)
2342 (backward-char arg))))
2295 2343
2296 2344
2297 ;; basic cursor movement. j, k, l, h commands. 2345 ;; basic cursor movement. j, k, l, h commands.
2298 2346
2299 (defun viper-forward-char (arg) 2347 (defun viper-forward-char (arg)
2332 (if com (viper-execute-com 'viper-backward-char val com))) 2380 (if com (viper-execute-com 'viper-backward-char val com)))
2333 (backward-char val) 2381 (backward-char val)
2334 (if com (viper-execute-com 'viper-backward-char val com))))) 2382 (if com (viper-execute-com 'viper-backward-char val com)))))
2335 2383
2336 ;; Like forward-char, but doesn't move at end of buffer. 2384 ;; Like forward-char, but doesn't move at end of buffer.
2385 ;; Returns distance traveled
2386 ;; (positive or 0, if arg positive; negative if arg negative).
2337 (defun viper-forward-char-carefully (&optional arg) 2387 (defun viper-forward-char-carefully (&optional arg)
2338 (setq arg (or arg 1)) 2388 (setq arg (or arg 1))
2339 (if (>= (point-max) (+ (point) arg)) 2389 (let ((pt (point)))
2340 (forward-char arg) 2390 (condition-case nil
2341 (goto-char (point-max)))) 2391 (forward-char arg)
2392 (error))
2393 (if (< (point) pt) ; arg was negative
2394 (- (viper-chars-in-region pt (point)))
2395 (viper-chars-in-region pt (point)))))
2342 2396
2343 ;; Like backward-char, but doesn't move at end of buffer. 2397 ;; Like backward-char, but doesn't move at beg of buffer.
2398 ;; Returns distance traveled
2399 ;; (negative or 0, if arg positive; positive if arg negative).
2344 (defun viper-backward-char-carefully (&optional arg) 2400 (defun viper-backward-char-carefully (&optional arg)
2345 (setq arg (or arg 1)) 2401 (setq arg (or arg 1))
2346 (if (<= (point-min) (- (point) arg)) 2402 (let ((pt (point)))
2347 (backward-char arg) 2403 (condition-case nil
2348 (goto-char (point-min)))) 2404 (backward-char arg)
2405 (error))
2406 (if (> (point) pt) ; arg was negative
2407 (viper-chars-in-region pt (point))
2408 (- (viper-chars-in-region pt (point))))))
2349 2409
2350 (defun viper-next-line-carefully (arg) 2410 (defun viper-next-line-carefully (arg)
2351 (condition-case nil 2411 (condition-case nil
2352 (next-line arg) 2412 (next-line arg)
2353 (error nil))) 2413 (error nil)))
2370 (if (looking-at "\n") 2430 (if (looking-at "\n")
2371 (progn 2431 (progn
2372 (forward-char) 2432 (forward-char)
2373 (viper-skip-all-separators-forward 'within-line)))) 2433 (viper-skip-all-separators-forward 'within-line))))
2374 (viper-skip-all-separators-backward 'within-line) 2434 (viper-skip-all-separators-backward 'within-line)
2375 (backward-char) 2435 (viper-backward-char-carefully)
2376 (if (looking-at "\n") 2436 (if (looking-at "\n")
2377 (viper-skip-all-separators-backward 'within-line) 2437 (viper-skip-all-separators-backward 'within-line)
2378 (forward-char)))) 2438 (forward-char))))
2379 2439
2380 (defun viper-forward-word-kernel (val) 2440 (defun viper-forward-word-kernel (val)
2387 ((not (viper-looking-at-alphasep)) 2447 ((not (viper-looking-at-alphasep))
2388 (viper-skip-nonalphasep-forward) 2448 (viper-skip-nonalphasep-forward)
2389 (viper-skip-separators t))) 2449 (viper-skip-separators t)))
2390 (setq val (1- val)))) 2450 (setq val (1- val))))
2391 2451
2392 ;; first search backward for pat. Then skip chars backwards using aux-pat 2452 ;; first skip non-newline separators backward, then skip \n. Then, if TWICE is
2393 (defun viper-fwd-skip (pat aux-pat lim) 2453 ;; non-nil, skip non-\n back again, but don't overshoot the limit LIM.
2394 (if (and (save-excursion 2454 (defun viper-separator-skipback-special (twice lim)
2395 (re-search-backward pat lim t)) 2455 (let ((prev-char (viper-char-at-pos 'backward))
2396 (= (point) (match-end 0))) 2456 (saved-point (point)))
2397 (goto-char (match-beginning 0))) 2457 ;; skip non-newline separators backward
2398 (skip-chars-backward aux-pat lim) 2458 (while (and (not (memq prev-char '(nil \n)))
2399 (if (= (point) lim) 2459 (< lim (point))
2400 (viper-forward-char-carefully)) 2460 ;; must be non-newline separator
2401 ) 2461 (if (eq viper-syntax-preference 'strict-vi)
2462 (memq prev-char '(?\ ?\t))
2463 (memq (char-syntax prev-char) '(?\ ?-))))
2464 (viper-backward-char-carefully)
2465 (setq prev-char (viper-char-at-pos 'backward)))
2466
2467 (if (and (< lim (point)) (eq prev-char ?\n))
2468 (backward-char)
2469 ;; If we skipped to the next word and the prefix of this line doesn't
2470 ;; consist of separators preceded by a newline, then don't skip backwards
2471 ;; at all.
2472 (goto-char saved-point))
2473 (setq prev-char (viper-char-at-pos 'backward))
2474
2475 ;; skip again, but make sure we don't overshoot the limit
2476 (if twice
2477 (while (and (not (memq prev-char '(nil \n)))
2478 (< lim (point))
2479 ;; must be non-newline separator
2480 (if (eq viper-syntax-preference 'strict-vi)
2481 (memq prev-char '(?\ ?\t))
2482 (memq (char-syntax prev-char) '(?\ ?-))))
2483 (viper-backward-char-carefully)
2484 (setq prev-char (viper-char-at-pos 'backward))))
2485
2486 (if (= (point) lim)
2487 (viper-forward-char-carefully))
2488 ))
2402 2489
2403 2490
2404 (defun viper-forward-word (arg) 2491 (defun viper-forward-word (arg)
2405 "Forward word." 2492 "Forward word."
2406 (interactive "P") 2493 (interactive "P")
2409 (com (viper-getcom arg))) 2496 (com (viper-getcom arg)))
2410 (if com (viper-move-marker-locally 'viper-com-point (point))) 2497 (if com (viper-move-marker-locally 'viper-com-point (point)))
2411 (viper-forward-word-kernel val) 2498 (viper-forward-word-kernel val)
2412 (if com (progn 2499 (if com (progn
2413 (cond ((memq com (list ?c (- ?c))) 2500 (cond ((memq com (list ?c (- ?c)))
2414 (viper-fwd-skip "\n[ \t]*" " \t" viper-com-point)) 2501 (viper-separator-skipback-special 'twice viper-com-point))
2415 ;; Yank words including the whitespace, but not newline 2502 ;; Yank words including the whitespace, but not newline
2416 ((memq com (list ?y (- ?y))) 2503 ((memq com (list ?y (- ?y)))
2417 (viper-fwd-skip "\n[ \t]*" "" viper-com-point)) 2504 (viper-separator-skipback-special nil viper-com-point))
2418 ((viper-dotable-command-p com) 2505 ((viper-dotable-command-p com)
2419 (viper-fwd-skip "\n[ \t]*" "" viper-com-point))) 2506 (viper-separator-skipback-special nil viper-com-point)))
2420 (viper-execute-com 'viper-forward-word val com))))) 2507 (viper-execute-com 'viper-forward-word val com)))))
2421 2508
2422 2509
2423 (defun viper-forward-Word (arg) 2510 (defun viper-forward-Word (arg)
2424 "Forward word delimited by white characters." 2511 "Forward word delimited by white characters."
2426 (viper-leave-region-active) 2513 (viper-leave-region-active)
2427 (let ((val (viper-p-val arg)) 2514 (let ((val (viper-p-val arg))
2428 (com (viper-getcom arg))) 2515 (com (viper-getcom arg)))
2429 (if com (viper-move-marker-locally 'viper-com-point (point))) 2516 (if com (viper-move-marker-locally 'viper-com-point (point)))
2430 (viper-loop val 2517 (viper-loop val
2431 (progn
2432 (viper-skip-nonseparators 'forward) 2518 (viper-skip-nonseparators 'forward)
2433 (viper-skip-separators t))) 2519 (viper-skip-separators t))
2434 (if com (progn 2520 (if com (progn
2435 (cond ((memq com (list ?c (- ?c))) 2521 (cond ((memq com (list ?c (- ?c)))
2436 (viper-fwd-skip "\n[ \t]*" " \t" viper-com-point)) 2522 (viper-separator-skipback-special 'twice viper-com-point))
2437 ;; Yank words including the whitespace, but not newline 2523 ;; Yank words including the whitespace, but not newline
2438 ((memq com (list ?y (- ?y))) 2524 ((memq com (list ?y (- ?y)))
2439 (viper-fwd-skip "\n[ \t]*" "" viper-com-point)) 2525 (viper-separator-skipback-special nil viper-com-point))
2440 ((viper-dotable-command-p com) 2526 ((viper-dotable-command-p com)
2441 (viper-fwd-skip "\n[ \t]*" "" viper-com-point))) 2527 (viper-separator-skipback-special nil viper-com-point)))
2442 (viper-execute-com 'viper-forward-Word val com))))) 2528 (viper-execute-com 'viper-forward-Word val com)))))
2443 2529
2444 2530
2445 ;; this is a bit different from Vi, but Vi's end of word 2531 ;; this is a bit different from Vi, but Vi's end of word
2446 ;; makes no sense whatsoever 2532 ;; makes no sense whatsoever
2483 (viper-leave-region-active) 2569 (viper-leave-region-active)
2484 (let ((val (viper-p-val arg)) 2570 (let ((val (viper-p-val arg))
2485 (com (viper-getcom arg))) 2571 (com (viper-getcom arg)))
2486 (if com (viper-move-marker-locally 'viper-com-point (point))) 2572 (if com (viper-move-marker-locally 'viper-com-point (point)))
2487 (viper-loop val 2573 (viper-loop val
2488 (progn
2489 (viper-end-of-word-kernel) 2574 (viper-end-of-word-kernel)
2490 (viper-skip-nonseparators 'forward) 2575 (viper-skip-nonseparators 'forward)
2491 (backward-char))) 2576 (backward-char))
2492 (if com 2577 (if com
2493 (progn 2578 (progn
2494 (forward-char) 2579 (forward-char)
2495 (viper-execute-com 'viper-end-of-Word val com))))) 2580 (viper-execute-com 'viper-end-of-Word val com)))))
2496 2581
2497 (defun viper-backward-word-kernel (val) 2582 (defun viper-backward-word-kernel (val)
2498 (while (> val 0) 2583 (while (> val 0)
2499 (backward-char) 2584 (viper-backward-char-carefully)
2500 (cond ((viper-looking-at-alpha) 2585 (cond ((viper-looking-at-alpha)
2501 (viper-skip-alpha-backward "_")) 2586 (viper-skip-alpha-backward "_"))
2502 ((viper-looking-at-separator) 2587 ((viper-looking-at-separator)
2503 (forward-char) 2588 (forward-char)
2504 (viper-skip-separators nil) 2589 (viper-skip-separators nil)
2505 (backward-char) 2590 (viper-backward-char-carefully)
2506 (cond ((viper-looking-at-alpha) 2591 (cond ((viper-looking-at-alpha)
2507 (viper-skip-alpha-backward "_")) 2592 (viper-skip-alpha-backward "_"))
2508 ((not (viper-looking-at-alphasep)) 2593 ((not (viper-looking-at-alphasep))
2509 (viper-skip-nonalphasep-backward)) 2594 (viper-skip-nonalphasep-backward))
2595 ((bobp)) ; could still be at separator, but at beg of buffer
2510 (t (forward-char)))) 2596 (t (forward-char))))
2511 ((not (viper-looking-at-alphasep)) 2597 ((not (viper-looking-at-alphasep))
2512 (viper-skip-nonalphasep-backward))) 2598 (viper-skip-nonalphasep-backward)))
2513 (setq val (1- val)))) 2599 (setq val (1- val))))
2514 2600
2538 (if (setq i (save-excursion (backward-char) (looking-at "\n"))) 2624 (if (setq i (save-excursion (backward-char) (looking-at "\n")))
2539 (backward-char)) 2625 (backward-char))
2540 (viper-move-marker-locally 'viper-com-point (point)) 2626 (viper-move-marker-locally 'viper-com-point (point))
2541 (if i (forward-char)))) 2627 (if i (forward-char))))
2542 (viper-loop val 2628 (viper-loop val
2543 (progn 2629 (viper-skip-separators nil) ; nil means backward here
2544 (viper-skip-separators nil) 2630 (viper-skip-nonseparators 'backward))
2545 (viper-skip-nonseparators 'backward)))
2546 (if com (viper-execute-com 'viper-backward-Word val com)))) 2631 (if com (viper-execute-com 'viper-backward-Word val com))))
2547 2632
2548 2633
2549 2634
2550 ;; line commands 2635 ;; line commands
2591 (interactive "P") 2676 (interactive "P")
2592 (viper-leave-region-active) 2677 (viper-leave-region-active)
2593 (let ((val (viper-p-val arg)) 2678 (let ((val (viper-p-val arg))
2594 (com (viper-getcom arg)) 2679 (com (viper-getcom arg))
2595 line-len) 2680 line-len)
2596 (setq line-len (- (viper-line-pos 'end) (viper-line-pos 'start))) 2681 (setq line-len
2682 (viper-chars-in-region
2683 (viper-line-pos 'start) (viper-line-pos 'end)))
2597 (if com (viper-move-marker-locally 'viper-com-point (point))) 2684 (if com (viper-move-marker-locally 'viper-com-point (point)))
2598 (beginning-of-line) 2685 (beginning-of-line)
2599 (forward-char (1- (min line-len val))) 2686 (forward-char (1- (min line-len val)))
2600 (while (> (current-column) (1- val)) 2687 (while (> (current-column) (1- val))
2601 (backward-char 1)) 2688 (backward-char 1))
2731 (goto-char (point-max))) 2818 (goto-char (point-max)))
2732 (if (let ((case-fold-search nil)) 2819 (if (let ((case-fold-search nil))
2733 (search-forward (char-to-string char) nil 0 arg)) 2820 (search-forward (char-to-string char) nil 0 arg))
2734 (setq point (point)) 2821 (setq point (point))
2735 (error "Command `%s': `%c' not found" cmd char)))) 2822 (error "Command `%s': `%c' not found" cmd char))))
2736 (goto-char (+ point (if (> arg 0) (if offset -2 -1) (if offset 1 0)))))) 2823 (goto-char point)
2824 (if (> arg 0)
2825 (backward-char (if offset 2 1))
2826 (forward-char (if offset 1 0)))))
2737 2827
2738 (defun viper-find-char-forward (arg) 2828 (defun viper-find-char-forward (arg)
2739 "Find char on the line. 2829 "Find char on the line.
2740 If called interactively read the char to find from the terminal, and if 2830 If called interactively read the char to find from the terminal, and if
2741 called from viper-repeat, the char last used is used. This behaviour is 2831 called from viper-repeat, the char last used is used. This behaviour is
3694 (copy-region-as-kill beg end) 3784 (copy-region-as-kill beg end)
3695 (error (copy-region-as-kill beg beg)))) 3785 (error (copy-region-as-kill beg beg))))
3696 3786
3697 3787
3698 (defun viper-delete-char (arg) 3788 (defun viper-delete-char (arg)
3699 "Delete character." 3789 "Delete next character."
3700 (interactive "P") 3790 (interactive "P")
3701 (let ((val (viper-p-val arg))) 3791 (let ((val (viper-p-val arg))
3792 end-del-pos)
3702 (viper-set-destructive-command 3793 (viper-set-destructive-command
3703 (list 'viper-delete-char val nil nil nil nil)) 3794 (list 'viper-delete-char val nil nil nil nil))
3704 (if (> val 1) 3795 (if (and viper-ex-style-editing
3705 (save-excursion 3796 (> val (viper-chars-in-region (point) (viper-line-pos 'end))))
3706 (let ((here (point))) 3797 (setq val (viper-chars-in-region (point) (viper-line-pos 'end))))
3707 (end-of-line)
3708 (if (> val (- (point) here))
3709 (setq val (- (point) here))))))
3710 (if (and (eq val 0) (not viper-ex-style-motion)) (setq val 1))
3711 (if (and viper-ex-style-motion (eolp)) 3798 (if (and viper-ex-style-motion (eolp))
3712 (if (bolp) (error "") (setq val 0))) ; not bol---simply back 1 ch 3799 (if (bolp) (error "") (setq val 0))) ; not bol---simply back 1 ch
3800 (save-excursion
3801 (viper-forward-char-carefully val)
3802 (setq end-del-pos (point)))
3713 (if viper-use-register 3803 (if viper-use-register
3714 (progn 3804 (progn
3715 (cond ((viper-valid-register viper-use-register '((Letter))) 3805 (cond ((viper-valid-register viper-use-register '((Letter)))
3716 (viper-append-to-register 3806 (viper-append-to-register
3717 (downcase viper-use-register) (point) (- (point) val))) 3807 (downcase viper-use-register) (point) end-del-pos))
3718 ((viper-valid-register viper-use-register) 3808 ((viper-valid-register viper-use-register)
3719 (copy-to-register 3809 (copy-to-register
3720 viper-use-register (point) (- (point) val) nil)) 3810 viper-use-register (point) end-del-pos nil))
3721 (t (error viper-InvalidRegister viper-use-register))) 3811 (t (error viper-InvalidRegister viper-use-register)))
3722 (setq viper-use-register nil))) 3812 (setq viper-use-register nil)))
3813
3814 (delete-char val t)
3723 (if viper-ex-style-motion 3815 (if viper-ex-style-motion
3724 (progn 3816 (if (and (eolp) (not (bolp))) (backward-char 1)))
3725 (delete-char val t) 3817 ))
3726 (if (and (eolp) (not (bolp))) (backward-char 1)))
3727 (if (eolp)
3728 (delete-backward-char val t)
3729 (delete-char val t)))))
3730 3818
3731 (defun viper-delete-backward-char (arg) 3819 (defun viper-delete-backward-char (arg)
3732 "Delete previous character. On reaching beginning of line, stop and beep." 3820 "Delete previous character. On reaching beginning of line, stop and beep."
3733 (interactive "P") 3821 (interactive "P")
3734 (let ((val (viper-p-val arg))) 3822 (let ((val (viper-p-val arg))
3823 end-del-pos)
3735 (viper-set-destructive-command 3824 (viper-set-destructive-command
3736 (list 'viper-delete-backward-char val nil nil nil nil)) 3825 (list 'viper-delete-backward-char val nil nil nil nil))
3737 (if (> val 1) 3826 (if (and
3738 (save-excursion 3827 viper-ex-style-editing
3739 (let ((here (point))) 3828 (> val (viper-chars-in-region (viper-line-pos 'start) (point))))
3740 (beginning-of-line) 3829 (setq val (viper-chars-in-region (viper-line-pos 'start) (point))))
3741 (if (> val (- here (point))) 3830 (save-excursion
3742 (setq val (- here (point))))))) 3831 (viper-backward-char-carefully val)
3832 (setq end-del-pos (point)))
3743 (if viper-use-register 3833 (if viper-use-register
3744 (progn 3834 (progn
3745 (cond ((viper-valid-register viper-use-register '(Letter)) 3835 (cond ((viper-valid-register viper-use-register '(Letter))
3746 (viper-append-to-register 3836 (viper-append-to-register
3747 (downcase viper-use-register) (point) (+ (point) val))) 3837 (downcase viper-use-register) end-del-pos (point)))
3748 ((viper-valid-register viper-use-register) 3838 ((viper-valid-register viper-use-register)
3749 (copy-to-register 3839 (copy-to-register
3750 viper-use-register (point) (+ (point) val) nil)) 3840 viper-use-register end-del-pos (point) nil))
3751 (t (error viper-InvalidRegister viper-use-register))) 3841 (t (error viper-InvalidRegister viper-use-register)))
3752 (setq viper-use-register nil))) 3842 (setq viper-use-register nil)))
3753 (if (bolp) (ding) 3843 (if (and (bolp) viper-ex-style-editing)
3754 (delete-backward-char val t)))) 3844 (ding))
3845 (delete-backward-char val t)))
3755 3846
3756 (defun viper-del-backward-char-in-insert () 3847 (defun viper-del-backward-char-in-insert ()
3757 "Delete 1 char backwards while in insert mode." 3848 "Delete 1 char backwards while in insert mode."
3758 (interactive) 3849 (interactive)
3759 (if (and viper-ex-style-editing-in-insert (bolp)) 3850 (if (and viper-ex-style-editing (bolp))
3760 (beep 1) 3851 (beep 1)
3761 (delete-backward-char 1 t))) 3852 (delete-backward-char 1 t)))
3762 3853
3763 (defun viper-del-backward-char-in-replace () 3854 (defun viper-del-backward-char-in-replace ()
3764 "Delete one character in replace mode. 3855 "Delete one character in replace mode.
3765 If `viper-delete-backwards-in-replace' is t, then DEL key actually deletes 3856 If `viper-delete-backwards-in-replace' is t, then DEL key actually deletes
3766 charecters. If it is nil, then the cursor just moves backwards, similarly 3857 charecters. If it is nil, then the cursor just moves backwards, similarly
3767 to Vi. The variable `viper-ex-style-editing-in-insert', if t, doesn't let the 3858 to Vi. The variable `viper-ex-style-editing', if t, doesn't let the
3768 cursor move past the beginning of line." 3859 cursor move past the beginning of line."
3769 (interactive) 3860 (interactive)
3770 (cond (viper-delete-backwards-in-replace 3861 (cond (viper-delete-backwards-in-replace
3771 (cond ((not (bolp)) 3862 (cond ((not (bolp))
3772 (delete-backward-char 1 t)) 3863 (delete-backward-char 1 t))
3773 (viper-ex-style-editing-in-insert 3864 (viper-ex-style-editing
3774 (beep 1)) 3865 (beep 1))
3775 ((bobp) 3866 ((bobp)
3776 (beep 1)) 3867 (beep 1))
3777 (t 3868 (t
3778 (delete-backward-char 1 t)))) 3869 (delete-backward-char 1 t))))
3779 (viper-ex-style-editing-in-insert 3870 (viper-ex-style-editing
3780 (if (bolp) 3871 (if (bolp)
3781 (beep 1) 3872 (beep 1)
3782 (backward-char 1))) 3873 (backward-char 1)))
3783 (t 3874 (t
3784 (backward-char 1)))) 3875 (backward-char 1))))
3792 (interactive "*P") 3883 (interactive "*P")
3793 (let ((val (viper-P-val arg))) 3884 (let ((val (viper-P-val arg)))
3794 (viper-set-destructive-command 3885 (viper-set-destructive-command
3795 (list 'viper-join-lines val nil nil nil nil)) 3886 (list 'viper-join-lines val nil nil nil nil))
3796 (viper-loop (if (null val) 1 (1- val)) 3887 (viper-loop (if (null val) 1 (1- val))
3797 (progn
3798 (end-of-line) 3888 (end-of-line)
3799 (if (not (eobp)) 3889 (if (not (eobp))
3800 (progn 3890 (progn
3801 (forward-line 1) 3891 (forward-line 1)
3802 (delete-region (point) (1- (point))) 3892 (delete-region (point) (1- (point)))
3804 ;; fixup-whitespace sometimes does not leave space 3894 ;; fixup-whitespace sometimes does not leave space
3805 ;; between objects, so we insert it as in Vi 3895 ;; between objects, so we insert it as in Vi
3806 (or (looking-at " ") 3896 (or (looking-at " ")
3807 (insert " ") 3897 (insert " ")
3808 (backward-char 1)) 3898 (backward-char 1))
3809 )))))) 3899 )))))
3810 3900
3811 3901
3812 ;; Replace state 3902 ;; Replace state
3813 3903
3814 (defun viper-change (beg end) 3904 (defun viper-change (beg end)
4260 ;; & dont-change-unless = t -- use it; else ask 4350 ;; & dont-change-unless = t -- use it; else ask
4261 (viper-ask-level dont-change-unless)) 4351 (viper-ask-level dont-change-unless))
4262 4352
4263 (setq viper-always t 4353 (setq viper-always t
4264 viper-ex-style-motion t 4354 viper-ex-style-motion t
4265 viper-ex-style-editing-in-insert t 4355 viper-ex-style-editing t
4266 viper-want-ctl-h-help nil) 4356 viper-want-ctl-h-help nil)
4267 4357
4268 (cond ((eq viper-expert-level 1) ; novice or beginner 4358 (cond ((eq viper-expert-level 1) ; novice or beginner
4269 (global-set-key ; in emacs-state 4359 (global-set-key ; in emacs-state
4270 viper-toggle-key 4360 viper-toggle-key
4287 4377
4288 (if (eq viper-expert-level 4) ; respect user's ex-style motion 4378 (if (eq viper-expert-level 4) ; respect user's ex-style motion
4289 ; and viper-no-multiple-ESC 4379 ; and viper-no-multiple-ESC
4290 (progn 4380 (progn
4291 (setq-default 4381 (setq-default
4292 viper-ex-style-editing-in-insert 4382 viper-ex-style-editing
4293 (viper-standard-value 'viper-ex-style-editing-in-insert) 4383 (viper-standard-value 'viper-ex-style-editing)
4294 viper-ex-style-motion 4384 viper-ex-style-motion
4295 (viper-standard-value 'viper-ex-style-motion)) 4385 (viper-standard-value 'viper-ex-style-motion))
4296 (setq viper-ex-style-motion 4386 (setq viper-ex-style-motion
4297 (viper-standard-value 'viper-ex-style-motion) 4387 (viper-standard-value 'viper-ex-style-motion)
4298 viper-ex-style-editing-in-insert 4388 viper-ex-style-editing
4299 (viper-standard-value 'viper-ex-style-editing-in-insert) 4389 (viper-standard-value 'viper-ex-style-editing)
4300 viper-re-search 4390 viper-re-search
4301 (viper-standard-value 'viper-re-search) 4391 (viper-standard-value 'viper-re-search)
4302 viper-no-multiple-ESC 4392 viper-no-multiple-ESC
4303 (viper-standard-value 'viper-no-multiple-ESC))))) 4393 (viper-standard-value 'viper-no-multiple-ESC)))))
4304 4394
4305 ;; A wizard!! 4395 ;; A wizard!!
4306 ;; Ideally, if 5 is selected, a buffer should pop up to let the 4396 ;; Ideally, if 5 is selected, a buffer should pop up to let the
4307 ;; user toggle the values of variables. 4397 ;; user toggle the values of variables.
4308 (t (setq-default viper-ex-style-editing-in-insert 4398 (t (setq-default viper-ex-style-editing
4309 (viper-standard-value 'viper-ex-style-editing-in-insert) 4399 (viper-standard-value 'viper-ex-style-editing)
4310 viper-ex-style-motion 4400 viper-ex-style-motion
4311 (viper-standard-value 'viper-ex-style-motion)) 4401 (viper-standard-value 'viper-ex-style-motion))
4312 (setq viper-want-ctl-h-help 4402 (setq viper-want-ctl-h-help
4313 (viper-standard-value 'viper-want-ctl-h-help) 4403 (viper-standard-value 'viper-want-ctl-h-help)
4314 viper-always 4404 viper-always
4315 (viper-standard-value 'viper-always) 4405 (viper-standard-value 'viper-always)
4316 viper-no-multiple-ESC 4406 viper-no-multiple-ESC
4317 (viper-standard-value 'viper-no-multiple-ESC) 4407 (viper-standard-value 'viper-no-multiple-ESC)
4318 viper-ex-style-motion 4408 viper-ex-style-motion
4319 (viper-standard-value 'viper-ex-style-motion) 4409 (viper-standard-value 'viper-ex-style-motion)
4320 viper-ex-style-editing-in-insert 4410 viper-ex-style-editing
4321 (viper-standard-value 'viper-ex-style-editing-in-insert) 4411 (viper-standard-value 'viper-ex-style-editing)
4322 viper-re-search 4412 viper-re-search
4323 (viper-standard-value 'viper-re-search) 4413 (viper-standard-value 'viper-re-search)
4324 viper-electric-mode 4414 viper-electric-mode
4325 (viper-standard-value 'viper-electric-mode) 4415 (viper-standard-value 'viper-electric-mode)
4326 viper-want-emacs-keys-in-vi 4416 viper-want-emacs-keys-in-vi
4364 so most Emacs commands can be used when Viper is in Vi state. 4454 so most Emacs commands can be used when Viper is in Vi state.
4365 Good progress---you are well on the way to level 3! 4455 Good progress---you are well on the way to level 3!
4366 3 -- GRAND MASTER: Like 3, but most Emacs commands are available also 4456 3 -- GRAND MASTER: Like 3, but most Emacs commands are available also
4367 in Viper's insert state. 4457 in Viper's insert state.
4368 4 -- GURU: Like 3, but user settings are respected for viper-no-multiple-ESC, 4458 4 -- GURU: Like 3, but user settings are respected for viper-no-multiple-ESC,
4369 viper-ex-style-motion, viper-ex-style-editing-in-insert, and 4459 viper-ex-style-motion, viper-ex-style-editing, and
4370 viper-re-search variables. Adjust these settings to your taste. 4460 viper-re-search variables. Adjust these settings to your taste.
4371 5 -- WIZARD: Like 4, but user settings are also respected for viper-always, 4461 5 -- WIZARD: Like 4, but user settings are also respected for viper-always,
4372 viper-electric-mode, viper-want-ctl-h-help, viper-want-emacs-keys-in-vi, 4462 viper-electric-mode, viper-want-ctl-h-help, viper-want-emacs-keys-in-vi,
4373 and viper-want-emacs-keys-in-insert. Adjust these to your taste. 4463 and viper-want-emacs-keys-in-insert. Adjust these to your taste.
4374 4464
4485 'viper-emacs-local-user-minor-mode 4575 'viper-emacs-local-user-minor-mode
4486 'viper-emacs-kbd-minor-mode 4576 'viper-emacs-kbd-minor-mode
4487 'viper-emacs-global-user-minor-mode 4577 'viper-emacs-global-user-minor-mode
4488 'viper-emacs-state-modifier-minor-mode 4578 'viper-emacs-state-modifier-minor-mode
4489 'viper-automatic-iso-accents 4579 'viper-automatic-iso-accents
4580 'viper-special-input-method
4490 'viper-want-emacs-keys-in-insert 4581 'viper-want-emacs-keys-in-insert
4491 'viper-want-emacs-keys-in-vi 4582 'viper-want-emacs-keys-in-vi
4492 'viper-keep-point-on-undo 4583 'viper-keep-point-on-undo
4493 'viper-no-multiple-ESC 4584 'viper-no-multiple-ESC
4494 'viper-electric-mode 4585 'viper-electric-mode
4495 'viper-ESC-key 4586 'viper-ESC-key
4496 'viper-want-ctl-h-help 4587 'viper-want-ctl-h-help
4497 'viper-ex-style-editing-in-insert 4588 'viper-ex-style-editing
4498 'viper-delete-backwards-in-replace 4589 'viper-delete-backwards-in-replace
4499 'viper-vi-style-in-minibuffer 4590 'viper-vi-style-in-minibuffer
4500 'viper-vi-state-hook 4591 'viper-vi-state-hook
4501 'viper-insert-state-hook 4592 'viper-insert-state-hook
4502 'viper-replace-state-hook 4593 'viper-replace-state-hook