Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!caip!nike!oliveb!glacier!SU-Russell!sato From: sato@SU-Russell.ARPA (Masahiko Sato) Newsgroups: net.emacs Subject: VIP (VI Package for GNU Emacs) - Part 2 Message-ID: <175@SU-Russell.ARPA> Date: Wed, 23-Jul-86 18:33:52 EDT Article-I.D.: SU-Russe.175 Posted: Wed Jul 23 18:33:52 1986 Date-Received: Thu, 24-Jul-86 08:11:50 EDT Organization: Stanford University, CSLI Lines: 1934 Below is the elisp code of VIP. ** masahiko (sato@su-russell.arpa) =============== Cut here =============== ;; VIP: A VI Package for GNU Emacs ;; Author: sato@su-russell.arpa (Masahiko Sato) ;; Version 17.1 of July 23, 1986 ;; This code works under version 17 of GNU Emacs. ;; external variables (defvar vi-local-map nil "Local map used in vi command mode. \(buffer specific\)") (defvar emacs-local-map nil "Local map used in emacs mode. \(buffer specific\)") (defvar insert-local-map nil "Local map used in insert command mode. \(buffer specific\)") (make-variable-buffer-local 'vi-local-map) (make-variable-buffer-local 'emacs-local-map) (make-variable-buffer-local 'insert-local-map) (defvar insert-point nil "Remember insert point as a marker. \(buffer specific\)") (set-default 'insert-point (make-marker)) (make-variable-buffer-local 'insert-point) (defvar com-point nil "Remember com point as a marker. \(buffer specific\)") (set-default 'com-point (make-marker)) (make-variable-buffer-local 'com-point) (defvar current-mode nil "Current mode. One of emacs-mode, vi-mode, insert-mode.") (make-variable-buffer-local 'current-mode) (set-default 'current-mode 'emacs-mode) (defvar current-major-mode nil "current-major-mode is the major-mode vi considers it is now. \(buffer specific\)") (make-variable-buffer-local 'current-major-mode) (defvar vi-last-shell-com nil "last shell command executed by ! command") (defvar use-register nil "name of register to store deleted or yanked strings.") (defvar 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") (defconst shift-width 8 "The number of colums shifted by > and < command.") (defconst re-replace nil "If t then do regexp replace, if nil then do string replace.") (defvar d-char nil "The char rembered by the vi \"r\" command") (defvar f-char nil "for use by \";\" command") (defvar f-forward nil "for use by \";\" command") (defvar f-offset nil "for use by \";\" command") (defconst vi-search-wrap-around t "if t, search wraps around") (defconst re-search nil "if t, search is reg-exp search, otherwise vanilla search.") (defvar s-string nil "last search string") (defvar s-forward nil "if t, search is forward.") (defconst vi-case-fold-search nil "if t, search ignores cases.") (defconst re-query-replace nil "If t then do regexp replace, if nil then do string replace.") (defvar vi-quote-string "> " "string inserted at the beginning of region") ;; basic set up (global-set-key "\C-z" 'change-mode-to-vi) (global-set-key "\^xo" 'vi-other-window) (defmacro loop (count body) "(COUNT BODY) Execute BODY COUNT times." (list 'let (list (list 'count count)) (list 'while (list '> 'count 0) body (list 'setq 'count (list '1- 'count))))) (defun push-mark-silent (&optional location) "Set mark at location (point, by default) and push old mark on mark ring. No message." (if (null (mark)) nil (setq mark-ring (cons (copy-marker (mark-marker)) mark-ring)) (if (> (length mark-ring) mark-ring-max) (progn (move-marker (car (nthcdr mark-ring-max mark-ring)) nil) (setcdr (nthcdr (1- mark-ring-max) mark-ring) nil)))) (set-mark (or location (point)))) (defun vi-goto-col (arg) "(ARG) Go to ARG's column." (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (save-excursion (end-of-line) (if (> val (1+ (current-column))) (error ""))) (if com (move-marker com-point (point))) (beginning-of-line) (forward-char (1- val)) (if com (execute-com 'vi-goto-col val com)))) (defun refresh-mode-line () "Redraw mode line." (set-buffer-modified-p (buffer-modified-p))) (defun copy-keymap (arg) "(ARG) Make a copy of the keymap ARG." (if (or (keymapp arg) (null arg)) (if (listp arg) (let* ((map (make-sparse-keymap)) (atmp (cdr arg)) (mtmp map) key rest) (while atmp (setq key (car (car atmp)) rest (cdr (car atmp))) (if (symbolp rest) (rplacd mtmp (cons (cons key rest) nil)) (rplacd mtmp (cons (cons key (copy-keymap rest)) nil))) (setq atmp (cdr atmp) mtmp (cdr mtmp))) map) (let ((map (make-keymap)) (i 0) bind) (while (> 128 i) (setq bind (aref arg i)) (if (symbolp bind) (aset map i bind) (aset map i (copy-keymap bind))) (setq i (1+ i))) map)) (error "Arg is not keymap"))) ;; changing mode (defun change-mode (new-mode) "(NEW-MODE) Change mode to NEW-MODE. NEW-MODE is either emacs-mode, vi-mode, or insert-mode." (or (eq new-mode current-mode) (progn (cond ((eq new-mode 'vi-mode) (if (eq current-mode 'insert-mode) (progn (copy-region-as-kill (point) insert-point) (repeat-insert-command)) (setq emacs-global-map global-map emacs-local-map (current-local-map) emacs-mode-line-format mode-line-format insert-local-map (copy-keymap (current-local-map)))) (change-mode-line "Vi: ") (use-global-map vi-command-mode-map) (if (eq major-mode current-major-mode) (use-local-map vi-local-map) (progn (setq current-major-mode major-mode) (make-vi-local-map major-mode) (use-local-map vi-local-map)))) ((eq new-mode 'insert-mode) (move-marker insert-point (point)) (change-mode-line "Insert") (use-global-map emacs-global-map) (use-local-map insert-local-map) (define-key insert-local-map "\e" 'change-mode-to-vi) (define-key insert-local-map "\^h" 'delete-backward-char) (define-key insert-local-map "\^w" 'delete-backward-word)) ((eq new-mode 'emacs-mode) (setq mode-line-format emacs-mode-line-format) (use-global-map emacs-global-map) (use-local-map emacs-local-map)) (t (error "Can't change to %s " new-mode))) (setq current-mode new-mode) (refresh-mode-line)))) (defun change-mode-line (string) "Assuming that the mode line format contains the string \"Emacs:\", this function replaces the string by \"Vi: \" etc. If the mode line format does not contain \"Emacs:\", default mode line format is used instead." (let (format) (save-window-excursion (save-restriction (switch-to-buffer " *working-space*") (set-mark (point)) (insert emacs-mode-line-format) (narrow-to-region (mark) (point)) (goto-char (point-min)) (if (not (search-forward "Emacs:" nil t)) (progn (delete-region (point-min) (point-max)) (insert "%1*%1*- %[Emacs:%] %16b %3p (%m) %M %-") (goto-char (point-min)) (search-forward "Emacs:"))) (set-mark (point)) (backward-char 6) (delete-region (point) (mark)) (insert string) (setq format (buffer-string)) (delete-region (point-min) (point-max)))) (setq mode-line-format format) (refresh-mode-line))) (defun change-mode-to-vi () "() Change mode to vi." (interactive) (change-mode 'vi-mode)) (defun change-mode-to-insert () "() Change mode to insert." (interactive) (change-mode 'insert-mode)) (defun change-mode-to-emacs () "() Change mode to emacs." (interactive) (change-mode 'emacs-mode)) ;; escape to emacs mode termporarilly (defun get-editor-command (l-map g-map &optional str) "(L-MAP G-MAP 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 (binding-of char l-map)) (if (null l-bind) ;; since local binding is empty, we concentrate on global one. (progn (setq g-bind (binding-of char g-map)) (if (null g-bind) nil ;; return nil, since both bindings are void. (if (keymapp g-bind) (get-editor-command nil g-bind (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 (binding-of char g-map)) (if (null g-bind) (get-editor-command l-bind nil (string-tail str)) (if (keymapp g-bind) ;; both bindings are keymap (get-editor-command l-bind g-bind (string-tail str)) ;; l-bind is a keymap, so we neglect g-bind (get-editor-command l-bind nil (string-tail str))))) ;; l-bind is a command (if (eq l-bind 'self-insert-command) char l-bind))))) (defun binding-of (char map) "(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 escape-to-emacs (arg &optional char) "(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)) (change-mode-to-emacs) (if char (setq unread-command-char char)) (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) (condition-case nil (setq com (get-editor-command (current-local-map) global-map)) (quit (change-mode-to-vi) (signal 'quit nil))) (if (numberp com) (loop (p-val prefix-arg) (insert-string (char-to-string com))) (condition-case conditions (command-execute com prefix-arg) (quit (message "Quit") (ding)) (error (message-conditions conditions))))) (setq prefix-arg nil) ;; reset prefix arg (if (equal buff (current-buffer)) (change-mode-to-vi)))) (defun message-conditions (conditions) "Print conditions as a message." (let ((case (car conditions)) (msg (cdr conditions))) (if (null msg) (message "%s" case) (message "%s %s" case (prin1-to-string msg))) (ding))) (defun vi-ESC (arg) "" (interactive "P") (escape-to-emacs arg ?\e)) (defun vi-ctl-c (arg) "" (interactive "P") (escape-to-emacs arg ?\C-c)) (defun vi-ctl-x (arg) "" (interactive "P") (escape-to-emacs arg ?\C-x)) (defun vi-ctl-h (arg) "" (interactive "P") (escape-to-emacs arg ?\C-h)) ;; prefix argmument 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". (defun vi-prefix-arg-value (char value com) "(CHAR VALUE COM) Compute numeric prefix arg value. Invoked by CHAR. VALUE is the value obtained so far, and COM is the command part obtained so far." (while (and (>= char ?0) (<= char ?9)) (setq value (+ (* (if (numberp value) value 0) 10) (- char ?0))) (setq char (read-char))) (setq prefix-arg value) (if com (setq prefix-arg (cons prefix-arg com))) (while (= char ?U) (describe-arg prefix-arg) (setq char (read-char))) (setq unread-command-char char)) (defun vi-prefix-arg-com (char value com) "Vi operator as prefix argument." (let ((cont t)) (while (and cont (or (= char ?c) (= char ?d) (= char ?y) (= char ?!) (= char ?<) (= char ?>) (= char ?=) (= char ?#) (= char ?r) (= char ?R) (= 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 (or (= char ?#) (= 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 use-register. ;; if char is !, =, or #, a copmlete com is formed so we exit while. (cond ((or (= char ?!) (= 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)) (setq cont nil)) ((or (= char ?<) (= char ?>)) (setq com char) (setq char (read-char)) (if (= com char) (setq com (cons char com))) (setq cont nil)) ((= char ?\") (let ((reg (read-char))) (if (and (<= ?A reg) (<= reg ?z)) (setq 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 prefix-arg ;; and if char is ?, describe prefix arg, otherwise exit by ;; pushing the char back (progn (setq prefix-arg (cons value com)) (while (= char ?U) (describe-arg prefix-arg) (setq char (read-char))) (setq unread-command-char 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. (let ((char (car com)) (com (cdr com))) (setq prefix-arg (cons value com)) (if (= char ?r) (vi-region prefix-arg) (vi-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 ((equal com '(?c . ?c)) (vi-line (cons value ?C))) ((equal com '(?d . ?d)) (vi-line (cons value ?D))) ((equal com '(?d . ?y)) (vi-yank-defun)) ((equal com '(?y . ?y)) (vi-line (cons value ?Y))) ((equal com '(?< . ?<)) (vi-line (cons value ?<))) ((equal com '(?> . ?>)) (vi-line (cons value ?>))) ((equal com '(?! . ?!)) (vi-line (cons value ?!))) ((equal com '(?= . ?=)) (vi-line (cons value ?=))) (t (error "")))))) (defun describe-arg (arg) (let (val com) (setq val (P-val arg) com (getcom arg)) (if (null val) (if (null com) (message "Value is nil, and commmand 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 vi-digit-argument (arg) "Begin numeric argument for the next command." (interactive "P") (vi-prefix-arg-value last-command-char nil (if (consp arg) (cdr arg) nil))) (defun vi-command-argument (arg) (interactive "P") (vi-prefix-arg-com last-command-char (cond ((null arg) nil) ((consp arg) (car arg)) ((numberp arg) arg) (t (error "strange arg"))) (cond ((null arg) nil) ((consp arg) (cdr arg)) ((numberp arg) nil) (t (error "strange arg"))))) (defun p-val (arg) "(ARG) Get value part of prefix-argument ARG." (cond ((null arg) 1) ((consp arg) (if (null (car arg)) 1 (car arg))) (t arg))) (defun P-val (arg) "(ARG) Get value part of prefix-argument ARG." (cond ((consp arg) (car arg)) (t arg))) (defun getcom (arg) "(ARG) Get com part of prefix-argument ARG." (cond ((null arg) nil) ((consp arg) (cdr arg)) (t nil))) (defun getCom (arg) "(ARG) Get com part of prefix-argument ARG and modify it." (let ((com (getcom arg))) (cond ((equal com ?c) ?C) ((equal com ?d) ?D) ((equal com ?y) ?Y) (t com)))) ;; repeat last destructive command (defun execute-com (m-com val com) "(M-COM VAL COM) Execute command COM. The list (M-COM VAL COM) is set to d-com for later use by execute-d-com" (setq d-com (list m-com val (if (or (= com ?c) (= com ?C) (= com ?!)) (- com) com))) (if com (cond ((= com ?c) (vi-change com-point (point))) ((= com (- ?c)) (vi-change-subr com-point (point))) ((or (= com ?C) (= com (- ?C))) (save-excursion (set-mark com-point) (enlarge-region (mark) (point)) (if use-register (progn (copy-to-register use-register (mark) (point) nil) (setq use-register nil))) (delete-region (mark) (point))) (open-line 1) (if (= com ?C) (change-mode-to-insert) (yank))) ((= com ?d) (if use-register (progn (copy-to-register use-register com-point (point) nil) (setq use-register nil))) (setq last-command (if (eq last-command 'd-command) 'kill-region nil)) (kill-region com-point (point)) (setq this-command 'd-command)) ((= com ?D) (save-excursion (set-mark com-point) (enlarge-region (mark) (point)) (if use-register (progn (copy-to-register use-register (mark) (point) nil) (setq use-register nil))) (setq last-command (if (eq last-command 'D-command) 'kill-region nil)) (kill-region (mark) (point)) (if (eq m-com 'vi-line) (setq this-command 'D-command))) (back-to-indentation)) ((= com ?y) (if use-register (progn (copy-to-register use-register com-point (point) nil) (setq use-register nil))) (setq last-command nil) (copy-region-as-kill com-point (point)) (goto-char com-point)) ((= com ?Y) (save-excursion (set-mark com-point) (enlarge-region (mark) (point)) (if use-register (progn (copy-to-register use-register (mark) (point) nil) (setq use-register nil))) (setq last-command nil) (copy-region-as-kill (mark) (point))) (goto-char com-point)) ((or (= com ?!) (= com (- ?!))) (save-excursion (set-mark com-point) (enlarge-region (mark) (point)) (shell-command-on-region (mark) (point) (if (= com ?!) (setq vi-last-shell-com (vi-read-string "!")) vi-last-shell-com) t))) ((= com ?=) (save-excursion (set-mark com-point) (enlarge-region (mark) (point)) (if (> (mark) (point)) (exchange-point-and-mark)) (indent-region (mark) (point) nil))) ((= com ?<) (save-excursion (set-mark com-point) (enlarge-region (mark) (point)) (indent-rigidly (mark) (point) (- shift-width))) (goto-char com-point)) ((= com ?>) (save-excursion (set-mark com-point) (enlarge-region (mark) (point)) (indent-rigidly (mark) (point) shift-width)) (goto-char com-point)) ((>= com 128) ;; this is special command # (special-prefix-com (- com 128)))))) (defun execute-d-com (arg) "(ARG) Re-excute last destructive command." (interactive "P") (if (eq last-command 'vi-undo) ;; if the last command was vi-undo, then undo-more (vi-undo-more) ;; otherwise execute the command stored in d-com. if arg is non-nil ;; its prefix value is used as new prefix value for the command. (let ((m-com (car d-com)) (val (P-val arg)) (com (car (cdr (cdr d-com))))) (if (null val) (setq val (car (cdr d-com)))) (funcall m-com (cons val com))))) (defun special-prefix-com (char) "This command is invoked interactively by the key sequence #" (cond ((= char ?c) (downcase-region (min com-point (point)) (max com-point (point)))) ((= char ?C) (upcase-region (min com-point (point)) (max com-point (point)))) ((= char ?g) (global-execute (min com-point (point)) (max com-point (point)))) ((= char ?q) (quote-region (min com-point (point)) (max com-point (point)))) ((= char ?s) (vi-spell-region com-point (point))))) (defun vi-spell-region (beg end) (use-global-map emacs-global-map) (condition-case conditions (spell-region beg end) (quit (use-global-map vi-command-mode-map) (signal 'quit nil))) (use-global-map vi-command-mode-map)) ;; undoing (defun vi-undo () "" (interactive) (message "undo!") (undo-start) (undo-more 2) (setq this-command 'vi-undo)) (defun vi-undo-more () "" (message "undo more!") (undo-more 1) (setq this-command 'vi-undo)) ;; redisplay and reset mode (defun vi-recenter (line) (interactive "P") (if (null line) (progn (if (eq current-mode 'vi-mode) (progn (change-mode-to-emacs) (change-mode-to-vi))) (recenter)) (recenter line))) (global-set-key "\^l" 'vi-recenter) ;; utilities (defun string-tail (str) (if (or (null str) (string= str "")) nil (let (val) (save-window-excursion (save-restriction (switch-to-buffer " *working-space*") (set-mark (point)) (insert str) (narrow-to-region (mark) (point)) (setq val (buffer-substring (1+ (mark)) (point))) (delete-region (point-min) (point-max)))) val))) (defun vi-yank-defun () (mark-defun) (copy-region-as-kill (point) (mark))) (defun enlarge-region (beg end) "(BEG END) Enlarge region between BEG and END." (if (< beg end) (progn (goto-char beg) (set-mark end)) (goto-char end) (set-mark beg)) (beginning-of-line) (exchange-point-and-mark) (next-line 1) (beginning-of-line) (if (> beg end) (exchange-point-and-mark))) (defun global-execute (beg end) "Call last keyboad macro for each line in the region." (if (> (point) (mark)) (exchange-point-and-mark)) (beginning-of-line) (call-last-kbd-macro) (while (< (point) (mark)) (forward-line 1) (beginning-of-line) (call-last-kbd-macro))) (defun quote-region (beg end) "Quote region by inserting the user supplied string at the beginning of each line in the region." (setq vi-quote-string (let ((str (vi-read-string (format "quote string \(default \"%s\"\): " vi-quote-string)))) (if (string= str "") vi-quote-string str))) (if (> (point) (mark)) (exchange-point-and-mark)) (beginning-of-line) (insert-string vi-quote-string) (beginning-of-line) (forward-line 1) (while (and (< (point) (mark)) (bolp)) (insert-string vi-quote-string) (beginning-of-line) (forward-line 1))) (defun end-with-a-newline-p (string) "Check if the string ends with a newline." (let (ans) (save-excursion (switch-to-buffer " *working-space*") (set-mark (point)) (insert string) (narrow-to-region (mark) (point)) (setq ans (search-backward "\n" (1- (point)) t)) (widen) (delete-region (point-min) (point-max))) ans)) (defun vi-read-string (prompt &optional init) (use-global-map emacs-global-map) (let (str) (condition-case conditions (setq str (read-string prompt init)) (quit (use-global-map vi-command-mode-map) (signal 'quit nil))) (use-global-map vi-command-mode-map) str)) (defun vi-read-buffer (prompt) (use-global-map emacs-global-map) (let (str) (condition-case conditions (setq str (read-buffer prompt)) (quit (use-global-map vi-command-mode-map) (signal 'quit nil))) (use-global-map vi-command-mode-map) str)) (defun vi-read-file-name (prompt) (use-global-map emacs-global-map) (let (str) (condition-case conditions (setq str (read-file-name prompt)) (quit (use-global-map vi-command-mode-map) (signal 'quit nil))) (use-global-map vi-command-mode-map) str)) ;; insertion commands (defun repeat-insert-command () "() This function is called when mode changes from insertion mode to vi command mode. It will repeat the insertion command if original insertion command was invoked with argument > 1." (let ((i-com (car d-com)) (val (car (cdr d-com)))) (if (> val 1) (progn (setq d-com (list i-com (1- val) ?r)) (execute-d-com nil) (setq d-com (list i-com val ?r)))))) (defun vi-insert (arg) "" (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (setq d-com (list 'vi-insert val ?r)) (if com (loop val (yank)) (change-mode-to-insert)))) (defun vi-append (arg) "" (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (setq d-com (list 'vi-append val ?r)) (if (not (eolp)) (forward-char)) (if (equal com ?r) (loop val (yank)) (change-mode-to-insert)))) (defun vi-Append (arg) "" (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (setq d-com (list 'vi-Append val ?r)) (end-of-line) (if (equal com ?r) (loop val (yank)) (change-mode-to-insert)))) (defun vi-Insert (arg) "" (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (setq d-com (list 'vi-Insert val ?r)) (back-to-indentation) (if (equal com ?r) (loop val (yank)) (change-mode-to-insert)))) (defun vi-open-line (arg) "" (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (setq d-com (list 'vi-open-line val ?r)) (let ((col (current-indentation))) (if (equal com ?r) (loop val (progn (end-of-line) (newline 1) (indent-to col) (yank))) (end-of-line) (newline 1) (indent-to col) (change-mode-to-insert))))) (defun vi-Open-line (arg) "" (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (setq d-com (list 'vi-Open-line val ?r)) (let ((col (current-indentation))) (if (equal com ?r) (loop val (progn (beginning-of-line) (open-line 1) (indent-to col) (yank))) (beginning-of-line) (open-line 1) (indent-to col) (change-mode-to-insert))))) (defun vi-ctl-open-line (arg) (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (setq d-com (list 'vi-ctl-open-line val ?r)) (if (equal com ?r) (loop val (progn (open-line 1) (yank))) (open-line 1) (change-mode-to-insert)))) (defun vi-substitute (arg) (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (save-excursion (set-mark (point)) (forward-char val) (if (equal com ?r) (vi-change-subr (mark) (point)) (vi-change (mark) (point)))) (setq d-com (list 'vi-substitute val ?r)))) (defun vi-substitute-line (arg) (interactive "p") (vi-line (cons arg ?C))) ;; selecting windows (defun vi-next-window (arg) (interactive "p") (change-mode-to-emacs) (other-window (if (null arg) 1 arg)) (if (not (string= (buffer-name (current-buffer)) " *Minibuf-1*")) (change-mode-to-vi))) (defun vi-other-window (arg) (interactive "p") (change-mode-to-emacs) (other-window (if (null arg) 1 arg))) ;; line command (defun vi-line (arg) (let ((val (car arg)) (com (cdr arg))) (move-marker com-point (point)) (next-line (1- val)) (execute-com 'vi-line val com))) (defun vi-yank-line (arg) "(ARG) Yank ARG lines (in vi's sense)" (interactive "P") (let ((val (p-val arg))) (vi-line (cons val ?Y)))) ;; region command (defun vi-region (arg) (interactive "P") (let ((val (P-val arg)) (com (getcom arg))) (move-marker com-point (mark)) (execute-com 'vi-region val com))) (defun vi-Region (arg) (interactive "P") (let ((val (P-val arg)) (com (getCom arg))) (move-marker com-point (point)) (execute-com 'vi-Region val com))) (defun vi-replace-char (arg) "(ARG) Replace the following ARG chars by the character read." (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (setq d-com (list 'vi-replace-char val ?r)) (vi-replace-char-subr (if (equal com ?r) d-char (read-char)) val))) (defun vi-replace-char-subr (char arg) (delete-char arg t) (setq d-char char) (loop (if (> arg 0) arg (- arg)) (insert char)) (backward-char arg)) (defun vi-replace-string () "() Replace string. If you supply null string as the string to be replaced, the query replace mode will toggle between string replace and regexp replace." (interactive) (let (str) (setq str (vi-read-string (if re-replace "Replace regexp: " "Replace string: "))) (if (string= str "") (progn (setq re-replace (not re-replace)) (message (format "Replace mode changed to %s." (if re-replace "regexp replace" "string replace")))) (if re-replace (replace-regexp str (vi-read-string (format "Replace regexp \"%s\" with: " str))) (replace-string str (vi-read-string (format "Replace \"%s\" with: " str))))))) ;; basic cursor movement. j, k, l, m commands. (defun vi-forward-char (arg) "(ARG) Move point right ARG characters (left if ARG negative). On reaching end of buffer, stop and signal error." (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (if com (move-marker com-point (point))) (forward-char val) (if com (execute-com 'vi-forward-char val com)))) (defun vi-backward-char (arg) "(ARG) Move point left ARG characters (right if ARG negative). On reaching end of buffer, stop and signal error." (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (if com move-marker com-point (point)) (backward-char val) (if com (execute-com 'vi-backward-char val com)))) ;; word command (defun vi-forward-word (arg) "" (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (if com (move-marker com-point (point))) (forward-word val) (skip-chars-forward " \t\n") (if com (progn (if (or (= com ?c) (= com (- ?c))) (progn (backward-word 1) (forward-word 1))) (if (or (= com ?d) (= com ?y)) (progn (backward-word 1) (forward-word 1) (skip-chars-forward " \t"))) (execute-com 'vi-forward-word val com))))) (defun vi-end-of-word (arg) (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (if com (move-marker com-point (point))) (forward-char) (forward-word val) (backward-char) (if com (progn (forward-char) (execute-com 'vi-end-of-word val com))))) (defun vi-backward-word (arg) "" (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (if com (move-marker com-point (point))) (backward-word val) (if com (execute-com 'vi-backward-word val com)))) (defun vi-forward-Word (arg) "" (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (if com (move-marker com-point (point))) (re-search-forward "[^ \t\n]*[ \t\n]+" nil t val) (if com (progn (if (or (= com ?c) (= com (- ?c))) (progn (backward-word 1) (forward-word 1))) (if (or (= com ?d) (= com ?y)) (progn (backward-word 1) (forward-word 1) (skip-chars-forward " \t"))) (execute-com 'vi-forward-Word val com))))) (defun vi-end-of-Word (arg) "" (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (if com (move-marker com-point (point))) (forward-char) (if (re-search-forward "[^ \t\n]+" nil t val) (backward-char)) (if com (progn (forward-char) (execute-com 'vi-end-of-Word val com))))) (defun vi-backward-Word (arg) "" (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (if com (move-marker com-point (point))) (if (re-search-backward "[ \t\n]+[^ \t\n]+" nil t val) (forward-char) (goto-char (point-min))) (if com (execute-com 'vi-backward-Word val com)))) (defun vi-beginning-of-line (arg) (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (if com (move-marker com-point (point))) (beginning-of-line val) (if com (execute-com 'vi-beginning-of-line val com)))) (defun vi-bol-and-skip-white (arg) (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (if com (move-marker com-point (point))) (back-to-indentation) (if com (execute-com 'vi-bol-and-skip-white val com)))) (defun vi-goto-eol (arg) (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (if com (move-marker com-point (point))) (end-of-line val) (if com (execute-com 'vi-goto-eol val com)))) (defun vi-next-line (arg) (interactive "P") (let ((val (p-val arg)) (com (getCom arg))) (if com (move-marker com-point (point))) (next-line val) (setq this-command 'next-line) (if com (execute-com 'vi-next-line val com)))) (defun vi-next-line-at-bol (arg) (interactive "P") (let ((val (p-val arg)) (com (getCom arg))) (if com (move-marker com-point (point))) (next-line val) (back-to-indentation) (if com (execute-com 'vi-next-line-at-bol val com)))) (defun vi-previous-line (arg) (interactive "P") (let ((val (p-val arg)) (com (getCom arg))) (if com (move-marker com-point (point))) (next-line (- val)) (setq this-command 'previous-line) (if com (execute-com 'vi-previous-line val com)))) (defun vi-previous-line-at-bol (arg) (interactive "P") (let ((val (p-val arg)) (com (getCom arg))) (if com (move-marker com-point (point))) (next-line (- val)) (back-to-indentation) (if com (execute-com 'vi-previous-line val com)))) (defun vi-change-to-eol (arg) (interactive "P") (vi-goto-eol (cons arg ?c))) (defun vi-kill-line (arg) (interactive "P") (vi-goto-eol (cons arg ?d))) ;; moving around (defun vi-G (arg) (interactive "P") (let ((val (P-val arg)) (com (getCom arg))) (move-marker com-point (point)) (set-mark (point)) (if (null val) (goto-char (point-max)) (goto-char (point-min)) (forward-line (1- val))) (back-to-indentation) (if com (execute-com 'vi-G val com)))) (defun vi-find-char (arg char forward offset) "(ARG CHAR FORWARD OFFSET) Find ARG's occurence of CHAR on the current line. If FORWARD then search is forward, otherwise bacekward. OFFSET is used to adjust point after search." (let ((arg (if forward arg (- arg))) point) (save-excursion (save-restriction (if (> arg 0) (narrow-to-region ;; forward search begins here (if (eolp) (error "") (point)) ;; forward search ends here (progn (next-line 1) (beginning-of-line) (point))) (narrow-to-region ;; backward search begins from here (if (bolp) (error "") (point)) ;; backward search ends here (progn (beginning-of-line) (point)))) ;; if arg > 0, point is forwarded before search. (if (> arg 0) (goto-char (1+ (point-min))) (goto-char (point-max))) (setq point (scan-buffer (point) arg char)) (if (or (and (> arg 0) (= point (point-max))) (and (< arg 0) (= point (point-min)))) (error "")))) (goto-char (+ point (if offset (if (> arg 0) -2 0) -1))))) (defun vi-f (arg) "(ARG) Find char on the line. If called interactively read the char to find from the terminal, and if called from execute-d-com, the char last used is used. This behaviour is controlled by the sign of prefix numeric value." (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (if (> val 0) ;; this means that the function was called interactively (setq f-char (read-char) f-forward t f-offset nil) (setq val (- val))) (if com (move-marker com-point (point))) (vi-find-char val f-char t nil) (setq val (- val)) (if com (progn (forward-char) (execute-com 'vi-f val com))))) (defun vi-t (arg) "" (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (if (> val 0) ;; this means that the function was called interactively (setq f-char (read-char) f-forward t f-offset nil) (setq val (- val))) (if com (move-marker com-point (point))) (vi-find-char val f-char t t) (setq val (- val)) (if com (progn (forward-char) (execute-com 'vi-t val com))))) (defun vi-F (arg) "" (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (if (> val 0) ;; this means that the function was called interactively (setq f-char (read-char) f-forward t f-offset nil) (setq val (- val))) (if com (move-marker com-point (point))) (vi-find-char val f-char nil nil) (setq val (- val)) (if com (execute-com 'vi-F val com)))) (defun vi-T (arg) "" (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (if (> val 0) ;; this means that the function was called interactively (setq f-char (read-char) f-forward t f-offset nil) (setq val (- val))) (if com (move-marker com-point (point))) (vi-find-char val f-char nil t) (setq val (- val)) (if com (execute-com 'vi-T val com)))) (defun vi-semi-colon (arg) "" (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (if com (move-marker com-point (point))) (vi-find-char val f-char f-forward f-offset) (if com (progn (if f-forward (forward-char)) (execute-com 'vi-semi-colon val com))))) (defun vi-comma (arg) "" (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (if com (move-marker com-point (point))) (vi-find-char val f-char (not f-forward) f-offset) (if com (progn (if f-forward (forward-char)) (execute-com 'vi-comma val com))))) ;; window scrolling etc. (defun vi-window-top (arg) "" (interactive "P") (let ((val (p-val arg)) (com (getCom arg))) (if com (move-marker com-point (point))) (move-to-window-line (1- val)) (if com (execute-com 'vi-window-top val com)))) (defun vi-window-middle (arg) "" (interactive "P") (let ((val (p-val arg)) (com (getCom arg))) (if com (move-marker com-point (point))) (move-to-window-line (+ (/ (1- (window-height)) 2) (1- val))) (if com (execute-com 'vi-window-middle val com)))) (defun vi-window-bottom (arg) "" (interactive "P") (let ((val (p-val arg)) (com (getCom arg))) (if com (move-marker com-point (point))) (move-to-window-line (- val)) (if com (execute-com 'vi-window-bottom val com)))) (defun vi-line-to-top (arg) "" (interactive "p") (recenter (1- arg))) (defun vi-line-to-middle (arg) "" (interactive "p") (recenter (+ (1- arg) (/ (1- (window-height)) 2)))) (defun vi-line-to-bottom (arg) "" (interactive "p") (recenter (- (window-height) (1+ arg)))) ;; paren match (defun vi-paren-match (arg) "(ARG) Go to the matching parenthesis." (interactive "P") (let ((com (getcom arg))) (cond ((looking-at "[\(\[{]") (if com (move-marker com-point (point))) (forward-sexp 1) (if com (execute-com 'vi-paren-match nil com) (backward-char))) ((looking-at "[])}]") (forward-char) (if com (move-marker com-point (point))) (backward-sexp 1) (if com (execute-com 'vi-paren-match nil com))) (t (error ""))))) ;; sentence and paragraph (defun vi-forward-sentence (arg) (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (if com (move-marker com-point (point))) (forward-sentence val) (if com (execute-com 'vi-forward-sentence nil com)))) (defun vi-backward-sentence (arg) (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (if com (move-marker com-point (point))) (backward-sentence val) (if com (execute-com 'vi-backward-sentence nil com)))) (defun vi-forward-paragraph (arg) (interactive "P") (let ((val (p-val arg)) (com (getCom arg))) (if com (move-marker com-point (point))) (forward-paragraph val) (if com (execute-com 'vi-forward-paragraph nil com)))) (defun vi-backward-paragraph (arg) (interactive "P") (let ((val (p-val arg)) (com (getCom arg))) (if com (move-marker com-point (point))) (backward-paragraph val) (if com (execute-com 'vi-backward-paragraph nil com)))) ;; scrolling (defun vi-scroll (arg) "" (interactive "p") (if (> arg 0) (while (> arg 0) (scroll-up) (setq arg (1- arg))) (while (> 0 arg) (scroll-down) (setq arg (1+ arg))))) (defun vi-scroll-back (arg) "" (interactive "p") (vi-scroll (- arg))) (defun vi-scroll-down (arg) "" (interactive "P") (if (null arg) (scroll-down (/ (window-height) 2)) (scroll-down arg))) (defun vi-scroll-down-one (arg) "" (interactive "p") (scroll-down arg)) (defun vi-scroll-up (arg) "" (interactive "P") (if (null arg) (scroll-up (/ (window-height) 2)) (scroll-up arg))) (defun vi-scroll-up-one (arg) "" (interactive "p") (scroll-up arg)) ;; splitting window (defun buffer-in-two-windows () (interactive) (delete-other-windows) (split-window-vertically nil)) ;; searching (defun vi-search-forward (arg) "(ARG) Search a string forward. ARG is used to find the ARG's occurence of the string. Default is vanilla search. Search mode can be toggled by giving null search string." (interactive "P") (let ((val (P-val arg)) (com (getcom arg))) (setq s-forward t s-string (vi-read-string (if re-search "RE-/" "/"))) (if (string= s-string "") (progn (setq re-search (not re-search)) (message (format "Search mode changed to %s search." (if re-search "regular expression" "vanilla")))) (vi-search s-string t val) (if com (progn (move-marker com-point (mark)) (execute-com 'vi-n val com)))))) (defun vi-search-backward (arg) "(ARG) Search a string backward. ARG is used to find the ARG's occurence of the string. Default is vanilla search. Search mode can be toggled by giving null search string." (interactive "P") (let ((val (P-val arg)) (com (getcom arg))) (setq s-forward nil s-string (vi-read-string (if re-search "RE-?" "?"))) (if (string= s-string "") (progn (setq re-search (not re-search)) (message (format "Search mode changed to %s search." (if re-search "regular expression" "vanilla")))) (vi-search s-string nil val) (if com (progn (move-marker com-point (mark)) (execute-com 'vi-n val com)))))) (defun vi-search (string forward arg &optional no-offset init-point) "(STRING FORWARD COUNT &optional NO-OFFSET) Search COUNT's occurrence of STRING. Search will be forward if FORWARD, otherwise backward." (let ((val (p-val arg)) (com (getcom arg)) (null-arg (null (P-val arg))) (offset (not no-offset)) (case-fold-search vi-case-fold-search) start-point) (setq start-point (if init-point init-point (point))) (if forward (condition-case conditions (progn (if (and offset (not (eobp))) (forward-char)) (if re-search (progn (re-search-forward string nil nil val) (re-search-backward string)) (search-forward string nil nil val) (search-backward string)) (push-mark start-point)) (search-failed (if (and null-arg vi-search-wrap-around) (progn (goto-char (point-min)) (vi-search string forward (cons 1 com) t start-point)) (goto-char start-point) (signal 'search-failed (cdr conditions))))) (condition-case conditions (progn (if re-search (re-search-backward string nil nil val) (search-backward string nil nil val)) (push-mark start-point)) (search-failed (if (and null-arg vi-search-wrap-around) (progn (goto-char (point-max)) (vi-search string forward (cons 1 com) t start-point)) (goto-char start-point) (signal 'search-failed (cdr conditions)))))))) (defun vi-isearch (arg) "(ARG) Primitive incremental search. Last serch string is provided, which you can edit and submit again. Given ARG, search ARG's occurnece." (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (setq s-string (vi-read-string (if s-forward (if re-search "RE-/" "/") (if re-search "RE-?" "?")) s-string)) (vi-search s-string s-forward val) (if com (execute-com 'vi-n val com)))) (defun vi-n (arg) (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (if (null s-string) (error "No previous search string.")) (vi-search s-string s-forward arg) (if com (execute-com 'vi-n val com)))) (defun vi-N (arg) (interactive "P") (let ((val (p-val arg)) (com (getcom arg))) (if (null s-string) (error "No previous search string.")) (vi-search s-string (not s-forward) arg) (if com (execute-com 'vi-N val com)))) ;; visiting and killing files, buffers (defun vi-switch-to-buffer () (interactive) (let (buffer) (setq buffer (vi-read-buffer (format "switch to buffer \(%s\): " (buffer-name (other-buffer (current-buffer)))))) (change-mode-to-emacs) (switch-to-buffer buffer) (change-mode-to-vi))) (defun vi-switch-to-buffer-other-window () (interactive) (let (buffer) (setq buffer (vi-read-buffer (format "Switch to buffer \(%s\): " (buffer-name (other-buffer (current-buffer)))))) (change-mode-to-emacs) (switch-to-buffer-other-window buffer) (change-mode-to-vi))) (defun vi-kill-buffer () (interactive) (let (buffer buffer-name) (setq buffer-name (vi-read-buffer (format "Kill buffer \(%s\): " (buffer-name (current-buffer))))) (setq buffer (if (null buffer-name) (current-buffer) (get-buffer buffer-name))) (if (null buffer) (error "Buffer %s nonexistent." buffer-name)) (if (buffer-modified-p buffer) (error "I can't kill modified buffer.") (if (equal buffer (current-buffer)) (progn (change-mode-to-emacs) (kill-buffer buffer) (change-mode-to-vi)) (kill-buffer buffer))))) (defun vi-find-file () (interactive) (let (file) (setq file (vi-read-file-name "visit file: ")) (change-mode-to-emacs) (switch-to-buffer (find-file-noselect file)) (change-mode-to-vi))) (defun vi-find-file-other-window () (interactive) (let (file) (setq file (vi-read-file-name "Visit file: ")) (change-mode-to-emacs) (switch-to-buffer-other-window (find-file-noselect file)) (change-mode-to-vi))) (defun vi-insert-file () (interactive) (let (file) (setq file (vi-read-file-name "insert file: ")) (change-mode-to-emacs) (insert-file file) (change-mode-to-vi))) (defun vi-write-file () (interactive) (write-file (vi-read-file-name "write file: "))) (defun vi-info-on-file () (interactive) (message "\"%s\" line %d of %d" (if (buffer-file-name) (buffer-file-name) "") (1+ (count-lines (point-min) (point))) (1+ (count-lines (point-min) (point-max))))) ;; modifying buffer (defun vi-undo () "" (interactive) (message "undo!") (undo-start) (undo-more 2) (setq this-command 'vi-undo)) (defun vi-undo-more () "" (message "undo more!") (undo-more 1) (setq this-command 'vi-undo)) ;; yank and pop (defun vi-yank () "yank first element of kill-ring silently." (save-excursion (push-mark-silent (point)) (insert (car kill-ring-yank-pointer)) (exchange-point-and-mark)) (skip-chars-forward " \t")) (defun vi-p (arg) (interactive "P") (let ((val (p-val arg))) (setq d-com (list 'vi-p val nil)) (if (end-with-a-newline-p (car kill-ring-yank-pointer)) (progn (next-line 1) (beginning-of-line)) (if (and (not (eolp)) (not (eobp))) (forward-char))) (if use-register (progn (insert-register use-register) (setq use-register nil)) (loop val (vi-yank))))) (defun vi-P (arg) (interactive "P") (let ((val (p-val arg))) (setq d-com (list 'vi-P val nil)) (if (end-with-a-newline-p (car kill-ring-yank-pointer)) (beginning-of-line)) (if use-register (progn (insert-register use-register) (setq use-register nil)) (loop val (vi-yank))))) (defun vi-delete-char (arg) (interactive "P") (let ((val (p-val arg))) (setq d-com (list 'vi-delete-char val nil)) (delete-char val t))) (defun vi-delete-backward-char (arg) (interactive "P") (let ((val (p-val arg))) (setq d-com (list 'vi-delete-backward-char val nil)) (delete-backward-char val t))) ;; join lines. (defun vi-join-lines (arg) "(ARG) Join this line to next, if ARG is nil. Otherwise, join ARG lines" (interactive "*P") (let ((val (P-val arg))) (setq d-com (list 'vi-join-lines val nil)) (loop (if (null val) 1 (1- val)) (progn (beginning-of-line) (forward-line 1) (delete-region (point) (1- (point))) (fixup-whitespace))))) ;; making small changes (defun vi-change (beg end) (setq c-string (vi-read-string (format "%s => " (buffer-substring beg end)))) (vi-change-subr beg end)) (defun vi-change-subr (beg end) (if use-register (progn (copy-to-register use-register beg end nil) (setq use-register nil))) (kill-region beg end) (setq this-command 'vi-change) (insert-string c-string)) ;; query replace (defun vi-query-replace () "() Query replace. If you supply null string as the string to be replaced, the query replace mode will toggle between string replace and regexp replace." (interactive) (let (str) (setq str (vi-read-string (if re-query-replace "Query replace regexp: " "Query replace: "))) (if (string= str "") (progn (setq re-query-replace (not re-query-replace)) (message "Query replace mode changed to %s." (if re-query-replace "regexp replace" "string replace"))) (if re-query-replace (query-replace-regexp str (vi-read-string (format "Query replace regexp \"%s\" with: " str))) (query-replace str (vi-read-string (format "Query replace \"%s\" with: " str))))))) ;; marking (defun vi-mark-beginning-of-buffer () (interactive) (set-mark (point)) (goto-char (point-min)) (exchange-point-and-mark) (message "mark set at the beginning of buffer")) (defun vi-mark-end-of-buffer () (interactive) (set-mark (point)) (goto-char (point-max)) (exchange-point-and-mark) (message "mark set at the end of buffer")) (defun vi-mark-point (char) (interactive "c") (cond ((and (<= ?a char) (<= char ?z)) (point-to-register (- char (- ?a ?\C-a)))) ((= char ?<) (vi-mark-beginning-of-buffer)) ((= char ?>) (vi-mark-end-of-buffer)) ((= char ?.) (push-mark)) ((= char ?,) (set-mark-command 1)) ((= char ?D) (mark-defun)) (t (error "")))) (defun vi-goto-mark (arg) (interactive "P") (let ((char (read-char)) (com (getcom arg))) (vi-goto-mark-subr char com nil))) (defun vi-goto-mark-and-skip-white (arg) (interactive "P") (let ((char (read-char)) (com (getCom arg))) (vi-goto-mark-subr char com t))) (defun vi-goto-mark-subr (char com skip-white) (cond ((and (<= ?a char) (<= char ?z)) (let ((buff (current-buffer))) (if com (move-marker com-point (point))) (change-mode-to-emacs) (goto-char (register-to-point (- char (- ?a ?\C-a)))) (if skip-white (back-to-indentation)) (change-mode-to-vi) (if com (if (equal buff (current-buffer)) (execute-com (if skip-white 'vi-goto-mark-and-skip-white 'vi-goto-mark) nil com) (change-mode-to-emacs) (switch-to-buffer buff) (goto-char com-point) (change-mode-to-vi) (error ""))))) ((and (not skip-white) (= char ?`)) (if com (move-marker com-point (point))) (exchange-point-and-mark) (if com (execute-com 'vi-goto-mark nil com))) ((and skip-white (= char ?')) (if com (move-marker com-point (point))) (exchange-point-and-mark) (back-to-indentation) (if com (execute-com 'vi-goto-mark-and-skip-white nil com))) (t (error "")))) (defun vi-exchange-point-and-mark () (interactive) (exchange-point-and-mark) (back-to-indentation)) ;; commands in insertion mode (defun delete-backward-word (arg) (interactive "p") (save-excursion (set-mark (point)) (backward-word arg) (delete-region (point) (mark)))) ;; key bindings (set 'vi-command-mode-map (make-keymap)) (define-key vi-command-mode-map "\e" 'vi-ESC) (define-key vi-command-mode-map "+" 'vi-next-line-at-bol) (define-key vi-command-mode-map "-" 'vi-previous-line-at-bol) (define-key vi-command-mode-map "0" 'vi-beginning-of-line) (define-key vi-command-mode-map "1" 'vi-digit-argument) (define-key vi-command-mode-map "2" 'vi-digit-argument) (define-key vi-command-mode-map "3" 'vi-digit-argument) (define-key vi-command-mode-map "4" 'vi-digit-argument) (define-key vi-command-mode-map "5" 'vi-digit-argument) (define-key vi-command-mode-map "6" 'vi-digit-argument) (define-key vi-command-mode-map "7" 'vi-digit-argument) (define-key vi-command-mode-map "8" 'vi-digit-argument) (define-key vi-command-mode-map "9" 'vi-digit-argument) (define-key vi-command-mode-map "\^a" 'beginning-of-line) (define-key vi-command-mode-map "\^b" 'vi-scroll-back) (define-key vi-command-mode-map "\^c" 'vi-ctl-c) (define-key vi-command-mode-map "\^d" 'vi-scroll-up) (define-key vi-command-mode-map "\^e" 'vi-scroll-up-one) (define-key vi-command-mode-map "\^f" 'vi-scroll) (define-key vi-command-mode-map "\^g" 'vi-info-on-file) (define-key vi-command-mode-map "\^h" 'vi-backward-char) (define-key vi-command-mode-map "\^l" 'vi-recenter) (define-key vi-command-mode-map "\^m" 'vi-next-line-at-bol) (define-key vi-command-mode-map "\^n" 'vi-next-window) (define-key vi-command-mode-map "\^o" 'vi-ctl-open-line) (define-key vi-command-mode-map "\^s" 'suspend-emacs) (define-key vi-command-mode-map "\^u" 'vi-scroll-down) (define-key vi-command-mode-map "\^x" 'vi-ctl-x) (define-key vi-command-mode-map "\^y" 'vi-scroll-down-one) (define-key vi-command-mode-map "\^z" 'change-mode-to-emacs) (define-key vi-command-mode-map ":" 'vi-isearch) (define-key vi-command-mode-map "." 'execute-d-com) (define-key vi-command-mode-map " " 'vi-forward-char) (define-key vi-command-mode-map "|" 'vi-goto-col) (define-key vi-command-mode-map ";" 'vi-semi-colon) (define-key vi-command-mode-map "," 'vi-comma) (define-key vi-command-mode-map "%" 'vi-paren-match) (define-key vi-command-mode-map "}" 'vi-forward-paragraph) (define-key vi-command-mode-map "{" 'vi-backward-paragraph) (define-key vi-command-mode-map ")" 'vi-forward-sentence) (define-key vi-command-mode-map "(" 'vi-backward-sentence) (define-key vi-command-mode-map "^" 'vi-bol-and-skip-white) (define-key vi-command-mode-map "$" 'vi-goto-eol) (define-key vi-command-mode-map "`" 'vi-goto-mark) (define-key vi-command-mode-map "'" 'vi-goto-mark-and-skip-white) (define-key vi-command-mode-map "\"" 'vi-command-argument) (define-key vi-command-mode-map "/" 'vi-search-forward) (define-key vi-command-mode-map "\\" 'escape-to-emacs) (define-key vi-command-mode-map "?" 'vi-search-backward) (define-key vi-command-mode-map "#" 'vi-command-argument) (define-key vi-command-mode-map "*" 'call-last-kbd-macro) (define-key vi-command-mode-map "!" 'vi-command-argument) (define-key vi-command-mode-map "=" 'vi-command-argument) (define-key vi-command-mode-map "<" 'vi-command-argument) (define-key vi-command-mode-map ">" 'vi-command-argument) (define-key vi-command-mode-map "a" 'vi-append) (define-key vi-command-mode-map "b" 'vi-backward-word) (define-key vi-command-mode-map "c" 'vi-command-argument) (define-key vi-command-mode-map "d" 'vi-command-argument) (define-key vi-command-mode-map "e" 'vi-end-of-word) (define-key vi-command-mode-map "f" 'vi-f) (define-key vi-command-mode-map "g" 'keyboard-quit) (define-key vi-command-mode-map "h" 'vi-backward-char) (define-key vi-command-mode-map "i" 'vi-insert) (define-key vi-command-mode-map "j" 'vi-next-line) (define-key vi-command-mode-map "k" 'vi-previous-line) (define-key vi-command-mode-map "l" 'vi-forward-char) (define-key vi-command-mode-map "m" 'vi-mark-point) (define-key vi-command-mode-map "n" 'vi-n) (define-key vi-command-mode-map "o" 'vi-open-line) (define-key vi-command-mode-map "p" 'vi-p) (define-key vi-command-mode-map "r" 'vi-replace-char) (define-key vi-command-mode-map "s" 'vi-substitute) (define-key vi-command-mode-map "t" 'vi-t) (define-key vi-command-mode-map "u" 'vi-undo) (define-key vi-command-mode-map "v" 'vi-find-file) (define-key vi-command-mode-map "w" 'vi-forward-word) (define-key vi-command-mode-map "x" 'vi-delete-char) (define-key vi-command-mode-map "y" 'vi-command-argument) (define-key vi-command-mode-map "zH" 'vi-line-to-top) (define-key vi-command-mode-map "zM" 'vi-line-to-middle) (define-key vi-command-mode-map "zL" 'vi-line-to-bottom) (define-key vi-command-mode-map "z\^m" 'vi-line-to-top) (define-key vi-command-mode-map "z+" 'vi-line-to-top) (define-key vi-command-mode-map "z." 'vi-line-to-middle) (define-key vi-command-mode-map "z-" 'vi-line-to-bottom) (define-key vi-command-mode-map "A" 'vi-Append) (define-key vi-command-mode-map "B" 'vi-backward-Word) (define-key vi-command-mode-map "C" 'vi-change-to-eol) (define-key vi-command-mode-map "D" 'vi-kill-line) (define-key vi-command-mode-map "E" 'vi-end-of-Word) (define-key vi-command-mode-map "F" 'vi-F) (define-key vi-command-mode-map "G" 'vi-G) (define-key vi-command-mode-map "H" 'vi-window-top) (define-key vi-command-mode-map "I" 'vi-Insert) (define-key vi-command-mode-map "J" 'vi-join-lines) (define-key vi-command-mode-map "K" 'vi-kill-buffer) (define-key vi-command-mode-map "L" 'vi-window-bottom) (define-key vi-command-mode-map "M" 'vi-window-middle) (define-key vi-command-mode-map "N" 'vi-N) (define-key vi-command-mode-map "O" 'vi-Open-line) (define-key vi-command-mode-map "P" 'vi-P) (define-key vi-command-mode-map "Q" 'vi-query-replace) (define-key vi-command-mode-map "R" 'vi-replace-string) (define-key vi-command-mode-map "S" 'vi-substitute-line) (define-key vi-command-mode-map "T" 'vi-T) (define-key vi-command-mode-map "V" 'vi-find-file-other-window) (define-key vi-command-mode-map "W" 'vi-forward-Word) (define-key vi-command-mode-map "X" 'vi-delete-backward-char) (define-key vi-command-mode-map "Y" 'vi-yank-line) (define-key vi-command-mode-map "ZZ" 'save-buffers-kill-emacs) (define-key vi-command-mode-map "\177" 'vi-delete-backward-char) ;; set up local keymap for various major modes. (defun make-vi-local-map (mode) (set 'vi-local-map '(keymap)) (cond ((eq mode 'shell-mode) (define-key vi-local-map "\C-m" 'vi-shell-send-input) (define-key vi-local-map "\C-p" 'copy-previous-shell-input)) ((eq mode 'rmail-mode) (define-key vi-local-map "q" 'vi-rmail-quit)) (t (setq vi-local-map '(keymap))))) (defun vi-rmail-quit () (interactive) (change-mode-to-emacs) (rmail-quit)) ;; command for shell mode. (defun vi-shell-send-input () (interactive) (end-of-line) (shell-send-input)) (defvar vi-shell-previous-input-point nil) (defun copy-previous-shell-input (arg) "Copy previous shell input. If ARG, ARG'th previous shell input will be copied. Repeated application of this command continue to get older input." (interactive "p") (delete-region (point) (point-max)) (save-excursion (if (eq last-command 'copy-previous-shell-input) (goto-char vi-shell-previous-input-point) (beginning-of-line)) (if (re-search-backward shell-prompt-pattern nil t arg) (progn (setq vi-shell-previous-input-point (point)) (re-search-forward shell-prompt-pattern nil t) (let ((copy (buffer-substring (point) (progn (end-of-line) (point))))) (goto-char (point-max)) (insert copy))) (error "No more previous shell command.")))) (defun vip-version () (interactive) (message "VIP version 17.1 of July 23, 1986")) (if (file-exists-p "~/.vip") (load "~/.vip"))