]> code.delx.au - gnu-emacs/blobdiff - lisp/emulation/viper-cmd.el
Update maintainer's email address.
[gnu-emacs] / lisp / emulation / viper-cmd.el
index eb5e5ede4c7f530a48e8b88534afc1ffc0328956..ac3ef55d6e45af78285b83208c5e7808ef2a1977 100644 (file)
@@ -1,6 +1,7 @@
 ;;; viper-cmd.el --- Vi command support for Viper
 
-;; Copyright (C) 1997, 98, 99, 2000, 01, 02 Free Software Foundation, Inc.
+;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+;;   2005, 2006 Free Software Foundation, Inc.
 
 ;; Author: Michael Kifer <kifer@cs.stonybrook.edu>
 
@@ -18,8 +19,8 @@
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Commentary:
 
@@ -36,6 +37,8 @@
 (defvar viper-always)
 (defvar viper-mode-string)
 (defvar viper-custom-file-name)
+(defvar viper--key-maps)
+(defvar viper--intercept-key-maps)
 (defvar iso-accents-mode)
 (defvar quail-mode)
 (defvar quail-current-str)
@@ -43,6 +46,8 @@
 (defvar mark-even-if-inactive)
 (defvar init-message)
 (defvar initial)
+(defvar undo-beg-posn)
+(defvar undo-end-posn)
 
 ;; loading happens only in non-interactive compilation
 ;; in order to spare non-viperized emacs from being viperized
@@ -92,7 +97,7 @@
 ;; Variables for defining VI commands
 
 ;; Modifying commands that can be prefixes to movement commands
