From 774642e5492984eceb237d6fc4de129fd3996ed5 Mon Sep 17 00:00:00 2001 From: Juri Linkov Date: Tue, 23 Mar 2010 18:09:45 +0200 Subject: [PATCH] Implement Occur multi-line matches. http://lists.gnu.org/archive/html/emacs-devel/2010-03/msg01044.html * replace.el (occur): Doc fix. (occur-engine): Set `begpt' to the beginning of the first line. Set `endpt' to the end of the last match line. At first, count line numbers between `origpt' and `begpt'. Split out code from `out-line' variable to new let-bindings `match-prefix' and `match-str'. In `out-line' add non-numeric prefix to all non-first lines of multi-line matches. Finally, count lines between `begpt' and `endpt' and add to `lines'. --- etc/TODO | 3 --- lisp/ChangeLog | 14 ++++++++++++ lisp/replace.el | 60 +++++++++++++++++++++++++++++++------------------ 3 files changed, 52 insertions(+), 25 deletions(-) diff --git a/etc/TODO b/etc/TODO index a20ffdaa0d3..6ce2947bd93 100644 --- a/etc/TODO +++ b/etc/TODO @@ -105,9 +105,6 @@ for users to customize. ** erase-buffer should perhaps disregard read-only properties of text. -** Make occur correctly handle matches that span more than one line, - as well as overlapping matches. - ** Fix the kill/yank treatment of invisible text. At the moment, invisible text is placed in the kill-ring, so that the contents of the ring may not correspond to the text as displayed to the user. diff --git a/lisp/ChangeLog b/lisp/ChangeLog index b84b8436993..c417eb7246e 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,17 @@ +2010-03-23 Juri Linkov + + Implement Occur multi-line matches. + http://lists.gnu.org/archive/html/emacs-devel/2010-03/msg01044.html + + * replace.el (occur): Doc fix. + (occur-engine): Set `begpt' to the beginning of the first line. + Set `endpt' to the end of the last match line. At first, count + line numbers between `origpt' and `begpt'. Split out code from + `out-line' variable to new let-bindings `match-prefix' and + `match-str'. In `out-line' add non-numeric prefix to all + non-first lines of multi-line matches. Finally, count lines + between `begpt' and `endpt' and add to `lines'. + 2010-03-23 Juri Linkov * replace.el (occur-accumulate-lines, occur-engine): diff --git a/lisp/replace.el b/lisp/replace.el index f2d49b4de1c..4a8b39dbca7 100644 --- a/lisp/replace.el +++ b/lisp/replace.el @@ -1045,7 +1045,7 @@ invoke `occur'." (defun occur (regexp &optional nlines) "Show all lines in the current buffer containing a match for REGEXP. -This function can not handle matches that span more than one line. +If a match spreads across multiple lines, all those lines are shown. Each line is displayed with NLINES lines before and after, or -NLINES before if NLINES is negative. @@ -1210,11 +1210,14 @@ See also `multi-occur'." (when (setq endpt (re-search-forward regexp nil t)) (setq matches (1+ matches)) ;; increment match count (setq matchbeg (match-beginning 0)) - (setq lines (+ lines (1- (count-lines origpt endpt)))) + ;; Get beginning of first match line and end of the last. (save-excursion (goto-char matchbeg) - (setq begpt (line-beginning-position) - endpt (line-end-position))) + (setq begpt (line-beginning-position)) + (goto-char endpt) + (setq endpt (line-end-position))) + ;; Sum line numbers up to the first match line. + (setq lines (+ lines (count-lines origpt begpt))) (setq marker (make-marker)) (set-marker marker matchbeg) (setq curstring (occur-engine-line begpt endpt keep-props)) @@ -1234,24 +1237,33 @@ See also `multi-occur'." curstring) (setq start (match-end 0)))) ;; Generate the string to insert for this match - (let* ((out-line + (let* ((match-prefix + ;; Using 7 digits aligns tabs properly. + (apply #'propertize (format "%7d:" lines) + (append + (when prefix-face + `(font-lock-face prefix-face)) + `(occur-prefix t mouse-face (highlight) + occur-target ,marker follow-link t + help-echo "mouse-2: go to this occurrence")))) + (match-str + ;; We don't put `mouse-face' on the newline, + ;; because that loses. And don't put it + ;; on context lines to reduce flicker. + (propertize curstring 'mouse-face (list 'highlight) + 'occur-target marker + 'follow-link t + 'help-echo + "mouse-2: go to this occurrence")) + (out-line (concat - ;; Using 7 digits aligns tabs properly. - (apply #'propertize (format "%7d:" lines) - (append - (when prefix-face - `(font-lock-face prefix-face)) - `(occur-prefix t mouse-face (highlight) - occur-target ,marker follow-link t - help-echo "mouse-2: go to this occurrence"))) - ;; We don't put `mouse-face' on the newline, - ;; because that loses. And don't put it - ;; on context lines to reduce flicker. - (propertize curstring 'mouse-face (list 'highlight) - 'occur-target marker - 'follow-link t - 'help-echo - "mouse-2: go to this occurrence") + match-prefix + ;; Add non-numeric prefix to all non-first lines + ;; of multi-line matches. + (replace-regexp-in-string + "\n" + "\n :" + match-str) ;; Add marker at eol, but no mouse props. (propertize "\n" 'occur-target marker))) (data @@ -1270,7 +1282,11 @@ See also `multi-occur'." (goto-char endpt)) (if endpt (progn - (setq lines (1+ lines)) + ;; Sum line numbers between first and last match lines. + (setq lines (+ lines (count-lines begpt endpt) + ;; Add 1 for empty last match line since + ;; count-lines returns 1 line less. + (if (and (bolp) (eolp)) 1 0))) ;; On to the next match... (forward-line 1)) (goto-char (point-max)))))) -- 2.39.2