aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/replace.el
diff options
context:
space:
mode:
authorTom Tromey2013-06-03 12:25:05 -0600
committerTom Tromey2013-06-03 12:25:05 -0600
commit68359abba96d7ec4db8aab3d3dd9cf1105c3bab5 (patch)
tree862703e7e1a1888170136a8296a5750d6b2ae2eb /lisp/replace.el
parentcbcba8ce7f980b01c18c0fd561ef6687b1361507 (diff)
parente2d8a6f0a229b4ebe26484b892ec4f14888f58b6 (diff)
downloademacs-68359abba96d7ec4db8aab3d3dd9cf1105c3bab5.tar.gz
emacs-68359abba96d7ec4db8aab3d3dd9cf1105c3bab5.zip
merge from trunk; clean up some issues
Diffstat (limited to 'lisp/replace.el')
-rw-r--r--lisp/replace.el374
1 files changed, 236 insertions, 138 deletions
diff --git a/lisp/replace.el b/lisp/replace.el
index 17eea19edd8..af05bd11fb2 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -250,6 +250,10 @@ letters. \(Transferring the case pattern means that if the old text
250matched is all caps, or capitalized, then its replacement is upcased 250matched is all caps, or capitalized, then its replacement is upcased
251or capitalized.) 251or capitalized.)
252 252
253Ignore read-only matches if `query-replace-skip-read-only' is non-nil,
254ignore hidden matches if `search-invisible' is nil, and ignore more
255matches using a non-nil `isearch-filter-predicates'.
256
253If `replace-lax-whitespace' is non-nil, a space or spaces in the string 257If `replace-lax-whitespace' is non-nil, a space or spaces in the string
254to be replaced will match a sequence of whitespace chars defined by the 258to be replaced will match a sequence of whitespace chars defined by the
255regexp in `search-whitespace-regexp'. 259regexp in `search-whitespace-regexp'.
@@ -300,6 +304,10 @@ pattern of the old text to the new text, if `case-replace' and
300all caps, or capitalized, then its replacement is upcased or 304all caps, or capitalized, then its replacement is upcased or
301capitalized.) 305capitalized.)
302 306
307Ignore read-only matches if `query-replace-skip-read-only' is non-nil,
308ignore hidden matches if `search-invisible' is nil, and ignore more
309matches using a non-nil `isearch-filter-predicates'.
310
303If `replace-regexp-lax-whitespace' is non-nil, a space or spaces in the regexp 311If `replace-regexp-lax-whitespace' is non-nil, a space or spaces in the regexp
304to be replaced will match a sequence of whitespace chars defined by the 312to be replaced will match a sequence of whitespace chars defined by the
305regexp in `search-whitespace-regexp'. 313regexp in `search-whitespace-regexp'.
@@ -380,6 +388,10 @@ that reads REGEXP.
380Preserves case in each replacement if `case-replace' and `case-fold-search' 388Preserves case in each replacement if `case-replace' and `case-fold-search'
381are non-nil and REGEXP has no uppercase letters. 389are non-nil and REGEXP has no uppercase letters.
382 390
391Ignore read-only matches if `query-replace-skip-read-only' is non-nil,
392ignore hidden matches if `search-invisible' is nil, and ignore more
393matches using a non-nil `isearch-filter-predicates'.
394
383If `replace-regexp-lax-whitespace' is non-nil, a space or spaces in the regexp 395If `replace-regexp-lax-whitespace' is non-nil, a space or spaces in the regexp
384to be replaced will match a sequence of whitespace chars defined by the 396to be replaced will match a sequence of whitespace chars defined by the
385regexp in `search-whitespace-regexp'. 397regexp in `search-whitespace-regexp'.
@@ -470,6 +482,10 @@ are non-nil and FROM-STRING has no uppercase letters.
470\(Preserving case means that if the string matched is all caps, or capitalized, 482\(Preserving case means that if the string matched is all caps, or capitalized,
471then its replacement is upcased or capitalized.) 483then its replacement is upcased or capitalized.)
472 484
485Ignore read-only matches if `query-replace-skip-read-only' is non-nil,
486ignore hidden matches if `search-invisible' is nil, and ignore more
487matches using a non-nil `isearch-filter-predicates'.
488
473If `replace-lax-whitespace' is non-nil, a space or spaces in the string 489If `replace-lax-whitespace' is non-nil, a space or spaces in the string
474to be replaced will match a sequence of whitespace chars defined by the 490to be replaced will match a sequence of whitespace chars defined by the
475regexp in `search-whitespace-regexp'. 491regexp in `search-whitespace-regexp'.
@@ -512,6 +528,10 @@ and TO-STRING is also null.)"
512Preserve case in each match if `case-replace' and `case-fold-search' 528Preserve case in each match if `case-replace' and `case-fold-search'
513are non-nil and REGEXP has no uppercase letters. 529are non-nil and REGEXP has no uppercase letters.
514 530
531Ignore read-only matches if `query-replace-skip-read-only' is non-nil,
532ignore hidden matches if `search-invisible' is nil, and ignore more
533matches using a non-nil `isearch-filter-predicates'.
534
515If `replace-regexp-lax-whitespace' is non-nil, a space or spaces in the regexp 535If `replace-regexp-lax-whitespace' is non-nil, a space or spaces in the regexp
516to be replaced will match a sequence of whitespace chars defined by the 536to be replaced will match a sequence of whitespace chars defined by the
517regexp in `search-whitespace-regexp'. 537regexp in `search-whitespace-regexp'.
@@ -1125,6 +1145,14 @@ If the value is nil, don't highlight the buffer names specially."
1125 :type 'face 1145 :type 'face
1126 :group 'matching) 1146 :group 'matching)
1127 1147
1148(defcustom list-matching-lines-prefix-face 'shadow
1149 "Face used by \\[list-matching-lines] to show the prefix column.
1150If the face doesn't differ from the default face,
1151don't highlight the prefix with line numbers specially."
1152 :type 'face
1153 :group 'matching
1154 :version "24.4")
1155
1128(defcustom occur-excluded-properties 1156(defcustom occur-excluded-properties
1129 '(read-only invisible intangible field mouse-face help-echo local-map keymap 1157 '(read-only invisible intangible field mouse-face help-echo local-map keymap
1130 yank-handler follow-link) 1158 yank-handler follow-link)
@@ -1334,7 +1362,9 @@ See also `multi-occur'."
1334 (isearch-no-upper-case-p regexp t) 1362 (isearch-no-upper-case-p regexp t)
1335 case-fold-search) 1363 case-fold-search)
1336 list-matching-lines-buffer-name-face 1364 list-matching-lines-buffer-name-face
1337 nil list-matching-lines-face 1365 (if (face-differs-from-default-p list-matching-lines-prefix-face)
1366 list-matching-lines-prefix-face)
1367 list-matching-lines-face
1338 (not (eq occur-excluded-properties t)))))) 1368 (not (eq occur-excluded-properties t))))))
1339 (let* ((bufcount (length active-bufs)) 1369 (let* ((bufcount (length active-bufs))
1340 (diff (- (length bufs) bufcount))) 1370 (diff (- (length bufs) bufcount)))
@@ -1359,16 +1389,18 @@ See also `multi-occur'."
1359(defun occur-engine (regexp buffers out-buf nlines case-fold 1389(defun occur-engine (regexp buffers out-buf nlines case-fold
1360 title-face prefix-face match-face keep-props) 1390 title-face prefix-face match-face keep-props)
1361 (with-current-buffer out-buf 1391 (with-current-buffer out-buf
1362 (let ((globalcount 0) 1392 (let ((global-lines 0) ;; total count of matching lines
1393 (global-matches 0) ;; total count of matches
1363 (coding nil) 1394 (coding nil)
1364 (case-fold-search case-fold)) 1395 (case-fold-search case-fold))
1365 ;; Map over all the buffers 1396 ;; Map over all the buffers
1366 (dolist (buf buffers) 1397 (dolist (buf buffers)
1367 (when (buffer-live-p buf) 1398 (when (buffer-live-p buf)
1368 (let ((matches 0) ;; count of matched lines 1399 (let ((lines 0) ;; count of matching lines
1369 (lines 1) ;; line count 1400 (matches 0) ;; count of matches
1370 (prev-after-lines nil) ;; context lines of prev match 1401 (curr-line 1) ;; line count
1371 (prev-lines nil) ;; line number of prev match endpt 1402 (prev-line nil) ;; line number of prev match endpt
1403 (prev-after-lines nil) ;; context lines of prev match
1372 (matchbeg 0) 1404 (matchbeg 0)
1373 (origpt nil) 1405 (origpt nil)
1374 (begpt nil) 1406 (begpt nil)
@@ -1389,7 +1421,7 @@ See also `multi-occur'."
1389 (while (not (eobp)) 1421 (while (not (eobp))
1390 (setq origpt (point)) 1422 (setq origpt (point))
1391 (when (setq endpt (re-search-forward regexp nil t)) 1423 (when (setq endpt (re-search-forward regexp nil t))
1392 (setq matches (1+ matches)) ;; increment match count 1424 (setq lines (1+ lines)) ;; increment matching lines count
1393 (setq matchbeg (match-beginning 0)) 1425 (setq matchbeg (match-beginning 0))
1394 ;; Get beginning of first match line and end of the last. 1426 ;; Get beginning of first match line and end of the last.
1395 (save-excursion 1427 (save-excursion
@@ -1398,7 +1430,7 @@ See also `multi-occur'."
1398 (goto-char endpt) 1430 (goto-char endpt)
1399 (setq endpt (line-end-position))) 1431 (setq endpt (line-end-position)))
1400 ;; Sum line numbers up to the first match line. 1432 ;; Sum line numbers up to the first match line.
1401 (setq lines (+ lines (count-lines origpt begpt))) 1433 (setq curr-line (+ curr-line (count-lines origpt begpt)))
1402 (setq marker (make-marker)) 1434 (setq marker (make-marker))
1403 (set-marker marker matchbeg) 1435 (set-marker marker matchbeg)
1404 (setq curstring (occur-engine-line begpt endpt keep-props)) 1436 (setq curstring (occur-engine-line begpt endpt keep-props))
@@ -1407,6 +1439,7 @@ See also `multi-occur'."
1407 (start 0)) 1439 (start 0))
1408 (while (and (< start len) 1440 (while (and (< start len)
1409 (string-match regexp curstring start)) 1441 (string-match regexp curstring start))
1442 (setq matches (1+ matches))
1410 (add-text-properties 1443 (add-text-properties
1411 (match-beginning 0) (match-end 0) 1444 (match-beginning 0) (match-end 0)
1412 (append 1445 (append
@@ -1420,10 +1453,10 @@ See also `multi-occur'."
1420 ;; Generate the string to insert for this match 1453 ;; Generate the string to insert for this match
1421 (let* ((match-prefix 1454 (let* ((match-prefix
1422 ;; Using 7 digits aligns tabs properly. 1455 ;; Using 7 digits aligns tabs properly.
1423 (apply #'propertize (format "%7d:" lines) 1456 (apply #'propertize (format "%7d:" curr-line)
1424 (append 1457 (append
1425 (when prefix-face 1458 (when prefix-face
1426 `(font-lock-face prefix-face)) 1459 `(font-lock-face ,prefix-face))
1427 `(occur-prefix t mouse-face (highlight) 1460 `(occur-prefix t mouse-face (highlight)
1428 ;; Allow insertion of text at 1461 ;; Allow insertion of text at
1429 ;; the end of the prefix (for 1462 ;; the end of the prefix (for
@@ -1447,7 +1480,9 @@ See also `multi-occur'."
1447 ;; of multi-line matches. 1480 ;; of multi-line matches.
1448 (replace-regexp-in-string 1481 (replace-regexp-in-string
1449 "\n" 1482 "\n"
1450 "\n :" 1483 (if prefix-face
1484 (propertize "\n :" 'font-lock-face prefix-face)
1485 "\n :")
1451 match-str) 1486 match-str)
1452 ;; Add marker at eol, but no mouse props. 1487 ;; Add marker at eol, but no mouse props.
1453 (propertize "\n" 'occur-target marker))) 1488 (propertize "\n" 'occur-target marker)))
@@ -1458,7 +1493,8 @@ See also `multi-occur'."
1458 ;; The complex multi-line display style. 1493 ;; The complex multi-line display style.
1459 (setq ret (occur-context-lines 1494 (setq ret (occur-context-lines
1460 out-line nlines keep-props begpt endpt 1495 out-line nlines keep-props begpt endpt
1461 lines prev-lines prev-after-lines)) 1496 curr-line prev-line prev-after-lines
1497 prefix-face))
1462 ;; Set first elem of the returned list to `data', 1498 ;; Set first elem of the returned list to `data',
1463 ;; and the second elem to `prev-after-lines'. 1499 ;; and the second elem to `prev-after-lines'.
1464 (setq prev-after-lines (nth 1 ret)) 1500 (setq prev-after-lines (nth 1 ret))
@@ -1470,28 +1506,34 @@ See also `multi-occur'."
1470 (if endpt 1506 (if endpt
1471 (progn 1507 (progn
1472 ;; Sum line numbers between first and last match lines. 1508 ;; Sum line numbers between first and last match lines.
1473 (setq lines (+ lines (count-lines begpt endpt) 1509 (setq curr-line (+ curr-line (count-lines begpt endpt)
1474 ;; Add 1 for empty last match line since 1510 ;; Add 1 for empty last match line since
1475 ;; count-lines returns 1 line less. 1511 ;; count-lines returns 1 line less.
1476 (if (and (bolp) (eolp)) 1 0))) 1512 (if (and (bolp) (eolp)) 1 0)))
1477 ;; On to the next match... 1513 ;; On to the next match...
1478 (forward-line 1)) 1514 (forward-line 1))
1479 (goto-char (point-max))) 1515 (goto-char (point-max)))
1480 (setq prev-lines (1- lines))) 1516 (setq prev-line (1- curr-line)))
1481 ;; Flush remaining context after-lines. 1517 ;; Flush remaining context after-lines.
1482 (when prev-after-lines 1518 (when prev-after-lines
1483 (with-current-buffer out-buf 1519 (with-current-buffer out-buf
1484 (insert (apply #'concat (occur-engine-add-prefix 1520 (insert (apply #'concat (occur-engine-add-prefix
1485 prev-after-lines))))))) 1521 prev-after-lines prefix-face)))))))
1486 (when (not (zerop matches)) ;; is the count zero? 1522 (when (not (zerop lines)) ;; is the count zero?
1487 (setq globalcount (+ globalcount matches)) 1523 (setq global-lines (+ global-lines lines)
1524 global-matches (+ global-matches matches))
1488 (with-current-buffer out-buf 1525 (with-current-buffer out-buf
1489 (goto-char headerpt) 1526 (goto-char headerpt)
1490 (let ((beg (point)) 1527 (let ((beg (point))
1491 end) 1528 end)
1492 (insert (propertize 1529 (insert (propertize
1493 (format "%d match%s%s in buffer: %s\n" 1530 (format "%d match%s%s%s in buffer: %s\n"
1494 matches (if (= matches 1) "" "es") 1531 matches (if (= matches 1) "" "es")
1532 ;; Don't display the same number of lines
1533 ;; and matches in case of 1 match per line.
1534 (if (= lines matches)
1535 "" (format " in %d line%s"
1536 lines (if (= lines 1) "" "s")))
1495 ;; Don't display regexp for multi-buffer. 1537 ;; Don't display regexp for multi-buffer.
1496 (if (> (length buffers) 1) 1538 (if (> (length buffers) 1)
1497 "" (format " for \"%s\"" 1539 "" (format " for \"%s\""
@@ -1506,12 +1548,17 @@ See also `multi-occur'."
1506 `(occur-title ,buf)))) 1548 `(occur-title ,buf))))
1507 (goto-char (point-min))))))) 1549 (goto-char (point-min)))))))
1508 ;; Display total match count and regexp for multi-buffer. 1550 ;; Display total match count and regexp for multi-buffer.
1509 (when (and (not (zerop globalcount)) (> (length buffers) 1)) 1551 (when (and (not (zerop global-lines)) (> (length buffers) 1))
1510 (goto-char (point-min)) 1552 (goto-char (point-min))
1511 (let ((beg (point)) 1553 (let ((beg (point))
1512 end) 1554 end)
1513 (insert (format "%d match%s total for \"%s\":\n" 1555 (insert (format "%d match%s%s total for \"%s\":\n"
1514 globalcount (if (= globalcount 1) "" "es") 1556 global-matches (if (= global-matches 1) "" "es")
1557 ;; Don't display the same number of lines
1558 ;; and matches in case of 1 match per line.
1559 (if (= global-lines global-matches)
1560 "" (format " in %d line%s"
1561 global-lines (if (= global-lines 1) "" "s")))
1515 (query-replace-descr regexp))) 1562 (query-replace-descr regexp)))
1516 (setq end (point)) 1563 (setq end (point))
1517 (add-text-properties beg end (when title-face 1564 (add-text-properties beg end (when title-face
@@ -1523,7 +1570,7 @@ See also `multi-occur'."
1523 ;; buffer. 1570 ;; buffer.
1524 (set-buffer-file-coding-system coding)) 1571 (set-buffer-file-coding-system coding))
1525 ;; Return the number of matches 1572 ;; Return the number of matches
1526 globalcount))) 1573 global-matches)))
1527 1574
1528(defun occur-engine-line (beg end &optional keep-props) 1575(defun occur-engine-line (beg end &optional keep-props)
1529 (if (and keep-props (if (boundp 'jit-lock-mode) jit-lock-mode) 1576 (if (and keep-props (if (boundp 'jit-lock-mode) jit-lock-mode)
@@ -1537,10 +1584,13 @@ See also `multi-occur'."
1537 str) 1584 str)
1538 (buffer-substring-no-properties beg end))) 1585 (buffer-substring-no-properties beg end)))
1539 1586
1540(defun occur-engine-add-prefix (lines) 1587(defun occur-engine-add-prefix (lines &optional prefix-face)
1541 (mapcar 1588 (mapcar
1542 #'(lambda (line) 1589 #'(lambda (line)
1543 (concat " :" line "\n")) 1590 (concat (if prefix-face
1591 (propertize " :" 'font-lock-face prefix-face)
1592 " :")
1593 line "\n"))
1544 lines)) 1594 lines))
1545 1595
1546(defun occur-accumulate-lines (count &optional keep-props pt) 1596(defun occur-accumulate-lines (count &optional keep-props pt)
@@ -1563,13 +1613,14 @@ See also `multi-occur'."
1563;; Generate context display for occur. 1613;; Generate context display for occur.
1564;; OUT-LINE is the line where the match is. 1614;; OUT-LINE is the line where the match is.
1565;; NLINES and KEEP-PROPS are args to occur-engine. 1615;; NLINES and KEEP-PROPS are args to occur-engine.
1566;; LINES is line count of the current match, 1616;; CURR-LINE is line count of the current match,
1567;; PREV-LINES is line count of the previous match, 1617;; PREV-LINE is line count of the previous match,
1568;; PREV-AFTER-LINES is a list of after-context lines of the previous match. 1618;; PREV-AFTER-LINES is a list of after-context lines of the previous match.
1569;; Generate a list of lines, add prefixes to all but OUT-LINE, 1619;; Generate a list of lines, add prefixes to all but OUT-LINE,
1570;; then concatenate them all together. 1620;; then concatenate them all together.
1571(defun occur-context-lines (out-line nlines keep-props begpt endpt 1621(defun occur-context-lines (out-line nlines keep-props begpt endpt
1572 lines prev-lines prev-after-lines) 1622 curr-line prev-line prev-after-lines
1623 &optional prefix-face)
1573 ;; Find after- and before-context lines of the current match. 1624 ;; Find after- and before-context lines of the current match.
1574 (let ((before-lines 1625 (let ((before-lines
1575 (nreverse (cdr (occur-accumulate-lines 1626 (nreverse (cdr (occur-accumulate-lines
@@ -1584,22 +1635,22 @@ See also `multi-occur'."
1584 1635
1585 (when prev-after-lines 1636 (when prev-after-lines
1586 ;; Don't overlap prev after-lines with current before-lines. 1637 ;; Don't overlap prev after-lines with current before-lines.
1587 (if (>= (+ prev-lines (length prev-after-lines)) 1638 (if (>= (+ prev-line (length prev-after-lines))
1588 (- lines (length before-lines))) 1639 (- curr-line (length before-lines)))
1589 (setq prev-after-lines 1640 (setq prev-after-lines
1590 (butlast prev-after-lines 1641 (butlast prev-after-lines
1591 (- (length prev-after-lines) 1642 (- (length prev-after-lines)
1592 (- lines prev-lines (length before-lines) 1)))) 1643 (- curr-line prev-line (length before-lines) 1))))
1593 ;; Separate non-overlapping context lines with a dashed line. 1644 ;; Separate non-overlapping context lines with a dashed line.
1594 (setq separator "-------\n"))) 1645 (setq separator "-------\n")))
1595 1646
1596 (when prev-lines 1647 (when prev-line
1597 ;; Don't overlap current before-lines with previous match line. 1648 ;; Don't overlap current before-lines with previous match line.
1598 (if (<= (- lines (length before-lines)) 1649 (if (<= (- curr-line (length before-lines))
1599 prev-lines) 1650 prev-line)
1600 (setq before-lines 1651 (setq before-lines
1601 (nthcdr (- (length before-lines) 1652 (nthcdr (- (length before-lines)
1602 (- lines prev-lines 1)) 1653 (- curr-line prev-line 1))
1603 before-lines)) 1654 before-lines))
1604 ;; Separate non-overlapping before-context lines. 1655 ;; Separate non-overlapping before-context lines.
1605 (unless (> nlines 0) 1656 (unless (> nlines 0)
@@ -1609,10 +1660,13 @@ See also `multi-occur'."
1609 ;; Return a list where the first element is the output line. 1660 ;; Return a list where the first element is the output line.
1610 (apply #'concat 1661 (apply #'concat
1611 (append 1662 (append
1612 (and prev-after-lines 1663 (if prev-after-lines
1613 (occur-engine-add-prefix prev-after-lines)) 1664 (occur-engine-add-prefix prev-after-lines prefix-face))
1614 (and separator (list separator)) 1665 (if separator
1615 (occur-engine-add-prefix before-lines) 1666 (list (if prefix-face
1667 (propertize separator 'font-lock-face prefix-face)
1668 separator)))
1669 (occur-engine-add-prefix before-lines prefix-face)
1616 (list out-line))) 1670 (list out-line)))
1617 ;; And the second element is the list of context after-lines. 1671 ;; And the second element is the list of context after-lines.
1618 (if (> nlines 0) after-lines)))) 1672 (if (> nlines 0) after-lines))))
@@ -1818,6 +1872,68 @@ It is used by `query-replace-regexp', `replace-regexp',
1818It is called with three arguments, as if it were 1872It is called with three arguments, as if it were
1819`re-search-forward'.") 1873`re-search-forward'.")
1820 1874
1875(defun replace-search (search-string limit regexp-flag delimited-flag
1876 case-fold-search)
1877 "Search for the next occurence of SEARCH-STRING to replace."
1878 ;; Let-bind global isearch-* variables to values used
1879 ;; to search the next replacement. These let-bindings
1880 ;; should be effective both at the time of calling
1881 ;; `isearch-search-fun-default' and also at the
1882 ;; time of funcalling `search-function'.
1883 ;; These isearch-* bindings can't be placed higher
1884 ;; outside of this function because then another I-search
1885 ;; used after `recursive-edit' might override them.
1886 (let* ((isearch-regexp regexp-flag)
1887 (isearch-word delimited-flag)
1888 (isearch-lax-whitespace
1889 replace-lax-whitespace)
1890 (isearch-regexp-lax-whitespace
1891 replace-regexp-lax-whitespace)
1892 (isearch-case-fold-search case-fold-search)
1893 (isearch-adjusted nil)
1894 (isearch-nonincremental t) ; don't use lax word mode
1895 (isearch-forward t)
1896 (search-function
1897 (or (if regexp-flag
1898 replace-re-search-function
1899 replace-search-function)
1900 (isearch-search-fun-default))))
1901 (funcall search-function search-string limit t)))
1902
1903(defvar replace-overlay nil)
1904
1905(defun replace-highlight (match-beg match-end range-beg range-end
1906 search-string regexp-flag delimited-flag
1907 case-fold-search)
1908 (if query-replace-highlight
1909 (if replace-overlay
1910 (move-overlay replace-overlay match-beg match-end (current-buffer))
1911 (setq replace-overlay (make-overlay match-beg match-end))
1912 (overlay-put replace-overlay 'priority 1001) ;higher than lazy overlays
1913 (overlay-put replace-overlay 'face 'query-replace)))
1914 (if query-replace-lazy-highlight
1915 (let ((isearch-string search-string)
1916 (isearch-regexp regexp-flag)
1917 (isearch-word delimited-flag)
1918 (isearch-lax-whitespace
1919 replace-lax-whitespace)
1920 (isearch-regexp-lax-whitespace
1921 replace-regexp-lax-whitespace)
1922 (isearch-case-fold-search case-fold-search)
1923 (isearch-forward t)
1924 (isearch-other-end match-beg)
1925 (isearch-error nil))
1926 (isearch-lazy-highlight-new-loop range-beg range-end))))
1927
1928(defun replace-dehighlight ()
1929 (when replace-overlay
1930 (delete-overlay replace-overlay))
1931 (when query-replace-lazy-highlight
1932 (lazy-highlight-cleanup lazy-highlight-cleanup)
1933 (setq isearch-lazy-highlight-last-string nil))
1934 ;; Close overlays opened by `isearch-range-invisible' in `perform-replace'.
1935 (isearch-clean-overlays))
1936
1821(defun perform-replace (from-string replacements 1937(defun perform-replace (from-string replacements
1822 query-flag regexp-flag delimited-flag 1938 query-flag regexp-flag delimited-flag
1823 &optional repeat-count map start end) 1939 &optional repeat-count map start end)
@@ -1852,6 +1968,9 @@ make, or the user didn't cancel the call."
1852 (keep-going t) 1968 (keep-going t)
1853 (stack nil) 1969 (stack nil)
1854 (replace-count 0) 1970 (replace-count 0)
1971 (skip-read-only-count 0)
1972 (skip-filtered-count 0)
1973 (skip-invisible-count 0)
1855 (nonempty-match nil) 1974 (nonempty-match nil)
1856 (multi-buffer nil) 1975 (multi-buffer nil)
1857 (recenter-last-op nil) ; Start cycling order with initial position. 1976 (recenter-last-op nil) ; Start cycling order with initial position.
@@ -1905,62 +2024,40 @@ make, or the user didn't cancel the call."
1905 ;; Loop finding occurrences that perhaps should be replaced. 2024 ;; Loop finding occurrences that perhaps should be replaced.
1906 (while (and keep-going 2025 (while (and keep-going
1907 (not (or (eobp) (and limit (>= (point) limit)))) 2026 (not (or (eobp) (and limit (>= (point) limit))))
1908 ;; Let-bind global isearch-* variables to values used 2027 ;; Use the next match if it is already known;
1909 ;; to search the next replacement. These let-bindings 2028 ;; otherwise, search for a match after moving forward
1910 ;; should be effective both at the time of calling 2029 ;; one char if progress is required.
1911 ;; `isearch-search-fun-default' and also at the 2030 (setq real-match-data
1912 ;; time of funcalling `search-function'. 2031 (cond ((consp match-again)
1913 ;; These isearch-* bindings can't be placed higher 2032 (goto-char (nth 1 match-again))
1914 ;; outside of this loop because then another I-search 2033 (replace-match-data
1915 ;; used after `recursive-edit' might override them. 2034 t real-match-data match-again))
1916 (let* ((isearch-regexp regexp-flag) 2035 ;; MATCH-AGAIN non-nil means accept an
1917 (isearch-word delimited-flag) 2036 ;; adjacent match.
1918 (isearch-lax-whitespace 2037 (match-again
1919 replace-lax-whitespace) 2038 (and
1920 (isearch-regexp-lax-whitespace 2039 (replace-search search-string limit
1921 replace-regexp-lax-whitespace) 2040 regexp-flag delimited-flag
1922 (isearch-case-fold-search case-fold-search) 2041 case-fold-search)
1923 (isearch-adjusted nil) 2042 ;; For speed, use only integers and
1924 (isearch-nonincremental t) ; don't use lax word mode 2043 ;; reuse the list used last time.
1925 (isearch-forward t) 2044 (replace-match-data t real-match-data)))
1926 (search-function 2045 ((and (< (1+ (point)) (point-max))
1927 (or (if regexp-flag 2046 (or (null limit)
1928 replace-re-search-function 2047 (< (1+ (point)) limit)))
1929 replace-search-function) 2048 ;; If not accepting adjacent matches,
1930 (isearch-search-fun-default)))) 2049 ;; move one char to the right before
1931 ;; Use the next match if it is already known; 2050 ;; searching again. Undo the motion
1932 ;; otherwise, search for a match after moving forward 2051 ;; if the search fails.
1933 ;; one char if progress is required. 2052 (let ((opoint (point)))
1934 (setq real-match-data 2053 (forward-char 1)
1935 (cond ((consp match-again) 2054 (if (replace-search search-string limit
1936 (goto-char (nth 1 match-again)) 2055 regexp-flag delimited-flag
1937 (replace-match-data 2056 case-fold-search)
1938 t real-match-data match-again)) 2057 (replace-match-data
1939 ;; MATCH-AGAIN non-nil means accept an 2058 t real-match-data)
1940 ;; adjacent match. 2059 (goto-char opoint)
1941 (match-again 2060 nil))))))
1942 (and
1943 (funcall search-function search-string
1944 limit t)
1945 ;; For speed, use only integers and
1946 ;; reuse the list used last time.
1947 (replace-match-data t real-match-data)))
1948 ((and (< (1+ (point)) (point-max))
1949 (or (null limit)
1950 (< (1+ (point)) limit)))
1951 ;; If not accepting adjacent matches,
1952 ;; move one char to the right before
1953 ;; searching again. Undo the motion
1954 ;; if the search fails.
1955 (let ((opoint (point)))
1956 (forward-char 1)
1957 (if (funcall
1958 search-function search-string
1959 limit t)
1960 (replace-match-data
1961 t real-match-data)
1962 (goto-char opoint)
1963 nil)))))))
1964 2061
1965 ;; Record whether the match is nonempty, to avoid an infinite loop 2062 ;; Record whether the match is nonempty, to avoid an infinite loop
1966 ;; repeatedly matching the same empty string. 2063 ;; repeatedly matching the same empty string.
@@ -1982,12 +2079,27 @@ make, or the user didn't cancel the call."
1982 (and (/= (nth 0 match) (nth 1 match)) 2079 (and (/= (nth 0 match) (nth 1 match))
1983 match)))))) 2080 match))))))
1984 2081
1985 ;; Optionally ignore matches that have a read-only property. 2082 (cond
1986 (unless (and query-replace-skip-read-only 2083 ;; Optionally ignore matches that have a read-only property.
1987 (text-property-not-all 2084 ((not (or (not query-replace-skip-read-only)
1988 (nth 0 real-match-data) (nth 1 real-match-data) 2085 (not (text-property-not-all
1989 'read-only nil)) 2086 (nth 0 real-match-data) (nth 1 real-match-data)
1990 2087 'read-only nil))))
2088 (setq skip-read-only-count (1+ skip-read-only-count)))
2089 ;; Optionally filter out matches.
2090 ((not (run-hook-with-args-until-failure
2091 'isearch-filter-predicates
2092 (nth 0 real-match-data) (nth 1 real-match-data)))
2093 (setq skip-filtered-count (1+ skip-filtered-count)))
2094 ;; Optionally ignore invisible matches.
2095 ((not (or (eq search-invisible t)
2096 ;; Don't open overlays for automatic replacements.
2097 (and (not query-flag) search-invisible)
2098 ;; Open hidden overlays for interactive replacements.
2099 (not (isearch-range-invisible
2100 (nth 0 real-match-data) (nth 1 real-match-data)))))
2101 (setq skip-invisible-count (1+ skip-invisible-count)))
2102 (t
1991 ;; Calculate the replacement string, if necessary. 2103 ;; Calculate the replacement string, if necessary.
1992 (when replacements 2104 (when replacements
1993 (set-match-data real-match-data) 2105 (set-match-data real-match-data)
@@ -2192,45 +2304,31 @@ make, or the user didn't cancel the call."
2192 (match-end 0) 2304 (match-end 0)
2193 (current-buffer)) 2305 (current-buffer))
2194 (match-data t))) 2306 (match-data t)))
2195 stack))))) 2307 stack))))))
2196 2308
2197 (replace-dehighlight)) 2309 (replace-dehighlight))
2198 (or unread-command-events 2310 (or unread-command-events
2199 (message "Replaced %d occurrence%s" 2311 (message "Replaced %d occurrence%s%s"
2200 replace-count 2312 replace-count
2201 (if (= replace-count 1) "" "s"))) 2313 (if (= replace-count 1) "" "s")
2314 (if (> (+ skip-read-only-count
2315 skip-filtered-count
2316 skip-invisible-count) 0)
2317 (format " (skipped %s)"
2318 (mapconcat
2319 'identity
2320 (delq nil (list
2321 (if (> skip-read-only-count 0)
2322 (format "%s read-only"
2323 skip-read-only-count))
2324 (if (> skip-invisible-count 0)
2325 (format "%s invisible"
2326 skip-invisible-count))
2327 (if (> skip-filtered-count 0)
2328 (format "%s filtered out"
2329 skip-filtered-count))))
2330 ", "))
2331 "")))
2202 (or (and keep-going stack) multi-buffer))) 2332 (or (and keep-going stack) multi-buffer)))
2203 2333
2204(defvar replace-overlay nil)
2205
2206(defun replace-highlight (match-beg match-end range-beg range-end
2207 search-string regexp-flag delimited-flag
2208 case-fold-search)
2209 (if query-replace-highlight
2210 (if replace-overlay
2211 (move-overlay replace-overlay match-beg match-end (current-buffer))
2212 (setq replace-overlay (make-overlay match-beg match-end))
2213 (overlay-put replace-overlay 'priority 1001) ;higher than lazy overlays
2214 (overlay-put replace-overlay 'face 'query-replace)))
2215 (if query-replace-lazy-highlight
2216 (let ((isearch-string search-string)
2217 (isearch-regexp regexp-flag)
2218 (isearch-word delimited-flag)
2219 (isearch-lax-whitespace
2220 replace-lax-whitespace)
2221 (isearch-regexp-lax-whitespace
2222 replace-regexp-lax-whitespace)
2223 (isearch-case-fold-search case-fold-search)
2224 (isearch-forward t)
2225 (isearch-other-end match-beg)
2226 (isearch-error nil))
2227 (isearch-lazy-highlight-new-loop range-beg range-end))))
2228
2229(defun replace-dehighlight ()
2230 (when replace-overlay
2231 (delete-overlay replace-overlay))
2232 (when query-replace-lazy-highlight
2233 (lazy-highlight-cleanup lazy-highlight-cleanup)
2234 (setq isearch-lazy-highlight-last-string nil)))
2235
2236;;; replace.el ends here 2334;;; replace.el ends here