Right now I am trying to use the evil plugin in emacs so that I can have the editing capability of vim with the extensibility of emacs. Right now I'm trying to port over one of my favorite parts of my .vimrc: have space repeat whatever my last executed macro was. In my .vimrc it was simply
nore <Space> ##
I am trying to do the same thing in my .emacs file with
(define-key evil-normal-state-map " " (lambda () (interactive) (evil-execute-macro 1 "#")))
## repeats the last macro fine, however hitting space gives me the error
After 0 kbd macro iterations: No previous macro
I'm fairly new to lisp and evil so I'm sure I'm doing something very wrong and I would appreciate any help.
You can bind it similarly to vim:
(define-key evil-normal-state-map " " (kbd "##"))
Regarding your code: The second argument of evil-execute-macro should be a character, i.e. ?#. But this only holds if evil-execute-macro is called interactively because the content of the corresponding register is only retrieved in the interactive form.
This boils down to this: The correct call would be (evil-execute-macro 1 last-kbd-macro).
Related
This s-expression in my .emacs file does not produce the desired result:
(define-key global-map (kbd "C-=") 'djhaskin987-untab-to-tab-stop)
Why can't I bind a command to Ctrl+=?
EDIT for clarification:
I am using emacs23-nox on the standard build of urxvt-256colors for Debian, except that I have recompiled with --disable-iso405776 (or something to that effect) it so that Ctrl+Shift doesn't do the weird 'insert character' thing. I don't know if this affects anything. For example, C-M-i sends M-TAB, which I don't understand.
EDIT II:
I apologize for not making this clear. The function djhaskin987-untab-to-tab-stop has the line (interactive) in it. This part works.
The accepted answer in combination with the link in the first comment to it is enough to get started on a complete solution. The steps are:
make your terminal output escape codes for the key
make Emacs recognise the escape codes as a standard keypress
bind the keypress in a mode map
The first is very terminal and/or operating system dependent.
The link in the first comment shows some examples for X Window System. The key names are available in /usr/X11R6/include/X11/keysymdef.h (or try locate keysymdef.h), prefixed with XK_ (which should be removed for our purposes). I read that symbolic names are preferred over key literals.
I don't currently run X but I think it should look like this in your case:
XTerm.VT100.Translations: #override \
Ctrl ~Meta ~Shift <Key> equal: string(0x1b) string("[emacs-C-=")\n
The first string is the escape, the second is of your choosing.
In iTerm you can use Preferences->Keys and choose Send Escape Sequence as the Action. For example, I have:
Emacs Wiki lists some configuration methods for other terminals.
Now you can teach Emacs to recognize it as a C-=. First define-key into input-decode-map. I have a couple of helper functions:
(defun my/global-map-and-set-key (key command &optional prefix suffix)
"`my/map-key' KEY then `global-set-key' KEY with COMMAND.
PREFIX or SUFFIX can wrap the key when passing to `global-set-key'."
(my/map-key key)
(global-set-key (kbd (concat prefix key suffix)) command))
(defun my/map-key (key)
"Map KEY from escape sequence \"\e[emacs-KEY\."
(define-key function-key-map (concat "\e[emacs-" key) (kbd key)))
So then:
(my/global-map-and-set-key "C-=" 'some-function-to-bind-to)
Some keys (currently: ()\|;'`"#.,) will need escaping in the string, like C-\..
In a terminal, TAB is represented by the same byte sequence as C-i. And typically the terminal has no special byte-sequence for C-=, so it will just send a =. There is nothing that Emacs can do about it. But you might be able to teach your terminal emulator to send some special byte sequence of your choice (check the documentation of your terminal emulator for that), after which you can teach Emacs to recognize it as a C-= (with something like (define-key input-decode-map "...thebytes..." [?\C-=])).
The problem is that you use emacs in the terminal.
The terminal does not allow "C-=".
Try your function in the graphical emacs and it will work.
You will have to find another keybinding for the terminal.
You can map C-= using the default ascii codes: ^[[61;5u. Then you can bind it in Emacs either using:
(global-set-key (kbd "C-=") 'djhaskin987-untab-to-tab-stop))
or let use-package do it, e.g.:
(use-package expand-region
:ensure t
:bind (("C-=" . er/expand-region)))
I do want to thank Sam Brightman, for his wonderful solution. It's a very clean, albeit heavy-handed, approach that will work for any keys that cannot be sent via normal ascii codes. I've been wanting to get C-TAB working inside iterm2 for a long time. I was able to do it by deleting the builtin preferences keys for C-TAB/C-S-TAB and using his approach. With the following, I can be ssh'd into remote Linux boxes and quickly switch through lots of open buffers in projects, just like a desktop editor.
(use-package nswbuff
:defer 1
:after (projectile)
:commands (nswbuff-switch-to-previous-buffer
nswbuff-switch-to-next-buffer)
:config
(progn
(my/global-map-and-set-key "C-TAB" 'nswbuff-switch-to-previous-buffer)
(my/global-map-and-set-key "C-S-TAB" 'nswbuff-switch-to-next-buffer))
:init
(setq nswbuff-display-intermediate-buffers t
nswbuff-exclude-buffer-regexps '("^ "
"^\*.*\*"
"\*Treemacs.*\*"
"^magit.*:.+")
nswbuff-include-buffer-regexps '("^*Org Src")
nswbuff-start-with-current-centered t
nswbuff-buffer-list-function '(lambda ()
(interactive)
(if (projectile-project-p)
(nswbuff-projectile-buffer-list)
(buffer-list)))))
The function you're binding must be interactive. Try:
(define-key global-map (kbd "C-=")
(lambda () (interactive) (djhaskin987-untab-to-tab-stop)))
I have the following code that attempts to create a new line and then jump to it. The idea is that move-end-of-line will jump to the end of the current line, and ["C-m"] would act as return/enter. Yet executing this command gives the error: "wrong number of arguments". How do I fix this?
(global-set-key (kbd "C-.") 'new-line)
(defun new-line ()
(interactive)
(move-end-of-line)
["C-m"]
)
I think you need to read the Emacs & elisp manuals: these questions are pretty easy to answer. Here's one way to do it.
(defun insert-line-after-line (&optional n)
(interactive "p")
(end-of-line 1) ;end of current line
(open-line n) ;open n new lines
(forward-line 1)) ;go to start of first of them
But seriously: Emacs has very extensive self-documentation, it is easy to find out how to do these things.
An option is to record a macro and use that.
M-x kmacro-start-macro
C-e
C-m
M-x kmacro-end-macro
If you don't care about the macro persisting, just run it:
C-x e
But if you want it to persist you would save it:
M-x name-last-kbd-macro new-line
M-x insert-kbd-macro new-line
and paste the output into your initialisation file (with your shortcut definition):
(global-set-key (kbd "C-.") 'new-line)
(fset 'new-line
[end return])
["C-m"] is like the way you specify a key for doing a key binding, but this is not the same as how you programmatically tell Emacs to insert a character into a document. You could use (insert-char ?\^M) (see ref here), but that would result in a literal ^M character (try it; another way to do the same thing interactively is Ctrl-Q followed by Ctrl-M). (insert "\n") seems to be what you're looking for.
Also, the reason you're getting the message "wrong number of arguments" is because (move-end-of-line) requires an argument when called out of interactive context. (move-end-of-line 1) works.
That said, possibly an easier way to achieve the result you're looking for is with the following setting:
(setq next-line-add-newlines t)
This will allow you to just do C-n at the end of the file and not worry about the distinction between moving and inserting.
I am a VIM guy - but evil-mode allowed me to productively use Emacs for my Scala development, and it did it so well that I am sort of hooked... I want to customize the environment to my liking, so I e.g. added these to my .emacs:
(define-key evil-normal-state-map (kbd "<f7>") 'ensime-typecheck-all)
(define-key evil-normal-state-map (kbd "C-]") 'ensime-edit-definition)
While in evil-normal-mode, the first line allows me to do a typecheck of my Scala code by just hitting F7, while the second one navigates me to a type/val definition via the muscle-memoried Ctrl-] (used for tags-based navigation in VIM).
My only problem is that what I've done so far is a "global" assignment - if I open a Python file, I'd want F7 to do a different thing (pyflakes or pylint). How can I assign different actions to the same key based on what kind of file is currently open in the buffer I am viewing?
In case it helps, in my .vimrc, I've done this via sections like these:
au BufNewFile,BufRead *.ml call SetupOCamlEnviron()
function! SetupOCamlEnviron()
se shiftwidth=2
"
" Remap F7 to make if the file is an .ml one
"
noremap <buffer> <special> <F7> :make<CR>
noremap! <buffer> <special> <F7> <ESC>:make<CR>
"
" Thanks to Merlin
"
noremap <buffer> <silent> <F6> :SyntasticCheck<CR>
noremap! <buffer> <silent> <F6> <ESC>:SyntasticCheck<CR>
inoremap <buffer> <C-Space> <C-x><C-o>
noremap <buffer> <C-]> :Locate<CR>
inoremap <buffer> <C-]> <ESC>:Locate<CR>
endfunction
How do I do this kind of thing in Emacs/evil?
EDIT: In search of a way to do this, I realized I can dispatch on different code when F7 is pressed in normal mode - so I wrote this Emacs lisp:
(defun current-buffer-extension ()
(if (stringp (buffer-file-name))
(file-name-extension buffer-file-name)
"Unknown"))
(defun handle-f7 ()
(interactive)
(if (string= (current-buffer-extension) "scala")
(ensime-typecheck-all)))
(define-key evil-normal-state-map (kbd "<f7>") 'handle-f7)
...which can be extended with other tool invocations as I learn more about Emacs, by adding actions based on the file extension.
Being completely new to Emacs, I am open to suggestions...
Am I on the right track here? Is there a better way to do what I want? Have I violated some principle by hooking evil-normal-mode keystrokes?
The thing you are looking for is called hook. There are plenty of hooks that emacs runs is specifics moments, and are fully customizable by user.
For instance, whenever entering a mode, a "mode-hook" is run. So you could do:
(add-hook 'python-mode-hook (lambda ()
(setq fill-column 79)
(local-set-key [(f3)] 'run-flake8)))
Hooks are the canonical way of customizing a lot of things in emacs, and there is plenty of examples around about those. In the example above, I define the key F3 to do something whenever I am in python mode.
Note that the example does not cope with evil keymap, but uses a local key that should have preference. If you want to assign a key to do different things depending on the evil state, you should either add some additional logic or make the evil-X-state-map buffer local and then change it the way you want (you could do that in the hook)
Edit: Regarding your question about if you have "violated some principle"... lets say that because of the hooks and the ability to set local variables, checking file extensions to customize behaviour is never (afaik) done other than for setting the mode (and that is done internally). Even checking the major-mode (that would be preferred to checking extension) is not done, as it is less scalable than just hooking preferences and functionality into modes.
Evil has a useful facility for mode-specific keybindings: evil-define-key. As arguments, it takes:
the state (as a quoted symbol, in your case, 'normal),
an unquoted keymap (I don't use ensime, but it's probably something like ensime-mode-map),
the key sequence, and
the command to bind.
So, to make your bindings ensime-specific (again, fiddle with the specific map name to make sure it's correct):
(evil-define-key 'normal ensime-mode-map (kbd "<f7>") #'ensime-typecheck-all)
(evil-define-key 'normal ensime-mode-map (kbd "C-]") #'ensime-edit-definition)
You can also bind f7 to something else for use with python (again, tinker with the map names and commands accordingly):
(evil-define-key 'normal python-mode-map (kbd "<f7>") #'run-flake8)
(Aside: I'm using the sharp-quote (#', which is lisp-shorthand for "function") in front of command names rather than the plain quote ('). For your purposes the two are basically equivalent, but it's good to get in the habit of the former in case you start byte-compiling your setup files, as the byte-compiler will warn you if the function in question is undefined when you sharp-quote but not if you simple-quote. See a related discussion on the Emacs Stack Exchange site.)
This s-expression in my .emacs file does not produce the desired result:
(define-key global-map (kbd "C-=") 'djhaskin987-untab-to-tab-stop)
Why can't I bind a command to Ctrl+=?
EDIT for clarification:
I am using emacs23-nox on the standard build of urxvt-256colors for Debian, except that I have recompiled with --disable-iso405776 (or something to that effect) it so that Ctrl+Shift doesn't do the weird 'insert character' thing. I don't know if this affects anything. For example, C-M-i sends M-TAB, which I don't understand.
EDIT II:
I apologize for not making this clear. The function djhaskin987-untab-to-tab-stop has the line (interactive) in it. This part works.
The accepted answer in combination with the link in the first comment to it is enough to get started on a complete solution. The steps are:
make your terminal output escape codes for the key
make Emacs recognise the escape codes as a standard keypress
bind the keypress in a mode map
The first is very terminal and/or operating system dependent.
The link in the first comment shows some examples for X Window System. The key names are available in /usr/X11R6/include/X11/keysymdef.h (or try locate keysymdef.h), prefixed with XK_ (which should be removed for our purposes). I read that symbolic names are preferred over key literals.
I don't currently run X but I think it should look like this in your case:
XTerm.VT100.Translations: #override \
Ctrl ~Meta ~Shift <Key> equal: string(0x1b) string("[emacs-C-=")\n
The first string is the escape, the second is of your choosing.
In iTerm you can use Preferences->Keys and choose Send Escape Sequence as the Action. For example, I have:
Emacs Wiki lists some configuration methods for other terminals.
Now you can teach Emacs to recognize it as a C-=. First define-key into input-decode-map. I have a couple of helper functions:
(defun my/global-map-and-set-key (key command &optional prefix suffix)
"`my/map-key' KEY then `global-set-key' KEY with COMMAND.
PREFIX or SUFFIX can wrap the key when passing to `global-set-key'."
(my/map-key key)
(global-set-key (kbd (concat prefix key suffix)) command))
(defun my/map-key (key)
"Map KEY from escape sequence \"\e[emacs-KEY\."
(define-key function-key-map (concat "\e[emacs-" key) (kbd key)))
So then:
(my/global-map-and-set-key "C-=" 'some-function-to-bind-to)
Some keys (currently: ()\|;'`"#.,) will need escaping in the string, like C-\..
In a terminal, TAB is represented by the same byte sequence as C-i. And typically the terminal has no special byte-sequence for C-=, so it will just send a =. There is nothing that Emacs can do about it. But you might be able to teach your terminal emulator to send some special byte sequence of your choice (check the documentation of your terminal emulator for that), after which you can teach Emacs to recognize it as a C-= (with something like (define-key input-decode-map "...thebytes..." [?\C-=])).
The problem is that you use emacs in the terminal.
The terminal does not allow "C-=".
Try your function in the graphical emacs and it will work.
You will have to find another keybinding for the terminal.
You can map C-= using the default ascii codes: ^[[61;5u. Then you can bind it in Emacs either using:
(global-set-key (kbd "C-=") 'djhaskin987-untab-to-tab-stop))
or let use-package do it, e.g.:
(use-package expand-region
:ensure t
:bind (("C-=" . er/expand-region)))
I do want to thank Sam Brightman, for his wonderful solution. It's a very clean, albeit heavy-handed, approach that will work for any keys that cannot be sent via normal ascii codes. I've been wanting to get C-TAB working inside iterm2 for a long time. I was able to do it by deleting the builtin preferences keys for C-TAB/C-S-TAB and using his approach. With the following, I can be ssh'd into remote Linux boxes and quickly switch through lots of open buffers in projects, just like a desktop editor.
(use-package nswbuff
:defer 1
:after (projectile)
:commands (nswbuff-switch-to-previous-buffer
nswbuff-switch-to-next-buffer)
:config
(progn
(my/global-map-and-set-key "C-TAB" 'nswbuff-switch-to-previous-buffer)
(my/global-map-and-set-key "C-S-TAB" 'nswbuff-switch-to-next-buffer))
:init
(setq nswbuff-display-intermediate-buffers t
nswbuff-exclude-buffer-regexps '("^ "
"^\*.*\*"
"\*Treemacs.*\*"
"^magit.*:.+")
nswbuff-include-buffer-regexps '("^*Org Src")
nswbuff-start-with-current-centered t
nswbuff-buffer-list-function '(lambda ()
(interactive)
(if (projectile-project-p)
(nswbuff-projectile-buffer-list)
(buffer-list)))))
The function you're binding must be interactive. Try:
(define-key global-map (kbd "C-=")
(lambda () (interactive) (djhaskin987-untab-to-tab-stop)))
Cannot get to bind Enter to newline-and-indent in Emacs !!! Very annoying.
I already tried everything on the following thread by changing 'mode' to ruby and still nothing:
How do I make Emacs auto-indent my C code?
I know that the problem is the RETURN key, since if I bind to something else, works fine.
I tried [enter], (kbd "enter"), (read-kbd-macro "enter"), (kbd "RET")
Follow-up 1.
This is what I get from C-hkRET
RET runs the command newline, which is an interactive compiled Lisp
function.
It is bound to RET.
(newline &optional ARG)
Insert a newline, and move to left margin of the new line if it's blank.
If use-hard-newlines' is non-nil, the newline is marked with the
text-propertyhard'.
With ARG, insert that many newlines.
Call auto-fill-function' if the current column number is greater
than the value offill-column' and ARG is nil.
I dont know what to make of it or how to figure out if it's a global
or local binding that gets in the way. trying to remap C-j
also doesnt work.
As a previous comment says, use C-h k (describe-key) to see what the key is bound to at the point when it's not doing what you want. The (kbd "foo") syntax will be correct for whichever foo describe-key refers to it as.
Chances are that you are simply not defining that key in the appropriate keymap.
Note that major and minor mode keymaps take precedence over the global keymap, so you shouldn't necessarily be surprised if a global binding is overridden.
edit:
Myself, I have a hook function for common behaviours for all the programming modes I use, and it includes the sort of remapping you're after. The relevant part looks like this:
(defun my-coding-config ()
(local-set-key (kbd "RET") (key-binding (kbd "M-j")))
(local-set-key (kbd "<S-return>") 'newline)
)
(mapc
(lambda (language-mode-hook)
(add-hook language-mode-hook 'my-coding-config))
'(cperl-mode-hook
css-mode-hook
emacs-lisp-mode-hook
;; etc...
))
See Daimrod's answer for the explanation of why I'm re-binding RET to the current binding of M-j -- although I'm using comment-indent-new-line (or similar) instead of newline-and-indent (or similar), which does what I want in both comments and non-comments.
In Emacs 24, programming modes seem to derive from prog-mode, so you could probably (un-tested) reduce that list to prog-mode-hook plus any exceptions for third-party modes which don't yet do that.
As said earlier, use C-hkC-j because
C-j is the standard key to do newline-and-indent.
If you open a new file, activate ruby-mode and try the previous
command you will see why it doesn't work. Because ruby-mode doesn't
have newline-and-indent but rather
reindent-then-newline-and-indent. Yes that's stupid but you can either ask
to the maintener to change it, or accept it.
However I suggest you to use C-j to do it because
ruby-mode is not the only mode to do so, like paredit-mode which
uses paredit-newline.