How to get Emacs to unwrap a block of code? - emacs

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?

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)))

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!

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.

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?

Related

The lisp that convert string and grep in emacs?

I have a file formatted as
abc|<hoge>
a|<foo> b|<foo> c|<foo>
family|<bar> guy|<bar>
a|<foo> comedy|<bar> show|<foo>
action|<hoge>
and want to search search strings by raw (Like "a comedy show" instead of a|<foo> comedy|<bar> show|<foo>) on emacs.
I believe using grep on lisp would be the easiest answer but I have not yet figured out how. Would someone enlighten me?
Well, grep is a separate program (which you could also use). In Emacs, you'd use the function search-forward-regexp, which you can run using either M-x (hold Meta, usually Alt key, and press x) and then type search-forward-regexp and press Return.
You'll then need to key in the regexp to search. Put simply, it seems like you want to ignore |< something >, which in Emacs's variety of regexes is:
|<[a-z]+>
so you might search for e.g.
a|<[a-z]+> comedy|<[a-z]+> show|<[a-z]+>
You can create a Lisp function to convert a string this way, by splitting it on spaces and adding the regex sequences:
(defun find-string-in-funny-file (s) ; Define a function
"Find a string in the file with the |<foo> things in it." ; Document its purpose
(interactive "sString to find: ") ; Accept input if invoked interactively with M-x
(push-mark) ; Save the current location, so `pop-global-mark' can return here
; (usually C-u C-SPC)
(goto-char 0) ; Start at the top of the file
(let ((re (apply #'concat ; join into one string…
(cl-loop
for word in (split-string s " ") ; for each word in `s'
collect (regexp-quote word) ; collect that word, plus
collect "|<[a-z]+> ")))) ; also the regex bits to skip
(search-forward-regexp ; search for the next occurrence
(substring re 0 (- (length re) 2))))) ; after removing the final space from `re'
You can explore what those functions each do in the (online) Emacs Lisp manual; for example, pick from the menu "Help→Describe→Function" or press C-h f (Control+h, then f) and type interactive (RET) for the manual's documentation of that special form.
If you paste the above (defun) into the *scratch* buffer, and position the cursor after the final ) at the end, you can press C-j to evaluate it, and the function will remain with you until you close Emacs.
If you save it in a file named something .el, you can use M-x load-file to load it again in future.
If you then load your "funny" file, and type M-x find-string-in-funny-file, it'll search your file for your string, and leave the cursor on the string. If it's not found, you'll see a message to that effect.
BUGS: The function is less than spectacular style

How to attach character to the next N lines using Emacs?

Using emacs24 I'd like to attach for example # at the beginning of the next five lines.
So having this:
Line1
line2
line3
get this:
#Line1
#line2
#line3
for the number of lines that I specify. How can I do that? Thanks!
While there may be something built in to Emacs that does this, and you can certainly write a little Lisp to get it done, I would usually use "rectangular editing" features to get this done. Imagine that the buffer contains the following, with . representing the point (where your cursor is)
.Line1
line2
line3
Set the mark
Press C-n twice. This is the state of the buffer now:
Line1
line2
.line3
Press C-x r t.
Type #.
Press enter.
I would find this much more natural than entering a value for the number of times to repeat a command, because you can visually select the lines you want to edit. YMMV
Edit
Here's how to do this using a bit of Emacs Lisp. Note that although I've been using Emacs for a few years now, I only recently began learning how to actually use Emacs Lisp, so this code might not be that great! It does get the job done.
(defun insert-n-times (s n)
(interactive "Mstring:\nNtimes:")
(while (> n 0)
(insert s)
(goto-char (- (point) 1))
(next-line)
(setq n (- n 1))))
Use it by doing the following: M-x insert-n-times RET <type a string> RET <type a number>
Another method is using macro to get such repetitive work done. Here is a page that describes how to use macros in Emacs. You can have a look at it if you are not familiar with it.
In your case, the following keys would work:
Move the cursor to the beginning of Line1
C-x (
Type a '#'
C-n, then C-a
C-x )
Move the cursor to the line to the beginning of which you want to add '#'
C-u 10 C-x e
Basically, step 2-5 will record a macro which will add a # at the beginning, and then move to the beginning of the next line. Step 6-7 will execute the macro 10 times (of course, you can change it to arbitrary number). I guess this will be quite a lot of keystrokes and newbies may not like it. Maybe others have better solutions.
Line1
line2
line3
I wrote the following code:
You first give a digit argument (the amount of times you want to do this), e.g. M-3 (hold alt, hit 3), to do the following 3 times
Either use a key for it, like a suggestion below (f8), or use M-x prompt-for-insert
It will ask you for a string to enter. e.g. "foo" and hit return button.
It will then do as you ask.
(defun prompt-for-insert (val)
(interactive "P")
(let ((astring (read-string "What do you want to insert?"))
(value val))
(while (> value 0)
(insert astring)
(move-beginning-of-line 2)
(decf value)))
)
(global-set-key [f8] 'prompt-for-insert)
The whole sequence will then be:
M-3 [f8] foo RET
Resulting in:
fooLine1
fooline2
fooline3
Why not just query-replace-regexp or replace-regexp? E.g. select the region and do C-M-%^RET#RET!
Try M-x string-insert-rectangle. This command inserts a string on every line of the rectangle.
While comment-region is good in this specific example, check out the multiple-cursors package for a very powerful way to do this kind of thing in general.
You can just hit C-> repeatedly until you have a cursor at the beginning of each line, then hit # and you're done (C-g to get rid of the extra cursors.)
It's a much more interactive form of C-x r t and works with non-rectangular regions too (after a C-s for example.)

emacs macro to convert a vector to a matrix in .csv notation

I have a single line text file of csv values
I would like to able to 'pretty-print' the file to span multiple lines to make it more readable
The 1st no. represents the no. of csv values in the next section and so on
e.g.
3,1,2,3,3,4,5,6
would be converted to:
3,1,2,3
3,4,5,6
I know a little about making macros, e.g.
C-x (
C-s RET ,
C-x )
using this I can do:
C-u 3 C-x e to move 3 csv values along
My sticking point is how to use the value from file to paste into the arg to C-u
maybe I should be using an e-lisp function instead as its a function I would like to 'save' for continual use across emacs sessions. Is it possible to save macros as such?
any ideas gratefully received
I find elisp easier to think about than keyboard macros. How about this:
(defun csv-line-breaks ()
(interactive)
(while (search-forward "," nil t
(1+ (string-to-number (thing-at-point 'word))))
(delete-char -1)
(insert "\n")))
(global-set-key (kbd "C-c b") 'csv-line-breaks)
With this in your .emacs (or just evaluate the code in your scratch buffer), you put point at the beginning of the line, then hit C-c b to break the line up into the chunks you want.
What this does:
Looping over the buffer until it runs out of values, and for each loop:
Read the first value. (thing-at-point 'word) grabs anything it finds between whitespace of punctuation (more or less).
Convert the value, which is actually a string, into a number
Add one to that number, and move forward that many commas
Delete the previous comma
Insert a new line
You might want to take a look at csv-mode for Emacs: http://emacswiki.org/emacs/CsvMode
Although it might not do exactly what you're looking for, it has a feature for formatting for readability, as well as other features for munging csv files in a variety of ways.

emacs equivalent of ct

looking for an equivalent cut and paste strategy that would replicate vim's 'cut til'. I'm sure this is googleable if I actually knew what it was called in vim, but heres what i'm looking for:
if i have a block of text like so:
foo bar (baz)
and I was at the beginning of the line and i wanted to cut until the first paren, in visual mode, I'd do:
ct (
I think there is probably a way to look back and i think you can pass more specific regular expressions. But anyway, looking for some emacs equivalents to doing this kind of text replacement. Thanks.
Here are three ways:
Just type M-dM-d to delete two words. This will leave the final space, so you'll have to delete it yourself and then add it back if you paste the two words back elsewhere.
M-z is zap-to-char, which deletes text from the cursor up to and including a character you specify. In this case you'd have to do something like M-2M-zSPC to zap up to and including the second space character.
Type C-SPC to set the mark, then go into incremental search with C-s, type a space to jump to the first space, then C-s to search forward for the next space, RET to terminate the search, and finally C-w to kill the text you selected.
Personally I'd generally go with #1.
as ataylor said zap-to-char is the way to go, The following modification to the zap-to-char is what exactly you want
(defun zap-up-to-char (arg char)
"Like standard zap-to-char, but stops just before the given character."
(interactive "p\ncZap up to char: ")
(kill-region (point)
(progn
(search-forward (char-to-string char) nil nil arg)
(forward-char (if (>= arg 0) -1 1))
(point))))
(define-key global-map [(meta ?z)] 'zap-up-to-char) ; Rebind M-z to our version
BTW don't forget that it has the ability to go backward with a negative prefix
That sounds like zap-to-char in emacs, bound to M-z by default. Note that zap-to-char will cut all the characters up to and including the one you've selected.

Emacs Command to Delete Up to Non-Whitespace Character

I often want to make a multiline function call and reduce it down to one line. For example, convert...
function_call(
'first_arg',
'second')
to
function_call('first_arg', 'second')
Does emacs have some commands to help with this. Specifically, is there a command that will delete all whitespace from the point to the first non-whitespace character?
You might try delete-indentation, my favorite command for joining multiple lines into one line. In your example, put the cursor on the line with "second" and hit M-^ twice. Here are the docs:
M-^ runs the command delete-indentation, which is an interactive compiled Lisp function in simple.el.
It is bound to M-^.
(delete-indentation &optional arg)
Join this line to previous and fix up whitespace at join. If there is a fill prefix, delete it from the beginning of this line. With argument, join this line to following line.
Take a look at the fixup-whitespace function. It comes with Emacs, in simple.el. Its docs are:
Fixup white space between objects around point.
Leave one space or none, according to the context.
A similar function, just-one-space, that
Deletes all spaces and tabs around point, leaving one space
is typically bound to M-SPC.
Specifically, is there a command that will delete all whitespace from the point to the first non-whitespace character?
There's a command that does almost that:
M-\ runs the command delete-horizontal-space
which is an interactive compiled Lisp function in `simple.el'.
It is bound to M-\.
(delete-horizontal-space &optional backward-only)
Delete all spaces and tabs around point.
If backward-only is non-nil, only delete them before point.
You can always use M-z to delete upto a character.
For eg in your case:
M-z ' to delete upto the single quote (unfortunately this will delete the single quote as well, but that is a minor inconvenience).
I use the following macro to "pull" the next line onto the end of the current line, compressing whitespace.
(defun pull-next-line()
(interactive)
(move-end-of-line 1)
(kill-line)
(just-one-space))
This is exactly the opposite of #jrockway's move-line-up and of delete-indentation, which I find more natural. The just-one-space command in the macro is exactly #Mike's M-SPACE.
I bind pull-next-line to M-J (in analogy with Vim's J, for "join", command) using the following in my .emacs.
(global-set-key (kbd "M-J") 'pull-next-line)
Example. Calling pull-next-line on the first line of
function_call(
'first_arg',
'second')
yields
function_call( 'first_arg',
'second')
Calling it a second time yields
function_call( 'first_arg', 'second')
Alt-space will reduce a string of whitespace to a single space character, but it won't delete the newline. Still, that should help a little.
To delete everything from point to the first non-whitespace (or newline), type a non-whitespace char, Alt-space, backspace (to remove final whitespace char), then backspace (to delete the char you added.
To turn the multi-line function declaration into a single-line declaration, use a combination of Alt-space, backspace, and Alt-E (goto-endofline) commands.
A rather drastic way of doing this is Hungry-Delete mode:
Hungry-Delete is a minor-mode that causes deletion to delete all whitespace in the direction you are deleting.
A slightly different approach would be creating a keyboard macro to do the job for you.
so, for creating the macro stage a general scenario like so:
foo
bar
[a line with "foo" then a couple of lines later and with some white spaces, write "bar"]
then standing anywhere between foo and bar, do the following:
C-x ( ; start recording macro
M-b ; move backwards to the beginning of foo
END ; move to the end of foo
C-space ; place mark
C-M-f ; move to the end of bar
HOME ; move to the beginning of the line
C-w ; yank out all the white space
M-SPACE ; leave only one space
C-x ) ; end recording the macro
M-x name-last-kbd-macro ; name it, call it jline or something
Now you can always remove all whitespace between two words with M-x one-line
Make sure you remember to save your keyboard macro by issuing M-x insert-kbd-macro somewhere in your .emacs file - this is how it looks:
(fset 'jline
[?\M-b end ?\C- ?\C-\M-f home ?\C-w escape ? ])
I do this:
(defun move-line-up ()
"Removes leading spaces from the current line, and then moves
the current line to the end of the previous line."
(interactive)
(let (start end)
(save-excursion
(beginning-of-line)
; get first non-space character, only look on this line
(let ((search-end (save-excursion (end-of-line) (point))))
(re-search-forward "[^[:space:]]" search-end))
(setq end (1- (point)))
(previous-line)
(end-of-line)
(setq start (point))
(delete-region start end))
(goto-char start)))
(defun move-next-line-up ()
"Moves the next line to the end of the current line"
(interactive)
(next-line)
(move-line-up))
And bind these as:
(global-set-key (kbd "C-x ,") 'move-line-up)
(global-set-key (kbd "C-x .") 'move-next-line-up)
So to solve your problem, on the line that says "second)", just run C-x , C-x ,
If you want all of your deletes to act that way, you might check out greedy-delete.