To insert mode from autocmd in Vim - vim

I am trying to create an autocommand that will create boiler plate comments and code for new Java source files. As a simple start, I have added the following two lines (only a new line after the first line below in the actual file) to my .vim/ftplugin/java.vim:
autocmd BufNewFile *.java
\ exe "normal O/*\r" . expand('%:t') . "\t" . strftime("%B %d %Y") .
"\r/\r\rpublic class " . expand('%:t:r') . " {\r\t\<Esc>i"
With the last part, \t\<Esc>i, I am trying to insert a tab and shift to insert mode automatically. I can't make the switch to insert mode work and have tried different permutations of two or more of \<Esc>, \<Insert>, "insert" , i and \t. What am I missing ?
I am using VIM 7.2 on Linux.

You could use the :startinsert command. Just execute it after the :normal command:
autocmd! BufNewFile *.java
\ exe "normal O/*\r" . expand('%:t') . "\t" . strftime("%B %d %Y") .
\ "\r/\r\rpublic class " . expand('%:t:r') . " {\r\t" |
\ startinsert!
Here's some more information on that: http://vimdoc.sourceforge.net/htmldoc/insert.html#:startinsert.

Related

Comment & Uncomment using same command - No plugin

I'm using a modified version of https://stackoverflow.com/a/1676672/618584
autocmd FileType php,styl,javascript let b:comment_leader = '// '
noremap <C-\> :<C-B>silent <C-E>s/^/<C-R>=escape(b:comment_leader,'\/')<CR>/<CR>:nohlsearch<CR>
"noremap <C-\> :<C-B>silent <C-E>s/^\V<C-R>=escape(b:comment_leader,'\/')<CR>//e<CR>:nohlsearch<CR>
I want to remove comments using the same command (see commented out line above). What I need to do is check if the line begins with '//' and if so, map the to removing the comment.
Any idea how to do this?
I was previously using tpope's commentary plugin, and to achieve what I wnt with that, I'd do:
" comments toggle
autocmd FileType php setlocal commentstring=\/\/\ %s
nmap <C-\> gcc
xmap <C-\> gcugin I'd do:
But again, I do not want to use a plugin because I only code in JS and PHP.
First, I would build abstractions via a custom function. Adding a custom command would make sense, too:
function! CommentToggle() range
silent execute a:firstline . ',' . a:lastline . 's/^/' . escape(b:comment_leader, '\/') . '/e'
"silent execute a:firstline . ',' . a:lastline . 's/^\V' . escape(b:comment_leader, '\/') . '//e'
endfunction
command! -range CT <line1>,<line2>call CommentToggle()|nohlsearch
noremap <C-\> :CT<CR>
With this, toggling just means checking (let's say the first line determines the on/off for all lines, i.e. you only operate on all-comments or nothing-commented) the line:
function! CommentToggle() range
if getline(a:firstline) =~ '^\V' . escape(b:comment_leader, '\')
silent execute a:firstline . ',' . a:lastline . 's/^\V' . escape(b:comment_leader, '\/') . '//e'
else
silent execute a:firstline . ',' . a:lastline . 's/^/' . escape(b:comment_leader, '\/') . '/e'
endif
endfunction

how to auto update file path in file header with autocmd in vi/vim?

I have a function in my .vimrc that automatically updates the file I'm currently editing with the timestamp (Modified) of the last 'save' (:w).
I would like to also update the Filename and Filepath. I have an autocmd that updates the filename (through expand("%"). As for the Filepath, from what I read in the documentation, using expand("%:p:h") should permit me to insert the path (excluding the filename), but it does not work.
Anybody can tell me how insert the Filepath in my header ?
Example of file header that I wish to update:
Modified: November 13 2016
Filename: myfile
Filepath: /home/me/path/tomyfile/
Code I have at the moment :
autocmd BufWritePre * call UpdHeader()
function! UpdHeader()
" update path <<<<<< DOES NOT WORK >>>>>>>
silent! execute "1," . 10 . "g/Filepath:.*/s//Filepath: " .expand("%:p:h")
" update filename <<WORKS>>
silent! execute "1," . 10 . "g/Filename:.*/s//Filename: " . expand("%")
" update last mod date <<WORKS>>
silent! execute "1," . 10 . "g/Modified:.*/s//Modified: " . strftime("%d %B %Y%t%t%T (%z)%tBy : ") . $USER
...
endf
thx!
M
You need to perform proper escaping on the filepath, as you use / both as a separator in :substitute, and the (Unix-style) replacement path also has / separators in it. :substitute would have alerted your via E488: Trailing characters, but you've :silent! it.
A quick fix would be switching of :substitute separators, hoping that # will never appear in a file path:
silent! execute "1," . 10 . "g/Filepath:.*/s##Filepath: " .expand("%:p:h")
Better do proper escaping:
silent! execute "1," . 10 . "g/Filepath:.*/s//Filepath: " .escape(expand("%:p:h"), '/\'. (&magic ? '&~' : ''))
Alternatively, you can replace with an expression:
silent! execute "1," . 10 . "g/Filepath:.*/s//\\='Filepath: ' .expand('%:p:h')"
Your filename expansion would benefit from that as well.

Autocmd bufnewfile causing "Trailing characters" error on relative paths

I am having issue with my .vimrc file. I have completed an autocommand for all python and sh files. I have included both below. All works as expected when using a direct path ie:
gvim test.py
If I use a path relative to the cwd, however, such as:
gvim ../test.py
I receive the following error:
Error detected while processing BufNewFile Auto commands for "*.{py,sh}"
E488: Trailing characters
Any ideas on how to fix this problem?
autocmd bufnewfile *.{py,sh}
\ let path = expand("~/bin/Templates/")|
\ let extension = expand("%:e")|
\ let template = path . extension|
\ let name = "John Doe" |
\ if filereadable(template)|
\ execute "silent! 0r" . template|
\ execute "1," . 10 . "g/# File Name:.*/s//# File Name: " .expand("%")|
\ execute "1," . 10 . "g/# Creation Date:.*/s//# Creation Date: " .strftime("%b-%d-%Y")|
\ execute "1," . 10 . "g/Created By:.*/s//Created By: " . name|
\ execute "normal Gdd/CURSOR\<CR>dw"|
\ endif|
\ startinsert!
autocmd bufwritepre,filewritepre *.{py,sh}
\ execute "normal ma"|
\ execute "1," . 10 . "g/# Last Modified:.*/s/# Last Modified:.*/# Last Modified: "
\ .strftime("%b-%d-%Y")
autocmd bufwritepost,filewritepost *.{py,sh}
\ execute "normal 'a"
The template for python files is as follows:
#!/usr/bin/python
# File Name: <filename>
# Creation Date: <date>
# Last Modified: <N/A>
# Created By: <Name>
# Description: CURSOR
First of all, let's have a look at :help 10.2:
The general form of the `:substitute` command is as follows:
:[range]substitute/from/to/[flags]
Please keep /[flags] in mind. Now when you enter gvim test.py in the command line, the following command is executed in Vim:
:s//# File Name: test.py
But when you enter gvim ../test.py Vim executes:
:s//# File Name: ../test.py
so Vim uses test.py as :substitute's flags and that's not the desired behavior.
What you need is to replace expand("%") with expand("%:t") to get only the file name. See :help expand() for details.

Using Uncrustify with VIM

In my vimrc I call Uncrustify by this command:
%!uncrustify -l CPP -c D:\uncrustify\default.cfg
After that on some code I get a Windows Fatal error:
But when I call uncrustify on the same code in the console using the -f option, there is no error.
How can I change my vimrc to avoid such errors in the future? What can invoke this error?
In order to integrate Uncrustify with Vim properly, add the following to your .vimrc:
" Restore cursor position, window position, and last search after running a
" command.
function! Preserve(command)
" Save the last search.
let search = #/
" Save the current cursor position.
let cursor_position = getpos('.')
" Save the current window position.
normal! H
let window_position = getpos('.')
call setpos('.', cursor_position)
" Execute the command.
execute a:command
" Restore the last search.
let #/ = search
" Restore the previous window position.
call setpos('.', window_position)
normal! zt
" Restore the previous cursor position.
call setpos('.', cursor_position)
endfunction
" Specify path to your Uncrustify configuration file.
let g:uncrustify_cfg_file_path =
\ shellescape(fnamemodify('~/.uncrustify.cfg', ':p'))
" Don't forget to add Uncrustify executable to $PATH (on Unix) or
" %PATH% (on Windows) for this command to work.
function! Uncrustify(language)
call Preserve(':silent %!uncrustify'
\ . ' -q '
\ . ' -l ' . a:language
\ . ' -c ' . g:uncrustify_cfg_file_path)
endfunction
Now you can either map this function (Uncrustify) to a combination of keys or you could do the convenient trick that I use. Create a file ~/.vim/after/ftplugin/cpp.vim where you can override any Vim settings particularly for C++ and add the following line there:
autocmd BufWritePre <buffer> :call Uncrustify('cpp')
This basically adds a pre-save hook. Now when you save the file with C++ code it will be automatically formatted by Uncrustify utilizing the configuration file you supplied earlier.
For example, the same could be done for Java: in ~/.vim/after/ftplugin/java.vim add:
autocmd BufWritePre <buffer> :call Uncrustify('java')
You got the point.
NOTE: Everything presented here is well-tested and used every day by me.
I have found the placing the following code into your .vimrc to be sufficient:
let g:uncrustifyCfgFile = '~/.uncrustify.cfg'
function! UncrustifyFunc(options) range
exec a:firstline.','.a:lastline.'!uncrustify '.a:options
\.' -c '.g:uncrustifyCfgFile.' -q -l '.&filetype
endfunction
command! -range=% UncrustifyRange <line1>,<line2>call UncrustifyFunc('--frag')
command! Uncrustify let s:save_cursor = getcurpos()
\| %call UncrustifyFunc('')
\| call setpos('.', s:save_cursor)
Note this does assume that you have "uncrustify" binary in your $PATH.
It also assumes your configure file is ~/.uncrustify.cfg however you can change that by modifiying the g:uncrustifyCfgFile variable.
To call run
:Uncrustify
It also works on ranges (which was what promoted me to make this function). Visual selection example:
:'<,'>UncrustifyRange
I have only tired it with C, CPP and JAVA (I assume others will work as well)
In addition to #Alexander Shukaev's answer, adding the following will perform a check for uncrustify config correctness and not auto format if error is detected:
let output = system('uncrustify -q -c ' . a:cfgfile)
if v:shell_error != 0
echo output
endif
return v:shell_error
endfunction
" Don't forget to add Uncrustify executable to $PATH (on Unix) or
" %PATH% (on Windows) for this command to work.
function! Uncrustify(language)
if CheckUncrustifyCfg(g:uncrustify_cfg_file_path)
echo "Config file" g:uncrustify_cfg_file_path "has errors"
echo "No formatting will be performed"
return
endif
call Preserve(':silent %!uncrustify'
\ . ' -q '
\ . ' -l ' . a:language
\ . ' -c ' . g:uncrustify_cfg_file_path)
endfunction

Configure Vim to insert text for Lines of Code

I'm using Vim for all program editing and I have a standard header I use at the top of all my source code files. I have a .vimrc file set up to update certain fields in this header (like Last Modified) when I save any changes using :w
My question is, how do I put in a function to count lines of code, following the basic rule that only non-blank lines are counted?
I know within an open vim buffer, I can use
:%s/\n//gn
to count all lines, and
:%s/\n\n//gn
to count blank lines (basically count how many times two newlines appear in a row, indicating a blank line). But how do I put this in my .vimrc file?
Here's the code fragment from my .vimrc that updates the header fields:
function! LastModified()
if &modified
let save_cursor = getpos(".")
let n = min([20, line("$")])
keepjumps exe '1,' . n . 's#^\(.\{,10}Last Modified:\).*#\1' .
\ strftime(' %a %b %d, %Y %I:%M%p') . '#e'
keepjumps exe '1,' . n . 's#^\(.\{,10}Filename:\).*#\1' .
\ ' ' . #% . '#e'
keepjumps exe '1,' . n . 's#^\(.\{,10}LOC:\).*#\1' .
\ ' ' . '' . '#e'
call histdel('search', -1)
call setpos('.', save_cursor)
endif
endfun
Also, I would just like to add, I know there are numerous other ways to do this (like using wc --lines from the shell) but I'm interested in learning how to really configure my editor (so call it a learning exercise).
You actually should not want to use :s here:
function! CountNonEmpty()
return len(filter(getline(1, line('$')), '!empty(v:val)'))
endfunction
By the way, I would have used getline+map+setline to implement your header updater:
function! LastModified()
if &modified
" If number of buffer lines is < 20, then getline(1, 20)"
" will return only existing lines without any errors "
call setline(1, map(getline(1, 20), 'substitute(substitute(substitute(v:val, '.
\'"^\\v(.{,10}Last Modified:).*", "\\1 ".strftime("%s %b %d, %Y %I:%M%p"), ""),'.
\'"^\\v(.{,10}Filename:).*", "\\1 ".escape(#%, "&\\~"), ""),'.
\'"^\\v(.{,10}LOC:).*", "\\1 ", "")'))
endif
endfunction
This might help:
function! CountNonEmpty()
redir => g:nonblank
silent %s/^.\+$/&/n
redir END
return substitute(g:nonblank, '\n\s*\(\d\+\)\D.*$', '\1', '')
endfunction
:redir => Stores the output of the following ex commands into the given variable. See :help :redir

Resources