Vim script comparisson between a string and a filename-modifier - vim

so a very basic question, how can I compare a string with a file-name modifier like %:p:h. I got stuck because the comparisson always returns false
function! WhenEnter()
if expand("%:p:h") == fnameescape("C:\\tools\\neovim\\Neovim\\bin")
execute 'NERDTree "C:\Users\<user>\Desktop"<CR>'
execute ':NERDTreeToggle<CR>'
else
execute 'NERDTree "%:p:h"<CR>'
execute ':NERDTreeToggle<CR>'
endif
endfunction()
autocmd vimenter * :call WhenEnter()
I just want to begin NERDTree in my desktop by default if I just opened neovim with the executable "because if not it just directs to C:\tools\neovim\Neovim" and for especific files I just want it to be the current folder.
I have tried a LOT of things to make it work, expand,fnameespace etc but nothing seems to make that comparisson work

function! WhenEnter()
if expand("%:p:h") == "C:\\tools\\neovim\\Neovim\\bin"
execute 'NERDTree C:\Users\virgi\Desktop'
execute ':NERDTreeToggle'
else
execute ':NERDTree "%:p:h"'
execute ':NERDTreeToggle'
endif
endfunction()
that is actually how I managed it to work

The problem is not with the file-name modifier, but with using fnameescape - see :help fnameescape for cases where this function is needed. In your case,
if expand("%:p:h") == "C:\\tools\\neovim\\Neovim\\bin"
is correct (provided that the file path head is indeed C:\tools\neovim\Neovim\bin).
If still the if branch isn't executed, insert an echo expand("%:p:h") to see why.

Related

How to check syntastic's status?

I updated node with homebrew today and that meant that all the npm modules got blown away. This of course means that the jshint executable (e.g. obtained by npm install -g jshint) is no longer present so Syntastic just silently stopped checking syntax in my js files.
It didnt take me too long to notice, but I'd like to be able to know about this change. I'd like syntastic to display something (preferably in red) in the command statusline to the tune of Syntastic - cannot run jshint.
The simplest solution would be to edit the file
syntastic/syntax_checkers/javascript/jshint.vim
And change the function from
function! SyntaxCheckers_javascript_jshint_IsAvailable()
return executable('jshint')
endfunction
to
function! SyntaxCheckers_javascript_jshint_IsAvailable()
if executable('jshint') != 1
echohl Error
echo "Syntastic - cannot run jshint"
echohl None
endif
return executable('jshint')
endfunction
echohl sets the highlight color of echo to the hightlight group Error (which is most likely red but it may not be). Then it prints out the message you want to print when you save. However this is not on the status line.
It seems Syntastic unfortunately lacks the ability to report missing checkers with the visibility one could expect. Ideally such functionality should be added. For those not up for patching Syntastic, a possible workaround is to turn on debugging, search for strings known to be problematic and alert on them. E.g. by marking the first line with an error sign and bringing up the log in a new buffer. I added that to my .vimrc as shown below.
let g:syntastic_debug = 1
function! SyntasticCheckerNotFound()
redir => messages
silent messages
redir END
let pos = match(messages, "syntastic.*Checker.*is not available")
if pos != -1
new
setlocal buftype=nofile
put =messages
sign place 1 line=1 name=SyntasticError buffer=1
" goto pos
endif
let g:syntastic_debug = 0
endfunction
autocmd VimEnter <buffer> call SyntasticCheckerNotFound()
When running the function above on the VimEnter event, it only executes one time when vim is started and only on the first file provided as an argument. Far from perfect, but it could be good enough to decrease the time and effort required to determine broken linting due to missing checkers.

How to show the command that last executed in vim?

Sometimes when I write a wrong script, I really have no idea why it doesn't have the expected effects. For example, the following script:
nnoremap gr :call Look_For_String()<CR><C-L>
function! Look_For_String()
exe "grep -R " . expand("<cword>") . &dir
endfunction
The function is to search the current word under cursor in directory &dir, but it doesn't do as expected. So I want to know what command it executed.Is that possible?
What I would do in this case is replacing the :execute with :echomsg, re-source the script (:so %), and re-execute.
For more complex situations, you can set the 'verbose' option. With a value of 15, every Ex command is printed. Since the display often interferes with the script's functionality, it's often advisable to redirect the diagnostic output to a file by setting 'verbosefile', too.

Installing VIM command as a plugin

