.vimrc variables are not evaluated - vim

I am trying to create installation script for https://github.com/junegunn/vim-plug/wiki/tips
if empty(glob('~/.vim/autoload/plug.vim'))
let s:downloadurl = "https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim"
let s:destinedirectory = $HOME . "/.vim/autoload/"
let s:destinefile = s:destinedirectory . "plug.vim"
if !isdirectory(s:destinedirectory)
call mkdir(s:destinedirectory, "p")
echo "Created directory: " . s:destinedirectory
endif
if executable("curl")
silent !curl --location --fail --output s:destinefile --create-dirs s:downloadurl
else
silent !wget -o s:destinefile --force-directories s:downloadurl
endif
autocmd VimEnter * PlugInstall --sync | source $MYVIMRC
endif
But vim is not evaluating my variables, i.e., instead of running the command
wget -o /home/user/.vim/plug.vim --force-directories https://raw.githubusercontent...
It is running:
wget -o s:destinefile --force-directories s:downloadurl

You could use execute to evaluate the variables in commands. For your case:
silent execute '!wget -o '.s:destinefile.' --force-directories '.s:downloadurl
Here the dot is the string concatenation operator documented in :help expr-..

Related

How to set the permission of the file based one the suffix during creating using vim?

When I create a new python script, I usually want to make it executable. I can do it in two steps: first create the file using vim; the set the permission using chmod. The question is: is it possible to merge the two steps into one?
What I would like to see is: when I create the file from vim, it will check the suffix and set proper permissions (configurable). And I expect it also works for files like .sh, .exe... Thanks.
I use the following; it checks the file's shebang (e.g. #!/usr/bin/python) instead of the file extension.
" On the initial save, make the file executable if it has a shebang line,
" e.g. #!/usr/bin/env ...
" This uses the user's umask for determining the executable bits to be set.
function! s:GetShebang()
return matchstr(getline(1), '^#!\S\+')
endfunction
function! s:MakeExecutable()
if exists('b:executable') | return | endif
let l:shebang = s:GetShebang()
if empty(l:shebang) ||
\ executable(expand('%:p')) ||
\ ! executable('chmod')
return
endif
call system('chmod +x ' . shellescape(expand('%')))
if v:shell_error
echohl ErrorMsg
echomsg 'Cannot make file executable: ' . v:shell_error
echohl None
let b:executable = 0
else
echomsg 'Detected shebang' l:shebang . '; made file executable as' getfperm(expand('%'))
let b:executable = 1
endif
endfunction
augroup ExecutableFileDetect
autocmd!
autocmd BufWritePost * call <SID>MakeExecutable()
augroup END

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.

How to write a .vimrc function to match a filename in a given file and open it with the vsplit command?

I have a file called Index.txt with the following lines:
/Project/A/B/C/D/main.c
/Project/A/B/C/D/main_backend.c
/Project/A/B/C/D/main_frontend.c
I'd like to create a command called Fsearch to execute a search in Index.txt using regular expressions, match the first occurrence and execute :vsplit with it. For example, if I execute:
:Fsearch main_backend.c
Vim should execute:
:vsplit /Project/A/B/C/D/main_backend.c
and If I execute:
:Fsearch main*.c
Vim should execute:
:vsplit /Project/A/B/C/D/main.c
This is what I've tried so far but I'm pretty sure it could be improved:
function! CopyMatches(reg)
let l:file = grep -m 1 a:reg ~/Index.txt
echom l:file
if len(l:file) > 0
exec ':vsp ' . l:file
else
echom 'File not found: ' . l:file
end
endfunction
command! -nargs=* Fsearch call CopyMatches('<args>')
Any suggestion?
You could try this:
function! CopyMatches(reg)
execute "silent! grep!" a:reg " ~/Index.txt"
redraw!
let l:file = getqflist()
if len(l:file) > 0
let l:path_head = fnamemodify( "~/workspace", ":p" )
for l:item in l:file
let l:current_file = l:path_head . "/" . l:item["text"]
if match( l:current_file, getcwd() ) != -1
execute 'vsplit' fnamemodify( l:current_file, ":~:.")
return
endif
endfor
echom "File not found:" a:reg
else
echom "File not found:" a:reg
endif
endfunction
command! -nargs=* Fsearch call CopyMatches('<args>')
Explanation:
The :grep built-in command is a wrap used by Vim to execute an external grep (see :help grep for more information).
The :grep! form of the :grep command doesn't jump to the first match automatically (i.e., :grep! won't open Index.txt).
The :silent! command is used to suppress the default full screen grep output.
Vim uses quickfix list with :grep so you can get all occurrences from getqflist() function (see :help getqflist() for details)

Vim—make lines in a buffer enterable

I wrote the following one-liner command.
command! -nargs=? Gfind execute "split | enew | cd `git-pwd` | read !git ls-files | grep " . expand("<args>") . " " <bar>
(
git-pwd returns the current get repo's root or './'
#!/bin/bash
git-pwd() {
local root=$(git rev-parse --show-cdup 2>&1 )
[[ "$root" == "" ]] && { echo "./" && return; }
[[ "$root" == fatal:* ]] { echo "./" && return 1; }
echo "$root"
}
[[ "$BASH_SOURCE" == "$0" ]] && git-pwd "$#"
)
It allows me to do :Gfind regex and a split window opens up with the list of files whose path/name matches the regex. That I can use for navigation with gf.
I wonder if there's an easy way to make the returned files in that window enterable like in cwindow or NERDTree.
Alternatives
Use :Gedit with completion abbreviated paths. e.g. :Gedit f/b/b<tab> which will expand to :Gedit foo/bar/baz (Requires fugitive.vim)
Glob with :Gedit. e.g. :Gedit **/baz<tab>
Use a fuzzy finder like CtrlP.vim to jump around your project.
Use something like projectionist.vim to build navigation commands for a well structured project.
There are low tech solutions that use :find and 'path':
set path=.,**
nnoremap <leader>f :find *
These are not mutually exclusive as you can use all these methods as each have their own pro's and con's. I personally use projectionist.vim as my main navigation method.
Answer to your question
I would imagine the best thing would be to use the QuickFix list. Your command would populate the quickfix list with the files matching your pattern and then you can use :copen to actually see the files and move between them or use :cnext/:cprev type commands to move between files.
Put the following in your ~/.vimrc file:
command! -nargs=? Gfind call s:gfind(<q-args>)
function! s:gfind(pat)
let grepprg = &grepprg
let errorformat = &errorformat
let &grepprg = 'cd ' . shellescape(fugitive#repo().dir()) . ' && git ls-files | grep '
let &errorformat = '%f'
execute 'grep ' . a:pat
cwindow
let &grepprg = grepprg
let &errorformat = errorformat
endfunction
Notes: I have not tested this code. It also uses fugitive.vim, but you can use your git-cwd trick if you rather. You may want to remove cwindow command to depending on your workflow.

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

Resources