]> code.delx.au - gnu-emacs-elpa/blob - packages/all-19970304.el
e5ddf14b91c9a186c33499663ebdc0d22f5ffe31
[gnu-emacs-elpa] / packages / all-19970304.el
1 ;;; all.el --- Edit all lines matching a given regexp.
2
3 ;; Copyright (C) 1985, 1986, 1987, 1992, 1994, 2011 Free Software Foundation, Inc.
4 ;; Copyright (C) 1994 Per Abrahamsen
5
6 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
7 ;; Version: $Id: all.el,v 5.2 1997/03/04 10:29:42 abraham Exp $
8 ;; Keywords: matching
9
10 ;; LCD Archive Entry:
11 ;; all|Per Abrahamsen|abraham@dina.kvl.dk|
12 ;; Edit all lines matching a given regexp|
13 ;; $Date: 1997/03/04 10:29:42 $|$Revision: 5.2 $|~/misc/all.Z|
14
15 ;; This program is free software; you can redistribute it and/or modify
16 ;; it under the terms of the GNU General Public License as published by
17 ;; the Free Software Foundation; either version 2, or (at your option)
18 ;; any later version.
19 ;;
20 ;; This program is distributed in the hope that it will be useful,
21 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
22 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 ;; GNU General Public License for more details.
24 ;;
25 ;; You should have received a copy of the GNU General Public License
26 ;; along with this program; if not, write to the Free Software
27 ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28
29 ;;; Commentary:
30
31 ;; Just like occur, except that changes in the *All* buffer is
32 ;; propagated to the original buffer.
33
34 ;; I also added highlighting of the matches.
35
36 ;; You can no longer use mouse-2 to find a match in the original file,
37 ;; since the default definition of mouse to is useful.
38 ;; However, `C-c C-c' still works.
39
40 ;; Line numbers are not listed in the *All* buffer.
41
42 ;; Ok, it is _not_ just like occur.
43
44 ;; Some limitations:
45
46 ;; - Undo in the *All* buffer is an ordinary change in the original.
47 ;; - Changes to the original buffer is not reflected in the *All* buffer.
48 ;; - A single change in the *All* buffer must be limited to a single match.
49
50 ;; Requires GNU Emacs 19.23 or later.
51
52 ;;; Code:
53
54 (defvar all-mode-map ())
55
56 (if all-mode-map
57 ()
58 (setq all-mode-map (make-sparse-keymap))
59 (define-key all-mode-map "\C-c\C-c" 'all-mode-goto))
60
61 (defvar all-buffer nil)
62
63 (defun all-mode ()
64 "Major mode for output from \\[all].
65
66 All changes made in this buffer will be propagated to the buffer where
67 you ran \\[all].
68
69 Press \\[all-mode-goto] to go to the same spot in the original buffer."
70 (kill-all-local-variables)
71 (use-local-map all-mode-map)
72 (setq major-mode 'all-mode)
73 (setq mode-name "All")
74 (make-local-variable 'all-buffer)
75 (run-hooks 'all-mode-hook))
76
77 (defun all-mode-find (pos)
78 ;; Find position in original buffer corresponding to POS.
79 (let ((overlay (all-mode-find-overlay pos)))
80 (if overlay
81 (+ (marker-position (overlay-get overlay 'marker))
82 (- pos (overlay-start overlay))))))
83
84 (defun all-mode-find-overlay (pos)
85 ;; Find the overlay containing POS.
86 (let ((overlays (overlays-at pos)))
87 (while (and overlays (null (overlay-get (car overlays) 'marker)))
88 (setq overlays (cdr overlays)))
89 (car-safe overlays)))
90
91 (defun all-mode-goto ()
92 "Move point to the corresponding position in the original buffer."
93 (interactive)
94 (let ((pos (all-mode-find (point))))
95 (if pos
96 (pop-to-buffer all-buffer)
97 (error "This text is not from the original buffer"))
98 (goto-char pos)))
99
100 (defvar all-initialization-p nil)
101
102 (defun all-before-change-function (from to)
103 ;; Check that change is legal
104 (and all-buffer
105 (not all-initialization-p)
106 (let ((start (all-mode-find-overlay from))
107 (end (all-mode-find-overlay to)))
108 (not (and start (eq start end))))
109 (error "Changes should be limited to a single text piece")))
110
111 (add-hook 'before-change-functions 'all-before-change-function)
112
113 (defun all-after-change-function (from to length)
114 ;; Propagate changes from *All* buffer.
115 (and all-buffer
116 (null all-initialization-p)
117 (let ((buffer (current-buffer))
118 (pos (all-mode-find from)))
119 (if pos
120 (progn
121 (set-buffer all-buffer)
122 (delete-region pos (+ pos length))
123 (save-excursion
124 (goto-char pos)
125 (insert-buffer-substring buffer from to))
126 (set-buffer buffer))))))
127
128 (add-hook 'after-change-functions 'all-after-change-function)
129
130 ;;;###autoload
131 (defun all (regexp &optional nlines)
132 "Show all lines in the current buffer containing a match for REGEXP.
133
134 If a match spreads across multiple lines, all those lines are shown.
135
136 Each line is displayed with NLINES lines before and after, or -NLINES
137 before if NLINES is negative.
138 NLINES defaults to `list-matching-lines-default-context-lines'.
139 Interactively it is the prefix arg.
140
141 The lines are shown in a buffer named `*All*'.
142 Any changes made in that buffer will be propagated to this buffer."
143 (interactive (list (let* ((default (car regexp-history))
144 (input
145 (read-from-minibuffer
146 (if default
147 (format
148 "Edit lines matching regexp (default `%s'): " default)
149 "Edit lines matching regexp: ")
150 nil nil nil
151 'regexp-history)))
152 (if (> (length input) 0) input
153 (setcar regexp-history default)))
154 current-prefix-arg))
155 (setq nlines (if nlines (prefix-numeric-value nlines)
156 list-matching-lines-default-context-lines))
157 (setq all-initialization-p t)
158 (let ((first t)
159 (buffer (current-buffer))
160 (prevend nil)
161 (prevstart nil)
162 (prevpos (point-min)))
163 (with-output-to-temp-buffer "*All*"
164 (save-excursion
165 (set-buffer standard-output)
166 (all-mode)
167 (setq all-buffer buffer)
168 (insert "Lines matching ")
169 (prin1 regexp)
170 (insert " in buffer " (buffer-name buffer) ?. ?\n)
171 (insert "--------\n"))
172 (if (eq buffer standard-output)
173 (goto-char (point-max)))
174 (save-excursion
175 (beginning-of-buffer)
176 ;; Find next match, but give up if prev match was at end of buffer.
177 (while (and (not (= prevpos (point-max)))
178 (re-search-forward regexp nil t))
179 (goto-char (match-beginning 0))
180 (beginning-of-line)
181 (setq prevpos (point))
182 (goto-char (match-end 0))
183 (let* ((start (save-excursion
184 (goto-char (match-beginning 0))
185 (forward-line (if (< nlines 0) nlines (- nlines)))
186 (point)))
187 (end (save-excursion
188 (goto-char (match-end 0))
189 (if (> nlines 0)
190 (forward-line (1+ nlines))
191 (forward-line 1))
192 (point)))
193 marker)
194 (cond ((null prevend)
195 (setq prevstart start
196 prevend end))
197 ((> start prevend)
198 (all-insert)
199 (setq prevstart start
200 prevend end))
201 (t
202 (setq prevend end)))))
203 (if prevend
204 (all-insert)))))
205 (setq all-initialization-p nil))
206
207 (defun all-insert ()
208 ;; Insert match.
209 (save-excursion
210 (setq marker (make-marker))
211 (set-marker marker prevstart)
212 (set-buffer standard-output)
213 (let ((from (point))
214 to)
215 (insert-buffer-substring buffer prevstart prevend)
216 (setq to (point))
217 (overlay-put (make-overlay from to) 'marker marker)
218 (goto-char from)
219 (while (re-search-forward regexp to t)
220 (overlay-put (make-overlay (match-beginning 0) (match-end 0))
221 'face 'highlight))
222 (goto-char to)
223 (if (> nlines 0)
224 (insert "--------\n")))))
225
226 (provide 'all)
227
228 ;;; all.el ends here