|
|
1.1 root 1: ;; Replace commands for Emacs.
2: ;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
3:
4: ;; This file is part of GNU Emacs.
5:
6: ;; GNU Emacs is free software; you can redistribute it and/or modify
7: ;; it under the terms of the GNU General Public License as published by
8: ;; the Free Software Foundation; either version 1, or (at your option)
9: ;; any later version.
10:
11: ;; GNU Emacs is distributed in the hope that it will be useful,
12: ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13: ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: ;; GNU General Public License for more details.
15:
16: ;; You should have received a copy of the GNU General Public License
17: ;; along with GNU Emacs; see the file COPYING. If not, write to
18: ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19:
20:
21: (fset 'delete-non-matching-lines 'keep-lines)
22: (defun keep-lines (regexp)
23: "Delete all lines except those containing matches for REGEXP.
24: A match split across lines preserves all the lines it lies in.
25: Applies to all lines after point."
26: (interactive "sKeep lines (containing match for regexp): ")
27: (save-excursion
28: (or (bolp) (forward-line 1))
29: (let ((start (point)))
30: (while (not (eobp))
31: ;; Start is first char not preserved by previous match.
32: (if (not (re-search-forward regexp nil 'move))
33: (delete-region start (point-max))
34: (let ((end (save-excursion (goto-char (match-beginning 0))
35: (beginning-of-line)
36: (point))))
37: ;; Now end is first char preserved by the new match.
38: (if (< start end)
39: (delete-region start end))))
40: (setq start (save-excursion (forward-line 1)
41: (point)))))))
42:
43: (fset 'delete-matching-lines 'flush-lines)
44: (defun flush-lines (regexp)
45: "Delete lines containing matches for REGEXP.
46: If a match is split across lines, all the lines it lies in are deleted.
47: Applies to lines after point."
48: (interactive "sFlush lines (containing match for regexp): ")
49: (save-excursion
50: (while (and (not (eobp))
51: (re-search-forward regexp nil t))
52: (delete-region (save-excursion (goto-char (match-beginning 0))
53: (beginning-of-line)
54: (point))
55: (progn (forward-line 1) (point))))))
56:
57: (fset 'count-matches 'how-many)
58: (defun how-many (regexp)
59: "Print number of matches for REGEXP following point."
60: (interactive "sHow many matches for (regexp): ")
61: (let ((count 0) (opoint -1))
62: (save-excursion
63: ;; If we did forward-char on the previous loop,
64: ;; and that brought us to eof, search anyway.
65: (while (and (or (not (eobp)) (/= opoint (point)))
66: (re-search-forward regexp nil t))
67: (if (prog1 (= opoint (point)) (setq opoint (point)))
68: (forward-char 1)
69: (setq count (1+ count))))
70: (message "%d occurrences" count))))
71:
72: (defvar occur-mode-map ())
73: (if occur-mode-map
74: ()
75: (setq occur-mode-map (make-sparse-keymap))
76: (define-key occur-mode-map "\C-c\C-c" 'occur-mode-goto-occurrence))
77:
78: (defvar occur-buffer nil)
79: (defvar occur-nlines nil)
80: (defvar occur-pos-list nil)
81:
82: (defun occur-mode ()
83: "Major mode for output from \\[occur].
84: Move point to one of the occurrences in this buffer,
85: then use \\[occur-mode-goto-occurrence] to go to the same occurrence
86: in the buffer that the occurrences were found in.
87: \\{occur-mode-map}"
88: (kill-all-local-variables)
89: (use-local-map occur-mode-map)
90: (setq major-mode 'occur-mode)
91: (setq mode-name "Occur")
92: (make-local-variable 'occur-buffer)
93: (make-local-variable 'occur-nlines)
94: (make-local-variable 'occur-pos-list))
95:
96: (defun occur-mode-goto-occurrence ()
97: "Go to the line this occurrence was found in, in the buffer it was found in."
98: (interactive)
99: (if (or (null occur-buffer)
100: (null (buffer-name occur-buffer)))
101: (progn
102: (setq occur-buffer nil
103: occur-pos-list nil)
104: (error "Buffer in which occurences were found is deleted.")))
105: (let* ((occur-number (save-excursion
106: (beginning-of-line)
107: (/ (1- (count-lines (point-min) (point)))
108: (cond ((< occur-nlines 0)
109: (- 2 occur-nlines))
110: ((> occur-nlines 0)
111: (+ 2 (* 2 occur-nlines)))
112: (t 1)))))
113: (pos (nth occur-number occur-pos-list)))
114: (pop-to-buffer occur-buffer)
115: (goto-char (marker-position pos))))
116:
117: (defvar list-matching-lines-default-context-lines 0
118: "*Default number of context lines to include around a list-matching-lines
119: match. A negative number means to include that many lines before the match.
120: A positive number means to include that many lines both before and after.")
121:
122: (fset 'list-matching-lines 'occur)
123: (defun occur (regexp &optional nlines)
124: "Show all lines following point containing a match for REGEXP.
125: Display each line with NLINES lines before and after,
126: or -NLINES before if NLINES is negative.
127: NLINES defaults to list-matching-lines-default-context-lines.
128: Interactively it is the prefix arg.
129:
130: The lines are shown in a buffer named *Occur*.
131: It serves as a menu to find any of the occurrences in this buffer.
132: \\[describe-mode] in that buffer will explain how."
133: (interactive "sList lines matching regexp: \nP")
134: (setq nlines (if nlines (prefix-numeric-value nlines)
135: list-matching-lines-default-context-lines))
136: (let ((first t)
137: (buffer (current-buffer))
138: linenum prevpos)
139: (save-excursion
140: (beginning-of-line)
141: (setq linenum (1+ (count-lines (point-min) (point))))
142: (setq prevpos (point)))
143: (with-output-to-temp-buffer "*Occur*"
144: (save-excursion
145: (set-buffer standard-output)
146: (insert "Lines matching ")
147: (prin1 regexp)
148: (insert " in buffer " (buffer-name buffer) ?. ?\n)
149: (occur-mode)
150: (setq occur-buffer buffer)
151: (setq occur-nlines nlines)
152: (setq occur-pos-list ()))
153: (if (eq buffer standard-output)
154: (goto-char (point-max)))
155: (save-excursion
156: ;; Find next match, but give up if prev match was at end of buffer.
157: (while (and (not (= prevpos (point-max)))
158: (re-search-forward regexp nil t))
159: (beginning-of-line 1)
160: (save-excursion
161: (setq linenum (+ linenum (count-lines prevpos (point))))
162: (setq prevpos (point)))
163: (let* ((start (save-excursion
164: (forward-line (if (< nlines 0) nlines (- nlines)))
165: (point)))
166: (end (save-excursion
167: (if (> nlines 0)
168: (forward-line (1+ nlines))
169: (forward-line 1))
170: (point)))
171: (tag (format "%3d" linenum))
172: (empty (make-string (length tag) ?\ ))
173: tem)
174: (save-excursion
175: (setq tem (make-marker))
176: (set-marker tem (point))
177: (set-buffer standard-output)
178: (setq occur-pos-list (cons tem occur-pos-list))
179: (or first (zerop nlines)
180: (insert "--------\n"))
181: (setq first nil)
182: (insert-buffer-substring buffer start end)
183: (backward-char (- end start))
184: (setq tem (if (< nlines 0) (- nlines) nlines))
185: (while (> tem 0)
186: (insert empty ?:)
187: (forward-line 1)
188: (setq tem (1- tem)))
189: (insert tag ?:)
190: (forward-line 1)
191: (while (< tem nlines)
192: (insert empty ?:)
193: (forward-line 1)
194: (setq tem (1+ tem))))
195: (forward-line 1)))
196: (set-buffer standard-output)
197: ;; Put positions in increasing order to go with buffer.
198: (setq occur-pos-list (nreverse occur-pos-list))
199: (if (interactive-p)
200: (message "%d matching lines." (length occur-pos-list)))))))
201:
202: (defconst query-replace-help
203: "Type Space or `y' to replace one match, Delete or `n' to skip to next,
204: ESC or `q' to exit, Period to replace one match and exit,
205: Comma to replace but not move point immediately,
206: C-r to enter recursive edit (\\[exit-recursive-edit] to get out again),
207: C-w to delete match and recursive edit,
208: C-l to clear the screen, redisplay, and offer same replacement again,
209: ! to replace all remaining matches with no more questions,
210: ^ to move point back to previous match.
211:
212: Type a Space now to remove this message."
213: "Help message while in query-replace")
214:
215: (defun perform-replace (from-string to-string
216: query-flag regexp-flag delimited-flag)
217: (let ((nocasify (not (and case-fold-search case-replace
218: (string-equal from-string
219: (downcase from-string)))))
220: (literal (not regexp-flag))
221: (search-function (if regexp-flag 're-search-forward 'search-forward))
222: (search-string from-string)
223: (keep-going t)
224: (lastrepl nil)) ;Position after last match considered.
225: (if delimited-flag
226: (setq search-function 're-search-forward
227: search-string (concat "\\b"
228: (if regexp-flag from-string
229: (regexp-quote from-string))
230: "\\b")))
231: (push-mark)
232: (push-mark)
233: (while (and keep-going
234: (not (eobp))
235: (progn
236: (set-mark (point))
237: (funcall search-function search-string nil t)))
238: ;; Don't replace the null string
239: ;; right after end of previous replacement.
240: (if (eq lastrepl (point))
241: (forward-char 1)
242: (undo-boundary)
243: (if (not query-flag)
244: (replace-match to-string nocasify literal)
245: (let (done replaced)
246: (while (not done)
247: ;; Preserve the match data. Process filters and sentinels
248: ;; could run inside read-char..
249: (let ((data (match-data))
250: (help-form
251: '(concat "Query replacing "
252: (if regexp-flag "regexp " "")
253: from-string " with " to-string ".\n\n"
254: (substitute-command-keys query-replace-help))))
255: (setq char help-char)
256: (while (= char help-char)
257: (message "Query replacing %s with %s: " from-string to-string)
258: (setq char (read-char))
259: (if (= char ??)
260: (setq unread-command-char help-char char help-char)))
261: (store-match-data data))
262: (cond ((or (= char ?\e)
263: (= char ?q))
264: (setq keep-going nil)
265: (setq done t))
266: ((= char ?^)
267: (goto-char (mark))
268: (setq replaced t))
269: ((or (= char ?\ )
270: (= char ?y))
271: (or replaced
272: (replace-match to-string nocasify literal))
273: (setq done t))
274: ((= char ?\.)
275: (or replaced
276: (replace-match to-string nocasify literal))
277: (setq keep-going nil)
278: (setq done t))
279: ((= char ?\,)
280: (if (not replaced)
281: (progn
282: (replace-match to-string nocasify literal)
283: (setq replaced t))))
284: ((= char ?!)
285: (or replaced
286: (replace-match to-string nocasify literal))
287: (setq done t query-flag nil))
288: ((or (= char ?\177)
289: (= char ?n))
290: (setq done t))
291: ((= char ?\C-l)
292: (recenter nil))
293: ((= char ?\C-r)
294: (store-match-data
295: (prog1 (match-data)
296: (save-excursion (recursive-edit)))))
297: ((= char ?\C-w)
298: (delete-region (match-beginning 0) (match-end 0))
299: (store-match-data
300: (prog1 (match-data)
301: (save-excursion (recursive-edit))))
302: (setq replaced t))
303: (t
304: (setq keep-going nil)
305: (setq unread-command-char char)
306: (setq done t))))))
307: (setq lastrepl (point))))
308: (pop-mark)
309: keep-going))
310:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.