54

I recently learned about multiple-cursors, and it looks like a very useful package. I went through the documentation on the original repo, but the commands still look a bit obscure to me.

I then watched the video in Emacs Rocks!, and the video is great, but it focuses mostly on what multiple-cursors is capable of doing, rather than on how to do it.

Are there any walk-throughs, tutorials or examples that illustrate its most basic functionality?

  • 4
    I was able to get up and running with multiple-cursors very quickly just by reading the README file. My recommendation is to just learn mc/mark-next-like-this. Try it out, and get familiar with what it does. From there refer back to the README whenever you have a question that starts with "I wonder if multiple-cursors can do ..." All of that said, I do think that a more basic introduction than the Emacs Rocks! video would be helpful for beginners. – nispio Oct 7 '14 at 1:37
  • Totally agree! Absolutely nonclear how to use it. I've just mask lines then do mc/edit-lines with KBD binded (not through M-x as noted on Github) Then I see multiple cursors but they just dissapears after any text input – Dima Fomin Dec 3 '17 at 20:09
17

In addition to the uses @bastibe describes, I use multiple cursors to add or remove text from the beginning/end of a group of lines:

  1. Move point to the beginning or end of the area of interest
  2. call set-rectangular-region-anchor (bound to whatever key you like, I think the suggestion from Magnars was H-space, if you have a hyper key)
  3. Moved point forward or backwards by line (C-n and C-p) until you have a cursor on every line you want to edit
  4. Insert or delete text as needed, optionally moving to the end of the line (C-e) to make changes there.

You can use forward-word, forward sentence etc to move back and forth along the lines, which allows you to edit the fourth word in each line, even if the text on each line isn't identical.

