Create Command to Fix Indentation - vim

I am familiar with the = filter. == key sequence indents the current line, while gg=G indents the entire file. I am trying to create a command:FixIndentation to get a similar effect, to fix indentation in the entire file.
# vim documentation provides example to map to key
map <F7> gg=G<C-o><C-o>
# my attempt to map to a command fails
command ReIndent execute "gg=G"
:ReIndent
E492: Not an editor command: gg=G

add normal! to tell it to execute it in normal mode:
command ReIndent execute "normal! gg=G"

Related

Mapping a working substitute command to a shortcut via vimrc

The following substitute command works fine on the command line:
:s/\vlabel\{(\w|:)+}/nonumber
It searches for label{eq:xyz123} and replaces its occurence on the current line line with nonumber.
I would like to map this to a command via vimrc. I tried:
nnoremap <leader>nn :s/\vlabel\{(\w|:)+}/nonumber<CR>
but this gives the error:
E492: Not an editor command: :)+}/nonumber<CR>
What is the right way to effect this mapping?
You can use:
nnoremap <leader>nn :s/\vlabel\{(\w<bar>:)+}/nonumber<CR>
Note the use of <bar> instead of |. The error occurs because | is interpreted as a delimiter of commands; i.e., Vim is interpreting your command as if there were two separate lines:
nnoremap <leader>nn :s/\vlabel\{(\w
:)+}/nonumber<CR>
For more, you can read :help map-bar.

Regex in .vimrc throwing "Not an editor command"