-(defconst viper-prefix-commands '(?c ?d ?y ?! ?= ?# ?< ?> ?\"))
+(defvar viper-prefix-commands '(?c ?d ?y ?! ?= ?# ?< ?> ?\"))
 ;; define viper-prefix-command-p
 (viper-test-com-defun viper-prefix-command)
 
            (viper-save-cursor-color 'before-insert-mode))
        ;; set insert mode cursor color
        (viper-change-cursor-color viper-insert-state-cursor-color)))
+  (if (and viper-emacs-state-cursor-color (eq viper-current-state 'emacs-state))
+      (let ((has-saved-cursor-color-in-emacs-mode
+            (stringp (viper-get-saved-cursor-color-in-emacs-mode))))
+       (or has-saved-cursor-color-in-emacs-mode
+           (string= (viper-get-cursor-color) viper-emacs-state-cursor-color)
+           ;; save current color, if not already saved
+           (viper-save-cursor-color 'before-emacs-mode))
+       ;; set emacs mode cursor color
+       (viper-change-cursor-color viper-emacs-state-cursor-color)))
 
   (if (and (memq this-command '(dabbrev-expand hippie-expand))
           (integerp viper-pre-command-point)
                                          'viper-insertion-ring))
 
                (if viper-ESC-moves-cursor-back
-                   (or (bolp) (backward-char 1))))
+                   (or (bolp) (viper-beginning-of-field) (backward-char 1))))
               ))
 
        ;; insert or replace
   )
 
 
-
 (defun viper-adjust-keys-for (state)
   "Make necessary adjustments to keymaps before entering STATE."
   (cond ((memq state '(insert-state replace-state))
 ;; This ensures that Viper bindings are in effect, regardless of which minor
 ;; modes were turned on by the user or by other packages.
 (defun viper-normalize-minor-mode-map-alist ()
-  (setq minor-mode-map-alist
-       (viper-append-filter-alist
-        (list (cons 'viper-vi-intercept-minor-mode viper-vi-intercept-map)
-              (cons 'viper-vi-minibuffer-minor-mode viper-minibuffer-map)
-              (cons 'viper-vi-local-user-minor-mode viper-vi-local-user-map)
-              (cons 'viper-vi-kbd-minor-mode viper-vi-kbd-map)
-              (cons 'viper-vi-global-user-minor-mode viper-vi-global-user-map)
-              (cons 'viper-vi-state-modifier-minor-mode
-                    (if (keymapp
-                         (cdr (assoc major-mode
-                                     viper-vi-state-modifier-alist)))
-                        (cdr (assoc major-mode viper-vi-state-modifier-alist))
-                      viper-empty-keymap))
-              (cons 'viper-vi-diehard-minor-mode  viper-vi-diehard-map)
-              (cons 'viper-vi-basic-minor-mode     viper-vi-basic-map)
-              (cons 'viper-insert-intercept-minor-mode
-                    viper-insert-intercept-map)
+  (setq viper--intercept-key-maps
+       (list
+        (cons 'viper-vi-intercept-minor-mode viper-vi-intercept-map)
+        (cons 'viper-insert-intercept-minor-mode viper-insert-intercept-map)
+        (cons 'viper-emacs-intercept-minor-mode viper-emacs-intercept-map)
+        ))
+  (setq viper--key-maps
+       (list (cons 'viper-vi-minibuffer-minor-mode viper-minibuffer-map)
+             (cons 'viper-vi-local-user-minor-mode viper-vi-local-user-map)
+             (cons 'viper-vi-kbd-minor-mode viper-vi-kbd-map)
+             (cons 'viper-vi-global-user-minor-mode viper-vi-global-user-map)
+             (cons 'viper-vi-state-modifier-minor-mode
+                   (if (keymapp
+                        (cdr (assoc major-mode viper-vi-state-modifier-alist)))
+                       (cdr (assoc major-mode viper-vi-state-modifier-alist))
+                     viper-empty-keymap))
+             (cons 'viper-vi-diehard-minor-mode  viper-vi-diehard-map)
+             (cons 'viper-vi-basic-minor-mode     viper-vi-basic-map)
               (cons 'viper-replace-minor-mode  viper-replace-map)
               ;; viper-insert-minibuffer-minor-mode must come after
               ;; viper-replace-minor-mode
                       viper-empty-keymap))
               (cons 'viper-insert-diehard-minor-mode viper-insert-diehard-map)
               (cons 'viper-insert-basic-minor-mode viper-insert-basic-map)
-              (cons 'viper-emacs-intercept-minor-mode
-                    viper-emacs-intercept-map)
               (cons 'viper-emacs-local-user-minor-mode
                     viper-emacs-local-user-map)
               (cons 'viper-emacs-kbd-minor-mode viper-emacs-kbd-map)
                         (cdr
                          (assoc major-mode viper-emacs-state-modifier-alist))
                       viper-empty-keymap))
-              )
-        minor-mode-map-alist)))
+              ))
+       
+  ;; This var is not local in Emacs, so we make it local.  It must be local
+  ;; because although the stack of minor modes can be the same for all buffers,
+  ;; the associated *keymaps* can be different.  In Viper,
+  ;; viper-vi-local-user-map, viper-insert-local-user-map, and others can have
+  ;; different keymaps for different buffers.  Also, the keymaps associated
+  ;; with viper-vi/insert-state-modifier-minor-mode can be different.
+  ;; ***This is needed only in case emulation-mode-map-alists is not defined.
+  ;; In emacs with emulation-mode-map-alists, nothing needs to be done
+  (unless
+      (and (fboundp 'add-to-ordered-list) (boundp 'emulation-mode-map-alists))
+    (set (make-local-variable 'minor-mode-map-alist)
+         (viper-append-filter-alist
+          (append viper--intercept-key-maps viper--key-maps)
+          minor-mode-map-alist)))
+  )
 
 
 \f
 
 ;; Modifies mode-line-buffer-identification.
 (defun viper-refresh-mode-line ()
-  (setq viper-mode-string
+  (set (make-local-variable 'viper-mode-string)
        (cond ((eq viper-current-state 'emacs-state) viper-emacs-state-id)
              ((eq viper-current-state 'vi-state) viper-vi-state-id)
              ((eq viper-current-state 'replace-state) viper-replace-state-id)
        (indent-to-left-margin))
     (viper-add-newline-at-eob-if-necessary)
     (viper-adjust-undo)
-    (viper-change-state 'vi-state)
 
-    (viper-restore-cursor-color 'after-insert-mode)
+    (if (eq viper-current-state 'emacs-state)
+       (viper-restore-cursor-color 'after-emacs-mode)
+      (viper-restore-cursor-color 'after-insert-mode))
+
+    (viper-change-state 'vi-state)
 
     ;; Protect against user errors in hooks
     (condition-case conds
   (or (viper-overlay-p viper-replace-overlay)
       (viper-set-replace-overlay (point-min) (point-min)))
   (viper-hide-replace-overlay)
+
+  (if viper-emacs-state-cursor-color
+      (let ((has-saved-cursor-color-in-emacs-mode
+            (stringp (viper-get-saved-cursor-color-in-emacs-mode))))
+       (or has-saved-cursor-color-in-emacs-mode
+           (string= (viper-get-cursor-color) viper-emacs-state-cursor-color)
+           (viper-save-cursor-color 'before-emacs-mode))
+       (viper-change-cursor-color viper-emacs-state-cursor-color)))
+
   (viper-change-state 'emacs-state)
 
-  ;; Protect agains user errors in hooks
+  ;; Protect against user errors in hooks
   (condition-case conds
       (run-hooks 'viper-emacs-state-hook)
     (error
@@ -765,7 +804,8 @@ Vi's prefix argument will be used.  Otherwise, the prefix argument passed to
           )
 
          (if (commandp com)
-             (progn
+             ;; pretend that current state is the state we excaped to
+             (let ((viper-current-state state))
                (setq prefix-arg (or prefix-arg arg))
                (command-execute com)))
          )
@@ -802,12 +842,12 @@ Vi's prefix argument will be used.  Otherwise, the prefix argument passed to
                 ;; The next cmd  and viper-set-unread-command-events
                 ;; are intended to prevent the input method
                 ;; from swallowing ^M, ^Q and other special characters
-                (setq ch (read-char))
+                (setq ch (read-char-exclusive))
                 ;; replace ^M with the newline
                 (if (eq ch ?\C-m) (setq ch ?\n))
                 ;; Make sure ^V and ^Q work as quotation chars
                 (if (memq ch '(?\C-v ?\C-q))
-                    (setq ch (read-char)))
+                    (setq ch (read-char-exclusive)))
                 (viper-set-unread-command-events ch)
                 (quail-input-method nil)
 
@@ -824,12 +864,12 @@ Vi's prefix argument will be used.  Otherwise, the prefix argument passed to
               ;; same as above but for XEmacs, which doesn't have
               ;; quail-input-method
               (let (unread-command-events)
-                (setq ch (read-char))
+                (setq ch (read-char-exclusive))
                 ;; replace ^M with the newline
                 (if (eq ch ?\C-m) (setq ch ?\n))
                 ;; Make sure ^V and ^Q work as quotation chars
                 (if (memq ch '(?\C-v ?\C-q))
-                    (setq ch (read-char)))
+                    (setq ch (read-char-exclusive)))
                 (viper-set-unread-command-events ch)
                 (quail-start-translation nil)
 
@@ -849,12 +889,20 @@ Vi's prefix argument will be used.  Otherwise, the prefix argument passed to
                   (setq ch (aref (read-key-sequence nil) 0)))
               (insert ch))
              (t
-              (setq ch (read-char))
+              ;;(setq ch (read-char-exclusive))
+              (setq ch (aref (read-key-sequence nil) 0))
+              (if viper-xemacs-p
+                  (setq ch (event-to-character ch)))
               ;; replace ^M with the newline
               (if (eq ch ?\C-m) (setq ch ?\n))
               ;; Make sure ^V and ^Q work as quotation chars
               (if (memq ch '(?\C-v ?\C-q))
-                  (setq ch (read-char)))
+                  (progn
+                    ;;(setq ch (read-char-exclusive))
+                    (setq ch (aref (read-key-sequence nil) 0))
+                    (if viper-xemacs-p
+                        (setq ch (event-to-character ch))))
+                )
               (insert ch))
              )
        (setq last-command-event
@@ -931,8 +979,10 @@ Suffixes such as .el or .elc should be stripped."
 
   ;; Change the default for minor-mode-map-alist each time a harnessed minor
   ;; mode adds its own keymap to the a-list.
-  (eval-after-load
-   load-file '(setq-default minor-mode-map-alist minor-mode-map-alist))
+  (unless
+      (and (fboundp 'add-to-ordered-list) (boundp 'emulation-mode-map-alists))
+    (eval-after-load
+       load-file '(setq-default minor-mode-map-alist minor-mode-map-alist)))
   )
 
 
@@ -987,9 +1037,15 @@ as a Meta key and any number of multiple escapes is allowed."
        (inhibit-quit t))
     (if (viper-ESC-event-p event)
        (progn
-         (if (viper-fast-keysequence-p)
+         ;; Some versions of Emacs (eg., 22.50.8 have a bug, which makes even
+         ;; a single ESC into ;; a fast keyseq. To guard against this, we
+         ;; added a check if there are other events as well. Keep the next
+         ;; line for the next time the bug reappears, so that will remember to
+         ;; report it.
+         ;;(if (and (viper-fast-keysequence-p) unread-command-events)
+         (if (viper-fast-keysequence-p) ;; for Emacsen without the above bug
              (progn
-               (let (minor-mode-map-alist)
+               (let (minor-mode-map-alist emulation-mode-map-alists)
                  (viper-set-unread-command-events event)
                  (setq keyseq (read-key-sequence nil 'continue-echo))
                  ) ; let
@@ -1021,7 +1077,7 @@ as a Meta key and any number of multiple escapes is allowed."
                              (not viper-translate-all-ESC-keysequences))
                         ;; put keys following ESC on the unread list
                         ;; and return ESC as the key-sequence
-                        (viper-set-unread-command-events (subseq keyseq 1))
+                        (viper-set-unread-command-events (viper-subseq keyseq 1))
                         (setq last-input-event event
                               keyseq (if viper-emacs-p
                                          "\e"
@@ -1032,7 +1088,7 @@ as a Meta key and any number of multiple escapes is allowed."
                         (viper-set-unread-command-events
                          (vconcat (vector
                                    (character-to-event (event-key first-key)))
-                                  (subseq keyseq 1)))
+                                  (viper-subseq keyseq 1)))
                         (setq last-input-event event
                               keyseq (vector (character-to-event ?\e))))
                        ((eventp first-key)
@@ -1063,7 +1119,7 @@ as a Meta key and any number of multiple escapes is allowed."
 
     ;; call the actual function to execute ESC (if no other symbols followed)
     ;; or the key bound to the ESC sequence (if the sequence was issued
-    ;; with very short delay between characters.
+    ;; with very short delay between characters).
     (if (eq cmd 'viper-intercept-ESC-key)
        (setq cmd
              (cond ((eq viper-current-state 'vi-state)
@@ -1206,65 +1262,69 @@ as a Meta key and any number of multiple escapes is allowed."
               (setq com char)
               (setq char (read-char))))))
 
-  (if (atom com)
-      ;; `com' is a single char, so we construct the command argument
-      ;; and if `char' is `?', we describe the arg; otherwise
-      ;; we prepare the command that will be executed at the end.
-      (progn
-       (setq cmd-info (cons value com))
-       (while (viper= char ?U)
-         (viper-describe-arg cmd-info)
-         (setq char (read-char)))
-       ;; `char' is a movement cmd, a digit arg cmd, or a register cmd---so we
-       ;; execute it at the very end
-       (or (viper-movement-command-p char)
-           (viper-digit-command-p char)
-           (viper-regsuffix-command-p char)
-           (viper= char ?!) ; bang command
-           (error ""))
-       (setq cmd-to-exec-at-end
-             (viper-exec-form-in-vi
-              `(key-binding (char-to-string ,char)))))
-
-    ;; as com is non-nil, this means that we have a command to execute
-    (if (viper-memq-char (car com) '(?r ?R))
-       ;; execute apropriate region command.
-       (let ((char (car com)) (com (cdr com)))
-         (setq prefix-arg (cons value com))
-         (if (viper= char ?r)
-             (viper-region prefix-arg)
-           (viper-Region prefix-arg))
-         ;; reset prefix-arg
-         (setq prefix-arg nil))
-      ;; otherwise, reset prefix arg and call appropriate command
-      (setq value (if (null value) 1 value))
-      (setq prefix-arg nil)
-      (cond
-       ;; If we change ?C to ?c here, then cc will enter replacement mode
-       ;; rather than deleting lines.  However, it will affect 1 less line than
-       ;; normal.  We decided to not use replacement mode here and follow Vi,
-       ;; since replacement mode on n full lines can be achieved with nC.
-       ((equal com '(?c . ?c)) (viper-line (cons value ?C)))
-       ((equal com '(?d . ?d)) (viper-line (cons value ?D)))
-       ((equal com '(?d . ?y)) (viper-yank-defun))
-       ((equal com '(?y . ?y)) (viper-line (cons value ?Y)))
-       ((equal com '(?< . ?<)) (viper-line (cons value ?<)))
-       ((equal com '(?> . ?>)) (viper-line (cons value ?>)))
-       ((equal com '(?! . ?!)) (viper-line (cons value ?!)))
-       ((equal com '(?= . ?=)) (viper-line (cons value ?=)))
-       (t (error "")))))
-
-  (if cmd-to-exec-at-end
-      (progn
-       (setq last-command-char char)
-       (setq last-command-event
-             (viper-copy-event
-              (if viper-xemacs-p (character-to-event char) char)))
-       (condition-case nil
-           (funcall cmd-to-exec-at-end cmd-info)
-         (error
-          (error "")))))
-  ))
+    (if (atom com)
+       ;; `com' is a single char, so we construct the command argument
+       ;; and if `char' is `?', we describe the arg; otherwise
+       ;; we prepare the command that will be executed at the end.
+       (progn
+         (setq cmd-info (cons value com))
+         (while (viper= char ?U)
+           (viper-describe-arg cmd-info)
+           (setq char (read-char)))
+         ;; `char' is a movement cmd, a digit arg cmd, or a register cmd---so
+         ;; we execute it at the very end
+         (or (viper-movement-command-p char)
+             (viper-digit-command-p char)
+             (viper-regsuffix-command-p char)
+             (viper= char ?!) ; bang command
+             (viper= char ?g) ; the gg command (like G0)
+             (error ""))
+         (setq cmd-to-exec-at-end
+               (viper-exec-form-in-vi
+                `(key-binding (char-to-string ,char)))))
+
+      ;; as com is non-nil, this means that we have a command to execute
+      (if (viper-memq-char (car com) '(?r ?R))
+         ;; execute apropriate region command.
+         (let ((char (car com)) (com (cdr com)))
+           (setq prefix-arg (cons value com))
+           (if (viper= char ?r)
+               (viper-region prefix-arg)
+             (viper-Region prefix-arg))
+           ;; reset prefix-arg
+           (setq prefix-arg nil))
+       ;; otherwise, reset prefix arg and call appropriate command
+       (setq value (if (null value) 1 value))
+       (setq prefix-arg nil)
+       (cond
+        ;; If we change ?C to ?c here, then cc will enter replacement mode
+        ;; rather than deleting lines.  However, it will affect 1 less line
+        ;; than normal.  We decided to not use replacement mode here and
+        ;; follow Vi, since replacement mode on n full lines can be achieved
+        ;; with nC.
+        ((equal com '(?c . ?c)) (viper-line (cons value ?C)))
+        ((equal com '(?d . ?d)) (viper-line (cons value ?D)))
+        ((equal com '(?d . ?y)) (viper-yank-defun))
+        ((equal com '(?y . ?y)) (viper-line (cons value ?Y)))
+        ((equal com '(?< . ?<)) (viper-line (cons value ?<)))
+        ((equal com '(?> . ?>)) (viper-line (cons value ?>)))
+        ((equal com '(?! . ?!)) (viper-line (cons value ?!)))
+        ((equal com '(?= . ?=)) (viper-line (cons value ?=)))
+        ;; gg  acts as G0
+        ((equal (car com) ?g)   (viper-goto-line 0))
+        (t (error "")))))
+    
+    (if cmd-to-exec-at-end
+       (progn
+         (setq last-command-char char)
+         (setq last-command-event
+               (viper-copy-event
+                (if viper-xemacs-p (character-to-event char) char)))
+         (condition-case nil
+             (funcall cmd-to-exec-at-end cmd-info)
+           (error
+            (error "")))))
+    ))
 
 (defun viper-describe-arg (arg)
   (let (val com)
@@ -1407,7 +1467,8 @@ as a Meta key and any number of multiple escapes is allowed."
          (if (eq last-command 'd-command) 'kill-region nil))
     (setq chars-deleted (abs (- (point) viper-com-point)))
     (if (> chars-deleted viper-change-notification-threshold)
-       (message "Deleted %d characters" chars-deleted))
+       (unless (viper-is-in-minibuffer)
+         (message "Deleted %d characters" chars-deleted)))
     (kill-region viper-com-point (point))
     (setq this-command 'd-command)
     (if viper-ex-style-motion
@@ -1433,7 +1494,8 @@ as a Meta key and any number of multiple escapes is allowed."
            (if (eq last-command 'D-command) 'kill-region nil))
       (setq lines-deleted (count-lines (point) viper-com-point))
       (if (> lines-deleted viper-change-notification-threshold)
-         (message "Deleted %d lines" lines-deleted))
+         (unless (viper-is-in-minibuffer)
+           (message "Deleted %d lines" lines-deleted)))
       (kill-region (mark t) (point))
       (if (eq m-com 'viper-line) (setq this-command 'D-command)))
     (back-to-indentation)))
@@ -1458,7 +1520,8 @@ as a Meta key and any number of multiple escapes is allowed."
     (copy-region-as-kill viper-com-point (point))
     (setq chars-saved (abs (- (point) viper-com-point)))
     (if (> chars-saved viper-change-notification-threshold)
-       (message "Saved %d characters" chars-saved))
+       (unless (viper-is-in-minibuffer)
+         (message "Saved %d characters" chars-saved)))
     (goto-char viper-com-point)))
 
 ;; save lines
@@ -1482,7 +1545,8 @@ as a Meta key and any number of multiple escapes is allowed."
       (copy-region-as-kill (mark t) (point))
       (setq lines-saved (count-lines (mark t) (point)))
       (if (> lines-saved viper-change-notification-threshold)
-         (message "Saved %d lines" lines-saved))))
+         (unless (viper-is-in-minibuffer)
+           (message "Saved %d lines" lines-saved)))))
   (viper-deactivate-mark)
   (goto-char viper-com-point))
 
@@ -1529,7 +1593,8 @@ as a Meta key and any number of multiple escapes is allowed."
   nil)
 
 (defun viper-exec-buffer-search (m-com com)
-  (setq viper-s-string (buffer-substring (point) viper-com-point))
+  (setq viper-s-string
+       (regexp-quote (buffer-substring (point) viper-com-point)))
   (setq viper-s-forward t)
   (setq viper-search-history (cons viper-s-string viper-search-history))
   (setq viper-intermediate-command 'viper-exec-buffer-search)
@@ -1671,6 +1736,7 @@ invokes the command before that, etc."
                        (max viper-com-point (point))))
        ((viper= char ?g)
         (push-mark viper-com-point t)
+        ;; execute the last emacs kbd macro on each line of the region
         (viper-global-execute))
        ((viper= char ?q)
         (push-mark viper-com-point t)
@@ -1682,42 +1748,63 @@ invokes the command before that, etc."
 \f
 ;; undoing
 
+;; hook used inside undo
+(defvar viper-undo-functions nil)
+
+;; Runs viper-before-change-functions inside before-change-functions
+(defun viper-undo-sentinel (beg end length)
+  (run-hook-with-args 'viper-undo-functions beg end length))
+
+(add-hook 'after-change-functions 'viper-undo-sentinel)
+
+;; Hook used in viper-undo
+(defun viper-after-change-undo-hook (beg end len)
+  (if (and (boundp 'undo-in-progress) undo-in-progress)
+      (setq undo-beg-posn beg
+           undo-end-posn (or end beg))
+    ;; some other hooks may be changing various text properties in
+    ;; the buffer in response to 'undo'; so remove this hook to avoid
+    ;; its repeated invocation
+    (remove-hook 'viper-undo-functions 'viper-after-change-undo-hook 'local)
+  ))
+
 (defun viper-undo ()
   "Undo previous change."
   (interactive)
   (message "undo!")
   (let ((modified (buffer-modified-p))
         (before-undo-pt (point-marker))
-       (after-change-functions after-change-functions)
        undo-beg-posn undo-end-posn)
 
-    ;; no need to remove this hook, since this var has scope inside a let.
-    (add-hook 'after-change-functions
-             '(lambda (beg end len)
-                (setq undo-beg-posn beg
-                      undo-end-posn (or end beg))))
+    ;; the viper-after-change-undo-hook removes itself after the 1st invocation
+    (add-hook 'viper-undo-functions 'viper-after-change-undo-hook nil 'local)
 
     (undo-start)
     (undo-more 2)
-    (setq undo-beg-posn (or undo-beg-posn before-undo-pt)
-         undo-end-posn (or undo-end-posn undo-beg-posn))
+    ;;(setq undo-beg-posn (or undo-beg-posn (point))
+    ;;    undo-end-posn (or undo-end-posn (point)))
+    ;;(setq undo-beg-posn (or undo-beg-posn before-undo-pt)
+    ;;      undo-end-posn (or undo-end-posn undo-beg-posn))
 
-    (goto-char undo-beg-posn)
-    (sit-for 0)
-    (if (and viper-keep-point-on-undo
-            (pos-visible-in-window-p before-undo-pt))
+    (if (and undo-beg-posn undo-end-posn)
        (progn
-         (push-mark (point-marker) t)
-         (viper-sit-for-short 300)
-         (goto-char undo-end-posn)
-         (viper-sit-for-short 300)
-         (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))
+         (goto-char undo-beg-posn)
+         (sit-for 0)
+         (if (and viper-keep-point-on-undo
+                  (pos-visible-in-window-p before-undo-pt))
+             (progn
+               (push-mark (point-marker) t)
+               (viper-sit-for-short 300)
+               (goto-char undo-end-posn)
+               (viper-sit-for-short 300)
+               (if (pos-visible-in-window-p undo-beg-posn)
+                   (goto-char before-undo-pt)
+                 (goto-char undo-beg-posn)))
+           (push-mark before-undo-pt t))
+         ))
+
     (if (and (eolp) (not (bolp))) (backward-char 1))
-    (if (not modified) (set-buffer-modified-p t)))
+    )
   (setq this-command 'viper-undo))
 
 ;; Continue undoing previous changes.
@@ -1765,7 +1852,7 @@ invokes the command before that, etc."
            (setq viper-undo-needs-adjustment t)))))
 
 
-
+;;; Viper's destructive Command ring utilities
 
 (defun viper-display-current-destructive-command ()
   (let ((text (nth 4 viper-d-com))
@@ -1879,12 +1966,15 @@ Undo previous insertion and inserts new."
       (end-of-line)
       ;; make sure all lines end with newline, unless in the minibuffer or
       ;; when requested otherwise (require-final-newline is nil)
-      (if (and (eobp)
-              (not (bolp))
-              require-final-newline
-              (not (viper-is-in-minibuffer))
-              (not buffer-read-only))
-         (insert "\n"))))
+      (save-restriction
+       (widen)
+       (if (and (eobp)
+                (not (bolp))
+                require-final-newline
+                (not (viper-is-in-minibuffer))
+                (not buffer-read-only))
+           (insert "\n")))
+      ))
 
 (defun viper-yank-defun ()
   (mark-defun)
@@ -1975,13 +2065,24 @@ Undo previous insertion and inserts new."
 ;;; Minibuffer business
 
 (defsubst viper-set-minibuffer-style ()
-  (add-hook 'minibuffer-setup-hook 'viper-minibuffer-setup-sentinel))
+  (add-hook 'minibuffer-setup-hook 'viper-minibuffer-setup-sentinel)
+  (add-hook 'post-command-hook 'viper-minibuffer-post-command-hook))
 
 
 (defun viper-minibuffer-setup-sentinel ()
   (let ((hook (if viper-vi-style-in-minibuffer
                  'viper-change-state-to-insert
                'viper-change-state-to-emacs)))
+    ;; making buffer-local variables so that normal buffers won't affect the
+    ;; minibuffer and vice versa. Otherwise, command arguments will affect
+    ;; minibuffer ops and insertions from the minibuffer will change those in
+    ;; the normal buffers
+    (make-local-variable 'viper-d-com)
+    (make-local-variable 'viper-last-insertion)
+    (make-local-variable 'viper-command-ring)
+    (setq viper-d-com nil
+         viper-last-insertion nil
+         viper-command-ring nil)
     (funcall hook)
     ))
 
@@ -2008,6 +2109,11 @@ Undo previous insertion and inserts new."
       (minibuffer-prompt-end)
     (point-min)))
 
+(defun viper-minibuffer-post-command-hook()
+  (when (active-minibuffer-window)
+    (when (< (point) (viper-minibuffer-real-start))
+      (goto-char (viper-minibuffer-real-start)))))
+
 
 ;; Interpret last event in the local map first; if fails, use exit-minibuffer.
 ;; Run viper-minibuffer-exit-hook before exiting.
@@ -2087,7 +2193,7 @@ To turn this feature off, set this variable to nil."
 Remove this function from `viper-minibuffer-exit-hook', if this causes
 problems."
   (if (viper-is-in-minibuffer)
-      (progn
+      (let ((inhibit-field-text-motion t))
        (goto-char (viper-minibuffer-real-start))
        (end-of-line)
        (delete-region (point) (point-max)))))
@@ -2123,7 +2229,7 @@ problems."
     (setq keymap (or keymap minibuffer-local-map)
          initial (or initial "")
          temp-msg (if default
-                      (format "(default: %s) " default)
+                      (format "(default %s) " default)
                     ""))
 
     (setq viper-incomplete-ex-cmd nil)
@@ -2539,7 +2645,7 @@ These keys are ESC, RET, and LineFeed"
     ;; last line of buffer when this line has no \n.
     (viper-add-newline-at-eob-if-necessary)
     (viper-execute-com 'viper-line val com))
-  (if (and (eobp) (not (bobp))) (forward-line -1))
+  (if (and (eobp) (bolp) (not (bobp))) (forward-line -1))
   )
 
 (defun viper-yank-line (arg)
@@ -2707,7 +2813,7 @@ On reaching beginning of line, stop and signal error."
     (viper-backward-char-carefully)
     (if (looking-at "\n")
        (viper-skip-all-separators-backward 'within-line)
-      (or (bobp) (forward-char)))))
+      (or (viper-looking-at-separator) (forward-char)))))
 
 
 (defun viper-forward-word-kernel (val)
@@ -2981,19 +3087,34 @@ On reaching beginning of line, stop and signal error."
     (setq this-command 'next-line)
     (if com (viper-execute-com 'viper-next-line val com))))
 
+
 (defun viper-next-line-at-bol (arg)
-  "Next line at beginning of line."
+  "Next line at beginning of line.
+If point is on a widget or a button, simulate clicking on that widget/button."
   (interactive "P")
-  (viper-leave-region-active)
-  (save-excursion
-    (end-of-line)
-    (if (eobp) (error "Last line in buffer")))
-  (let ((val (viper-p-val arg))
-       (com (viper-getCom arg)))
-    (if com (viper-move-marker-locally 'viper-com-point (point)))
-    (forward-line val)
-    (back-to-indentation)
-    (if com (viper-execute-com 'viper-next-line-at-bol val com))))
+  (let* ((field (get-char-property (point) 'field))
+        (button (get-char-property (point) 'button))
+        (doc (get-char-property (point) 'widget-doc))
+        (widget (or field button doc)))
+    (if (and widget
+             (if (symbolp widget)
+                 (get widget 'widget-type)
+               (and (consp widget)
+                    (get (widget-type widget) 'widget-type))))
+        (widget-button-press (point))
+      (if (and (fboundp 'button-at) (fboundp 'push-button) (button-at (point)))
+          (push-button)
+       ;; not a widget or a button
+        (viper-leave-region-active)
+        (save-excursion
+          (end-of-line)
+          (if (eobp) (error "Last line in buffer")))
+        (let ((val (viper-p-val arg))
+              (com (viper-getCom arg)))
+          (if com (viper-move-marker-locally 'viper-com-point (point)))
+          (forward-line val)
+          (back-to-indentation)
+          (if com (viper-execute-com 'viper-next-line-at-bol val com)))))))
 
 
 (defun viper-previous-line (arg)
@@ -3120,7 +3241,7 @@ On reaching beginning of line, stop and signal error."
 (defun viper-find-char-forward (arg)
   "Find char on the line.
 If called interactively read the char to find from the terminal, and if
-called from viper-repeat, the char last used is used.  This behaviour is
+called from viper-repeat, the char last used is used.  This behavior is
 controlled by the sign of prefix numeric value."
   (interactive "P")
   (let ((val (viper-p-val arg))
@@ -3630,31 +3751,37 @@ the Emacs binding of `/'."
           (setq msg "Search style remains unchanged")))
     (princ msg t)))
 
-(defun viper-set-searchstyle-toggling-macros (unset)
+(defun viper-set-searchstyle-toggling-macros (unset &optional major-mode)
   "Set the macros for toggling the search style in Viper's vi-state.
 The macro that toggles case sensitivity is bound to `//', and the one that
 toggles regexp search is bound to `///'.
-With a prefix argument, this function unsets the macros. "
+With a prefix argument, this function unsets the macros.
+If MAJOR-MODE is set, set the macros only in that major mode."
   (interactive "P")
-  (or noninteractive
-      (if (not unset)
-         (progn
-           ;; toggle case sensitivity in search
-           (viper-record-kbd-macro
-            "//" 'vi-state
-            [1 (meta x) v i p e r - t o g g l e - s e a r c h - s t y l e return]
-            't)
-           ;; toggle regexp/vanila search
-           (viper-record-kbd-macro
-            "///" 'vi-state
-            [2 (meta x) v i p e r - t o g g l e - s e a r c h - s t y l e return]
-            't)
-           (if (interactive-p)
-               (message
-                "// and /// now toggle case-sensitivity and regexp search")))
-       (viper-unrecord-kbd-macro "//" 'vi-state)
-       (sit-for 2)
-       (viper-unrecord-kbd-macro "///" 'vi-state))))
+  (let (scope)
+    (if (and major-mode (symbolp major-mode))
+       (setq scope major-mode)
+      (setq scope 't))
+    (or noninteractive
+       (if (not unset)
+           (progn
+             ;; toggle case sensitivity in search
+             (viper-record-kbd-macro
+              "//" 'vi-state
+              [1 (meta x) v i p e r - t o g g l e - s e a r c h - s t y l e return]
+              scope)
+             ;; toggle regexp/vanila search
+             (viper-record-kbd-macro
+              "///" 'vi-state
+              [2 (meta x) v i p e r - t o g g l e - s e a r c h - s t y l e return]
+              scope)
+             (if (interactive-p)
+                 (message
+                  "// and /// now toggle case-sensitivity and regexp search")))
+         (viper-unrecord-kbd-macro "//" 'vi-state)
+         (sit-for 2)
+         (viper-unrecord-kbd-macro "///" 'vi-state)))
+    ))
 
 
 (defun viper-set-parsing-style-toggling-macro (unset)
@@ -3715,7 +3842,8 @@ Null string will repeat previous search."
   (interactive "P")
   (let ((val (viper-P-val arg))
        (com (viper-getcom arg))
-       (old-str viper-s-string))
+       (old-str viper-s-string)
+       debug-on-error)
     (setq viper-s-forward t)
     (viper-if-string "/")
     ;; this is not used at present, but may be used later
@@ -3727,7 +3855,8 @@ Null string will repeat previous search."
     (if com
        (progn
          (viper-move-marker-locally 'viper-com-point (mark t))
-         (viper-execute-com 'viper-search-next val com)))))
+         (viper-execute-com 'viper-search-next val com)))
+    ))
 
 (defun viper-search-backward (arg)
   "Search a string backward.
@@ -3736,7 +3865,8 @@ Null string will repeat previous search."
   (interactive "P")
   (let ((val (viper-P-val arg))
        (com (viper-getcom arg))
-       (old-str viper-s-string))
+       (old-str viper-s-string)
+       debug-on-error)
     (setq viper-s-forward nil)
     (viper-if-string "?")
     ;; this is not used at present, but may be used later
@@ -3841,8 +3971,10 @@ Null string will repeat previous search."
   "Repeat previous search."
   (interactive "P")
   (let ((val (viper-p-val arg))
-       (com (viper-getcom arg)))
-    (if (null viper-s-string) (error viper-NoPrevSearch))
+       (com (viper-getcom arg))
+       debug-on-error)
+    (if (or (null viper-s-string) (string= viper-s-string ""))
+       (error viper-NoPrevSearch))
     (viper-search viper-s-string viper-s-forward arg)
     (if com
        (progn
@@ -3853,7 +3985,8 @@ Null string will repeat previous search."
   "Repeat previous search in the reverse direction."
   (interactive "P")
   (let ((val (viper-p-val arg))
-       (com (viper-getcom arg)))
+       (com (viper-getcom arg))
+       debug-on-error)
     (if (null viper-s-string) (error viper-NoPrevSearch))
     (viper-search viper-s-string (not viper-s-forward) arg)
     (if com
@@ -3867,6 +4000,7 @@ Null string will repeat previous search."
 (defun viper-buffer-search-enable (&optional c)
   (cond (c (setq viper-buffer-search-char c))
        ((null viper-buffer-search-char)
+        ;; ?g acts as a default value for viper-buffer-search-char
         (setq viper-buffer-search-char ?g)))
   (define-key viper-vi-basic-map
     (cond ((viper-characterp viper-buffer-search-char)
@@ -3984,8 +4118,9 @@ Null string will repeat previous search."
          lines-inserted (abs (count-lines (point) sv-point)))
     (if (or (> chars-inserted viper-change-notification-threshold)
            (> lines-inserted viper-change-notification-threshold))
-       (message "Inserted %d character(s), %d line(s)"
-                chars-inserted lines-inserted)))
+       (unless (viper-is-in-minibuffer)
+         (message "Inserted %d character(s), %d line(s)"
+                  chars-inserted lines-inserted))))
   ;; Vi puts cursor on the last char when the yanked text doesn't contain a
   ;; newline; it leaves the cursor at the beginning when the text contains
   ;; a newline
@@ -4026,8 +4161,9 @@ Null string will repeat previous search."
          lines-inserted (abs (count-lines (point) sv-point)))
     (if (or (> chars-inserted viper-change-notification-threshold)
            (> lines-inserted viper-change-notification-threshold))
-       (message "Inserted %d character(s), %d line(s)"
-                chars-inserted lines-inserted)))
+       (unless (viper-is-in-minibuffer)
+         (message "Inserted %d character(s), %d line(s)"
+                  chars-inserted lines-inserted))))
   ;; Vi puts cursor on the last char when the yanked text doesn't contain a
   ;; newline; it leaves the cursor at the beginning when the text contains
   ;; a newline
@@ -4112,7 +4248,8 @@ Null string will repeat previous search."
   (interactive)
   (if (and viper-ex-style-editing (bolp))
       (beep 1)
-    (delete-backward-char 1 t)))
+    ;; don't put on kill ring
+    (delete-backward-char 1 nil)))
 
 
 (defun viper-del-backward-char-in-replace ()
@@ -4124,13 +4261,15 @@ cursor move past the beginning of line."
   (interactive)
   (cond (viper-delete-backwards-in-replace
         (cond ((not (bolp))
-               (delete-backward-char 1 t))
+               ;; don't put on kill ring
+               (delete-backward-char 1 nil))
               (viper-ex-style-editing
                (beep 1))
               ((bobp)
                (beep 1))
               (t
-               (delete-backward-char 1 t))))
+               ;; don't put on kill ring
+               (delete-backward-char 1 nil))))
        (viper-ex-style-editing
         (if (bolp)
             (beep 1)
@@ -4728,7 +4867,7 @@ sensitive for VI-style look-and-feel."
              level-changed t)
        (insert "
 Please specify your level of familiarity with the venomous VI PERil
-(and the VI Plan for Emacs Rescue).
+\(and the VI Plan for Emacs Rescue).
 You can change it at any time by typing `M-x viper-set-expert-level RET'
 
  1 -- BEGINNER: Almost all Emacs features are suppressed.
@@ -4947,5 +5086,5 @@ Mail anyway (y or n)? ")
 
 
 
-;;; arch-tag: 739a6450-5fda-44d0-88b0-325053d888c2
+;; arch-tag: 739a6450-5fda-44d0-88b0-325053d888c2
 ;;; viper-cmd.el ends here