changeset 1069:13daf40fb997

[xemacs-hg @ 2002-10-24 14:59:22 by youngs] 2002-10-25 Scott Evans <gse@antisleep.com> * replace.el (operate-on-non-matching-lines) (operate-on-non-matching-lines): Generalized from delete-non-matching-lines and delete-matching-lines. The "operate" versions work with regions, can copy to the kill ring, and return the number of lines copied/deleted. (delete-non-matching-lines): Use operate-on-non-matching-lines. (delete-matching-lines): Use operate-on-matching-lines. (kill-non-matching-lines): New. (copy-non-matching-lines): New. (kill-matching-lines): New. (copy-matching-lines): New.
author youngs
date Thu, 24 Oct 2002 14:59:27 +0000
parents 9d75b4fe084c
children 989ddde6705d
files lisp/ChangeLog lisp/replace.el
diffstat 2 files changed, 213 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/ChangeLog	Thu Oct 24 14:19:36 2002 +0000
+++ b/lisp/ChangeLog	Thu Oct 24 14:59:27 2002 +0000
@@ -1,3 +1,17 @@
+2002-10-25  Scott Evans  <gse@antisleep.com>
+
+	* replace.el (operate-on-non-matching-lines)
+	(operate-on-non-matching-lines): Generalized from
+	delete-non-matching-lines and delete-matching-lines.  The
+	"operate" versions work with regions, can copy to the kill ring,
+	and return the number of lines copied/deleted.
+	(delete-non-matching-lines): Use operate-on-non-matching-lines.
+	(delete-matching-lines): Use operate-on-matching-lines.
+	(kill-non-matching-lines): New.
+	(copy-non-matching-lines): New.
+	(kill-matching-lines): New.
+	(copy-matching-lines): New.
+
 2002-10-24  Andy Piper  <andy@xemacs.org>
 
 	* dialog.el (make-dialog-box): for general dialogs only
--- a/lisp/replace.el	Thu Oct 24 14:19:36 2002 +0000
+++ b/lisp/replace.el	Thu Oct 24 14:59:27 2002 +0000
@@ -212,53 +212,220 @@
   (perform-replace regexp to-string nil t delimited))
 
 
+
+;; gse wonders: Is there a better place for this to go?  Might other packages
+;; want to use it?
 (defvar regexp-history nil
   "History list for some commands that read regular expressions.")
 