I have the following command run as a vim plugin under ~/.vim/plugin/autohighlight.vim
:autocmd CursorMoved * exe printf('match IncSearch /\<%s\>/', expand('<cword>'))
The thing is, it throws a bunch of errors anywhere except when I'm editing a file. (file Explorer, other windows)
Is there a way to tell the script to only take effect when a file is edited and not anywhere else in VIM?
You can try this one:
autocmd CursorMoved * :if filewritable(#%)==1 |
\ call matchadd('IncSearch', '\V\<'.escape(expand('<cword>').'\>', '\'), 10, 1) |
\endif
It will do highlighting only if current buffer name is a writable file (not directory). It will fail if you are editing something which uses BufWriteCmd to perform saving (for example, if you are editing file inside a zip archive).
By the way, can you provide these errors? I was able to get an error when I used :e ., but it was not related to the fact that you are observing a directory, it appeared just because you forgot to do escaping. If you have written escape(expand('<cword>'), '\/') instead of expand('<cword>') then such error would not appear.

Execute a script directly within vim/mvim/gvim

TextMate has a nice feature that allows you to execute a script from within the current context and shows you the output in a separate window. This lets you write and test code on the go. I'm almost certain there is a similar feature with MacVim/gVIM, but I'm not sure what it is. Currently I save my buffers to disk, then go to the command line and execute the script in that respect. How do I improve that workflow with vim?
You can do this in vim using the ! command. For instance to count the number of words in the current file you can do:
:! wc %
The % is replaced by the current filename. To run a script you could call the interpreter on the file - for instance if you are writing a perl script:
:! perl %
vim tutorial: Mapping keys in Vim
You can map keys so perl executes current script as suggested by jts above.
map <C-p> :w<CR>:!perl %<CR>
will map Ctrl+P to write file and run it by perl
imap <C-p> <Esc>:w<CR>:!perl %<CR>
lets you call the same in insert mode.
You should have .vimrc (_vimrc for Windows) file in your vim/home folder. It has instructions on how vim should behave.
map <C-p> :w<CR>:!perl %<CR> is just instruction to map Ctrl+p to:
a) write current the file :w
b) run command (perl) using % (currently open file) as parameter :!perl %
<CR> after each command stands for "carriage return": an instruction to execute specific command. imap does the same as map but listens Ctrl+p while in insert mode.
You could run it right from vim:
:!./script.sh
All suggestions here merely showcased :!{cmd} %, which passes current buffer to the shell cmd.
But there is another option :write !{cmd}
For example, the effect of the :write !sh command is that each line of the current buffer is executed in the shell.It is often useful, when for instance you've added a couple of lines to you buffer, and want to see execution result immediately without saving the buffer first.Also it is possible to execute some range, rather than whole content of the buffer::[range]write !{cmd}
save the file and call the script using an interpreter
eg.:
:!python %
It sounds like you're looking for !:
:!{cmd} Execute {cmd} with the shell.
You can use % to denote the current filename, if you need to pass it to the script:
!proofread-script %
You can also use ! with a range, to use the command as a filter:
!{motion}{filter} " from normal mode
:{range}!{filter} " from command mode
(In the first case, as with many other commands, when you type the motion, it'll pass you into command mode, converting the motion into a range, e.g. :.,.+2!)
And finally, if you don't actually need to pass input from your file, but want the output in your file, that's essentially a trivial filter, and the fastest way to do it is !!{cmd}. This will replace the current line with the output of the command.
To execute the current executable script, use
:!./%
! executes a shell command, % is the current filename and ./ adds the current dir in front.
Put this small snippet in your .vimrc to execute the current file with one keystroke (like F5) and display the result in a new split-pane buffer.
:! is okay but you need to switch to your terminal to see the result.
While you can do that with ctrl-z and bring vim back with fg it still means you need to switch context a lot.
The way this snippet works is by first guessing the executable based on the filetype and then running it with the current file as its argument.
Next a handy utility method takes the output and dumps it into a new buffer.
It's not perfect, but really fast for common workflows.
Here's the snippet copied below:
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"""""""""""""""""""""""""" RUN CURRENT FILE """""""""""""""""""""""""""""
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Execute current file
nnoremap <F5> :call ExecuteFile()<CR>
" Will attempt to execute the current file based on the `&filetype`
" You need to manually map the filetypes you use most commonly to the
" correct shell command.
function! ExecuteFile()
let filetype_to_command = {
\ 'javascript': 'node',
\ 'coffee': 'coffee',
\ 'python': 'python',
\ 'html': 'open',
\ 'sh': 'sh'
\ }
let cmd = get(filetype_to_command, &filetype, &filetype)
call RunShellCommand(cmd." %s")
endfunction
" Enter any shell command and have the output appear in a new buffer
" For example, to word count the current file:
"
" :Shell wc %s
"
" Thanks to: http://vim.wikia.com/wiki/Display_output_of_shell_commands_in_new_window
command! -complete=shellcmd -nargs=+ Shell call RunShellCommand(<q-args>)
function! RunShellCommand(cmdline)
echo a:cmdline
let expanded_cmdline = a:cmdline
for part in split(a:cmdline, ' ')
if part[0] =~ '\v[%#<]'
let expanded_part = fnameescape(expand(part))
let expanded_cmdline = substitute(expanded_cmdline, part, expanded_part, '')
endif
endfor
botright new
setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap
call setline(1, 'You entered: ' . a:cmdline)
call setline(2, 'Expanded Form: ' .expanded_cmdline)
call setline(3,substitute(getline(2),'.','=','g'))
execute '$read !'. expanded_cmdline
setlocal nomodifiable
1
endfunction
Well it depends on your OS - actually I did not test it on M$ Window$ - but Conque is one of the best plugins around there: http://code.google.com/p/conque/
Actually, it can be better, but works. You can embed a shell window in a vim "window".

vim filters and stdout/stderr

When I use :%! to run the contents of a file through a filter and the filter fails (it returns another code than 0) and prints an error message to stderr I get my file replaced with this error message. Is there a way to tell vim to skip the filtering if the filter returns an status code that indicates an error and/or ignore output the filter program writes to stderr?
There are cases where you want your file to replaced with the output of the filter but most often this behavior is wrong. Of course I can just undo the filtering with one keypress but it isn't optimal.
Also I have a similar problem when writing a custom vim script to do the filtering. I have a script that calls a filter program with system() and replaces the file in the buffer with its output but there doesn't seem to be a way to detect if the lines returned by system() where written to stdout or to stderr. Is there a way to tell them apart in vim script?
:!{cmd} Executes {cmd} with the shell and sets v:shell_error.
If you happen to set up mappings to call your filters, you could do something like the following:
function! UndoIfShellError()
if v:shell_error
undo
endif
endfuntion
nmap <leader>filter :%!/path/to/filter<CR>:call UndoIfShellError()<CR>
You can use Python to distinguish between stdout and stderr:
python import vim, subprocess
python b=vim.current.buffer
python line=vim.current.range.start
python p=subprocess.Popen(["command", "argument", ...], stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
python returncode=p.poll()
python if not returncode: b.append(("STDOUT:\n"+p.stdout.read()+"\nSTDERR:\n"+p.stderr.read()).split("\n"), line)
To Vim 7 were added new autocommand events: ShellCmdPost and ShellFilterPost
augroup FILTER_ERROR
au!
autocmd ShellFilterPost * if v:shell_error | undo | endif
augroup END
An alternative would be to run the filter command such as it modifies the file on disk.
For example, for gofmt (www.golang.org) I have these mappings in place:
map <f9> :w<CR>:silent !gofmt -w=true %<CR>:e<CR>
imap <f9> <ESC>:w<CR>:silent !gofmt -w=true %<CR>:e<CR>
Explanation:
:w - save file
:silent - avoid pressing enter at the end
% - passes the file to gofmt
-w=true - tells gofmt to write back to the file
:e - tells vim to reload modified file
This is what I ended up doing:
function MakeItAFunction(line1, line2, args)
let l:results=system() " call filter via system or systemlist
if v:shell_error
"no changes were ever actually made!
echom "Error with etc etc"
echom results
endif
"process results if anything needed?
" delete lines but don't put in register:
execute a:line1.",".a:line2." normal \"_dd"
call append(a:line1-1, l:result) " add lines
call cursor(a:line1, 1) " back to starting place
" echom any messages
endfunction
command -range <command keys> MakeItAFunction(<line1>,<line2>,<q-args>)
" or <f-args>, etc.
You can see my full code at http://vim.wikia.com/wiki/Perl_compatible_regular_expressions
It's complicated, but it works and when it's used, it's fairly transparent and graceful. Hope that helps in any way!

Resources