Suppose I define the following shortcut
(global-set-key (kbd "C-d C-j") "Hello!")
Is it possible to configure emacs so that if I type "C-d C-j C-j C-j" I will get "Hello! Hello! Hello!" rather than having to type "C-d C-j C-d C-j C-d C-j"?
I don’t think you can configure Emacs so that it does that for all commands. However, you can implement this functionality in the commands themselves. This is what is done for C-x e. Here is a macro I just wrote (guided by the standard definition of kmacro-call-macro in GNU Emacs 23.1.1) that makes it easy to add this functionality to your own commands:
(defmacro with-easy-repeat (&rest body)
"Execute BODY and repeat while the user presses the last key."
(declare (indent 0))
`(let* ((repeat-key (and (> (length (this-single-command-keys)) 1)
last-input-event))
(repeat-key-str (format-kbd-macro (vector repeat-key) nil)))
,#body
(while repeat-key
(message "(Type %s to repeat)" repeat-key-str)
(let ((event (read-event)))
(clear-this-command-keys t)
(if (equal event repeat-key)
(progn ,#body
(setq last-input-event nil))
(setq repeat-key nil)
(push last-input-event unread-command-events))))))
Here’s how you use it:
(defun hello-world ()
(interactive)
(with-easy-repeat
(insert "Hello, World!\n")))
(global-set-key (kbd "C-c x y z") 'hello-world)
Now you can type C-c x y z z z to insert Hello, World! three times.
If you are looking for something generic that works on all commands I cant see how that would work - how would emacs know if you are starting a new command or want to repeat the previous. A better example would be "C-c h", if you type "h" after that, should emacs repeat the command or insert a h?
That said, emacs already has a mechanism for this - the universal argument.
Try this key sequence:
C-u 3 C-d C-j
It is even fewer keypresses than C-d C-j C-j C-j C-j
Try something like this:
(global-set-key (kbd "C-c C-j") (lambda()
(interactive)
(insert "Hello!")
(message "Type j to print Hello!")
(while (equal (read-event) ?j)
(insert "Hello!"))
(push last-input-event unread-command-events)))
Idea taken from kmacro-call-macro
No. The sequence "ctrl-d ctrl-j" is what is bound to the string "Hello!" Emacs binds the sequence as a whole to the given string. Here's some good info on the topic:
Link
On the other hand, if you wanted just three instances of "Hello!", you could define that sequence C-d C-j C-d C-j C-d C-j as "Hello! Hello! Hello!", but it would be shorter to just define a simpler sequence for the string you want.
I use this all the time. You'll need library repeat.el (part of GNU Emacs) to use it.
(defun make-repeatable (command)
"Repeat COMMAND."
(let ((repeat-message-function 'ignore))
(setq last-repeatable-command command)
(repeat nil)))
(defun my-hello ()
"Single `hello'."
(interactive)
(insert "HELLO!"))
(defun my-hello-repeat ()
(interactive)
(require 'repeat)
(make-repeatable 'my-hello))
Now bind my-hello-repeat:
(global-set-key (kbd "") 'my-hello-repeat)
Now just hold down the home key to repeat HELLO!.
I use this same technique in multiple libraries, including Bookmark+, thing-cmds, and wide-n.
smartrep is all you want
(require 'smartrep)
(defvar ctl-d-map (make-keymap)) ;; create C-d map
(define-key global-map "\C-d" ctl-d-map)
(smartrep-define-key
global-map "C-d"
'(("C-j" . (insert "hello"))))
Related
I am using the following.
(global-set-key [f9] 'helm-do-grep-1)
But when I press f9, It complains wrong type argument. I just want it behavior like "C-u C-c h g" to grep recursively. But type so many keys is boring.
update:
I need to grep recursively. helm-do-grep run in non-recursive mode.
You can use
(global-set-key [f9]
(lambda ()
(interactive)
(let ((current-prefix-arg 't))
(call-interactively 'helm-do-grep))))
Upd. If you're interested: the version with kbd sequence
(global-set-key [f9]
(lambda ()
(interactive)
(let ((minibuffer-message-timeout 0))
(execute-kbd-macro (read-kbd-macro "C-u C-c h g C-x Q"))))
See the definition of C-x Q here https://stackoverflow.com/a/28435402/1937596
As the error message already points out, the function helm-do-grep-1 has one argument: https://github.com/emacs-helm/helm/blob/master/helm-grep.el#L810
Probably what you wanted is binding f9 to helm-do-grep which calls helm-do-grep-1 in return with the correct parameters (
https://github.com/emacs-helm/helm/blob/master/helm-grep.el#L1129)
(global-set-key [f9] 'helm-do-grep)
Update:
You can find several solutions to your question here: http://www.reddit.com/r/emacs/comments/2dxj69/how_do_make_helmdogrep_to_do_recursive_always/
To show another possibility you could also do the following:
(global-set-key [f5]
(lambda ()
(interactive)
(call-interactively (key-binding (kbd "C-c h g")))))
In that case, you call helm-do-grep using <f5> and the recursive approach with C-u <f5>. However, this approach will depend on your key bindings.
There are already some questions on the topic of repeatable emacs commands (i.e. the behaviour of C-x z [repeat-command], where each subsequent z repeats the last command), however, none of the automatic solutions can cope with non-prefix keybindings (My terminology: C-c p is a prefix keybinding with prefix C-c, the keystroke M-s-+ on the other hand is a non-prefix keybinding).
In my setup I have bound M-s-+ to text-scale-increase and M-s-- to text-scale-decrease. It would be nice to just hit + or - for repeated zooming after the initial command. This can be achieved by the following piece of elisp:
(defvar text-scale-temp-keymap (make-sparse-keymap))
(define-key text-scale-temp-keymap (kbd "+") 'text-scale-increase)
(define-key text-scale-temp-keymap (kbd "-") 'text-scale-decrease)
(defun text-scale-increase-rep (inc)
(interactive "p")
(text-scale-increase inc)
(set-temporary-overlay-map text-scale-temp-keymap t))
(defun text-scale-decrease-rep (inc)
(interactive "p")
(text-scale-decrease inc)
(set-temporary-overlay-map text-scale-temp-keymap t))
(global-set-key (kbd "M-s-+") 'text-scale-increase-rep)
(global-set-key (kbd "M-s--") 'text-scale-decrease-rep)
However, to repeat this code every time I want to create a repeatable keybinding is cumbersome and unnecessary. I'm asking for a way to automatise the task. Image this code
(make-repeatable-command 'text-scale-increase '(("+" . text-scale-increase)
("-" . text-scale-decrease)))
would create the command named text-scale-increase-rep and an overlay keymap named text-scale-increase-temporary-map with the corresponding keys.
I assume this is possible, but how?
Try this:
(defun defrepeatable (alist)
(lexical-let ((keymap (make-sparse-keymap))
(func (cdar alist)))
(mapcar (lambda(x) (define-key keymap (car x) (cdr x))) alist)
(lambda (arg)
(interactive "p")
(funcall func arg)
(set-temporary-overlay-map keymap t))))
(global-set-key (kbd "C-z")
(defrepeatable
'(("+" . text-scale-increase)
("-" . text-scale-decrease))))
An alternative --
You do not need all of that, if all you want to do is (a) define a repeatable command and (b) bind it to a (repeatable) key.
The solution I presented in the pages (1, 2) that you linked to, applies here too. The point of that solution was not that it is limited to use with a prefix key but that you can also use it to repeat a key that is on a prefix key.
Here is the same solution, applied to your example. You only need to define repeat-command once -- you can use it to define any number of repeatable commands.
(defun repeat-command (command)
"Repeat COMMAND."
(interactive)
(let ((repeat-previous-repeated-command command)
(last-repeatable-command 'repeat))
(repeat nil)))
(defun text-scale-increase-rep (inc)
(interactive "p")
(repeat-command 'text-scale-increase))
(defun text-scale-decrease-rep (inc)
(interactive "p")
(repeat-command 'text-scale-decrease))
(global-set-key (kbd "M-s-+") 'text-scale-increase-rep)
(global-set-key (kbd "M-s--") 'text-scale-decrease-rep)
Let's say I bind the key to a certain function as follows:
(global-set-key (kbd "C-c =") 'function-foo)
Now, I want the key binding to work as:
After I press C-c = for the first time, if I want to repeat the function-foo, I don't need to press C-c again, but simply repeat pressing =. Then, after I call the function-foo for enough times, I can just press keys other than = (or explicitly press C-g) to quit.
How to do this?
This may be the thing you are looking for:
(defun function-foo ()
(interactive)
(do-your-thing)
(set-temporary-overlay-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "=") 'function-foo)
map)))
There's a smartrep.el package that does exactly what you need. The documentation is a bit scarce but you can get a grip of how it's supposed to be used by looking into numerous emacs configs found on github. For example (taken from here):
(require 'smartrep)
(smartrep-define-key
global-map "C-q" '(("n" . (scroll-other-window 1))
("p" . (scroll-other-window -1))
("N" . 'scroll-other-window)
("P" . (scroll-other-window '-))
("a" . (beginning-of-buffer-other-window 0))
("e" . (end-of-buffer-other-window 0))))
This is what I use. I like it because you don't have to specify the repeating key.
(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."
(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")))
You want your function-foo to use set-temporary-overlay-map.
In addition to what #juanleon suggested, which uses set-temporary-overlay-map, here is an alternative that I use quite a bit. It uses standard library repeat.el.
;; This function builds a repeatable version of its argument COMMAND.
(defun repeat-command (command)
"Repeat COMMAND."
(interactive)
(let ((repeat-previous-repeated-command command)
(last-repeatable-command 'repeat))
(repeat nil)))
Use that to define different repeatable commands. E.g.,
(defun backward-char-repeat ()
"Like `backward-char', but repeatable even on a prefix key."
(interactive)
(repeat-command 'backward-char))
Then bind such a command to a key with a repeatable suffix, e.g., C-c = (for C-c = = = =...)
See this SO post for more information.
Is there a way to switch between buffers without having to go through the
buffer-list, or writing the name of the buffer that I want to switch to? More specific I wonder if emacs can tab between buffers much like how it is working in notepad++
Emacs 22.1 and higher supports the previous-buffer (C-x <left arrow>) and next-buffer (C-x <right arrow>) commands.
These two commands can be added to older Emacsen using this script.
I've never ended up using C-x <right> or C-x <C-right> much, because I find them cumbersome to repeat if I want to cycle past more than one buffer, so I've just written a couple of functions to let you continue to switch to next/previous-buffer with <C-right> and <C-left> if the last command was also a next/previous-buffer command.
e.g. C-x <C-left> <C-left> <C-left> <C-right> <C-left> would take you back three buffers, forward one, and backward again.
I've made the assumption that <C-left> & <C-right> are usually bound to forward/backward-word, and am calling those explicitly as the fallback.
(defun my-forward-word-or-buffer-or-windows (&optional arg)
"Enable <C-left> to call next-buffer if the last command was
next-buffer or previous-buffer, and winner-redo if the last
command was winner-undo or winner-redo."
(interactive "p")
(cond ((memq last-command (list 'next-buffer 'previous-buffer))
(progn (next-buffer)
(setq this-command 'next-buffer)))
((memq last-command (list 'winner-redo 'winner-undo))
(progn (winner-redo)
(setq this-command 'winner-redo)))
(t ;else
(progn (forward-word arg)
(setq this-command 'forward-word)))))
(defun my-backward-word-or-buffer-or-windows (&optional arg)
"Enable <C-left> to call previous-buffer if the last command
was next-buffer or previous-buffer, and winner-undo if the last
command was winner-undo or winner-redo."
(interactive "p")
(cond ((memq last-command (list 'next-buffer 'previous-buffer))
(progn (previous-buffer)
(setq this-command 'previous-buffer)))
((memq last-command (list 'winner-redo 'winner-undo))
(progn (winner-undo)
(setq this-command 'winner-undo)))
(t ;else
(progn (backward-word arg)
(setq this-command 'backward-word)))))
(global-set-key (kbd "<C-left>") 'my-backward-word-or-buffer-or-windows)
(global-set-key (kbd "<C-right>") 'my-forward-word-or-buffer-or-windows)
(I use Icicles for buffer switching, myself, but...)
If you want to repeat the previous command any number of times, just use C-x z z z z z z... In this case, e.g., C-x left C-x z z z...
If that's too cumbersome, bind (next|previous)-buffer to other, repeatable keys, as others have suggested.
But repeatable keys are in great demand. If you don't want to waste any, you can even put such commands on a prefix key, so that, e.g., you can do, e.g., C-x left left left... Here's a trick to do that (taken from the Bookmark+ code):
(defun my-repeat-command (command)
"Repeat COMMAND."
(let ((repeat-message-function 'ignore))
(setq last-repeatable-command command)
(repeat nil)))
(defun my-next-whatever-repeat (arg) ; `C-x right'
"Jump to the Nth-next whatever.
N defaults to 1, meaning the next whatever.
Plain `C-u' means start over at the first whatever (and no repeat)."
(interactive "P")
(require 'repeat)
(my-repeat-command 'next-whatever))
(define-key ctl-x-map [right] 'my-next-whatever-repeat
Although the following suggestion does use the buffer-list, Ivy (or Helm) and evil, I think it is a nice, nearly equivalent alternative to the common Ctrl-TAB way (incl. updating the buffer list) when using e.g. Spacemacs.
Of course the commands can be adapted to your personal config (vanilla Emacs)
(evil-global-set-key 'motion (kbd "<C-tab>") 'ivy-switch-buffer)
(evil-global-set-key 'insert (kbd "<C-iso-lefttab>") 'ivy-switch-buffer)
(define-key ivy-mode-map (kbd "<C-tab>") 'ivy-next-line-and-call)
(define-key ivy-mode-map (kbd "<C-iso-lefttab>") 'ivy-previous-line-and-call)
or for the equivalent for Helm
(evil-global-set-key 'motion (kbd "<C-tab>") 'helm-buffers-list)
(evil-global-set-key 'motion (kbd "<C-iso-lefttab>") 'helm-buffers-list)
(define-key helm-map (kbd "<C-tab>") 'helm-follow-action-forward)
(define-key helm-map (kbd "<C-iso-lefttab>") 'helm-follow-action-backward)
The keystring for the last command means Ctrl-Shift-tab in my keyboard. You can find the one to use with C-h k C-S-tab.
Indeed you still need to press RET or C-l after releasing <C-tab>.
For evil users using Helm, a possibly even nicer alternative is to bind helm-buffers-list to C-j and C-k, then set helm-follow-mode-persistent to t, and in the helm-buffers-list buffer activate helm-follow-mode with C-c C-f. Now you can switch (and preview) buffers with C-j and C-k.
I currently bind compile to C-x c. I know I can run compile in comint mode by using C-u C-x c but I'd prefer to just bind it to C-x c directly. I can't fathom how to do this without copying the whole of the compile function from compile.el, tweaking it and binding that. Is there a better way?
Edit: To clarify my sloppy language, I don't wish to bind C-x c whilst in comint mode. I wish to cause C-x c to run 'compile using comint mode. I currently have C-x bound to 'compile. I can do what I want by typing C-u C-x c but I'd prefer to just be able to type C-x c to do that.
I think this works...
(defun c-w-c ()
(interactive)
(call-interactively 'compile t (vector 21 (this-command-keys-vector))))
(global-set-key (kbd "C-x c") 'c-w-c)
the '21' prepended into the vector is the ctrl-u prefix key, and it seems to fool the compile function into thinking it was called with C-u C-x c.
Edit:
It didn't work, but this does:
(defun c-w-c ()
(interactive)
(setq current-prefix-arg '(4))
(call-interactively 'compile))
You can do something like this :
(global-set-key [(C-f5)] 'compile)
(global-set-key [(f5)] 'recompile)
It binds compile to C-f5 and each time you want to recompile with the same command as you've given in compile, just type f5. It works whatever the major mode you're currently in.
For your case, do like this :
(global-set-key [?\C-x ?c] 'compile)
Are you asking for this?
(define-key comint-mode-map (kbd "C-x c") 'compile)
This works too:
(define-key comint-mode-map (kbd "C-x c")
(lambda (command)
(interactive
(list
(let ((command (eval compile-command)))
(if (or compilation-read-command current-prefix-arg)
(compilation-read-command command)
command))))
(compile command t)))
It's ugly because it duplicates the "interactive" spec from the compile command.