;; Author: Masahiko Sato <ms@sail.stanford.edu>
;; Version: 3.5
-;; Last-Modified: 15 Sep 1987
+;; Keywords: emulations
;;; 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.
(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.")
"*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")
;; 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)
(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-char 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-char 0))
- ;; 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
))
(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
(while (= char ?U)
(vip-describe-arg prefix-arg)
(setq char (read-char)))
- (setq unread-command-char char))
+ (setq unread-command-events (list char)))
(defun vip-prefix-arg-com (char value com)
"Vi operator as prefix argument."
(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))
(while (= char ?U)
(vip-describe-arg prefix-arg)
(setq char (read-char)))
- (setq unread-command-char char))
+ (setq unread-command-events (list char)))
;; as com is non-nil, this means that we have a command to execute
(if (or (= (car com) ?r) (= (car com) ?R))
;; execute apropriate region command.
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)
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")
(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)))))))
(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)
;; 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")
(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")
(progn
(if (and (<= ?A vip-use-register) (<= vip-use-register ?Z))
(vip-append-to-register
- (+ vip-use-register 32) (point) (- (point) val) nil)
+ (+ vip-use-register 32) (point) (- (point) val))
(copy-to-register vip-use-register (point) (- (point) val) nil))
(setq vip-use-register nil)))
(delete-char val t)))
(progn
(if (and (<= ?A vip-use-register) (<= vip-use-register ?Z))
(vip-append-to-register
- (+ vip-use-register 32) (point) (+ (point) val) nil)
+ (+ vip-use-register 32) (point) (+ (point) val))
(copy-to-register vip-use-register (point) (+ (point) val) nil))
(setq vip-use-register nil)))
(delete-backward-char val t)))
(defun vip-mark-point (char)
(interactive "c")
(cond ((and (<= ?a char) (<= char ?z))
- (point-to-register (- char (- ?a ?\C-a))))
+ (point-to-register (- char (- ?a ?\C-a)) nil))
((= char ?<) (vip-mark-beginning-of-buffer))
((= char ?>) (vip-mark-end-of-buffer))
((= char ?.) (push-mark))
(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
"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")
(if ex-buffer
(if (and (<= ?A ex-buffer) (<= ex-buffer ?Z))
(vip-append-to-register
- (+ ex-buffer 32) (point) (mark) nil)
+ (+ ex-buffer 32) (point) (mark))
(copy-to-register ex-buffer (point) (mark) nil)))
(delete-region (point) (mark))))))
(error "Mark must specify a letter"))))
(save-excursion
(goto-char (car ex-addresses))
- (point-to-register (- char (- ?a ?\C-a))))))
+ (point-to-register (- char (- ?a ?\C-a)) nil))))
(defun ex-map ()
"ex map"
(shell))
(defun ex-substitute (&optional repeat r-flag)
- "ex substitute. if REPEAT use previous reg-exp which is ex-reg-exp or
+ "ex substitute.
+If REPEAT use previous reg-exp which is ex-reg-exp or
vip-s-string"
(let (pat repl (opt-g nil) (opt-c nil) (matched-pos nil))
(if repeat (setq ex-token nil) (vip-get-ex-pat))
(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)))))