0

I can use Rectangle commands (https://www.gnu.org/software/emacs/manual/html_node/emacs/Rectangles.html) to operate over a text region.

What if I want to select text from columns COL to COL+4 over different rows, i.e., to add or remove characters or spaces at the beginning of multiple lines?

I'm sure this has to be dead easy to achieve, but I couldn't find any reference anywhere.

4
  • Please clarify: Do you mean that the rows are not consecutive? How are the "multiple lines" to be selected? An example might help.
    – NickD
    Sep 26, 2023 at 9:56
  • A "region" means a contiguous sequence of characters in the buffer, so your subject is confusing -- any normal selection is "an arbitrary region". You then mention rectangles and "multiple lines", and rectangles do operate over "multiple lines", so this is also confusing. Please clarify your question.
    – phils
    Sep 26, 2023 at 13:03
  • 1
    @phils: Actually, Emacs supports "noncontiguous regions" to some extent now. (That's the term the docs use - e.g., argument REGION-NONCONTIGUOUS-P for helper function perform-replace and functions that use it.)
    – Drew
    Sep 26, 2023 at 22:09
  • 1
    @Drew: Ah, interesting. I see that the region-extract-function variable can be bound, and it can return a list (edit: which I now see you've written an answer about). The (old) rectangle commands I use are AFAIK all based on apply-on-rectangle (which doesn't use that approach), so I didn't know about this feature. Neat.
    – phils
    Sep 26, 2023 at 22:52

2 Answers 2

3

Emacs can not do it out of the box, rectangle commands operate on contiguous range.

But there are packages that might be what you need:

and probably more.

1
  • Wonderful answer! Straight to the point, and extra helpful thanks to the provided links.
    – solr
    Sep 28, 2023 at 12:09
3

What if I want to select text from columns COL to COL+4 over different rows, i.e., to add or remove characters or spaces at the beginning of multiple lines?

Yes, what if you do? How do you want to tell Emacs which rows to use?

Emacs does let you create such a noncontiguous region. (It lets you create noncontiguous regions of any kind, not just those that fit nicely into a rectangle.)

But it's up to you to define a function (e.g., a command) that somehow gets from the user the info about which rows in a rectangle to keep (or alternatively, which rows not to keep). You assign or bind variable region-extract-function to your function.


Here's one way you can play with this - but if you're defining a feature for other users then you'll want to think about how you would have them tell you where the pieces of a noncontiguous region are, i.e., how to interactively split up a rectangular region into pieces that are not contiguous (which rows to leave out).

To get a feel for this, and as food for thought: you can leverage library Zones (zones.el). For example:

In a buffer where you haven't done any narrowing (or if you have, do (setq zz-izones nil)):

  1. For each piece of text you want to include in your noncontiguous region, in order (e.g. from top to bottom of your rectangle: select it, then hit C-x n a.

    That adds that zone of text to the value of the default zones variable, zz-izones.

  2. Evaluate this code:

   (setq orig-r-e-f               region-extract-function
         region-extract-function  #'foo)

   (defun foo (method)
     (if (eq method 'bounds)
         (zz-noncontiguous-region-from-izones)
       (funcall orig-r-e-f method)))
  1. Use some Emacs command, such as query-replace, that can act on a noncontiguous region.

    (You probably need to activate the region first, e.g. with C-SPC, even though the region is ignored by the new value of region-extract-function. This is because commands such as query-replace only act on a noncontiguous region when they think the region is active.)

  2. When done playing around, do M-: (setq region-extract-function orig-r-e-f) to restore the original value of that variable.

In a real setting you would do a bit more, and more cleanly, but that gives you an idea. In a nutshell:

  • C-x n a adds the current active region to the sequence of zones recorded as the value of variable zz-izones. (A sequence of zones is similar to a vanilla-Emacs noncontiguous region, but it's more general.)

  • Function zz-noncontiguous-region-from-izones does just what it says: it takes the zones from variable zz-izones and returns a corresponding vanilla-Emacs noncontiguous region.

  • If you set or bind variable region-extract-function to a function which, when passed the symbol bounds, returns a noncontiguous region, then you can pass that variable to various vanilla Emacs functions -- such as perform-replace -- that act on a noncontiguous region.

The reason I introduce you to zones.el here is that C-x n a gives you an easy interactive way to set up a sequence of zones, which give you a noncontiguous region.

Obviously, if the noncontiguous region that you want always has rows of a rectangle, then you could come up with another, simpler, way for a user to specify the region pieces. But at least C-x n a gives you an interactive way to do so directly.

2
  • TYVM Drew for your explanation, I now understand better how this functionality is handled in Emacs. Upvoted!
    – solr
    Sep 28, 2023 at 12:08
  • 1
    @solr: I added some more info, so you can play with it.
    – Drew
    Sep 28, 2023 at 22:35

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.