unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* [PATCH] New command to invert lines in region
@ 2016-10-03 10:43 Tino Calancha
  2016-10-03 11:02 ` Kaushal Modi
  0 siblings, 1 reply; 10+ messages in thread
From: Tino Calancha @ 2016-10-03 10:43 UTC (permalink / raw)
  To: Emacs developers; +Cc: tino.calancha


Hello Emacs,

i cannot find a command to invert the lines within a region.
Does such thing already exists? Where?
IMO, it might be good to have a command doing such thing.
For instance, let's suppose the region contains following lines:

foo 2 3
bar 8 9
baz 10 14
qux 22 28

The proposed command would change the region to:

qux 22 28
baz 10 14
bar 8 9
foo 2 3

What do you think about this idea? Does it have sense?
Feel free to make comments.
Regards,
Tino


I have prepared following patch:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
From 763e69bd0f22ae91be23cb384ec33cca0220f937 Mon Sep 17 00:00:00 2001
From: Tino Calancha <tino.calancha@gmail.com>
Date: Mon, 3 Oct 2016 19:25:18 +0900
Subject: [PATCH] invert-lines: New comman to invert lines in region

* lisp/simple.el (invert-lines): New command.
Bind to 'C-x I'.
* etc/NEWS: Add entry for this new feature.
---
  etc/NEWS       |  4 ++++
  lisp/simple.el | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
  2 files changed, 56 insertions(+)

diff --git a/etc/NEWS b/etc/NEWS
index bd94c94..d3dffc0 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -61,6 +61,10 @@ affected by this, as SGI stopped supporting IRIX in December 2013.

  * Changes in Emacs 26.1

+
+** The new command 'invert-lines' invert the lines in region.  Bound
+to 'C-x I'.
+
  +++
  ** The new function 'call-shell-region' executes a command in an
  inferior shell with the buffer region as input.
diff --git a/lisp/simple.el b/lisp/simple.el
index 70bd759..9233bf6 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -6761,6 +6761,58 @@ global-visual-line-mode
    visual-line-mode turn-on-visual-line-mode)


+(defun invert-lines (&optional buffer start end)
+  "Invert order of lines in region.
+Optional arg BUFFER (or buffer name) is the output buffer.
+ Default to current one.
+Optional arguments, START and END, define the region.
+ If START is nil, then default to minimum permissible value of point
+ in the current buffer.
+ If END is nil, then default to maximum permissible value of point
+ in the current buffer.
+With prefix argument prompt for BUFFER."
+  (interactive
+   (let ((buf (if current-prefix-arg
+                  (read-buffer "Invert lines to buffer: "
+                               (current-buffer)
+                               'must-match)
+                (current-buffer)))
+         (beg (region-beginning))
+         (end (region-end)))
+     (list buf beg end)))
+  (let ((tmp-buf (get-buffer-create
+                  (generate-new-buffer " *invert-lines*")))
+        (buf (or buffer (current-buffer)))
+        (beg-pos (or start (point-min)))
+        (end-pos (or end (point-max)))
+        (init-pos (point))
+        line)
+    (unwind-protect
+        (progn
+          (goto-char beg-pos)
+          (while (and (not (eobp))
+                      (not (>= (point) end-pos))
+                      (re-search-forward "^.*$"))
+            (setq line (match-string 0))
+            (with-current-buffer tmp-buf
+              (save-excursion
+                (insert line "\n")))
+            (forward-line 1))
+          (if (eq (get-buffer buf) (current-buffer))
+              (progn
+                (delete-region beg-pos end-pos)
+                (goto-char beg-pos)
+                (insert-buffer-substring tmp-buf))
+            (with-current-buffer tmp-buf
+              (copy-to-buffer buf (point-min) (point-max)))))
+      (kill-buffer tmp-buf)
+      (goto-char init-pos)
+      (when (region-active-p)
+        (deactivate-mark 'force)))))
+
+(define-key ctl-x-map "I" 'invert-lines)
+
+
  (defun transpose-chars (arg)
    "Interchange characters around point, moving forward one character.
  With prefix arg ARG, effect is to take character before point
-- 
2.9.3

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
In GNU Emacs 26.0.50.4 (x86_64-pc-linux-gnu, GTK+ Version 3.22.0)
  of 2016-10-03 built on calancha-pc
Repository revision: 8cd975cebd588d5435fa2b333dba6c526e602933



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH] New command to invert lines in region
  2016-10-03 10:43 [PATCH] New command to invert lines in region Tino Calancha
@ 2016-10-03 11:02 ` Kaushal Modi
  2016-10-03 11:21   ` Tino Calancha
  0 siblings, 1 reply; 10+ messages in thread
From: Kaushal Modi @ 2016-10-03 11:02 UTC (permalink / raw)
  To: Tino Calancha, Emacs developers

[-- Attachment #1: Type: text/plain, Size: 4419 bytes --]

I believe there is reverse-lines

On Mon, Oct 3, 2016, 6:43 AM Tino Calancha <tino.calancha@gmail.com> wrote:

>
> Hello Emacs,
>
> i cannot find a command to invert the lines within a region.
> Does such thing already exists? Where?
> IMO, it might be good to have a command doing such thing.
> For instance, let's suppose the region contains following lines:
>
> foo 2 3
> bar 8 9
> baz 10 14
> qux 22 28
>
> The proposed command would change the region to:
>
> qux 22 28
> baz 10 14
> bar 8 9
> foo 2 3
>
> What do you think about this idea? Does it have sense?
> Feel free to make comments.
> Regards,
> Tino
>
>
> I have prepared following patch:
>
>
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> From 763e69bd0f22ae91be23cb384ec33cca0220f937 Mon Sep 17 00:00:00 2001
> From: Tino Calancha <tino.calancha@gmail.com>
> Date: Mon, 3 Oct 2016 19:25:18 +0900
> Subject: [PATCH] invert-lines: New comman to invert lines in region
>
> * lisp/simple.el (invert-lines): New command.
> Bind to 'C-x I'.
> * etc/NEWS: Add entry for this new feature.
> ---
>   etc/NEWS       |  4 ++++
>   lisp/simple.el | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 56 insertions(+)
>
> diff --git a/etc/NEWS b/etc/NEWS
> index bd94c94..d3dffc0 100644
> --- a/etc/NEWS
> +++ b/etc/NEWS
> @@ -61,6 +61,10 @@ affected by this, as SGI stopped supporting IRIX in
> December 2013.
>
>   * Changes in Emacs 26.1
>
> +
> +** The new command 'invert-lines' invert the lines in region.  Bound
> +to 'C-x I'.
> +
>   +++
>   ** The new function 'call-shell-region' executes a command in an
>   inferior shell with the buffer region as input.
> diff --git a/lisp/simple.el b/lisp/simple.el
> index 70bd759..9233bf6 100644
> --- a/lisp/simple.el
> +++ b/lisp/simple.el
> @@ -6761,6 +6761,58 @@ global-visual-line-mode
>     visual-line-mode turn-on-visual-line-mode)
>
>
> +(defun invert-lines (&optional buffer start end)
> +  "Invert order of lines in region.
> +Optional arg BUFFER (or buffer name) is the output buffer.
> + Default to current one.
> +Optional arguments, START and END, define the region.
> + If START is nil, then default to minimum permissible value of point
> + in the current buffer.
> + If END is nil, then default to maximum permissible value of point
> + in the current buffer.
> +With prefix argument prompt for BUFFER."
> +  (interactive
> +   (let ((buf (if current-prefix-arg
> +                  (read-buffer "Invert lines to buffer: "
> +                               (current-buffer)
> +                               'must-match)
> +                (current-buffer)))
> +         (beg (region-beginning))
> +         (end (region-end)))
> +     (list buf beg end)))
> +  (let ((tmp-buf (get-buffer-create
> +                  (generate-new-buffer " *invert-lines*")))
> +        (buf (or buffer (current-buffer)))
> +        (beg-pos (or start (point-min)))
> +        (end-pos (or end (point-max)))
> +        (init-pos (point))
> +        line)
> +    (unwind-protect
> +        (progn
> +          (goto-char beg-pos)
> +          (while (and (not (eobp))
> +                      (not (>= (point) end-pos))
> +                      (re-search-forward "^.*$"))
> +            (setq line (match-string 0))
> +            (with-current-buffer tmp-buf
> +              (save-excursion
> +                (insert line "\n")))
> +            (forward-line 1))
> +          (if (eq (get-buffer buf) (current-buffer))
> +              (progn
> +                (delete-region beg-pos end-pos)
> +                (goto-char beg-pos)
> +                (insert-buffer-substring tmp-buf))
> +            (with-current-buffer tmp-buf
> +              (copy-to-buffer buf (point-min) (point-max)))))
> +      (kill-buffer tmp-buf)
> +      (goto-char init-pos)
> +      (when (region-active-p)
> +        (deactivate-mark 'force)))))
> +
> +(define-key ctl-x-map "I" 'invert-lines)
> +
> +
>   (defun transpose-chars (arg)
>     "Interchange characters around point, moving forward one character.
>   With prefix arg ARG, effect is to take character before point
> --
> 2.9.3
>
>
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> In GNU Emacs 26.0.50.4 (x86_64-pc-linux-gnu, GTK+ Version 3.22.0)
>   of 2016-10-03 built on calancha-pc
> Repository revision: 8cd975cebd588d5435fa2b333dba6c526e602933
>
> --

Kaushal Modi

[-- Attachment #2: Type: text/html, Size: 7920 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] New command to invert lines in region
  2016-10-03 11:02 ` Kaushal Modi