As an example, I do this sort of work all the time:

  • C-u M-!ls /test-dat/pp5/*fsaRETURN

    This inserts the contens of the pp5 directory into the buffer. I place point ! at the start of the listing:

!/test-dat/pp5/ONAB-6-5_Frag#89.fsa
/test-dat/pp5/QCJB-22-5_Frag#90.fsa
/test-dat/pp5/ONGL-1-5_Frag#102.fsa
/test-dat/pp5/ONGL-1-5_Frag#78.fsa
  • Add cursors to every line with H-space, C-n x 4
  • duplicate each line with C-k C-y space C-y C-a

!/test-dat/pp5/ONAB-6-5_Frag#89.fsa /test-dat/pp5/ONAB-6-5_Frag#89.fsa
!/test-dat/pp5/QCJB-22-5_Frag#90.fsa /test-dat/pp5/QCJB-22-5_Frag#90.fsa
!/test-dat/pp5/ONGL-1-5_Frag#102.fsa /test-dat/pp5/ONGL-1-5_Frag#102.fsa
!/test-dat/pp5/ONGL-1-5_Frag#78.fsa /test-dat/pp5/ONGL-1-5_Frag#78.fsa
  • trim the first section into variable names with M-d x 3 C-d C-f x3 M-d x3 <-

ONAB-6-5 <-! /test-dat/pp5/ONAB-6-5_Frag#89.fsa
QCJB-22-5 <-! /test-dat/pp5/QCJB-22-5_Frag#90.fsa
ONGL-1-5 <-! /test-dat/pp5/ONGL-1-5_Frag#102.fsa
ONGL-1-5 <-! /test-dat/pp5/ONGL-1-5_Frag#78.fsa
  • then wrap the actual file name in the function to load it: read.file( C-d"C-e")RETURN

ONAB-6-5 <- read.file("/test-dat/pp5/ONAB-6-5_Frag#89.fsa")
QCJB-22-5 <- read.file("/test-dat/pp5/QCJB-22-5_Frag#90.fsa")
ONGL-1-5 <- read.file("/test-dat/pp5/ONGL-1-5_Frag#102.fsa")
ONGL-1-5 <- read.file("/test-dat/pp5/ONGL-1-5_Frag#78.fsa")

And voila, you have converted a file listing into the code to read that listing. It's actually much harder to describe than to actually do!

  • 3
    If you do this same thing frequently, you can wrap it in a keyboard macro. Keyboard macros and multiple-cursors can make a really powerful combination. – nispio Oct 7 '14 at 18:14
  • @nispio agreed! Sometimes I am repeating the same process and a macro would be useful. Often, though, there are small differences in the middle of the work flow that require slight changes that would 'break' a macro. – Tyler Oct 7 '14 at 18:22
  • 1
    You can often accurately describe the location you want the cursor to jump to using a regexp. In such cases, using phi-search can be more robust than navigating with commands like M-f (x3) – nispio Oct 7 '14 at 18:29
  • @nispio sure, it depends on the situation. With consistently structured names it's easy to move by word. I hadn't used search in multiple cursors as the built-in emacs search commands are brittle with mc. I didn't know about phi-search, that looks great! – Tyler Oct 7 '14 at 18:51
21

I basically have two frequent use cases for multiple-cursors:

  • Replace some string. Mark one instance of a string, then use mc/mark-next-like-this and mc/mark-previous-like-this to mark more instances of it. I then immediately hit C-w to delete every instance, and write a new string instead. I use this often to rename a variable in code.
  • Edit several places simultaneously. Either mark several instances of a string like before, but cancel the selection (but not the cursors) immediately using C-g, or place mark and point in the same column of different lines, and use mc/edit-lines to get one cursor per line. You now can use regular editing commands that operate on every one of these cursors.

The first use case is particularly useful with expand-region. I have er/expand-region bound to C-j, and mc/mark-next-like-this and mc/mark-previous-like-this to C-> and C-<. With that, I can easily select the word point is on, and mark the next/previous occurrence of that word instantly.

The second use case replaced most uses of macros for me. Instead of recording a macro, and then applying that in several places, I would place a cursor on every place, and just do the operation in all places at once.

  • Thanks @bastibe. Any particular bindings that you or multiple-cursors recommend for e.g. mark-next-like-this & mark-previous-like-this ? – Amelio Vazquez-Reina Oct 7 '14 at 15:30
  • @user815423426 as outlined in the post, I use C-> and C-< for mark-next-like-this and mark-previous-like-this. – bastibe Oct 8 '14 at 8:23
  • why not to use standart M-% to search and replace ? – Dima Fomin Dec 3 '17 at 20:13
6

I'd like to add some extras that I sometimes use with multiple-cursors.

I've found the following to be useful:

iy-go-to-char

Sometimes, you find yourself needing to move to the next # or the next , or some specific delimiter. This is especially handy when you need to move across different numbers of words for each cursor. It provides the functions iy-go-to-char and iy-go-to-char-backward, which you can bind and use nicely.

expand-region

This is really useful for similar reason to iy - when you've got slightly different lines under each cursor, and you maybe want to select the quoted string under the point or similar.

custom stuff

These are things that are just elisp in my config, but I find useful. Probably not written by me.

Prompt for input
I got this one from Magnars in response to a request for putting a different string under each cursor. The code is simple, but binding it to something and using for multiple cursors is a handy way to insert slightly different stuff in each place.

(defun prompt-for-insert ()
  (interactive)
  (insert (read-string "Insert: ")))

Increment number at point
This either came from SO, or emacswiki. Not sure which. It's pretty useful on its own, and also when used in combination with mc/insert-numbers

(defun my-increment-number-decimal (&optional arg)
  "Increment the number forward from point by 'arg'."
  (interactive "p*")
  (save-excursion
    (save-match-data
      (let (inc-by field-width answer)
        (setq inc-by (if arg arg 1))
        (skip-chars-backward "0123456789")
        (when (re-search-forward "[0-9]+" nil t)
          (setq field-width (- (match-end 0) (match-beginning 0)))
          (setq answer (+ (string-to-number (match-string 0) 10) inc-by))
          (when (< answer 0)
            (setq answer (+ (expt 10 field-width) answer)))
          (replace-match (format (concat "%0" (int-to-string field-width) "d")
                                 answer)))))))

eval-and-replace
This is super powerful, and enables some really useful bits 'n' pieces. It evaluates whatever sexp is behind the cursor, and inserts the result of evaluating it.
Combine it with multiple-cursors-numbers to e.g. insert powers of two, or a series that goes 0 1 2 0 1 2 0 1 2 across each line or something. (I've done both of these usefully) Or use it with s.el to write out those tedious java config with default things. You write out each CONFIG_VALUE_VARIABLE, then transform that into CONFIG_VALUE_VARIABLE = "configValueVariable" by running s-camel-case.

(defun eval-and-replace ()
  (interactive)
  (let ((value (eval (preceding-sexp))))
    (kill-sexp -1)
    (insert (format "%s" value))))
  • iy-go-to-char is super helpful. Just what I was looking for. – Heinrich Hartmann Jun 15 '16 at 9:25
1
  1. Go to the end* of what you want selected.
  2. Press C-S-b or M-S-b to select backwards until you get a portion selected. You can use shift left arrow as well.
  3. Then press C-> (press shift if the key > is on top of your keyboard's key) until you get more than one item selected.

*It is important to select backwards or the first selection will place the cursor in the wrong position.

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

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