Commits

Anonymous committed 90e2df2

Created

Comments (0)

Files changed (14)

+1998-01-12  SL Baur  <steve@altair.xemacs.org>
+
+	* Makefile: Update to newer package interface.
+
+1998-01-03  SL Baur  <steve@altair.xemacs.org>
+
+	* Makefile: Update to newer package interface.
+
+1997-12-21  SL Baur  <steve@altair.xemacs.org>
+
+	* Makefile: Created.
+
+# Makefile for VIper lisp code
+
+# This file is part of XEmacs.
+
+# XEmacs is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any
+# later version.
+
+# XEmacs is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with XEmacs; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+VERSION = 1.02
+PACKAGE = viper
+PKG_TYPE = regular
+REQUIRES = xemacs-base
+CATEGORY = wp
+
+ELCS = viper-cmd.elc viper-ex.elc viper-init.elc viper-keym.elc \
+	viper-macs.elc viper-mous.elc viper-util.elc viper.elc
+
+INFO_FILES = viper.info*
+
+DATA_FILES = viperCard.tex
+
+include ../../XEmacs.rules
+
+all:: $(ELCS) auto-autoloads.elc custom-load.elc viper.info
+
+srckit: srckit-std
+
+binkit: binkit-sourcedatainfo
+#
+#	Makefile for compiling and installing Viper
+#
+
+# -------- USER MAY NEED TO CHANGE THESE ---------------------
+# To compile under XEmacs, uncomment XEmacs-specific versions of the
+# variables VERSION, EMACS, DATADIR and comment out the Emacs-specific
+# versions.
+
+VERSION = 20.0
+EMACS = emacs-$(VERSION)
+#VERSION = 20.3
+#EMACS = xemacs-$(VERSION)
+PREFIX = /usr/local
+DATADIR = $(PREFIX)/share
+#DATADIR = $(PREFIX)/lib
+LISPDIR = $(DATADIR)/emacs/site-lisp
+INFODIR = $(PREFIX)/info
+ETCDIR = $(DATADIR)/emacs/$(VERSION)/etc
+COMPDIR =
+
+# --------- YOU PROBABLY DON'T WANT TO CHANGE THESE ----------------
+TeX = tex
+TEXINDEX = texindex
+MAKEINFO = makeinfo
+INSTALL = install
+
+# --------- ONLY AUTHORIZED PERSONNEL BEYOND THIS POINT!!! ------------
+VIPER = viper.el viper-cmd.el viper-util.el viper-mous.el viper-ex.el \
+        viper-macs.el viper-keym.el viper-init.el
+VIPERelc = $(COMPDIR)viper-util.elc \
+	   $(COMPDIR)viper-mous.elc \
+	   $(COMPDIR)viper-ex.elc \
+	   $(COMPDIR)viper-macs.elc \
+	   $(COMPDIR)viper-keym.elc \
+	   $(COMPDIR)viper.elc \
+	   $(COMPDIR)viper-cmd.elc \
+	   $(COMPDIR)viper-init.elc
+
+COMPILE_ARGS = -batch -f batch-byte-compile
+
+all: dvi info hello elc goodbye
+
+elc: $(VIPERelc)
+
+goodbye:
+	@echo ""
+	@echo ""
+	@echo ""
+	@echo "    The above compiler warnings were normal -- don't panic!"
+	@echo ""
+	@echo "    Please report bugs via the command  :submitReport"
+	@echo ""
+	@echo ""
+	@echo ""
+
+hello:
+	@echo ""
+	@echo ""
+	@echo "Byte compiling using Emacs"
+	@echo "Use  make EMACS=xemacs  to compile under XEmacs"
+	@echo ""
+	@echo ""
+	@echo "    The following compiler warnings are normal -- don't panic!"
+	@echo ""
+	@echo ""
+	@echo ""
+
+viper.dvi: viper.texi
+	@echo ""
+	@echo ""
+	@echo "Making viper.dvi --- a Printable Version of the Viper Manual";
+	@echo ""
+	$(TeX) viper.texi
+	@echo ""
+	@echo "Indexing "
+	$(TEXINDEX) viper.cp
+	$(TEXINDEX) viper.fn
+	$(TEXINDEX) viper.ky
+	$(TEXINDEX) viper.pg
+#	$(TEXINDEX) viper.tp
+	$(TEXINDEX) viper.vr
+	@echo ""
+	@echo "Texing Again";
+	$(TeX) viper.texi
+
+viper: viper.texi 
+	@echo ""
+	@echo ""
+	@echo "Making Info Files for the Viper Manual"
+	@echo ""
+	$(MAKEINFO) viper.texi
+
+viperCard.dvi: viperCard.tex
+	@echo ""
+	@echo ""
+	@echo "Making the Viper Reference Card"
+	@echo ""
+	$(TeX) viperCard.tex
+
+${COMPDIR}viper-init.elc: viper-init.el
+	@echo ""
+	$(EMACS) $(COMPILE_ARGS) viper-init.el
+
+$(COMPDIR)viper-util.elc: viper-util.el viper-init.el
+	@echo ""
+	$(EMACS) $(COMPILE_ARGS) viper-util.el
+
+$(COMPDIR)viper-ex.elc: viper-ex.el viper-util.el viper-init.el
+	@echo ""
+	$(EMACS) $(COMPILE_ARGS) viper-ex.el
+
+$(COMPDIR)viper-mous.elc: viper-mous.el viper-util.el viper-init.el
+	@echo ""
+	$(EMACS) $(COMPILE_ARGS) viper-mous.el
+
+$(COMPDIR)viper-macs.elc: viper-macs.el viper-util.el viper-init.el
+	@echo ""
+	$(EMACS) $(COMPILE_ARGS) viper-macs.el
+
+$(COMPDIR)viper-keym.elc: viper-keym.el viper-util.el viper-init.el
+	@echo ""
+	$(EMACS) $(COMPILE_ARGS) viper-keym.el
+
+$(COMPDIR)viper.elc: viper.el viper-util.el viper-init.el
+	@echo ""
+	$(EMACS) $(COMPILE_ARGS) viper.el
+
+$(COMPDIR)viper-cmd.elc: viper-cmd.el viper.el viper-util.el viper-init.el
+	@echo ""
+	$(EMACS) $(COMPILE_ARGS) viper-cmd.el
+
+
+dvi: viper.dvi viperCard.dvi
+
+info: viper
+
+install: all
+	$(INSTALL) -m444 $(VIPER) $(LISPDIR)
+	$(INSTALL) -m644 viper*.elc $(LISPDIR)
+	$(INSTALL) -m444 viper viper-? $(INFODIR)
+	$(INSTALL) -m644 viper.dvi viperCard.dvi $(ETCDIR)
+	@echo ""
+	@echo "Please move viper.texi to emacs-distribution-directory/man/"
+	@echo ""
+
+clean:
+	rm -f *.elc *~ core
+
+distclean: clean
+ 
+realclean: clean
+	rm -f *.dvi ../info/viper ../info/viper-?
+	rm -f viper.aux viper.cp viper.cps viper.fn viper.fns viper.ky \
+	      viper.kys viper.log viper.pg viper.pgs viper.toc viper.tp \
+	      viper.tps viper.vr viper.vrs
+**** Viper requires Emacs 19.23 or later.
+
+This directory:
+
+README	    	-- This file
+Makefile	-- Automated installation file
+
+viper.el    	-- Viper Emacs Lisp code
+viper-cmd.el   	-- Viper Emacs Lisp code
+viper-macs.el	-- Viper Emacs Lisp code
+viper-ex.el	-- Viper Emacs Lisp code
+viper-init.el	-- Viper Emacs Lisp code
+viper-util.el	-- Viper Emacs Lisp code
+viper-mous.el	-- Viper Emacs Lisp code
+viper-keym.el	-- Viper Emacs Lisp code
+
+viper.texi  	-- Manual in Texinfo format
+
+viperCard.tex   -- Reference card in TeX format
+
+viper, viper-?	-- The Info files
+
+viper.dvi	-- Dvi version of the Viper manual
+viperCard.dvi	-- Dvi version of the quick reference card
+
+To install Viper, do:
+
+		uncompress viper.tar.Z
+		tar xf viper.tar
+
+
+Then do the following:
+
+1. To compile Lisp:
+		
+      	    	make elc
+   
+   Since the DVI and Info files are bundled with the distribution, this is
+   the only make command you need.
+   
+2. To recompile the DVI files (if you have to), type:
+		
+	       make dvi
+		
+3. To re-make the info files (if needed), type:
+
+	       make info
+	       
+4. To redo everything:
+
+	       make all
+	       
+   "make all" is useful if you made your own changes to the *.texi or
+   *.el files. This way, this single command will recompile exactly what's
+   needed.
+   
+5. You can also run
+
+	       make install
+	       
+   to do what "make all" does plus to copy viper*.elc into
+   a suitable Lisp directory and Viper Info files into the Info
+   directory; DVI files containing printable version of Viper
+   Manual and Reference Card will be copied into the 'etc' directory.
+   
+   You will still have to edit the 'dir' file manually (see below), if
+   you haven't done so during a previous installation.
+   
+   To make all this happen, you will most likely have to change the PREFIX
+   variable in Makefile and, possibly, one or more of these variables:
+   
+   	DATADIR, LISPDIR, INFODIR, ETCDIR, and VERSION
+	
+   if they don't point to the right directories in your installation.
+   You also need to have a write permission for all directories
+   mentioned in LISPDIR, INFODIR, and ETCDIR.
+   
+6. XEmacs users must invoke make with the parameter EMACS=xemacs
+   or whatever name is used to invoke XEmacs (some backward sites
+   still use xemacs for Emacs 18). An even better thing would be to
+   edit Makefile directly as indicated in the comments there.
+
+(viper
+  (version VERSION
+   description "VI emulation support."
+   filename FILENAME
+   md5sum MD5SUM
+   size SIZE
+   provides (viper)
+   requires (REQUIRES)
+   type regular
+))
+;;; viper-cmd.el --- Vi command support for Viper
+;; Copyright (C) 1997 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; 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.
+
+;; Code
+
+(provide 'viper-cmd)
+(require 'advice)
+
+;; Compiler pacifier
+(defvar viper-minibuffer-current-face)
+(defvar viper-minibuffer-insert-face)
+(defvar viper-minibuffer-vi-face)
+(defvar viper-minibuffer-emacs-face)
+(defvar viper-always)
+(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)
+
+;; loading happens only in non-interactive compilation
+;; in order to spare non-viperized emacs from being viperized
+(if noninteractive
+    (eval-when-compile
+      (let ((load-path (cons (expand-file-name ".") load-path)))
+	(or (featurep 'viper-util)
+	    (load "viper-util.el" nil nil 'nosuffix))
+	(or (featurep 'viper-keym)
+	    (load "viper-keym.el" nil nil 'nosuffix))
+	(or (featurep 'viper-mous)
+	    (load "viper-mous.el" nil nil 'nosuffix))
+	(or (featurep 'viper-macs)
+	    (load "viper-macs.el" nil nil 'nosuffix))
+	(or (featurep 'viper-ex)
+	    (load "viper-ex.el" nil nil 'nosuffix))
+	)))
+;; end pacifier
+
+
+(require 'viper-util)
+(require 'viper-keym)
+(require 'viper-mous)
+(require 'viper-macs)
+(require 'viper-ex)
+
+
+
+;; Generic predicates
+
+;; These test functions are shamelessly lifted from vip 4.4.2 by Aamod Sane
+
+;; generate test functions
+;; given symbol foo, foo-p is the test function, foos is the set of
+;; Viper command keys
+;; (macroexpand '(viper-test-com-defun foo))
+;; (defun foo-p (com) (consp (memq (if (< com 0) (- com) com) foos)))
+
+(defmacro viper-test-com-defun (name)
+  (let* ((snm (symbol-name name))
+	 (nm-p (intern (concat snm "-p")))
+	 (nms (intern (concat snm "s"))))
+    (` (defun (, nm-p) (com) 
+	 (consp (memq (if (and (viper-characterp com) (< com 0))
+			  (- com) com) (, nms)))))))
+  
+;; Variables for defining VI commands
+
+;; Modifying commands that can be prefixes to movement commands
+(defconst viper-prefix-commands '(?c ?d ?y ?! ?= ?# ?< ?> ?\"))
+;; define viper-prefix-command-p
+(viper-test-com-defun viper-prefix-command)
+  
+;; Commands that are pairs eg. dd. r and R here are a hack
+(defconst viper-charpair-commands '(?c ?d ?y ?! ?= ?< ?> ?r ?R))
+;; define viper-charpair-command-p
+(viper-test-com-defun viper-charpair-command)
+
+(defconst viper-movement-commands '(?b ?B ?e ?E ?f ?F ?G ?h ?H ?j ?k ?l
+				     ?H ?M ?L ?n ?t ?T ?w ?W ?$ ?%
+				     ?^ ?( ?) ?- ?+ ?| ?{ ?} ?[ ?] ?' ?`
+				     ?; ?, ?0 ?? ?/ ?\C-m ?\ 
+				     space return
+				     delete backspace
+				     )
+				     "Movement commands")
+;; define viper-movement-command-p
+(viper-test-com-defun viper-movement-command)
+
+;; Vi digit commands
+(defconst viper-digit-commands '(?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9))
+
+;; define viper-digit-command-p
+(viper-test-com-defun viper-digit-command)
+
+;; Commands that can be repeated by . (dotted)
+(defconst viper-dotable-commands '(?c ?d ?C ?s ?S ?D ?> ?<))
+;; define viper-dotable-command-p
+(viper-test-com-defun viper-dotable-command)
+
+;; Commands that can follow a #
+(defconst viper-hash-commands '(?c ?C ?g ?q ?s))
+;; define viper-hash-command-p
+(viper-test-com-defun viper-hash-command)
+
+;; Commands that may have registers as prefix
+(defconst viper-regsuffix-commands '(?d ?y ?Y ?D ?p ?P ?x ?X))
+;; define viper-regsuffix-command-p
+(viper-test-com-defun viper-regsuffix-command)
+
+(defconst viper-vi-commands (append viper-movement-commands
+				  viper-digit-commands
+				  viper-dotable-commands
+				  viper-charpair-commands
+				  viper-hash-commands
+				  viper-prefix-commands
+				  viper-regsuffix-commands)
+  "The list of all commands in Vi-state.")
+;; define viper-vi-command-p
+(viper-test-com-defun viper-vi-command)
+
+
+;;; CODE
+
+;; sentinels
+
+;; Runs viper-after-change-functions inside after-change-functions
+(defun viper-after-change-sentinel (beg end len)
+  (let ((list viper-after-change-functions))
+    (while list
+      (funcall (car list) beg end len)
+      (setq list (cdr list)))))
+      
+;; Runs viper-before-change-functions inside before-change-functions
+(defun viper-before-change-sentinel (beg end)
+  (let ((list viper-before-change-functions))
+    (while list
+      (funcall (car list) beg end)
+      (setq list (cdr list)))))
+
+(defsubst viper-post-command-sentinel ()
+  (run-hooks 'viper-post-command-hooks))
+  
+(defsubst viper-pre-command-sentinel ()
+  (run-hooks 'viper-pre-command-hooks))
+  
+;; Needed so that Viper will be able to figure the last inserted
+;; chunk of text with reasonable accuracy.
+(defsubst viper-insert-state-post-command-sentinel ()
+  (if (and (memq viper-current-state '(insert-state replace-state))
+	   viper-insert-point
+	   (>= (point) viper-insert-point))
+      (setq viper-last-posn-while-in-insert-state (point-marker)))
+  (if (eq viper-current-state 'insert-state)
+      (progn
+	(or (stringp viper-saved-cursor-color)
+	    (string= (viper-get-cursor-color) viper-insert-state-cursor-color)
+	    (setq viper-saved-cursor-color (viper-get-cursor-color)))
+	(if (stringp viper-saved-cursor-color)
+	    (viper-change-cursor-color viper-insert-state-cursor-color))
+	))
+  (if (and (eq this-command 'dabbrev-expand)
+	   (integerp viper-pre-command-point)
+	   (markerp viper-insert-point)
+	   (marker-position viper-insert-point)
+	   (> viper-insert-point viper-pre-command-point))
+      (viper-move-marker-locally viper-insert-point viper-pre-command-point))
+  )
+  
+(defsubst viper-insert-state-pre-command-sentinel ()
+  (or (memq this-command '(self-insert-command))
+      (memq (viper-event-key last-command-event)
+	    '(up down left right (meta f) (meta b)
+		 (control n) (control p) (control f) (control b)))
+      (viper-restore-cursor-color-after-insert))
+  (if (and (eq this-command 'dabbrev-expand)
+	   (markerp viper-insert-point)
+	   (marker-position viper-insert-point))
+      (setq viper-pre-command-point (marker-position viper-insert-point))))
+	
+(defsubst viper-R-state-post-command-sentinel ()
+  ;; Restoring cursor color is needed despite
+  ;; viper-replace-state-pre-command-sentinel: When you jump to another buffer
+  ;; in another frame, the pre-command hook won't change cursor color to
+  ;; default in that other frame.  So, if the second frame cursor was red and
+  ;; we set the point outside the replacement region, then the cursor color
+  ;; will remain red. Restoring the default, below, prevents this.
+  (if (and (<= (viper-replace-start) (point))
+	   (<=  (point) (viper-replace-end)))
+      (viper-change-cursor-color viper-replace-overlay-cursor-color)
+    (viper-restore-cursor-color-after-replace)
+    ))
+
+;; to speed up, don't change cursor color before self-insert
+;; and common move commands
+(defsubst viper-replace-state-pre-command-sentinel ()
+  (or (memq this-command '(self-insert-command))
+      (memq (viper-event-key last-command-event)
+	    '(up down left right (meta f) (meta b)
+		 (control n) (control p) (control f) (control b)))
+      (viper-restore-cursor-color-after-replace)))
+  
+(defun viper-replace-state-post-command-sentinel ()
+  ;; Restoring cursor color is needed despite
+  ;; viper-replace-state-pre-command-sentinel: When one jumps to another buffer
+  ;; in another frame, the pre-command hook won't change cursor color to
+  ;; default in that other frame.  So, if the second frame cursor was red and
+  ;; we set the point outside the replacement region, then the cursor color
+  ;; will remain red. Restoring the default, below, fixes this problem.
+  ;;
+  ;; We optimize for self-insert-command's here, since they either don't change
+  ;; cursor color or, if they terminate replace mode, the color will be changed
+  ;; in viper-finish-change
+  (or (memq this-command '(self-insert-command))
+      (viper-restore-cursor-color-after-replace))
+  (cond 
+   ((eq viper-current-state 'replace-state)
+    ;; delete characters to compensate for inserted chars.
+    (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)
+	;; terminate replace mode if reached replace limit
+	(if (= viper-last-posn-in-replace-region (viper-replace-end))
+	    (viper-finish-change)))
+      
+      (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))))
+      ))
+   ;; terminate replace mode if changed Viper states.
+   (t (viper-finish-change))))
+
+
+;; changing mode
+
+;; Change state to NEW-STATE---either emacs-state, vi-state, or insert-state.
+(defun viper-change-state (new-state)
+  ;; Keep viper-post/pre-command-hooks fresh.
+  ;; We remove then add viper-post/pre-command-sentinel since it is very
+  ;; desirable that viper-pre-command-sentinel is the last hook and
+  ;; viper-post-command-sentinel is the first hook.
+  (remove-hook 'post-command-hook 'viper-post-command-sentinel)
+  (add-hook 'post-command-hook 'viper-post-command-sentinel)
+  (remove-hook 'pre-command-hook 'viper-pre-command-sentinel)
+  (add-hook 'pre-command-hook 'viper-pre-command-sentinel t)
+  ;; These hooks will be added back if switching to insert/replace mode
+  (viper-remove-hook 'viper-post-command-hooks
+		     'viper-insert-state-post-command-sentinel)
+  (viper-remove-hook 'viper-pre-command-hooks
+		     'viper-insert-state-pre-command-sentinel)
+  (setq viper-intermediate-command nil)
+  (cond ((eq new-state 'vi-state)
+	 (cond ((member viper-current-state '(insert-state replace-state))
+		    
+		;; move viper-last-posn-while-in-insert-state
+		;; This is a normal hook that is executed in insert/replace
+		;; states after each command. In Vi/Emacs state, it does
+		;; nothing. We need to execute it here to make sure that
+		;; the last posn was recorded when we hit ESC.
+		;; It may be left unrecorded if the last thing done in
+		;; insert/repl state was dabbrev-expansion or abbrev
+		;; expansion caused by hitting ESC
+		(viper-insert-state-post-command-sentinel)
+		
+		(condition-case conds
+		    (progn
+		      (viper-save-last-insertion
+		       viper-insert-point 
+		       viper-last-posn-while-in-insert-state)
+		      (if viper-began-as-replace
+			  (setq viper-began-as-replace nil)
+			;; repeat insert commands if numerical arg > 1
+			(save-excursion
+			  (viper-repeat-insert-command))))
+		  (error
+		   (viper-message-conditions conds)))
+		     
+		(if (> (length viper-last-insertion) 0)
+		    (viper-push-onto-ring viper-last-insertion
+					  'viper-insertion-ring))
+		
+		(if viper-ex-style-editing
+		    (or (bolp) (backward-char 1))))
+	       ))
+	 
+	;; insert or replace
+	((memq new-state '(insert-state replace-state))
+	 (if (memq viper-current-state '(emacs-state vi-state))
+	     (viper-move-marker-locally 'viper-insert-point (point)))
+	 (viper-move-marker-locally
+	  'viper-last-posn-while-in-insert-state (point))
+	 (viper-add-hook 'viper-post-command-hooks
+			 'viper-insert-state-post-command-sentinel t)
+	 (viper-add-hook 'viper-pre-command-hooks
+			 'viper-insert-state-pre-command-sentinel t))
+	) ; outermost cond
+  
+  ;; 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)
+  (viper-refresh-mode-line)
+  )
+
+
+    
+(defun viper-adjust-keys-for (state)
+  "Make necessary adjustments to keymaps before entering STATE."
+  (cond ((memq state '(insert-state replace-state))
+	 (if viper-auto-indent
+	     (progn
+	       (define-key viper-insert-basic-map "\C-m" 'viper-autoindent)
+	       (if viper-want-emacs-keys-in-insert
+		   ;; expert
+		   (define-key viper-insert-basic-map "\C-j" nil)
+		 ;; novice
+		 (define-key viper-insert-basic-map "\C-j" 'viper-autoindent)))
+	   (define-key viper-insert-basic-map "\C-m" nil)
+	   (define-key viper-insert-basic-map "\C-j" nil))
+		    
+	 (setq viper-insert-diehard-minor-mode
+	       (not viper-want-emacs-keys-in-insert))
+		   
+	 (if viper-want-ctl-h-help
+	     (progn
+	       (define-key viper-insert-basic-map "\C-h" 'help-command)
+	       (define-key viper-replace-map "\C-h" 'help-command))
+	   (define-key viper-insert-basic-map 
+	     "\C-h" 'viper-del-backward-char-in-insert)
+	   (define-key viper-replace-map
+	     "\C-h" 'viper-del-backward-char-in-replace))
+	 ;; In XEmacs, C-h overrides backspace, so we make sure it doesn't.
+	 (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)
+	 ) ; end insert/replace case
+	(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 "\C-h" 'help-command)
+	   (define-key viper-vi-basic-map "\C-h" 'viper-backward-char))
+	 ;; In XEmacs, C-h overrides backspace, so we make sure it doesn't.
+	 (define-key viper-vi-basic-map [backspace] 'viper-backward-char))
+	))
+	     
+   
+;; Normalizes minor-mode-map-alist by putting Viper keymaps first.
+;; 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) 
+	       (cons 'viper-replace-minor-mode  viper-replace-map)
+	       ;; viper-insert-minibuffer-minor-mode must come after
+	       ;; viper-replace-minor-mode 
+	       (cons 'viper-insert-minibuffer-minor-mode
+		     viper-minibuffer-map) 
+	       (cons 'viper-insert-local-user-minor-mode
+		     viper-insert-local-user-map)
+	       (cons 'viper-insert-kbd-minor-mode viper-insert-kbd-map)
+	       (cons 'viper-insert-global-user-minor-mode
+		     viper-insert-global-user-map)
+	       (cons 'viper-insert-state-modifier-minor-mode
+		     (if (keymapp
+			  (cdr (assoc major-mode
+				      viper-insert-state-modifier-alist))) 
+			 (cdr (assoc major-mode
+				     viper-insert-state-modifier-alist))
+		       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)
+	       (cons 'viper-emacs-global-user-minor-mode
+		     viper-emacs-global-user-map)
+	       (cons 'viper-emacs-state-modifier-minor-mode
+		     (if (keymapp
+			  (cdr
+			   (assoc major-mode viper-emacs-state-modifier-alist)))
+			 (cdr
+			  (assoc major-mode viper-emacs-state-modifier-alist))
+		       viper-empty-keymap))
+	       )
+	 minor-mode-map-alist)))
+	 
+ 
+
+
+
+;; Viper mode-changing commands and utilities
+
+;; Modifies mode-line-buffer-identification.
+(defun viper-refresh-mode-line ()
+  (setq 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)
+	      ((eq viper-current-state 'insert-state) viper-insert-state-id)))
+    
+  ;; Sets Viper mode string in global-mode-string
+  (force-mode-line-update))
+	
+
+;; Switch from Insert state to Vi state.
+(defun viper-exit-insert-state ()
+  (interactive)
+  (viper-change-state-to-vi))
+
+(defun viper-set-mode-vars-for (state)
+  "Sets Viper minor mode variables to put Viper's state STATE in effect."
+  
+  ;; Emacs state
+  (setq viper-vi-minibuffer-minor-mode	     nil
+        viper-insert-minibuffer-minor-mode   nil
+	viper-vi-intercept-minor-mode	     nil
+	viper-insert-intercept-minor-mode    nil
+	
+	viper-vi-local-user-minor-mode       nil
+	viper-vi-kbd-minor-mode        	     nil
+	viper-vi-global-user-minor-mode      nil
+	viper-vi-state-modifier-minor-mode   nil
+	viper-vi-diehard-minor-mode          nil
+        viper-vi-basic-minor-mode            nil
+	
+	viper-replace-minor-mode 	       nil
+	
+	viper-insert-local-user-minor-mode     nil
+	viper-insert-kbd-minor-mode            nil
+	viper-insert-global-user-minor-mode    nil
+	viper-insert-state-modifier-minor-mode nil
+	viper-insert-diehard-minor-mode        nil
+	viper-insert-basic-minor-mode          nil
+	viper-emacs-intercept-minor-mode       t
+	viper-emacs-local-user-minor-mode      t
+	viper-emacs-kbd-minor-mode             (not (viper-is-in-minibuffer))
+	viper-emacs-global-user-minor-mode     t
+	viper-emacs-state-modifier-minor-mode  t
+	)
+  
+  ;; Vi state
+  (if (eq state 'vi-state) ; adjust for vi-state
+      (setq 
+       viper-vi-intercept-minor-mode	   t 
+       viper-vi-minibuffer-minor-mode	   (viper-is-in-minibuffer)
+       viper-vi-local-user-minor-mode	   t
+       viper-vi-kbd-minor-mode        	   (not (viper-is-in-minibuffer))
+       viper-vi-global-user-minor-mode	   t
+       viper-vi-state-modifier-minor-mode    t
+       ;; don't let the diehard keymap block command completion 
+       ;; and other things in the minibuffer
+       viper-vi-diehard-minor-mode    	   (not
+					    (or viper-want-emacs-keys-in-vi
+						(viper-is-in-minibuffer)))
+       viper-vi-basic-minor-mode      	      t 
+       viper-emacs-intercept-minor-mode       nil
+       viper-emacs-local-user-minor-mode      nil
+       viper-emacs-kbd-minor-mode     	      nil
+       viper-emacs-global-user-minor-mode     nil
+       viper-emacs-state-modifier-minor-mode  nil
+       ))
+  
+  ;; Insert and Replace states
+  (if (member state '(insert-state replace-state))
+      (setq 
+       viper-insert-intercept-minor-mode      t 
+       viper-replace-minor-mode	     	      (eq state 'replace-state)
+       viper-insert-minibuffer-minor-mode     (viper-is-in-minibuffer)
+       viper-insert-local-user-minor-mode     t
+       viper-insert-kbd-minor-mode     	      (not (viper-is-in-minibuffer))
+       viper-insert-global-user-minor-mode     t
+       viper-insert-state-modifier-minor-mode  t
+       ;; don't let the diehard keymap block command completion 
+       ;; and other things in the minibuffer
+       viper-insert-diehard-minor-mode 	      (not
+					       (or
+					        viper-want-emacs-keys-in-insert
+					        (viper-is-in-minibuffer)))
+       viper-insert-basic-minor-mode   	      t
+       viper-emacs-intercept-minor-mode       nil
+       viper-emacs-local-user-minor-mode      nil
+       viper-emacs-kbd-minor-mode     	      nil
+       viper-emacs-global-user-minor-mode     nil
+       viper-emacs-state-modifier-minor-mode  nil
+       ))
+       
+  ;; minibuffer faces
+  (if (viper-has-face-support-p)
+      (setq viper-minibuffer-current-face
+	    (cond ((eq state 'emacs-state) viper-minibuffer-emacs-face)
+		  ((eq state 'vi-state) viper-minibuffer-vi-face)
+		  ((memq state '(insert-state replace-state))
+		   viper-minibuffer-insert-face))))
+  
+  (if (viper-is-in-minibuffer)
+      (viper-set-minibuffer-overlay))
+  )
+
+;; This also takes care of the annoying incomplete lines in files.
+;; Also, this fixes `undo' to work vi-style for complex commands.
+(defun viper-change-state-to-vi ()
+  "Change Viper state to Vi."
+  (interactive)
+  (if (and viper-first-time (not (viper-is-in-minibuffer)))
+      (viper-mode)
+    (if overwrite-mode (overwrite-mode nil))
+    (if abbrev-mode (expand-abbrev))
+    (if (and auto-fill-function (> (current-column) fill-column))
+	(funcall auto-fill-function))
+    ;; don't leave whitespace lines around
+    (if (and (memq last-command
+		   '(viper-autoindent
+		     viper-open-line viper-Open-line
+		     viper-replace-state-exit-cmd))
+	     (viper-over-whitespace-line))
+	(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)
+    
+    ;; Protect against user errors in hooks
+    (condition-case conds
+	(run-hooks 'viper-vi-state-hook)
+      (error
+       (viper-message-conditions conds)))))
+
+(defun viper-change-state-to-insert ()
+  "Change Viper state to Insert."
+  (interactive)
+  (viper-change-state 'insert-state)
+  
+  (or (stringp viper-saved-cursor-color)
+      (string= (viper-get-cursor-color) viper-insert-state-cursor-color)
+      (setq viper-saved-cursor-color (viper-get-cursor-color)))
+  ;; Commented out, because if viper-change-state-to-insert is executed
+  ;; non-interactively then the old cursor color may get lost. Same old Emacs
+  ;; bug related to local variables?
+;;;(if (stringp viper-saved-cursor-color)
+;;;      (viper-change-cursor-color viper-insert-state-cursor-color))
+
+  ;; Protect against user errors in hooks
+  (condition-case conds
+      (run-hooks 'viper-insert-state-hook)
+    (error
+     (viper-message-conditions conds))))
+     
+(defsubst viper-downgrade-to-insert ()
+ (setq viper-current-state 'insert-state
+       viper-replace-minor-mode nil))
+
+    
+  
+;; Change to replace state. When the end of replacement region is reached,
+;; replace state changes to insert state.
+(defun viper-change-state-to-replace (&optional non-R-cmd)
+  (viper-change-state 'replace-state)
+  ;; Run insert-state-hook
+  (condition-case conds
+      (run-hooks 'viper-insert-state-hook 'viper-replace-state-hook)
+    (error
+     (viper-message-conditions conds)))
+  
+  (if non-R-cmd
+      (viper-start-replace)
+    ;; 'R' is implemented using Emacs's overwrite-mode
+    (viper-start-R-mode))
+  )
+
+    
+(defun viper-change-state-to-emacs ()
+  "Change Viper state to Emacs."
+  (interactive)
+  (viper-change-state 'emacs-state)
+  
+  ;; Protect agains user errors in hooks
+  (condition-case conds
+      (run-hooks 'viper-emacs-state-hook)
+    (error
+     (viper-message-conditions conds))))
+  
+;; escape to emacs mode termporarily
+(defun viper-escape-to-emacs (arg &optional events)
+  "Escape to Emacs state from Vi state for one Emacs command.
+ARG is used as the prefix value for the executed command.  If
+EVENTS is a list of events, which become the beginning of the command."
+  (interactive "P")
+  (if (= last-command-char ?\\)
+      (message "Switched to EMACS state for the next command..."))
+  (viper-escape-to-state arg events 'emacs-state))
+  
+;; escape to Vi mode termporarily
+(defun viper-escape-to-vi (arg)
+  "Escape from Emacs state to Vi state for one Vi 1-character command.
+If the Vi command that the user types has a prefix argument, e.g., `d2w', then
+Vi's prefix argument will be used. Otherwise, the prefix argument passed to
+`viper-escape-to-vi' is used."
+  (interactive "P")
+  (message "Switched to VI state for the next command...")
+  (viper-escape-to-state arg nil 'vi-state))
+  
+;; Escape to STATE mode for one Emacs command.
+(defun viper-escape-to-state (arg events state)
+  ;;(let (com key prefix-arg)
+  (let (com key)
+    ;; this temporarily turns off Viper's minor mode keymaps
+    (viper-set-mode-vars-for state)
+    (viper-normalize-minor-mode-map-alist)
+    (if events (viper-set-unread-command-events events))
+    
+    ;; protect against keyboard quit and other errors
+    (condition-case nil
+	(let (viper-vi-kbd-minor-mode 
+	      viper-insert-kbd-minor-mode
+	      viper-emacs-kbd-minor-mode)
+	  (unwind-protect
+	      (progn
+		(setq com (key-binding (setq key 
+					     (if viper-xemacs-p
+						 (read-key-sequence nil)
+					       (read-key-sequence nil t)))))
+		;; In case of binding indirection--chase definitions.
+		;; Have to do it here because we execute this command under
+		;; different keymaps, so command-execute may not do the
+		;; right thing there
+		(while (vectorp com) (setq com (key-binding com))))
+	    nil)
+	  ;; Execute command com in the original Viper state, not in state
+	  ;; `state'. Otherwise, if we switch buffers while executing the
+	  ;; escaped to command, Viper's mode vars will remain those of
+	  ;; `state'. When we return to the orig buffer, the bindings will be
+	  ;; screwed up.
+	  (viper-set-mode-vars-for viper-current-state)
+	  
+	  ;; this-command, last-command-char, last-command-event
+	  (setq this-command com)
+	  (if viper-xemacs-p ; XEmacs represents key sequences as vectors
+	      (setq last-command-event
+		    (viper-copy-event (viper-seq-last-elt key))
+		    last-command-char (event-to-character last-command-event))
+	    ;; Emacs represents them as sequences (str or vec)
+	    (setq last-command-event
+		  (viper-copy-event (viper-seq-last-elt key))
+		  last-command-char last-command-event))
+	    
+	  (if (commandp com)
+	      (progn
+		(setq prefix-arg (or prefix-arg arg))
+		(command-execute com)))
+	  )
+      (quit (ding))
+      (error (beep 1))))
+  ;; set state in the new buffer
+  (viper-set-mode-vars-for viper-current-state))
+      
+(defun viper-exec-form-in-vi  (form)
+  "Execute FORM in Vi state, regardless of the Ccurrent Vi state."
+  (let ((buff (current-buffer))
+	result)
+    (viper-set-mode-vars-for 'vi-state)
+
+    (condition-case nil
+	(let (viper-vi-kbd-minor-mode) ; execute without kbd macros
+	  (setq result (eval form))
+	  )
+      (error
+       (signal 'quit nil)))
+
+    (if (not (equal buff (current-buffer))) ; cmd switched buffer
+	(save-excursion
+	  (set-buffer buff)
+	  (viper-set-mode-vars-for viper-current-state)))
+    (viper-set-mode-vars-for viper-current-state)
+    result))
+
+(defun viper-exec-form-in-emacs  (form)
+  "Execute FORM in Emacs, temporarily disabling Viper's minor modes.
+Similar to viper-escape-to-emacs, but accepts forms rather than keystrokes."
+  (let ((buff (current-buffer))
+	result)
+    (viper-set-mode-vars-for 'emacs-state)
+    (setq result (eval form))
+    (if (not (equal buff (current-buffer))) ; cmd switched buffer
+	(save-excursion
+	  (set-buffer buff)
+	  (viper-set-mode-vars-for viper-current-state)))
+    (viper-set-mode-vars-for viper-current-state)
+    result))
+
+  
+;; This is needed because minor modes sometimes override essential Viper
+;; bindings. By letting Viper know which files these modes are in, it will
+;; arrange to reorganize minor-mode-map-alist so that things will work right.
+(defun viper-harness-minor-mode (load-file)
+  "Familiarize Viper with a minor mode defined in LOAD_FILE.
+Minor modes that have their own keymaps may overshadow Viper keymaps.
+This function is designed to make Viper aware of the packages that define
+such minor modes.
+Usage:
+    (viper-harness-minor-mode load-file)
+
+LOAD-FILE is a name of the file where the specific minor mode is defined.
+Suffixes such as .el or .elc should be stripped."
+
+  (interactive "sEnter name of the load file: ")
+  
+  (eval-after-load load-file '(viper-normalize-minor-mode-map-alist))
+  
+  ;; 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))
+  )
+
+
+(defun viper-ESC (arg)
+  "Emulate ESC key in Emacs.
+Prevents multiple escape keystrokes if viper-no-multiple-ESC is true.
+If viper-no-multiple-ESC is 'twice double ESC would ding in vi-state.
+Other ESC sequences are emulated via the current Emacs's major mode
+keymap. This is more convenient on TTYs, since this won't block
+function keys such as up,down, etc. ESC will also will also work as
+a Meta key in this case. When viper-no-multiple-ESC is nil, ESC functions
+as a Meta key and any number of multiple escapes is allowed."
+  (interactive "P")
+  (let (char)
+    (cond ((and (not viper-no-multiple-ESC) (eq viper-current-state 'vi-state))
+	   (setq char (viper-read-char-exclusive))
+	   (viper-escape-to-emacs arg (list ?\e char) ))
+	  ((and (eq viper-no-multiple-ESC 'twice) 
+		(eq viper-current-state 'vi-state))
+	   (setq char (viper-read-char-exclusive))
+	   (if (= char (string-to-char viper-ESC-key))
+	       (ding)
+	     (viper-escape-to-emacs arg (list ?\e char) )))
+	  (t (ding)))
+    ))
+
+(defun viper-alternate-Meta-key (arg)
+  "Simulate Emacs Meta key."
+  (interactive "P")
+  (sit-for 1) (message "ESC-")
+  (viper-escape-to-emacs arg '(?\e)))
+
+(defun viper-toggle-key-action ()
+  "Action bound to `viper-toggle-key'."
+  (interactive)
+  (if (and (< viper-expert-level 2) (equal viper-toggle-key "\C-z"))
+      (if (viper-window-display-p)
+	  (viper-iconify)
+	(suspend-emacs))
+    (viper-change-state-to-emacs)))
+
+
+;; Intercept ESC sequences on dumb terminals.
+;; Based on the idea contributed by Marcelino Veiga Tuimil <mveiga@dit.upm.es>
+
+;; Check if last key was ESC and if so try to reread it as a function key.
+;; But only if there are characters to read during a very short time.
+;; Returns the last event, if any.
+(defun viper-envelop-ESC-key ()
+  (let ((event last-input-event)
+	(keyseq [nil])
+	inhibit-quit)
+    (if (viper-ESC-event-p event)
+	(progn 
+	  (if (viper-fast-keysequence-p)
+	      (progn
+		(let (minor-mode-map-alist)
+		  (viper-set-unread-command-events event)
+		  (setq keyseq
+			(funcall
+			 (ad-get-orig-definition 'read-key-sequence) nil))
+		  ) ; let
+		;; If keyseq translates into something that still has ESC
+		;; at the beginning, separate ESC from the rest of the seq.
+		;; In XEmacs we check for events that are keypress meta-key
+		;; and convert them into [escape key]
+		;;
+		;; This is needed for the following reason:
+		;; If ESC is the first symbol, we interpret it as if the
+		;; user typed ESC and then quickly some other symbols.
+		;; If ESC is not the first one, then the key sequence
+		;; entered was apparently translated into a function key or
+		;; something (e.g., one may have
+		;; (define-key function-key-map "\e[192z" [f11])
+		;; which would translate the escape-sequence generated by
+		;; f11 in an xterm window into the symbolic key f11.
+		;;
+		;; If `first-key' is not an ESC event, we make it into the
+		;; last-command-event in order to pretend that this key was
+		;; pressed. This is needed to allow arrow keys to be bound to
+		;; macros. Otherwise, viper-exec-mapped-kbd-macro will think
+		;; that the last event was ESC and so it'll execute whatever is
+		;; bound to ESC. (Viper macros can't be bound to
+		;; ESC-sequences).
+		(let* ((first-key (elt keyseq 0))
+		       (key-mod (event-modifiers first-key)))
+		  (cond ((viper-ESC-event-p first-key)
+			 ;; put keys following ESC on the unread list
+			 ;; and return ESC as the key-sequence
+			 (viper-set-unread-command-events (subseq keyseq 1))
+			 (setq last-input-event event
+			       keyseq (if viper-emacs-p
+					  "\e"
+					(vector (character-to-event ?\e)))))
+			((and viper-xemacs-p
+			      (key-press-event-p first-key)
+			      (equal '(meta) key-mod))
+			 (viper-set-unread-command-events 
+			  (vconcat (vector
+				    (character-to-event (event-key first-key)))
+				   (subseq keyseq 1)))
+			 (setq last-input-event event
+			       keyseq (vector (character-to-event ?\e))))
+			((eventp first-key)
+			 (setq last-command-event
+			       (viper-copy-event first-key)))
+			))
+		) ; end progn
+		
+	    ;; this is escape event with nothing after it
+	    ;; put in unread-command-event and then re-read
+	    (viper-set-unread-command-events event)
+	    (setq keyseq
+		  (funcall (ad-get-orig-definition 'read-key-sequence) nil))
+	    ))
+      ;; not an escape event
+      (setq keyseq (vector event)))
+    keyseq))
+
+    
+
+;; Listen to ESC key.
+;; If a sequence of keys starting with ESC is issued with very short delays,
+;; interpret these keys in Emacs mode, so ESC won't be interpreted as a Vi key.
+(defun viper-intercept-ESC-key ()
+  "Function that implements ESC key in Viper emulation of Vi."
+  (interactive)
+  (let ((cmd (or (key-binding (viper-envelop-ESC-key)) 
+		 '(lambda () (interactive) (error "")))))
+    
+    ;; 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.
+    (if (eq cmd 'viper-intercept-ESC-key)
+	(setq cmd
+	      (cond ((eq viper-current-state 'vi-state)
+		     'viper-ESC)
+		    ((eq viper-current-state 'insert-state)
+		     'viper-exit-insert-state) 
+		    ((eq viper-current-state 'replace-state)
+		     'viper-replace-state-exit-cmd)
+		    (t 'viper-change-state-to-vi)
+		    )))
+    (call-interactively cmd)))
+
+	   
+
+
+;; prefix argument for Vi mode
+
+;; In Vi mode, prefix argument is a dotted pair (NUM . COM) where NUM
+;; represents the numeric value of the prefix argument and COM represents
+;; command prefix such as "c", "d", "m" and "y".
+
+;; Get value part of prefix-argument ARG.
+(defsubst viper-p-val (arg)
+  (cond ((null arg) 1)
+	((consp arg)
+	 (if (or (null (car arg)) (equal (car arg) '(nil)))
+	     1 (car arg)))
+	(t arg)))
+
+;; Get raw value part of prefix-argument ARG.
+(defsubst viper-P-val (arg)
+  (cond ((consp arg) (car arg))
+	(t arg)))
+
+;; Get com part of prefix-argument ARG.
+(defsubst viper-getcom (arg)
+  (cond ((null arg) nil)
+	((consp arg) (cdr arg))
+	(t nil)))
+
+;; Get com part of prefix-argument ARG and modify it.
+(defun viper-getCom (arg)
+  (let ((com (viper-getcom arg)))
+    (cond ((equal com ?c) ?c)
+	  ;; Previously, ?c was being converted to ?C, but this prevented
+	  ;; multiline replace regions.
+	  ;;((equal com ?c) ?C)
+	  ((equal com ?d) ?D)
+	  ((equal com ?y) ?Y)
+	  (t com))))
+
+
+;; Compute numeric prefix arg value. 
+;; Invoked by EVENT. COM is the command part obtained so far.
+(defun viper-prefix-arg-value (event com)
+  (let ((viper-intermediate-command 'viper-digit-argument)
+	value func)
+    ;; read while number
+    (while (and (viper-characterp event) (>= event ?0) (<= event ?9))
+      (setq value (+ (* (if (integerp value) value 0) 10) (- event ?0)))
+      (setq event (viper-read-event-convert-to-char)))
+    
+    (setq prefix-arg value)
+    (if com (setq prefix-arg (cons prefix-arg com)))
+    (while (eq event ?U)
+      (viper-describe-arg prefix-arg)
+      (setq event (viper-read-event-convert-to-char)))
+    
+    (if (or com (and (not (eq viper-current-state 'vi-state))
+		     ;; make sure it is a Vi command
+		     (viper-characterp event) (viper-vi-command-p event)
+		     ))
+	;; If appears to be one of the vi commands,
+	;; then execute it with funcall and clear prefix-arg in order to not
+	;; confuse subsequent commands
+	(progn
+	  ;; last-command-char is the char we want emacs to think was typed
+	  ;; last. If com is not nil, the viper-digit-argument command was
+	  ;; called from within viper-prefix-arg command, such as `d', `w',
+	  ;; etc., i.e., the user typed, say, d2. In this case, `com' would be
+	  ;; `d', `w', etc.  If viper-digit-argument was invoked by
+	  ;; viper-escape-to-vi (which is indicated by the fact that the
+	  ;; current state is not vi-state), then `event' represents the vi
+	  ;; command to be executed (e.g., `d', `w', etc). Again,
+	  ;; last-command-char must make emacs believe that this is the command
+	  ;; we typed.
+	  (cond ((eq event 'return) (setq event ?\C-m))
+		((eq event 'delete) (setq event ?\C-?))
+		((eq event 'backspace) (setq event ?\C-h))
+		((eq event 'space) (setq event ?\ )))
+	  (setq last-command-char (or com event))
+	  (setq func (viper-exec-form-in-vi 
+		      (` (key-binding (char-to-string (, event))))))
+	  (funcall func prefix-arg)
+	  (setq prefix-arg nil))
+      ;; some other command -- let emacs do it in its own way
+      (viper-set-unread-command-events event))
+    ))
+		     
+
+;; Vi operator as prefix argument."
+(defun viper-prefix-arg-com (char value com)
+  (let ((cont t)
+	cmd-info 
+	cmd-to-exec-at-end)
+    (while (and cont
+		(memq char
+		      (list ?c ?d ?y ?! ?< ?> ?= ?# ?r ?R ?\"
+			    viper-buffer-search-char)))
+      (if com
+	  ;; this means that we already have a command character, so we
+	  ;; construct a com list and exit while.  however, if char is "
+	  ;; it is an error.
+	  (progn
+	    ;; new com is (CHAR . OLDCOM)
+	    (if (memq char '(?# ?\")) (error ""))
+	    (setq com (cons char com))
+	    (setq cont nil))
+	;; If com is nil we set com as char, and read more.  Again, if char is
+	;; ", we read the name of register and store it in viper-use-register.
+	;; if char is !, =, or #, a complete com is formed so we exit the while
+	;; loop.
+	(cond ((memq char '(?! ?=))
+	       (setq com char)
+	       (setq char (read-char))
+	       (setq cont nil))
+	      ((= char ?#)
+	       ;; read a char and encode it as com
+	       (setq com (+ 128 (read-char)))
+	       (setq char (read-char)))
+	      ((= char ?\")
+	       (let ((reg (read-char)))
+		 (if (viper-valid-register reg)
+		     (setq viper-use-register reg)
+		   (error ""))
+		 (setq char (read-char))))
+	      (t
+	       (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 (= 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)
+	    (= 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 (memq (car com) '(?r ?R))
+	;; execute apropriate region command.
+	(let ((char (car com)) (com (cdr com)))
+	  (setq prefix-arg (cons value com))
+	  (if (= 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 "")))))
+  ))
+
+(defun viper-describe-arg (arg)
+  (let (val com)
+    (setq val (viper-P-val arg)
+	  com (viper-getcom arg))
+    (if (null val)
+	(if (null com)
+	    (message "Value is nil, and command is nil")
+	  (message "Value is nil, and command is `%c'" com))
+      (if (null com)
+	  (message "Value is `%d', and command is nil" val)
+	(message "Value is `%d', and command is `%c'" val com)))))
+
+(defun viper-digit-argument (arg)
+  "Begin numeric argument for the next command."
+  (interactive "P")
+  (viper-leave-region-active)
+  (viper-prefix-arg-value
+   last-command-char (if (consp arg) (cdr arg) nil)))
+
+(defun viper-command-argument (arg)
+  "Accept a motion command as an argument."
+  (interactive "P")
+  (let ((viper-intermediate-command 'viper-command-argument))
+    (condition-case nil
+	(viper-prefix-arg-com
+	 last-command-char   
+	 (cond ((null arg) nil)
+	       ((consp arg) (car arg))
+	       ((integerp arg) arg)
+	       (t (error viper-InvalidCommandArgument)))
+	 (cond ((null arg) nil)
+	       ((consp arg) (cdr arg))
+	       ((integerp arg) nil)
+	       (t (error viper-InvalidCommandArgument))))
+      (quit (setq viper-use-register nil)
+	    (signal 'quit nil)))
+    (viper-deactivate-mark)))
+
+
+;; repeat last destructive command
+
+;; Append region to text in register REG.
+;; START and END are buffer positions indicating what to append.
+(defsubst viper-append-to-register (reg start end)
+  (set-register reg (concat (if (stringp (get-register reg))
+				(get-register reg) "")
+			    (buffer-substring start end))))
+
+;; Saves last inserted text for possible use by viper-repeat command.
+(defun viper-save-last-insertion (beg end)
+  (condition-case nil
+      (setq viper-last-insertion (buffer-substring beg end))
+    (error
+     ;; beg or end marker are somehow screwed up
+     (setq viper-last-insertion nil)))
+  (setq viper-last-insertion (buffer-substring beg end))
+  (or (< (length viper-d-com) 5)
+      (setcar (nthcdr 4 viper-d-com) viper-last-insertion))
+  (or (null viper-command-ring)
+      (ring-empty-p viper-command-ring)
+      (progn
+	(setcar (nthcdr 4 (viper-current-ring-item viper-command-ring))
+		viper-last-insertion)
+	;; del most recent elt, if identical to the second most-recent
+	(viper-cleanup-ring viper-command-ring)))
+  )
+    
+(defsubst viper-yank-last-insertion ()
+  "Inserts the text saved by the previous viper-save-last-insertion command."
+  (condition-case nil
+      (insert viper-last-insertion)
+    (error nil)))
+  
+			    
+;; define functions to be executed
+
+;; invoked by the `C' command
+(defun viper-exec-change (m-com com) 
+  (or (and (markerp viper-com-point) (marker-position viper-com-point))
+      (set-marker viper-com-point (point) (current-buffer)))
+  ;; handle C cmd at the eol and at eob.
+  (if (or (and (eolp) (= viper-com-point (point)))
+	  (= viper-com-point (point-max)))
+      (progn
+	(insert " ")(backward-char 1)))
+  (if (= viper-com-point (point))
+      (viper-forward-char-carefully))
+  (set-mark viper-com-point)
+  (if (eq m-com 'viper-next-line-at-bol)
+      (viper-enlarge-region (mark t) (point)))
+  (if (< (point) (mark t))
+      (exchange-point-and-mark))
+  (if (eq (preceding-char) ?\n)
+      (viper-backward-char-carefully)) ; give back the newline
+  (if (= com ?c)
+      (viper-change (mark t) (point))
+    (viper-change-subr (mark t) (point))))
+
+;; this is invoked by viper-substitute-line
+(defun viper-exec-Change (m-com com)
+  (save-excursion
+    (set-mark viper-com-point)
+    (viper-enlarge-region (mark t) (point))
+    (if viper-use-register
+	(progn
+	  (cond ((viper-valid-register viper-use-register '(letter digit))
+		 (copy-to-register
+		  viper-use-register (mark t) (point) nil))
+		((viper-valid-register viper-use-register '(Letter))
+		 (viper-append-to-register
+		  (downcase viper-use-register) (mark t) (point)))
+		(t (setq viper-use-register nil)
+		   (error viper-InvalidRegister viper-use-register)))
+	  (setq viper-use-register nil)))
+    (delete-region (mark t) (point)))
+  (open-line 1)
+  (if (= com ?C)
+      (viper-change-state-to-insert)
+    (viper-yank-last-insertion)))
+
+(defun viper-exec-delete (m-com com)
+  (or (and (markerp viper-com-point) (marker-position viper-com-point))
+      (set-marker viper-com-point (point) (current-buffer)))
+  (if viper-use-register
+      (progn
+	(cond ((viper-valid-register viper-use-register '(letter digit))
+	       (copy-to-register
+		viper-use-register viper-com-point (point) nil))
+	      ((viper-valid-register viper-use-register '(Letter))
+	       (viper-append-to-register
+		(downcase viper-use-register) viper-com-point (point)))
+	      (t (setq viper-use-register nil)
+		 (error viper-InvalidRegister viper-use-register)))
+	(setq viper-use-register nil)))
+  (setq last-command
+	(if (eq last-command 'd-command) 'kill-region nil))
+  (kill-region viper-com-point (point))
+  (setq this-command 'd-command)
+  (if viper-ex-style-motion
+      (if (and (eolp) (not (bolp))) (backward-char 1))))
+
+(defun viper-exec-Delete (m-com com)
+  (save-excursion
+    (set-mark viper-com-point)
+    (viper-enlarge-region (mark t) (point))
+    (if viper-use-register
+	(progn
+	  (cond ((viper-valid-register viper-use-register '(letter digit))
+		 (copy-to-register
+		  viper-use-register (mark t) (point) nil))
+		((viper-valid-register viper-use-register '(Letter))
+		 (viper-append-to-register
+		  (downcase viper-use-register) (mark t) (point)))
+		(t (setq viper-use-register nil)
+		   (error viper-InvalidRegister viper-use-register)))
+	  (setq viper-use-register nil)))
+    (setq last-command
+	  (if (eq last-command 'D-command) 'kill-region nil))
+    (kill-region (mark t) (point))
+    (if (eq m-com 'viper-line) (setq this-command 'D-command)))
+  (back-to-indentation))
+
+(defun viper-exec-yank (m-com com)
+  (or (and (markerp viper-com-point) (marker-position viper-com-point))
+      (set-marker viper-com-point (point) (current-buffer)))
+  (if viper-use-register
+      (progn
+	(cond ((viper-valid-register viper-use-register '(letter digit))
+	       (copy-to-register
+		viper-use-register viper-com-point (point) nil))
+	      ((viper-valid-register viper-use-register '(Letter))
+	       (viper-append-to-register
+		(downcase viper-use-register) viper-com-point (point)))
+	      (t (setq viper-use-register nil)
+		 (error viper-InvalidRegister viper-use-register)))
+	(setq viper-use-register nil)))
+  (setq last-command nil)
+  (copy-region-as-kill viper-com-point (point))
+  (goto-char viper-com-point))
+
+(defun viper-exec-Yank (m-com com)
+  (save-excursion
+    (set-mark viper-com-point)
+    (viper-enlarge-region (mark t) (point))
+    (if viper-use-register
+	(progn
+	  (cond ((viper-valid-register viper-use-register '(letter digit))
+		 (copy-to-register
+		  viper-use-register (mark t) (point) nil))
+		((viper-valid-register viper-use-register '(Letter))
+		 (viper-append-to-register
+		  (downcase viper-use-register) (mark t) (point)))
+		(t (setq viper-use-register nil)
+		   (error viper-InvalidRegister  viper-use-register)))
+	  (setq viper-use-register nil)))
+    (setq last-command nil)
+    (copy-region-as-kill (mark t) (point)))
+  (viper-deactivate-mark)
+  (goto-char viper-com-point))
+
+(defun viper-exec-bang (m-com com)
+  (save-excursion
+    (set-mark viper-com-point)
+    (viper-enlarge-region (mark t) (point))
+    (exchange-point-and-mark)
+    (shell-command-on-region
+     (mark t) (point)
+     (if (= com ?!)
+	 (setq viper-last-shell-com
+	       (viper-read-string-with-history 
+		"!"
+		nil
+		'viper-shell-history
+		(car viper-shell-history)
+		))
+       viper-last-shell-com)
+     t)))
+
+(defun viper-exec-equals (m-com com)
+  (save-excursion
+    (set-mark viper-com-point)
+    (viper-enlarge-region (mark t) (point))
+    (if (> (mark t) (point)) (exchange-point-and-mark))
+    (indent-region (mark t) (point) nil)))
+
+(defun viper-exec-shift (m-com com)
+  (save-excursion
+    (set-mark viper-com-point)
+    (viper-enlarge-region (mark t) (point))
+    (if (> (mark t) (point)) (exchange-point-and-mark))
+    (indent-rigidly (mark t) (point) 
+		    (if (= com ?>)
+			viper-shift-width
+		      (- viper-shift-width))))
+  ;; return point to where it was before shift
+  (goto-char viper-com-point))
+
+;; this is needed because some commands fake com by setting it to ?r, which
+;; denotes repeated insert command.
+(defsubst viper-exec-dummy (m-com com)
+  nil)
+
+(defun viper-exec-buffer-search (m-com com)
+  (setq viper-s-string (buffer-substring (point) viper-com-point))
+  (setq viper-s-forward t)
+  (setq viper-search-history (cons viper-s-string viper-search-history))
+  (viper-search viper-s-string viper-s-forward 1))
+
+(defvar viper-exec-array (make-vector 128 nil))
+
+;; Using a dispatch array allows adding functions like buffer search
+;; without affecting other functions. Buffer search can now be bound
+;; to any character.
+
+(aset viper-exec-array ?c 'viper-exec-change)
+(aset viper-exec-array ?C 'viper-exec-Change)
+(aset viper-exec-array ?d 'viper-exec-delete)
+(aset viper-exec-array ?D 'viper-exec-Delete)
+(aset viper-exec-array ?y 'viper-exec-yank)
+(aset viper-exec-array ?Y 'viper-exec-Yank)
+(aset viper-exec-array ?r 'viper-exec-dummy)
+(aset viper-exec-array ?! 'viper-exec-bang)
+(aset viper-exec-array ?< 'viper-exec-shift)
+(aset viper-exec-array ?> 'viper-exec-shift)
+(aset viper-exec-array ?= 'viper-exec-equals)
+
+
+
+;; This function is called by various movement commands to execute a
+;; destructive command on the region specified by the movement command. For
+;; instance, if the user types cw, then the command viper-forward-word will
+;; call viper-execute-com to execute viper-exec-change, which eventually will
+;; call viper-change to invoke the replace mode on the region.
+;;
+;; The var viper-d-com is set to (M-COM VAL COM REG INSETED-TEXT COMMAND-KEYS)
+;; via a call to viper-set-destructive-command, for later use by viper-repeat.
+(defun viper-execute-com (m-com val com)
+  (let ((reg viper-use-register))
+    ;; this is the special command `#'
+    (if (> com 128)
+	(viper-special-prefix-com (- com 128))
+      (let ((fn (aref viper-exec-array (if (< com 0) (- com) com))))
+	(if (null fn)
+	    (error "%c: %s" com viper-InvalidViCommand)
+	  (funcall fn m-com com))))
+    (if (viper-dotable-command-p com)
+	(viper-set-destructive-command
+	 (list m-com val
+	       (if (memq com (list ?c ?C ?!)) (- com) com)
+	       reg nil nil)))
+    ))
+
+
+(defun viper-repeat (arg)
+  "Re-execute last destructive command.
+Use the info in viper-d-com, which has the form
+\(com val ch reg inserted-text command-keys\),
+where `com' is the command to be re-executed, `val' is the
+argument to `com', `ch' is a flag for repeat, and `reg' is optional;
+if it exists, it is the name of the register for `com'.
+If the prefix argument, ARG, is non-nil, it is used instead of `val'."
+  (interactive "P")
+  (let ((save-point (point)) ; save point before repeating prev cmd
+	;; Pass along that we are repeating a destructive command
+	;; This tells viper-set-destructive-command not to update
+	;; viper-command-ring
+	(viper-intermediate-command 'viper-repeat))
+    (if (eq last-command 'viper-undo)
+	;; if the last command was viper-undo, then undo-more
+	(viper-undo-more)
+      ;; otherwise execute the command stored in viper-d-com.  if arg is
+      ;; non-nil its prefix value is used as new prefix value for the command.
+      (let ((m-com (car viper-d-com))
+	    (val (viper-P-val arg))
+	    (com (nth 2 viper-d-com))
+	    (reg (nth 3 viper-d-com)))
+        (if (null val) (setq val (nth 1 viper-d-com)))
+        (if (null m-com) (error "No previous command to repeat."))
+        (setq viper-use-register reg)
+	(if (nth 4 viper-d-com) ; text inserted by command
+	    (setq viper-last-insertion (nth 4 viper-d-com)
+		  viper-d-char (nth 4 viper-d-com)))
+        (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)
+	       (or (bolp) (backward-char 1))))
+	(if (and (eolp) (not (bolp)))
+	    (backward-char 1))
+     ))
+  (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
+  ;; because viper-d-com is not fully constructed in this case (its keys and
+  ;; the inserted text may be nil). Besides, in this case, the command
+  ;; executed by `.' is already on the ring.
+  (if (eq last-command 'viper-display-current-destructive-command)
+      (viper-push-onto-ring viper-d-com 'viper-command-ring))
+  (viper-deactivate-mark)
+  ))
+  
+(defun viper-repeat-from-history ()
+  "Repeat a destructive command from history.
+Doesn't change viper-command-ring in any way, so `.' will work as before
+executing this command.
+This command is supposed to be bound to a two-character Vi macro where
+the second character is a digit 0 to 9. The digit indicates which
+history command to execute. `<char>0' is equivalent to `.', `<char>1'
+invokes the command before that, etc."
+  (interactive)
+  (let* ((viper-intermediate-command 'repeating-display-destructive-command)
+	 (idx (cond (viper-this-kbd-macro
+		      (string-to-number
+		       (symbol-name (elt viper-this-kbd-macro 1))))
+		    (t 0)))
+	 (num idx)
+	 (viper-d-com viper-d-com))
+
+    (or (and (numberp num) (<= 0 num) (<= num 9))
+	(progn
+	  (setq idx 0
+		num 0)
+	  (message
+	   "`viper-repeat-from-history' must be invoked as a Vi macro bound to `<key><digit>'")))
+    (while (< 0 num)
+      (setq viper-d-com (viper-special-ring-rotate1 viper-command-ring -1))
+      (setq num (1- num)))
+    (viper-repeat nil)
+    (while (> idx num)
+      (viper-special-ring-rotate1 viper-command-ring 1)
+      (setq num (1+ num)))
+    ))
+      
+
+;; The hash-command. It is invoked interactively by the key sequence #<char>.
+;; The chars that can follow `#' are determined by viper-hash-command-p
+(defun viper-special-prefix-com (char)
+  (cond ((= char ?c)
+	 (downcase-region (min viper-com-point (point))
+			  (max viper-com-point (point))))
+	((= char ?C)
+	 (upcase-region (min viper-com-point (point))
+			(max viper-com-point (point))))
+	((= char ?g)
+	 (push-mark viper-com-point t)
+	 (viper-global-execute))
+	((= char ?q)
+	 (push-mark viper-com-point t)
+	 (viper-quote-region))
+	((= char ?s) (funcall viper-spell-function viper-com-point (point)))
+	(t (error "#%c: %s" char viper-InvalidViCommand))))
+
+
+;; undoing
+
+(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))))
+  
+    (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))
+    
+    (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 (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))
+    (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.
+(defun viper-undo-more ()
+  (message "undo more!")
+  (condition-case nil
+      (undo-more 1)
+    (error (beep)
+	   (message "No further undo information in this buffer")))
+  (if (and (eolp) (not (bolp))) (backward-char 1))
+  (setq this-command 'viper-undo))
+
+;; The following two functions are used to set up undo properly.
+;; 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 ()
+  (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 ()  
+  (if (listp buffer-undo-list)
+      (if (not viper-undo-needs-adjustment)
+	  (let ((inhibit-quit t))
+	    (setq buffer-undo-list 
+		  (cons viper-buffer-undo-list-mark buffer-undo-list))
+	    (setq viper-undo-needs-adjustment t)))))
+
+
+
+      
+(defun viper-display-current-destructive-command ()
+  (let ((text (nth 4 viper-d-com))
+	(keys (nth 5 viper-d-com))
+	(max-text-len 30))
+    
+    (setq this-command 'viper-display-current-destructive-command)
+	
+    (message " `.' runs  %s%s"
+	     (concat "`" (viper-array-to-string keys) "'")
+	     (viper-abbreviate-string 
+	      (if viper-xemacs-p
+		  (replace-in-string 
+		   (cond ((characterp text) (char-to-string text))
+			 ((stringp text) text)
+			 (t ""))
+		   "\n" "^J")
+		text)
+	      max-text-len
+	      "  inserting  `" "'" "    ......."))
+    ))
+    
+    
+;; don't change viper-d-com if it was viper-repeat command invoked with `.'
+;; or in some other way (non-interactively).
+(defun viper-set-destructive-command (list)
+  (or (eq viper-intermediate-command 'viper-repeat)
+      (progn
+	(setq viper-d-com list)
+	(setcar (nthcdr 5 viper-d-com)
+		(viper-array-to-string (if (arrayp viper-this-command-keys)
+					   viper-this-command-keys
+					 (this-command-keys))))
+	(viper-push-onto-ring viper-d-com 'viper-command-ring)))
+  (setq viper-this-command-keys nil))
+    
+(defun viper-prev-destructive-command (next)
+  "Find previous destructive command in the history of destructive commands.
+With prefix argument, find next destructive command."
+  (interactive "P")
+  (let (cmd viper-intermediate-command)
+    (if (eq last-command 'viper-display-current-destructive-command)
+	;; repeated search through command history
+	(setq viper-intermediate-command
+	      'repeating-display-destructive-command)
+      ;; first search through command history--set temp ring
+      (setq viper-temp-command-ring (copy-list viper-command-ring))) 
+    (setq cmd (if next
+		  (viper-special-ring-rotate1 viper-temp-command-ring 1)
+		(viper-special-ring-rotate1 viper-temp-command-ring -1)))
+    (if (null cmd)
+	()
+      (setq viper-d-com cmd))
+    (viper-display-current-destructive-command)))
+      
+(defun viper-next-destructive-command ()
+  "Find next destructive command in the history of destructive commands."
+  (interactive)
+  (viper-prev-destructive-command 'next))
+  
+(defun viper-insert-prev-from-insertion-ring (arg)
+  "Cycle through insertion ring in the direction of older insertions.
+Undoes previous insertion and inserts new.
+With prefix argument, cycles in the direction of newer elements.
+In minibuffer, this command executes whatever the invocation key is bound
+to in the global map, instead of cycling through the insertion ring."
+  (interactive "P")
+  (let (viper-intermediate-command)
+    (if (eq last-command 'viper-insert-from-insertion-ring)
+	(progn  ; repeated search through insertion history
+	  (setq viper-intermediate-command 'repeating-insertion-from-ring)
+	  (if (eq viper-current-state 'replace-state)
+	      (undo 1)
+	    (if viper-last-inserted-string-from-insertion-ring
+		(backward-delete-char
+		 (length viper-last-inserted-string-from-insertion-ring))))
+	  )
+      ;;first search through insertion history
+      (setq viper-temp-insertion-ring (copy-list viper-insertion-ring)))
+    (setq this-command 'viper-insert-from-insertion-ring)
+    ;; so that things will be undone properly
+    (setq buffer-undo-list (cons nil buffer-undo-list))
+    (setq viper-last-inserted-string-from-insertion-ring
+	  (viper-special-ring-rotate1 viper-temp-insertion-ring (if arg 1 -1)))
+    
+    ;; this change of viper-intermediate-command must come after
+    ;; viper-special-ring-rotate1, so that the ring will rotate, but before the
+    ;; insertion.
+    (setq viper-intermediate-command nil)
+    (if viper-last-inserted-string-from-insertion-ring
+	(insert viper-last-inserted-string-from-insertion-ring))
+    ))
+
+(defun viper-insert-next-from-insertion-ring ()
+  "Cycle through insertion ring in the direction of older insertions.
+Undo previous insertion and inserts new."
+  (interactive)
+  (viper-insert-prev-from-insertion-ring 'next))
+    
+
+;; some region utilities
+
+;; If at the last line of buffer, add \\n before eob, if newline is missing.
+(defun viper-add-newline-at-eob-if-necessary ()
+  (save-excursion
+      (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"))))
+
+(defun viper-yank-defun ()
+  (mark-defun)
+  (copy-region-as-kill (point) (mark t)))
+
+;; Enlarge region between BEG and END.
+(defun viper-enlarge-region (beg end)
+  (or beg (setq beg end)) ; if beg is nil, set to end
+  (or end (setq end beg)) ; if end is nil, set to beg
+  
+  (if (< beg end)
+      (progn (goto-char beg) (set-mark end))
+    (goto-char end)
+    (set-mark beg))
+  (beginning-of-line)
+  (exchange-point-and-mark)
+  (if (or (not (eobp)) (not (bolp))) (forward-line 1))
+  (if (not (eobp)) (beginning-of-line))
+  (if (> beg end) (exchange-point-and-mark)))
+
+
+;; Quote region by each line with a user supplied string.
+(defun viper-quote-region ()
+  (let ((quote-str viper-quote-string)
+	(donot-change-dafault t))
+    (setq quote-str
+	  (viper-read-string-with-history
+	   "Quote string: "
+	   nil
+	   'viper-quote-region-history
+	   (cond ((string-match "tex.*-mode" (symbol-name major-mode)) "%%")
+		 ((string-match "java.*-mode" (symbol-name major-mode)) "//")
+		 ((string-match "perl.*-mode" (symbol-name major-mode)) "#")
+		 ((string-match "lisp.*-mode" (symbol-name major-mode)) ";;")
+		 ((memq major-mode '(c-mode cc-mode c++-mode)) "//")
+		 ((memq major-mode '(sh-mode shell-mode)) "#")
+		 (t (setq donot-change-dafault nil)
+		    quote-str))))
+    (or donot-change-dafault
+	(setq viper-quote-string quote-str))
+    (viper-enlarge-region (point) (mark t))
+    (if (> (point) (mark t)) (exchange-point-and-mark))
+    (insert quote-str)
+    (beginning-of-line)
+    (forward-line 1)
+    (while (and (< (point) (mark t)) (bolp))
+      (insert quote-str)
+      (beginning-of-line)
+      (forward-line 1))))
+
+;;  Tells whether BEG is on the same line as END.
+;;  If one of the args is nil, it'll return nil.
+(defun viper-same-line (beg end)
+   (let ((selective-display nil)
+	 (incr 0)
+	 temp)
+     (if (and beg end (> beg end))
+	 (setq temp beg
+	       beg end
+	       end temp))
+     (if (and beg end)
+	 (cond ((or (> beg (point-max)) (> end (point-max))) ; out of range
+		nil)
+	       (t
+		;; This 'if' is needed because Emacs treats the next empty line
+		;; as part of the previous line.
+		(if (= (viper-line-pos 'start) end)
+		    (setq incr 1))
+		(<= (+ incr (count-lines beg end)) 1))))
+     ))
+	 
+	 
+;; Check if the string ends with a newline.
+(defun viper-end-with-a-newline-p (string)
+  (or (string= string "")
+      (= (viper-seq-last-elt string) ?\n)))
+
+(defun viper-tmp-insert-at-eob (msg)
+  (let ((savemax (point-max)))
+      (goto-char savemax)
+      (insert msg)
+      (sit-for 2)
+      (goto-char savemax) (delete-region (point) (point-max))
+      ))  
+      
+
+
+;;; Minibuffer business
+	    
+(defsubst viper-set-minibuffer-style ()
+  (add-hook 'minibuffer-setup-hook 'viper-minibuffer-setup-sentinel))
+  
+  
+(defun viper-minibuffer-setup-sentinel ()
+  (let ((hook (if viper-vi-style-in-minibuffer
+		  'viper-change-state-to-insert
+		'viper-change-state-to-emacs)))
+    (funcall hook)
+    ))
+  
+;; Interpret last event in the local map first; if fails, use exit-minibuffer.
+;; Run viper-minibuffer-exit-hook before exiting.
+(defun viper-exit-minibuffer ()
+  "Exit minibuffer Viper way."
+  (interactive)
+  (let (command)
+    (setq command (local-key-binding (char-to-string last-command-char)))
+    (run-hooks 'viper-minibuffer-exit-hook)
+    (if command
+	(command-execute command)
+      (exit-minibuffer))))
+  
+
+(defcustom viper-smart-suffix-list
+  '("" "tex" "c" "cc" "C" "el" "java" "html" "htm" "pl" "P" "p")
+  "*List of suffixes that Viper tries to append to filenames ending with a `.'.
+This is useful when you the current directory contains files with the same
+prefix and many different suffixes. Usually, only one of the suffixes
+represents an editable file. However, file completion will stop at the `.'
+The smart suffix feature lets you hit RET in such a case, and Viper will
+select the appropriate suffix.
+
+Suffixes are tried in the order given and the first suffix for which a
+corresponding file exists is selected. If no file exists for any of the
+suffixes, the user is asked to confirm.
+
+To turn this feature off, set this variable to nil."
+  :type '(repeat string)
+  :group 'viper-misc)
+    
+
+;; Try to add a suitable suffix to files whose name ends with a `.'
+;; Useful when the user hits RET on a non-completed file name.
+;; Used as a minibuffer exit hook in read-file-name
+(defun viper-file-add-suffix ()
+  (let ((count 0)
+	(len (length viper-smart-suffix-list))
+	(file (buffer-string))
+	found key cmd suff)
+    (goto-char (point-max))
+    (if (and viper-smart-suffix-list (string-match "\\.$" file))
+	(progn
+	  (while (and (not found) (< count len))
+	    (setq suff (nth count viper-smart-suffix-list)
+		  count (1+ count))
+	    (if (file-exists-p
+		 (format "%s%s" (substitute-in-file-name file) suff))
+		(progn
+		  (setq found t)
+		  (insert suff))))
+	  
+	  (if found
+	      ()
+	    (viper-tmp-insert-at-eob " [Please complete file name]")
+	    (unwind-protect 
+		(while (not (memq cmd
+				  '(exit-minibuffer viper-exit-minibuffer)))
+		  (setq cmd
+			(key-binding (setq key (read-key-sequence nil))))
+		  (cond ((eq cmd 'self-insert-command)
+			 (if viper-xemacs-p
+			     (insert (events-to-keys key))
+			   (insert key)))
+			((memq cmd '(exit-minibuffer viper-exit-minibuffer))
+			 nil)
+			(t (command-execute cmd)))
+		  )))
+	  ))))
+
+
+(defun viper-minibuffer-trim-tail ()
+  "Delete junk at the end of the first line of the minibuffer input.
+Remove this function from `viper-minibuffer-exit-hook', if this causes
+problems."
+  (if (viper-is-in-minibuffer)
+      (progn
+	(goto-char (point-min))
+	(end-of-line)
+	(delete-region (point) (point-max)))))
+
+
+;;; Reading string with history  
+    
+(defun viper-read-string-with-history (prompt &optional initial 
+					      history-var default keymap
+					      init-message)
+  ;; Read string, prompting with PROMPT and inserting the INITIAL
+  ;; value. Uses HISTORY-VAR. DEFAULT is the default value to accept if the
+  ;; input is an empty string.
+  ;; Default value is displayed until the user types something in the
+  ;; minibuffer. 
+  ;; KEYMAP is used, if given, instead of minibuffer-local-map.
+  ;; INIT-MESSAGE is the message temporarily displayed after entering the
+  ;; minibuffer.
+  (let ((minibuffer-setup-hook 
+	 (function
+	  (lambda ()
+	    (if (stringp init-message)
+		(viper-tmp-insert-at-eob init-message))
+	    (if (stringp initial)
+		(progn
+		  ;; don't wait if we have unread events or in kbd macro
+		  (or unread-command-events
+		      executing-kbd-macro
+		      (sit-for 840))
+		  (erase-buffer)
+		  (insert initial)))
+	    (viper-minibuffer-setup-sentinel))))
+	(val "")
+	(padding "")
+	temp-msg)
+    
+    (setq keymap (or keymap minibuffer-local-map)
+	  initial (or initial "")
+	  temp-msg (if default
+		       (format "(default: %s) " default)
+		     ""))
+		   
+    (setq viper-incomplete-ex-cmd nil)
+    (setq val (read-from-minibuffer prompt 
+				    (concat temp-msg initial val padding)
+				    keymap nil history-var))
+    (setq minibuffer-setup-hook nil
+	  padding (viper-array-to-string (this-command-keys))
+	  temp-msg "")
+    ;; the following tries to be smart about what to put in history
+    (if (not (string= val (car (eval history-var))))
+	(set history-var (cons val (eval history-var))))
+    (if (or (string= (nth 0 (eval history-var)) (nth 1 (eval history-var)))
+	    (string= (nth 0 (eval history-var)) ""))
+	(set history-var (cdr (eval history-var))))
+    ;; If the user enters nothing but the prev cmd wasn't viper-ex,
+    ;; viper-command-argument, or `! shell-command', this probably means 
+    ;; that the user typed something then erased. Return "" in this case, not
+    ;; the default---the default is too confusing in this case.
+    (cond ((and (string= val "")
+		(not (string= prompt "!")) ; was a `! shell-command'
+		(not (memq last-command
+			   '(viper-ex
+			     viper-command-argument
+			     t)
+			   )))
+	   "")
+	  ((string= val "") (or default ""))
+	  (t val))
+    ))
+  
+
+
+;; insertion commands
+
+;; Called when state changes from Insert Vi command mode.
+;; Repeats the insertion command if Insert state was entered with prefix
+;; argument > 1.
+(defun viper-repeat-insert-command ()
+  (let ((i-com (car viper-d-com))
+	(val   (nth 1 viper-d-com))
+	(char  (nth 2 viper-d-com)))
+    (if (and val (> val 1)) ; first check that val is non-nil
+	(progn        
+	  (setq viper-d-com (list i-com (1- val) ?r nil nil nil))
+	  (viper-repeat nil)
+	  (setq viper-d-com (list i-com val char nil nil nil))
+	  ))))
+
+(defun viper-insert (arg)
+  "Insert before point."
+  (interactive "P")
+  (viper-set-complex-command-for-undo)
+  (let ((val (viper-p-val arg))
+	(com (viper-getcom arg)))
+    (viper-set-destructive-command (list 'viper-insert val ?r nil nil nil))
+    (if com
+	(viper-loop val (viper-yank-last-insertion))
+      (viper-change-state-to-insert))))
+
+(defun viper-append (arg)
+  "Append after point."
+  (interactive "P")
+  (viper-set-complex-command-for-undo)
+  (let ((val (viper-p-val arg))
+	(com (viper-getcom arg)))
+    (viper-set-destructive-command (list 'viper-append val ?r nil nil nil))
+    (if (not (eolp)) (forward-char))
+    (if (equal com ?r)
+	(viper-loop val (viper-yank-last-insertion))
+      (viper-change-state-to-insert))))
+
+(defun viper-Append (arg)
+  "Append at end of li