]> git.eshelyaron.com Git - emacs.git/commitdiff
new version
authorMichael Kifer <kifer@cs.stonybrook.edu>
Fri, 22 Aug 1997 03:15:57 +0000 (03:15 +0000)
committerMichael Kifer <kifer@cs.stonybrook.edu>
Fri, 22 Aug 1997 03:15:57 +0000 (03:15 +0000)
lisp/ediff.el
lisp/emulation/viper-cmd.el
lisp/emulation/viper-init.el
lisp/emulation/viper-keym.el
lisp/emulation/viper-util.el
lisp/emulation/viper.el

index dd69b41649c7c3061ef605319e69db3f6efd651d..ea7d747a70ae2b43ec77aa5b069d146edce5e32b 100644 (file)
 
 (defgroup ediff nil
   "A comprehensive visual interface to diff & patch"
+  :tag "Ediff"
   :group 'tools)
 
 
index be02683ad1045400f934c9e6cf5789d10ca0e189..a2d113255110d038f7ba41690bfe128c957caa79 100644 (file)
@@ -16,6 +16,8 @@
 (defvar viper-mode-string)
 (defvar viper-custom-file-name)
 (defvar iso-accents-mode)
+(defvar quail-mode)
+(defvar quail-current-str)
 (defvar zmacs-region-stays)
 (defvar mark-even-if-inactive)
 
     (let ((replace-boundary (viper-replace-end)))
       (save-excursion
        (goto-char viper-last-posn-in-replace-region)
+       (viper-trim-replace-chars-to-delete-if-necessary)
        (delete-char viper-replace-chars-to-delete)
-       (setq viper-replace-chars-to-delete 0
-             viper-replace-chars-deleted 0)
+       (setq viper-replace-chars-to-delete 0)
        ;; terminate replace mode if reached replace limit
-       (if (= viper-last-posn-in-replace-region 
-              (viper-replace-end))
-           (viper-finish-change viper-last-posn-in-replace-region)))
+       (if (= viper-last-posn-in-replace-region (viper-replace-end))
+           (viper-finish-change)))
       
-      (if (and (<= (viper-replace-start) (point))
-              (<=  (point) replace-boundary))
+      (if (viper-pos-within-region
+          (point) (viper-replace-start) replace-boundary)
          (progn
            ;; the state may have changed in viper-finish-change above
            (if (eq viper-current-state 'replace-state)
                (viper-change-cursor-color viper-replace-overlay-cursor-color))
            (setq viper-last-posn-in-replace-region (point-marker))))
       ))
-   
-   (t ;; terminate replace mode if changed Viper states.
-    (viper-finish-change viper-last-posn-in-replace-region))))
+   ;; terminate replace mode if changed Viper states.
+   (t (viper-finish-change))))
 
 
 ;; changing mode
                    (viper-push-onto-ring viper-last-insertion
                                          'viper-insertion-ring))
                
-               (if viper-ex-style-editing-in-insert
+               (if viper-ex-style-editing
                    (or (bolp) (backward-char 1))))
               ))
         
   ;; Nothing needs to be done to switch to emacs mode! Just set some
   ;; variables, which is already done in viper-change-state-to-emacs!
 
