aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/replace.el
diff options
context:
space:
mode:
authorJuri Linkov2010-03-30 19:03:08 +0300
committerJuri Linkov2010-03-30 19:03:08 +0300
commitdc2d2590b24f7e4ee648b5d073ba744fbda7a4d8 (patch)
tree8d15261ebed74c762df72b14eb4023534c784520 /lisp/replace.el
parent47c88c067f98772d5b505d7b6ad3d0909da5f68a (diff)
downloademacs-dc2d2590b24f7e4ee648b5d073ba744fbda7a4d8.tar.gz
emacs-dc2d2590b24f7e4ee648b5d073ba744fbda7a4d8.zip
Make occur handle multi-line matches cleanly with context.
http://lists.gnu.org/archive/html/emacs-devel/2010-03/msg01280.html * replace.el (occur-accumulate-lines): Add optional arg `pt'. (occur-engine): Add local variables `ret', `prev-after-lines', `prev-lines'. Use more arguments for `occur-context-lines'. Set first elem of its returned list to `data', and the second elem to `prev-after-lines'. Don't print the separator line. In the end, print remaining context after-lines. (occur-context-lines): Add new arguments `begpt', `endpt', `lines', `prev-lines', `prev-after-lines'. Rewrite to combine after-lines of the previous match with before-lines of the current match and not overlap them. Return a list with two values: the output line and the list of context after-lines. * search.texi (Other Repeating Search): Remove line that `occur' can not handle multiline matches. * occur-testsuite.el (occur-tests): Add tests for context lines.
Diffstat (limited to 'lisp/replace.el')
-rw-r--r--lisp/replace.el90
1 files changed, 73 insertions, 17 deletions
diff --git a/lisp/replace.el b/lisp/replace.el
index a74da4b89b5..14a1869b4f9 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -1005,8 +1005,10 @@ which means to discard all text properties."
1005 :group 'matching 1005 :group 'matching
1006 :version "22.1") 1006 :version "22.1")
1007 1007
1008(defun occur-accumulate-lines (count &optional keep-props) 1008(defun occur-accumulate-lines (count &optional keep-props pt)
1009 (save-excursion 1009 (save-excursion
1010 (when pt
1011 (goto-char pt))
1010 (let ((forwardp (> count 0)) 1012 (let ((forwardp (> count 0))
1011 result beg end moved) 1013 result beg end moved)
1012 (while (not (or (zerop count) 1014 (while (not (or (zerop count)
@@ -1189,12 +1191,15 @@ See also `multi-occur'."
1189 (when (buffer-live-p buf) 1191 (when (buffer-live-p buf)
1190 (let ((matches 0) ;; count of matched lines 1192 (let ((matches 0) ;; count of matched lines
1191 (lines 1) ;; line count 1193 (lines 1) ;; line count
1194 (prev-after-lines nil) ;; context lines of prev match
1195 (prev-lines nil) ;; line number of prev match endpt
1192 (matchbeg 0) 1196 (matchbeg 0)
1193 (origpt nil) 1197 (origpt nil)
1194 (begpt nil) 1198 (begpt nil)
1195 (endpt nil) 1199 (endpt nil)
1196 (marker nil) 1200 (marker nil)
1197 (curstring "") 1201 (curstring "")
1202 (ret nil)
1198 (inhibit-field-text-motion t) 1203 (inhibit-field-text-motion t)
1199 (headerpt (with-current-buffer out-buf (point)))) 1204 (headerpt (with-current-buffer out-buf (point))))
1200 (with-current-buffer buf 1205 (with-current-buffer buf
@@ -1271,14 +1276,17 @@ See also `multi-occur'."
1271 ;; The simple display style 1276 ;; The simple display style
1272 out-line 1277 out-line
1273 ;; The complex multi-line display style. 1278 ;; The complex multi-line display style.
1274 (occur-context-lines out-line nlines keep-props) 1279 (setq ret (occur-context-lines
1275 ))) 1280 out-line nlines keep-props begpt endpt
1281 lines prev-lines prev-after-lines))
1282 ;; Set first elem of the returned list to `data',
1283 ;; and the second elem to `prev-after-lines'.
1284 (setq prev-after-lines (nth 1 ret))
1285 (nth 0 ret))))
1276 ;; Actually insert the match display data 1286 ;; Actually insert the match display data
1277 (with-current-buffer out-buf 1287 (with-current-buffer out-buf
1278 (let ((beg (point)) 1288 (let ((beg (point))
1279 (end (progn (insert data) (point)))) 1289 (end (progn (insert data) (point)))))))
1280 (unless (= nlines 0)
1281 (insert "-------\n")))))
1282 (goto-char endpt)) 1290 (goto-char endpt))
1283 (if endpt 1291 (if endpt
1284 (progn 1292 (progn
@@ -1289,7 +1297,13 @@ See also `multi-occur'."
1289 (if (and (bolp) (eolp)) 1 0))) 1297 (if (and (bolp) (eolp)) 1 0)))
1290 ;; On to the next match... 1298 ;; On to the next match...
1291 (forward-line 1)) 1299 (forward-line 1))
1292 (goto-char (point-max)))))) 1300 (goto-char (point-max)))
1301 (setq prev-lines (1- lines)))
1302 ;; Flush remaining context after-lines.
1303 (when prev-after-lines
1304 (with-current-buffer out-buf
1305 (insert (apply #'concat (occur-engine-add-prefix
1306 prev-after-lines)))))))
1293 (when (not (zerop matches)) ;; is the count zero? 1307 (when (not (zerop matches)) ;; is the count zero?
1294 (setq globalcount (+ globalcount matches)) 1308 (setq globalcount (+ globalcount matches))
1295 (with-current-buffer out-buf 1309 (with-current-buffer out-buf
@@ -1345,18 +1359,60 @@ See also `multi-occur'."
1345;; Generate context display for occur. 1359;; Generate context display for occur.
1346;; OUT-LINE is the line where the match is. 1360;; OUT-LINE is the line where the match is.
1347;; NLINES and KEEP-PROPS are args to occur-engine. 1361;; NLINES and KEEP-PROPS are args to occur-engine.
1362;; LINES is line count of the current match,
1363;; PREV-LINES is line count of the previous match,
1364;; PREV-AFTER-LINES is a list of after-context lines of the previous match.
1348;; Generate a list of lines, add prefixes to all but OUT-LINE, 1365;; Generate a list of lines, add prefixes to all but OUT-LINE,
1349;; then concatenate them all together. 1366;; then concatenate them all together.
1350(defun occur-context-lines (out-line nlines keep-props) 1367(defun occur-context-lines (out-line nlines keep-props begpt endpt
1351 (apply #'concat 1368 lines prev-lines prev-after-lines)
1352 (nconc 1369 ;; Find after- and before-context lines of the current match.
1353 (occur-engine-add-prefix 1370 (let ((before-lines
1354 (nreverse (cdr (occur-accumulate-lines 1371 (nreverse (cdr (occur-accumulate-lines
1355 (- (1+ (abs nlines))) keep-props)))) 1372 (- (1+ (abs nlines))) keep-props begpt))))
1356 (list out-line) 1373 (after-lines
1357 (if (> nlines 0) 1374 (cdr (occur-accumulate-lines
1358 (occur-engine-add-prefix 1375 (1+ nlines) keep-props endpt)))
1359 (cdr (occur-accumulate-lines (1+ nlines) keep-props))))))) 1376 separator)
1377
1378 ;; Combine after-lines of the previous match
1379 ;; with before-lines of the current match.
1380
1381 (when prev-after-lines
1382 ;; Don't overlap prev after-lines with current before-lines.
1383 (if (>= (+ prev-lines (length prev-after-lines))
1384 (- lines (length before-lines)))
1385 (setq prev-after-lines
1386 (butlast prev-after-lines
1387 (- (length prev-after-lines)
1388 (- lines prev-lines (length before-lines) 1))))
1389 ;; Separate non-overlapping context lines with a dashed line.
1390 (setq separator "-------\n")))
1391
1392 (when prev-lines
1393 ;; Don't overlap current before-lines with previous match line.
1394 (if (<= (- lines (length before-lines))
1395 prev-lines)
1396 (setq before-lines
1397 (nthcdr (- (length before-lines)
1398 (- lines prev-lines 1))
1399 before-lines))
1400 ;; Separate non-overlapping before-context lines.
1401 (unless (> nlines 0)
1402 (setq separator "-------\n"))))
1403
1404 (list
1405 ;; Return a list where the first element is the output line.
1406 (apply #'concat
1407 (append
1408 (and prev-after-lines
1409 (occur-engine-add-prefix prev-after-lines))
1410 (and separator (list separator))
1411 (occur-engine-add-prefix before-lines)
1412 (list out-line)))
1413 ;; And the second element is the list of context after-lines.
1414 (if (> nlines 0) after-lines))))
1415
1360 1416
1361;; It would be nice to use \\[...], but there is no reasonable way 1417;; It would be nice to use \\[...], but there is no reasonable way
1362;; to make that display both SPC and Y. 1418;; to make that display both SPC and Y.