+(defun operate-on-non-matching-lines (regexp delete kill &optional beg end)
+  "Internal function used by delete-non-matching-lines,
+kill-non-matching-lines, and copy-matching-lines.
+
+REGEXP is a regular expression to *not* match when performing
+operations.
+
+If DELETE is non-nil, the lines of text are deleted.  It doesn't make
+sense to set this to nil if KILL is nil -- nothing will happen.
+
+If KILL is non-nil, the lines of text are stored in the kill ring (as
+one block of text).
+
+BEG and END, if non-nil, specify the start and end locations to work
+within.  If these are nil, point and point-max are used.
+
+A match split across lines preserves all the lines it lies in.
+Applies to all lines after point.
+
+Returns the number of lines matched."
+  (with-search-caps-disable-folding regexp t
+    (save-excursion
+      ;; Move to a beginning point if specified.
+      (when beg (goto-char beg))
+      ;; Always start on the beginning of a line.
+      (or (bolp) (forward-line 1))
+
+      (let ((matched-text nil)
+            (curmatch-start (point))
+            (limit (copy-marker (point-max))))
+        ;; Limit search if limits were specified.
+        (when end (setq limit (copy-marker end)))
+
+        ;; Search.  Stop if we are at end of buffer or outside the
+        ;; limit.
+	(while (not (or
+                     (eobp)
+                     (and limit (>= (point) limit))))
+	  ;; curmatch-start is first char not preserved by previous match.
+	  (if (not (re-search-forward regexp limit 'move))
+              (let ((curmatch-end limit))
+                (setq matched-text (concat matched-text (buffer-substring curmatch-start curmatch-end)))
+                (if delete (delete-region curmatch-start curmatch-end)))
+	    (let ((curmatch-end (save-excursion (goto-char (match-beginning 0))
+				       (beginning-of-line)
+				       (point))))
+	      ;; Now curmatch-end is first char preserved by the new match.
+	      (if (< curmatch-start curmatch-end)
+                  (progn
+                    (setq matched-text (concat matched-text (buffer-substring curmatch-start curmatch-end)))
+                    (if delete (delete-region curmatch-start curmatch-end))))))
+	  (setq curmatch-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))
+	       (forward-char 1)))
+
+        ;; If any lines were matched and KILL is non-nil, insert the
+        ;; matched lines into the kill ring.
+        (if (and matched-text kill) (kill-new matched-text))
+
+        ;; Return the number of matched lines.
+        (with-temp-buffer
+          ;; Use concat to make a string even if matched-text is nil.
+          (insert (concat matched-text))
+          (count-lines (point-min) (point-max)))
+        ))))
+
 (define-function 'keep-lines 'delete-non-matching-lines)
 (defun delete-non-matching-lines (regexp)
-  "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."
+  "Delete lines that do not match REGEXP, from point to the end of the
+buffer (or within the region, if it is active)."
   (interactive (list (read-from-minibuffer
 		      "Keep lines (containing match for regexp): "
 		      nil nil nil 'regexp-history)))
-  (with-interactive-search-caps-disable-folding regexp t
+  (let ((beg nil)
+        (end nil)
+        (count nil))
+    (when (region-active-p)
+      (setq beg (region-beginning))
+      (setq end (region-end)))
+    (setq count (operate-on-non-matching-lines regexp t nil beg end))
+    (message "%i lines deleted" count)))
+
+(defun kill-non-matching-lines (regexp)
+  "Delete the lines that do not match REGEXP, from point to the end of
+the buffer (or within the region, if it is active).  The deleted lines
+are placed in the kill ring as one block of text."
+  (interactive (list (read-from-minibuffer
+		      "Kill non-matching lines (regexp): "
+		      nil nil nil 'regexp-history)))
+  (let ((beg nil)
+        (end nil)
+        (count nil))
+    (when (region-active-p)
+      (setq beg (region-beginning))
+      (setq end (region-end)))
+    (setq count (operate-on-non-matching-lines regexp t t beg end))
+    (message "%i lines killed" count)))
+
+(defun copy-non-matching-lines (regexp)
+  "Find all lines that do not match REGEXP from point to the end of the
+buffer (or within the region, if it is active), and place them in the
+kill ring as one block of text."
+  (interactive (list (read-from-minibuffer
+		      "Copy non-matching lines (regexp): "
+		      nil nil nil 'regexp-history)))
+  (let ((beg nil)
+        (end nil)
+        (count nil))
+    (when (region-active-p)
+      (setq beg (region-beginning))
+      (setq end (region-end)))
+    (setq count (operate-on-non-matching-lines regexp nil t beg end))
+    (message "%i lines copied" count)))
+
+(defun operate-on-matching-lines (regexp delete kill &optional beg end)
+  "Internal function used by delete-matching-lines, kill-matching-lines,
+and copy-matching-lines.
+
+If DELETE is non-nil, the lines of text are deleted.  It doesn't make
+sense to set this to nil if KILL is nil -- nothing will happen.
+
+If KILL is non-nil, the lines of text are stored in the kill ring (as
+one block of text).
+
+BEG and END, if non-nil, specify the start and end locations to work
+within.  If these are nil, point and point-max are used.
+
+If a match is split across lines, all the lines it lies in are deleted.
+Applies to lines after point.
+Returns the number of lines matched."
+  (with-search-caps-disable-folding regexp t
     (save-excursion
-      (or (bolp) (forward-line 1))
-      (let ((start (point)))
-	(while (not (eobp))
-	  ;; Start is first char not preserved by previous match.
-	  (if (not (re-search-forward regexp nil 'move))
-	      (delete-region start (point-max))
-	    (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)))
-	  ;; If the match was empty, avoid matching again at same place.
-	  (and (not (eobp)) (= (match-beginning 0) (match-end 0))
-	       (forward-char 1)))))))
+      (let ((matched-text nil)
+            (curmatch-start nil)
+            (curmatch-end nil)
+            (limit nil))
+
+        ;; Limit search if limits were specified.
+        (when beg (goto-char beg))
+        (when end (setq limit (copy-marker end)))
+
+        (while (and (not (eobp))
+                    (re-search-forward regexp limit t))
+          (setq curmatch-start (save-excursion (goto-char (match-beginning 0))
+                                               (beginning-of-line)
+                                               (point)))
+          (setq curmatch-end (progn (forward-line 1) (point)))
+          (setq matched-text (concat matched-text (buffer-substring curmatch-start curmatch-end)))
+          (if delete (delete-region curmatch-start curmatch-end)))
+
+        (if (and matched-text kill) (kill-new matched-text))
+
+        ;; Return the number of matched lines.
+        (with-temp-buffer
+          ;; Use concat to make a string even if matched-text is nil.
+          (insert (concat matched-text))
+          (count-lines (point-min) (point-max)))
+        ))))
 
 (define-function 'flush-lines 'delete-matching-lines)
 (defun delete-matching-lines (regexp)
-  "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."
+  "Delete the lines that match REGEXP, from point to the end of the
+buffer (or within the region, if it is active)."
   (interactive (list (read-from-minibuffer
 		      "Flush lines (containing match for regexp): "
 		      nil nil nil 'regexp-history)))
-  (with-interactive-search-caps-disable-folding regexp t
-    (save-excursion
-      (while (and (not (eobp))
-		  (re-search-forward regexp nil t))
-	(delete-region (save-excursion (goto-char (match-beginning 0))
-				       (beginning-of-line)
-				       (point))
-		       (progn (forward-line 1) (point)))))))
+  (let ((beg nil)
+        (end nil)
+        (count nil))
+    (when (region-active-p)
+      (setq beg (region-beginning))
+      (setq end (region-end)))
+    (setq count (operate-on-matching-lines regexp t nil beg end))
+    (message "%i lines deleted" count)))
+
+(defun kill-matching-lines (regexp)
+  "Delete the lines that match REGEXP, from point to the end of the
+buffer (or within the region, if it is active).  The deleted lines are
+placed in the kill ring as one block of text."
+  (interactive (list (read-from-minibuffer
+		      "Kill lines (containing match for regexp): "
+		      nil nil nil 'regexp-history)))
+  (let ((beg nil)
+        (end nil)
+        (count nil))
+    (when (region-active-p)
+      (setq beg (region-beginning))
+      (setq end (region-end)))
+    (setq count (operate-on-matching-lines regexp t t beg end))
+    (message "%i lines killed" count)))
+
+(defun copy-matching-lines (regexp)
+  "Find all lines that match REGEXP from point to the end of the
+buffer (or within the region, if it is active), and place them in the
+kill ring as one block of text."
+  (interactive (list (read-from-minibuffer
+		      "Copy lines (containing match for regexp): "
+		      nil nil nil 'regexp-history)))
+  (let ((beg nil)
+        (end nil)
+        (count nil))
+    (when (region-active-p)
+      (setq beg (region-beginning))
+      (setq end (region-end)))
+    (setq count (operate-on-matching-lines regexp nil t beg end))
+    (message "%i lines copied" count)))
 
 (define-function 'how-many 'count-matches)
 (defun count-matches (regexp)