📄 vip.el
字号:
;; VIP: A VI Package for GNU Emacs (version 3.5 of September 15, 1987);; Author: Masahiko Sato (ms@sail.stanford.edu). In Japan, the author's;; address is: masahiko@sato.riec.tohoku.junet;; Send suggestions and bug reports to one of the above addresses.;; When you report a bug, be sure to include the version number of VIP and;; Emacs you are using.;; Execute info command by typing "M-x info" to get information on VIP.;; external variables(defvar vip-emacs-local-map nil "Local map used in emacs mode. \(buffer specific\)")(defvar vip-insert-local-map nil "Local map used in insert command mode. \(buffer specific\)") (make-variable-buffer-local 'vip-emacs-local-map)(make-variable-buffer-local 'vip-insert-local-map)(defvar vip-insert-point nil "Remember insert point as a marker. \(buffer specific\)")(set-default 'vip-insert-point (make-marker))(make-variable-buffer-local 'vip-insert-point)(defvar vip-com-point nil "Remember com point as a marker. \(buffer specific\)")(set-default 'vip-com-point (make-marker))(make-variable-buffer-local 'vip-com-point)(defvar vip-current-mode nil "Current mode. One of emacs-mode, vi-mode, insert-mode.")(make-variable-buffer-local 'vip-current-mode)(setq-default vip-current-mode 'emacs-mode)(defvar vip-emacs-mode-line-buffer-identification nil "value of mode-line-buffer-identification in emacs-mode.")(make-variable-buffer-local 'vip-emacs-mode-line-buffer-identification)(setq-default vip-emacs-mode-line-buffer-identification '("Emacs: %17b"))(defvar vip-current-major-mode nil "vip-current-major-mode is the major-mode vi considers it is now.\(buffer specific\)")(make-variable-buffer-local 'vip-current-major-mode)(defvar vip-last-shell-com nil "last shell command executed by ! command")(defvar vip-use-register nil "name of register to store deleted or yanked strings.")(defvar vip-d-com nil "If non-nil, it's value is a list (M-COM VAL COM), and is used tore-execute last destrcutive command")(defconst vip-shift-width 8 "*The number of colums shifted by > and < command.")(defconst vip-re-replace nil "*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")(defvar vip-f-char nil "for use by \";\" command")(defvar vip-F-char nil "for use by \".\" command")(defvar vip-f-forward nil "for use by \";\" command") (defvar vip-f-offset nil "for use by \";\" command")(defconst vip-search-wrap-around t "*if t, search wraps around")(defconst vip-re-search nil "*if t, search is reg-exp search, otherwise vanilla search.")(defvar vip-s-string nil "last search string")(defvar vip-s-forward nil "if t, search is forward.")(defconst vip-case-fold-search nil "*if t, search ignores cases.")(defconst vip-re-query-replace nil "*If t then do regexp replace, if nil then do string replace.")(defconst vip-open-with-indent nil "*if t, indent when open a new line.")(defconst vip-help-in-insert-mode nil "*if t then C-h is bound to help-command in insert mode, if nil then it isbound to delete-backward-char.")(defvar vip-quote-string "> " "string inserted at the beginning of region")(defvar vip-tags-file-name "TAGS")(defvar vip-inhibit-startup-message nil);; basic set up(global-set-key "\C-z" 'vip-change-mode-to-vi)(defmacro vip-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 vip-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 vip-goto-col (arg) "Go to ARG's column." (interactive "P") (let ((val (vip-p-val arg)) (com (vip-getcom arg))) (save-excursion (end-of-line) (if (> val (1+ (current-column))) (error ""))) (if com (move-marker vip-com-point (point))) (beginning-of-line) (forward-char (1- val)) (if com (vip-execute-com 'vip-goto-col val com))))(defun vip-refresh-mode-line () "Redraw mode line." (set-buffer-modified-p (buffer-modified-p)))(defun vip-copy-keymap (map) (if (null map) (make-sparse-keymap) (copy-keymap map)));; changing mode(defun vip-change-mode (new-mode) "Change mode to NEW-MODE. NEW-MODE is either emacs-mode, vi-mode,or insert-mode." (or (eq new-mode vip-current-mode) (progn (cond ((eq new-mode 'vi-mode) (if (eq vip-current-mode 'insert-mode) (progn (vip-copy-region-as-kill (point) vip-insert-point) (vip-repeat-insert-command)) (setq vip-emacs-local-map (current-local-map) vip-emacs-mode-line-buffer-identification mode-line-buffer-identification vip-insert-local-map (vip-copy-keymap (current-local-map)))) (vip-change-mode-line "Vi: ") (use-local-map vip-mode-map)) ((eq new-mode 'insert-mode) (move-marker vip-insert-point (point)) (if (eq vip-current-mode 'emacs-mode) (setq vip-emacs-local-map (current-local-map) vip-emacs-mode-line-buffer-identification mode-line-buffer-identification vip-insert-local-map (vip-copy-keymap (current-local-map))) (setq vip-insert-local-map (vip-copy-keymap vip-emacs-local-map))) (vip-change-mode-line "Insert") (use-local-map vip-insert-local-map) (define-key vip-insert-local-map "\e" 'vip-change-mode-to-vi) (define-key vip-insert-local-map "\C-z" 'vip-ESC) (define-key vip-insert-local-map "\C-h" (if vip-help-in-insert-mode 'help-command 'delete-backward-char)) (define-key vip-insert-local-map "\C-w" 'vip-delete-backward-word)) ((eq new-mode 'emacs-mode) (vip-change-mode-line "Emacs:") (use-local-map vip-emacs-local-map))) (setq vip-current-mode new-mode) (vip-refresh-mode-line))))(defun vip-copy-region-as-kill (beg end) "If BEG and END do not belong to the same buffer, it copies empty region." (condition-case nil (copy-region-as-kill beg end) (error (copy-region-as-kill beg beg))))(defun vip-change-mode-line (string) "Assuming that the mode line format contains the string \"Emacs:\", thisfunction replaces the string by \"Vi: \" etc." (setq mode-line-buffer-identification (if (string= string "Emacs:") vip-emacs-mode-line-buffer-identification (list (concat string " %17b")))))(defun vip-mode () "Turn on VIP emulation of VI." (interactive) (if (not vip-inhibit-startup-message) (progn (switch-to-buffer "VIP Startup Message") (erase-buffer) (insert "VIP is a Vi emulation package for GNU Emacs. VIP provides most Vi commandsincluding Ex commands. VIP is however different from Vi in several points.You can get more information on VIP by: 1. Typing `M-x info' and selecting menu item \"vip\". 2. Typing `C-h k' followed by a key whose description you want. 3. Printing VIP manual which can be found as GNU/man/vip.texinfo 4. Printing VIP Reference Card which can be found as GNU/etc/vipcard.texThis startup message appears whenever you load VIP unless you type `y' now.Type `n' to quit this window for now.\n") (goto-char (point-min)) (if (y-or-n-p "Inhibit VIP startup message? ") (progn (save-excursion (set-buffer (find-file-noselect (substitute-in-file-name "~/.vip"))) (goto-char (point-max)) (insert "\n(setq vip-inhibit-startup-message t)\n") (save-buffer) (kill-buffer (current-buffer))) (message "VIP startup message inhibited.") (sit-for 2))) (kill-buffer (current-buffer)) (message "") (setq vip-inhibit-startup-message t))) (vip-change-mode-to-vi))(defun vip-change-mode-to-vi () "Change mode to vi mode." (interactive) (vip-change-mode 'vi-mode))(defun vip-change-mode-to-insert () "Change mode to insert mode." (interactive) (vip-change-mode 'insert-mode))(defun vip-change-mode-to-emacs () "Change mode to emacs mode." (interactive) (vip-change-mode 'emacs-mode));; 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, usinglocal keymap L-MAP and global keymap G-MAP. If the command is aself-insert-command, the character just read is returned instead. Optionalstring 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 bindingis 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 tovi mode. ARG is used as the prefix value for the executed command. IfCHAR 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)) (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))) (setq prefix-arg nil) ;; reset prefix arg ))(defun vip-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 vip-ESC (arg) "Emulate ESC key in Emacs mode." (interactive "P") (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))(defun vip-ctl-x (arg) "Emulate C-x key in Emacs mode." (interactive "P") (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));; 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 vip-prefix-arg-value (char value com) "Compute numeric prefix arg value. Invoked by CHAR. VALUE is the valueobtained 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) (vip-describe-arg prefix-arg) (setq char (read-char))) (setq unread-command-char char))(defun vip-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 vip-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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -