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.

10
  • 1
    There's a secondary selection.
    – wasamasa
    May 7, 2015 at 12:59
  • 2
    There is a package multiselect: skamphausen.de/cgi-bin/ska/multiselect It looks a bit like a fast hack.
    – Tobias
    May 7, 2015 at 13:08
  • Depending on the size of what you're selecting and why, multiple-cursors may give you a solution. May 7, 2015 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 7, 2015 at 13:17
  • 1
    The Emacs Wiki has a good section about the secondary selection. Various enhancements make it more usable from the keyboard, for instance.
    – Drew
    May 7, 2015 at 15:35

8 Answers 8

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.

1
  • 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... May 8, 2015 at 7: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.

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.

0
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.

3
  • @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, 2020 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, 2020 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, 2020 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.

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

4
  • 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 3, 2018 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 3, 2018 at 18:25
  • @Name Does it work now? Let me know if you have further questions.
    – clemera
    Dec 3, 2018 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 4, 2018 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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.