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

Related

A quick way to repeatedly enter a variable name in Emacs?

I was just typing in this sort of code for Nth time:
menu.add_item(spamspamspam, "spamspamspam");
And I'm wondering if there's a faster way to do it.
I'd like a behavior similar to yasnippet's mirrors, except
I don't want to create a snippet: the argument order varies from
project to project and from language to language.
The only thing that's constant is the variable name that needs to be
repeated several times on the same line.
I'd like to type in
menu.add_item($,"")
and with the point between the quotes, call the shortcut and start typing,
and finally exit with C-e.
This seems advantageous to me, since there's zero extra cursor movement.
I have an idea of how to do this, but I'm wondering if it's already done,
or if something better/faster can be done.
UPD The yasnippet way after all.
Thanks to thisirs for the answer. This is indeed the yasnippet code I had initially in mind:
(defun yas-one-line ()
(interactive)
(insert "$")
(let ((snippet
(replace-regexp-in-string
"\\$" "$1"
(substring-no-properties
(delete-and-extract-region
(line-beginning-position)
(line-end-position))))))
(yas/expand-snippet snippet)))
But I'm still hoping to see something better/faster.
yasnippet can actually be used to create a snippet on-the-fly:
(defun yas-one-line ()
(interactive)
(let ((snippet (delete-and-extract-region
(line-beginning-position)
(line-end-position))))
(yas-expand-snippet snippet)))
Now just type:
menu.add_item($1,"$1")
and call yas-one-line. The above snippet is expanded by yasnippet!
You could try
(defvar sm-push-id-last nil)
(defun sm-push-id ()
(interactive)
(if (not sm-push-id-last)
(setq sm-push-id-last (point))
(text-clone-create sm-push-id-last sm-push-id-last
t "\\(?:\\sw\\|\\s_\\)*")
(setq sm-push-id-last nil)))
after which you can do M-x sm-push-id RET , SPC M-x sm-push-id RET toto and that will insert toto, toto. Obviously, this would make more sense if you bind sm-push-id to a convenient key-combo. Also this only works to insert a duplicate pair of identifiers. If you need to insert something else, you'll have to adjust the regexp. Using too lax a regexp means that the clones will tend to overgrow their intended use, so they may become annoying (e.g. you type foo") and not only foo but also ") gets mirrored on the previous copy).
Record a macro. Hit F3 (or possibly C-x (, it depends) to begin recording. Type whatever you want and run whatever commands you need, then hit F4 (or C-x )) to finish. Then hit F4 again the next time you want to run the macro. See chapter 17 of the Emacs manual for more information (C-h i opens the info browser, the Emacs manual is right at the top of the list).
So, for example, you could type the beginning of the line:
menu.add_item(spamspamspam
Then, with point at the end of that line, record this macro:
F3 C-SPC C-left M-w C-e , SPC " C-y " ) ; RET F4
This copies the last word on the line and pastes it back in, but inside of the quotes.

Changing window faster in Emacs (or repeating last shortcut with a single strike)

