tags:

views:

509

answers:

4

Say I have a line in an emacs buffer that looks like this:

foo -option1 value1 -option2 value2 -option3 value3 \
    -option4 value4 ...

I want it to look like this:

foo -option1 value1 \
    -option2 value2 \
    -option3 value3 \
    -option4 value4 \
    ...

I want each option/value pair on a separate line. I also want those subsequent lines indented appropriately according to mode rather than to add a fixed amount of whitespace. I would prefer that the code work on the current block, stopping at the first non-blank line or line that does not contain an option/value pair though I could settle for it working on a selected region.

Anybody know of an elisp function to do this?

A: 

In this case I would use a macro. You can start recording a macro with C-x (, and stop recording it with C-x ). When you want to replay the macro type C-x e.

In this case, I would type, C-a C-x ( C-s v a l u e C-f C-f \ RET SPC SPC SPC SPC C-x )

That would record a macro that searches for "value", moves forward 2, inserts a slash and newline, and finally spaces the new line over to line up. Then you could repeat this macro a few times.

EDIT: I just realized, your literal text may not be as easy to search as "value1". You could also search for spaces and cycle through the hits. For example, hitting, C-s a few times after the first match to skip over some of the matches.

Note: Since your example is "ad-hoc" this solution will be too. Often you use macros when you need an ad-hoc solution. One way to make the macro apply more consistently is to put the original statement all on one line (can also be done by a macro or manually).

EDIT: Thanks for the comment about ( versus C-(, you were right my mistake!

Jason Dagit
C-x ( runs the command kmacro-start-macro, not C-x C-(. Same for C-x ), etc
J.F. Sebastian
A: 

Personally, I do stuff like this all the time.

But I don't write a function to do it unless I'll be doing it every day for a year.

You can easily do it with query-replace, like this:

m-x (query-replace " -option" "^Q^J -option")

I say ^Q^J as that is what you'll type to quote a newline and put it in the string.

Then just press 'y' for the strings to replace, and 'n' to skip the wierd corner cases you'd find.

Another workhorse function is query-replace-regexp that can do replacements of regular expressions.

and also grep-query-replace, which will perform query-replace by parsing the output of a grep command. This is useful because you can search for "foo" in 100 files, then do the query-replace on each occurrence skipping from file to file.

mike511
A: 

Your mode may support this already. In C mode and Makefile mode, at least, M-q (fill-paragraph) will insert line continuations in the fill-column and wrap your lines.

What mode are you editing this in?

Allen
tcl-mode. Fill-paragraph is not what I want because I don't want the paragraph filled, I want it split into lines, one option/value pair per line
Bryan Oakley
+2  A: 

Nobody had what I was looking for so I decided to dust off my elisp manual and do it myself. This seems to work well enough, though the output isn't precisely what I asked for. In this version the first option goes on a line by itself instead of staying on the first line like in my original question.

(defun tcl-multiline-options ()
  "spread option/value pairs across multiple lines with continuation characters"
  (interactive)
  (save-excursion
    (tcl-join-continuations)
    (beginning-of-line)
    (while (re-search-forward " -[^ ]+ +"  (line-end-position) t)
      (goto-char (match-beginning 0))
      (insert " \\\n")
      (goto-char (+(match-end 0) 3))
      (indent-according-to-mode)
      (forward-sexp))
    ))

(defun tcl-join-continuations ()
  "join multiple continuation lines into a single physical line"
  (interactive)
  (while (progn (end-of-line) (char-equal (char-before) ?\\))
    (forward-line 1))
  (while (save-excursion (end-of-line 0) (char-equal (char-before) ?\\))
    (end-of-line 0)
    (delete-char -1)
    (delete-char 1)
    (fixup-whitespace)
    ))
Bryan Oakley