From: Okam via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
To: 49120@debbugs.gnu.org
Subject: bug#49120: [PATCH] Add commands 'kill-lines' and 'copy-lines'
Date: Sat, 19 Jun 2021 17:12:25 +0000 [thread overview]
Message-ID: <337118f4-d1a2-ec51-fb29-a933a3cac785@protonmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 420 bytes --]
These commands work similarly to the 'flush-lines' command, but add the
lines to the kill ring as a single item.
For example, when working with text lists, such as in
- Documentation: Do thing 1
- Source: Add new function
- Documentation: Do thing 2
if one wanted to copy only the lines containing "Documentation", while
leaving the buffer untouched, the 'copy-lines' command could be used.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-commands-kill-lines-and-copy-lines.patch --]
[-- Type: text/x-patch; name=0001-Add-commands-kill-lines-and-copy-lines.patch, Size: 7761 bytes --]
>From b35c21cdb2d3c051bd374bcd2f9e3fe16ffb9380 Mon Sep 17 00:00:00 2001
From: Earl Hyatt <okamsn@protonmail.com>
Date: Sat, 19 Jun 2021 08:30:31 -0400
Subject: [PATCH] Add commands 'kill-lines' and 'copy-lines'
* doc/emacs/search.texi: Document these additions.
* lisp/replace.el: Add the commands 'kill-lines' and 'copy-lines'.
'kill-lines' (alias 'kill-matching-lines') is like 'flush-lines',
but adds the lines to the kill ring as a single item.
'copy-lines' (alias 'copy-matching-lines') is like 'kill-lines',
but only copies those lines instead of killing them.
---
doc/emacs/search.texi | 10 ++++
etc/NEWS | 4 ++
lisp/replace.el | 130 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 144 insertions(+)
diff --git a/doc/emacs/search.texi b/doc/emacs/search.texi
index e6b066e973..2ddb44c310 100644
--- a/doc/emacs/search.texi
+++ b/doc/emacs/search.texi
@@ -1971,6 +1971,16 @@ Other Repeating Search
(a newline that ends a line counts as part of that line).
If a match is split across lines, this command keeps all those lines.
+
+@findex kill-lines
+@item M-x kill-lines
+Like @code{flush-lines}, but also add the matching lines to the kill
+ring as a single item.
+
+@findex copy-lines
+@item M-x copy-lines
+Like @code{kill-lines}, but the matching lines are not removed from
+the buffer.
@end table
@node Search Customizations
diff --git a/etc/NEWS b/etc/NEWS
index 1693342f0a..42210315b6 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -461,6 +461,10 @@ highlighting on heading lines using standard outline faces. This
works well only when there are no conflicts with faces used by the
major mode.
+** New commands 'copy-lines' and 'kill-lines'.
+These commands are similar to the command 'flush-lines',
+but add the matching lines to the kill ring as a single item.
+
\f
* Changes in Specialized Modes and Packages in Emacs 28.1
diff --git a/lisp/replace.el b/lisp/replace.el
index fe2cbc447a..edbd85f2b3 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -912,6 +912,8 @@ read-regexp
(defalias 'delete-non-matching-lines 'keep-lines)
(defalias 'delete-matching-lines 'flush-lines)
+(defalias 'kill-matching-lines 'kill-lines)
+(defalias 'copy-matching-lines 'copy-lines)
(defalias 'count-matches 'how-many)
(defun keep-lines-read-args (prompt)
@@ -1054,6 +1056,134 @@ flush-lines
count))
count))
+(defun kill-lines (regexp &optional rstart rend interactive)
+ "Kill lines containing matches for REGEXP.
+
+When called from Lisp (and usually when called interactively as
+well, see below), applies to the part of the buffer after point.
+The line point is in is killed if and only if it contains a match
+for regexp starting after point.
+
+If REGEXP contains upper case characters (excluding those
+preceded by `\\') and `search-upper-case' is non-nil, the
+matching is case-sensitive.
+
+Second and third arg RSTART and REND specify the region to
+operate on. Lines partially contained in this region are killed
+if and only if they contain a match entirely contained in it.
+
+Interactively, in Transient Mark mode when the mark is active,
+operate on the contents of the region. Otherwise, operate from
+point to the end of (the accessible portion of) the buffer. When
+calling this function from Lisp, you can pretend that it was
+called interactively by passing a non-nil INTERACTIVE argument.
+
+If a match is split across lines, all the lines it lies in are
+killed. They are killed _before_ looking for the next match.
+Hence, a match starting on the same line at which another match
+ended is ignored.
+
+Return the number of killed matching lines. When called
+interactively, also print the number."
+ (interactive
+ (progn
+ (barf-if-buffer-read-only)
+ (keep-lines-read-args "Kill lines containing match for regexp")))
+ (if rstart
+ (progn
+ (goto-char (min rstart rend))
+ (setq rend (copy-marker (max rstart rend))))
+ (if (and interactive (use-region-p))
+ (setq rstart (region-beginning)
+ rend (copy-marker (region-end)))
+ (setq rstart (point)
+ rend (point-max-marker)))
+ (goto-char rstart))
+ (let ((count 0)
+ (case-fold-search
+ (if (and case-fold-search search-upper-case)
+ (isearch-no-upper-case-p regexp t)
+ case-fold-search)))
+ (save-excursion
+ (while (and (< (point) rend)
+ (re-search-forward regexp rend t))
+ (unless (zerop count)
+ (setq last-command 'kill-region))
+ (kill-region (save-excursion (goto-char (match-beginning 0))
+ (forward-line 0)
+ (point))
+ (progn (forward-line 1) (point)))
+ (setq count (1+ count))))
+ (set-marker rend nil)
+ (when interactive (message (ngettext "Killed %d matching line"
+ "Killed %d matching lines"
+ count)
+ count))
+ count))
+
+(defun copy-lines (regexp &optional rstart rend interactive)
+ "Copy lines containing matches for REGEXP to the kill ring.
+
+When called from Lisp (and usually when called interactively as
+well, see below), applies to the part of the buffer after point.
+The line point is in is copied if and only if it contains a match
+for regexp starting after point.
+
+If REGEXP contains upper case characters (excluding those
+preceded by `\\') and `search-upper-case' is non-nil, the
+matching is case-sensitive.
+
+Second and third arg RSTART and REND specify the region to
+operate on. Lines partially contained in this region are copied
+if and only if they contain a match entirely contained in it.
+
+Interactively, in Transient Mark mode when the mark is active,
+operate on the contents of the region. Otherwise, operate from
+point to the end of (the accessible portion of) the buffer. When
+calling this function from Lisp, you can pretend that it was
+called interactively by passing a non-nil INTERACTIVE argument.
+
+If a match is split across lines, all the lines it lies in are
+copied.
+
+Return the number of copied matching lines. When called
+interactively, also print the number."
+ (interactive
+ (progn
+ (barf-if-buffer-read-only)
+ (keep-lines-read-args "Copy lines containing match for regexp")))
+ (if rstart
+ (progn
+ (goto-char (min rstart rend))
+ (setq rend (copy-marker (max rstart rend))))
+ (if (and interactive (use-region-p))
+ (setq rstart (region-beginning)
+ rend (copy-marker (region-end)))
+ (setq rstart (point)
+ rend (point-max-marker)))
+ (goto-char rstart))
+ (let ((count 0)
+ (case-fold-search
+ (if (and case-fold-search search-upper-case)
+ (isearch-no-upper-case-p regexp t)
+ case-fold-search)))
+ (save-excursion
+ (while (and (< (point) rend)
+ (re-search-forward regexp rend t))
+ (unless (zerop count)
+ (setq last-command 'kill-region))
+ (copy-region-as-kill (save-excursion (goto-char (match-beginning 0))
+ (forward-line 0)
+ (point))
+ (progn (forward-line 1) (point)))
+ (setq count (1+ count))))
+ (set-marker rend nil)
+ (when interactive (message (ngettext "Copied %d matching line"
+ "Copied %d matching lines"
+ count)
+ count))
+ count))
+
(defun how-many (regexp &optional rstart rend interactive)
"Print and return number of matches for REGEXP following point.
When called from Lisp and INTERACTIVE is omitted or nil, just return
--
2.25.1
next reply other threads:[~2021-06-19 17:12 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-06-19 17:12 Okam via Bug reports for GNU Emacs, the Swiss army knife of text editors [this message]
2021-06-19 17:33 ` bug#49120: [PATCH] Add commands 'kill-lines' and 'copy-lines' Eli Zaretskii
2021-07-01 23:50 ` Okam via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-07-03 7:07 ` Eli Zaretskii
2021-07-20 12:10 ` Lars Ingebrigtsen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=337118f4-d1a2-ec51-fb29-a933a3cac785@protonmail.com \
--to=bug-gnu-emacs@gnu.org \
--cc=49120@debbugs.gnu.org \
--cc=okamsn@protonmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.