+  ;; ISO accents
+  ;; always turn off iso-accents-mode in vi-state, or else we won't be able to
+  ;; use the keys `,',^ , as they will do accents instead of Vi actions.
+  (cond ((eq new-state 'vi-state) (viper-set-iso-accents-mode nil));accents off
+       (viper-automatic-iso-accents (viper-set-iso-accents-mode t));accents on
+       (t (viper-set-iso-accents-mode nil)))
+  ;; Always turn off quail mode in vi state
+  (cond ((eq new-state 'vi-state) (viper-set-input-method nil)) ;intl input off
+       (viper-special-input-method (viper-set-input-method t)) ;intl input on
+       (t (viper-set-input-method nil)))
+
   (setq viper-current-state new-state)
+
+  (viper-update-syntax-classes)
   (viper-normalize-minor-mode-map-alist)
   (viper-adjust-keys-for new-state)
   (viper-set-mode-vars-for new-state)
                   
         (if viper-want-ctl-h-help
             (progn 
+              (define-key viper-insert-basic-map [backspace] 'help-command)
+              (define-key viper-replace-map [backspace] 'help-command)
               (define-key viper-insert-basic-map [(control h)] 'help-command)
               (define-key viper-replace-map [(control h)] 'help-command))
+          (define-key viper-insert-basic-map 
+            [backspace] 'viper-del-backward-char-in-insert)
+          (define-key viper-replace-map
+            [backspace] 'viper-del-backward-char-in-replace)
           (define-key viper-insert-basic-map 
             [(control h)] 'viper-del-backward-char-in-insert)
           (define-key viper-replace-map
        (t ; Vi state
         (setq viper-vi-diehard-minor-mode (not viper-want-emacs-keys-in-vi))
         (if viper-want-ctl-h-help
-            (define-key viper-vi-basic-map [(control h)] 'help-command)
+            (progn
+              (define-key viper-vi-basic-map [backspace] 'help-command)
+              (define-key viper-vi-basic-map [(control h)] 'help-command))
+          (define-key viper-vi-basic-map [backspace] 'viper-backward-char)
           (define-key viper-vi-basic-map [(control h)] 'viper-backward-char)))
        ))
             
             (viper-over-whitespace-line))
        (indent-to-left-margin))
     (viper-add-newline-at-eob-if-necessary)
-    (if viper-undo-needs-adjustment  (viper-adjust-undo))
+    (viper-adjust-undo)
     (viper-change-state 'vi-state)
 
-    ;; always turn off iso-accents-mode, or else we won't be able to use the
-    ;; keys `,',^ in Vi state, as they will do accents instead of Vi actions.
-    (if (and (boundp 'iso-accents-mode) iso-accents-mode)
-       (iso-accents-mode -1))
-
     (viper-restore-cursor-color-after-insert)
     
-    ;; Protection against user errors in hooks
+    ;; Protect against user errors in hooks
     (condition-case conds
        (run-hooks 'viper-vi-state-hook)
       (error
   "Change Viper state to Insert."
   (interactive)
   (viper-change-state 'insert-state)
-  (if (and viper-automatic-iso-accents (fboundp 'iso-accents-mode))
-      (iso-accents-mode 1)) ; turn iso accents on
   
   (or (stringp viper-saved-cursor-color)
       (string= (viper-get-cursor-color) viper-insert-state-cursor-color)
   ;; bug related to local variables?
 ;;;(if (stringp viper-saved-cursor-color)
 ;;;      (viper-change-cursor-color viper-insert-state-cursor-color))
-  ;; Protection against user errors in hooks
+
+  ;; Protect against user errors in hooks
   (condition-case conds
       (run-hooks 'viper-insert-state-hook)
     (error
 ;; replace state changes to insert state.
 (defun viper-change-state-to-replace (&optional non-R-cmd)
   (viper-change-state 'replace-state)
-  (if (and viper-automatic-iso-accents (fboundp 'iso-accents-mode))
-      (iso-accents-mode 1)) ; turn iso accents on
   ;; Run insert-state-hook
   (condition-case conds
       (run-hooks 'viper-insert-state-hook 'viper-replace-state-hook)
   "Change Viper state to Emacs."
   (interactive)
   (viper-change-state 'emacs-state)
-  (if (and viper-automatic-iso-accents (fboundp 'iso-accents-mode))
-      (iso-accents-mode 1)) ; turn iso accents on
   
-  ;; Protection agains user errors in hooks
+  ;; Protect agains user errors in hooks
   (condition-case conds
       (run-hooks 'viper-emacs-state-hook)
     (error
@@ -1395,12 +1407,12 @@ If the prefix argument, ARG, is non-nil, it is used instead of `val'."
         (funcall m-com (cons val com))
         (cond ((and (< save-point (point)) viper-keep-point-on-repeat)
               (goto-char save-point)) ; go back to before repeat.
-             ((and (< save-point (point)) viper-ex-style-editing-in-insert)
+             ((and (< save-point (point)) viper-ex-style-editing)
               (or (bolp) (backward-char 1))))
        (if (and (eolp) (not (bolp)))
            (backward-char 1))
      ))
-  (if viper-undo-needs-adjustment (viper-adjust-undo)) ; take care of undo
+  (viper-adjust-undo) ; take care of undo
   ;; If the prev cmd was rotating the command ring, this means that `.' has
   ;; just executed a command from that ring. So, push it on the ring again.
   ;; If we are just executing previous command , then don't push viper-d-com
@@ -1495,8 +1507,8 @@ invokes the command before that, etc."
          (viper-sit-for-short 300)
          (goto-char undo-end-posn)
          (viper-sit-for-short 300)
-         (if (and (> (abs (- undo-beg-posn before-undo-pt)) 1)
-                 (> (abs (- undo-end-posn before-undo-pt)) 1))
+         (if (and (> (viper-chars-in-region undo-beg-posn before-undo-pt) 1)
+                  (> (viper-chars-in-region undo-end-posn before-undo-pt) 1))
              (goto-char before-undo-pt)
            (goto-char undo-beg-posn)))
       (push-mark before-undo-pt t))
@@ -1518,24 +1530,26 @@ invokes the command before that, etc."
 ;; In VI, unlike Emacs, if you open a line, say, and add a bunch of lines,
 ;; they are undone all at once.  
 (defun viper-adjust-undo ()
-  (let ((inhibit-quit t)
-       tmp tmp2)
-    (setq viper-undo-needs-adjustment nil)
-    (if (listp buffer-undo-list)
-       (if (setq tmp (memq viper-buffer-undo-list-mark buffer-undo-list))
-           (progn
-             (setq tmp2 (cdr tmp)) ; the part after mark
-             
-             ;; cut tail from buffer-undo-list temporarily by direct
-             ;; manipulation with pointers in buffer-undo-list
-             (setcdr tmp nil)
-             
-             (setq buffer-undo-list (delq nil buffer-undo-list))
-             (setq buffer-undo-list
-                   (delq viper-buffer-undo-list-mark buffer-undo-list))
-             ;; restore tail of buffer-undo-list
-             (setq buffer-undo-list (nconc buffer-undo-list tmp2)))
-         (setq buffer-undo-list (delq nil buffer-undo-list))))))
+  (if viper-undo-needs-adjustment
+      (let ((inhibit-quit t)
+           tmp tmp2)
+       (setq viper-undo-needs-adjustment nil)
+       (if (listp buffer-undo-list)
+           (if (setq tmp (memq viper-buffer-undo-list-mark buffer-undo-list))
+               (progn
+                 (setq tmp2 (cdr tmp)) ; the part after mark
+                 
+                 ;; cut tail from buffer-undo-list temporarily by direct
+                 ;; manipulation with pointers in buffer-undo-list
+                 (setcdr tmp nil)
+                 
+                 (setq buffer-undo-list (delq nil buffer-undo-list))
+                 (setq buffer-undo-list
+                       (delq viper-buffer-undo-list-mark buffer-undo-list))
+                 ;; restore tail of buffer-undo-list
+                 (setq buffer-undo-list (nconc buffer-undo-list tmp2)))
+             (setq buffer-undo-list (delq nil buffer-undo-list)))))
+    ))
   
 
 (defun viper-set-complex-command-for-undo ()  
@@ -1560,7 +1574,11 @@ invokes the command before that, etc."
             (concat "`" (viper-array-to-string keys) "'")
             (viper-abbreviate-string 
              (if viper-xemacs-p
-                 (replace-in-string text "\n" "^J")
+                 (replace-in-string 
+                  (cond ((characterp text) (char-to-string text))
+                        ((stringp text) text)
+                        (t ""))
+                  "\n" "^J")
                text)
              max-text-len
              "  inserting  `" "'" "    ......."))
@@ -1892,7 +1910,6 @@ Undo previous insertion and inserts new."
     (let ((col (current-indentation)))
       (if (equal com ?r)
          (viper-loop val
-                   (progn
                      (end-of-line)
                      (newline 1)
                      (if viper-auto-indent 
@@ -1902,7 +1919,7 @@ Undo previous insertion and inserts new."
                                (indent-according-to-mode)
                              (indent-to col))
                            ))
-                     (viper-yank-last-insertion)))
+                     (viper-yank-last-insertion))
        (end-of-line)
        (newline 1)
        (if viper-auto-indent
@@ -1923,7 +1940,6 @@ Undo previous insertion and inserts new."
     (let ((col (current-indentation)))
       (if (equal com ?r)
          (viper-loop val
-                   (progn
                      (beginning-of-line)
                      (open-line 1)
                      (if viper-auto-indent 
@@ -1933,7 +1949,7 @@ Undo previous insertion and inserts new."
                                (indent-according-to-mode)
                              (indent-to col))
                            ))
-                     (viper-yank-last-insertion)))
+                     (viper-yank-last-insertion))
        (beginning-of-line)
        (open-line 1)
        (if viper-auto-indent
@@ -1955,9 +1971,8 @@ Undo previous insertion and inserts new."
      (list 'viper-open-line-at-point val ?r nil nil nil))
     (if (equal com ?r)
        (viper-loop val
-                 (progn
                    (open-line 1)
-                   (viper-yank-last-insertion)))
+                   (viper-yank-last-insertion))
       (open-line 1)
       (viper-change-state-to-insert))))
 
@@ -1985,8 +2000,7 @@ Undo previous insertion and inserts new."
 (defun viper-start-replace ()
   (setq viper-began-as-replace t
        viper-sitting-in-replace t
-       viper-replace-chars-to-delete 0
-       viper-replace-chars-deleted 0)
+       viper-replace-chars-to-delete 0)
   (viper-add-hook
    'viper-after-change-functions 'viper-replace-mode-spy-after t)
   (viper-add-hook
@@ -2007,90 +2021,86 @@ Undo previous insertion and inserts new."
   )
   
 
-;; checks how many chars were deleted by the last change
 (defun viper-replace-mode-spy-before (beg end)
-  (setq viper-replace-chars-deleted
-       (- end beg
-          (max 0 (- end (viper-replace-end)))
-          (max 0 (- (viper-replace-start) beg))
-          )))
+  (setq viper-replace-region-chars-deleted (viper-chars-in-region beg end))
+  )
 
-;; Invoked as an after-change-function to set up parameters of the last change
+;; Invoked as an after-change-function to calculate how many chars have to be
+;; deleted. This function may be called several times within a single command,
+;; if this command performs several separate buffer changes. Therefore, if adds
+;; up the number of chars inserted and subtracts the number of chars deleted.
 (defun viper-replace-mode-spy-after (beg end length)
-  (if (memq viper-intermediate-command '(repeating-insertion-from-ring))
+  (if (memq viper-intermediate-command 
+           '(dabbrev-expand repeating-insertion-from-ring))
+      ;; Take special care of text insertion from insertion ring inside
+      ;; replacement overlays.
       (progn
        (setq viper-replace-chars-to-delete 0)
        (viper-move-marker-locally 
         'viper-last-posn-in-replace-region (point)))
     
-    (let (beg-col end-col real-end chars-to-delete)
-      (setq real-end (min end (viper-replace-end)))
-      (save-excursion
-       (goto-char beg)
-       (setq beg-col (current-column))
-       (goto-char real-end)
-       (setq end-col (current-column)))
-      
-      ;; If beg of change is outside the replacement region, then don't
-      ;; delete anything in the repl region (set chars-to-delete to 0).
-      ;;
-      ;; This works fine except that we have to take special care of
-      ;; dabbrev-expand.  The problem stems from new-dabbrev.el, which
-      ;; sometimes simply shifts the repl region rightwards, without
-      ;; deleting an equal amount of characters.
-      ;;
-      ;; The reason why new-dabbrev.el causes this are this:
-      ;; if one dinamically completes a partial word that starts before the
-      ;; replacement region (but ends inside) then new-dabbrev.el first
-      ;; moves cursor backwards, to the beginning of the word to be
-      ;; completed (say, pt A). Then it inserts the 
-      ;; completed word and then deletes the old, incomplete part.
-      ;; Since the complete word is inserted at position before the repl
-      ;; region, the next If-statement would have set chars-to-delete to 0
-      ;; unless we check for the current command, which must be
-      ;; dabbrev-expand.
-      ;;
-      ;; In fact, it might be also useful to have overlays for insert
-      ;; regions as well, since this will let us capture the situation when
-      ;; dabbrev-expand goes back past the insertion point to find the
-      ;; beginning of the word to be expanded.
-      (if (or (and (<= (viper-replace-start) beg)
-                  (<= beg (viper-replace-end)))
-             (and (= length 0) (eq this-command 'dabbrev-expand)))
-         (setq chars-to-delete
-               (max (- end-col beg-col) (- real-end beg) 0))
-       (setq chars-to-delete 0))
-      
-      ;; if beg = last change position, it means that we are within the
-      ;; same command that does multiple changes. Moreover, it means
-      ;; that we have two subsequent changes (insert/delete) that
-      ;; complement each other.
-      (if (= beg (marker-position viper-last-posn-in-replace-region))
-         (setq viper-replace-chars-to-delete 
-               (- (+ chars-to-delete viper-replace-chars-to-delete)
-                  viper-replace-chars-deleted)) 
-       (setq viper-replace-chars-to-delete chars-to-delete))
-      
+    (let* ((real-end (min end (viper-replace-end)))
+          (column-shift (- (save-excursion (goto-char real-end)
+                                           (current-column))
+                           (save-excursion (goto-char beg)
+                                           (current-column))))
+          (chars-deleted 0))
+
+      (if (> length 0)
+         (setq chars-deleted viper-replace-region-chars-deleted))
+      (setq viper-replace-region-chars-deleted 0)
+      (setq viper-replace-chars-to-delete
+           (+ viper-replace-chars-to-delete
+              (- 
+               ;; if column shift is bigger, due to a TAB insertion, take
+               ;; column-shift instead of the number of inserted chars
+               (max (viper-chars-in-region beg real-end)
+                    ;; This test accounts for Chinese/Japanese/...  chars,
+                    ;; which occupy 2 columns instead of one. If we use
+                    ;; column-shift here, we may delete two chars instead of
+                    ;; one when the user types one Chinese character. Deleting
+                    ;; two would be OK, if they were European chars, but it is
+                    ;; not OK if they are Chinese chars. Since it is hard to
+                    ;; figure out which characters are being deleted in any
+                    ;; given region, we decided to treat Eastern and European
+                    ;; characters equally, even though Eastern chars may
+                    ;; occupy more columns.
+                    (if (memq this-command '(self-insert-command
+                                             quoted-insert viper-insert-tab))
+                        column-shift
+                      0))
+               ;; the number of deleted chars
+               chars-deleted)))
+
       (viper-move-marker-locally 
        'viper-last-posn-in-replace-region
-       (max (if (> end (viper-replace-end)) (viper-replace-start) end)
+       (max (if (> end (viper-replace-end)) (viper-replace-end) end)
            (or (marker-position viper-last-posn-in-replace-region)
                (viper-replace-start)) 
            ))
       
-      (setq viper-replace-chars-to-delete
-           (max 0
-                (min viper-replace-chars-to-delete
-                     (- (viper-replace-end) viper-last-posn-in-replace-region)
-                     (- (viper-line-pos 'end)
-                        viper-last-posn-in-replace-region)
-                     )))
       )))
 
-
-;; Delete stuff between posn and the end of viper-replace-overlay-marker, if
-;; posn is within the overlay.
-(defun viper-finish-change (posn)
+;; Make sure we don't delete more than needed.
+;; This is executed at viper-last-posn-in-replace-region
+(defsubst viper-trim-replace-chars-to-delete-if-necessary ()
+  (setq viper-replace-chars-to-delete
+       (max 0
+            (min viper-replace-chars-to-delete
+                 ;; Don't delete more than to the end of repl overlay
+                 (viper-chars-in-region
+                  (viper-replace-end) viper-last-posn-in-replace-region)
+                 ;; point is viper-last-posn-in-replace-region now
+                 ;; So, this limits deletion to the end of line
+                 (viper-chars-in-region (point) (viper-line-pos 'end))
+                 ))))
+
+
+;; Delete stuff between viper-last-posn-in-replace-region and the end of
+;; viper-replace-overlay-marker, if viper-last-posn-in-replace-region is within
+;; the overlay and current point is before the end of the overlay.
+;; Don't delete anything if current point is past the end of the overlay.
+(defun viper-finish-change ()
   (viper-remove-hook
    'viper-after-change-functions 'viper-replace-mode-spy-after)
   (viper-remove-hook
@@ -2102,12 +2112,13 @@ Undo previous insertion and inserts new."
   (viper-restore-cursor-color-after-replace)
   (setq viper-sitting-in-replace nil) ; just in case we'll need to know it
   (save-excursion
-    (if (and 
-        viper-replace-overlay
-        (>= posn (viper-replace-start))
-        (<  posn (viper-replace-end)))
-          (delete-region posn (viper-replace-end)))
-    )
+    (if (and viper-replace-overlay
+            (viper-pos-within-region viper-last-posn-in-replace-region
+                                     (viper-replace-start)
+                                     (viper-replace-end)) 
+            (< (point) (viper-replace-end)))
+       (delete-region
+        viper-last-posn-in-replace-region (viper-replace-end))))
   
   (if (eq viper-current-state 'replace-state)
       (viper-downgrade-to-insert))
@@ -2150,9 +2161,9 @@ Undo previous insertion and inserts new."
   "Binding for keys that cause Replace state to switch to Vi or to Insert.
 These keys are ESC, RET, and LineFeed"
   (interactive)
-  (if overwrite-mode  ;; If you are in replace mode invoked via 'R'
+  (if overwrite-mode   ; if in replace mode invoked via 'R'
       (viper-finish-R-mode)
-    (viper-finish-change viper-last-posn-in-replace-region))
+    (viper-finish-change))
   (let (com)
     (if (eq this-command 'viper-intercept-ESC-key)
        (setq com 'viper-exit-insert-state)
@@ -2269,29 +2280,66 @@ These keys are ESC, RET, and LineFeed"
        (com (viper-getcom arg)))
     (viper-replace-char-subr com val)
     (if (and (eolp) (not (bolp))) (forward-char 1))
+    (setq viper-this-command-keys
+         (format "%sr" (if (integerp arg) arg "")))
     (viper-set-destructive-command
      (list 'viper-replace-char val ?r nil viper-d-char nil))
   ))
 
 (defun viper-replace-char-subr (com arg)
-  (let ((take-care-of-iso-accents
-        (and (boundp 'iso-accents-mode) viper-automatic-iso-accents))
-       char)
+  (let (char)
     (setq char (if (equal com ?r)
                   viper-d-char
                 (read-char)))
-    (if (and  take-care-of-iso-accents (memq char '(?' ?\" ?^ ?~)))
-       ;; get European characters
-       (progn
-         (iso-accents-mode 1)
-         (viper-set-unread-command-events char)
-         (setq char (aref (read-key-sequence nil) 0))
-         (iso-accents-mode -1)))
-    (delete-char arg t)
-    (setq viper-d-char char)
-    (viper-loop (if (> arg 0) arg (- arg)) 
-           (if (eq char ?\C-m) (insert "\n") (insert char)))
-    (backward-char arg)))
+    (let (inhibit-quit) ; preserve consistency of undo-list and iso-accents
+      (if (and  viper-automatic-iso-accents (memq char '(?' ?\" ?^ ?~)))
+         ;; get European characters
+         (progn
+           (viper-set-iso-accents-mode t)
+           (viper-set-unread-command-events char)
+           (setq char (aref (read-key-sequence nil) 0))
+           (viper-set-iso-accents-mode nil)))
+      (viper-set-complex-command-for-undo)
+      (if (eq char ?\C-m) (setq char ?\n))
+      (if (and viper-special-input-method (fboundp 'quail-start-translation))
+         ;; get Intl. characters
+         (progn
+           (viper-set-input-method t)
+           (setq last-command-event 
+                 (viper-copy-event
+                  (if viper-xemacs-p (character-to-event char) char)))
+           (delete-char 1 t)
+           (condition-case nil
+               (if com
+                   (insert char)
+                 (if viper-emacs-p
+                     (quail-start-translation 1)
+                   (quail-start-translation)))
+             (error))
+           ;; quail translation failed
+           (if (and (not (stringp quail-current-str))
+                    (not (viper-characterp quail-current-str)))
+               (progn
+                 (viper-adjust-undo)
+                 (undo-start)
+                 (undo-more 1)
+                 (viper-set-input-method nil)
+                 (error "Composing character failed, changes undone")))
+           ;; quail translation seems ok
+           (or com
+               ;;(setq char quail-current-str))
+               (setq char (viper-char-at-pos 'backward)))
+           (setq viper-d-char char)
+           (viper-loop (1- (if (> arg 0) arg (- arg)))
+                       (delete-char 1 t)
+                       (insert char))
+           (viper-set-input-method nil))
+       (delete-char arg t)
+       (setq viper-d-char char)
+       (viper-loop (if (> arg 0) arg (- arg)) 
+                   (insert char)))
+      (viper-adjust-undo)
+      (backward-char arg))))
 
 \f
 ;; basic cursor movement.  j, k, l, h commands.
@@ -2334,18 +2382,30 @@ On reaching beginning of line, stop and signal error."
       (if com (viper-execute-com 'viper-backward-char val com)))))
       
 ;; Like forward-char, but doesn't move at end of buffer.
+;; Returns distance traveled 
+;; (positive or 0, if arg positive; negative if arg negative).
 (defun viper-forward-char-carefully (&optional arg)      
   (setq arg (or arg 1))
-  (if (>= (point-max) (+ (point) arg))
-      (forward-char arg)
-    (goto-char (point-max))))
+  (let ((pt (point)))
+    (condition-case nil
+       (forward-char arg)
+      (error))
+    (if (< (point) pt) ; arg was negative
+       (- (viper-chars-in-region pt (point)))
+      (viper-chars-in-region pt (point)))))
       
-;; Like backward-char, but doesn't move at end of buffer.
+;; Like backward-char, but doesn't move at beg of buffer.
+;; Returns distance traveled
+;; (negative or 0, if arg positive; positive if arg negative).
 (defun viper-backward-char-carefully (&optional arg)      
   (setq arg (or arg 1))
-  (if (<= (point-min) (- (point) arg))
-      (backward-char arg)
-    (goto-char (point-min))))
+  (let ((pt (point)))
+    (condition-case nil
+       (backward-char arg)
+      (error))
+    (if (> (point) pt) ; arg was negative
+       (viper-chars-in-region pt (point))
+      (- (viper-chars-in-region pt (point))))))
 
 (defun viper-next-line-carefully (arg)
   (condition-case nil
@@ -2372,7 +2432,7 @@ On reaching beginning of line, stop and signal error."
              (forward-char)
              (viper-skip-all-separators-forward  'within-line))))
     (viper-skip-all-separators-backward 'within-line)
-    (backward-char)
+    (viper-backward-char-carefully)
     (if (looking-at "\n")
        (viper-skip-all-separators-backward 'within-line)
       (forward-char))))
@@ -2389,16 +2449,43 @@ On reaching beginning of line, stop and signal error."
           (viper-skip-separators t)))
     (setq val (1- val))))
 
-;; first search backward for pat. Then skip chars backwards using aux-pat
-(defun viper-fwd-skip (pat aux-pat lim)
-  (if (and (save-excursion 
-            (re-search-backward pat lim t))
-          (= (point) (match-end 0)))
-      (goto-char (match-beginning 0)))
-  (skip-chars-backward aux-pat lim)
-  (if (= (point) lim)
-      (viper-forward-char-carefully))
-  )
+;; first skip non-newline separators backward, then skip \n. Then, if TWICE is
+;; non-nil, skip non-\n back again, but don't overshoot the limit LIM.
+(defun viper-separator-skipback-special (twice lim)
+  (let ((prev-char (viper-char-at-pos 'backward))
+       (saved-point (point)))
+    ;; skip non-newline separators backward
+    (while (and (not (memq prev-char '(nil \n)))
+               (< lim (point))
+               ;; must be non-newline separator
+               (if (eq viper-syntax-preference 'strict-vi)
+                   (memq prev-char '(?\  ?\t))
+                 (memq (char-syntax prev-char) '(?\  ?-))))
+      (viper-backward-char-carefully)
+      (setq prev-char (viper-char-at-pos 'backward)))
+
+    (if (and (< lim (point)) (eq prev-char ?\n))
+       (backward-char)
+      ;; If we skipped to the next word and the prefix of this line doesn't
+      ;; consist of separators preceded by a newline, then don't skip backwards
+      ;; at all.
+      (goto-char saved-point))
+    (setq prev-char (viper-char-at-pos 'backward))
+
+    ;; skip again, but make sure we don't overshoot the limit
+    (if twice
+       (while (and (not (memq prev-char '(nil \n)))
+                   (< lim (point))
+                   ;; must be non-newline separator
+                   (if (eq viper-syntax-preference 'strict-vi)
+                       (memq prev-char '(?\  ?\t))
+                     (memq (char-syntax prev-char) '(?\  ?-))))
+         (viper-backward-char-carefully)
+         (setq prev-char (viper-char-at-pos 'backward))))
+
+    (if (= (point) lim)
+       (viper-forward-char-carefully))
+    ))
 
          
 (defun viper-forward-word (arg)
@@ -2411,12 +2498,12 @@ On reaching beginning of line, stop and signal error."
     (viper-forward-word-kernel val)
     (if com (progn
              (cond ((memq com (list ?c (- ?c)))
-                    (viper-fwd-skip "\n[ \t]*" " \t" viper-com-point))
+                    (viper-separator-skipback-special 'twice viper-com-point))
                    ;; Yank words including the whitespace, but not newline
                    ((memq com (list ?y (- ?y)))
-                    (viper-fwd-skip "\n[ \t]*" "" viper-com-point))
+                    (viper-separator-skipback-special nil viper-com-point))
                    ((viper-dotable-command-p com)
-                    (viper-fwd-skip "\n[ \t]*" "" viper-com-point)))
+                    (viper-separator-skipback-special nil viper-com-point)))
              (viper-execute-com 'viper-forward-word val com)))))
          
 
@@ -2428,17 +2515,16 @@ On reaching beginning of line, stop and signal error."
        (com (viper-getcom arg)))
     (if com (viper-move-marker-locally 'viper-com-point (point)))
     (viper-loop val
-             (progn
                (viper-skip-nonseparators 'forward)
-               (viper-skip-separators t)))
+               (viper-skip-separators t))
     (if com (progn
              (cond ((memq com (list ?c (- ?c)))
-                    (viper-fwd-skip "\n[ \t]*" " \t" viper-com-point))
+                    (viper-separator-skipback-special 'twice viper-com-point))
                    ;; Yank words including the whitespace, but not newline
                    ((memq com (list ?y (- ?y)))
-                    (viper-fwd-skip "\n[ \t]*" "" viper-com-point))
+                    (viper-separator-skipback-special nil viper-com-point))
                    ((viper-dotable-command-p com)
-                    (viper-fwd-skip "\n[ \t]*" "" viper-com-point)))
+                    (viper-separator-skipback-special nil viper-com-point)))
              (viper-execute-com 'viper-forward-Word val com)))))
 
 
@@ -2485,10 +2571,9 @@ On reaching beginning of line, stop and signal error."
        (com (viper-getcom arg)))
     (if com (viper-move-marker-locally 'viper-com-point (point)))
     (viper-loop val
-             (progn
                (viper-end-of-word-kernel)
                (viper-skip-nonseparators 'forward)
-               (backward-char)))
+               (backward-char))
     (if com 
        (progn
          (forward-char)
@@ -2496,17 +2581,18 @@ On reaching beginning of line, stop and signal error."
 
 (defun viper-backward-word-kernel (val)
   (while (> val 0)
-    (backward-char)
+    (viper-backward-char-carefully)
     (cond ((viper-looking-at-alpha)
           (viper-skip-alpha-backward "_"))
          ((viper-looking-at-separator)
           (forward-char)
           (viper-skip-separators nil)
-          (backward-char)
+          (viper-backward-char-carefully)
           (cond ((viper-looking-at-alpha)
                  (viper-skip-alpha-backward "_"))
                 ((not (viper-looking-at-alphasep))
                  (viper-skip-nonalphasep-backward))
+                ((bobp)) ; could still be at separator, but at beg of buffer
                 (t (forward-char))))
          ((not (viper-looking-at-alphasep))
           (viper-skip-nonalphasep-backward)))
@@ -2540,9 +2626,8 @@ On reaching beginning of line, stop and signal error."
          (viper-move-marker-locally 'viper-com-point (point))
          (if i (forward-char))))
     (viper-loop val
-             (progn 
-               (viper-skip-separators nil)
-               (viper-skip-nonseparators 'backward)))
+               (viper-skip-separators nil) ; nil means backward here
+               (viper-skip-nonseparators 'backward))
     (if com (viper-execute-com 'viper-backward-Word val com))))
 
 
@@ -2593,7 +2678,9 @@ On reaching beginning of line, stop and signal error."
   (let ((val (viper-p-val arg))
        (com (viper-getcom arg))
        line-len)
-    (setq line-len (- (viper-line-pos 'end) (viper-line-pos 'start)))
+    (setq line-len
+         (viper-chars-in-region
+          (viper-line-pos 'start) (viper-line-pos 'end)))
     (if com (viper-move-marker-locally 'viper-com-point (point)))
     (beginning-of-line)
     (forward-char (1- (min line-len val)))
@@ -2733,7 +2820,10 @@ On reaching beginning of line, stop and signal error."
              (search-forward (char-to-string char) nil 0 arg))
            (setq point (point))
          (error "Command `%s':  `%c' not found" cmd char))))
-    (goto-char (+ point (if (> arg 0) (if offset -2 -1) (if offset 1 0))))))
+    (goto-char point)
+    (if (> arg 0)
+       (backward-char (if offset 2 1))
+      (forward-char (if offset 1 0)))))
 
 (defun viper-find-char-forward (arg)
   "Find char on the line. 
@@ -3696,67 +3786,68 @@ To turn this feature off, set this variable to nil."
     
 
 (defun viper-delete-char (arg)
-  "Delete character."
+  "Delete next character."
   (interactive "P")
-  (let ((val (viper-p-val arg)))
+  (let ((val (viper-p-val arg))
+       end-del-pos)
     (viper-set-destructive-command
      (list 'viper-delete-char val nil nil nil nil))
-    (if (> val 1)
-       (save-excursion
-         (let ((here (point)))
-           (end-of-line)
-           (if (> val (- (point) here))
-               (setq val (- (point) here))))))
-    (if (and (eq val 0) (not viper-ex-style-motion)) (setq val 1))
+    (if (and viper-ex-style-editing
+            (> val (viper-chars-in-region (point) (viper-line-pos 'end))))
+       (setq val (viper-chars-in-region (point) (viper-line-pos 'end))))
     (if (and viper-ex-style-motion (eolp))
        (if (bolp) (error "") (setq val 0))) ; not bol---simply back 1 ch
+    (save-excursion
+      (viper-forward-char-carefully val)
+      (setq end-del-pos (point)))
     (if viper-use-register
        (progn
          (cond ((viper-valid-register viper-use-register '((Letter)))
                 (viper-append-to-register
-                 (downcase viper-use-register) (point) (- (point) val)))
+                 (downcase viper-use-register) (point) end-del-pos))
                ((viper-valid-register viper-use-register)
                 (copy-to-register
-                 viper-use-register (point) (- (point) val) nil))
+                 viper-use-register (point) end-del-pos nil))
                (t (error viper-InvalidRegister viper-use-register)))
          (setq viper-use-register nil)))
+
+    (delete-char val t)
     (if viper-ex-style-motion
-       (progn
-         (delete-char val t)
-         (if (and (eolp) (not (bolp))) (backward-char 1)))
-      (if (eolp)
-          (delete-backward-char val t)
-        (delete-char val t)))))
+       (if (and (eolp) (not (bolp))) (backward-char 1)))
+    ))
 
 (defun viper-delete-backward-char (arg)
   "Delete previous character. On reaching beginning of line, stop and beep."
   (interactive "P")
-  (let ((val (viper-p-val arg)))
+  (let ((val (viper-p-val arg))
+       end-del-pos)
     (viper-set-destructive-command
      (list 'viper-delete-backward-char val nil nil nil nil))
-    (if (> val 1)
-       (save-excursion
-         (let ((here (point)))
-           (beginning-of-line)
-           (if (> val (- here (point)))
-               (setq val (- here (point)))))))
+    (if (and 
+        viper-ex-style-editing
+        (> val (viper-chars-in-region (viper-line-pos 'start) (point))))
+       (setq val (viper-chars-in-region (viper-line-pos 'start) (point))))
+    (save-excursion
+      (viper-backward-char-carefully val)
+      (setq end-del-pos (point)))
     (if viper-use-register
        (progn
          (cond ((viper-valid-register viper-use-register '(Letter))
                 (viper-append-to-register
-                 (downcase viper-use-register) (point) (+ (point) val)))
+                 (downcase viper-use-register) end-del-pos (point)))
                ((viper-valid-register viper-use-register)
                 (copy-to-register
-                 viper-use-register (point) (+ (point) val) nil))
+                 viper-use-register end-del-pos (point) nil))
                (t (error viper-InvalidRegister viper-use-register)))
          (setq viper-use-register nil)))
-    (if (bolp) (ding)
-      (delete-backward-char val t))))
+    (if (and (bolp) viper-ex-style-editing)
+       (ding))
+    (delete-backward-char val t)))
       
 (defun viper-del-backward-char-in-insert ()
   "Delete 1 char backwards while in insert mode."
   (interactive)      
-  (if (and viper-ex-style-editing-in-insert (bolp))
+  (if (and viper-ex-style-editing (bolp))
       (beep 1)
     (delete-backward-char 1 t)))
       
@@ -3764,19 +3855,19 @@ To turn this feature off, set this variable to nil."
   "Delete one character in replace mode.
 If `viper-delete-backwards-in-replace' is t, then DEL key actually deletes
 charecters. If it is nil, then the cursor just moves backwards, similarly
-to Vi. The variable `viper-ex-style-editing-in-insert', if t, doesn't let the
+to Vi. The variable `viper-ex-style-editing', if t, doesn't let the
 cursor move past the beginning of line."
   (interactive)
   (cond (viper-delete-backwards-in-replace
         (cond ((not (bolp))
                (delete-backward-char 1 t))
-              (viper-ex-style-editing-in-insert
+              (viper-ex-style-editing
                (beep 1))
               ((bobp)
                (beep 1))
               (t
                (delete-backward-char 1 t))))
-       (viper-ex-style-editing-in-insert
+       (viper-ex-style-editing
         (if (bolp)
             (beep 1)
           (backward-char 1)))
@@ -3794,7 +3885,6 @@ cursor move past the beginning of line."
     (viper-set-destructive-command
      (list 'viper-join-lines val nil nil nil nil))
     (viper-loop (if (null val) 1 (1- val))
-             (progn
                (end-of-line)
                (if (not (eobp))
                    (progn
@@ -3806,7 +3896,7 @@ cursor move past the beginning of line."
                      (or (looking-at " ")
                          (insert " ")
                          (backward-char 1))
-                     ))))))
+                     )))))
 
 \f
 ;; Replace state
@@ -4262,7 +4352,7 @@ sensitive for VI-style look-and-feel."
   
   (setq viper-always                           t
        viper-ex-style-motion                   t
-       viper-ex-style-editing-in-insert        t    
+       viper-ex-style-editing                  t    
        viper-want-ctl-h-help nil)
 
   (cond ((eq viper-expert-level 1) ; novice or beginner
@@ -4289,14 +4379,14 @@ sensitive for VI-style look-and-feel."
                                        ; and viper-no-multiple-ESC
             (progn
               (setq-default
-               viper-ex-style-editing-in-insert
-               (viper-standard-value 'viper-ex-style-editing-in-insert)
+               viper-ex-style-editing
+               (viper-standard-value 'viper-ex-style-editing)
                viper-ex-style-motion
                (viper-standard-value 'viper-ex-style-motion))
               (setq viper-ex-style-motion 
                     (viper-standard-value 'viper-ex-style-motion)
-                    viper-ex-style-editing-in-insert
-                    (viper-standard-value 'viper-ex-style-editing-in-insert)
+                    viper-ex-style-editing
+                    (viper-standard-value 'viper-ex-style-editing)
                     viper-re-search
                     (viper-standard-value 'viper-re-search)
                     viper-no-multiple-ESC 
@@ -4305,8 +4395,8 @@ sensitive for VI-style look-and-feel."
        ;; A wizard!!
        ;; Ideally, if 5 is selected, a buffer should pop up to let the
        ;; user toggle the values of variables.
-       (t (setq-default viper-ex-style-editing-in-insert
-                        (viper-standard-value 'viper-ex-style-editing-in-insert)
+       (t (setq-default viper-ex-style-editing
+                        (viper-standard-value 'viper-ex-style-editing)
                         viper-ex-style-motion
                         (viper-standard-value 'viper-ex-style-motion))
           (setq  viper-want-ctl-h-help 
@@ -4317,8 +4407,8 @@ sensitive for VI-style look-and-feel."
                  (viper-standard-value 'viper-no-multiple-ESC)
                  viper-ex-style-motion 
                  (viper-standard-value 'viper-ex-style-motion)
-                 viper-ex-style-editing-in-insert
-                 (viper-standard-value 'viper-ex-style-editing-in-insert)
+                 viper-ex-style-editing
+                 (viper-standard-value 'viper-ex-style-editing)
                  viper-re-search
                  (viper-standard-value 'viper-re-search)
                  viper-electric-mode 
@@ -4366,7 +4456,7 @@ You can change it at any time by typing `M-x viper-set-expert-level RET'
  3 -- GRAND MASTER: Like 3, but most Emacs commands are available also
        in Viper's insert state.
  4 -- GURU: Like 3, but user settings are respected for viper-no-multiple-ESC,
-       viper-ex-style-motion, viper-ex-style-editing-in-insert, and
+       viper-ex-style-motion, viper-ex-style-editing, and
        viper-re-search variables. Adjust these settings to your taste.
  5 -- WIZARD: Like 4, but user settings are also respected for viper-always,
        viper-electric-mode, viper-want-ctl-h-help, viper-want-emacs-keys-in-vi,
@@ -4487,6 +4577,7 @@ Please, specify your level now: ")
                        'viper-emacs-global-user-minor-mode
                        'viper-emacs-state-modifier-minor-mode
                        'viper-automatic-iso-accents
+                       'viper-special-input-method
                        'viper-want-emacs-keys-in-insert
                        'viper-want-emacs-keys-in-vi
                        'viper-keep-point-on-undo
@@ -4494,7 +4585,7 @@ Please, specify your level now: ")
                        'viper-electric-mode
                        'viper-ESC-key
                        'viper-want-ctl-h-help
-                       'viper-ex-style-editing-in-insert
+                       'viper-ex-style-editing
                        'viper-delete-backwards-in-replace
                        'viper-vi-style-in-minibuffer
                        'viper-vi-state-hook
index 18878d8328bbe58dc2ed34edc9357b3074be8853..83d6038129a61f9704a267d44a3a0d8d900d70f0 100644 (file)
@@ -25,6 +25,9 @@
 
 ;; compiler pacifier
 (defvar mark-even-if-inactive)
+(defvar quail-mode)
+(defvar iso-accents-mode)
+(defvar viper-current-state)
 (defvar viper-version)
 (defvar viper-expert-level)
 ;; end pacifier
@@ -83,13 +86,15 @@ In all likelihood, you don't need to bother with this setting."
        (make-variable-buffer-local '(, var))
      )))
 
-(defmacro viper-loop (count body)
-  "(viper-loop COUNT BODY) Execute BODY COUNT times."
-  (list 'let (list (list 'count count))
-       (list 'while '(> count 0)
-             body
-             '(setq count (1- count))
-             )))
+;; (viper-loop COUNT BODY) Execute BODY COUNT times.
+(defmacro viper-loop (count &rest body)
+  (` (let ((count (, count)))
+       (while (> count 0)
+        (progn
+          (,@ body)
+          (setq count (1- count))
+          ))
+       )))
 
 (defmacro viper-buffer-live-p (buf)
   (` (and (, buf) (get-buffer (, buf)) (buffer-name (get-buffer (, buf))))))
@@ -124,6 +129,19 @@ In all likelihood, you don't need to bother with this setting."
 ;; last elt of a sequence
 (defsubst viper-seq-last-elt (seq)
   (elt seq (1- (length seq))))
+
+(defsubst viper-string-to-list (string)
+  (append (vconcat string) nil))
+
+(defsubst viper-charlist-to-string (list)
+  (mapconcat 'char-to-string list ""))
+
+;; like char-after/before, but saves typing
+(defun viper-char-at-pos (direction &optional offset)
+  (or (integerp offset) (setq offset 0))
+  (if (eq direction 'forward)
+      (char-after (+ (point) offset))
+    (char-before (- (point) offset))))
   
 \f
 (defvar viper-minibuffer-overlay-priority 300)
@@ -251,16 +269,81 @@ Use `M-x viper-set-expert-level' to change this.")
 (defconst viper-max-expert-level 5)
 
 
-;;; ISO characters
-  
+;;; ISO characters and MULE
+
+;; If non-nil, ISO accents will be turned on in insert/replace emacs states and
+;; turned off in vi-state.  For some users, this behavior may be too
+;; primitive. In this case, use insert/emacs/vi state hooks.
 (viper-deflocalvar viper-automatic-iso-accents nil "")
-(defcustom viper-automatic-iso-accents nil
-  "*If non-nil, ISO accents will be turned on in insert/replace emacs states and turned off in vi-state. 
-For some users, this behavior may be too primitive. In this case, use
-insert/emacs/vi state hooks."
-  :type 'boolean
-  :group 'viper)
+;; Set iso-accents-mode to ARG. Check if it is bound first
+(defsubst viper-set-iso-accents-mode (arg)
+  (if (boundp 'iso-accents-mode)
+      (setq iso-accents-mode arg)))
+  
+;; Internal flag used to control when viper mule hooks are run.
+;; Don't change this!
+(defvar viper-mule-hook-flag t)
+;; If non-nil, the default intl. input method is turned on.
+(viper-deflocalvar viper-special-input-method nil "")
   
+;; viper hook to run on input-method activation
+(defun viper-activate-input-method-action ()
+  (if (null viper-mule-hook-flag)
+      ()
+    (setq viper-special-input-method t)
+    ;; turn off special input methods in vi-state
+    (if (eq viper-current-state 'vi-state)
+       (viper-set-input-method nil))
+    (if (memq viper-current-state '(vi-state insert-state replace-state))
+       (message "Viper special input method%s: on"
+                (if (or current-input-method default-input-method)
+                    (format " %S" 
+                            (or current-input-method default-input-method))
+                  "")))
+    ))
+;; viper hook to run on input-method deactivation
+(defun viper-inactivate-input-method-action ()
+  (if (null viper-mule-hook-flag)
+      ()
+    (setq viper-special-input-method nil)
+    (if (memq viper-current-state '(vi-state insert-state replace-state))
+       (message "Viper special input method%s: off"
+                (if (or current-input-method default-input-method)
+                    (format " %S"
+                            (or current-input-method default-input-method))
+                  "")))))
+
+(defun viper-inactivate-input-method ()
+  (cond ((and viper-emacs-p (fboundp 'inactivate-input-method))
+        (inactivate-input-method))
+       ((and viper-xemacs-p (boundp 'current-input-method))
+        ;; XEmacs had broken quil-mode for some time, so we are working around
+        ;; it here 
+        (setq quail-mode nil)
+        (if (featurep 'quail)
+            (quail-delete-overlays))
+        (setq describe-current-input-method-function nil)
+        (setq current-input-method nil)
+        (run-hooks 'input-method-inactivate-hook)
+        (force-mode-line-update))
+       ))
+(defun viper-activate-input-method ()
+  (cond ((and viper-emacs-p (fboundp 'activate-input-method))
+        (activate-input-method default-input-method))
+       ((and viper-xemacs-p (fboundp 'quail-mode))
+        (quail-mode 1))))
+
+;; Set quail-mode to ARG
+(defun viper-set-input-method (arg)
+  (setq viper-mule-hook-flag t) ; just a precaution
+  (let (viper-mule-hook-flag) ; temporarily inactivate viper mule hooks
+    (cond ((and arg (> (prefix-numeric-value arg) 0) default-input-method)
+          ;; activate input method
+          (viper-activate-input-method))
+         (t ; deactivate input method
+          (viper-inactivate-input-method)))
+    ))
+
 
 ;; VI-style Undo
 
@@ -372,7 +455,12 @@ color displays. By default, the delimiters are used only on TTYs."
 ;; Remember the number of characters that have to be deleted in replace
 ;; mode to compensate for the inserted characters.
 (viper-deflocalvar viper-replace-chars-to-delete 0 "")
-(viper-deflocalvar viper-replace-chars-deleted 0 "")
+;; This variable is used internally by the before/after changed functions to
+;; determine how many chars were deleted by the change. This can't be
+;; determined inside after-change-functions because those get the length of the
+;; deleted region, not the number of chars deleted (which are two different
+;; things under MULE).
+(viper-deflocalvar viper-replace-region-chars-deleted 0 "")
 
 ;; Insertion ring and command ring
 (defcustom viper-insertion-ring-size 14
@@ -520,8 +608,7 @@ to a new place after repeating previous Vi command."
 (defvar viper-use-register nil)
 
 
-
-;; Variables for Moves and Searches
+;;; Variables for Moves and Searches
 
 ;; For use by `;' command.
 (defvar viper-f-char nil)
@@ -589,18 +676,22 @@ If nil, these commands cross line boundaries."
   :type 'boolean
   :group 'viper)
 
-(viper-deflocalvar viper-ex-style-editing-in-insert t "")
-(defcustom viper-ex-style-editing-in-insert t
-  "*If t, `Backspace' and `Delete' don't cross line boundaries in insert, etc.
+(viper-deflocalvar viper-ex-style-editing t "")
+(defcustom viper-ex-style-editing t
+  "*If t, Ex-style behavior while editing in Vi command and insert states.
+`Backspace' and `Delete' don't cross line boundaries in insert.
+`X' and `x' can't delete characters across line boundary in Vi, etc.
 Note: this doesn't preclude `Backspace' and `Delete' from deleting characters
-by moving past the insertion point. This is a feature, not a bug."
+by moving past the insertion point. This is a feature, not a bug.
+
+If nil, the above commands can work across lines."
   :type 'boolean
   :group 'viper)
 
-(viper-deflocalvar viper-ESC-moves-cursor-back viper-ex-style-editing-in-insert "")
+(viper-deflocalvar viper-ESC-moves-cursor-back viper-ex-style-editing "")
 (defcustom viper-ESC-moves-cursor-back nil
   "*If t, ESC moves cursor back when changing from insert to vi state.
-If nil, the cursor stays where it was."
+If nil, the cursor stays where it was when ESC was hit."
   :type 'boolean
   :group 'viper)
 
index 76ba0285bb4539f48644a736ff945fc05fb3f0c3..9ff82875e5b819ab48ff9352c238b6faf8b4e8d9 100644 (file)
@@ -28,7 +28,7 @@
 (defvar viper-current-state)
 (defvar viper-mode-string)
 (defvar viper-expert-level)
-(defvar viper-ex-style-editing-in-insert)
+(defvar viper-ex-style-editing)
 (defvar viper-ex-style-motion)
 
 ;; loading happens only in non-interactive compilation
@@ -597,8 +597,8 @@ Arguments: (major-mode viper-state keymap)"
     (princ (format "viper-always  %S\n" viper-always))
     (princ (format "viper-ex-style-motion  %S\n"
                   viper-ex-style-motion))
-    (princ (format "viper-ex-style-editing-in-insert  %S\n"
-                  viper-ex-style-editing-in-insert))
+    (princ (format "viper-ex-style-editing  %S\n"
+                  viper-ex-style-editing))
     (princ (format "viper-want-emacs-keys-in-vi  %S\n"
                   viper-want-emacs-keys-in-vi)) 
     (princ (format "viper-want-emacs-keys-in-insert  %S\n"
index 9a11e0d35e959d6f25d8742317f26f1a4b77ecaf..7f8a4a4a2e46164e1f09a70818bcc7565809a339 100644 (file)
@@ -35,6 +35,7 @@
 (defvar ex-unix-type-shell)
 (defvar ex-unix-type-shell-options)
 (defvar viper-ex-tmp-buf-name)
+(defvar viper-syntax-preference)
 
 (require 'cl)
 (require 'ring)
     (goto-char cur-pos)
     result))
 
+;; Emacs counts each multibyte character as several positions in the buffer, so
+;; we use Emacs' chars-in-region. XEmacs is counting each char as just one pos,
+;; so we can simply subtract. 
+(defun viper-chars-in-region (beg end &optional preserve-sign)
+  (let ((count (abs (if (fboundp 'chars-in-region)
+                       (chars-in-region beg end)
+                     (- end beg)))))
+    (if (and (< end beg) preserve-sign)
+       (- count)
+      count)))
+
+;; Test if POS is between BEG and END
+(defsubst viper-pos-within-region (pos beg end)
+  (and (>= pos (min beg end)) (>= (max beg end) pos)))
+
 
 ;; Like move-marker but creates a virgin marker if arg isn't already a marker.
 ;; The first argument must eval to a variable name.
@@ -1058,45 +1074,104 @@ the `Local variables' section of a file."
 
 ;;; Movement utilities
 
-(defcustom viper-syntax-preference 'strict-vi
-  "*Syntax type characterizing Viper's alphanumeric symbols.
-`emacs' means only word constituents are considered to be alphanumeric.
-Word constituents are symbols specified as word constituents by the current
-syntax table.
-`extended' means word and symbol constituents.
-`reformed-vi' means Vi-ish behavior: word constituents and the symbol `_'.
-However, word constituents are determined according to Emacs syntax tables,
-which may be different from Vi in some major modes.
-`strict-vi' means Viper words are exactly as in Vi."
-  :type '(radio (const strict-vi) (const reformed-vi) 
-                (const extended) (const emacs))
-  :group 'viper)
+;; Characters that should not be considered as part of the word, in reformed-vi
+;; syntax mode.
+(defconst viper-non-word-characters-reformed-vi
+  "!@#$%^&*()-+=|\\~`{}[];:'\",<.>/?")
+;; These are characters that are not to be considered as parts of a word in
+;; Viper.
+;; Set each time state changes and at loading time
+(viper-deflocalvar viper-non-word-characters  nil)
 
+;; must be buffer-local
 (viper-deflocalvar viper-ALPHA-char-class "w"
   "String of syntax classes characterizing Viper's alphanumeric symbols.
 In addition, the symbol `_' may be considered alphanumeric if
-`viper-syntax-preference'is `reformed-vi'.")
+`viper-syntax-preference' is `strict-vi' or `reformed-vi'.")
 
-(viper-deflocalvar viper-strict-ALPHA-chars "a-zA-Z0-9_"
+(defconst viper-strict-ALPHA-chars "a-zA-Z0-9_"
+  "Regexp matching the set of alphanumeric characters acceptable to strict
+Vi.")
+(defconst viper-strict-SEP-chars " \t\n"
   "Regexp matching the set of alphanumeric characters acceptable to strict
 Vi.")
-(viper-deflocalvar viper-strict-SEP-chars " \t\n"
+(defconst viper-strict-SEP-chars-sans-newline " \t"
   "Regexp matching the set of alphanumeric characters acceptable to strict
 Vi.")
 
-(viper-deflocalvar viper-SEP-char-class " -"
+(defconst viper-SEP-char-class " -"
   "String of syntax classes for Vi separators.
 Usually contains ` ', linefeed, TAB or formfeed.")
 
-(defun viper-update-alphanumeric-class ()
-  "Set the syntax class of Viper alphanumerals according to `viper-syntax-preference'.
-Must be called in order for changes to `viper-syntax-preference' to take effect."
+
+;; Set Viper syntax classes and related variables according to
+;; `viper-syntax-preference'.  
+(defun viper-update-syntax-classes (&optional set-default)
+  (let ((preference (cond ((eq viper-syntax-preference 'emacs)
+                          "w")   ; Viper words have only Emacs word chars
+                         ((eq viper-syntax-preference 'extended)
+                          "w_")  ; Viper words have Emacs word & symbol chars
+                         (t "w"))) ; Viper words are Emacs words plus `_'
+       (non-word-chars (cond ((eq viper-syntax-preference 'reformed-vi)
+                              (viper-string-to-list
+                               viper-non-word-characters-reformed-vi))
+                             (t nil))))
+    (if set-default
+       (setq-default viper-ALPHA-char-class preference
+                     viper-non-word-characters non-word-chars)
+      (setq viper-ALPHA-char-class preference
+           viper-non-word-characters non-word-chars))
+    ))
+
+;; SYMBOL is used because customize requires it, but it is ignored, unless it
+;; is `nil'. If nil, use setq.
+(defun viper-set-syntax-preference (&optional symbol value)
+  "Set Viper syntax preference.
+If called interactively or if SYMBOL is nil, sets syntax preference in current
+buffer. If called non-interactively, preferably via the customization widget,
+sets the default value."
   (interactive)
-  (setq-default
-   viper-ALPHA-char-class
-   (cond ((eq viper-syntax-preference 'emacs) "w")     ; only word constituents
-        ((eq viper-syntax-preference 'extended) "w_") ; word & symbol chars
-        (t "w"))))     ; vi syntax: word constituents and the symbol `_'
+  (or value
+      (setq value
+           (completing-read
+            "Viper syntax preference: "
+            '(("strict-vi") ("reformed-vi") ("extended") ("emacs"))
+            nil 'require-match)))
+  (if (stringp value) (setq value (intern value)))
+  (or (memq value '(strict-vi reformed-vi extended emacs))
+      (error "Invalid Viper syntax preference, %S" value))
+  (if symbol
+      (setq-default viper-syntax-preference value)
+    (setq viper-syntax-preference value))
+  (viper-update-syntax-classes))
+
+(defcustom viper-syntax-preference 'reformed-vi
+  "*Syntax type characterizing Viper's alphanumeric symbols.
+Affects movement and change commands that deal with Vi-style words.
+Works best when set in the hooks to various major modes.
+
+`strict-vi' means Viper words are (hopefully) exactly as in Vi.
+
+`reformed-vi' means Viper words are like Emacs words \(as determined using
+Emacs syntax tables, which are different for different major modes\) with two
+exceptions: the symbol `_' is always part of a word and typical Vi non-word
+symbols, such as `,',:,\",),{, etc., are excluded.
+This behaves very close to `strict-vi', but also works well with non-ASCII
+characters from various alphabets.
+
+`extended' means Viper word constituents are symbols that are marked as being
+parts of words OR symbols in Emacs syntax tables.
+This is most appropriate for major modes intended for editing programs.
+
+`emacs' means Viper words are the same as Emacs words as specified by Emacs
+syntax tables.
+This option is appropriate if you like Emacs-style words."
+  :type '(radio (const strict-vi) (const reformed-vi) 
+                (const extended) (const emacs))
+  :set 'viper-set-syntax-preference
+  :group 'viper)
+(make-variable-buffer-local 'viper-syntax-preference)
+
 
 ;; addl-chars are characters to be temporarily considered as alphanumerical
 (defun viper-looking-at-alpha (&optional addl-chars)
@@ -1107,19 +1182,26 @@ Must be called in order for changes to `viper-syntax-preference' to take effect.
     (if char
        (if (eq viper-syntax-preference 'strict-vi)
            (looking-at (concat "[" viper-strict-ALPHA-chars addl-chars "]"))
-         (or (memq char
-                   ;; convert string to list
-                   (append (vconcat addl-chars) nil))
-             (memq (char-syntax char)
-                   (append (vconcat viper-ALPHA-char-class) nil)))))
+         (or
+          ;; or one of the additional chars being asked to include
+          (memq char (viper-string-to-list addl-chars))
+          (and
+           ;; not one of the excluded word chars
+           (not (memq char viper-non-word-characters))
+           ;; char of the Viper-word syntax class
+           (memq (char-syntax char)
+                 (viper-string-to-list viper-ALPHA-char-class))))))
     ))
 
 (defun viper-looking-at-separator ()
   (let ((char (char-after (point))))
     (if char
-       (or (eq char ?\n) ; RET is always a separator in Vi
-           (memq (char-syntax char)
-                 (append (vconcat viper-SEP-char-class) nil))))))
+       (if (eq viper-syntax-preference 'strict-vi)
+           (memq char (viper-string-to-list viper-strict-SEP-chars))
+         (or (eq char ?\n) ; RET is always a separator in Vi
+             (memq (char-syntax char)
+                   (viper-string-to-list viper-SEP-char-class)))))
+    ))
 
 (defsubst viper-looking-at-alphasep (&optional addl-chars)
   (or (viper-looking-at-separator) (viper-looking-at-alpha addl-chars)))
@@ -1148,51 +1230,102 @@ Must be called in order for changes to `viper-syntax-preference' to take effect.
 
 ;; weird syntax tables may confuse strict-vi style
 (defsubst viper-skip-all-separators-forward (&optional within-line)
-  (viper-skip-syntax 'forward
-                    viper-SEP-char-class
-                    (or within-line "\n")
-                    (if within-line (viper-line-pos 'end))))
+  (if (eq viper-syntax-preference 'strict-vi)
+      (if within-line 
+         (skip-chars-forward viper-strict-SEP-chars-sans-newline)
+       (skip-chars-forward viper-strict-SEP-chars))
+    (viper-skip-syntax 'forward
+                      viper-SEP-char-class
+                      (or within-line "\n")
+                      (if within-line (viper-line-pos 'end)))))
 (defsubst viper-skip-all-separators-backward (&optional within-line)
-  (viper-skip-syntax 'backward
-                    viper-SEP-char-class
-                    (or within-line "\n")
-                    (if within-line (viper-line-pos 'start))))
+  (if (eq viper-syntax-preference 'strict-vi)
+      (if within-line 
+         (skip-chars-backward viper-strict-SEP-chars-sans-newline)
+       (skip-chars-backward viper-strict-SEP-chars))
+    (viper-skip-syntax 'backward
+                      viper-SEP-char-class
+                      (or within-line "\n")
+                      (if within-line (viper-line-pos 'start)))))
 (defun viper-skip-nonseparators (direction)
-  (let ((func (intern (format "skip-syntax-%S" direction))))
-    (funcall func (concat "^" viper-SEP-char-class)
-            (viper-line-pos (if (eq direction 'forward) 'end 'start)))))
+  (viper-skip-syntax
+   direction
+   (concat "^" viper-SEP-char-class)
+   nil
+   (viper-line-pos (if (eq direction 'forward) 'end 'start))))
+
 
+;; skip over non-word constituents and non-separators
 (defun viper-skip-nonalphasep-forward ()
   (if (eq viper-syntax-preference 'strict-vi)
       (skip-chars-forward
        (concat "^" viper-strict-SEP-chars viper-strict-ALPHA-chars))
-    (skip-syntax-forward
-     (concat
-      "^" viper-ALPHA-char-class viper-SEP-char-class) (viper-line-pos 'end))))
+    (viper-skip-syntax
+     'forward
+     (concat "^" viper-ALPHA-char-class viper-SEP-char-class)
+     ;; Emacs may consider some of these as words, but we don't want them
+     viper-non-word-characters 
+     (viper-line-pos 'end))))
 (defun viper-skip-nonalphasep-backward ()
   (if (eq viper-syntax-preference 'strict-vi)
       (skip-chars-backward
        (concat "^" viper-strict-SEP-chars viper-strict-ALPHA-chars))
-    (skip-syntax-backward
-     (concat
-      "^"
-      viper-ALPHA-char-class viper-SEP-char-class)
+    (viper-skip-syntax
+     'backward
+     (concat "^" viper-ALPHA-char-class viper-SEP-char-class)
+     ;; Emacs may consider some of these as words, but we don't want them
+     viper-non-word-characters
      (viper-line-pos 'start))))
 
 ;; Skip SYNTAX like skip-syntax-* and ADDL-CHARS like skip-chars-*
 ;; Return the number of chars traveled.
-;; Either SYNTAX or ADDL-CHARS can be nil, in which case they are interpreted
-;; as an empty string.
+;; Both SYNTAX or ADDL-CHARS can be strings or lists of characters.
+;; When SYNTAX is "w", then viper-non-word-characters are not considered to be
+;; words, even if Emacs syntax table says they are.
 (defun viper-skip-syntax (direction syntax addl-chars &optional limit)
   (let ((total 0)
        (local 1)
-       (skip-chars-func (intern (format "skip-chars-%S" direction)))
-       (skip-syntax-func (intern (format "skip-syntax-%S" direction))))
-    (or (stringp addl-chars) (setq addl-chars ""))
-    (or (stringp syntax) (setq syntax ""))
+       (skip-chars-func
+        (if (eq direction 'forward)
+            'skip-chars-forward 'skip-chars-backward))
+       (skip-syntax-func
+        (if (eq direction 'forward)
+            'viper-forward-char-carefully 'viper-backward-char-carefully))
+       char-looked-at syntax-of-char-looked-at negated-syntax)
+    (setq addl-chars
+         (cond ((listp addl-chars) (viper-charlist-to-string addl-chars))
+               ((stringp addl-chars) addl-chars)
+               (t "")))
+    (setq syntax
+         (cond ((listp syntax) syntax)
+               ((stringp syntax) (viper-string-to-list syntax))
+               (t nil)))
+    (if (memq ?^ syntax) (setq negated-syntax t))
+
     (while (and (not (= local 0)) (not (eobp)))
+      (setq char-looked-at (viper-char-at-pos direction)
+           ;; if outside the range, set to nil
+           syntax-of-char-looked-at (if char-looked-at
+                                        (char-syntax char-looked-at)))
       (setq local
-           (+ (funcall skip-syntax-func syntax limit)
+           (+ (if (and
+                   (cond ((and limit (eq direction 'forward))
+                          (< (point) limit))
+                         (limit ; backward & limit
+                          (> (point) limit))
+                         (t t)) ; no limit
+                   ;; char under/before cursor has appropriate syntax
+                   (if negated-syntax
+                       (not (memq syntax-of-char-looked-at syntax))
+                     (memq syntax-of-char-looked-at syntax))
+                   ;; if char-syntax class is "word", make sure it is not one
+                   ;; of the excluded characters
+                   (if (and (eq syntax-of-char-looked-at ?w)
+                            (not negated-syntax))
+                       (not (memq char-looked-at viper-non-word-characters))
+                     t))
+                  (funcall skip-syntax-func 1)
+                0)
               (funcall skip-chars-func addl-chars limit)))
       (setq total (+ total local)))
     total
index 269c54d18a4549ba56b516d0684ca923b510baad..f87f47a81f15770eb88961ce34d0fe84b37cdf16 100644 (file)
@@ -8,7 +8,7 @@
 
 ;; Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
 
-(defconst viper-version "2.96 of August 7, 1997"
+(defconst viper-version "3.00 (Polyglot) of August 18, 1997"
   "The current version of Viper")
 
 ;; This file is part of GNU Emacs.
 
 ;; compiler pacifier
 (defvar mark-even-if-inactive)
+(defvar quail-mode)
 (defvar viper-expert-level)
 (defvar viper-expert-level)
 
@@ -469,7 +470,7 @@ This startup message appears whenever you load Viper, unless you type `y' now."
 ;; This hook designed to enable Vi-style editing in comint-based modes."
 (defun viper-comint-mode-hook ()
   (setq require-final-newline nil
-       viper-ex-style-editing-in-insert nil
+       viper-ex-style-editing nil
        viper-ex-style-motion nil)
   (viper-change-state-to-insert))
 
@@ -828,6 +829,62 @@ remains buffer-local."
   (defadvice rmail-cease-edit (after viper-rmail-advice activate)
     "Switch to emacs state when done editing message."
     (viper-change-state-to-emacs))
+
+  ;; ISO accents
+  ;; Need to do it after loading iso-acc, or else this loading will wipe out
+  ;; the advice.
+  (eval-after-load
+   "iso-acc"
+   (defadvice iso-accents-mode (around viper-iso-accents-advice activate)
+     "Set viper-automatic-iso-accents to iso-accents-mode."
+     (let ((arg (ad-get-arg 0)))
+       ad-do-it
+       (setq viper-automatic-iso-accents 
+            (if (eq viper-current-state 'vi-state)
+                (if arg
+                    ;; if iso-accents-mode was called with positive arg, turn
+                    ;; accents on
+                    (> (prefix-numeric-value arg) 0)
+                  ;; else: toggle viper-automatic-iso-accents
+                  (not viper-automatic-iso-accents))
+              ;; other states: accept what iso-accents-mode has done
+              iso-accents-mode))
+       ;; turn off ISO accents in vi-state
+       (if (eq viper-current-state 'vi-state)
+          (viper-set-iso-accents-mode nil))
+       (if (memq viper-current-state '(vi-state insert-state replace-state))
+          (message "Viper ISO accents mode: %s"
+                   (if viper-automatic-iso-accents "on" "off")))
+       )))
+
+  ;; International input methods
+  (if viper-emacs-p
+      (eval-after-load "mule-cmds"
+       (progn
+         (defadvice inactivate-input-method (after viper-mule-advice activate)
+           "Set viper-special-input-method to disable intl. input methods."
+           (viper-inactivate-input-method-action))
+         (defadvice activate-input-method (after viper-mule-advice activate)
+           "Set viper-special-input-method to enable intl. input methods."
+           (viper-activate-input-method-action))
+         ))
+    ;; XEmacs Although these hooks exist in Emacs, they don't seem to be always
+    ;; called on input-method activation/deactivation, so we the above advise
+    ;; functions instead.
+    (eval-after-load "mule-cmds"
+      (progn
+       (add-hook 'input-method-activate-hook
+                 'viper-activate-input-method-action t)
+       (add-hook 'input-method-inactivate-hook
+                 'viper-inactivate-input-method-action t)))
+    )
+  (eval-after-load "mule-cmds"
+    (defadvice toggle-input-method (around viper-mule-advice activate)
+      "Adjust input-method toggling in vi-state."
+      (if (and viper-special-input-method (eq viper-current-state 'vi-state))
+         (viper-inactivate-input-method)
+       ad-do-it)))
+  
   ) ; viper-set-hooks
 
 
@@ -1089,8 +1146,8 @@ These two lines must come in the order given.
                (cons 'viper-always (list viper-always))
                (cons 'viper-no-multiple-ESC (list viper-no-multiple-ESC))
                (cons 'viper-ex-style-motion (list viper-ex-style-motion))
-               (cons 'viper-ex-style-editing-in-insert
-                     (list viper-ex-style-editing-in-insert))
+               (cons 'viper-ex-style-editing
+                     (list viper-ex-style-editing))
                (cons 'viper-want-emacs-keys-in-vi 
                      (list viper-want-emacs-keys-in-vi))
                (cons 'viper-electric-mode (list viper-electric-mode))
@@ -1104,7 +1161,7 @@ These two lines must come in the order given.
       (viper-set-minibuffer-style)
       (if viper-buffer-search-char
          (viper-buffer-search-enable))
-      (viper-update-alphanumeric-class)
+      (viper-update-syntax-classes 'set-default)
       ))
    
 \f