Automatic insertion of a colon after 'def', 'if' etc
Question:
I recently switched to Vim at the request of a friend after Sublime Text 2 decided it didn’t believe a module was installed even though it was…I digress.
I’ve managed to set up some stuff to make editing Python (currently me only language) easier. However, there’s one feature I’m missing from Sublime. It would automatically add a colon to the end of lines which require them (the beginning of function definitions, if statements etc.). This prevented countless annoying errors and I miss it 😛
I was wondering whether there was some sort of command I could put in .vimrc to do this.
An example:
If were to type def
, I would like vim to automatically insert a colon to make it def :
and place the cursor before the colon ready for me to type my function name.
Cheers and apologies if I’m being stupid in any way.
Answers:
Take a look at the old snipmate, the new snipmate and ultisnips. These plugins provide roughly similar “snippet-expansion” mechanisms modeled after TextMate’s system.
This snippet doesn’t do exactly what you are asking, but it may still be useful to you.
Basically, it puts a semicolon at the end of a line (if the line starts with predefined words, and the colon is not there yet) when you press Enter.
inoremap <cr> <c-r>=ColonCheck()<cr><cr>
fun! ColonCheck()
if getline(".") =~ '^s*(if|else|elif|while|for|try|except|finally|class|def)>.*[^:]s*$'
return ":"
else
return ""
endif
endfun
This is a rather hacky answer, but you can do a simple mapping like:
inoremap def def :<Esc>i
which would do exactly what you want. That is, when you type ‘def’, it interprets that as ‘def :’, then escapes back to normal mode (here you could move about a bit), then back to insert.
This works as well:
inoremap def def :<Left>
The problem, of course is that it will substitute defs whenever they appear, which is not ideal.
Rather than use imap
s like @CG Mortion’s answer suggests, I would strongly advise you to use iabbr
s for these sorts of small fixes instead.
With an imap
you would never be able to type “define” in insert mode unless you paused between pressing ‘d’, ‘e’, or ‘f’, or did one of a number of other hacky things to prevent the mapping from happening. With iabbr
the abbreviation is only expanded once a non-keyword character is pressed. iabbr def def:<left>
works exactly as you’d expect and it doesn’t have the drawbacks of imap
s.
As mentioned in other answers, I would also suggest you move on to a snippet engine once you decide that you want something a little more complex. They are very powerful and can save you loads of time.
Simlar problem: https://stackoverflow.com/a/6950427/875064
augroup PythonProgramming
au BufNewFile,BufRead,BufEnter *.py iabbr def def:<left>
augroup END
I use LunarVim and add to the config this line:
lvim.keys.insert_mode[":<Enter>"] = "<Esc>$a:<Enter>"
I recently switched to Vim at the request of a friend after Sublime Text 2 decided it didn’t believe a module was installed even though it was…I digress.
I’ve managed to set up some stuff to make editing Python (currently me only language) easier. However, there’s one feature I’m missing from Sublime. It would automatically add a colon to the end of lines which require them (the beginning of function definitions, if statements etc.). This prevented countless annoying errors and I miss it 😛
I was wondering whether there was some sort of command I could put in .vimrc to do this.
An example:
If were to type def
, I would like vim to automatically insert a colon to make it def :
and place the cursor before the colon ready for me to type my function name.
Cheers and apologies if I’m being stupid in any way.
Take a look at the old snipmate, the new snipmate and ultisnips. These plugins provide roughly similar “snippet-expansion” mechanisms modeled after TextMate’s system.
This snippet doesn’t do exactly what you are asking, but it may still be useful to you.
Basically, it puts a semicolon at the end of a line (if the line starts with predefined words, and the colon is not there yet) when you press Enter.
inoremap <cr> <c-r>=ColonCheck()<cr><cr>
fun! ColonCheck()
if getline(".") =~ '^s*(if|else|elif|while|for|try|except|finally|class|def)>.*[^:]s*$'
return ":"
else
return ""
endif
endfun
This is a rather hacky answer, but you can do a simple mapping like:
inoremap def def :<Esc>i
which would do exactly what you want. That is, when you type ‘def’, it interprets that as ‘def :’, then escapes back to normal mode (here you could move about a bit), then back to insert.
This works as well:
inoremap def def :<Left>
The problem, of course is that it will substitute defs whenever they appear, which is not ideal.
Rather than use imap
s like @CG Mortion’s answer suggests, I would strongly advise you to use iabbr
s for these sorts of small fixes instead.
With an imap
you would never be able to type “define” in insert mode unless you paused between pressing ‘d’, ‘e’, or ‘f’, or did one of a number of other hacky things to prevent the mapping from happening. With iabbr
the abbreviation is only expanded once a non-keyword character is pressed. iabbr def def:<left>
works exactly as you’d expect and it doesn’t have the drawbacks of imap
s.
As mentioned in other answers, I would also suggest you move on to a snippet engine once you decide that you want something a little more complex. They are very powerful and can save you loads of time.
Simlar problem: https://stackoverflow.com/a/6950427/875064
augroup PythonProgramming
au BufNewFile,BufRead,BufEnter *.py iabbr def def:<left>
augroup END
I use LunarVim and add to the config this line:
lvim.keys.insert_mode[":<Enter>"] = "<Esc>$a:<Enter>"