diff options
| author | Richard M. Stallman | 1987-01-07 19:02:47 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1987-01-07 19:02:47 +0000 |
| commit | b20cd8dbd051aa561257df965c0d3eaef5df069e (patch) | |
| tree | b583dd9e1022af590108dc3234668c9a0b1e5839 /lisp/emulation | |
| parent | 62983f7ea0b7cf27069464efde1a7654eb900e94 (diff) | |
| download | emacs-b20cd8dbd051aa561257df965c0d3eaef5df069e.tar.gz emacs-b20cd8dbd051aa561257df965c0d3eaef5df069e.zip | |
Initial revision
Diffstat (limited to 'lisp/emulation')
| -rw-r--r-- | lisp/emulation/vi.el | 1446 |
1 files changed, 1446 insertions, 0 deletions
diff --git a/lisp/emulation/vi.el b/lisp/emulation/vi.el new file mode 100644 index 00000000000..324f0b5882d --- /dev/null +++ b/lisp/emulation/vi.el | |||
| @@ -0,0 +1,1446 @@ | |||
| 1 | ; Evi: Major mode for emulating "vi" editor under GNU Emacs. | ||
| 2 | ; Originally written by : seismo!wucs!nz@rsch.wisc.edu (Neal Ziring) | ||
| 3 | ; Extensively redesigned and rewritten by wu@crys.wisc.edu (Felix S.T. Wu) | ||
| 4 | ; Last revision: 01/07/87 Wed (for GNU Emacs 18.33) | ||
| 5 | ; | ||
| 6 | ; INSTALLATION PROCEDURE: | ||
| 7 | ; 1) Add a global key binding for command "vi-mode" (I use ESC ESC instead of | ||
| 8 | ; the single ESC used in real "vi", so I can access other ESC prefixed emacs | ||
| 9 | ; commands while I'm in "vi"), say, by putting the following line in your | ||
| 10 | ; ".emacs" file: | ||
| 11 | ; (define-key global-map "\e\e" 'vi-mode) ;quick switch into vi-mode | ||
| 12 | ; 2) If you wish you can define "find-file-hooks" to enter "vi" automatically | ||
| 13 | ; after a file is loaded into the buffer. For example, I defined it as: | ||
| 14 | ; (setq find-file-hooks (list | ||
| 15 | ; (function (lambda () | ||
| 16 | ; (if (not (or (eq major-mode 'Info-mode) | ||
| 17 | ; (eq major-mode 'vi-mode))) | ||
| 18 | ; (vi-mode)))))) | ||
| 19 | ; 3) In your .emacs file you can define the command "vi-mode" to be "autoload" | ||
| 20 | ; or you can execute the "load" command to load "vi" directly. | ||
| 21 | ; 4) Read the comments for command "vi-mode" before you start using it. | ||
| 22 | ; | ||
| 23 | ; COULD DO | ||
| 24 | ; 1). A general 'define-operator' function to replace current hack | ||
| 25 | ; 2). In operator handling, should allow other point moving Emacs commands | ||
| 26 | ; (such as ESC <, ESC >) to be used as arguments. | ||
| 27 | ; | ||
| 28 | |||
| 29 | (defun vi-switch-mode (arg mode-char) | ||
| 30 | "Switch the major mode of current buffer as specified by the following char \\{vi-tilde-map}" | ||
| 31 | (interactive "P\nc") | ||
| 32 | (let ((mode-cmd (lookup-key vi-tilde-map (char-to-string mode-char)))) | ||
| 33 | (if (null mode-cmd) | ||
| 34 | (with-output-to-temp-buffer "*Help*" | ||
| 35 | (princ (substitute-command-keys "Possible major modes to switch to: \\{vi-tilde-map}"))) | ||
| 36 | (setq prefix-arg arg) ; prefix arg will be passed down | ||
| 37 | (command-execute mode-cmd nil) ; may need to save mode-line-format etc | ||
| 38 | (set-buffer-modified-p (buffer-modified-p))))) ; just in case | ||
| 39 | |||
| 40 | |||
| 41 | (if (null (where-is-internal 'vi-switch-mode (current-local-map))) | ||
| 42 | (define-key ctl-x-map "~" 'vi-switch-mode)) | ||
| 43 | |||
| 44 | (defvar vi-tilde-map nil | ||
| 45 | "Keymap used for \\[vi-switch-mode] prefix key. Link to various major modes.") | ||
| 46 | |||
| 47 | (if vi-tilde-map | ||
| 48 | nil | ||
| 49 | (setq vi-tilde-map (make-keymap)) | ||
| 50 | (define-key vi-tilde-map "a" 'abbrev-mode) | ||
| 51 | (define-key vi-tilde-map "c" 'c-mode) | ||
| 52 | (define-key vi-tilde-map "d" 'vi-debugging) | ||
| 53 | (define-key vi-tilde-map "e" 'emacs-lisp-mode) | ||
| 54 | (define-key vi-tilde-map "f" 'auto-fill-mode) | ||
| 55 | (define-key vi-tilde-map "g" 'prolog-mode) | ||
| 56 | (define-key vi-tilde-map "h" 'hanoi) | ||
| 57 | (define-key vi-tilde-map "i" 'info-mode) | ||
| 58 | (define-key vi-tilde-map "l" 'lisp-mode) | ||
| 59 | (define-key vi-tilde-map "n" 'nroff-mode) | ||
| 60 | (define-key vi-tilde-map "o" 'overwrite-mode) | ||
| 61 | (define-key vi-tilde-map "O" 'outline-mode) | ||
| 62 | (define-key vi-tilde-map "P" 'picture-mode) | ||
| 63 | (define-key vi-tilde-map "r" 'vi-readonly-mode) | ||
| 64 | (define-key vi-tilde-map "t" 'text-mode) | ||
| 65 | (define-key vi-tilde-map "v" 'vi-mode) | ||
| 66 | (define-key vi-tilde-map "x" 'tex-mode) | ||
| 67 | (define-key vi-tilde-map "~" 'vi-back-to-old-mode)) | ||
| 68 | |||
| 69 | (defun vi-debugging (arg) | ||
| 70 | "Toggle debug-on-error flag. If prefix arg is given, set t." | ||
| 71 | (interactive "P") | ||
| 72 | (if arg | ||
| 73 | (setq debug-on-error t) | ||
| 74 | (setq debug-on-error (not debug-on-error))) | ||
| 75 | (if debug-on-error | ||
| 76 | (message "Debug-on-error ...") | ||
| 77 | (message "NO more debug-on-error"))) | ||
| 78 | |||
| 79 | (defun vi-back-to-old-mode () | ||
| 80 | "Go back to the previous mode without setting up for insertion." | ||
| 81 | (interactive) | ||
| 82 | (if vi-mode-old-major-mode | ||
| 83 | (progn | ||
| 84 | (setq mode-name vi-mode-old-mode-name) | ||
| 85 | (use-local-map vi-mode-old-local-map) | ||
| 86 | (setq major-mode vi-mode-old-major-mode) | ||
| 87 | (setq case-fold-search vi-mode-old-case-fold) | ||
| 88 | (set-buffer-modified-p (buffer-modified-p))))) | ||
| 89 | |||
| 90 | (defun vi-readonly-mode () | ||
| 91 | "Toggle current buffer's readonly flag." | ||
| 92 | (interactive) | ||
| 93 | (setq buffer-read-only (not buffer-read-only))) | ||
| 94 | |||
| 95 | (defvar vi-com-map nil | ||
| 96 | "Keymap used in Evi's command state | ||
| 97 | Command state includes most of the vi editing commands, with some Emacs | ||
| 98 | command extensions.") | ||
| 99 | |||
| 100 | (put 'vi-undefined 'suppress-keymap t) | ||
| 101 | (if vi-com-map nil | ||
| 102 | (setq vi-com-map (make-keymap)) | ||
| 103 | ;;(fillarray vi-com-map 'vi-undefined) | ||
| 104 | (define-key vi-com-map "\C-@" 'vi-mark-region) ; extension | ||
| 105 | (define-key vi-com-map "\C-a" 'vi-ask-for-info) ; extension | ||
| 106 | (define-key vi-com-map "\C-b" 'vi-backward-windowfull) | ||
| 107 | (define-key vi-com-map "\C-c" 'vi-do-old-mode-C-c-command) ; extension | ||
| 108 | (define-key vi-com-map "\C-d" 'vi-scroll-down-window) | ||
| 109 | (define-key vi-com-map "\C-e" 'vi-expose-line-below) | ||
| 110 | (define-key vi-com-map "\C-f" 'vi-forward-windowfull) | ||
| 111 | (define-key vi-com-map "\C-g" 'keyboard-quit) | ||
| 112 | (define-key vi-com-map "\C-i" 'indent-relative-maybe) ; TAB | ||
| 113 | (define-key vi-com-map "\C-j" 'vi-next-line) ; LFD | ||
| 114 | (define-key vi-com-map "\C-k" 'vi-kill-line) ; extension | ||
| 115 | (define-key vi-com-map "\C-l" 'recenter) | ||
| 116 | (define-key vi-com-map "\C-m" 'vi-next-line-first-nonwhite) ; RET | ||
| 117 | (define-key vi-com-map "\C-n" 'vi-next-line) | ||
| 118 | (define-key vi-com-map "\C-o" 'vi-split-open-line) | ||
| 119 | (define-key vi-com-map "\C-p" 'previous-line) | ||
| 120 | (define-key vi-com-map "\C-q" 'vi-query-replace) ; extension | ||
| 121 | (define-key vi-com-map "\C-r" 'vi-isearch-backward) ; modification | ||
| 122 | (define-key vi-com-map "\C-s" 'vi-isearch-forward) ; extension | ||
| 123 | (define-key vi-com-map "\C-t" 'vi-transpose-objects) ; extension | ||
| 124 | (define-key vi-com-map "\C-u" 'vi-scroll-up-window) | ||
| 125 | (define-key vi-com-map "\C-v" 'scroll-up) ; extension | ||
| 126 | (define-key vi-com-map "\C-w" 'vi-kill-region) ; extension | ||
| 127 | (define-key vi-com-map "\C-x" 'Control-X-prefix) ; extension | ||
| 128 | (define-key vi-com-map "\C-y" 'vi-expose-line-above) | ||
| 129 | (define-key vi-com-map "\C-z" 'suspend-emacs) | ||
| 130 | |||
| 131 | (define-key vi-com-map "\e" 'ESC-prefix); C-[ (ESC) | ||
| 132 | (define-key vi-com-map "\C-\\" 'vi-unimplemented) | ||
| 133 | (define-key vi-com-map "\C-]" 'find-tag) | ||
| 134 | (define-key vi-com-map "\C-^" 'vi-locate-def) ; extension | ||
| 135 | (define-key vi-com-map "\C-_" 'vi-undefined) | ||
| 136 | |||
| 137 | (define-key vi-com-map " " 'forward-char) | ||
| 138 | (define-key vi-com-map "!" 'vi-operator) | ||
| 139 | (define-key vi-com-map "\"" 'vi-char-argument) | ||
| 140 | (define-key vi-com-map "#" 'universal-argument) ; extension | ||
| 141 | (define-key vi-com-map "$" 'end-of-line) | ||
| 142 | (define-key vi-com-map "%" 'vi-find-matching-paren) | ||
| 143 | (define-key vi-com-map "&" 'vi-unimplemented) | ||
| 144 | (define-key vi-com-map "'" 'vi-goto-line-mark) | ||
| 145 | (define-key vi-com-map "(" 'backward-sexp) | ||
| 146 | (define-key vi-com-map ")" 'forward-sexp) | ||
| 147 | (define-key vi-com-map "*" 'vi-name-last-change-or-macro) ; extension | ||
| 148 | (define-key vi-com-map "+" 'vi-next-line-first-nonwhite) | ||
| 149 | (define-key vi-com-map "," 'vi-reverse-last-find-char) | ||
| 150 | (define-key vi-com-map "-" 'vi-previous-line-first-nonwhite) | ||
| 151 | (define-key vi-com-map "." 'vi-redo-last-change-command) | ||
| 152 | (define-key vi-com-map "/" 'vi-search-forward) | ||
| 153 | (define-key vi-com-map "0" 'beginning-of-line) | ||
| 154 | |||
| 155 | (define-key vi-com-map "1" 'vi-digit-argument) | ||
| 156 | (define-key vi-com-map "2" 'vi-digit-argument) | ||
| 157 | (define-key vi-com-map "3" 'vi-digit-argument) | ||
| 158 | (define-key vi-com-map "4" 'vi-digit-argument) | ||
| 159 | (define-key vi-com-map "5" 'vi-digit-argument) | ||
| 160 | (define-key vi-com-map "6" 'vi-digit-argument) | ||
| 161 | (define-key vi-com-map "7" 'vi-digit-argument) | ||
| 162 | (define-key vi-com-map "8" 'vi-digit-argument) | ||
| 163 | (define-key vi-com-map "9" 'vi-digit-argument) | ||
| 164 | |||
| 165 | (define-key vi-com-map ":" 'vi-ex-cmd) | ||
| 166 | (define-key vi-com-map ";" 'vi-repeat-last-find-char) | ||
| 167 | (define-key vi-com-map "<" 'vi-operator) | ||
| 168 | (define-key vi-com-map "=" 'vi-operator) | ||
| 169 | (define-key vi-com-map ">" 'vi-operator) | ||
| 170 | (define-key vi-com-map "?" 'vi-search-backward) | ||
| 171 | (define-key vi-com-map "@" 'vi-call-named-change-or-macro) ; extension | ||
| 172 | |||
| 173 | (define-key vi-com-map "A" 'vi-append-at-end-of-line) | ||
| 174 | (define-key vi-com-map "B" 'vi-backward-blank-delimited-word) | ||
| 175 | (define-key vi-com-map "C" 'vi-change-rest-of-line) | ||
| 176 | (define-key vi-com-map "D" 'vi-kill-line) | ||
| 177 | (define-key vi-com-map "E" 'vi-end-of-blank-delimited-word) | ||
| 178 | (define-key vi-com-map "F" 'vi-backward-find-char) | ||
| 179 | (define-key vi-com-map "G" 'vi-goto-line) | ||
| 180 | (define-key vi-com-map "H" 'vi-home-window-line) | ||
| 181 | (define-key vi-com-map "I" 'vi-insert-before-first-nonwhite) | ||
| 182 | (define-key vi-com-map "J" 'vi-join-lines) | ||
| 183 | (define-key vi-com-map "K" 'vi-undefined) | ||
| 184 | (define-key vi-com-map "L" 'vi-last-window-line) | ||
| 185 | (define-key vi-com-map "M" 'vi-middle-window-line) | ||
| 186 | (define-key vi-com-map "N" 'vi-reverse-last-search) | ||
| 187 | (define-key vi-com-map "O" 'vi-open-above) | ||
| 188 | (define-key vi-com-map "P" 'vi-put-before) | ||
| 189 | (define-key vi-com-map "Q" 'vi-quote-words) ; extension | ||
| 190 | (define-key vi-com-map "R" 'vi-replace-chars) | ||
| 191 | (define-key vi-com-map "S" 'vi-substitute-lines) | ||
| 192 | (define-key vi-com-map "T" 'vi-backward-upto-char) | ||
| 193 | (define-key vi-com-map "U" 'vi-unimplemented) | ||
| 194 | (define-key vi-com-map "V" 'vi-undefined) | ||
| 195 | (define-key vi-com-map "W" 'vi-forward-blank-delimited-word) | ||
| 196 | (define-key vi-com-map "X" 'call-last-kbd-macro) ; modification/extension | ||
| 197 | (define-key vi-com-map "Y" 'vi-yank-line) | ||
| 198 | (define-key vi-com-map "Z" (make-sparse-keymap)) ;allow below prefix command | ||
| 199 | (define-key vi-com-map "ZZ" 'vi-save-all-and-exit) | ||
| 200 | |||
| 201 | (define-key vi-com-map "[" 'vi-unimplemented) | ||
| 202 | (define-key vi-com-map "\\" 'vi-operator) ; extension for vi-narrow-op | ||
| 203 | (define-key vi-com-map "]" 'vi-unimplemented) | ||
| 204 | (define-key vi-com-map "^" 'back-to-indentation) | ||
| 205 | (define-key vi-com-map "_" 'vi-undefined) | ||
| 206 | (define-key vi-com-map "`" 'vi-goto-char-mark) | ||
| 207 | |||
| 208 | (define-key vi-com-map "a" 'vi-insert-after) | ||
| 209 | (define-key vi-com-map "b" 'backward-word) | ||
| 210 | (define-key vi-com-map "c" 'vi-operator) | ||
| 211 | (define-key vi-com-map "d" 'vi-operator) | ||
| 212 | (define-key vi-com-map "e" 'vi-end-of-word) | ||
| 213 | (define-key vi-com-map "f" 'vi-forward-find-char) | ||
| 214 | (define-key vi-com-map "g" 'vi-beginning-of-buffer) ; extension | ||
| 215 | (define-key vi-com-map "h" 'backward-char) | ||
| 216 | (define-key vi-com-map "i" 'vi-insert-before) | ||
| 217 | (define-key vi-com-map "j" 'vi-next-line) | ||
| 218 | (define-key vi-com-map "k" 'previous-line) | ||
| 219 | (define-key vi-com-map "l" 'forward-char) | ||
| 220 | (define-key vi-com-map "m" 'vi-set-mark) | ||
| 221 | (define-key vi-com-map "n" 'vi-repeat-last-search) | ||
| 222 | (define-key vi-com-map "o" 'vi-open-below) | ||
| 223 | (define-key vi-com-map "p" 'vi-put-after) | ||
| 224 | (define-key vi-com-map "q" 'vi-replace) | ||
| 225 | (define-key vi-com-map "r" 'vi-replace-1-char) | ||
| 226 | (define-key vi-com-map "s" 'vi-substitute-chars) | ||
| 227 | (define-key vi-com-map "t" 'vi-forward-upto-char) | ||
| 228 | (define-key vi-com-map "u" 'undo) | ||
| 229 | (define-key vi-com-map "v" 'vi-verify-spelling) | ||
| 230 | (define-key vi-com-map "w" 'vi-forward-word) | ||
| 231 | (define-key vi-com-map "x" 'vi-kill-char) | ||
| 232 | (define-key vi-com-map "y" 'vi-operator) | ||
| 233 | (define-key vi-com-map "z" 'vi-adjust-window) | ||
| 234 | |||
| 235 | (define-key vi-com-map "{" 'backward-paragraph) | ||
| 236 | (define-key vi-com-map "|" 'vi-goto-column) | ||
| 237 | (define-key vi-com-map "}" 'forward-paragraph) | ||
| 238 | (define-key vi-com-map "~" 'vi-change-case) | ||
| 239 | (define-key vi-com-map "\177" 'delete-backward-char)) | ||
| 240 | |||
| 241 | (put 'backward-char 'point-moving-unit 'char) | ||
| 242 | (put 'vi-next-line 'point-moving-unit 'line) | ||
| 243 | (put 'next-line 'point-moving-unit 'line) | ||
| 244 | (put 'forward-line 'point-moving-unit 'line) | ||
| 245 | (put 'previous-line 'point-moving-unit 'line) | ||
| 246 | (put 'vi-isearch-backward 'point-moving-unit 'search) | ||
| 247 | (put 'vi-search-backward 'point-moving-unit 'search) | ||
| 248 | (put 'vi-isearch-forward 'point-moving-unit 'search) | ||
| 249 | (put 'vi-search-forward 'point-moving-unit 'search) | ||
| 250 | (put 'forward-char 'point-moving-unit 'char) | ||
| 251 | (put 'end-of-line 'point-moving-unit 'char) | ||
| 252 | (put 'vi-find-matching-paren 'point-moving-unit 'match) | ||
| 253 | (put 'vi-goto-line-mark 'point-moving-unit 'line) | ||
| 254 | (put 'backward-sexp 'point-moving-unit 'sexp) | ||
| 255 | (put 'forward-sexp 'point-moving-unit 'sexp) | ||
| 256 | (put 'vi-next-line-first-nonwhite 'point-moving-unit 'line) | ||
| 257 | (put 'vi-previous-line-first-nonwhite 'point-moving-unit 'line) | ||
| 258 | (put 'vi-reverse-last-find-char 'point-moving-unit 'rev-find) | ||
| 259 | (put 'vi-re-search-forward 'point-moving-unit 'search) | ||
| 260 | (put 'beginning-of-line 'point-moving-unit 'char) | ||
| 261 | (put 'vi-beginning-of-buffer 'point-moving-unit 'char) | ||
| 262 | (put 'vi-repeat-last-find-char 'point-moving-unit 'find) | ||
| 263 | (put 'vi-re-search-backward 'point-moving-unit 'search) | ||
| 264 | (put 'vi-backward-blank-delimited-word 'point-moving-unit 'WORD) | ||
| 265 | (put 'vi-end-of-blank-delimited-word 'point-moving-unit 'match) | ||
| 266 | (put 'vi-backward-find-char 'point-moving-unit 'find) | ||
| 267 | (put 'vi-goto-line 'point-moving-unit 'line) | ||
| 268 | (put 'vi-home-window-line 'point-moving-unit 'line) | ||
| 269 | (put 'vi-last-window-line 'point-moving-unit 'line) | ||
| 270 | (put 'vi-middle-window-line 'point-moving-unit 'line) | ||
| 271 | (put 'vi-reverse-last-search 'point-moving-unit 'rev-search) | ||
| 272 | (put 'vi-backward-upto-char 'point-moving-unit 'find) | ||
| 273 | (put 'vi-forward-blank-delimited-word 'point-moving-unit 'WORD) | ||
| 274 | (put 'back-to-indentation 'point-moving-unit 'char) | ||
| 275 | (put 'vi-goto-char-mark 'point-moving-unit 'char) | ||
| 276 | (put 'backward-word 'point-moving-unit 'word) | ||
| 277 | (put 'vi-end-of-word 'point-moving-unit 'match) | ||
| 278 | (put 'vi-forward-find-char 'point-moving-unit 'find) | ||
| 279 | (put 'backward-char 'point-moving-unit 'char) | ||
| 280 | (put 'vi-forward-char 'point-moving-unit 'char) | ||
| 281 | (put 'vi-repeat-last-search 'point-moving-unit 'search) | ||
| 282 | (put 'vi-forward-upto-char 'point-moving-unit 'find) | ||
| 283 | (put 'vi-forward-word 'point-moving-unit 'word) | ||
| 284 | (put 'vi-goto-column 'point-moving-unit 'match) | ||
| 285 | (put 'forward-paragraph 'point-moving-unit 'paragraph) | ||
| 286 | (put 'backward-paragraph 'point-moving-unit 'paragraph) | ||
| 287 | |||
| 288 | ;;; region mark commands | ||
| 289 | (put 'mark-page 'point-moving-unit 'region) | ||
| 290 | (put 'mark-paragraph 'point-moving-unit 'region) | ||
| 291 | (put 'mark-word 'point-moving-unit 'region) | ||
| 292 | (put 'mark-sexp 'point-moving-unit 'region) | ||
| 293 | (put 'mark-defun 'point-moving-unit 'region) | ||
| 294 | (put 'mark-whole-buffer 'point-moving-unit 'region) | ||
| 295 | (put 'mark-end-of-sentence 'point-moving-unit 'region) | ||
| 296 | (put 'mark-c-function 'point-moving-unit 'region) | ||
| 297 | ;;; | ||
| 298 | |||
| 299 | (defvar vi-mark-alist nil | ||
| 300 | "Alist of (NAME . MARK), marks are local to each buffer.") | ||
| 301 | |||
| 302 | (defvar vi-scroll-amount (/ (window-height) 2) | ||
| 303 | "Default amount of lines for scrolling (used by "^D"/"^U").") | ||
| 304 | |||
| 305 | (defvar vi-shift-width 4 | ||
| 306 | "Shift amount for "<"/">" operators.") | ||
| 307 | |||
| 308 | (defvar vi-ins-point nil ; integer | ||
| 309 | "Last insertion point. Should use 'mark' instead.") | ||
| 310 | |||
| 311 | (defvar vi-ins-length nil ; integer | ||
| 312 | "Length of last insertion.") | ||
| 313 | |||
| 314 | (defvar vi-ins-repetition nil ; integer | ||
| 315 | "The repetition required for last insertion.") | ||
| 316 | |||
| 317 | (defvar vi-ins-overwrt-p nil ; boolean | ||
| 318 | "T if last insertion was a replace actually.") | ||
| 319 | |||
| 320 | (defvar vi-ins-prefix-code nil ; ready-to-eval sexp | ||
| 321 | "Code to be eval'ed before (redo-)insertion begins.") | ||
| 322 | |||
| 323 | (defvar vi-last-find-char nil ; cons cell | ||
| 324 | "Save last direction, char and upto-flag used for char finding.") | ||
| 325 | |||
| 326 | (defvar vi-last-change-command nil ; cons cell | ||
| 327 | "Save commmands for redoing last changes. Each command is in (FUNC . ARGS) | ||
| 328 | form that is ready to be 'apply'ed.") | ||
| 329 | |||
| 330 | (defvar vi-last-shell-command nil ; last shell op command line | ||
| 331 | "Save last shell command given for \"!\" operator.") | ||
| 332 | |||
| 333 | (defvar vi-insert-state nil ; boolean | ||
| 334 | "T if it is in insert state.") | ||
| 335 | |||
| 336 | ; in "loaddefs.el" | ||
| 337 | ;(defvar search-last-string "" | ||
| 338 | ; "Last string search for by a search command.") | ||
| 339 | |||
| 340 | (defvar vi-search-last-command nil ; (re-)search-forward(backward) | ||
| 341 | "Save last search command for possible redo.") | ||
| 342 | |||
| 343 | (defvar vi-mode-old-local-map nil | ||
| 344 | "Save the local-map used before entering vi-mode.") | ||
| 345 | |||
| 346 | (defvar vi-mode-old-mode-name nil | ||
| 347 | "Save the mode-name before entering vi-mode.") | ||
| 348 | |||
| 349 | (defvar vi-mode-old-major-mode nil | ||
| 350 | "Save the major-mode before entering vi-mode.") | ||
| 351 | |||
| 352 | (defvar vi-mode-old-case-fold nil) | ||
| 353 | |||
| 354 | ;(defconst vi-add-to-mode-line-1 | ||
| 355 | ; '(overwrite-mode nil " Insert")) | ||
| 356 | |||
| 357 | ;; Value is same as vi-add-to-mode-line-1 when in vi mode, | ||
| 358 | ;; but nil in other buffers. | ||
| 359 | ;(defvar vi-add-to-mode-line nil) | ||
| 360 | |||
| 361 | (defun vi-mode-setup () | ||
| 362 | "Setup a buffer for vi-mode by creating necessary buffer-local variables." | ||
| 363 | ; (make-local-variable 'vi-add-to-mode-line) | ||
| 364 | ; (setq vi-add-to-mode-line vi-add-to-mode-line-1) | ||
| 365 | ; (or (memq vi-add-to-mode-line minor-mode-alist) | ||
| 366 | ; (setq minor-mode-alist (cons vi-add-to-mode-line minor-mode-alist))) | ||
| 367 | (make-local-variable 'vi-scroll-amount) | ||
| 368 | (setq vi-scroll-amount (/ (window-height) 2)) | ||
| 369 | (make-local-variable 'vi-shift-width) | ||
| 370 | (setq vi-shift-width 4) | ||
| 371 | (make-local-variable 'vi-ins-point) | ||
| 372 | (make-local-variable 'vi-ins-length) | ||
| 373 | (make-local-variable 'vi-ins-repetition) | ||
| 374 | (make-local-variable 'vi-ins-overwrt-p) | ||
| 375 | (make-local-variable 'vi-ins-prefix-code) | ||
| 376 | (make-local-variable 'vi-last-change-command) | ||
| 377 | (make-local-variable 'vi-last-shell-command) | ||
| 378 | (make-local-variable 'vi-last-find-char) | ||
| 379 | (make-local-variable 'vi-mark-alist) | ||
| 380 | (make-local-variable 'vi-insert-state) | ||
| 381 | (make-local-variable 'vi-mode-old-local-map) | ||
| 382 | (make-local-variable 'vi-mode-old-mode-name) | ||
| 383 | (make-local-variable 'vi-mode-old-major-mode) | ||
| 384 | (make-local-variable 'vi-mode-old-case-fold) | ||
| 385 | (run-hooks 'vi-mode-hook)) | ||
| 386 | |||
| 387 | (defun vi-mode () | ||
| 388 | "Major mode that acts like the `vi' editor. | ||
| 389 | The purpose of this mode is to provide you the combined power of vi (namely, | ||
| 390 | the \"cross product\" effect of commands and repeat last changes) and Emacs. | ||
| 391 | |||
| 392 | This command redefines nearly all keys to look like vi commands. | ||
| 393 | It records the previous major mode, and any vi command for input | ||
| 394 | \(`i', `a', `s', etc.) switches back to that mode. | ||
| 395 | Thus, ordinary Emacs (in whatever major mode you had been using) | ||
| 396 | is \"input\" mode as far as vi is concerned. | ||
| 397 | |||
| 398 | To get back into vi from \"input\" mode, you must issue this command again. | ||
| 399 | Therefore, it is recommended that you assign it to a key. | ||
| 400 | |||
| 401 | Major differences between this mode and real vi : | ||
| 402 | |||
| 403 | * Limitations and unsupported features | ||
| 404 | - Search patterns with line offset (e.g. /pat/+3 or /pat/z.) are | ||
| 405 | not supported. | ||
| 406 | - Ex commands are not implemented; try ':' to get some hints. | ||
| 407 | - No line undo (i.e. the 'U' command), but multi-undo is a standard feature. | ||
| 408 | |||
| 409 | * Modifications | ||
| 410 | - The stopping positions for some point motion commands (word boundary, | ||
| 411 | pattern search) are slightly different from standard 'vi'. | ||
| 412 | Also, no automatic wrap around at end of buffer for pattern searching. | ||
| 413 | - Since changes are done in two steps (deletion then insertion), you need | ||
| 414 | to undo twice to completely undo a change command. But this is not needed | ||
| 415 | for undoing a repeated change command. | ||
| 416 | - No need to set/unset 'magic', to search for a string with regular expr | ||
| 417 | in it just put a prefix arg for the search commands. Replace cmds too. | ||
| 418 | - ^R is bound to incremental backward search, so use ^L to redraw screen. | ||
| 419 | |||
| 420 | * Extensions | ||
| 421 | - Some standard (or modified) Emacs commands were integrated, such as | ||
| 422 | incremental search, query replace, transpose objects, and keyboard macros. | ||
| 423 | - In command state, ^X links to the 'ctl-x-map', and ESC can be linked to | ||
| 424 | esc-map or set undefined. These can give you the full power of Emacs. | ||
| 425 | - See vi-com-map for those keys that are extensions to standard vi, e.g. | ||
| 426 | `vi-name-last-change-or-macro', `vi-verify-spelling', `vi-locate-def', | ||
| 427 | `vi-mark-region', and 'vi-quote-words'. Some of them are quite handy. | ||
| 428 | - Use \\[vi-switch-mode] to switch among different modes quickly. | ||
| 429 | |||
| 430 | Syntax table and abbrevs while in vi mode remain as they were in Emacs." | ||
| 431 | (interactive) | ||
| 432 | (if (null vi-mode-old-major-mode) ; very first call for current buffer | ||
| 433 | (vi-mode-setup)) | ||
| 434 | |||
| 435 | (if (eq major-mode 'vi-mode) | ||
| 436 | (message "Already in vi-mode." (ding)) | ||
| 437 | (setq vi-mode-old-local-map (current-local-map)) | ||
| 438 | (setq vi-mode-old-mode-name mode-name) | ||
| 439 | (setq vi-mode-old-major-mode major-mode) | ||
| 440 | (setq vi-mode-old-case-fold case-fold-search) ; this is needed !! | ||
| 441 | (setq case-fold-search nil) ; exact case match in searching | ||
| 442 | (use-local-map vi-com-map) | ||
| 443 | (setq major-mode 'vi-mode) | ||
| 444 | (setq mode-name "VI") | ||
| 445 | (set-buffer-modified-p (buffer-modified-p)) ; force mode line update | ||
| 446 | (if vi-insert-state ; this is a return from insertion | ||
| 447 | (vi-end-of-insert-state)))) | ||
| 448 | |||
| 449 | (defun vi-ding() | ||
| 450 | "Ding !" | ||
| 451 | (interactive) | ||
| 452 | (ding)) | ||
| 453 | |||
| 454 | (defun vi-save-all-and-exit () | ||
| 455 | "Save all modified buffers without asking, then exits emacs." | ||
| 456 | (interactive) | ||
| 457 | (save-some-buffers t) | ||
| 458 | (kill-emacs)) | ||
| 459 | |||
| 460 | ;; to be used by "ex" commands | ||
| 461 | (defvar vi-replaced-string nil) | ||
| 462 | (defvar vi-replacing-string nil) | ||
| 463 | |||
| 464 | (defun vi-ex-cmd () | ||
| 465 | "Ex commands are not implemented in Evi mode. For some commonly used ex | ||
| 466 | commands, you can use the following alternatives for similar effect : | ||
| 467 | w C-x C-s (save-buffer) | ||
| 468 | wq C-x C-c (save-buffers-kill-emacs) | ||
| 469 | w fname C-x C-w (write-file) | ||
| 470 | e fname C-x C-f (find-file) | ||
| 471 | r fname C-x i (insert-file) | ||
| 472 | s/old/new use q (vi-replace) to do unconditional replace | ||
| 473 | use C-q (vi-query-replace) to do query replace | ||
| 474 | set sw=n M-x set-variable vi-shift-width n " | ||
| 475 | (interactive) | ||
| 476 | ;; (let ((cmd (read-string ":")) (lines 1)) | ||
| 477 | ;; (cond ((string-match "s")))) | ||
| 478 | (with-output-to-temp-buffer "*Help*" | ||
| 479 | (princ (documentation 'vi-ex-cmd)))) | ||
| 480 | |||
| 481 | (defun vi-undefined () | ||
| 482 | (interactive) | ||
| 483 | (message "Command key \"%s\" is undefined in Evi." | ||
| 484 | (single-key-description last-command-char)) | ||
| 485 | (ding)) | ||
| 486 | |||
| 487 | (defun vi-unimplemented () | ||
| 488 | (interactive) | ||
| 489 | (message "Command key \"%s\" is not implemented in Evi." | ||
| 490 | (single-key-description last-command-char)) | ||
| 491 | (ding)) | ||
| 492 | |||
| 493 | ;;;;; | ||
| 494 | (defun vi-goto-insert-state (repetition &optional prefix-code do-it-now-p) | ||
| 495 | "Go into insert state, the text entered will be repeated if REPETITION > 1. | ||
| 496 | If PREFIX-CODE is given, do it before insertion begins if DO-IT-NOW-P is T. | ||
| 497 | In any case, the prefix-code will be done before each 'redo-insert'. | ||
| 498 | This function expects 'overwrite-mode' being set properly beforehand." | ||
| 499 | (if do-it-now-p (apply (car prefix-code) (cdr prefix-code))) | ||
| 500 | (setq vi-ins-point (point)) | ||
| 501 | (setq vi-ins-repetition repetition) | ||
| 502 | (setq vi-ins-prefix-code prefix-code) | ||
| 503 | (setq mode-name vi-mode-old-mode-name) | ||
| 504 | (setq case-fold-search vi-mode-old-case-fold) | ||
| 505 | (use-local-map vi-mode-old-local-map) | ||
| 506 | (setq major-mode vi-mode-old-major-mode) | ||
| 507 | (set-buffer-modified-p (buffer-modified-p)) ; force mode line update | ||
| 508 | (setq vi-insert-state t)) | ||
| 509 | |||
| 510 | (defun vi-end-of-insert-state () | ||
| 511 | "Terminate insertion and set up last change command." | ||
| 512 | (if (or (< (point) vi-ins-point) ;Check if there is any effective change | ||
| 513 | (and (= (point) vi-ins-point) (null vi-ins-prefix-code)) | ||
| 514 | (<= vi-ins-repetition 0)) | ||
| 515 | (vi-goto-command-state t) | ||
| 516 | (if (> vi-ins-repetition 1) | ||
| 517 | (progn | ||
| 518 | (let ((str (buffer-substring vi-ins-point (point)))) | ||
| 519 | (while (> vi-ins-repetition 1) | ||
| 520 | (insert str) | ||
| 521 | (setq vi-ins-repetition (1- vi-ins-repetition)))))) | ||
| 522 | (vi-set-last-change-command 'vi-first-redo-insertion vi-ins-point (point) | ||
| 523 | overwrite-mode vi-ins-prefix-code) | ||
| 524 | (vi-goto-command-state t))) | ||
| 525 | |||
| 526 | (defun vi-first-redo-insertion (begin end &optional overwrite-p prefix-code) | ||
| 527 | "Redo last insertion the first time. Extract the string and save it for | ||
| 528 | future redoes. Do prefix-code if it's given, use overwrite mode if asked." | ||
| 529 | (let ((str (buffer-substring begin end))) | ||
| 530 | (if prefix-code (apply (car prefix-code) (cdr prefix-code))) | ||
| 531 | (if overwrite-p (delete-region (point) (+ (point) (length str)))) | ||
| 532 | (insert str) | ||
| 533 | (vi-set-last-change-command 'vi-more-redo-insertion str overwrite-p prefix-code))) | ||
| 534 | |||
| 535 | (defun vi-more-redo-insertion (str &optional overwrite-p prefix-code) | ||
| 536 | "Redo more insertion : copy string from STR to point, use overwrite mode | ||
| 537 | if overwrite-p is T; apply prefix-code first if it's non-nil." | ||
| 538 | (if prefix-code (apply (car prefix-code) (cdr prefix-code))) | ||
| 539 | (if overwrite-p (delete-region (point) (+ (point) (length str)))) | ||
| 540 | (insert str)) | ||
| 541 | |||
| 542 | (defun vi-goto-command-state (&optional from-insert-state-p) | ||
| 543 | "Go to vi-mode command state. If optional arg exists, means return from | ||
| 544 | insert state." | ||
| 545 | (use-local-map vi-com-map) | ||
| 546 | (setq vi-insert-state nil) | ||
| 547 | (if from-insert-state-p | ||
| 548 | (if overwrite-mode | ||
| 549 | (overwrite-mode 0) | ||
| 550 | ; (set-minor-mode 'ins "Insert" nil) | ||
| 551 | ))) | ||
| 552 | |||
| 553 | (defun vi-kill-line (arg) | ||
| 554 | "kill specified number of lines (=d$), text saved in the kill ring." | ||
| 555 | (interactive "*P") | ||
| 556 | (kill-line arg) | ||
| 557 | (vi-set-last-change-command 'kill-line arg)) | ||
| 558 | |||
| 559 | (defun vi-kill-region () | ||
| 560 | (interactive) | ||
| 561 | (kill-region) | ||
| 562 | (vi-set-last-change-command 'kill-region)) | ||
| 563 | |||
| 564 | (defun vi-append-at-end-of-line (arg) | ||
| 565 | "go to end of line and then go into vi insert state." | ||
| 566 | (interactive "*p") | ||
| 567 | (vi-goto-insert-state arg '(end-of-line) t)) | ||
| 568 | |||
| 569 | (defun vi-change-rest-of-line (arg) | ||
| 570 | "Change the rest of (ARG) lines (= c$ in vi)." | ||
| 571 | (interactive "*P") | ||
| 572 | (vi-goto-insert-state 1 (list 'kill-line arg) t)) | ||
| 573 | |||
| 574 | (defun vi-insert-before-first-nonwhite (arg) | ||
| 575 | "(= ^i in vi)" | ||
| 576 | (interactive "*p") | ||
| 577 | (vi-goto-insert-state arg '(back-to-indentation) t)) | ||
| 578 | |||
| 579 | (defun vi-open-above (arg) | ||
| 580 | "open new line(s) above current line and enter insert state." | ||
| 581 | (interactive "*p") | ||
| 582 | (vi-goto-insert-state 1 | ||
| 583 | (list (function (lambda (x) | ||
| 584 | (or (beginning-of-line) | ||
| 585 | (open-line x)))) arg) | ||
| 586 | t)) | ||
| 587 | |||
| 588 | (defun vi-open-below (arg) | ||
| 589 | "open new line(s) and go into insert mode on the last line." | ||
| 590 | (interactive "*p") | ||
| 591 | (vi-goto-insert-state 1 | ||
| 592 | (list (function (lambda (x) | ||
| 593 | (or (end-of-line) | ||
| 594 | (open-line x) | ||
| 595 | (forward-line x)))) arg) | ||
| 596 | t)) | ||
| 597 | |||
| 598 | (defun vi-insert-after (arg) | ||
| 599 | "start vi insert state after cursor." | ||
| 600 | (interactive "*p") | ||
| 601 | (vi-goto-insert-state arg | ||
| 602 | (list (function (lambda () | ||
| 603 | (if (not (eolp)) (forward-char))))) | ||
| 604 | t)) | ||
| 605 | |||
| 606 | (defun vi-insert-before (arg) | ||
| 607 | "enter insert state before the cursor." | ||
| 608 | (interactive "*p") | ||
| 609 | (vi-goto-insert-state arg)) | ||
| 610 | |||
| 611 | (defun vi-goto-line (arg) | ||
| 612 | "Go to ARGth line." | ||
| 613 | (interactive "P") | ||
| 614 | (if (null (vi-raw-numeric-prefix arg)) | ||
| 615 | (end-of-buffer) | ||
| 616 | (goto-line (vi-prefix-numeric-value arg)))) | ||
| 617 | |||
| 618 | (defun vi-beginning-of-buffer () | ||
| 619 | "Move point to the beginning of current buffer." | ||
| 620 | (interactive) | ||
| 621 | (goto-char (point-min))) | ||
| 622 | |||
| 623 | ;;;;; not used now | ||
| 624 | ;;(defvar regexp-search t ; string | ||
| 625 | ;; "*T if search string can contain regular expressions. (= set magic in vi)") | ||
| 626 | ;;;;; | ||
| 627 | |||
| 628 | (defun vi-isearch-forward (arg) | ||
| 629 | "Incremental search forward. Use regexp version if ARG is non-nil." | ||
| 630 | (interactive "P") | ||
| 631 | (let ((scmd (if arg 'isearch-forward-regexp 'isearch-forward)) | ||
| 632 | (opoint (point))) | ||
| 633 | (call-interactively scmd) | ||
| 634 | (if (= opoint (point)) | ||
| 635 | nil | ||
| 636 | (setq vi-search-last-command (if arg 're-search-forward 'search-forward))))) | ||
| 637 | |||
| 638 | (defun vi-isearch-backward (arg) | ||
| 639 | "Incremental search backward. Use regexp version if ARG is non-nil." | ||
| 640 | (interactive "P") | ||
| 641 | (let ((scmd (if arg 'isearch-backward-regexp 'isearch-backward)) | ||
| 642 | (opoint (point))) | ||
| 643 | (call-interactively scmd) | ||
| 644 | (if (= opoint (point)) | ||
| 645 | nil | ||
| 646 | (setq vi-search-last-command (if arg 're-search-backward 'search-backward))))) | ||
| 647 | |||
| 648 | (defun vi-search-forward (arg string) | ||
| 649 | "Nonincremental search forward. Use regexp version if ARG is non-nil." | ||
| 650 | (interactive (if current-prefix-arg | ||
| 651 | (list t (read-string "regexp/" nil)) | ||
| 652 | (list nil (read-string "/" nil)))) | ||
| 653 | (setq vi-search-last-command (if arg 're-search-forward 'search-forward)) | ||
| 654 | (if (> (length string) 0) (setq search-last-string string)) | ||
| 655 | (funcall vi-search-last-command search-last-string nil nil 1)) | ||
| 656 | |||
| 657 | (defun vi-search-backward (arg string) | ||
| 658 | "Nonincremental search backward. Use regexp version if ARG is non-nil." | ||
| 659 | (interactive (if current-prefix-arg | ||
| 660 | (list t (read-string "regexp?" nil)) | ||
| 661 | (list nil (read-string "?" nil)))) | ||
| 662 | (setq vi-search-last-command (if arg 're-search-backward 'search-backward)) | ||
| 663 | (if (> (length string) 0) (setq search-last-string string)) | ||
| 664 | (funcall vi-search-last-command search-last-string nil nil 1)) | ||
| 665 | |||
| 666 | (defun vi-repeat-last-search (arg &optional search-command search-string) | ||
| 667 | "Repeat last search command. If optional search-command/string are given, | ||
| 668 | use those instead of the ones saved." | ||
| 669 | (interactive "p") | ||
| 670 | (if (null search-command) (setq search-command vi-search-last-command)) | ||
| 671 | (if (null search-string) (setq search-string search-last-string)) | ||
| 672 | (if (null search-command) | ||
| 673 | (message "No last search command to repeat." (ding)) | ||
| 674 | (funcall search-command search-string nil nil arg))) | ||
| 675 | |||
| 676 | (defun vi-reverse-last-search (arg &optional search-command search-string) | ||
| 677 | "Redo last search command in reverse direction. If the optional search args | ||
| 678 | are given, use those instead of the ones saved." | ||
| 679 | (interactive "p") | ||
| 680 | (if (null search-command) (setq search-command vi-search-last-command)) | ||
| 681 | (if (null search-string) (setq search-string search-last-string)) | ||
| 682 | (if (null search-command) | ||
| 683 | (message "No last search command to repeat." (ding)) | ||
| 684 | (funcall (cond ((eq search-command 're-search-forward) 're-search-backward) | ||
| 685 | ((eq search-command 're-search-backward) 're-search-forward) | ||
| 686 | ((eq search-command 'search-forward) 'search-backward) | ||
| 687 | ((eq search-command 'search-backward) 'search-forward)) | ||
| 688 | search-string nil nil arg))) | ||
| 689 | |||
| 690 | (defun vi-join-lines (arg) | ||
| 691 | "join ARG lines from current line (default 2), cleaning up white space." | ||
| 692 | (interactive "P") | ||
| 693 | (if (null (vi-raw-numeric-prefix arg)) | ||
| 694 | (delete-indentation t) | ||
| 695 | (setq count (vi-prefix-numeric-value arg)) | ||
| 696 | (while (>= count 2) | ||
| 697 | (delete-indentation t) | ||
| 698 | (setq count (1- count)))) | ||
| 699 | (vi-set-last-change-command 'vi-join-lines arg)) | ||
| 700 | |||
| 701 | (defun vi-backward-kill-line () | ||
| 702 | "kill the current line. Only works in insert state." | ||
| 703 | (interactive) | ||
| 704 | (if (not vi-insert-state) | ||
| 705 | nil | ||
| 706 | (beginning-of-line 1) | ||
| 707 | (kill-line nil))) | ||
| 708 | |||
| 709 | (defun vi-abort-ins () | ||
| 710 | "abort insert state, kill inserted text and go back to command state." | ||
| 711 | (interactive) | ||
| 712 | (if (not vi-insert-state) | ||
| 713 | nil | ||
| 714 | (if (> (point) vi-ins-point) | ||
| 715 | (kill-region vi-ins-point (point))) | ||
| 716 | (vi-goto-command-state t))) | ||
| 717 | |||
| 718 | (defun vi-backward-windowfull (count) | ||
| 719 | "Backward COUNT windowfulls. Default is one." | ||
| 720 | (interactive "p") | ||
| 721 | ; (set-mark-command nil) | ||
| 722 | (while (> count 0) | ||
| 723 | (scroll-down nil) | ||
| 724 | (setq count (1- count)))) | ||
| 725 | |||
| 726 | (defun vi-scroll-down-window (count) | ||
| 727 | "Scrolls down window COUNT lines. If COUNT is nil (actually, non-integer), | ||
| 728 | scrolls default amount. The given COUNT is remembered for future scrollings." | ||
| 729 | (interactive "P") | ||
| 730 | (if (integerp count) | ||
| 731 | (setq vi-scroll-amount count)) | ||
| 732 | (scroll-up vi-scroll-amount)) | ||
| 733 | |||
| 734 | (defun vi-expose-line-below (count) | ||
| 735 | "Expose COUNT more lines below the current window. Default COUNT is 1." | ||
| 736 | (interactive "p") | ||
| 737 | (scroll-up count)) | ||
| 738 | |||
| 739 | (defun vi-forward-windowfull (count) | ||
| 740 | "Forward COUNT windowfulls. Default is one." | ||
| 741 | (interactive "p") | ||
| 742 | ; (set-mark-command nil) | ||
| 743 | (while (> count 0) | ||
| 744 | (scroll-up nil) | ||
| 745 | (setq count (1- count)))) | ||
| 746 | |||
| 747 | (defun vi-next-line (count) | ||
| 748 | "Go down count lines, try to keep at the same column." | ||
| 749 | (interactive "p") | ||
| 750 | (setq this-command 'next-line) ; this is a needed trick | ||
| 751 | (if (= (point) (or (line-move count) (point))) | ||
| 752 | (ding) ; no moving, already at end of buffer | ||
| 753 | (setq last-command 'next-line))) | ||
| 754 | |||
| 755 | (defun vi-next-line-first-nonwhite (count) | ||
| 756 | "Go down COUNT lines. Stop at first non-white." | ||
| 757 | (interactive "p") | ||
| 758 | (if (= (point) (progn (forward-line count) (back-to-indentation) (point))) | ||
| 759 | (ding))) ; no moving, already at end of buffer | ||
| 760 | |||
| 761 | (defun vi-previous-line-first-nonwhite (count) | ||
| 762 | "Go up COUNT lines. Stop at first non-white." | ||
| 763 | (interactive "p") | ||
| 764 | (previous-line count) | ||
| 765 | (back-to-indentation)) | ||
| 766 | |||
| 767 | (defun vi-scroll-up-window (count) | ||
| 768 | "Scrolls up window COUNT lines. If COUNT is nil (actually, non-integer), | ||
| 769 | scrolls default amount. The given COUNT is remembered for future scrollings." | ||
| 770 | (interactive "P") | ||
| 771 | (if (integerp count) | ||
| 772 | (setq vi-scroll-amount count)) | ||
| 773 | (scroll-down vi-scroll-amount)) | ||
| 774 | |||
| 775 | (defun vi-expose-line-above (count) | ||
| 776 | "Expose COUNT more lines above the current window. Default COUNT is 1." | ||
| 777 | (interactive "p") | ||
| 778 | (scroll-down count)) | ||
| 779 | |||
| 780 | (defun vi-char-argument (arg) | ||
| 781 | "Get following character (could be any CHAR) as part of the prefix argument. | ||
| 782 | Possible perfix-arg cases are NIL, INTEGER, (NIL . CHAR) or (INTEGER . CHAR)." | ||
| 783 | (interactive "P") | ||
| 784 | (let ((char (read-char))) | ||
| 785 | (cond ((null arg) (setq prefix-arg (cons nil char))) | ||
| 786 | ((integerp arg) (setq prefix-arg (cons arg char))) | ||
| 787 | ; This can happen only if the user changed his/her mind for CHAR, | ||
| 788 | ; Or there are some leading "universal-argument"s | ||
| 789 | (t (setq prefix-arg (cons (car arg) char)))))) | ||
| 790 | |||
| 791 | (defun vi-goto-mark (mark-char &optional line-flag) | ||
| 792 | "Go to marked position or line (if line-flag is given). Goto mark '@' means | ||
| 793 | jump into and pop the top mark on the mark ring." | ||
| 794 | (cond ((char-equal mark-char last-command-char) ; `` or '' | ||
| 795 | (exchange-point-and-mark) (if line-flag (back-to-indentation))) | ||
| 796 | ((char-equal mark-char ?@) ; jump and pop mark | ||
| 797 | (set-mark-command t) (if line-flag (back-to-indentation))) | ||
| 798 | (t | ||
| 799 | (let ((mark (vi-get-mark mark-char))) | ||
| 800 | (if (null mark) | ||
| 801 | (message "Mark register undefined." (vi-ding)) | ||
| 802 | (set-mark-command nil) | ||
| 803 | (goto-char mark) | ||
| 804 | (if line-flag (back-to-indentation))))))) | ||
| 805 | |||
| 806 | (defun vi-goto-line-mark (char) | ||
| 807 | "Go to the line (at first non-white) marked by next char." | ||
| 808 | (interactive "c") | ||
| 809 | (vi-goto-mark char t)) | ||
| 810 | |||
| 811 | (defun vi-goto-char-mark (char) | ||
| 812 | "Go to the char position marked by next mark-char." | ||
| 813 | (interactive "c") | ||
| 814 | (vi-goto-mark char)) | ||
| 815 | |||
| 816 | (defun vi-digit-argument (arg) | ||
| 817 | "Set numeric prefix argument." | ||
| 818 | (interactive "P") | ||
| 819 | (cond ((null arg) (digit-argument arg)) | ||
| 820 | ((integerp arg) (digit-argument nil) | ||
| 821 | (setq prefix-arg (* prefix-arg arg))) | ||
| 822 | (t (digit-argument nil) ; in (NIL . CHAR) or (NUM . CHAR) form | ||
| 823 | (setq prefix-arg (cons (* prefix-arg | ||
| 824 | (if (null (car arg)) 1 (car arg))) | ||
| 825 | (cdr arg)))))) | ||
| 826 | |||
| 827 | (defun vi-raw-numeric-prefix (arg) | ||
| 828 | "Return the raw value of numeric part prefix argument." | ||
| 829 | (if (consp arg) (car arg) arg)) | ||
| 830 | |||
| 831 | (defun vi-prefix-numeric-value (arg) | ||
| 832 | "Return numeric meaning of the raw prefix argument. This is a modification | ||
| 833 | to the standard one provided in `callint.c' to handle (_ . CHAR) cases." | ||
| 834 | (cond ((null arg) 1) | ||
| 835 | ((integerp arg) arg) | ||
| 836 | ((consp arg) (if (car arg) (car arg) 1)))) | ||
| 837 | |||
| 838 | (defun vi-reverse-last-find-char (count &optional find-arg) | ||
| 839 | "Reverse last f F t T operation COUNT times. If the optional FIND-ARG | ||
| 840 | is given, it is used instead of the saved one." | ||
| 841 | (interactive "p") | ||
| 842 | (if (null find-arg) (setq find-arg vi-last-find-char)) | ||
| 843 | (if (null find-arg) | ||
| 844 | (message "No last find char to repeat." (ding)) | ||
| 845 | (vi-find-char (cons (* (car find-arg) -1) (cdr find-arg)) count))) ;6/13/86 | ||
| 846 | |||
| 847 | (defun vi-find-char (arg count) | ||
| 848 | "Find in DIRECTION (1/-1) for CHAR of COUNT'th times on current line. | ||
| 849 | If UPTO-FLAG is T, stop before the char. ARG = (DIRECTION.CHAR.UPTO-FLAG." | ||
| 850 | (let* ((direction (car arg)) (char (car (cdr arg))) | ||
| 851 | (upto-flag (cdr (cdr arg))) (pos (+ (point) direction))) | ||
| 852 | (if (catch 'exit-find-char | ||
| 853 | (while t | ||
| 854 | (cond ((null (char-after pos)) (throw 'exit-find-char nil)) | ||
| 855 | ((char-equal (char-after pos) ?\n) (throw 'exit-find-char nil)) | ||
| 856 | ((char-equal char (char-after pos)) (setq count (1- count)) | ||
| 857 | (if (= count 0) | ||
| 858 | (throw 'exit-find-char | ||
| 859 | (if upto-flag | ||
| 860 | (setq pos (- pos direction)) | ||
| 861 | pos))))) | ||
| 862 | (setq pos (+ pos direction)))) | ||
| 863 | (goto-char pos) | ||
| 864 | (ding)))) | ||
| 865 | |||
| 866 | (defun vi-repeat-last-find-char (count &optional find-arg) | ||
| 867 | "Repeat last f F t T operation COUNT times. If optional FIND-ARG is given, | ||
| 868 | it is used instead of the saved one." | ||
| 869 | (interactive "p") | ||
| 870 | (if (null find-arg) (setq find-arg vi-last-find-char)) | ||
| 871 | (if (null find-arg) | ||
| 872 | (message "No last find char to repeat." (ding)) | ||
| 873 | (vi-find-char find-arg count))) | ||
| 874 | |||
| 875 | (defun vi-backward-find-char (count char) | ||
| 876 | "Find the COUNT'th CHAR backward on current line." | ||
| 877 | (interactive "p\nc") | ||
| 878 | (setq vi-last-find-char (cons -1 (cons char nil))) | ||
| 879 | (vi-repeat-last-find-char count)) | ||
| 880 | |||
| 881 | (defun vi-forward-find-char (count char) | ||
| 882 | "Find the COUNT'th CHAR forward on current line." | ||
| 883 | (interactive "p\nc") | ||
| 884 | (setq vi-last-find-char (cons 1 (cons char nil))) | ||
| 885 | (vi-repeat-last-find-char count)) | ||
| 886 | |||
| 887 | (defun vi-backward-upto-char (count char) | ||
| 888 | "Find upto the COUNT'th CHAR backward on current line." | ||
| 889 | (interactive "p\nc") | ||
| 890 | (setq vi-last-find-char (cons -1 (cons char t))) | ||
| 891 | (vi-repeat-last-find-char count)) | ||
| 892 | |||
| 893 | (defun vi-forward-upto-char (count char) | ||
| 894 | "Find upto the COUNT'th CHAR forward on current line." | ||
| 895 | (interactive "p\nc") | ||
| 896 | (setq vi-last-find-char (cons 1 (cons char t))) | ||
| 897 | (vi-repeat-last-find-char count)) | ||
| 898 | |||
| 899 | (defun vi-end-of-word (count) | ||
| 900 | "Move forward until encountering the end of a word. | ||
| 901 | With argument, do this that many times." | ||
| 902 | (interactive "p") | ||
| 903 | (if (not (eobp)) (forward-char)) | ||
| 904 | (if (re-search-forward "\\W*\\w+\\>" nil t count) | ||
| 905 | (backward-char))) | ||
| 906 | |||
| 907 | (defun vi-replace-1-char (count char) | ||
| 908 | "Replace char after point by CHAR. Repeat COUNT times." | ||
| 909 | (interactive "p\nc") | ||
| 910 | (delete-char count nil) ; don't save in kill ring | ||
| 911 | (setq last-command-char char) | ||
| 912 | (self-insert-command count) | ||
| 913 | (vi-set-last-change-command 'vi-replace-1-char count char)) | ||
| 914 | |||
| 915 | (defun vi-replace-chars (arg) | ||
| 916 | "Replace chars over old ones." | ||
| 917 | (interactive "*p") | ||
| 918 | (overwrite-mode 1) | ||
| 919 | (vi-goto-insert-state arg)) | ||
| 920 | |||
| 921 | (defun vi-substitute-chars (count) | ||
| 922 | "Substitute COUNT chars by the input chars, enter insert state." | ||
| 923 | (interactive "*p") | ||
| 924 | (vi-goto-insert-state 1 (list (function (lambda (c) ; this is a bit tricky | ||
| 925 | (delete-region (point) | ||
| 926 | (+ (point) c)))) | ||
| 927 | count) t)) | ||
| 928 | |||
| 929 | (defun vi-substitute-lines (count) | ||
| 930 | "Substitute COUNT lines by the input chars. (=cc in vi)" | ||
| 931 | (interactive "*p") | ||
| 932 | (vi-goto-insert-state 1 (list 'vi-delete-op 'next-line (1- count)) t)) | ||
| 933 | |||
| 934 | (defun vi-prefix-char-value (arg) | ||
| 935 | "Get the char part of the current prefix argument." | ||
| 936 | (cond ((null arg) nil) | ||
| 937 | ((integerp arg) nil) | ||
| 938 | ((consp arg) (cdr arg)) | ||
| 939 | (t nil))) | ||
| 940 | |||
| 941 | (defun vi-operator (arg) | ||
| 942 | "Handling vi operators (d/c/</>/!/=/y). Current implementation requires | ||
| 943 | the key bindings of the operators being fixed." | ||
| 944 | (interactive "P") | ||
| 945 | (catch 'vi-exit-op | ||
| 946 | (let ((this-op-char last-command-char)) | ||
| 947 | (setq last-command-char (read-char)) | ||
| 948 | (setq this-command (lookup-key vi-com-map (char-to-string last-command-char))) | ||
| 949 | (if (not (eq this-command 'vi-digit-argument)) | ||
| 950 | (setq prefix-arg arg) | ||
| 951 | (vi-digit-argument arg) | ||
| 952 | (setq last-command-char (read-char)) | ||
| 953 | (setq this-command (lookup-key vi-com-map (char-to-string last-command-char)))) | ||
| 954 | (cond ((char-equal this-op-char last-command-char) ; line op | ||
| 955 | (vi-execute-op this-op-char 'next-line | ||
| 956 | (cons (1- (vi-prefix-numeric-value prefix-arg)) | ||
| 957 | (vi-prefix-char-value prefix-arg)))) | ||
| 958 | ;; We assume any command that has no property 'point-moving-unit' | ||
| 959 | ;; as having that property with the value 'CHAR'. 3/12/86 | ||
| 960 | (t ;; (get this-command 'point-moving-unit) | ||
| 961 | (vi-execute-op this-op-char this-command prefix-arg)))))) | ||
| 962 | ;; (t (throw 'vi-exit-op (ding))))))) | ||
| 963 | |||
| 964 | (defun vi-execute-op (op-char motion-command arg) | ||
| 965 | "Execute vi edit operator as specified by OP-CHAR, the operand is the region | ||
| 966 | determined by the MOTION-COMMAND with ARG." | ||
| 967 | (cond ((= op-char ?d) | ||
| 968 | (if (vi-delete-op motion-command arg) | ||
| 969 | (vi-set-last-change-command 'vi-delete-op (vi-repeat-command-of motion-command) arg))) | ||
| 970 | ((= op-char ?c) | ||
| 971 | (if (vi-delete-op motion-command arg) | ||
| 972 | (vi-goto-insert-state 1 (list 'vi-delete-op | ||
| 973 | (vi-repeat-command-of motion-command) arg) nil))) | ||
| 974 | ((= op-char ?y) | ||
| 975 | (if (vi-yank-op motion-command arg) | ||
| 976 | (vi-set-last-change-command 'vi-yank-op (vi-repeat-command-of motion-command) arg))) | ||
| 977 | ((= op-char ?!) | ||
| 978 | (if (vi-shell-op motion-command arg) | ||
| 979 | (vi-set-last-change-command 'vi-shell-op (vi-repeat-command-of motion-command) arg vi-last-shell-command))) | ||
| 980 | ((= op-char ?<) | ||
| 981 | (if (vi-shift-op motion-command arg (- vi-shift-width)) | ||
| 982 | (vi-set-last-change-command 'vi-shift-op (vi-repeat-command-of motion-command) arg (- vi-shift-width)))) | ||
| 983 | ((= op-char ?>) | ||
| 984 | (if (vi-shift-op motion-command arg vi-shift-width) | ||
| 985 | (vi-set-last-change-command 'vi-shift-op (vi-repeat-command-of motion-command) arg vi-shift-width))) | ||
| 986 | ((= op-char ?=) | ||
| 987 | (if (vi-indent-op motion-command arg) | ||
| 988 | (vi-set-last-change-command 'vi-indent-op (vi-repeat-command-of motion-command) arg))) | ||
| 989 | ((= op-char ?\\) | ||
| 990 | (vi-narrow-op motion-command arg)))) | ||
| 991 | |||
| 992 | (defun vi-repeat-command-of (command) | ||
| 993 | "Return the command for redo the given command." | ||
| 994 | (let ((cmd-type (get command 'point-moving-unit))) | ||
| 995 | (cond ((eq cmd-type 'search) 'vi-repeat-last-search) | ||
| 996 | ((eq cmd-type 'find) 'vi-repeat-last-find-char) | ||
| 997 | (t command)))) | ||
| 998 | |||
| 999 | (defun vi-effective-range (motion-command arg) | ||
| 1000 | "Return (begin . end) of the range spanned by executing the given | ||
| 1001 | MOTION-COMMAND with ARG. | ||
| 1002 | MOTION-COMMAND in ready-to-eval list form is not yet supported." | ||
| 1003 | (save-excursion | ||
| 1004 | (let ((begin (point)) end opoint | ||
| 1005 | (moving-unit (get motion-command 'point-moving-unit))) | ||
| 1006 | (setq prefix-arg arg) | ||
| 1007 | (setq opoint (point)) | ||
| 1008 | (command-execute motion-command nil) | ||
| 1009 | ;; Check if there is any effective motion. Note that for single line operation | ||
| 1010 | ;; the motion-command causes no effective point movement (since it moves up or | ||
| 1011 | ;; down zero lines), but it should be counted as effectively moved. | ||
| 1012 | (if (and (= (point) opoint) (not (eq moving-unit 'line))) | ||
| 1013 | (cons opoint opoint) ; no effective motion | ||
| 1014 | (if (eq moving-unit 'region) | ||
| 1015 | (setq begin (or (mark) (point)))) | ||
| 1016 | (if (<= begin (point)) | ||
| 1017 | (setq end (point)) | ||
| 1018 | (setq end begin) | ||
| 1019 | (setq begin (point))) | ||
| 1020 | (cond ((or (eq moving-unit 'match) (eq moving-unit 'find)) | ||
| 1021 | (setq end (1+ end))) | ||
| 1022 | ((eq moving-unit 'line) | ||
| 1023 | (goto-char begin) (beginning-of-line) (setq begin (point)) | ||
| 1024 | (goto-char end) (next-line 1) (beginning-of-line) (setq end (point)))) | ||
| 1025 | (if (> end (point-max)) (setq end (point-max))) ; force in buffer region | ||
| 1026 | (cons begin end))))) | ||
| 1027 | |||
| 1028 | (defun vi-delete-op (motion-command arg) | ||
| 1029 | "Delete range specified by MOTION-COMMAND with ARG." | ||
| 1030 | (let* ((range (vi-effective-range motion-command arg)) | ||
| 1031 | (begin (car range)) (end (cdr range)) reg) | ||
| 1032 | (if (= begin end) | ||
| 1033 | nil ; point not moved, abort op | ||
| 1034 | (setq reg (vi-prefix-char-value arg)) | ||
| 1035 | (if (null reg) | ||
| 1036 | (kill-region begin end) ; kill ring as unnamed registers | ||
| 1037 | (if (and (>= reg ?A) (<= reg ?Z)) | ||
| 1038 | (append-to-register (downcase reg) begin end t) | ||
| 1039 | (copy-to-register reg begin end t))) | ||
| 1040 | t))) | ||
| 1041 | |||
| 1042 | (defun vi-yank-op (motion-command arg) | ||
| 1043 | "Yank (in vi sense) range specified by MOTION-COMMAND with ARG." | ||
| 1044 | (let* ((range (vi-effective-range motion-command arg)) | ||
| 1045 | (begin (car range)) (end (cdr range)) reg) | ||
| 1046 | (if (= begin end) | ||
| 1047 | nil ; point not moved, abort op | ||
| 1048 | (setq reg (vi-prefix-char-value arg)) | ||
| 1049 | (if (null reg) | ||
| 1050 | (copy-region-as-kill begin end); kill ring as unnamed registers | ||
| 1051 | (if (and (>= reg ?A) (<= reg ?Z)) | ||
| 1052 | (append-to-register (downcase reg) begin end nil) | ||
| 1053 | (copy-to-register reg begin end nil))) | ||
| 1054 | t))) | ||
| 1055 | |||
| 1056 | (defun vi-yank-line (arg) | ||
| 1057 | "Yank (in vi sense) lines (= `yy' command)." | ||
| 1058 | (interactive "*P") | ||
| 1059 | (setq arg (cons (1- (vi-prefix-numeric-value arg)) (vi-prefix-char-value arg))) | ||
| 1060 | (if (vi-yank-op 'next-line arg) | ||
| 1061 | (vi-set-last-change-command 'vi-yank-op 'next-line arg))) | ||
| 1062 | |||
| 1063 | (defun vi-string-end-with-nl-p (string) | ||
| 1064 | "See if STRING ends with a newline char. Used in checking whether the yanked | ||
| 1065 | text should be put back as lines or not." | ||
| 1066 | (= (aref string (1- (length string))) ?\n)) | ||
| 1067 | |||
| 1068 | (defun vi-put-before (arg &optional after-p) | ||
| 1069 | "Put yanked (in vi sense) text back before/above cursor. If a numeric prefix | ||
| 1070 | value (currently it should be >1) is given, put back text as lines. | ||
| 1071 | If the optional after-p is given, put after/below the cursor." | ||
| 1072 | (interactive "P") | ||
| 1073 | (let ((reg (vi-prefix-char-value arg)) put-text) | ||
| 1074 | (if (and reg (or (< reg ?1) (> reg ?9)) (null (get-register reg))) | ||
| 1075 | (error "Nothing in register %c" reg) | ||
| 1076 | (if (null reg) (setq reg ?1)) ; the default is the last text killed | ||
| 1077 | (setq put-text | ||
| 1078 | (if (and (>= reg ?1) (<= reg ?9)) | ||
| 1079 | (let ((ring-length (length kill-ring))) | ||
| 1080 | (setq this-command 'yank) ; So we may yank-pop !! | ||
| 1081 | (nth (% (+ (- reg ?0 1) (- ring-length | ||
| 1082 | (length kill-ring-yank-pointer))) | ||
| 1083 | ring-length) kill-ring)) | ||
| 1084 | (if (stringp (get-register reg)) | ||
| 1085 | (get-register reg) | ||
| 1086 | (error "Register %c is not containing text string" reg)))) | ||
| 1087 | (if (vi-string-end-with-nl-p put-text) ; put back text as lines | ||
| 1088 | (if after-p | ||
| 1089 | (progn (next-line 1) (beginning-of-line)) | ||
| 1090 | (beginning-of-line)) | ||
| 1091 | (if after-p (forward-char 1))) | ||
| 1092 | (push-mark (point)) | ||
| 1093 | (insert put-text) | ||
| 1094 | (exchange-point-and-mark) | ||
| 1095 | ;; (back-to-indentation) ; this is not allowed if we allow yank-pop | ||
| 1096 | (vi-set-last-change-command 'vi-put-before arg after-p)))) | ||
| 1097 | |||
| 1098 | (defun vi-put-after (arg) | ||
| 1099 | "Put yanked (in vi sense) text back after/below cursor." | ||
| 1100 | (interactive "P") | ||
| 1101 | (vi-put-before arg t)) | ||
| 1102 | |||
| 1103 | (defun vi-shell-op (motion-command arg &optional shell-command) | ||
| 1104 | "Perform shell command (as filter) on range specified by MOTION-COMMAND | ||
| 1105 | with ARG. If SHELL-COMMAND is not given, ask for one from minibuffer. | ||
| 1106 | If char argument is given, it directs the output to a *temp* buffer." | ||
| 1107 | (let* ((range (vi-effective-range motion-command arg)) | ||
| 1108 | (begin (car range)) (end (cdr range))) | ||
| 1109 | (if (= begin end) | ||
| 1110 | nil ; point not moved, abort op | ||
| 1111 | (cond ((null shell-command) | ||
| 1112 | (setq shell-command (read-string "!" nil)) | ||
| 1113 | (setq vi-last-shell-command shell-command))) | ||
| 1114 | (shell-command-on-region begin end shell-command (not (vi-prefix-char-value arg))) | ||
| 1115 | t))) | ||
| 1116 | |||
| 1117 | (defun vi-shift-op (motion-command arg amount) | ||
| 1118 | "Perform shift command on range specified by MOTION-COMMAND with ARG for | ||
| 1119 | AMOUNT on each line. Negative amount means shift left. | ||
| 1120 | SPECIAL FEATURE: char argument can be used to specify shift amount(1-9)." | ||
| 1121 | (let* ((range (vi-effective-range motion-command arg)) | ||
| 1122 | (begin (car range)) (end (cdr range))) | ||
| 1123 | (if (= begin end) | ||
| 1124 | nil ; point not moved, abort op | ||
| 1125 | (if (vi-prefix-char-value arg) | ||
| 1126 | (setq amount (if (> amount 0) | ||
| 1127 | (- (vi-prefix-char-value arg) ?0) | ||
| 1128 | (- ?0 (vi-prefix-char-value arg))))) | ||
| 1129 | (indent-rigidly begin end amount) | ||
| 1130 | t))) | ||
| 1131 | |||
| 1132 | (defun vi-indent-op (motion-command arg) | ||
| 1133 | "Perform indent command on range specified by MOTION-COMMAND with ARG." | ||
| 1134 | (let* ((range (vi-effective-range motion-command arg)) | ||
| 1135 | (begin (car range)) (end (cdr range))) | ||
| 1136 | (if (= begin end) | ||
| 1137 | nil ; point not moved, abort op | ||
| 1138 | (indent-region begin end nil) ; insert TAB as indent command | ||
| 1139 | t))) | ||
| 1140 | |||
| 1141 | (defun vi-narrow-op (motion-command arg) | ||
| 1142 | "Narrow to region specified by MOTION-COMMAND with ARG." | ||
| 1143 | (let* ((range (vi-effective-range motion-command arg)) | ||
| 1144 | (begin (car range)) (end (cdr range)) reg) | ||
| 1145 | (if (= begin end) | ||
| 1146 | nil ; point not moved, abort op | ||
| 1147 | (narrow-to-region begin end)))) | ||
| 1148 | |||
| 1149 | (defun vi-get-mark (char) | ||
| 1150 | "Return contents of vi mark register named CHAR, or nil if undefined." | ||
| 1151 | (cdr (assq char vi-mark-alist))) | ||
| 1152 | |||
| 1153 | (defun vi-set-mark (char) | ||
| 1154 | "Set contents of vi mark register named CHAR to current point. '@' is the | ||
| 1155 | special anonymous mark register." | ||
| 1156 | (interactive "c") | ||
| 1157 | (if (char-equal char ?@) | ||
| 1158 | (set-mark-command nil) | ||
| 1159 | (let ((aelt (assq char vi-mark-alist))) | ||
| 1160 | (if aelt | ||
| 1161 | (move-marker (cdr aelt) (point)) ; fixed 6/12/86 | ||
| 1162 | (setq aelt (cons char (copy-marker (point)))) | ||
| 1163 | (setq vi-mark-alist (cons aelt vi-mark-alist)))))) | ||
| 1164 | |||
| 1165 | (defun vi-find-matching-paren () | ||
| 1166 | "Locate the matching paren. It's a hack right now." | ||
| 1167 | (interactive) | ||
| 1168 | (cond ((looking-at "[[({]") (forward-sexp 1) (backward-char 1)) | ||
| 1169 | ((looking-at "[])}]") (forward-char 1) (backward-sexp 1)) | ||
| 1170 | (t (ding)))) | ||
| 1171 | |||
| 1172 | (defun vi-backward-blank-delimited-word (count) | ||
| 1173 | "Backward COUNT blank-delimited words." | ||
| 1174 | (interactive "p") | ||
| 1175 | (if (re-search-backward "[ \t\n\`][^ \t\n\`]+" nil t count) | ||
| 1176 | (if (not (bobp)) (forward-char 1)))) | ||
| 1177 | |||
| 1178 | (defun vi-forward-blank-delimited-word (count) | ||
| 1179 | "Forward COUNT blank-delimited words." | ||
| 1180 | (interactive "p") | ||
| 1181 | (if (re-search-forward "[^ \t\n]*[ \t\n]+[^ \t\n]" nil t count) | ||
| 1182 | (if (not (eobp)) (backward-char 1)))) | ||
| 1183 | |||
| 1184 | (defun vi-end-of-blank-delimited-word (count) | ||
| 1185 | "Forward to the end of the COUNT'th blank-delimited word." | ||
| 1186 | (interactive "p") | ||
| 1187 | (if (re-search-forward "[^ \t\n\']+[ \t\n\']" nil t count) | ||
| 1188 | (if (not (eobp)) (backward-char 2)))) | ||
| 1189 | |||
| 1190 | (defun vi-home-window-line (arg) | ||
| 1191 | "To window home or arg'th line from the top of the window." | ||
| 1192 | (interactive "p") | ||
| 1193 | (move-to-window-line (1- arg)) | ||
| 1194 | (back-to-indentation)) | ||
| 1195 | |||
| 1196 | (defun vi-last-window-line (arg) | ||
| 1197 | "To window last line or arg'th line from the bottom of the window." | ||
| 1198 | (interactive "p") | ||
| 1199 | (move-to-window-line (- arg)) | ||
| 1200 | (back-to-indentation)) | ||
| 1201 | |||
| 1202 | (defun vi-middle-window-line () | ||
| 1203 | "To the middle line of the window." | ||
| 1204 | (interactive) | ||
| 1205 | (move-to-window-line nil) | ||
| 1206 | (back-to-indentation)) | ||
| 1207 | |||
| 1208 | (defun vi-forward-word (count) | ||
| 1209 | "Stop at the beginning of the COUNT'th words from point." | ||
| 1210 | (interactive "p") | ||
| 1211 | (if (re-search-forward "\\w*\\W+\\<" nil t count) | ||
| 1212 | t | ||
| 1213 | (vi-ding))) | ||
| 1214 | |||
| 1215 | (defun vi-set-last-change-command (fun &rest args) | ||
| 1216 | "Set (FUN . ARGS) as the last-change-command." | ||
| 1217 | (setq vi-last-change-command (cons fun args))) | ||
| 1218 | |||
| 1219 | (defun vi-redo-last-change-command (count &optional command) | ||
| 1220 | "Redo last change command COUNT times. If the optional COMMAND is given, | ||
| 1221 | it is used instead of the current last-change-command." | ||
| 1222 | (interactive "p") | ||
| 1223 | (if (null command) | ||
| 1224 | (setq command vi-last-change-command)) | ||
| 1225 | (if (null command) | ||
| 1226 | (message "No last change command available.") | ||
| 1227 | (while (> count 0) | ||
| 1228 | (apply (car command) (cdr command)) | ||
| 1229 | (setq count (1- count))))) | ||
| 1230 | |||
| 1231 | (defun vi-kill-char (count) | ||
| 1232 | "Kill COUNT chars from current point." | ||
| 1233 | (interactive "*p") | ||
| 1234 | (delete-char count t) ; save in kill ring | ||
| 1235 | (vi-set-last-change-command 'delete-char count t)) | ||
| 1236 | |||
| 1237 | (defun vi-transpose-objects (arg unit) | ||
| 1238 | "Transpose objects, the following char specifies unit of objects to be | ||
| 1239 | transposed -- \"c\" for chars, \"l\" for lines, \"w\" for words, \"s\" for | ||
| 1240 | sexp, \"p\" for paragraph. | ||
| 1241 | For the use of the prefix-arg, refer to individual functions called." | ||
| 1242 | (interactive "*P\nc") | ||
| 1243 | (if (char-equal unit ??) | ||
| 1244 | (progn | ||
| 1245 | (message "Transpose: c(har), l(ine), p(aragraph), s(-exp), w(ord),") | ||
| 1246 | (setq unit (read-char)))) | ||
| 1247 | (vi-set-last-change-command 'vi-transpose-objects arg unit) | ||
| 1248 | (cond ((char-equal unit ?c) (transpose-chars arg)) | ||
| 1249 | ((char-equal unit ?l) (transpose-lines (vi-prefix-numeric-value arg))) | ||
| 1250 | ((char-equal unit ?p) (transpose-paragraphs (vi-prefix-numeric-value arg))) | ||
| 1251 | ((char-equal unit ?s) (transpose-sexps (vi-prefix-numeric-value arg))) | ||
| 1252 | ((char-equal unit ?w) (transpose-words (vi-prefix-numeric-value arg))) | ||
| 1253 | (t (vi-transpose-objects arg ??)))) | ||
| 1254 | |||
| 1255 | (defun vi-query-replace (arg) | ||
| 1256 | "Query replace, use regexp version if ARG is non-nil." | ||
| 1257 | (interactive "*P") | ||
| 1258 | (let ((rcmd (if arg 'query-replace-regexp 'query-replace))) | ||
| 1259 | (call-interactively rcmd nil))) | ||
| 1260 | |||
| 1261 | (defun vi-replace (arg) | ||
| 1262 | "Replace strings, use regexp version if ARG is non-nil." | ||
| 1263 | (interactive "*P") | ||
| 1264 | (let ((rcmd (if arg 'replace-regexp 'replace-string))) | ||
| 1265 | (call-interactively rcmd nil))) | ||
| 1266 | |||
| 1267 | (defun vi-adjust-window (arg position) | ||
| 1268 | "Move current line to the top/center/bottom of the window." | ||
| 1269 | (interactive "p\nc") | ||
| 1270 | (cond ((char-equal position ?\r) (recenter 0)) | ||
| 1271 | ((char-equal position ?-) (recenter -1)) | ||
| 1272 | ((char-equal position ?.) (recenter (/ (window-height) 2))) | ||
| 1273 | (t (message "Move current line to: \\r(top) -(bottom) .(middle)") | ||
| 1274 | (setq position (read-char)) | ||
| 1275 | (vi-adjust-window arg position)))) | ||
| 1276 | |||
| 1277 | (defun vi-goto-column (col) | ||
| 1278 | "Go to given column of the current line." | ||
| 1279 | (interactive "p") | ||
| 1280 | (let ((opoint (point))) | ||
| 1281 | (beginning-of-line) | ||
| 1282 | (while (> col 1) | ||
| 1283 | (if (eolp) | ||
| 1284 | (setq col 0) | ||
| 1285 | (forward-char 1) | ||
| 1286 | (setq col (1- col)))) | ||
| 1287 | (if (= col 1) | ||
| 1288 | t | ||
| 1289 | (goto-char opoint) | ||
| 1290 | (ding)))) | ||
| 1291 | |||
| 1292 | (defun vi-name-last-change-or-macro (arg char) | ||
| 1293 | "Give name to the last change command or just defined kbd macro. If prefix | ||
| 1294 | ARG is given, name last macro, otherwise name last change command. The | ||
| 1295 | following CHAR will be the name for the command or macro." | ||
| 1296 | (interactive "P\nc") | ||
| 1297 | (if arg | ||
| 1298 | (name-last-kbd-macro (intern (char-to-string char))) | ||
| 1299 | (if (eq (car vi-last-change-command) 'vi-first-redo-insertion) | ||
| 1300 | (let* ((args (cdr vi-last-change-command)) ; save the insertion text | ||
| 1301 | (str (buffer-substring (nth 0 args) (nth 1 args))) | ||
| 1302 | (overwrite-p (nth 2 args)) | ||
| 1303 | (prefix-code (nth 3 args))) | ||
| 1304 | (vi-set-last-change-command 'vi-more-redo-insertion str | ||
| 1305 | overwrite-p prefix-code))) | ||
| 1306 | (fset (intern (char-to-string char)) vi-last-change-command))) | ||
| 1307 | |||
| 1308 | (defun vi-call-named-change-or-macro (count char) | ||
| 1309 | "Execute COUNT times the keyboard macro definition named by the following CHAR." | ||
| 1310 | (interactive "p\nc") | ||
| 1311 | (if (stringp (symbol-function (intern (char-to-string char)))) | ||
| 1312 | (execute-kbd-macro (intern (char-to-string char)) count) | ||
| 1313 | (vi-redo-last-change-command count (symbol-function (intern (char-to-string char)))))) | ||
| 1314 | |||
| 1315 | (defun vi-change-case (arg) ; could be made as an operator ? | ||
| 1316 | "Change the case of the char after point." | ||
| 1317 | (interactive "*p") | ||
| 1318 | (catch 'exit | ||
| 1319 | (if (looking-at "[a-z]") | ||
| 1320 | (upcase-region (point) (+ (point) arg)) | ||
| 1321 | (if (looking-at "[A-Z]") | ||
| 1322 | (downcase-region (point) (+ (point) arg)) | ||
| 1323 | (ding) | ||
| 1324 | (throw 'exit nil))) | ||
| 1325 | (vi-set-last-change-command 'vi-change-case arg) ;should avoid redundant save | ||
| 1326 | (forward-char arg))) | ||
| 1327 | |||
| 1328 | (defun vi-ask-for-info (char) | ||
| 1329 | "Inquire status info. The next CHAR will specify the particular info requested." | ||
| 1330 | (interactive "c") | ||
| 1331 | (cond ((char-equal char ?l) (what-line)) | ||
| 1332 | ((char-equal char ?c) (what-cursor-position)) | ||
| 1333 | ((char-equal char ?p) (what-page)) | ||
| 1334 | (t (message "Ask for: l(ine number), c(ursor position), p(age number)") | ||
| 1335 | (setq char (read-char)) | ||
| 1336 | (vi-ask-for-info char)))) | ||
| 1337 | |||
| 1338 | (defun vi-mark-region (arg region) | ||
| 1339 | "Mark region approriately. The next char REGION is d(efun),s(-exp),b(uffer), | ||
| 1340 | p(aragraph), P(age), f(unction in C/Pascal etc.), w(ord), e(nd of sentence), | ||
| 1341 | l(ines)." | ||
| 1342 | (interactive "p\nc") | ||
| 1343 | (cond ((char-equal region ?d) (mark-defun arg)) | ||
| 1344 | ((char-equal region ?s) (mark-sexp arg)) | ||
| 1345 | ((char-equal region ?b) (mark-whole-buffer)) | ||
| 1346 | ((char-equal region ?p) (mark-paragraph arg)) | ||
| 1347 | ((char-equal region ?P) (mark-page arg)) | ||
| 1348 | ((char-equal region ?f) (mark-c-function arg)) | ||
| 1349 | ((char-equal region ?w) (mark-word arg)) | ||
| 1350 | ((char-equal region ?e) (mark-end-of-sentence arg)) | ||
| 1351 | ((char-equal region ?l) (vi-mark-lines arg)) | ||
| 1352 | (t (message "Mark: d(efun),s(-exp),b(uf),p(arag),P(age),f(unct),w(ord),e(os),l(ines)") | ||
| 1353 | (setq region (read-char)) | ||
| 1354 | (vi-mark-region arg region)))) | ||
| 1355 | |||
| 1356 | (defun vi-mark-lines (num) | ||
| 1357 | "Mark NUM of lines from current line as current region." | ||
| 1358 | (beginning-of-line 1) | ||
| 1359 | (push-mark) | ||
| 1360 | (end-of-line num)) | ||
| 1361 | |||
| 1362 | (defun vi-verify-spelling (arg unit) | ||
| 1363 | "Verify spelling for the objects specified by char UNIT : [b(uffer), | ||
| 1364 | r(egion), s(tring), w(ord) ]." | ||
| 1365 | (interactive "P\nc") | ||
| 1366 | (setq prefix-arg arg) ; seems not needed | ||
| 1367 | (cond ((char-equal unit ?b) (call-interactively 'spell-buffer)) | ||
| 1368 | ((char-equal unit ?r) (call-interactively 'spell-region)) | ||
| 1369 | ((char-equal unit ?s) (call-interactively 'spell-string)) | ||
| 1370 | ((char-equal unit ?w) (call-interactively 'spell-word)) | ||
| 1371 | (t (message "Spell check: b(uffer), r(egion), s(tring), w(ord)") | ||
| 1372 | (setq unit (read-char)) | ||
| 1373 | (vi-verify-spelling arg unit)))) | ||
| 1374 | |||
| 1375 | (defun vi-do-old-mode-C-c-command (arg) | ||
| 1376 | "This is a hack for accessing mode specific C-c commands in vi-mode." | ||
| 1377 | (interactive "P") | ||
| 1378 | (let ((cmd (lookup-key vi-mode-old-local-map | ||
| 1379 | (concat "\C-c" (char-to-string (read-char)))))) | ||
| 1380 | (if (catch 'exit-vi-mode ; kludge hack due to dynamic binding | ||
| 1381 | ; of case-fold-search | ||
| 1382 | (if (null cmd) | ||
| 1383 | (progn (ding) nil) | ||
| 1384 | (let ((case-fold-search vi-mode-old-case-fold)) ; a hack | ||
| 1385 | (setq prefix-arg arg) | ||
| 1386 | (command-execute cmd nil) | ||
| 1387 | nil))) | ||
| 1388 | (progn | ||
| 1389 | (vi-back-to-old-mode) | ||
| 1390 | (setq prefix-arg arg) | ||
| 1391 | (command-execute cmd nil))))) | ||
| 1392 | |||
| 1393 | (defun vi-quote-words (arg char) | ||
| 1394 | "Quote ARG words from the word point is on with the pattern specified by the | ||
| 1395 | CHAR. Currently, CHAR could be [,{,(,\",',`,<,*, etc." | ||
| 1396 | (interactive "*p\nc") | ||
| 1397 | (while (not (string-match "[[({<\"'`*]" (char-to-string char))) | ||
| 1398 | (message "Enter any of [,{,(,<,\",',`,* as quoting character.") | ||
| 1399 | (setq char (read-char))) | ||
| 1400 | (vi-set-last-change-command 'vi-quote-words arg char) | ||
| 1401 | (if (not (looking-at "\\<")) (forward-word -1)) | ||
| 1402 | (insert char) | ||
| 1403 | (cond ((char-equal char ?[) (setq char ?])) | ||
| 1404 | ((char-equal char ?{) (setq char ?})) | ||
| 1405 | ((char-equal char ?<) (setq char ?>)) | ||
| 1406 | ((char-equal char ?() (setq char ?))) | ||
| 1407 | ((char-equal char ?`) (setq char ?'))) | ||
| 1408 | (vi-end-of-word arg) | ||
| 1409 | (forward-char 1) | ||
| 1410 | (insert char)) | ||
| 1411 | |||
| 1412 | (defun vi-locate-def () | ||
| 1413 | "Locate definition in current file for the name before the point. It assumes | ||
| 1414 | a `(def..' always starts at the beginning of a line." | ||
| 1415 | (interactive) | ||
| 1416 | (let (name) | ||
| 1417 | (save-excursion | ||
| 1418 | (setq name (buffer-substring (progn (vi-backward-blank-delimited-word 1) | ||
| 1419 | (skip-chars-forward "^a-zA-Z") | ||
| 1420 | (point)) | ||
| 1421 | (progn (vi-end-of-blank-delimited-word 1) | ||
| 1422 | (forward-char) | ||
| 1423 | (skip-chars-backward "^a-zA-Z") | ||
| 1424 | (point))))) | ||
| 1425 | (set-mark-command nil) | ||
| 1426 | (goto-char (point-min)) | ||
| 1427 | (if (re-search-forward (concat "^(def[unvarconst ]*" name) nil t) | ||
| 1428 | nil | ||
| 1429 | (message "No definition for \"%s\" in current file." name (ding)) | ||
| 1430 | (set-mark-command t)))) | ||
| 1431 | |||
| 1432 | (defun vi-split-open-line (arg) | ||
| 1433 | "Insert a newline and leave point before it. | ||
| 1434 | With arg, inserts that many newlines." | ||
| 1435 | (interactive "*p") | ||
| 1436 | (vi-goto-insert-state 1 | ||
| 1437 | (list (function (lambda (arg) | ||
| 1438 | (let ((flag (and (bolp) (not (bobp))))) | ||
| 1439 | (if flag (forward-char -1)) | ||
| 1440 | (while (> arg 0) | ||
| 1441 | (save-excursion | ||
| 1442 | (insert ?\n) | ||
| 1443 | (if fill-prefix (insert fill-prefix))) | ||
| 1444 | (setq arg (1- arg))) | ||
| 1445 | (if flag (forward-char 1))))) arg) | ||
| 1446 | t)) | ||