(compare-windows): Push mark in both buffers at start.
[bpt/emacs.git] / lisp / emulation / vip.el
index 14da705..e343bf7 100644 (file)
@@ -6,6 +6,8 @@
 
 ;;; Commentary:
 
+;; A full-featured vi(1) emulator.
+;;
 ;; In Japan, the author's address is: masahiko@sato.riec.tohoku.junet
 ;;
 ;; Send suggestions and bug reports to one of the above addresses.
@@ -65,7 +67,7 @@
 
 (defvar vip-d-com nil
   "If non-nil, it's value is a list (M-COM VAL COM), and is used to
-re-execute last destrcutive command")
+re-execute last destructive command")
 
 (defconst vip-shift-width 8
   "*The number of colums shifted by > and < command.")
@@ -74,7 +76,7 @@ re-execute last destrcutive command")
   "*If t then do regexp replace, if nil then do string replace.")
 
 (defvar vip-d-char nil
-  "The character remenbered by the vi \"r\" command")
+  "The character remembered by the vi \"r\" command")
 
 (defvar vip-f-char nil
   "for use by \";\" command")
@@ -167,8 +169,7 @@ No message."
 ;; changing mode
 
 (defun vip-change-mode (new-mode)
-  "Change mode to NEW-MODE.  NEW-MODE is either emacs-mode, vi-mode,
-or insert-mode."
+  "Change mode to NEW-MODE---either emacs-mode, vi-mode, or insert-mode."
   (or (eq new-mode vip-current-mode)
       (progn
        (cond ((eq new-mode 'vi-mode)
@@ -274,76 +275,21 @@ Type `n' to quit this window for now.\n")
   (vip-change-mode 'emacs-mode))
 
 \f
-;; escape to emacs mode termporarilly
-
-(defun vip-get-editor-command (l-map g-map &optional str)
-  "Read characters from keyboard until an editor command is formed, using
-local keymap L-MAP and global keymap G-MAP.  If the command is a
-self-insert-command, the character just read is returned instead.  Optional
-string STR is used as initial input string."
-  (let (char l-bind g-bind)
-    (setq char
-         (if (or (null str) (string= str ""))
-             (read-char)
-           (string-to-char str)))
-    (setq last-command-char char)
-    (setq l-bind (vip-binding-of char l-map))
-    (if (null l-bind)
-       ;; since local binding is empty, we concentrate on global one.
-       (progn
-         (setq g-bind (vip-binding-of char g-map))
-         (if (null g-bind)
-             nil ;; return nil, since both bindings are void.
-           (if (keymapp g-bind)
-               (vip-get-editor-command nil g-bind (vip-string-tail str))
-             (if (eq g-bind 'self-insert-command) char g-bind))))
-      ;; local binding is nonvoid
-      (if (keymapp l-bind)
-         ;; since l-bind is a keymap, we consider g-bind as well.
-         (progn
-           (setq g-bind (vip-binding-of char g-map))
-           (if (null g-bind)
-               (vip-get-editor-command l-bind nil (vip-string-tail str))
-             (if (keymapp g-bind)
-                 ;; both bindings are keymap
-                 (vip-get-editor-command l-bind g-bind (vip-string-tail str))
-               ;; l-bind is a keymap, so we neglect g-bind
-               (vip-get-editor-command l-bind nil (vip-string-tail str)))))
-       ;; l-bind is a command
-       (if (eq l-bind 'self-insert-command) char l-bind)))))
-
-(defun vip-binding-of (char map)
-  "Return key-binding of CHAR under keymap MAP.  It is nil if the binding
-is void, or a command, or a keymap"
-  (let ((val (if (listp map)
-                (cdr (assq char map))
-              (aref map char))))
-    (cond ((null val) nil)
-         ((keymapp val)
-          (if (symbolp val) (symbol-function val) val))
-         (t
-          ;; otherwise, it is a function which is either a real function or
-          ;; a keymap fset to val.
-          (let ((fun (symbol-function val)))
-            (if (or (null fun) (keymapp fun)) fun val))))))
-
-(defun vip-escape-to-emacs (arg &optional char)
-  "Escape to emacs mode and execute one emacs command and then return to
-vi mode.  ARG is used as the prefix value for the executed command.  If
-CHAR is given it becomes the first character of the command."
-  (interactive "P")
-  (let (com (buff (current-buffer)) (first t))
-    (if char (setq unread-command-events (list char)))
+;; escape to emacs mode temporarily
+
+(defun vip-escape-to-emacs (arg &optional events)
+  "Escape to Emacs mode 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")
+  (let (com key (old-map (current-local-map)))
+    (if events (setq unread-command-events events))
     (setq prefix-arg arg)
-    (while (or first unread-command-events)
-      ;; this while loop is executed until unread command char will be
-      ;; exhausted.
-      (setq first nil)
-      (setq com (vip-get-editor-command vip-emacs-local-map global-map))
-      (if (numberp com)
-         (vip-loop (vip-p-val prefix-arg)
-                   (insert (char-to-string com)))
-       (command-execute com prefix-arg)))
+    (use-local-map vip-emacs-local-map)
+    (unwind-protect
+       (setq com (key-binding (setq key (read-key-sequence nil))))
+      (use-local-map old-map))
+    (command-execute com prefix-arg)
     (setq prefix-arg nil)  ;; reset prefix arg
     ))
 
@@ -358,25 +304,25 @@ CHAR is given it becomes the first character of the command."
 (defun vip-ESC (arg)
   "Emulate ESC key in Emacs mode."
   (interactive "P")
-  (vip-escape-to-emacs arg ?\e))
+  (vip-escape-to-emacs arg '(?\e)))
 
 (defun vip-ctl-c (arg)
   "Emulate C-c key in Emacs mode."
   (interactive "P")
-  (vip-escape-to-emacs arg ?\C-c))
+  (vip-escape-to-emacs arg '(?\C-c)))
 
 (defun vip-ctl-x (arg)
   "Emulate C-x key in Emacs mode."
   (interactive "P")
-  (vip-escape-to-emacs arg ?\C-x))
+  (vip-escape-to-emacs arg '(?\C-x)))
 
 (defun vip-ctl-h (arg)
   "Emulate C-h key in Emacs mode."
   (interactive "P")
-  (vip-escape-to-emacs arg ?\C-h))
+  (vip-escape-to-emacs arg '(?\C-h)))
 
 \f
-;; prefix argmument for vi mode
+;; 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
@@ -413,7 +359,7 @@ obtained so far, and COM is the command part obtained so far."
            (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 vip-use-register.
-       ;; if char is !, =, or #, a copmlete com is formed so we exit while.
+       ;; if char is !, =, or #, a complete com is formed so we exit while.
        (cond ((or (= char ?!) (= char ?=))
               (setq com char)
               (setq char (read-char))
@@ -476,7 +422,7 @@ obtained so far, and COM is the command part obtained so far."
          com (vip-getcom arg))
     (if (null val)
        (if (null com)
-           (message "Value is nil, and commmand is nil.")
+           (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)
@@ -680,8 +626,8 @@ to vip-d-com for later use by vip-repeat"
                          reg))))
 
 (defun vip-repeat (arg)
-  "(ARG)  Re-excute last destructive command.  vip-d-com has the form
-(COM ARG CH REG), where COM is the command to be re-executed, ARG is the
+  "(ARG)  Re-execute last destructive command.  vip-d-com has the form
+\(COM ARG CH REG), where COM is the command to be re-executed, ARG is the
 argument for COM, CH is a flag for repeat, and REG is optional and if exists
 is the name of the register for COM."
   (interactive "P")
@@ -980,9 +926,13 @@ the query replace mode will toggle between string replace and regexp replace."
                           (if vip-re-replace "regexp replace"
                             "string replace"))))
       (if vip-re-replace
-         (replace-regexp
-          str
-          (vip-read-string (format "Replace regexp \"%s\" with: " str)))
+         ;; (replace-regexp
+         ;;  str
+         ;;  (vip-read-string (format "Replace regexp \"%s\" with: " str)))
+         (while (re-search-forward str nil t)
+           (replace-match (vip-read-string
+                           (format "Replace regexp \"%s\" with: " str))
+                          nil nil))
        (replace-string
         str
         (vip-read-string (format "Replace \"%s\" with: " str)))))))
@@ -1182,7 +1132,7 @@ beginning of buffer, stop and signal error."
     (if com (vip-execute-com 'vip-goto-line val com))))
 
 (defun vip-find-char (arg char forward offset)
-  "Find ARG's occurence of CHAR on the current line.  If FORWARD then
+  "Find ARG's occurrence of CHAR on the current line.  If FORWARD then
 search is forward, otherwise backward.  OFFSET is used to adjust point
 after search."
   (let ((arg (if forward arg (- arg))) point)
@@ -1483,7 +1433,7 @@ used.  This behaviour is controlled by the sign of prefix numeric value."
 ;; searching
 
 (defun vip-search-forward (arg)
-  "Search a string forward.  ARG is used to find the ARG's occurence
+  "Search a string forward.  ARG is used to find the ARG's occurrence
 of the string.  Default is vanilla search.  Search mode can be toggled by
 giving null search string."
   (interactive "P")
@@ -1503,7 +1453,7 @@ giving null search string."
            (vip-execute-com 'vip-search-next val com))))))
 
 (defun vip-search-backward (arg)
-  "Search a string backward.  ARG is used to find the ARG's occurence
+  "Search a string backward.  ARG is used to find the ARG's occurrence
 of the string.  Default is vanilla search.  Search mode can be toggled by
 giving null search string."
   (interactive "P")
@@ -1879,12 +1829,7 @@ the query replace mode will toggle between string replace and regexp replace."
   (let ((char (read-char)))
     (if (and (<= ?A char) (<= char ?Z))
        (setq char (- char (- ?A ?\C-a))))
-         (setq prefix-arg arg)
-         (command-execute
-          (vip-get-editor-command
-           vip-emacs-local-map global-map
-           (format "%s%s" key (char-to-string char))))))
-  
+    (vip-escape-to-emacs arg (list (aref key 0) char))))
 \f
 ;; commands in insertion mode
 
@@ -2071,7 +2016,7 @@ is a command.")
   "pattern for global command")
 
 (defvar ex-map (make-sparse-keymap)
-  "save commnads for mapped keys")
+  "save commands for mapped keys")
 
 (defvar ex-tag nil
   "save ex tag")
@@ -3047,7 +2992,7 @@ vip-s-string"
            (forward-line (1- ex-count)))
        (set-mark end))
       (vip-enlarge-region (point) (mark))
-      (if ex-flag (error "Extra chacters at end of command"))
+      (if ex-flag (error "Extra characters at end of command"))
       (if ex-buffer
          (copy-to-register ex-buffer (point) (mark) nil))
       (copy-region-as-kill (point) (mark)))))