]> code.delx.au - gnu-emacs-elpa/blob - packages/all-1.0.el
* packages/all-1.0.el: Change version. Address byte-compiler warnings.
[gnu-emacs-elpa] / packages / all-1.0.el
1 ;;; all.el --- Edit all lines matching a given regexp
2
3 ;; Copyright (C) 1985-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: 1.0
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 are
32 ;; propagated to the original buffer.
33
34 ;; You can no longer use mouse-2 to find a match in the original file,
35 ;; since the default definition of mouse too is useful.
36 ;; However, `C-c C-c' still works.
37
38 ;; Line numbers are not listed in the *All* buffer.
39
40 ;; Ok, it is _not_ just like occur.
41
42 ;; Some limitations:
43
44 ;; - Undo in the *All* buffer is an ordinary change in the original.
45 ;; - Changes to the original buffer are not reflected in the *All* buffer.
46 ;; - A single change in the *All* buffer must be limited to a single match.
47
48 ;;; Code:
49
50 (defvar all-mode-map
51 (let ((map (make-sparse-keymap)))
52 (define-key map "\C-c\C-c" 'all-mode-goto)
53 map))
54
55 (defvar all-buffer nil)
56 (make-variable-buffer-local 'all-buffer)
57
58 (define-derived-mode all-mode fundamental-mode "All"
59 "Major mode for output from \\[all].
60
61 All changes made in this buffer will be propagated to the buffer where
62 you ran \\[all].
63
64 Press \\[all-mode-goto] to go to the same spot in the original buffer."
65 (add-hook 'before-change-functions 'all-before-change-function nil 'local)
66 (add-hook 'after-change-functions 'all-after-change-function nil 'local))
67
68 (defun all-mode-find (pos)
69 ;; Find position in original buffer corresponding to POS.
70 (let ((overlay (all-mode-find-overlay pos)))
71 (if overlay
72 (+ (marker-position (overlay-get overlay 'all-marker))
73 (- pos (overlay-start overlay))))))
74
75 (defun all-mode-find-overlay (pos)
76 ;; Find the overlay containing POS.
77 (let ((overlays (overlays-at pos)))
78 (while (and overlays (null (overlay-get (car overlays) 'all-marker)))
79 (setq overlays (cdr overlays)))
80 (car-safe overlays)))
81
82 (defun all-mode-goto ()
83 "Move point to the corresponding position in the original buffer."
84 (interactive)
85 (let ((pos (all-mode-find (point))))
86 (if pos
87 (pop-to-buffer all-buffer)
88 (error "This text is not from the original buffer"))
89 (goto-char pos)))
90
91 (defvar all-initialization-p nil)
92
93 (defun all-before-change-function (from to)
94 ;; Check that change is legal.
95 (and all-buffer
96 (not all-initialization-p)
97 (let ((start (all-mode-find-overlay from))
98 (end (all-mode-find-overlay to)))
99 (not (and start (eq start end))))
100 (error "Changes should be limited to a single text piece")))
101
102 (defun all-after-change-function (from to length)
103 ;; Propagate changes from *All* buffer.
104 (and all-buffer
105 (null all-initialization-p)
106 (let ((buffer (current-buffer))
107 (pos (all-mode-find from)))
108 (if pos
109 (with-current-buffer all-buffer
110 (save-excursion
111 (goto-char pos)
112 (delete-region pos (+ pos length))
113 (insert-buffer-substring buffer from to)))))))
114
115 ;;;###autoload
116 (defun all (regexp &optional nlines)
117 "Show all lines in the current buffer containing a match for REGEXP.
118
119 If a match spreads across multiple lines, all those lines are shown.
120
121 Each line is displayed with NLINES lines before and after, or -NLINES
122 before if NLINES is negative.
123 NLINES defaults to `list-matching-lines-default-context-lines'.
124 Interactively it is the prefix arg.
125
126 The lines are shown in a buffer named `*All*'.
127 Any changes made in that buffer will be propagated to this buffer."
128 (interactive
129 (list (let* ((default (car regexp-history)))
130 (read-string
131 (if default
132 (format
133 "Edit lines matching regexp (default `%s'): " default)
134 "Edit lines matching regexp: ")
135 nil 'regexp-history default))
136 current-prefix-arg))
137 (setq nlines (if nlines (prefix-numeric-value nlines)
138 list-matching-lines-default-context-lines))
139 (let ((all-initialization-p t)
140 (buffer (current-buffer))
141 (prevend nil)
142 (prevstart nil)
143 (prevpos (point-min)))
144 (with-output-to-temp-buffer "*All*"
145 (with-current-buffer standard-output
146 (all-mode)
147 (setq all-buffer buffer)
148 (insert "Lines matching ")
149 (prin1 regexp)
150 (insert " in buffer " (buffer-name buffer) ?. ?\n)
151 (insert "--------\n"))
152 (if (eq buffer standard-output)
153 (goto-char (point-max)))
154 (save-excursion
155 (goto-char (point-min))
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 (goto-char (match-beginning 0))
160 (beginning-of-line)
161 (setq prevpos (point))
162 (goto-char (match-end 0))
163 (let* ((start (save-excursion
164 (goto-char (match-beginning 0))
165 (forward-line (if (< nlines 0) nlines (- nlines)))
166 (point)))
167 (end (save-excursion
168 (goto-char (match-end 0))
169 (if (> nlines 0)
170 (forward-line (1+ nlines))
171 (forward-line 1))
172 (point))))
173 (cond ((null prevend)
174 (setq prevstart start
175 prevend end))
176 ((> start prevend)
177 (all-insert prevstart prevend regexp nlines)
178 (setq prevstart start
179 prevend end))
180 (t
181 (setq prevend end)))))
182 (if prevend
183 (all-insert prevstart prevend regexp nlines))))))
184
185 (defun all-insert (start end regexp nlines)
186 ;; Insert match.
187 (let ((marker (copy-marker start))
188 (buffer (current-buffer)))
189 (with-current-buffer standard-output
190 (let ((from (point))
191 to)
192 (insert-buffer-substring buffer start end)
193 (setq to (point))
194 (overlay-put (make-overlay from to) 'all-marker marker)
195 (goto-char from)
196 (while (re-search-forward regexp to t)
197 (put-text-property (match-beginning 0) (match-end 0)
198 'face 'match))
199 (goto-char to)
200 (if (> nlines 0)
201 (insert "--------\n"))))))
202
203 (provide 'all)
204
205 ;;; all.el ends here