Comment changes.
[bpt/emacs.git] / lisp / emulation / viper-ex.el
CommitLineData
6c2e12f4
KH
1;;; viper-ex.el -- functions implementing the Ex commands for Viper
2
3;; This file is part of GNU Emacs.
4
5;; GNU Emacs is free software; you can redistribute it and/or modify
6;; it under the terms of the GNU General Public License as published by
7;; the Free Software Foundation; either version 2, or (at your option)
8;; any later version.
9
10;; GNU Emacs is distributed in the hope that it will be useful,
11;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13;; GNU General Public License for more details.
14
15;; You should have received a copy of the GNU General Public License
16;; along with GNU Emacs; see the file COPYING. If not, write to
17;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18
19
20(require 'viper-util)
21
22;;; Variables
23
24(defconst vip-ex-work-buf-name " *ex-working-space*")
25(defconst vip-ex-work-buf (get-buffer-create vip-ex-work-buf-name))
26
27
fad2477b 28;;; Variable completion in :set command
6c2e12f4
KH
29
30;; The list of Ex commands. Used for completing command names.
31(defconst ex-token-alist
32 '(("!") ("=") (">") ("&") ("~")
33 ("yank") ("xit") ("WWrite") ("Write") ("write") ("wq") ("visual")
34 ("version") ("vglobal") ("unmap") ("undo") ("tag") ("transfer") ("suspend")
35 ("substitute") ("submitReport") ("stop") ("sr") ("source") ("shell")
36 ("set") ("rewind") ("recover") ("read") ("quit") ("pwd")
37 ("put") ("preserve") ("PreviousRelatedFile") ("RelatedFile")
38 ("next") ("Next") ("move") ("mark") ("map") ("kmark") ("join")
39 ("help") ("goto") ("global") ("file") ("edit") ("delete") ("copy")
40 ("chdir") ("cd") ("Buffer") ("buffer") ("args")) )
41
42;; A-list of Ex variables that can be set using the :set command.
43(defconst ex-variable-alist
44 '(("wrapscan") ("ws") ("wrapmargin") ("wm")
45 ("tab-stop-local") ("tsl") ("tabstop") ("ts")
46 ("showmatch") ("sm") ("shiftwidth") ("sw") ("shell") ("sh")
47 ("readonly") ("ro")
48 ("nowrapscan") ("nows") ("noshowmatch") ("nosm")
49 ("noreadonly") ("noro") ("nomagic") ("noma")
50 ("noignorecase") ("noic") ("noautoindent") ("noai")
51 ("magic") ("ma") ("ignorecase") ("ic") ("autoindent") ("ai")
52 ))
53
54
55
56;; Token recognized during parsing of Ex commands (e.g., "read", "comma")
57(defvar ex-token nil)
58
59;; Type of token.
60;; If non-nil, gives type of address; if nil, it is a command.
61(defvar ex-token-type nil)
62
63;; List of addresses passed to Ex command
64(defvar ex-addresses nil)
65
66;; It seems that this flag is used only for `#', `print', and `list', which
67;; aren't implemented. Check later.
68(defvar ex-flag nil)
69
70;; "buffer" where Ex commands keep deleted data.
71;; In Emacs terms, this is a register.
72(defvar ex-buffer nil)
73
74;; Value of ex count.
75(defvar ex-count nil)
76
77;; Flag for global command.
78(defvar ex-g-flag nil)
79
80;; If t, global command is executed on lines not matching ex-g-pat.
81(defvar ex-g-variant nil)
82
83;; Save reg-exp used in substitute.
84(defvar ex-reg-exp nil)
85
86
87;; Replace pattern for substitute.
88(defvar ex-repl nil)
89
90;; Pattern for global command.
91(defvar ex-g-pat nil)
92
93;; `sh' doesn't seem to expand wildcards, like `*'
94(defconst ex-find-file-shell "csh"
95 "Shell in which to interpret wildcards.")
96(defvar ex-find-file-shell-options "-f"
97 "*Options to pass to `ex-find-file-shell'.")
98
99;; Remembers the previous Ex tag.
100(defvar ex-tag nil)
101
102;; file used by Ex commands like :r, :w, :n
103(defvar ex-file nil)
104
105;; If t, tells Ex that this is a variant-command, i.e., w>>, r!, etc.
106(defvar ex-variant nil)
107
108;; Specified the offset of an Ex command, such as :read.
109(defvar ex-offset nil)
110
111;; Tells Ex that this is a w>> command.
112(defvar ex-append nil)
113
114;; File containing the shell command to be executed at Ex prompt,
115;; e.g., :r !date
116(defvar ex-cmdfile nil)
117
118;; flag used in vip-ex-read-file-name to indicate that we may be reading
119;; multiple file names. Used for :edit and :next
120(defvar vip-keep-reading-filename nil)
121
122(defconst ex-cycle-other-window t
123 "*If t, :n and :b cycles through files and buffers in other window.
124Then :N and :B cycles in the current window. If nil, this behavior is
125reversed.")
126
127(defconst ex-cycle-through-non-files nil
128 "*Cycle through *scratch* and other buffers that don't visit any file.")
129
130;; Last shell command executed with :! command.
131(defvar vip-ex-last-shell-com nil)
132
133;; Indicates if Minibuffer was exited temporarily in Ex-command.
134(defvar vip-incomplete-ex-cmd nil)
135
136;; Remembers the last ex-command prompt.
137(defvar vip-last-ex-prompt "")
138
139
140;;; Code
141
142(defun vip-check-sub (str)
143 "Check if ex-token is an initial segment of STR."
144 (let ((length (length ex-token)))
145 (if (and (<= length (length str))
146 (string= ex-token (substring str 0 length)))
147 (setq ex-token str)
148 (setq ex-token-type 'non-command))))
149
150(defun vip-get-ex-com-subr ()
151 "Get a complete ex command."
152 (let (case-fold-search)
153 (set-mark (point))
154 (re-search-forward "[a-zA-Z][a-zA-Z]*")
155 (setq ex-token-type 'command)
156 (setq ex-token (buffer-substring (point) (mark t)))
157 (exchange-point-and-mark)
158 (cond ((looking-at "a")
159 (cond ((looking-at "ab") (vip-check-sub "abbreviate"))
160 ((looking-at "ar") (vip-check-sub "args"))
161 (t (vip-check-sub "append"))))
162 ((looking-at "h") (vip-check-sub "help"))
163 ((looking-at "c")
164 (cond ((looking-at "cd") (vip-check-sub "cd"))
165 ((looking-at "ch") (vip-check-sub "chdir"))
166 ((looking-at "co") (vip-check-sub "copy"))
167 (t (vip-check-sub "change"))))
168 ((looking-at "d") (vip-check-sub "delete"))
169 ((looking-at "b") (vip-check-sub "buffer"))
170 ((looking-at "B") (vip-check-sub "Buffer"))
171 ((looking-at "e")
172 (if (looking-at "ex") (vip-check-sub "ex")
173 (vip-check-sub "edit")))
174 ((looking-at "f") (vip-check-sub "file"))
175 ((looking-at "g") (vip-check-sub "global"))
176 ((looking-at "i") (vip-check-sub "insert"))
177 ((looking-at "j") (vip-check-sub "join"))
178 ((looking-at "l") (vip-check-sub "list"))
179 ((looking-at "m")
180 (cond ((looking-at "map") (vip-check-sub "map"))
181 ((looking-at "mar") (vip-check-sub "mark"))
182 (t (vip-check-sub "move"))))
183 ((looking-at "k[a-z][^a-z]")
184 (setq ex-token "kmark")
185 (forward-char 1)
fad2477b
KH
186 (exchange-point-and-mark)) ; this is canceled out by another
187 ; exchange-point-and-mark at the end
6c2e12f4
KH
188 ((looking-at "k") (vip-check-sub "kmark"))
189 ((looking-at "n") (if (looking-at "nu")
190 (vip-check-sub "number")
191 (vip-check-sub "next")))
192 ((looking-at "N") (vip-check-sub "Next"))
193 ((looking-at "o") (vip-check-sub "open"))
194 ((looking-at "p")
195 (cond ((looking-at "pre") (vip-check-sub "preserve"))
196 ((looking-at "pu") (vip-check-sub "put"))
197 ((looking-at "pw") (vip-check-sub "pwd"))
198 (t (vip-check-sub "print"))))
199 ((looking-at "P") (vip-check-sub "PreviousRelatedFile"))
200 ((looking-at "R") (vip-check-sub "RelatedFile"))
201 ((looking-at "q") (vip-check-sub "quit"))
202 ((looking-at "r")
203 (cond ((looking-at "rec") (vip-check-sub "recover"))
204 ((looking-at "rew") (vip-check-sub "rewind"))
205 (t (vip-check-sub "read"))))
206 ((looking-at "s")
207 (cond ((looking-at "se") (vip-check-sub "set"))
208 ((looking-at "sh") (vip-check-sub "shell"))
209 ((looking-at "so") (vip-check-sub "source"))
210 ((looking-at "sr") (vip-check-sub "sr"))
211 ((looking-at "st") (vip-check-sub "stop"))
212 ((looking-at "sus") (vip-check-sub "suspend"))
213 ((looking-at "subm") (vip-check-sub "submitReport"))
214 (t (vip-check-sub "substitute"))))
215 ((looking-at "t")
216 (if (looking-at "ta") (vip-check-sub "tag")
217 (vip-check-sub "transfer")))
218 ((looking-at "u")
219 (cond ((looking-at "una") (vip-check-sub "unabbreviate"))
220 ((looking-at "unm") (vip-check-sub "unmap"))
221 (t (vip-check-sub "undo"))))
222 ((looking-at "v")
223 (cond ((looking-at "ve") (vip-check-sub "version"))
224 ((looking-at "vi") (vip-check-sub "visual"))
225 (t (vip-check-sub "vglobal"))))
226 ((looking-at "w")
227 (if (looking-at "wq") (vip-check-sub "wq")
228 (vip-check-sub "write")))
229 ((looking-at "W")
230 (if (looking-at "WW")
231 (vip-check-sub "WWrite")
232 (vip-check-sub "Write")))
233 ((looking-at "x") (vip-check-sub "xit"))
234 ((looking-at "y") (vip-check-sub "yank"))
235 ((looking-at "z") (vip-check-sub "z")))
236 (exchange-point-and-mark)
237 ))
238
239(defun vip-get-ex-token ()
240 "Get an ex-token which is either an address or a command.
241A token has a type, \(command, address, end-mark\), and a value."
242 (save-window-excursion
243 (set-buffer vip-ex-work-buf)
244 (skip-chars-forward " \t|")
245 (cond ((looking-at "#")
246 (setq ex-token-type 'command)
247 (setq ex-token (char-to-string (following-char)))
248 (forward-char 1))
249 ((looking-at "[a-z]") (vip-get-ex-com-subr))
250 ((looking-at "\\.")
251 (forward-char 1)
252 (setq ex-token-type 'dot))
253 ((looking-at "[0-9]")
254 (set-mark (point))
255 (re-search-forward "[0-9]*")
256 (setq ex-token-type
257 (cond ((eq ex-token-type 'plus) 'add-number)
258 ((eq ex-token-type 'minus) 'sub-number)
259 (t 'abs-number)))
260 (setq ex-token (string-to-int (buffer-substring (point) (mark t)))))
261 ((looking-at "\\$")
262 (forward-char 1)
263 (setq ex-token-type 'end))
264 ((looking-at "%")
265 (forward-char 1)
266 (setq ex-token-type 'whole))
267 ((looking-at "+")
268 (cond ((or (looking-at "+[-+]") (looking-at "+[\n|]"))
269 (forward-char 1)
270 (insert "1")
271 (backward-char 1)
272 (setq ex-token-type 'plus))
273 ((looking-at "+[0-9]")
274 (forward-char 1)
275 (setq ex-token-type 'plus))
276 (t
277 (error vip-BadAddress))))
278 ((looking-at "-")
279 (cond ((or (looking-at "-[-+]") (looking-at "-[\n|]"))
280 (forward-char 1)
281 (insert "1")
282 (backward-char 1)
283 (setq ex-token-type 'minus))
284 ((looking-at "-[0-9]")
285 (forward-char 1)
286 (setq ex-token-type 'minus))
287 (t
288 (error vip-BadAddress))))
289 ((looking-at "/")
290 (forward-char 1)
291 (set-mark (point))
292 (let ((cont t))
293 (while (and (not (eolp)) cont)
294 ;;(re-search-forward "[^/]*/")
295 (re-search-forward "[^/]*\\(/\\|\n\\)")
296 (if (not (vip-looking-back "[^\\\\]\\(\\\\\\\\\\)*\\\\/"))
297 (setq cont nil))))
298 (backward-char 1)
299 (setq ex-token (buffer-substring (point) (mark t)))
300 (if (looking-at "/") (forward-char 1))
301 (setq ex-token-type 'search-forward))
302 ((looking-at "\\?")
303 (forward-char 1)
304 (set-mark (point))
305 (let ((cont t))
306 (while (and (not (eolp)) cont)
307 ;;(re-search-forward "[^\\?]*\\?")
308 (re-search-forward "[^\\?]*\\(\\?\\|\n\\)")
309 (if (not (vip-looking-back "[^\\\\]\\(\\\\\\\\\\)*\\\\\\?"))
310 (setq cont nil))
311 (backward-char 1)
312 (if (not (looking-at "\n")) (forward-char 1))))
313 (setq ex-token-type 'search-backward)
314 (setq ex-token (buffer-substring (1- (point)) (mark t))))
315 ((looking-at ",")
316 (forward-char 1)
317 (setq ex-token-type 'comma))
318 ((looking-at ";")
319 (forward-char 1)
320 (setq ex-token-type 'semi-colon))
321 ((looking-at "[!=><&~]")
322 (setq ex-token-type 'command)
323 (setq ex-token (char-to-string (following-char)))
324 (forward-char 1))
325 ((looking-at "'")
326 (setq ex-token-type 'goto-mark)
327 (forward-char 1)
328 (cond ((looking-at "'") (setq ex-token nil))
329 ((looking-at "[a-z]") (setq ex-token (following-char)))
330 (t (error "Marks are ' and a-z")))
331 (forward-char 1))
332 ((looking-at "\n")
333 (setq ex-token-type 'end-mark)
334 (setq ex-token "goto"))
335 (t
336 (error vip-BadExCommand)))))
337
338;; Reads Ex command. Tries to determine if it has to exit because command
339;; is complete or invalid. If not, keeps reading command.
340(defun ex-cmd-read-exit ()
341 (interactive)
342 (setq vip-incomplete-ex-cmd t)
343 (let ((quit-regex1 (concat
344 "\\("
345 "set[ \t]*" "\\|" "edit[ \t]*" "\\|" "[nN]ext[ \t]*"
346 "\\|" "unm[ \t]*" "\\|" "^[ \t]*rep"
347 "\\)"))
348 (quit-regex2 (concat
349 "[a-zA-Z][ \t]*"
350 "\\(" "!" "\\|" ">>"
351 "\\|" "\\+[0-9]+"
352 "\\)"
353 "*[ \t]*$"))
354 (stay-regex (concat
355 "\\("
356 "^[ \t]*$" "\\|" "[ktgjmsz][ \t]*$" "\\|" "^[ \t]*ab.*"
357 "\\|" "tr[ansfer \t]*" "\\|" "sr[ \t]*"
358 "\\|" "mo.*" "\\|" "^[ \t]*k?ma[^p]*"
359 "\\|" "^[ \t]*fi.*" "\\|" "v?gl.*" "\\|" "[vg][ \t]*$"
360 "\\|" "jo.*" "\\|" "^[ \t]*ta.*" "\\|" "^[ \t]*una.*"
361 "\\|" "^[ \t]*su.*" "\\|['`][a-z][ \t]*"
362 "\\|" "![ \t]*[a-zA-Z].*"
363 "\\)"
364 "!*")))
365
366 (save-window-excursion ;; put cursor at the end of the Ex working buffer
367 (set-buffer vip-ex-work-buf)
368 (goto-char (point-max)))
369 (cond ((vip-looking-back quit-regex1) (exit-minibuffer))
370 ((vip-looking-back stay-regex) (insert " "))
371 ((vip-looking-back quit-regex2) (exit-minibuffer))
372 (t (insert " ")))))
373
374;; complete Ex command
375(defun ex-cmd-complete ()
376 (interactive)
377 (let (save-pos dist compl-list string-to-complete completion-result)
378
379 (save-excursion
380 (setq dist (skip-chars-backward "[a-zA-Z!=>&~]")
381 save-pos (point)))
382
383 (if (or (= dist 0)
384 (vip-looking-back "\\([ \t]*['`][ \t]*[a-z]*\\)")
385 (vip-looking-back
386 "^[ \t]*[a-zA-Z!=>&~][ \t]*[/?]*+[ \t]+[a-zA-Z!=>&~]+"))
387 ;; Preceding characters are not the ones allowed in an Ex command
388 ;; or we have typed past command name.
389 ;; Note: we didn't do parsing, so there may be surprises.
390 (if (or (vip-looking-back "[a-zA-Z!=>&~][ \t]*[/?]*[ \t]*")
391 (vip-looking-back "\\([ \t]*['`][ \t]*[a-z]*\\)")
392 (looking-at "[^ \t\n\C-m]"))
393 nil
394 (with-output-to-temp-buffer "*Completions*"
395 (display-completion-list
396 (vip-alist-to-list ex-token-alist))))
397 ;; Preceding chars may be part of a command name
398 (setq string-to-complete (buffer-substring save-pos (point)))
399 (setq completion-result
400 (try-completion string-to-complete ex-token-alist))
401
fad2477b 402 (cond ((eq completion-result t) ; exact match--do nothing
6c2e12f4
KH
403 (vip-tmp-insert-at-eob " (Sole completion)"))
404 ((eq completion-result nil)
405 (vip-tmp-insert-at-eob " (No match)"))
406 (t ;; partial completion
407 (goto-char save-pos)
408 (delete-region (point) (point-max))
409 (insert completion-result)
410 (let (case-fold-search)
411 (setq compl-list
412 (vip-filter-alist (concat "^" completion-result)
413 ex-token-alist)))
414 (if (> (length compl-list) 1)
415 (with-output-to-temp-buffer "*Completions*"
416 (display-completion-list
417 (vip-alist-to-list (reverse compl-list)))))))
418 )))
419
420(defun vip-ex (&optional string)
421 "Ex commands within Viper."
422 (interactive)
423 (or string
424 (setq ex-g-flag nil
425 ex-g-variant nil))
426 (let* ((map (copy-keymap minibuffer-local-map))
427 (address nil)
428 (cont t)
429 (dot (point))
430 com-str)
431
432 (vip-add-keymap vip-ex-cmd-map map)
433
434 (setq com-str (or string (vip-read-string-with-history
435 ":"
436 nil
437 'vip-ex-history
438 (car vip-ex-history)
439 map)))
440 (save-window-excursion
441 ;; just a precaution
442 (or (vip-buffer-live-p vip-ex-work-buf)
443 (setq vip-ex-work-buf (get-buffer-create vip-ex-work-buf-name)))
444 (set-buffer vip-ex-work-buf)
445 (delete-region (point-min) (point-max))
446 (insert com-str "\n")
447 (goto-char (point-min)))
448 (setq ex-token-type nil
449 ex-addresses nil)
450 (while cont
451 (vip-get-ex-token)
452 (cond ((memq ex-token-type '(command end-mark))
453 (if address (setq ex-addresses (cons address ex-addresses)))
454 (cond ((string= ex-token "global")
455 (ex-global nil)
456 (setq cont nil))
457 ((string= ex-token "vglobal")
458 (ex-global t)
459 (setq cont nil))
460 (t
461 (vip-execute-ex-command)
462 (save-window-excursion
463 (set-buffer vip-ex-work-buf)
464 (skip-chars-forward " \t")
465 (cond ((looking-at "|")
466 (forward-char 1))
467 ((looking-at "\n")
468 (setq cont nil))
469 (t (error "`%s': %s" ex-token vip-SpuriousText)))
470 ))
471 ))
472 ((eq ex-token-type 'non-command)
473 (error (format "`%s': %s" ex-token vip-BadExCommand)))
474 ((eq ex-token-type 'whole)
475 (setq ex-addresses
476 (cons (point-max) (cons (point-min) ex-addresses))))
477 ((eq ex-token-type 'comma)
478 (setq ex-addresses
479 (cons (if (null address) (point) address) ex-addresses)))
480 ((eq ex-token-type 'semi-colon)
481 (if address (setq dot address))
482 (setq ex-addresses
483 (cons (if (null address) (point) address) ex-addresses)))
484 (t (let ((ans (vip-get-ex-address-subr address dot)))
485 (if ans (setq address ans))))))))
486
487(defun vip-get-ex-pat ()
488 "Get a regular expression and set `ex-variant', if found."
489 (save-window-excursion
490 (set-buffer vip-ex-work-buf)
491 (skip-chars-forward " \t")
492 (if (looking-at "!")
493 (progn
494 (setq ex-g-variant (not ex-g-variant)
495 ex-g-flag (not ex-g-flag))
496 (forward-char 1)
497 (skip-chars-forward " \t")))
498 (let ((c (following-char)))
499 (if (string-match "[0-9A-Za-z]" (format "%c" c))
500 (error
501 "Global regexp must be inside matching non-alphanumeric chars"))
502 (if (looking-at "[^\\\\\n]")
503 (progn
504 (forward-char 1)
505 (set-mark (point))
506 (let ((cont t))
507 (while (and (not (eolp)) cont)
508 (if (not (re-search-forward (format "[^%c]*%c" c c) nil t))
509 (if (member ex-token '("global" "vglobal"))
510 (error
511 "Missing closing delimiter for global regexp")
512 (goto-char (point-max))))
513 (if (not (vip-looking-back
514 (format "[^\\\\]\\(\\\\\\\\\\)*\\\\%c" c)))
515 (setq cont nil))))
516 (setq ex-token
517 (if (= (mark t) (point)) ""
518 (buffer-substring (1- (point)) (mark t))))
519 (backward-char 1))
520 (setq ex-token nil))
521 c)))
522
523(defun vip-get-ex-command ()
524 "get an ex command"
525 (save-window-excursion
526 (set-buffer vip-ex-work-buf)
527 (if (looking-at "/") (forward-char 1))
528 (skip-chars-forward " \t")
529 (cond ((looking-at "[a-z]")
530 (vip-get-ex-com-subr)
531 (if (eq ex-token-type 'non-command)
532 (error "`%s': %s" ex-token vip-BadExCommand)))
533 ((looking-at "[!=><&~]")
534 (setq ex-token (char-to-string (following-char)))
535 (forward-char 1))
536 (t (error vip-BadExCommand)))))
537
538(defun vip-get-ex-opt-gc (c)
539 "Get an Ex option g or c."
540 (save-window-excursion
541 (set-buffer vip-ex-work-buf)
542 (if (looking-at (format "%c" c)) (forward-char 1))
543 (skip-chars-forward " \t")
544 (cond ((looking-at "g")
545 (setq ex-token "g")
546 (forward-char 1)
547 t)
548 ((looking-at "c")
549 (setq ex-token "c")
550 (forward-char 1)
551 t)
552 (t nil))))
553
554(defun vip-default-ex-addresses (&optional whole-flag)
555 "Compute default addresses. WHOLE-FLAG means use the whole buffer."
556 (cond ((null ex-addresses)
557 (setq ex-addresses
558 (if whole-flag
559 (cons (point-max) (cons (point-min) nil))
560 (cons (point) (cons (point) nil)))))
561 ((null (cdr ex-addresses))
562 (setq ex-addresses
563 (cons (car ex-addresses) ex-addresses)))))
564
565(defun vip-get-ex-address ()
566 "Get an ex-address as a marker and set ex-flag if a flag is found."
567 (let ((address (point-marker)) (cont t))
568 (setq ex-token "")
569 (setq ex-flag nil)
570 (while cont
571 (vip-get-ex-token)
572 (cond ((eq ex-token-type 'command)
573 (if (member ex-token '("print" "list" "#"))
574 (progn
575 (setq ex-flag t
576 cont nil))
577 (error "Address expected in this Ex command")))
578 ((eq ex-token-type 'end-mark)
579 (setq cont nil))
580 ((eq ex-token-type 'whole)
581 (error "Trailing address expected"))
582 ((eq ex-token-type 'comma)
583 (error "`%s': %s" ex-token vip-SpuriousText))
584 (t (let ((ans (vip-get-ex-address-subr address (point-marker))))
585 (if ans (setq address ans))))))
586 address))
587
588(defun vip-get-ex-address-subr (old-address dot)
589 "Returns an address as a point."
590 (let ((address nil))
591 (if (null old-address) (setq old-address dot))
592 (cond ((eq ex-token-type 'dot)
593 (setq address dot))
594 ((eq ex-token-type 'add-number)
595 (save-excursion
596 (goto-char old-address)
597 (forward-line (if (= old-address 0) (1- ex-token) ex-token))
598 (setq address (point-marker))))
599 ((eq ex-token-type 'sub-number)
600 (save-excursion
601 (goto-char old-address)
602 (forward-line (- ex-token))
603 (setq address (point-marker))))
604 ((eq ex-token-type 'abs-number)
605 (save-excursion
606 (goto-char (point-min))
607 (if (= ex-token 0) (setq address 0)
608 (forward-line (1- ex-token))
609 (setq address (point-marker)))))
610 ((eq ex-token-type 'end)
611 (setq address (point-max-marker)))
fad2477b
KH
612 ((eq ex-token-type 'plus) t) ; do nothing
613 ((eq ex-token-type 'minus) t) ; do nothing
6c2e12f4
KH
614 ((eq ex-token-type 'search-forward)
615 (save-excursion
616 (ex-search-address t)
617 (setq address (point-marker))))
618 ((eq ex-token-type 'search-backward)
619 (save-excursion
620 (ex-search-address nil)
621 (setq address (point-marker))))
622 ((eq ex-token-type 'goto-mark)
623 (save-excursion
624 (if (null ex-token)
625 (exchange-point-and-mark)
626 (goto-char (vip-register-to-point
627 (1+ (- ex-token ?a)) 'enforce-buffer)))
628 (setq address (point-marker)))))
629 address))
630
631
632(defun ex-search-address (forward)
633 "Search pattern and set address."
634 (if (string= ex-token "")
635 (if (null vip-s-string)
636 (error vip-NoPrevSearch)
637 (setq ex-token vip-s-string))
638 (setq vip-s-string ex-token))
639 (if forward
640 (progn
641 (forward-line 1)
642 (re-search-forward ex-token))
643 (forward-line -1)
644 (re-search-backward ex-token)))
645
646(defun vip-get-ex-buffer ()
647 "Get a buffer name and set `ex-count' and `ex-flag' if found."
648 (setq ex-buffer nil)
649 (setq ex-count nil)
650 (setq ex-flag nil)
651 (save-window-excursion
652 (set-buffer vip-ex-work-buf)
653 (skip-chars-forward " \t")
654 (if (looking-at "[a-zA-Z]")
655 (progn
656 (setq ex-buffer (following-char))
657 (forward-char 1)
658 (skip-chars-forward " \t")))
659 (if (looking-at "[0-9]")
660 (progn
661 (set-mark (point))
662 (re-search-forward "[0-9][0-9]*")
663 (setq ex-count (string-to-int (buffer-substring (point) (mark t))))
664 (skip-chars-forward " \t")))
665 (if (looking-at "[pl#]")
666 (progn
667 (setq ex-flag t)
668 (forward-char 1)))
669 (if (not (looking-at "[\n|]"))
670 (error "`%s': %s" ex-token vip-SpuriousText))))
671
672(defun vip-get-ex-count ()
673 (setq ex-variant nil
674 ex-count nil
675 ex-flag nil)
676 (save-window-excursion
677 (set-buffer vip-ex-work-buf)
678 (skip-chars-forward " \t")
679 (if (looking-at "!")
680 (progn
681 (setq ex-variant t)
682 (forward-char 1)))
683 (skip-chars-forward " \t")
684 (if (looking-at "[0-9]")
685 (progn
686 (set-mark (point))
687 (re-search-forward "[0-9][0-9]*")
688 (setq ex-count (string-to-int (buffer-substring (point) (mark t))))
689 (skip-chars-forward " \t")))
690 (if (looking-at "[pl#]")
691 (progn
692 (setq ex-flag t)
693 (forward-char 1)))
694 (if (not (looking-at "[\n|]"))
695 (error "`%s': %s"
696 (buffer-substring (point-min) (1- (point-max))) vip-BadExCommand))))
697
698(defun ex-expand-filsyms (cmd buf)
699 "Expand \% and \# in ex command."
700 (let (cf pf ret)
701 (save-excursion
702 (set-buffer buf)
703 (setq cf buffer-file-name)
fad2477b 704 (setq pf (ex-next nil t))) ; this finds alternative file name
6c2e12f4
KH
705 (if (and (null cf) (string-match "[^\\]%\\|\\`%" cmd))
706 (error "No current file to substitute for `\%'"))
707 (if (and (null pf) (string-match "[^\\]#\\|\\`#" cmd))
708 (error "No alternate file to substitute for `#'"))
709 (save-excursion
fad2477b
KH
710 (set-buffer (get-buffer-create " *ex-tmp*"))
711 (erase-buffer)
6c2e12f4
KH
712 (insert cmd)
713 (goto-char (point-min))
714 (while (re-search-forward "%\\|#" nil t)
715 (let ((data (match-data))
716 (char (buffer-substring (match-beginning 0) (match-end 0))))
717 (if (vip-looking-back (concat "\\\\" char))
718 (replace-match char)
719 (store-match-data data)
720 (if (string= char "%")
721 (replace-match cf)
722 (replace-match pf)))))
723 (end-of-line)
724 (setq ret (buffer-substring (point-min) (point)))
6c2e12f4
KH
725 (message "%s" ret))
726 ret))
727
728(defun vip-get-ex-file ()
729 "Get a file name and set ex-variant, `ex-append' and `ex-offset' if found."
730 (let (prompt)
731 (setq ex-file nil
732 ex-variant nil
733 ex-append nil
734 ex-offset nil
735 ex-cmdfile nil)
736 (save-excursion
737 (save-window-excursion
738 (set-buffer vip-ex-work-buf)
739 (skip-chars-forward " \t")
740 (if (looking-at "!")
741 (if (not (vip-looking-back "[ \t]"))
742 (progn
743 (setq ex-variant t)
744 (forward-char 1)
745 (skip-chars-forward " \t"))
746 (setq ex-cmdfile t)
747 (forward-char 1)
748 (skip-chars-forward " \t")))
749 (if (looking-at ">>")
750 (progn
751 (setq ex-append t
752 ex-variant t)
753 (forward-char 2)
754 (skip-chars-forward " \t")))
755 (if (looking-at "+")
756 (progn
757 (forward-char 1)
758 (set-mark (point))
759 (re-search-forward "[ \t\n]")
760 (backward-char 1)
761 (setq ex-offset (buffer-substring (point) (mark t)))
762 (forward-char 1)
763 (skip-chars-forward " \t")))
764 ;; this takes care of :r, :w, etc., when they get file names
765 ;; from the history list
fad2477b 766 (if (member ex-token '("read" "write" "edit" "visual" "next"))
6c2e12f4
KH
767 (progn
768 (setq ex-file (buffer-substring (point) (1- (point-max))))
769 (setq ex-file
770 ;; For :e, match multiple non-white strings separated
771 ;; by white. For others, find the first non-white string
772 (if (string-match
773 (if (string= ex-token "edit")
774 "[^ \t\n]+\\([ \t]+[^ \t\n]+\\)*"
775 "[^ \t\n]+")
776 ex-file)
777 (progn
778 ;; if file name comes from history, don't leave
779 ;; minibuffer when the user types space
780 (setq vip-incomplete-ex-cmd nil)
781 ;; this must be the last clause in this progn
782 (substring ex-file (match-beginning 0) (match-end 0))
783 )
784 ""))
785 ;; this leaves only the command name in the work area
786 ;; file names are gone
787 (delete-region (point) (1- (point-max)))
788 ))
789 (goto-char (point-max))
790 (skip-chars-backward " \t\n")
791 (setq prompt (buffer-substring (point-min) (point)))
792 ))
793
794 (setq vip-last-ex-prompt prompt)
795
796 ;; If we just finished reading command, redisplay prompt
797 (if vip-incomplete-ex-cmd
798 (setq ex-file (vip-ex-read-file-name (format ":%s " prompt)))
799 ;; file was typed in-line
800 (setq ex-file (or ex-file "")))
801 ))
802
803
804;; Completes file name or exits minibuffer. If Ex command accepts multiple
805;; file names, arranges to re-enter the minibuffer.
806(defun vip-complete-filename-or-exit ()
807 (interactive)
808 (setq vip-keep-reading-filename t)
809 ;; don't exit if directory---ex-commands don't
810 (cond ((ex-cmd-accepts-multiple-files-p ex-token) (exit-minibuffer))
811 (t (minibuffer-complete-word))))
812
813
814(defun ex-cmd-accepts-multiple-files-p (token)
815 (member token '("edit" "next" "Next")))
816
817;; If user doesn't enter anything, then "" is returned, i.e., the
818;; prompt-directory is not returned.
819(defun vip-ex-read-file-name (prompt)
820 (let* ((str "")
821 (minibuffer-local-completion-map
822 (copy-keymap minibuffer-local-completion-map))
823 beg end cont val)
824
825 (vip-add-keymap ex-read-filename-map minibuffer-local-completion-map)
826
827 (setq cont (setq vip-keep-reading-filename t))
828 (while cont
829 (setq vip-keep-reading-filename nil
830 val (read-file-name (concat prompt str) nil default-directory)
831 str (concat str (if (equal val "") "" " ")
832 val (if (equal val "") "" " ")))
833
834 ;; Only edit, next, and Next commands accept multiple files.
835 ;; vip-keep-reading-filename is set in the anonymous function that is
836 ;; bound to " " in ex-read-filename-map.
837 (setq cont (and vip-keep-reading-filename
838 (ex-cmd-accepts-multiple-files-p ex-token)))
839 )
840
fad2477b
KH
841 (setq beg (string-match "[^ \t]" str) ; delete leading blanks
842 end (string-match "[ \t]*$" str)) ; delete trailing blanks
6c2e12f4
KH
843 (if (member ex-token '("read" "write"))
844 (if (string-match "[\t ]*!" str)
845 ;; this is actually a shell command
846 (progn
847 (setq ex-cmdfile t)
848 (setq beg (1+ beg))
849 (setq vip-last-ex-prompt (concat vip-last-ex-prompt " !")))))
850 (substring str (or beg 0) end)))
851
852(defun vip-execute-ex-command ()
853 "Execute ex command using the value of addresses."
854 (vip-deactivate-mark)
855 (cond ((string= ex-token "args") (ex-args))
856 ((string= ex-token "copy") (ex-copy nil))
857 ((string= ex-token "cd") (ex-cd))
858 ((string= ex-token "chdir") (ex-cd))
859 ((string= ex-token "delete") (ex-delete))
860 ((string= ex-token "edit") (ex-edit))
861 ((string= ex-token "file") (vip-info-on-file))
862 ((string= ex-token "goto") (ex-goto))
863 ((string= ex-token "help") (ex-help))
864 ((string= ex-token "join") (ex-line "join"))
865 ((string= ex-token "kmark") (ex-mark))
866 ((string= ex-token "mark") (ex-mark))
867 ((string= ex-token "map") (ex-map))
868 ((string= ex-token "move") (ex-copy t))
869 ((string= ex-token "next") (ex-next ex-cycle-other-window))
870 ((string= ex-token "Next") (ex-next (not ex-cycle-other-window)))
871 ((string= ex-token "RelatedFile") (ex-next-related-buffer 1))
872 ((string= ex-token "put") (ex-put))
873 ((string= ex-token "pwd") (ex-pwd))
874 ((string= ex-token "preserve") (ex-preserve))
875 ((string= ex-token "PreviousRelatedFile") (ex-next-related-buffer -1))
876 ((string= ex-token "quit") (ex-quit))
877 ((string= ex-token "read") (ex-read))
878 ((string= ex-token "recover") (ex-recover))
879 ((string= ex-token "rewind") (ex-rewind))
880 ((string= ex-token "submitReport") (vip-submit-report))
881 ((string= ex-token "set") (ex-set))
882 ((string= ex-token "shell") (ex-shell))
883 ((string= ex-token "source") (ex-source))
884 ((string= ex-token "sr") (ex-substitute t t))
885 ((string= ex-token "substitute") (ex-substitute))
886 ((string= ex-token "suspend") (suspend-emacs))
887 ((string= ex-token "stop") (suspend-emacs))
888 ((string= ex-token "transfer") (ex-copy nil))
889 ((string= ex-token "buffer") (if ex-cycle-other-window
890 (vip-switch-to-buffer-other-window)
891 (vip-switch-to-buffer)))
892 ((string= ex-token "Buffer") (if ex-cycle-other-window
893 (vip-switch-to-buffer)
894 (vip-switch-to-buffer-other-window)))
895 ((string= ex-token "tag") (ex-tag))
896 ((string= ex-token "undo") (vip-undo))
897 ((string= ex-token "unmap") (ex-unmap))
898 ((string= ex-token "version") (vip-version))
899 ((string= ex-token "visual") (ex-edit))
900 ((string= ex-token "write") (ex-write nil))
901 ((string= ex-token "Write") (save-some-buffers))
902 ((string= ex-token "wq") (ex-write t))
903 ((string= ex-token "WWrite") (save-some-buffers t)) ; don't ask
904 ((string= ex-token "xit") (ex-write t))
905 ((string= ex-token "yank") (ex-yank))
906 ((string= ex-token "!") (ex-command))
907 ((string= ex-token "=") (ex-line-no))
908 ((string= ex-token ">") (ex-line "right"))
909 ((string= ex-token "<") (ex-line "left"))
910 ((string= ex-token "&") (ex-substitute t))
911 ((string= ex-token "~") (ex-substitute t t))
912 ((or (string= ex-token "append")
913 (string= ex-token "change")
914 (string= ex-token "insert")
915 (string= ex-token "open"))
916 (error
917 (format "`%s': Obsolete command, not supported by Viper"
918 ex-token)))
919 ((or (string= ex-token "abbreviate")
920 (string= ex-token "unabbreviate"))
921 (error
922 (format
923 "`%s': Vi's abbrevs are obsolete. Use more powerful Emacs' abbrevs"
924 ex-token)))
925 ((or (string= ex-token "list")
926 (string= ex-token "print")
927 (string= ex-token "z")
928 (string= ex-token "#"))
929 (error
930 (format "`%s': Command not implemented in Viper" ex-token)))
931 (t (error (format "`%s': %s" ex-token vip-BadExCommand)))))
932
933(defun vip-undisplayed-files ()
934 (mapcar
935 (function
936 (lambda (b)
937 (if (null (get-buffer-window b))
938 (let ((f (buffer-file-name b)))
939 (if f f
940 (if ex-cycle-through-non-files
941 (let ((s (buffer-name b)))
942 (if (string= " " (substring s 0 1))
943 nil
944 s))
945 nil)))
946 nil)))
947 (buffer-list)))
948
949
950(defun ex-args ()
951 (let ((l (vip-undisplayed-files))
952 (args "")
953 (file-count 1))
954 (while (not (null l))
955 (if (car l)
956 (setq args (format "%s %d) %s\n" args file-count (car l))
957 file-count (1+ file-count)))
958 (setq l (cdr l)))
959 (if (string= args "")
960 (message "All files are already displayed")
961 (save-excursion
962 (save-window-excursion
963 (with-output-to-temp-buffer " *vip-info*"
964 (princ "\n\nThese files are not displayed in any window.\n")
965 (princ "\n=============\n")
966 (princ args)
967 (princ "\n=============\n")
968 (princ "\nThe numbers can be given as counts to :next. ")
969 (princ "\n\nPress any key to continue...\n\n"))
fad2477b 970 (vip-read-event))))))
6c2e12f4
KH
971
972(defun ex-cd ()
973 "Ex cd command. Default directory of this buffer changes."
974 (vip-get-ex-file)
975 (if (string= ex-file "")
976 (setq ex-file "~"))
977 (setq default-directory (file-name-as-directory (expand-file-name ex-file))))
978
979(defun ex-copy (del-flag)
980 "Ex copy and move command. DEL-FLAG means delete."
981 (vip-default-ex-addresses)
982 (let ((address (vip-get-ex-address))
983 (end (car ex-addresses)) (beg (car (cdr ex-addresses))))
984 (goto-char end)
985 (save-excursion
986 (push-mark beg t)
987 (vip-enlarge-region (mark t) (point))
988 (if del-flag
989 (kill-region (point) (mark t))
990 (copy-region-as-kill (point) (mark t)))
991 (if ex-flag
992 (progn
993 (with-output-to-temp-buffer "*copy text*"
994 (princ
995 (if (or del-flag ex-g-flag ex-g-variant)
996 (current-kill 0)
997 (buffer-substring (point) (mark t)))))
998 (condition-case nil
999 (progn
1000 (read-string "[Hit return to continue] ")
1001 (save-excursion (kill-buffer "*copy text*")))
1002 (quit (save-excursion (kill-buffer "*copy text*"))
1003 (signal 'quit nil))))))
1004 (if (= address 0)
1005 (goto-char (point-min))
1006 (goto-char address)
1007 (forward-line 1))
1008 (insert (current-kill 0))))
1009
1010(defun ex-delete ()
1011 "Ex delete command."
1012 (vip-default-ex-addresses)
1013 (vip-get-ex-buffer)
1014 (let ((end (car ex-addresses)) (beg (car (cdr ex-addresses))))
1015 (if (> beg end) (error vip-FirstAddrExceedsSecond))
1016 (save-excursion
1017 (vip-enlarge-region beg end)
1018 (exchange-point-and-mark)
1019 (if ex-count
1020 (progn
1021 (set-mark (point))
1022 (forward-line (1- ex-count)))
1023 (set-mark end))
1024 (vip-enlarge-region (point) (mark t))
1025 (if ex-flag
1026 ;; show text to be deleted and ask for confirmation
1027 (progn
1028 (with-output-to-temp-buffer " *delete text*"
1029 (princ (buffer-substring (point) (mark t))))
1030 (condition-case nil
1031 (read-string "[Hit return to continue] ")
1032 (quit
1033 (save-excursion (kill-buffer " *delete text*"))
1034 (error "")))
1035 (save-excursion (kill-buffer " *delete text*")))
1036 (if ex-buffer
1037 (cond ((vip-valid-register ex-buffer '(Letter))
1038 (vip-append-to-register
1039 (downcase ex-buffer) (point) (mark t)))
1040 ((vip-valid-register ex-buffer)
1041 (copy-to-register ex-buffer (point) (mark t) nil))
1042 (t (error vip-InvalidRegister ex-buffer))))
1043 (kill-region (point) (mark t))))))
1044
1045
1046
1047(defun ex-edit (&optional file)
1048 "Ex edit command.
1049In Viper, `e' and `e!' behave identically. In both cases, the user is
1050asked if current buffer should really be discarded.
1051This command can take multiple file names. It replaces the current buffer
1052with the first file in its argument list."
1053 (if (not file)
1054 (vip-get-ex-file))
1055 (cond ((and (string= ex-file "") buffer-file-name)
1056 (setq ex-file (abbreviate-file-name (buffer-file-name))))
1057 ((string= ex-file "")
1058 (error vip-NoFileSpecified)))
1059
1060 (let (msg do-edit)
1061 (if buffer-file-name
1062 (cond ((buffer-modified-p)
1063 (setq msg
1064 (format "Buffer %s is modified. Edit buffer? "
1065 (buffer-name))
1066 do-edit t))
1067 ((not (verify-visited-file-modtime (current-buffer)))
1068 (setq msg
1069 (format "File %s changed on disk. Reread from disk? "
1070 buffer-file-name)
1071 do-edit t))
1072 (t (setq do-edit nil))))
1073
1074 (if do-edit
1075 (if (yes-or-no-p msg)
1076 (progn
1077 (set-buffer-modified-p nil)
1078 (kill-buffer (current-buffer)))
1079 (message "Buffer %s was left intact" (buffer-name))))
1080 ) ; let
1081
1082 (if (null (setq file (get-file-buffer ex-file)))
1083 (progn
1084 (ex-find-file ex-file)
1085 (vip-change-state-to-vi)
1086 (goto-char (point-min)))
1087 (switch-to-buffer file))
1088 (if ex-offset
1089 (progn
1090 (save-window-excursion
1091 (set-buffer vip-ex-work-buf)
1092 (delete-region (point-min) (point-max))
1093 (insert ex-offset "\n")
1094 (goto-char (point-min)))
1095 (goto-char (vip-get-ex-address))
1096 (beginning-of-line)))
1097 (ex-fixup-history vip-last-ex-prompt ex-file))
1098
1099;; splits the string FILESPEC into substrings separated by newlines `\012'
1100;; each line assumed to be a file name. find-file's each file thus obtained.
1101(defun ex-find-file (filespec)
fad2477b 1102 (let (s f filebuf status)
6c2e12f4
KH
1103 (if (string-match "[^a-zA-Z0-9_.-/]" filespec)
1104 (progn
1105 (save-excursion
fad2477b
KH
1106 (set-buffer (get-buffer-create " *ex-tmp*"))
1107 (erase-buffer)
1108 (setq status
1109 (call-process ex-find-file-shell nil t nil
1110 ex-find-file-shell-options
1111 "-c"
1112 (format "echo %s | tr ' ' '\\012'" filespec)))
6c2e12f4 1113 (goto-char (point-min))
fad2477b
KH
1114 ;; Give an error, if no match.
1115 (if (> status 0)
1116 (save-excursion
1117 (skip-chars-forward " \t\n\j")
1118 (if (looking-at "echo:")
1119 (vip-forward-word 1))
1120 (error "%S%s"
1121 filespec
1122 (buffer-substring (point) (vip-line-pos 'end)))
1123 ))
6c2e12f4
KH
1124 (while (not (eobp))
1125 (setq s (point))
1126 (end-of-line)
1127 (setq f (buffer-substring s (point)))
1128 (setq filebuf (find-file-noselect f))
1129 (forward-to-indentation 1))
fad2477b 1130 ))
6c2e12f4
KH
1131 (setq filebuf (find-file-noselect (setq f filespec))))
1132 (switch-to-buffer filebuf)
1133 ))
1134
1135(defun ex-global (variant)
1136 "Ex global command."
1137 (let ((gcommand ex-token))
1138 (if (or ex-g-flag ex-g-variant)
1139 (error "`%s' within `global' is not allowed" gcommand)
1140 (if variant
1141 (setq ex-g-flag nil
1142 ex-g-variant t)
1143 (setq ex-g-flag t
1144 ex-g-variant nil)))
1145 (vip-get-ex-pat)
1146 (if (null ex-token)
1147 (error "`%s': Missing regular expression" gcommand)))
1148
1149 (if (string= ex-token "")
1150 (if (null vip-s-string)
1151 (error vip-NoPrevSearch)
1152 (setq ex-g-pat vip-s-string))
1153 (setq ex-g-pat ex-token
1154 vip-s-string ex-token))
1155 (if (null ex-addresses)
1156 (setq ex-addresses (list (point-max) (point-min)))
1157 (vip-default-ex-addresses))
1158 (let ((marks nil) (mark-count 0)
1159 com-str (end (car ex-addresses)) (beg (car (cdr ex-addresses))))
1160 (if (> beg end) (error vip-FirstAddrExceedsSecond))
1161 (save-excursion
1162 (vip-enlarge-region beg end)
1163 (exchange-point-and-mark)
1164 (let ((cont t) (limit (point-marker)))
1165 (exchange-point-and-mark)
1166 ;; skip the last line if empty
1167 (beginning-of-line)
1168 (if (eobp) (vip-backward-char-carefully))
1169 (while (and cont (not (bobp)) (>= (point) limit))
1170 (beginning-of-line)
1171 (set-mark (point))
1172 (end-of-line)
1173 (let ((found (re-search-backward ex-g-pat (mark t) t)))
1174 (if (or (and ex-g-flag found)
1175 (and ex-g-variant (not found)))
1176 (progn
1177 (end-of-line)
1178 (setq mark-count (1+ mark-count))
1179 (setq marks (cons (point-marker) marks)))))
1180 (beginning-of-line)
1181 (if (bobp) (setq cont nil)
1182 (forward-line -1)
1183 (end-of-line)))))
1184 (save-window-excursion
1185 (set-buffer vip-ex-work-buf)
1186 (setq com-str (buffer-substring (1+ (point)) (1- (point-max)))))
1187 (while marks
1188 (goto-char (car marks))
1189 (vip-ex com-str)
1190 (setq mark-count (1- mark-count))
1191 (setq marks (cdr marks)))))
1192
1193(defun ex-goto ()
1194 "Ex goto command."
1195 (if (null ex-addresses)
1196 (setq ex-addresses (cons (point) nil)))
1197 (push-mark (point) t)
1198 (goto-char (car ex-addresses))
1199 (beginning-of-line))
1200
1201(defun ex-line (com)
1202 "Ex line commands. COM is join, shift-right or shift-left."
1203 (vip-default-ex-addresses)
1204 (vip-get-ex-count)
1205 (let ((end (car ex-addresses)) (beg (car (cdr ex-addresses))) point)
1206 (if (> beg end) (error vip-FirstAddrExceedsSecond))
1207 (save-excursion
1208 (vip-enlarge-region beg end)
1209 (exchange-point-and-mark)
1210 (if ex-count
1211 (progn
1212 (set-mark (point))
1213 (forward-line ex-count)))
1214 (if ex-flag
1215 ;; show text to be joined and ask for confirmation
1216 (progn
1217 (with-output-to-temp-buffer " *text*"
1218 (princ (buffer-substring (point) (mark t))))
1219 (condition-case nil
1220 (progn
1221 (read-string "[Hit return to continue] ")
1222 (ex-line-subr com (point) (mark t)))
1223 (quit (ding)))
1224 (save-excursion (kill-buffer " *text*")))
1225 (ex-line-subr com (point) (mark t)))
1226 (setq point (point)))
1227 (goto-char (1- point))
1228 (beginning-of-line)))
1229
1230(defun ex-line-subr (com beg end)
1231 (cond ((string= com "join")
1232 (goto-char (min beg end))
1233 (while (and (not (eobp)) (< (point) (max beg end)))
1234 (end-of-line)
1235 (if (and (<= (point) (max beg end)) (not (eobp)))
1236 (progn
1237 (forward-line 1)
1238 (delete-region (point) (1- (point)))
1239 (if (not ex-variant) (fixup-whitespace))))))
1240 ((or (string= com "right") (string= com "left"))
1241 (indent-rigidly
1242 (min beg end) (max beg end)
1243 (if (string= com "right") vip-shift-width (- vip-shift-width)))
1244 (goto-char (max beg end))
1245 (end-of-line)
1246 (vip-forward-char-carefully))))
1247
1248
1249(defun ex-mark ()
1250 "Ex mark command."
1251 (let (char)
1252 (if (null ex-addresses)
1253 (setq ex-addresses
1254 (cons (point) nil)))
1255 (save-window-excursion
1256 (set-buffer vip-ex-work-buf)
1257 (skip-chars-forward " \t")
1258 (if (looking-at "[a-z]")
1259 (progn
1260 (setq char (following-char))
1261 (forward-char 1)
1262 (skip-chars-forward " \t")
1263 (if (not (looking-at "[\n|]"))
1264 (error "`%s': %s" ex-token vip-SpuriousText)))
1265 (error "`%s' requires a following letter" ex-token)))
1266 (save-excursion
1267 (goto-char (car ex-addresses))
1268 (point-to-register (1+ (- char ?a))))))
1269
1270
1271
1272;; Alternate file is the file next to the first one in the buffer ring
1273(defun ex-next (cycle-other-window &optional find-alt-file)
1274 (catch 'ex-edit
1275 (let (count l)
1276 (if (not find-alt-file)
1277 (progn
1278 (vip-get-ex-file)
1279 (if (or (char-or-string-p ex-offset)
fad2477b
KH
1280 (and (not (string= "" ex-file))
1281 (not (string-match "^[0-9]+$" ex-file))))
6c2e12f4
KH
1282 (progn
1283 (ex-edit t)
1284 (throw 'ex-edit nil))
1285 (setq count (string-to-int ex-file))
1286 (if (= count 0) (setq count 1))
1287 (if (< count 0) (error "Usage: `next <count>' (count >= 0)"))))
1288 (setq count 1))
1289 (setq l (vip-undisplayed-files))
1290 (while (> count 0)
1291 (while (and (not (null l)) (null (car l)))
1292 (setq l (cdr l)))
1293 (setq count (1- count))
1294 (if (> count 0)
1295 (setq l (cdr l))))
1296 (if find-alt-file (car l)
1297 (progn
1298 (if (car l)
1299 (let* ((w (if cycle-other-window
1300 (get-lru-window) (selected-window)))
1301 (b (window-buffer w)))
1302 (set-window-buffer w (get-file-buffer (car l)))
fad2477b
KH
1303 (bury-buffer b)
1304 ;; this puts "next <count>" in the ex-command history
1305 (ex-fixup-history vip-last-ex-prompt ex-file))
6c2e12f4
KH
1306 (error "Not that many undisplayed files")))))))
1307
1308
1309(defun ex-next-related-buffer (direction &optional no-recursion)
1310
1311 (vip-ring-rotate1 vip-related-files-and-buffers-ring direction)
1312
1313 (let ((file-or-buffer-name
1314 (vip-current-ring-item vip-related-files-and-buffers-ring))
1315 (old-ring vip-related-files-and-buffers-ring)
1316 (old-win (selected-window))
1317 skip-rest buf wind)
1318
1319 (or (and (ring-p vip-related-files-and-buffers-ring)
1320 (> (ring-length vip-related-files-and-buffers-ring) 0))
1321 (error "This buffer has no related files or buffers"))
1322
1323 (or (stringp file-or-buffer-name)
1324 (error
1325 "File and buffer names must be strings, %S" file-or-buffer-name))
1326
1327 (setq buf (cond ((get-buffer file-or-buffer-name))
1328 ((file-exists-p file-or-buffer-name)
1329 (find-file-noselect file-or-buffer-name))
1330 ))
1331
1332 (if (not (vip-buffer-live-p buf))
1333 (error "Didn't find buffer %S or file %S"
1334 file-or-buffer-name
1335 (abbreviate-file-name (expand-file-name file-or-buffer-name))))
1336
1337 (if (equal buf (current-buffer))
1338 (or no-recursion
1339 ;; try again
1340 (setq skip-rest t)
1341 (ex-next-related-buffer direction 'norecursion)))
1342
1343 (if skip-rest
1344 ()
1345 ;; setup buffer
1346 (if (setq wind (vip-get-visible-buffer-window buf))
1347 ()
1348 (setq wind (get-lru-window (if vip-xemacs-p nil 'visible)))
1349 (set-window-buffer wind buf))
1350
1351 (if window-system
1352 (progn
1353 (vip-raise-frame (vip-window-frame wind))
1354 (if (equal (vip-window-frame wind) (vip-window-frame old-win))
1355 (save-window-excursion (select-window wind) (sit-for 1))
1356 (select-window wind)))
1357 (save-window-excursion (select-window wind) (sit-for 1)))
1358
1359 (save-excursion
1360 (set-buffer buf)
1361 (setq vip-related-files-and-buffers-ring old-ring))
1362
1363 (setq vip-local-search-start-marker (point-marker))
1364 )))
1365
1366
1367(defun ex-preserve ()
1368 "Force auto save."
1369 (message "Autosaving all buffers that need to be saved...")
1370 (do-auto-save t))
1371
1372(defun ex-put ()
1373 "Ex put."
1374 (let ((point (if (null ex-addresses) (point) (car ex-addresses))))
1375 (vip-get-ex-buffer)
1376 (setq vip-use-register ex-buffer)
1377 (goto-char point)
1378 (if (bobp) (vip-Put-back 1) (vip-put-back 1))))
1379
1380(defun ex-pwd ()
1381 "Ex print working directory."
1382 (message default-directory))
1383
1384(defun ex-quit ()
1385 "Ex quit command."
1386 (if (< vip-expert-level 3)
1387 (save-buffers-kill-emacs)
1388 (kill-buffer (current-buffer))))
1389
1390
1391(defun ex-read ()
1392 "Ex read command."
1393 (vip-get-ex-file)
1394 (let ((point (if (null ex-addresses) (point) (car ex-addresses))))
1395 (goto-char point)
1396 (vip-add-newline-at-eob-if-necessary)
1397 (if (not (or (bobp) (eobp))) (forward-line 1))
1398 (if (and (not ex-variant) (string= ex-file ""))
1399 (progn
1400 (if (null buffer-file-name)
1401 (error vip-NoFileSpecified))
1402 (setq ex-file buffer-file-name)))
1403 (if ex-cmdfile
1404 (shell-command ex-file t)
1405 (insert-file-contents ex-file)))
1406 (ex-fixup-history vip-last-ex-prompt ex-file))
1407
1408;; this function fixes ex-history for some commands like ex-read, ex-edit
1409(defun ex-fixup-history (&rest args)
1410 (setq vip-ex-history
1411 (cons (mapconcat 'identity args " ") (cdr vip-ex-history))))
1412
1413
1414(defun ex-recover ()
1415 "Ex recover from emacs \#file\#."
1416 (vip-get-ex-file)
1417 (if (or ex-append ex-offset)
1418 (error "`recover': %s" vip-SpuriousText))
1419 (if (string= ex-file "")
1420 (progn
1421 (if (null buffer-file-name)
1422 (error "This buffer isn't visiting any file"))
1423 (setq ex-file buffer-file-name))
1424 (setq ex-file (expand-file-name ex-file)))
1425 (if (and (not (string= ex-file (buffer-file-name)))
1426 (buffer-modified-p)
1427 (not ex-variant))
1428 (error "No write since last change \(:rec! overrides\)"))
1429 (recover-file ex-file))
1430
1431(defun ex-rewind ()
1432 "Tell that `rewind' is obsolete and that one should use `:next count'"
1433 (message
1434 "Use `:n <count>' instead. Counts are obtained from the `:args' command"))
1435
1436
1437;; read variable name for ex-set
1438(defun ex-set-read-variable ()
1439 (let ((minibuffer-local-completion-map
1440 (copy-keymap minibuffer-local-completion-map))
1441 (cursor-in-echo-area t)
1442 str batch)
1443 (define-key
1444 minibuffer-local-completion-map " " 'minibuffer-complete-and-exit)
1445 (define-key minibuffer-local-completion-map "=" 'exit-minibuffer)
1446 (if (vip-set-unread-command-events
1447 (ex-get-inline-cmd-args "[ \t]*[a-zA-Z]*[ \t]*" nil "\C-m"))
1448 (progn
1449 (setq batch t)
1450 (vip-set-unread-command-events ?\C-m)))
1451 (message ":set <Variable> [= <Value>]")
1452 (or batch (sit-for 2))
1453
1454 (while (string-match "^[ \\t\\n]*$"
1455 (setq str
1456 (completing-read ":set " ex-variable-alist)))
1457 (message ":set <Variable> ")
1458 ;; if there are unread events, don't wait
1459 (or (vip-set-unread-command-events "") (sit-for 2))
1460 ) ; while
1461 str))
1462
1463
1464(defun ex-set ()
1465 (let ((var (ex-set-read-variable))
1466 (val 0)
1467 (set-cmd "setq")
1468 (ask-if-save t)
1469 (auto-cmd-label "; don't touch or else...")
1470 (delete-turn-on-auto-fill-pattern
1471 "([ \t]*add-hook[ \t]+'vip-insert-state-hooks[ \t]+'turn-on-auto-fill.*)")
1472 actual-lisp-cmd lisp-cmd-del-pattern
1473 val2 orig-var)
1474 (setq orig-var var)
1475 (cond ((member var '("ai" "autoindent"))
1476 (setq var "vip-auto-indent"
1477 val "t"))
1478 ((member var '("noai" "noautoindent"))
1479 (setq var "vip-auto-indent"
1480 val "nil"))
1481 ((member var '("ic" "ignorecase"))
1482 (setq var "vip-case-fold-search"
1483 val "t"))
1484 ((member var '("noic" "noignorecase"))
1485 (setq var "vip-case-fold-search"
1486 val "nil"))
1487 ((member var '("ma" "magic"))
1488 (setq var "vip-re-search"
1489 val "t"))
1490 ((member var '("noma" "nomagic"))
1491 (setq var "vip-re-search"
1492 val "nil"))
1493 ((member var '("ro" "readonly"))
1494 (setq var "buffer-read-only"
1495 val "t"))
1496 ((member var '("noro" "noreadonly"))
1497 (setq var "buffer-read-only"
1498 val "nil"))
1499 ((member var '("sm" "showmatch"))
1500 (setq var "blink-matching-paren"
1501 val "t"))
1502 ((member var '("nosm" "noshowmatch"))
1503 (setq var "blink-matching-paren"
1504 val "nil"))
1505 ((member var '("ws" "wrapscan"))
1506 (setq var "vip-search-wrap-around-t"
1507 val "t"))
1508 ((member var '("nows" "nowrapscan"))
1509 (setq var "vip-search-wrap-around-t"
1510 val "nil")))
fad2477b 1511 (if (eq val 0) ; value must be set by the user
6c2e12f4
KH
1512 (let ((cursor-in-echo-area t))
1513 (message (format ":set %s = <Value>" var))
1514 ;; if there are unread events, don't wait
1515 (or (vip-set-unread-command-events "") (sit-for 2))
1516 (setq val (read-string (format ":set %s = " var)))
1517 (ex-fixup-history "set" orig-var val)
1518
1519 ;; check numerical values
1520 (if (member var
1521 '("sw" "shiftwidth" "ts" "tabstop" "wm" "wrapmargin"))
1522 (condition-case nil
1523 (or (numberp (setq val2 (car (read-from-string val))))
1524 (error "%s: Invalid value, numberp, %S" var val))
1525 (error
1526 (error "%s: Invalid value, numberp, %S" var val))))
1527
1528 (cond
1529 ((member var '("sw" "shiftwidth"))
1530 (setq var "vip-shift-width"))
1531 ((member var '("ts" "tabstop"))
1532 ;; make it take effect in curr buff and new bufs
1533 (kill-local-variable 'tab-width)
1534 (setq var "tab-width"
1535 set-cmd "setq-default"))
1536 ((member var '("tsl" "tab-stop-local"))
1537 (setq var "tab-width"
1538 set-cmd "setq"
1539 ask-if-save nil))
1540 ((member var '("wm" "wrapmargin"))
1541 ;; make it take effect in curr buff and new bufs
1542 (kill-local-variable 'fill-column)
1543 (setq var "fill-column"
1544 val (format "(- (window-width) %s)" val)
1545 set-cmd "setq-default"))
1546 ((member var '("sh" "shell"))
1547 (setq var "explicit-shell-file-name"
1548 val (format "\"%s\"" val)))))
1549 (ex-fixup-history "set" orig-var))
1550
1551 (setq actual-lisp-cmd (format "\n(%s %s %s) %s"
1552 set-cmd var val auto-cmd-label))
1553 (setq lisp-cmd-del-pattern
1554 (format "^\n?[ \t]*([ \t]*%s[ \t]+%s[ \t].*)[ \t]*%s"
1555 set-cmd var auto-cmd-label))
1556
1557 (if (and ask-if-save
1558 (y-or-n-p (format "Do you want to save this setting in %s "
1559 vip-custom-file-name)))
1560 (progn
1561 (vip-save-string-in-file
1562 actual-lisp-cmd vip-custom-file-name
1563 ;; del pattern
1564 lisp-cmd-del-pattern)
1565 (if (string= var "fill-column")
1566 (if (> val2 0)
1567 (vip-save-string-in-file
1568 (concat
1569 "(add-hook 'vip-insert-state-hooks 'turn-on-auto-fill) "
1570 auto-cmd-label)
1571 vip-custom-file-name
1572 delete-turn-on-auto-fill-pattern)
1573 (vip-save-string-in-file
1574 nil vip-custom-file-name delete-turn-on-auto-fill-pattern)
1575 (vip-save-string-in-file
1576 nil vip-custom-file-name
1577 ;; del pattern
1578 lisp-cmd-del-pattern)
1579 ))
1580 ))
1581
1582 (message (format "%s %s %s" set-cmd var (if (string-match "^[ \t]*$" val)
1583 (format "%S" val)
1584 val)))
1585 (eval (car (read-from-string actual-lisp-cmd)))
1586 (if (string= var "fill-column")
1587 (if (> val2 0)
1588 (auto-fill-mode 1)
1589 (auto-fill-mode -1)))
1590
1591 ))
1592
1593;; In inline args, skip regex-forw and (optionally) chars-back.
1594;; Optional 3d arg is a string that should replace ' ' to prevent its
1595;; special meaning
1596(defun ex-get-inline-cmd-args (regex-forw &optional chars-back replace-str)
1597 (save-excursion
1598 (set-buffer vip-ex-work-buf)
1599 (goto-char (point-min))
1600 (re-search-forward regex-forw nil t)
1601 (let ((beg (point))
1602 end)
1603 (goto-char (point-max))
1604 (if chars-back
1605 (skip-chars-backward chars-back)
1606 (skip-chars-backward " \t\n\C-m"))
1607 (setq end (point))
1608 ;; replace SPC with `=' to suppress the special meaning SPC has
1609 ;; in Ex commands
1610 (goto-char beg)
1611 (if replace-str
1612 (while (re-search-forward " +" nil t)
1613 (replace-match replace-str nil t)
1614 (vip-forward-char-carefully)))
1615 (goto-char end)
1616 (buffer-substring beg end))))
1617
1618
1619(defun ex-shell ()
1620 "Ex shell command."
1621 (shell))
1622
1623(defun ex-help ()
1624 "Viper help. Invokes Info."
1625 (condition-case nil
1626 (progn
1627 (pop-to-buffer (get-buffer-create "*info*"))
1628 (info vip-info-file-name)
1629 (message "Type `i' to search for a specific topic"))
1630 (error (beep 1)
1631 (with-output-to-temp-buffer " *vip-info*"
1632 (princ "The Info file for Viper does not seem to be installed.
1633
1634This file is part of the distribution of Viper. If you do not
1635have the full distribution, please obtain it from the `anonymous'
1636FTP account at `archive.cis.ohio-state.edu':
1637
1638 /pub/gnu/emacs/elisp-archive/modes/viper.shar
1639
1640The Info files for Viper should be installed as <name>, <name>-1, etc.,
1641where <name> is the value of `vip-info-file-name'.")))))
1642
1643(defun ex-source ()
1644 "Ex source command. Loads the file specified as argument or `~/.vip'."
1645 (vip-get-ex-file)
1646 (if (string= ex-file "")
1647 (load vip-custom-file-name)
1648 (load ex-file)))
1649
1650(defun ex-substitute (&optional repeat r-flag)
1651 "Ex substitute command.
1652If REPEAT use previous regexp which is ex-reg-exp or vip-s-string"
1653 (let ((opt-g nil)
1654 (opt-c nil)
1655 (matched-pos nil)
1656 (case-fold-search vip-case-fold-search)
1657 delim pat repl)
1658 (if repeat (setq ex-token nil) (setq delim (vip-get-ex-pat)))
1659 (if (null ex-token)
fad2477b
KH
1660 (progn
1661 (setq pat (if r-flag vip-s-string ex-reg-exp))
1662 (or (stringp pat)
1663 (error "No previous pattern to use in substitution"))
1664 (setq repl ex-repl
1665 delim (string-to-char pat)))
6c2e12f4
KH
1666 (setq pat (if (string= ex-token "") vip-s-string ex-token))
1667 (setq vip-s-string pat
1668 ex-reg-exp pat)
1669 (setq delim (vip-get-ex-pat))
1670 (if (null ex-token)
1671 (setq ex-token ""
1672 ex-repl "")
1673 (setq repl ex-token
1674 ex-repl ex-token)))
1675 (while (vip-get-ex-opt-gc delim)
1676 (if (string= ex-token "g") (setq opt-g t) (setq opt-c t)))
1677 (vip-get-ex-count)
1678 (if ex-count
1679 (save-excursion
1680 (if ex-addresses (goto-char (car ex-addresses)))
1681 (set-mark (point))
1682 (forward-line (1- ex-count))
1683 (setq ex-addresses (cons (point) (cons (mark t) nil))))
1684 (if (null ex-addresses)
1685 (setq ex-addresses (cons (point) (cons (point) nil)))
1686 (if (null (cdr ex-addresses))
1687 (setq ex-addresses (cons (car ex-addresses) ex-addresses)))))
1688 ;(setq G opt-g)
1689 (let ((beg (car ex-addresses))
1690 (end (car (cdr ex-addresses)))
1691 eol-mark)
1692 (save-excursion
1693 (vip-enlarge-region beg end)
1694 (let ((limit (save-excursion
1695 (goto-char (max (point) (mark t)))
1696 (point-marker))))
1697 (goto-char (min (point) (mark t)))
1698 (while (< (point) limit)
1699 (end-of-line)
1700 (setq eol-mark (point-marker))
1701 (beginning-of-line)
1702 (if opt-g
1703 (progn
1704 (while (and (not (eolp))
1705 (re-search-forward pat eol-mark t))
1706 (if (or (not opt-c) (y-or-n-p "Replace? "))
1707 (progn
1708 (setq matched-pos (point))
1709 (if (not (stringp repl))
1710 (error "Can't perform Ex substitution: No previous replacement pattern"))
1711 (replace-match repl t t))))
1712 (end-of-line)
1713 (vip-forward-char-carefully))
1714 (if (null pat)
1715 (error
1716 "Can't repeat Ex substitution: No previous regular expression"))
1717 (if (and (re-search-forward pat eol-mark t)
1718 (or (not opt-c) (y-or-n-p "Replace? ")))
1719 (progn
1720 (setq matched-pos (point))
1721 (if (not (stringp repl))
1722 (error "Can't perform Ex substitution: No previous replacement pattern"))
1723 (replace-match repl t t)))
1724 (end-of-line)
1725 (vip-forward-char-carefully))))))
1726 (if matched-pos (goto-char matched-pos))
1727 (beginning-of-line)
1728 (if opt-c (message "done"))))
1729
1730(defun ex-tag ()
1731 "Ex tag command."
1732 (let (tag)
1733 (save-window-excursion
1734 (set-buffer vip-ex-work-buf)
1735 (skip-chars-forward " \t")
1736 (set-mark (point))
1737 (skip-chars-forward "^ |\t\n")
1738 (setq tag (buffer-substring (mark t) (point))))
1739 (if (not (string= tag "")) (setq ex-tag tag))
1740 (vip-change-state-to-emacs)
1741 (condition-case conds
1742 (progn
1743 (if (string= tag "")
1744 (find-tag ex-tag t)
1745 (find-tag-other-window ex-tag))
1746 (vip-change-state-to-vi))
1747 (error
1748 (vip-change-state-to-vi)
1749 (vip-message-conditions conds)))))
1750
1751(defun ex-write (q-flag)
1752 "Ex write command."
1753 (vip-default-ex-addresses t)
1754 (vip-get-ex-file)
1755 (let ((end (car ex-addresses)) (beg (car (cdr ex-addresses)))
1756 temp-buf writing-same-file region
1757 file-exists writing-whole-file)
1758 (if (> beg end) (error vip-FirstAddrExceedsSecond))
1759 (if ex-cmdfile
1760 (progn
1761 (vip-enlarge-region beg end)
1762 (shell-command-on-region (point) (mark t) ex-file))
1763 (if (and (string= ex-file "") (not (buffer-file-name)))
1764 (setq ex-file
1765 (read-file-name
1766 (format "Buffer %s isn't visiting any file. File to save in: "
1767 (buffer-name)))))
1768
1769 (setq writing-whole-file (and (= (point-min) beg) (= (point-max) end))
1770 ex-file (if (string= ex-file "")
1771 (buffer-file-name)
1772 (expand-file-name ex-file))
1773 file-exists (file-exists-p ex-file)
1774 writing-same-file (string= ex-file (buffer-file-name)))
1775 (if (and writing-whole-file writing-same-file)
1776 (if (not (buffer-modified-p))
1777 (message "(No changes need to be saved)")
1778 (save-buffer)
1779 (ex-write-info file-exists ex-file beg end))
1780 ;; writing some other file or portion of the currents
1781 ;; file---create temp buffer for it
1782 ;; disable undo in that buffer, for efficiency
1783 (buffer-disable-undo (setq temp-buf (create-file-buffer ex-file)))
1784 (unwind-protect
1785 (save-excursion
1786 (if (and file-exists
1787 (not writing-same-file)
1788 (not (yes-or-no-p
1789 (format "File %s exists. Overwrite? " ex-file))))
1790 (error "Quit")
1791 (vip-enlarge-region beg end)
1792 (setq region (buffer-substring (point) (mark t)))
1793 (set-buffer temp-buf)
1794 (set-visited-file-name ex-file)
1795 (erase-buffer)
1796 (if (and file-exists ex-append)
1797 (insert-file-contents ex-file))
1798 (goto-char (point-max))
1799 (insert region)
1800 (save-buffer)
1801 (ex-write-info file-exists ex-file (point-min) (point-max))
1802 )
1803 (set-buffer temp-buf)
1804 (set-buffer-modified-p nil)
1805 (kill-buffer temp-buf)
1806 )
1807 ))
1808 ;; this prevents the loss of data if writing part of the buffer
1809 (if (and (buffer-file-name) writing-same-file)
1810 (set-visited-file-modtime))
1811 (or writing-whole-file
1812 (not writing-same-file)
1813 (set-buffer-modified-p t))
1814 (if q-flag
1815 (if (< vip-expert-level 2)
1816 (save-buffers-kill-emacs)
1817 (kill-buffer (current-buffer))))
1818 )))
1819
1820
1821(defun ex-write-info (exists file-name beg end)
1822 (message "`%s'%s %d lines, %d characters"
1823 (abbreviate-file-name file-name)
1824 (if exists "" " [New file]")
1825 (count-lines beg (min (1+ end) (point-max)))
1826 (- end beg)))
1827
1828(defun ex-yank ()
1829 "Ex yank command."
1830 (vip-default-ex-addresses)
1831 (vip-get-ex-buffer)
1832 (let ((end (car ex-addresses)) (beg (car (cdr ex-addresses))))
1833 (if (> beg end) (error vip-FirstAddrExceedsSecond))
1834 (save-excursion
1835 (vip-enlarge-region beg end)
1836 (exchange-point-and-mark)
1837 (if (or ex-g-flag ex-g-variant)
1838 (error "Can't execute `yank' within `global'"))
1839 (if ex-count
1840 (progn
1841 (set-mark (point))
1842 (forward-line (1- ex-count)))
1843 (set-mark end))
1844 (vip-enlarge-region (point) (mark t))
1845 (if ex-flag (error "`yank': %s" vip-SpuriousText))
1846 (if ex-buffer
1847 (cond ((vip-valid-register ex-buffer '(Letter))
1848 (vip-append-to-register
1849 (downcase ex-buffer) (point) (mark t)))
1850 ((vip-valid-register ex-buffer)
1851 (copy-to-register ex-buffer (point) (mark t) nil))
1852 (t (error vip-InvalidRegister ex-buffer))))
1853 (copy-region-as-kill (point) (mark t)))))
1854
1855(defun ex-command ()
1856 "Execute shell command."
1857 (let (command)
1858 (save-window-excursion
1859 (set-buffer vip-ex-work-buf)
1860 (skip-chars-forward " \t")
1861 (setq command (buffer-substring (point) (point-max)))
1862 (end-of-line))
1863 (setq command (ex-expand-filsyms command (current-buffer)))
1864 (if (and (> (length command) 0) (string= "!" (substring command 0 1)))
1865 (if vip-ex-last-shell-com
1866 (setq command (concat vip-ex-last-shell-com (substring command 1)))
1867 (error "No previous shell command")))
1868 (setq vip-ex-last-shell-com command)
1869 (if (null ex-addresses)
1870 (shell-command command)
1871 (let ((end (car ex-addresses)) (beg (car (cdr ex-addresses))))
1872 (if (null beg) (setq beg end))
1873 (save-excursion
1874 (goto-char beg)
1875 (set-mark end)
1876 (vip-enlarge-region (point) (mark t))
1877 (shell-command-on-region (point) (mark t) command t))
1878 (goto-char beg)))))
1879
1880(defun ex-line-no ()
1881 "Print line number."
1882 (message "%d"
1883 (1+ (count-lines
1884 (point-min)
1885 (if (null ex-addresses) (point-max) (car ex-addresses))))))
1886
1887(defun vip-info-on-file ()
1888 "Give information on the file visited by the current buffer."
1889 (interactive)
fad2477b
KH
1890 (let (file info)
1891 (setq file (if (buffer-file-name)
1892 (concat (abbreviate-file-name (buffer-file-name)) ":")
1893 (concat (buffer-name) " [Not visiting any file]:"))
1894 info (format "line=%d/%d pos=%d/%d col=%d %s"
1895 (count-lines (point-min) (vip-line-pos 'end))
1896 (count-lines (point-min) (point-max))
1897 (point) (1- (point-max))
1898 (1+ (current-column))
1899 (if (buffer-modified-p) "[Modified]" "[Unchanged]")))
1900 (if (< (+ 1 (length info) (length file))
1901 (window-width (minibuffer-window)))
1902 (message (concat file " " info))
1903 (save-window-excursion
1904 (with-output-to-temp-buffer " *vip-info*"
1905 (princ (concat "\n"
1906 file "\n\n\t" info
1907 "\n\n\nPress any key to continue...\n\n")))
1908 (vip-read-event)))
1909 ))
6c2e12f4
KH
1910
1911
1912(provide 'viper-ex)
1913
1914;;; viper-ex.el ends here