which will run faster and will not set the mark or print anything."
(interactive (query-replace-read-args "Replace regexp" t))
(perform-replace regexp to-string start end nil t delimited))
+
\f
(defvar regexp-history nil
"History list for some commands that read regular expressions.")
+
(defalias 'delete-non-matching-lines 'keep-lines)
-(defun keep-lines (regexp)
+(defalias 'delete-matching-lines 'flush-lines)
+(defalias 'count-matches 'how-many)
+
+
+(defun keep-lines-read-args (prompt)
+ "Read arguments for `keep-lines' and friends.
+Prompt for a regexp with PROMPT.
+
+Value is a list (REGEXP START END).
+
+If in Transient Mark node, and the mark is active, START is the
+start of the region, and end is a marker for the end of the region.
+Otherwise, START is the current point, and END is `point-max-marker'."
+ (let ((regexp (read-from-minibuffer prompt nil nil nil
+ 'regexp-history nil t))
+ start end)
+ (if (and transient-mark-mode mark-active)
+ (setq start (region-beginning)
+ end (save-excursion (goto-char (region-end)) (point-marker)))
+ (setq start (point)
+ end (point-max-marker)))
+ (list regexp start end)))
+
+
+(defun keep-lines (regexp &optional rstart rend)
"Delete all lines except those containing matches for REGEXP.
A match split across lines preserves all the lines it lies in.
Applies to all lines after point.
If REGEXP contains upper case characters (excluding those preceded by `\\'),
-the matching is case-sensitive."
- (interactive (list (read-from-minibuffer
- "Keep lines (containing match for regexp): "
- nil nil nil 'regexp-history nil t)))
+the matching is case-sensitive.
+
+Second and third arg RSTART and REND specify the region to operate on.
+
+In Transient Mark mode, if the mark is active, operate on the contents
+of the region. Otherwise, operate from point to the end of the buffer."
+ (interactive
+ (keep-lines-read-args "Keep lines (containing match for regexp): "))
+ (if rstart
+ (goto-char (min rstart rend))
+ (setq rstart (point) rend (point-max-marker)))
(save-excursion
(or (bolp) (forward-line 1))
(let ((start (point))
(case-fold-search (and case-fold-search
(isearch-no-upper-case-p regexp t))))
- (while (not (eobp))
+ (while (< (point) rend)
;; Start is first char not preserved by previous match.
- (if (not (re-search-forward regexp nil 'move))
- (delete-region start (point-max))
+ (if (not (re-search-forward regexp rend 'move))
+ (delete-region start rend)
(let ((end (save-excursion (goto-char (match-beginning 0))
(beginning-of-line)
(point))))
;; Now end is first char preserved by the new match.
(if (< start end)
(delete-region start end))))
- (setq start (save-excursion (forward-line 1)
- (point)))
+
+ (setq start (save-excursion (forward-line 1) (point)))
;; If the match was empty, avoid matching again at same place.
- (and (not (eobp)) (= (match-beginning 0) (match-end 0))
+ (and (< (point) rend)
+ (= (match-beginning 0) (match-end 0))
(forward-char 1))))))
-(defalias 'delete-matching-lines 'flush-lines)
-(defun flush-lines (regexp)
+
+(defun flush-lines (regexp &optional rstart rend)
"Delete lines containing matches for REGEXP.
If a match is split across lines, all the lines it lies in are deleted.
Applies to lines after point.
If REGEXP contains upper case characters (excluding those preceded by `\\'),
-the matching is case-sensitive."
- (interactive (list (read-from-minibuffer
- "Flush lines (containing match for regexp): "
- nil nil nil 'regexp-history nil t)))
+the matching is case-sensitive.
+
+Second and third arg RSTART and REND specify the region to operate on.
+
+In Transient Mark mode, if the mark is active, operate on the contents
+of the region. Otherwise, operate from point to the end of the buffer."
+ (interactive
+ (keep-lines-read-args "Flush lines (containing match for regexp): "))
+ (if rstart
+ (goto-char (min rstart rend))
+ (setq rstart (point) rend (point-max-marker)))
(let ((case-fold-search (and case-fold-search
(isearch-no-upper-case-p regexp t))))
(save-excursion
- (while (and (not (eobp))
- (re-search-forward regexp nil t))
+ (while (and (< (point) rend)
+ (re-search-forward regexp rend t))
(delete-region (save-excursion (goto-char (match-beginning 0))
(beginning-of-line)
(point))
(progn (forward-line 1) (point)))))))
-(defalias 'count-matches 'how-many)
-(defun how-many (regexp)
+
+(defun how-many (regexp &optional rstart rend)
"Print number of matches for REGEXP following point.
If REGEXP contains upper case characters (excluding those preceded by `\\'),
-the matching is case-sensitive."
- (interactive (list (read-from-minibuffer
- "How many matches for (regexp): "
- nil nil nil 'regexp-history nil t)))
- (let ((count 0) opoint
- (case-fold-search (and case-fold-search
- (isearch-no-upper-case-p regexp t))))
+the matching is case-sensitive.
+
+Second and third arg RSTART and REND specify the region to operate on.
+
+In Transient Mark mode, if the mark is active, operate on the contents
+of the region. Otherwise, operate from point to the end of the buffer."
+ (interactive
+ (keep-lines-read-args "How many matches for (regexp): "))
+ (if rstart
+ (goto-char (min rstart rend))
+ (setq rstart (point) rend (point-max-marker)))
+ (let ((count 0)
+ opoint
+ (case-fold-search (and case-fold-search
+ (isearch-no-upper-case-p regexp t))))
(save-excursion
- (while (and (not (eobp))
+ (while (and (< (point) rend)
(progn (setq opoint (point))
- (re-search-forward regexp nil t)))
+ (re-search-forward regexp rend t)))
(if (= opoint (point))
(forward-char 1)
(setq count (1+ count))))
(message "%d occurrences" count))))
+
\f
(defvar occur-mode-map ())
(if occur-mode-map
(setq input default))
input)
current-prefix-arg))
- (let ((nlines (if nlines
- (prefix-numeric-value nlines)
- list-matching-lines-default-context-lines))
- (first t)
- ;;flag to prevent printing separator for first match
- (occur-num-matches 0)
- (buffer (current-buffer))
- (dir default-directory)
- (linenum 1)
- (prevpos
- ;;position of most recent match
- (point-min))
- (case-fold-search (and case-fold-search
- (isearch-no-upper-case-p regexp t)))
- (final-context-start
- ;; Marker to the start of context immediately following
- ;; the matched text in *Occur*.
- (make-marker)))
+ (let* ((nlines (if nlines
+ (prefix-numeric-value nlines)
+ list-matching-lines-default-context-lines))
+ (current-tab-width tab-width)
+ ;; Minimum width of line number plus trailing colon.
+ (min-line-number-width 6)
+ ;; Width of line number prefix without the colon. Choose a
+ ;; width that's a multiple of `tab-width' in the original
+ ;; buffer so that lines in *Occur* appear right.
+ (line-number-width (1- (* (/ (- (+ min-line-number-width
+ tab-width)
+ 1)
+ tab-width)
+ tab-width)))
+ ;; Format string for line numbers.
+ (line-number-format (format "%%%dd" line-number-width))
+ (empty (make-string line-number-width ?\ ))
+ (first t)
+ ;;flag to prevent printing separator for first match
+ (occur-num-matches 0)
+ (buffer (current-buffer))
+ (dir default-directory)
+ (linenum 1)
+ (prevpos
+ ;;position of most recent match
+ (point-min))
+ (case-fold-search (and case-fold-search
+ (isearch-no-upper-case-p regexp t)))
+ (final-context-start
+ ;; Marker to the start of context immediately following
+ ;; the matched text in *Occur*.
+ (make-marker)))
;;; (save-excursion
;;; (beginning-of-line)
;;; (setq linenum (1+ (count-lines (point-min) (point))))
(setq linenum (+ linenum (count-lines prevpos (point)))))
(setq prevpos (point))
(goto-char (match-end 0))
- (let* ((start
- ;;start point of text in source buffer to be put
- ;;into *Occur*
- (save-excursion
+ (let* (;;start point of text in source buffer to be put
+ ;;into *Occur*
+ (start (save-excursion
(goto-char (match-beginning 0))
(forward-line (if (< nlines 0)
nlines
(- nlines)))
(point)))
- (end
;; end point of text in source buffer to be put
;; into *Occur*
- (save-excursion
- (goto-char (match-end 0))
- (if (> nlines 0)
- (forward-line (1+ nlines))
- (forward-line 1))
- (point)))
- (match-beg
+ (end (save-excursion
+ (goto-char (match-end 0))
+ (if (> nlines 0)
+ (forward-line (1+ nlines))
+ (forward-line 1))
+ (point)))
;; Amount of context before matching text
- (- (match-beginning 0) start))
- (match-len
+ (match-beg (- (match-beginning 0) start))
;; Length of matching text
- (- (match-end 0) (match-beginning 0)))
- (tag (format "%5d" linenum))
- (empty (make-string (length tag) ?\ ))
+ (match-len (- (match-end 0) (match-beginning 0)))
+ (tag (format line-number-format linenum))
tem
insertion-start
;; Number of lines of context to show for current match.
(text-end
;; Marker pointing to end of text for one match
;; in *Occur*.
- (make-marker))
- )
+ (make-marker)))
(save-excursion
(setq occur-marker (make-marker))
(set-marker occur-marker (point))
(or first (zerop nlines)
(insert "--------\n"))
(setq first nil)
+ (save-excursion
+ (set-buffer "*Occur*")
+ (setq tab-width current-tab-width))
;; Insert matching text including context lines from
;; source buffer into *Occur*
(let ((this-linenum linenum))
(while (< (point) final-context-start)
(if (null tag)
- (setq tag (format "%5d" this-linenum)))
+ (setq tag (format line-number-format this-linenum)))
(insert tag ?:)
(forward-line 1)
(setq tag nil)
(define-key query-replace-map "n" 'skip)
(define-key query-replace-map "Y" 'act)
(define-key query-replace-map "N" 'skip)
+(define-key query-replace-map "e" 'edit-replacement)
(define-key query-replace-map "E" 'edit-replacement)
(define-key query-replace-map "," 'act-and-show)
(define-key query-replace-map "q" 'exit)
(setq nonempty-match
(/= (nth 0 real-match-data) (nth 1 real-match-data)))
- ;; If the match is empty, record that the next one can't be adjacent.
+ ;; If the match is empty, record that the next one can't be
+ ;; adjacent.
+
;; Otherwise, if matching a regular expression, do the next
;; match now, since the replacement for this match may
;; affect whether the next match is adjacent to this one.
+ ;; If that match is empty, don't use it.
(setq match-again
(and nonempty-match
(or (not regexp-flag)
(and (looking-at search-string)
- (match-data)))))
+ (let ((match (match-data)))
+ (and (/= (nth 0 match) (nth 1 match))
+ match))))))
;; Calculate the replacement string, if necessary.
(when replacements