@ 2016-10-03 11:21   ` Tino Calancha
  2016-10-03 11:33     ` Tino Calancha
  0 siblings, 1 reply; 10+ messages in thread
From: Tino Calancha @ 2016-10-03 11:21 UTC (permalink / raw)
  To: Kaushal Modi; +Cc: Emacs developers, Tino Calancha



On Mon, 3 Oct 2016, Kaushal Modi wrote:

> 
> I believe there is reverse-lines
Indeed that was the alternative name that i was considering for the
command.  It's a good name too.
I cannot find an existent command with such name though.



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] New command to invert lines in region
  2016-10-03 11:21   ` Tino Calancha
@ 2016-10-03 11:33     ` Tino Calancha
  2016-10-15 22:25       ` Mathias Dahl
  0 siblings, 1 reply; 10+ messages in thread
From: Tino Calancha @ 2016-10-03 11:33 UTC (permalink / raw)
  To: Tino Calancha; +Cc: Emacs developers, Kaushal Modi



On Mon, 3 Oct 2016, Tino Calancha wrote:

>
>
> On Mon, 3 Oct 2016, Kaushal Modi wrote:
>
>> 
>> I believe there is reverse-lines
> Indeed that was the alternative name that i was considering for the
> command.  It's a good name too.
> I cannot find an existent command with such name though.
OK, i found it: reverse-region.  Pretty similar.
It doesn't allow writting to a different buffer than the current one.
The proposed command here allow that and save some consing.



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] New command to invert lines in region
  2016-10-03 11:33     ` Tino Calancha