if I want to change windows in emacs I do C-x o and that's fine with me...but when I want to change window lots of times in a row C-x o is not so convenient...is there a way to change window with just one strike after first C-x o ?
and in general...is there a (single) strike that would repeat my last shortcut?
I use C-tab to switch windows:
(global-set-key [C-tab] 'other-window)
Holding down the Control key, you can jump windows repeatedly just by hitting the tab key.
EDIT: my original answer contained the following
I don't think there's a built-in way to repeat last command for basic commands like this ...
This is no longer true. Emacs now contains repeat.el, which allows for exactly the behaviour rabidmachine9 asked for.
The following code will create a repeating other-window, such that after pressing C-x o the first time, pressing o afterwards will continue moving to the next window.
(require 'repeat)
(defun make-repeatable-command (cmd)
"Returns a new command that is a repeatable version of CMD.
The new command is named CMD-repeat. CMD should be a quoted
command.
This allows you to bind the command to a compound keystroke and
repeat it with just the final key. For example:
(global-set-key (kbd \"C-c a\") (make-repeatable-command 'foo))
will create a new command called foo-repeat. Typing C-c a will
just invoke foo. Typing C-c a a a will invoke foo three times,
and so on.
See related discussion here:
http://batsov.com/articles/2012/03/08/emacs-tip-number-4-repeat-last-command/#comment-459843643
https://groups.google.com/forum/?hl=en&fromgroups=#!topic/gnu.emacs.help/RHKP2gjx7I8"
(fset (intern (concat (symbol-name cmd) "-repeat"))
`(lambda ,(help-function-arglist cmd) ;; arg list
,(format "A repeatable version of `%s'." (symbol-name cmd)) ;; doc string
,(interactive-form cmd) ;; interactive form
;; see also repeat-message-function
(setq last-repeatable-command ',cmd)
(repeat nil)))
(intern (concat (symbol-name cmd) "-repeat")))
(global-set-key (kbd "C-x o") (make-repeatable-command 'other-window))
The function make-repeatable-command than then be used to create other repeating commands, using the same template.
Check out windmove; it lets you just hold down a modifier key and press an arrow key to move to the window in that direction. I've been using it for years with the default modifier (shift) and strangely enough it doesn't interfere with my impulses to use shift-arrow text selection in other applications.
There's also an equivalent for frames, which I should really try...
You have, say, 10 windows in the frame, and you are doing M-x other-window a lots of times in a row, I take it you mean to jump from, say window #2 to window #8 and then on to window #1 and so on. By doing lots of other-window in a row, I would imagine you do nothing of importance until you reach the desired window.
See if universal-argument bound to C-u helps. In the 10 window frame, if you are in window #3 and want to go to window #9, you are hopping to the 6th next window. So you would do C-u 6 C-x o. Or, you could as well do C-u -4 C-x o and reach window #9 from window #3.
Bit late to the party, but there is also window-numbering (known as 'window-number' in MELPA).
This includes a window number in the modeline -1-, -2- etc, and provides M-1, M-2 etc key bindings to directly select them. Very quick.

How do I bind a key to "the function represented by the following key sequence"?

I'm just starting to learn emacs (woohoo!) and I've been mucking around in my .emacs quite happily. Unfortunately, I don't know Lisp yet, so I'm having issues with the basics.
I've already remapped a few keys until I fix my muscle memory:
(global-set-key (kbd "<f9>") 'recompile)
That's fine. But how can I tell a key to 'simulate pressing several keys'? For instance, I don't know, make <f1> do the same as C-u 2 C-x } (widen buffer by two chars).
One way is to look up that C-x } calls shrink-window-horizontally, and do some sort of lambda thing. This is of course the neat and elegant way (how do you do this?). But surely there's a way to define <f1> to send the keystrokes C-u 2 C-x }?
Sure there is, and it's the obvious way:
(global-set-key (kbd "<f1>") (kbd "C-u 2 C-x }"))
For anything long-term, I would recommend the approach shown by seh, as that will naturally be more robust in most situations. It requires a little more work and know-how, of course, but it's all worthwhile :)
angus' approach is like a cut-down version of the keyboard macros feature that gives Emacs its name (and slightly simpler to use than macros for the example in question). You should definitely be aware of macros, however -- they can be exceedingly useful, and for anything more complicated it quickly becomes far easier to record one dynamically than to write out all the individual keys manually.
Here's the summary I wrote myself of the most important bits:
;;;; * Keyboard macros
;; C-x ( or F3 Begin recording.
;; F3 Insert counter (if recording has already commenced).
;; C-u <n> C-x ( or F3 Begin recording with an initial counter value <n>.
;; C-x ) or F4 End recording.
;; C-u <n> C-x ) or F4 End recording, then execute the macro <n>-1 times.
;; C-x e or F4 Execute the last recorded keyboard macro.
;; e or F4 Additional e or F4 presses repeat the macro.
;; C-u <n> C-x e or F4 Execute the last recorded keyboard macro <n> times.
;; C-x C-k r Apply the last macro to each line of the region.
;; C-x C-k e Edit a keyboard macro (RET for most recent).
;; C-x C-k b Set a key-binding.
;;
;; If you find yourself using lots of macros, you can even name them
;; for later use, and save them to your init file.
;; M-x name-last-kbd-macro RET (name) RET
;; M-x insert-kbd-macro RET (name) RET
;;
;; For more documentation:
;; C-h k C-x (
;; M-: (info "(emacs) Keyboard Macros") RET
If we play with the example from the question, you'll see how some of these things tie together...
To begin with, you can define the macro with F3C-u2C-x}F4
You could then bind it temporarily to F1 with C-xC-kbF1 (actually that's not true if F1 is currently a prefix key for an existing keymap, as typing it interactively will simply prompt for the remainder. You can circumvent this in code with (global-set-key (kbd "<f1>") ...), but I would suggest sticking to the reserved bindings).
If you then use describe-key (C-hk) to examine what is bound to that key, Emacs will show you a (lambda) expression which you could copy to your init file if you so wished.
Alternatively, you could name the macro and ask Emacs to insert the code into the current buffer:
M-x name-last-kbd-macro RET (name) RET
M-x insert-kbd-macro RETRET
This code will look different to the lambda expression shown by describe-key, but if you evaluate the inserted macro, you'll see the equivalence. You can likewise show that the (kbd "...") expression also evaluates to the same value, and therefore these are all just alternative ways of doing the same thing.
(You can use the *scratch* buffer to evaluate the code by moving point after the end of the expression, and either typing C-xC-e to show the value in the minibuffer, or C-j to insert the value into the buffer).
Note that the 'inserted' code uses fset to assign the macro to a symbol. You could bind the macro to a key either by executing the (fset) and then assigning that symbol to a key with (global-set-key), or you could ignore the (fset) and simply assign the macro value directly. This, of course, is directly equivalent to angus' answer.
Edit: I've just noticed that there's a kmacro-name-last-macro function bound to C-xC-kn which is nearly identical in form to name-last-kbd-macro, but which generates the lambda expression form seen when using kmacro-bind-to-key (C-xC-kb) and describe-key.
I'll use shrink-window-horizontally as the example function, but you can generalize the idea to any bindings you'd like to define.
If you want to use two as the default amount to shrink the window, rather than one, try the following:
(global-set-key [f9]
(lambda (&optional n)
(interactive "P")
(shrink-window-horizontally (or n 2))))
That binds the F9 key to an interactive function accepting a prefix argument. If you just press F9, you'll pass no argument, which summons the default value of 2, as the parameter n will receive nil as an argument. However, if you press, say, C-u 10 F9, you'll pass ten as the argument for n. This allows you to use your binding more flexibly.
general-simulate-key from general.el works better (in my case a sequence with popups and changing keymaps that I couldn't get to work with macros): https://github.com/noctuid/general.el#simulating-keypresses

Convert Emacs macro into Elisp

Is there a way to convert an emacs macro into elisp, not like what M-x insert-kbd-macro does, the actual activity becoming elisp statements.
Thanks for your help.
Nope, sorry. There is no trivial way to convert an emacs macro into elisp.
Update: There's been some work on Emacs to start down this path. See this thread as a starting point. It's still not possible (June 2010), but there's activity.
The first reason I can think of is dealing with interactive commands and translating keystrokes into proper arguments for functions.
Think of the following sequence:
C-x b .em TAB RET
This begins the command to switch to a buffer, types three characters, uses TAB completion to complete it and RET to accept. The equivalent lisp for the end result (in an emacs session where the TAB completion is unique) is:
(switch-to-buffer ".emacs")
Thinking of completion, there are also interactions with expansion of all types (dabbrev, hippie-expand, etc.).
A starting point can be M-x edit-last-kbd-macro which (in my case) shows this:
;; Keyboard Macro Editor. Press C-c C-c to finish; press C-x k RET to cancel.
;; Original keys: C-x b .em <tab> RET
Command: last-kbd-macro
Key: none
Macro:
C-x b ;; switch-to-buffer
.em ;; self-insert-command * 3
<tab> ;; pabbrev-expand-maybe
RET ;; newline-and-indent
Which at least gives you some of the function names. But you'll see that RET is labeled as 'newline-and-indent which is incorrect because at the time of the macro execution, the minibuffer is active and the binding is in fact 'minibuffer-complete-and-exit. Similarly, the proper binding for TAB is 'minibuffer-complete.
I made a package that allows pretty much exactly this at https://github.com/Silex/elmacro
It has some quirks but it works pretty well... for example, the following macro:
F3 C-e M-b M-u C-a C-n F4
Generates the following elisp:
(defun upcase-last-word ()
"Change me!"
(interactive)
(move-end-of-line 1)
(backward-word 1)
(upcase-word 1)
(move-beginning-of-line 1)
(next-line 1 1))

Emacs equivalent of Vim's yy10p?

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.