33

Suppose that I have already selected some text in the current buffer. Is it possible to select another stretch of text, while keeping the previous selection (and so on)?

Added: One motivation for this functionality is as follows: Assume that I have some text that looks like this:

paragraph 1 ...

paragraph 2 ...

paragraph 3 ...

paragraph 4 ...

paragraph 5 ...

I would like to remove some paragraphs (e.g. 2, 4 and 6) and insert them before paragraph 1.

itsjeyd
  • 14,586
  • 3
  • 58
  • 87
Name
  • 7,689
  • 4
  • 38
  • 84
  • 1
    There's a [secondary](http://www.emacswiki.org/emacs/SecondarySelection) [selection](https://www.gnu.org/software/emacs/manual/html_node/emacs/Secondary-Selection.html#Secondary-Selection). – wasamasa May 07 '15 at 12:59
  • 2
    There is a package multiselect: http://www.skamphausen.de/cgi-bin/ska/multiselect It looks a bit like a fast hack. – Tobias May 07 '15 at 13:08
  • Depending on the size of what you're selecting and why, `multiple-cursors` may give you a solution. – Jordon Biondo May 07 '15 at 13:09
  • @wasamasa I followed the instruction given in the link you provided. After the first selection, I selected the second region my keeping the Meta key. It was selected, but there are two problems: (1) the second selection seems to be not a real selection, as copying or deleting do not work. (2) it is not possible to select a third selection by this way. – Name May 07 '15 at 13:17
  • copy and delete does work: To paste from the secondary selection click middle mouse button with Alt-key pressed. To kill text in the secondary selection double-klick right mouse button with Alt pressed. – Tobias May 07 '15 at 13:23
  • @Name There are a few dedicated commands for the secondary selection involving the Meta key and yes, it's a second selection, not a third or whatever else you were thinking of. – wasamasa May 07 '15 at 13:26
  • @Tobias If you wish, consider to convert your comment to an answer, since it is as useful as the answers already provided. – Name May 07 '15 at 14:26
  • @JordonBiondo Is it possible to elaborate more? A complete solution using your idea of using `multiple-cursors` would be helpful. – Name May 07 '15 at 14:29
  • 1
    The Emacs Wiki has a good section about the [secondary selection](http://www.emacswiki.org/emacs/SecondarySelection). Various enhancements make it more usable from the keyboard, for instance. – Drew May 07 '15 at 15:35
  • On the page http://www.emacswiki.org/emacs/ApplyFunctionOnMultipleRegions you find `multi-select.el` and `multi-region.el`. I have not tested it yet. But, it looks promising. Futhermore, I have proposed some bugfixes for `multiselect.el` to Stefan Kamphausen (regarding regions in separate buffers and killed buffers). Don't know whether and when he will incorperate them into the package. – Tobias May 08 '15 at 07:48

8 Answers8

45

You can use append-next-kill (bound to C-M-w by default) to accumulate the text you want to insert above paragraph 1:

  1. Kill paragraph 2 as you normally would.

  2. Mark paragraph 4 and press C-M-w before killing it. Repeat this step for all paragraphs you'd like to move before paragraph 1.

When you're done, you can yank the accumulated text before paragraph 1.

itsjeyd
  • 14,586
  • 3
  • 58
  • 87
  • 5
    Even with the basic stuff, there's always some new things to learn! This is pretty useful, as I usually waste a lot of key pressing by travelling the kill ring when I need to do this. Wish I could upvote this some more... – Meaningful Username May 08 '15 at 07:48
11

You can use registers combined with the mark ring. Push the current marks with C-<SPC> C-<SPC>, recover them later with C-u C-<SPC>, or save them in a register, say b, via C-x r <SPC> b, and jump back later with C-x r j b.

Now mark another region. C-u C-x r s a will copy the marked region to register a and delete the text. Then mark the next region and C-u C-x r + a will append another selection to that register a and delete it.

You can then insert the contents with C-x r i a.

See the "Saving Text in Registers" section of the Emacs manual.

Andrew Swann
  • 3,436
  • 2
  • 15
  • 43
6

The new rectangle-region support in Emacs-24.4 actually introduced (a big part of) the infrastructure needed for this functionality [ after all, a rectangular region is a non-contiguous region].

So, it should be possible now to implement a "split-region" package which provides just the functionality you're asking for.

Admittedly, lots of Emacs commands still haven't been adapted to use the new infrastructure (e.g. commands like upcase-region, or undo-in-region, query-replace, ...) and hence don't work properly on rectangles yet (so they wouldn't work properly on a "split-region" either), but these are bugs which should hopefully get fixed over time.

Stefan
  • 26,154
  • 3
  • 46
  • 84
5

This responds to your general question, but not particularly to the use case you mention (moving bits of code around).

Emacs now has what it calls a noncontiguous region, which is the kind of selection that you are asking about. Vanilla Emacs does not provide any special way to create a noncontiguous region, except if it is a rectangle. But library Zones does.

Library Zones lets you define multiple zones in your buffer. A list of zones is a noncontiguous region. You can also think of it as multiple regions, depending on how you want to make use of it. You can have multiple zone lists defined at any time, each assigned to a different zones variable, and you can switch among them.

If you also use library Bookmark+ then you can save lists of zones persistently and restore them in later Emacs sessions. Bookmark+ also lets you assign arbitrary tags to a bookmark. This means that you can tag a list of zones.

The zones in a given zone list are typically in the same buffer, but they need not be. In this, a zone list is more general than a noncontiguous region. It is also more general in that each zone can contain additional information, besides just the zone limits, and it can have an identifier.

There are several ways to create a zone. One of the easiest is to use C-x n a: it defines a zone from the active region, and adds it to the current zone set. (C-x n n (narrow-to-region) also does this, in addition to narrowing.)

These are some of the things you can do with a set (list) of zones:

  • Sort them.
  • Unite (coalesce) adjacent or overlapping zones (which includes sorting them).
  • Intersect them.
  • Narrow the buffer to a zone in the list. Cycle among narrowings. See Multiple Narrowings.
  • Select a zone in the list as the active region. Cycle among regions.
  • Search them (they are automatically united first). For this you need library Isearch+.
  • Query-replace over them.
  • Highlight and unhighlight them. (For this you need library Highlight or library facemenu+.el.

See also Narrow Indirect, which lets you create indirect buffers that are clones of a given buffer and that are narrowed to different portions of it.

Drew
  • 75,699
  • 9
  • 109
  • 225
  • @alinsoar: Use `zz-add-zone` multiple times. That adds zones to the current zones variable (`zz-zones`, by default). If you want an ordinary Emacs noncontig region from a zones variable (set of zones), use `zz-noncontiguous-region-from-izones`, passing the value of the zones variable. – Drew Oct 21 '20 at 17:12
  • @alinsoar: That doesn't really mean anything. Yes, you can highlight all zones in a zone set, in various ways. And you can pass what Emacs calls a "noncontinuous region" (e.g. resulting as above) to any function that accepts one as arg (e.g. `occur` and any of the replacement functions/commands). And zones.el provides additional query-replace commands for use with a zones set (which is more general than a noncontiguous region, which is essentially a coalesced set of zones). – Drew Oct 21 '20 at 21:27
  • Sorry, but I don't understand your comments. And I get the impression you are looking for something else. – Drew Oct 22 '20 at 17:32
4

Install browse-kill-ring.el

copy-and-kill all regions of interest.

Got to point where re-insert should start.

M-x browse-kill-ring RET will open a buffer and place cursor in it.

Type n to travel chunks.

RET there will insert the chunk at point in original/other buffer.

Andreas Röhler
  • 1,894
  • 10
  • 10
3

If the lines you want to manipulate can be distinguished via a regex match, you can use occur-mode to view them in a new window. You can then use occur-edit-mode to edit them, with the original buffer reflecting the changes that you make in the Occur buffer.

This works wonderfully, for example, in combination with multiple-cursors-mode: because the lines you've selected to appear in the Occur buffer are displayed contiguously regardless of how far they are in the original buffer, you can mark all of them or a subset and then activate mc/edit-lines and edit them all at once. (Yes, I know that multiple-cursors can do this all by itself with mc/mark-all-like-this, but it's nice to have options.)

Any other editing operation that would be more easily done if you were seeing only the lines you wanted to work on, such as setting up a complicated regex search and replace, or a macro that needs to run on each line of a buffer in turn, can also be done this way.

3

Another way is to use the objed package (I'm the author). You can mark any text object with m the point is moved to the next object of current type automatically. Unmark any object by navigating to it and press m again. Here is an example screencast (shows marking lines but works for other objects like paragraphs, defuns... as well):

enter image description here

clemera
  • 3,401
  • 13
  • 40
  • When I try to install this package from Melpa I get the error `package-install-from-archive: http://melpa.milkbox.net/packages/objed-20181201.1346.tar: Not found`. – Name Dec 03 '18 at 16:17
  • @Name That sounds like need to update you package list. Try `M-x package-refresh-contents` and then `M-x package-install`. – clemera Dec 03 '18 at 18:25
  • @Name Does it work now? Let me know if you have further questions. – clemera Dec 03 '18 at 22:26
  • I was able to install the package. Seems to work well, I have not tested all its features. Thank you. – Name Dec 04 '18 at 10:00
2

Another option: Transposing paragraphs

For completeness sake, you can achieve your reordering of paragraphs (sequentially) with marked regions and M-0 M-x transpose-paragraph (the zero argument makes tra-par swap the paragraphs where point and mark are in, i.e. the region begins and ends)!

By the way this works for all transpose-.* commands (-words, -sexp, -sentences, ...) and is extremely handy in many situations.

Dieter.Wilhelm
  • 1,836
  • 14
  • 25