Emacs equivalent of Vim's yy10p? - emacs

How can I copy a line 10 times easily in Emacs? I can't find a copy-line shortcut or function. I can use C-aC-spcC-eM-w to laboriously copy the line but how can I then paste it more than once?
Any ideas before I go and write my own functions.

you can use a keyboard macro for that:-
C-a C-k C-x ( C-y C-j C-x ) C-u 9 C-x e
Explanation:-
C-a : Go to start of line
C-k : Kill line
C-x ( : Start recording keyboard macro
C-y : Yank killed line
C-j : Move to next line
C-x ) : Stop recording keyboard macro
C-u 9 : Repeat 9 times
C-x e : Execute keyboard macro

Copying:
If you frequently work with lines, you might want to make copy (kill-ring-save) and cut (kill-region) work on lines when no region is selected:
(defadvice kill-ring-save (before slickcopy activate compile)
"When called interactively with no active region, copy a single line instead."
(interactive
(if mark-active (list (region-beginning) (region-end))
(list (line-beginning-position)
(line-beginning-position 2)))))
(defadvice kill-region (before slickcut activate compile)
"When called interactively with no active region, kill a single line instead."
(interactive
(if mark-active (list (region-beginning) (region-end))
(list (line-beginning-position)
(line-beginning-position 2)))))
Then you can copy the line with just M-w.
Pasting:
Often a prefix argument just performs an action multiple times, so you'd expect C-u 10 C-y to work, but in this case C-y uses its argument to mean which element of the kill-ring to "yank" (paste). The only solution I can think of is what kronoz says: record a macro with C-x ( C-y C-x ) and then let the argument of C-u go to kmacro-end-and-call-macro instead (that's C-u 9 C-x e or even just C-9 C-x e or M-9 C-x e).
Another way:
You can also just stay in M-x viper-mode and use yy10p :)

You may know this, but for many commands a "C-u 10" prefix will do the trick. Unfortunately for the C-y yank command, "C-u" is redefined to mean "go back that many items in the kill ring, and yank that item".
I thought you might be able to use the copy-to-register and insert-register commands with the C-u prefix command, but apparently that doesn't work either.
Also C-x z, "repeat last command" seems to be immune to C-u.
Another thought would be to use M-: to get an Eval prompt and type in a bit of elisp. I thought something like (dotimes '10 'yank) might do it, but it doesn't seem to.
So it looks like using C-u on a macro may indeed be the best you can do short of writing your own little function.
Had I a vote, I'd vote for kronoz answer.