I am trying to create a keybinding to delete all the commented lines in the file.
The following gives me the desirable result :g/^\(#\|$\)/d
I am declaring the binding as following in ~/.vimrc
nnoremap <leader>dcl :g/\v^(#|$)/d<cr>
It is throwing the following error:
E492: Not an editor command: $)/d<cr>
What is the proper way to declare a keybinding with regex?
Replace your binding by:
nnoremap <leader>dcl :g/\v^(#<bar>$)/d<cr>
Indeed, in scripts or in the command line, vim considers | characters as a command delimiter; so you have to replace it by <bar>.

VIM mapping an internal command

I can't figure out how to map an internal command in vim.
I want to map to the command :Indent, the action g=GG (indenting the whole document)
I did this :
:command Indent execute "g=GG"
And it doesn't seem to work.
I successfully mapped
:command Java execute ":!javac *.java; echo ' **** done **** ' "
but how do i make it compile only the file that i am working on.
gg=G is a normal mode command. You need to use :normal, here:
:command! Indent normal! gg=G
But… :Indent<CR> is much longer than gg=G so I'm not sure that's a good idea.
I don't understand the need either. Still, if you want a command, at least let's have it support ranges:
:command! -range=% -nargs=0 Indent <line1>,<line2>normal! ==

Re-execute command by :history option in VIM

How can you execute a command again listed in the
:history
option in vim. There are numbers shown. Is the only way to copy the command by hand, then re-enter it? Or is there something like in shell script.
:history is only there for you to look at it.
To re-execute a previous command, you have two options:
Use <Up> and <Down> at the command prompt:
:m10
(do stuff)
:<Up>
Use the "command-line window":
You can call it with q: and navigate with search and use the beautiful normal mode commands we all love.
Position the cursor on a line and hit <CR> to re-execute the command.
Edit a command and hit <CR> to execute the new command.
You can quit the command-line window with :q.
See :help cmdline-window.
I use q: shortcut in normal mode to open interactive command history window. You just move to the right command and execute it by pressing Enter. You can find more information and other ways of accessing history here.
What I like to do is type the first few characters in the command and press <UP>. For example if you want to repeat an edit command of the file file.txt you could:
:e fil<UP><ENTER>
If the first <UP> does not give you the command you want, keep pressing<UP> until you find the command you were looking for.
If Vim is compiled with +eval you can use histget( {history} [, {index}])
:exe histget('c', 15)
That isn't exactly convenient to type, so you can also create a user-defined command:
:com -nargs=1 HI exe histget('c', <args>)
Thereafter you can use HI {index} to execute the history entry:
:HI 15

vim: map command with confirmation to key

I've written a few macros in my .vimrc for the version control system I'm using (Perforce) (please don't suggest the perforce plugin for vim, I tried it and I don't like it). They all work fine except the revert macro, which breaks due to a confirmation prompt (which I need so I don't accidentally fat-finger my changes away). It currently looks like this:
map <F8> :if confirm('Revert to original?', "&Yes\n&No", 1)==1 | !p4 revert <C-R>=expand("%:p")<CR><CR><CR>:edit<CR> | endif
This causes bash to complain when vim tries to load the file:
bin/bash: -c: line 0: syntax error near unexpected token `('
Looking at the buffer bash sees, it looks like the error is that vim sends it everything after the first pipe, not just the part meant for bash. I tried a few alternatives but I can't seem to make it work. I've got it to show confirm dialog correctly when I removed the pipes and endif (using shorthand if), but then vim complains after the user gives a response.
I think you want something along these lines:
:map <F8> :if confirm('Revert to original?', "&Yes\n&No", 1)==1 <Bar> exe "!p4 revert" . expand("%:p") <Bar> edit <Bar> endif<CR><CR>
Remember that :map is a dumb sequence of keystrokes: what you're mapping F8 to has to be a sequence of keystrokes that would work if typed. A <CR> in the middle of the :if statement doesn't mean ‘and press Enter when executing the command at this point if the condition is true’; it means ‘press Enter here when in the middle of typing in the :if command’, which obviously isn't what you want.
Building it up a piece at time, from the inside out:
There's a shell command you sometimes want to run.
That shell command needs to be inside an :if to do the ‘sometimes’ bit, and so have an :endif following it.
After a literal ! everything following is passed to the shell, including | characters which normally signify the start of another Vim command. That's reasonable, because | is a perfectly good character to use in shell commands. So we need some way of containing the shell command. :exe can do this; it executes the supplied string as a command — and its argument, being a string, has a defined end. So the general form is :if condition | exe "!shell command" | endif.
Your shell command has an expression in it. Using :exe makes this easy, since you can simply concatenate the string constant parts of the command with the result of the expression. So the command becomes :exe "!p4 revert" . expand("%:p") — try that out on its own on a file, and check it does what you want before going any further.
Putting that inside the condition gives you :if confirm('Revert to original?', "&Yes\n&No", 1)==1 | exe "!p4 revert" . expand("%:p") | edit | endif — again try that out before defining the mapping.
Once you have that working, define the mapping. A literal | does end a mapping and signify the start of the next Vim command. In your original the mapping definition only went to the end of the condition (check it with :map <F8> after loading a file) and the !p4 part was being run immediately, on the Vim file that defines the mapping! You need to change each | in your command into <Bar>, similarly to how each press of Enter in your command needs writing as <CR>. That gives you the mapping above. Try it by typing it at the command line first, then do :map <F8> again to check it's what you think it is. And only then try pressing F8.
If that works, put the mapping in your .vimrc.
Use of the pipe to string multiple vim commands together is not particularly well-defined, and there are numerous eccentricities. Critically, (see :help :bar) it can't be used after a command like the shell command :! which sees a | character as its argument.
You might find it easier to use the system() function.
E.G.
:echo system("p4 revert " . shellescape(expand("%:p")))
The shellescape() wrapper is useful in case you have characters like spaces or quotes in the filename (or have cleverly named it ; rm -rf ~ (Don't try this at home!)).
In the interest of creating more readable/maintainable code, you may want to move your code into a function:
function Revert()
if confirm('Revert to original?', "&Yes\n&No", 1)==1
return system("p4 revert " . shellescape(expand("%:p")))
endif
endfunction
which you would access by using the :call or :echo command in your macro.

Resources