@ 2016-10-15 22:25       ` Mathias Dahl
  2016-10-15 23:57         ` Kaushal Modi
                           ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Mathias Dahl @ 2016-10-15 22:25 UTC (permalink / raw)
  To: Tino Calancha; +Cc: Kaushal Modi, Emacs developers

[-- Attachment #1: Type: text/plain, Size: 1599 bytes --]

> OK, i found it: reverse-region.  Pretty similar.
> It doesn't allow writting to a different buffer than the current one.
> The proposed command here allow that and save some consing.
>

Writing the result into another buffer sounds quite arbitrary. Is it really
such a common scenario that this function should do it? Those who needs to
have the result in another buffer can easily add a few lines in the calling
code to make it so.

Out of curiosity I had a look at the current implementation of
`reverse-region' and found it quite complicated and hard to understand what
it does. I wrote my own naïve version that I think is much simpler to
understand and which seems to be as quick as the current version (I tested
on a buffer with 100 000 lines.) I have no idea on how much memory it
consumes compared to the current version though. It's so small that I am
including it here:

(defun reverse-region (beg end)
  "Reverse the order of lines in a region.
From a program takes two point or marker arguments, BEG and END."
  (interactive "r")
  (let ((lines (nreverse (split-string (buffer-substring beg end) "\n")))
        (cnt 0))
    (delete-region beg end)
    (dolist (line lines)
      ;; Try to do the right thing when the end of the region is on an
      ;; empty line, which should be a common use case.
      (unless (and (= cnt 0) (string= "" line))
        (setq cnt (1+ cnt))
        (insert line "\n")))))

If case people prefer this version and want to replace the current
implementation with it, I should have papers on file already.

/Mathias

[-- Attachment #2: Type: text/html, Size: 2422 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] New command to invert lines in region
  2016-10-15 22:25       ` Mathias Dahl
@ 2016-10-15 23:57         ` Kaushal Modi
  2016-10-16 11:03           ` Mathias Dahl
  2016-10-16 13:24         ` Noam Postavsky
  2016-10-16 18:25         ` Kalle Olavi Niemitalo
  2 siblings, 1 reply; 10+ messages in thread
From: Kaushal Modi @ 2016-10-15 23:57 UTC (permalink / raw)
  To: Mathias Dahl, Tino Calancha; +Cc: Emacs developers

[-- Attachment #1: Type: text/plain, Size: 979 bytes --]

On Sat, Oct 15, 2016, 6:25 PM Mathias Dahl <mathias.dahl@gmail.com> wrote:

>
>
> OK, i found it: reverse-region.  Pretty similar.
> It doesn't allow writting to a different buffer than the current one.
> The proposed command here allow that and save some consing.
>
>
> Writing the result into another buffer sounds quite arbitrary.
>

+1. I have never needed to save the result in a different buffer.

Is it really such a common scenario that this function should do it? Those
> who needs to have the result in another buffer can easily add a few lines
> in the calling code to make it so.
>

Exactly.

Out of curiosity I had a look at the current implementation of
> `reverse-region' and found it quite complicated and hard to understand what
> it does.
>

I don't have any for or against opinion on this (may be a slight against,
based on the "if it's not broken, why 'fix'" motto). I have been using
`reverse-region` for many years and it works just fine.
-- 

Kaushal Modi

[-- Attachment #2: Type: text/html, Size: 2898 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] New command to invert lines in region
  2016-10-15 23:57         ` Kaushal Modi
@ 2016-10-16 11:03           ` Mathias Dahl
  0 siblings, 0 replies; 10+ messages in thread
From: Mathias Dahl @ 2016-10-16 11:03 UTC (permalink / raw)
  To: Kaushal Modi; +Cc: Emacs developers, Tino Calancha

[-- Attachment #1: Type: text/plain, Size: 865 bytes --]

>
> Out of curiosity I had a look at the current implementation of
>> `reverse-region' and found it quite complicated and hard to understand what
>> it does.
>>
>
> I don't have any for or against opinion on this (may be a slight against,
> based on the "if it's not broken, why 'fix'" motto). I have been using
> `reverse-region` for many years and it works just fine.
>

Probably it works just fine, as you say. I agree there is a risk fixing
something that is not broken. I also think it is generally a good thing to
make code more readable and if code can be made more readable and at the
same time be made smaller (which often increase readability), without any
negative side effects, it is a win for maintainability of that code base,
in my opinion.

At any rate, this was just something I happened to notice and I thought it
would be fun to have a go at it.

[-- Attachment #2: Type: text/html, Size: 1594 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] New command to invert lines in region
  2016-10-15 22:25       ` Mathias Dahl
  2016-10-15 23:57         ` Kaushal Modi
@ 2016-10-16 13:24         ` Noam Postavsky
  2016-10-16 14:00           ` Eli Zaretskii
  2016-10-16 18:25         ` Kalle Olavi Niemitalo
  2 siblings, 1 reply; 10+ messages in thread
From: Noam Postavsky @ 2016-10-16 13:24 UTC (permalink / raw)
  To: Mathias Dahl; +Cc: Kaushal Modi, Emacs developers, Tino Calancha

On Sat, Oct 15, 2016 at 6:25 PM, Mathias Dahl <mathias.dahl@gmail.com> wrote:
>
> Out of curiosity I had a look at the current implementation of
> `reverse-region' and found it quite complicated and hard to understand what
> it does. I wrote my own naïve version that I think is much simpler to
> understand

It looks to me that your version is simpler mainly because you dropped
the handling of some corner cases. Having some tests to check those
would be required before replacing the implementation. Using
split-string does seem like a good idea though (probably that function
didn't exist yet when reverse-region was written).



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] New command to invert lines in region
  2016-10-16 13:24         ` Noam Postavsky
@ 2016-10-16 14:00           ` Eli Zaretskii
  0 siblings, 0 replies; 10+ messages in thread
From: Eli Zaretskii @ 2016-10-16 14:00 UTC (permalink / raw)
  To: Noam Postavsky; +Cc: kaushal.modi, emacs-devel, tino.calancha, mathias.dahl

> From: Noam Postavsky <npostavs@users.sourceforge.net>
> Date: Sun, 16 Oct 2016 09:24:25 -0400
> Cc: Kaushal Modi <kaushal.modi@gmail.com>,
> 	Emacs developers <emacs-devel@gnu.org>,
> 	Tino Calancha <tino.calancha@gmail.com>
> 
> Using split-string does seem like a good idea though

But doing so makes the Emacs footprint momentarily hold 3 different
copies of buffer text: one in the buffer, one in the string created
with buffer-string, and one more after split-string.  Right?  The
version in sort.el, OTOH, only ever keeps a single copy of that text,
plus the current line, because each line is deleted from the buffer
once it is added to the list of lines kept as strings.  So with very
large buffers, the version by Mathias will run out of memory sooner.

What I'd try is rewrite the function to move text between buffer
locations directly, without involving strings, because that should be
more efficient, as fewer objects need to be consed, and copying text
from and into buffers is more efficient in Emacs than going through a
string.



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] New command to invert lines in region
  2016-10-15 22:25       ` Mathias Dahl
  2016-10-15 23:57         ` Kaushal Modi
  2016-10-16 13:24         ` Noam Postavsky
@ 2016-10-16 18:25         ` Kalle Olavi Niemitalo
  2 siblings, 0 replies; 10+ messages in thread
From: Kalle Olavi Niemitalo @ 2016-10-16 18:25 UTC (permalink / raw)
  To: Mathias Dahl; +Cc: Kaushal Modi, Emacs developers, Tino Calancha

Mathias Dahl <mathias.dahl@gmail.com> writes:

> I wrote my own naïve version that I think is much simpler to
> understand and which seems to be as quick as the current version (I tested
> on a buffer with 100 000 lines.)

If I use point-to-register to set a marker at the beginning of
the region and another at the end of the region, then the
original version of reverse-region keeps the markers where they
are, but your version moves both markers to the beginning of the
region, because it deletes all the original lines before it
inserts anything.

It might be nice if reverse-region and sort-columns moved any
markers along with the lines.  I don't know how much that would
slow them down or whether there would be any practical use for
such a feature.



^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2016-10-16 18:25 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-03 10:43 [PATCH] New command to invert lines in region Tino Calancha
2016-10-03 11:02 ` Kaushal Modi
2016-10-03 11:21   ` Tino Calancha
2016-10-03 11:33     ` Tino Calancha
2016-10-15 22:25       ` Mathias Dahl
2016-10-15 23:57         ` Kaushal Modi
2016-10-16 11:03           ` Mathias Dahl
2016-10-16 13:24         ` Noam Postavsky
2016-10-16 14:00           ` Eli Zaretskii
2016-10-16 18:25         ` Kalle Olavi Niemitalo

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).