|
|
1.1 root 1: ; Evi: Major mode for emulating "vi" editor under GNU Emacs.
2: ; Originally written by : [email protected] (Neal Ziring)
3: ; Extensively redesigned and rewritten by [email protected] (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))
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.