You don't need both C-x ) and C-x e in this example.
You can just give the repeat argument straight to C-x ). This stops recording and repeats the macro, in one step. Or you can skip C-x ) and go straight to C-x e, since C-x e will end the recording before doing the repeats.
Which way to choose depends on how you like your repeat count to work. For C-x ) you say how many repeats you wanted in total (so 10 in this case). For C-x e you need to say how many more repeats are left (i.e. 9).
C-a C-k C-k will also kill the trailing newline, so you don't have to put it back yourself later. It's quicker than using the mark, and doesn't need you to change any variables.
Even better (unless you're in a terminal), you can use C-S-Backspace* to kill the entire line, regardless of where you are in it.
[* If you're using X windows, make sure to type shift (not alt) or you may terminate your session!]
Speaking of terminals, M-9 is a nice alternative if you find you can't type C-9.
In Emacs 22 and higher, by default F3 starts a macro and F4 end/repeats a macro. You just hit F3 to start recording, hit F4 when you're done, and hit F4 again to repeat the macro. (F4 also takes an argument.)
Putting this all together, to get 10 copies of the current line:
C-S-Backspace : kill this line
F3 : start macro
C-y : yank the line
C-1 C-0 F4 : make that 10 yanks
Not quite as short as y y 10 p, but pretty close. :)

Here's a function I took from an OS/2 port of Emacs. (Yes, I've been using Emacs for a while.)
;; Author: Eberhard Mattes <mattes#azu.informatik.uni-stuttgart.de>
(defun emx-dup-line (arg)
"Duplicate current line.
Set mark to the beginning of the new line.
With argument, do this that many times."
(interactive "*p")
(setq last-command 'identity) ; Don't append to kill ring
(let ((s (point)))
(beginning-of-line)
(let ((b (point)))
(forward-line)
(if (not (eq (preceding-char) ?\n)) (insert ?\n))
(copy-region-as-kill b (point))
(while (> arg 0)
(yank)
(setq arg (1- arg)))
(goto-char s))))
I have that bound to F9 d:
(global-set-key [f9 ?d] 'emx-dup-line)
Then I'd use C-u 10 F9 d to duplicate a line 10 times.

The only way I know to repeat arbitrary commands is to use the "repeat by argument" feature of keyboard macros.
C-a C-space down M-w C-x ( C-y C-x ) C-9 C-x e
C-a : Go to start of line
C-space : Set mark
down : Go to start of following line
M-w : Copy region
C-x ( : Start keyboard macro
C-y : Yank copied line
C-x ) : End keyboard macro
C-9 C-x e : Execute keyboard macro nine times.
That's kind of weak compared to vim. But only because vim is amazingly efficient at this sort of thing.
If you are really pining for modal vi-like interaction, you could use one of the vi emulation modes, such as viper-mode. Check in the section "Emulation" of online emacs manual.

You will want to kill the line: C-a C-k, and then C-y or ?

I don't know of a direct equivalent (C-y 10 times is the best I know), but you may be interested in Viper, which is a vi emulation package for emacs. It's part of the standard emacs distribution.

Based on Baxissimo's answer I defuned this:
(defun yank-n-times (arg)
"yank prefix-arg number of times. Not safe in any way."
(interactive "*p")
(dotimes 'arg (yank)))
Set that to some key, call it with a prefix argument, and off you go.
edit (also modified the interactive call above to be less lousy)
Or, here's a version that can sort of replace yank-pop:
(defun yank-n-times (&optional arg)
"yank prefix-arg number of times. Call yank-pop if last command was yank."
(interactive "*p")
(if (or (string= last-command "yank")
(string= last-command "yank-pop"))
(yank-pop arg)
(if (> arg 1)
(dotimes 'arg (yank))
(message "Previous arg was not a yank, and called without a prefix."))))
the message is kind of a lie, but you shouldn't call it without a prefix of greater than 1 anyway, so.
Not sure if it's a good idea, but I replaced M-y with this, I'll see how that goes.

First you need this key binding in your .emacs:
;; yank n times
(global-set-key "\C-y" (lambda (n) (interactive "*p") (dotimes (i n) (clipboard-yank))))
Then you can do:
C-a C-SPC C-n M-w C-u 10 C-y
C-a C-SPC C-n M-w - select whole line
C-u 10 C-y - repeat "clipboard-yank" 10 times

You get the line with C-k, you make the next command happen ten times with C-u 10, then you paste the line with C-y. Pretty simple.
If you always want C-k to do the whole line, you can set kill-whole-line to t. No more fiddling with C-a or C-e.
There's a lot you can do with fancy kill rings, registers, and macros, and I encourage you to learn them, but yanking a line ten times doesn't have to be tough or strange.

Related

Save and execute an Emacs keyboard macro

I have a problem for execute a personal macro in another session in Emacs. I succeeded to create macro and execute then but, after I want to save it for execute them in another time.
For this I write this code in ~/.emacs
(fset 'psTest
(lambda (&optional arg) "Keyboard macro."
(interactive "p")
(kmacro-exec-ring-item (quote ("^X2^X2^X2^X2" 0 "%d")) arg)))
but when I call my macro in another file [ M- x psTest ], Emacs doesn't execute my macro but writes key in my file
^X2^X2^X2^X2
all my commands:
In terminal:
user#PC $ emacs ~/.emacs
In emacs:
C-x (
C-x 2
C-x )
C-x C-k n psTest
M-x insert-kbd-macro [ENTER] psTest [ENTER]
C-x C-c
In terminal:
user#PC $ cat ~/.emacs :
(fset 'psTest
(lambda (&optional arg) "Keyboard macro." (interactive "p") (kmacro-exec-ring-item (quote ("^X2" 0 "%d")) arg)))
user#PC $ emacs ~/test
In emacs:
M- psTest
Now my macro [M- psTest] write ^X2 in my file instead of execute [^X2] which split the screen.
Where is my error?
Thanks
The problem lies in the sequence "^X2" in your macro definition. It contains two characters ^ and X rather than the single character 0x18 in the charset ascii (ASCII (ISO646 IRV)) which is used by emacs to refer to C-x but is displayed the same, though probably in a different color. If you replace the former two-letter-sequence with the latter character and evaluate the definition again, it should work.
You can insert the character with
C-x8RET #x18 RET.
PS: To display information about a specific character at point you can use
M-x desribe-char or what-cursor-position, which is bound to C-x = by default.
I agree with Simon Fromme.
To insert the C-x character, you may omit the #x prefix from his answer and type:
C-x8RET18RET
But you may also simply type C-qC-x in case you don't know the hexadecimal value of the ascii code of this or any other character!
Nevertheless, in your case, I would rather search for the function associated to the C-x 2 sequence. You'll easily find it is split-window-below using either:
C-h k C-x 2 RET
or M-x edit-last-kbd-macro RET
Then you can write some code easier to copy/paste/save like:
(fset 'psTest #'split-window-below)
or
(defun psTest ()
(interactive)
(split-window-below))
This might be a good way to start learning emacs-lisp!

Is there an apply-command-to-each-line-in-region in emacs?

I have a bunch of links saved in an orgmode file, say...
http://www.stackoverflow.com
http://www.google.com
http://www.github.com
I can open each one by having the cursor on the link and doing C-c C-o, and it conveniently pops up my default browser and opens that link in a tab.
Now suppose I have like 20 of these links. Is there a convenient way to apply a function like this to each line within a selected region, without recording an explicit macro?
I'd imagine it looking something like...
Select region
M-x foreach-in-region
Keystrokes to apply to each line: C-c C-o
And this is just for functions already defined. I imagine the way without would be something like...
with cursor on first line of link
F3 # to start record macro
C-c C-o
down arrow
F4
Select region (omitting the first line, since that's now already opened in my browser)
C-x C-k r
Does this exist? If not, how would I lisp this?
You should record the macro for one line, then use apply-macro-to-region-lines to execute it for all lines in region. C-x C-k r
Alternatively, you can use multiple-cursors to create a cursor on each line and C-c C-o to open all. multiple-cursors will transform your usage patterns over time for the better if you give it a chance.
(defun do-lines (fun &optional start end)
"Invoke function FUN on the text of each line from START to END."
(interactive
(let ((fn (intern (completing-read "Function: " obarray 'functionp t))))
(if (use-region-p)
(list fn (region-beginning) (region-end))
(list fn (point-min) (point-max)))))
(save-excursion
(goto-char start)
(while (< (point) end)
(funcall fun (buffer-substring (line-beginning-position) (line-end-position)))
(forward-line 1))))
Update after your comment --
Now it sounds like you want to not enter a function name but hit a key, and have the command bound to that key be applied to each line in the region (or buffer).
Something like the following will do that. However, be aware that command often have particular behavior wrt lines. For example, if you were to hit key C-k (kill-lines) then it already moves forward after each line it kills. Because do-lines does not know what kind of function (command) you will invoke, it advances to the next line after each invocation. For a command such as kill-lines this will thus do the wrong thing: it will end up advancing two lines, not one, thus skipping lines. IOW, be aware that the code for do-lines cannot compensate for what a particular function it invokes might do that might not correspond to what you expect. Instead, it does what it says it does.
(defun do-lines (command &optional start end)
"Invoke COMMAND on the text of each line from START to END."
(interactive
(let* ((key (read-key-sequence-vector "Hit key sequence: "))
(cmd (lookup-key global-map key t)))
(when (numberp cmd) (error "Not a valid key sequence"))
(unless (commandp cmd) (error "Key `%s' is not defined" (key-description key)))
(if (use-region-p)
(list cmd (region-beginning) (region-end))
(list cmd (point-min) (point-max)))))
(setq start (copy-marker start)
end (copy-marker end))
(save-excursion
(goto-char start)
(while (< (point) end)
(funcall command (buffer-substring (line-beginning-position) (line-end-position)))
(forward-line 1))))
In some situations, you can use Emacs Repeating using C-x z following by more `z'. I was trying to comment all the lines in region and it worked nicely for my use case.
The command C-x z (repeat) provides another way to repeat an Emacs
command many times
To repeat the command more than once, type additional z’s: each z repeats the command one more time
In the spirit of TIMTOWTDI[1], I'll point out a technique that works well for some situations, including the one in the OP.
If you're looking to run an external command on a line of space-separated strings (like URLs):
Select the region
Invoke M-| (Alt+Shift+\, shell-command-on-region)
Use xargs as a prefix command to the desired command (e.g., xdg-open, or x-www-browser)
For example, the full command entered for step 3 might be:
xargs -n1 xdg-open
The -n1 switch causes xargs to open invoke the given program with one argument at a time; it will run the program once for each input. If the command can handle multiple arguments at once, you can omit -n1. For example, I have a web command that can open multiple URLs as arguments, so just xargs web works.
The major benefit of this approach is, it works on anything POSIX-compliant without doing anything in advance. Disadvantages include, it only works on external commands, and it requires xargs (not included with every OS by default).
[1] There's More Than One Way To Do It, originally from Perl, but useful elsewhere.

How can I capture the `M-0 <f4>` event and write it to a buffer in that format in Emacs?

I'm working on capturing formatted keystrokes to a buffer related to a VimGolf minor mode that I've been working on for a few days now.
I have the capture function almost exactly where I want it except that it cannot seem to capture the kmacro-end-or-call-macro command triggered by <f4> or the calc-dispatch command triggered by C-x *. I'm not sure what else is potentially missing as my testing has only exposed these anomalies.
In case you don't want to click over to github, here's the function as it stands now:
(defun vimgolf-capture-keystroke ()
(with-current-buffer (get-buffer-create vimgolf-keystrokes-buffer-name)
(end-of-buffer)
(if (not (or executing-kbd-macro prefix-arg))
(progn
(insert (key-description (this-command-keys)))
(insert " ")))))
(defun vimgolf-capture-keystrokes ()
(add-hook 'post-command-hook 'vimgolf-capture-keystroke))
(defun vimgolf-stop-capture-keystrokes ()
(remove-hook 'post-command-hook 'vimgolf-capture-keystroke))
The only connection I can see between the two problem functions that I know about is that they both recurse into executing other commands prior to finishing the command that they actually execute.
I can capture the beginning of the commands but not the end by transforming the capture functions above into:
(defun vimgolf-capture-keystrokes ()
(add-hook 'pre-command-hook 'vimgolf-capture-keystroke))
(defun vimgolf-stop-capture-keystrokes ()
(remove-hook 'pre-command-hook 'vimgolf-capture-keystroke))
Even when I turn off executing-kbd-macro from the restriction on appending to the buffer, it still does not capture that event. I tried to examine the actual vector that comes down from the post-command-hook and in all cases it's exactly what I would expect but for <f4> it renders an empty vector.
So how do I get those keys into my capture buffer?
For convenience, I've been testing this using Challenge ID 4d2fb20e63b08b08b0000075.
The exact keys I press are <f3> C-e M-4 M-b M-d C-b M-2 <C-S-backspace> M-2 C-y C-f <f4> M-0 <f4> C-o M-< C-x * : M-1 v r C-u y
The way those keys come into my capture buffer with the function as it stands right now is <f3> C-e M-4 M-b M-d C-b M-2 <C-S-backspace> M-2 C-y C-f <f4> C-o M-< : M-1 v r C-u y
I remembered a package that can do this -- I just tried it out and it captures those specific keys. The other nice thing, for your purposes, is that it limits the captured keys to the current buffer. Plus, you can specify certain commands that will not get logged, which would be handy for excluding the vimgolf-specific commands. (An aside; if you use a separate "control buffer" for vimgolf-mode, a la ediff-mode, then you won't get any vimgolf-specific keystrokes polluting the command log for the challenge buffer.)
The aforementioned package's limitation (currently) is that it won't capture keystrokes entered in the minibuffer (e.g. for M-x sort-lines RET), but that should be possible to extend by also capturing keys when (minibufferp).
The package works by hooking into pre-command-hook rather than the post-command-hook you are currently using.
FWIW, if you want you can do without the angle brackets in key descriptions -- they are never necessary (serve no purpose -- just noise). Library naked.el lets you do this. Description here.

Appending characters to the end of each line in Emacs

Assume I have a text file with content
1
123
12
12345
If I want to add an 'a' in the beginning of each line I can simply use string-rectangle (C-x r t), but what if I want to append an 'a' to the end of each line, after which the file should become
1a
123a
12a
12345a
Thanks.
You could use replace-regexp for this purpose, with the $ regexp metacharacter that matches end-of-line. Go to the start of the buffer, and then do M-x replace-regexp, and answer $ and (your text) to the two prompts.
Or, in emacs-speak, for your specific example of adding a:
M-< M-x replace-regexp RET $ RET a RET
Emacs keyboard macros are your friend.
C-x ( C-e a C-n C-x )
Which just sets up the keyboard macro by: starting the keyboard macro (C-x (), go to the end of the line (C-e), insert an a, go to the next line (C-n), and then end the macro recording (C-x )).
Now you can either execute it (C-x e), and keep pressing e for each line you want to have it run on, or you can run it on a region with C-x C-k r.
If you do this a lot, you can save the macro, or you can write a function. This would be one such function:
(defun add-string-to-end-of-lines-in-region (str b e)
"prompt for string, add it to end of lines in the region"
(interactive "sWhat shall we append? \nr")
(goto-char e)
(forward-line -1)
(while (> (point) b)
(end-of-line)
(insert str)
(forward-line -1)))

How can I delete the current line in Emacs?

What is the emacs equivalent of vi's dd? I want to delete the current line. Tried CTRL + k but it only deletes from current position.
C-a # Go to beginning of line
C-k # Kill line from current point
There is also
C-S-backspace # Ctrl-Shift-Backspace
which invokes M-x kill-whole-line.
If you'd like to set a different global key binding, you'd put this in ~/.emacs:
(global-set-key "\C-cd" 'kill-whole-line) # Sets `C-c d` to `M-x kill-whole-line`
If you want to delete a number of whole lines, you can prefix the command with a number:
C-u 5 C-S-backspace # deletes 5 whole lines
M-5 C-S-backspace # deletes 5 whole lines
C-u C-S-backspace # delete 4 whole lines. C-u without a number defaults to 4
C-u -5 C-S-backspace # deletes previous 5 whole lines
M--5 C-S-backspace # deletes previous 5 whole lines
Sometimes I also find C-x z helpful:
C-S-backspace # delete 1 whole line
C-x z # repeat last command
z # repeat last command again.
# Press z as many times as you wish.
# Any other key acts normally, and ends the repeat command.
In case you don't want to kill the line (which would put it into the OS clipboard and kill ring) but simply delete it:
(defun delete-current-line ()
"Delete (not kill) the current line."
(interactive)
(save-excursion
(delete-region
(progn (forward-visible-line 0) (point))
(progn (forward-visible-line 1) (point)))))
Another method to delete the line without placing it into the kill ring:
(defun delete-current-line ()
"Deletes the current line"
(interactive)
(delete-region
(line-beginning-position)
(line-end-position)))
This will leave the point at the beginning of a blank line. To get rid of this also, you may wish to add something like (delete-blank-lines) to the end of the function, as in this example, which is perhaps a little less intuitive:
(defun delete-current-line ()
"Deletes the current line"
(interactive)
(forward-line 0)
(delete-char (- (line-end-position) (point)))
(delete-blank-lines))
Rather than having separate key to delete line, or having to invoke
prefix-argument. You can use crux-smart-kill-line
which will "kill to the end of the line and kill whole line on the next
call". But if you prefer delete instead of kill, you can use the
code below.
For point-to-string operation (kill/delete) I recommend to use zop-to-char
(defun aza-delete-line ()
"Delete from current position to end of line without pushing to `kill-ring'."
(interactive)
(delete-region (point) (line-end-position)))
(defun aza-delete-whole-line ()
"Delete whole line without pushing to kill-ring."
(interactive)
(delete-region (line-beginning-position) (line-end-position)))
(defun crux-smart-delete-line ()
"Kill to the end of the line and kill whole line on the next call."
(interactive)
(let ((orig-point (point)))
(move-end-of-line 1)
(if (= orig-point (point))
(aza-delete-whole-line)
(goto-char orig-point)
(aza-delete-line))))
source
The fastest/simplest way to delete (kill) a full line, from any point
on the line, without selecting anything, is:
C-w ; kill-region
It is versatile in deleting whatever is selected, or a line by default
if nothing is selected.
Given the question, you're probably also interested in replicating
Vim's "yank", yy (though in Emacs parlance a "yank" is confusingly
Vim's "put", p). This is:
M-w ; kill-ring-save
Nice and congruent, and pretty easy to remember. Even slightly
similar to Vim's i_CTRL-W.
Once you've put something in the kill ring with either of the above,
you'll likely want to "yank" (paste) it:
M-y ; yank-pop
(Note that C-S-backspace may not work in terminal Emacs.)
Install package whole-line-or-region and then run (whole-line-or-region-global-mode). This will make C-w kill the whole line if no region (selection) is active.
See the Package's GitHub page https://github.com/purcell/whole-line-or-region