6
|
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))
|