How to check syntastic's status? - vim

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.

Related

Exclude help and plugin pages from autocmd pattern

I want to write command like autocmd BufAdd * if &filetype != 'help' | echo 'foo', but it didn't work. I've tried different options: &l:filetype, &buftype, &l:buftype; tried with toggled filetype setting, but nothing changed. Global command autocmd BufAdd * echo 'bar' worked everywhere includes help pages, and the same time :echo &filetype on help pages returns help. What am I doing wrong?
Because,
While in BufAdd the current buffer can be (and quite probably is) different from the matched buffer;
While in BufAdd the matched buffer may (and quite probably will) not have any &filetype set yet.
Note that normally one should hook into some specific FileType with ~/.vim/after/ftplugin/xyz.vim instead.

Vim script comparisson between a string and a filename-modifier

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.

Golang Formatter and Vim - How to destroy history record?

Go (Golang) programming language comes with a tool called go fmt. Its a code formatter, which formats your code automagically (alignments, alphabetic sorting, tabbing, spacing, idioms...). Its really awesome.
So I've found this little autocommand which utilizes it in Vim, each time buffer is saved to file.
au FileType go au BufWritePre <buffer> Fmt
Fmt is a function that comes with Go vim plugin.
This is really great, but it has 1 problem. Each time formatter writes to buffer, it creates a jump in undo/redo history. Which becomes very painful when trying to undo/redo changes, since every 2nd change is formatter (making cursor jump to line 1).
So I am wondering, is there any way to discard latest change from undo/redo history after triggering Fmt?
EDIT:
Ok, so far I have:
au FileType go au BufWritePre <buffer> undojoin | Fmt
But its not all good yet. According to :h undojoin, undojoin is not allowed after undo. And sure enough, it fires an error when I try to :w after an undo.
So how do I achieve something like this pseudo-code:
if lastAction != undo then
au FileType go au BufWritePre <buffer> undojoin | Fmt
end
If I get this last bit figured out, I think I have a solution.
I think this is almost there, accomplishes what you ask, but I see it's deleting one undo point (I think this is expected from undojoin):
function! GoFmt()
try
exe "undojoin"
exe "Fmt"
catch
endtry
endfunction
au FileType go au BufWritePre <buffer> call GoFmt()
EDIT
Based on MattyW answer I recalled another alternative:
au FileType go au BufWritePre <buffer> %!gofmt
:%!<some command> executes a shell command over the buffer, so I do it before writing it to file. But also, it's gonna put the cursor at top of file...
Here is my go at this. It seems to be working well both with read/write autocmds and bound to a key. It puts the cursor back
and doesn't include the top-of-file event in the undos.
function! GoFormatBuffer()
if &modifiable == 1
let l:curw=winsaveview()
let l:tmpname=tempname()
call writefile(getline(1,'$'), l:tmpname)
call system("gofmt " . l:tmpname ." > /dev/null 2>&1")
if v:shell_error == 0
try | silent undojoin | catch | endtry
silent %!gofmt -tabwidth=4
endif
call delete(l:tmpname)
call winrestview(l:curw)
endif
endfunction
I check modifiable because I use vim as my pager.
I attempted to use #pepper_chino's answer but ran into issues where if fmt errors then vim would undo the last change prior to running GoFmt. I worked around this in a long and slightly convoluted way:
" Fmt calls 'go fmt' to convert the file to go's format standards. This being
" run often makes the undo buffer long and difficult to use. This function
" wraps the Fmt function causing it to join the format with the last action.
" This has to have a try/catch since you can't undojoin if the previous
" command was itself an undo.
function! GoFmt()
" Save cursor/view info.
let view = winsaveview()
" Check if Fmt will succeed or not. If it will fail run again to populate location window. If it succeeds then we call it with an undojoin.
" Copy the file to a temp file and attempt to run gofmt on it
let TempFile = tempname()
let SaveModified = &modified
exe 'w ' . TempFile
let &modified = SaveModified
silent exe '! ' . g:gofmt_command . ' ' . TempFile
call delete(TempFile)
if v:shell_error
" Execute Fmt to populate the location window
silent Fmt
else
" Now that we know Fmt will succeed we can now run Fmt with its undo
" joined to the previous edit in the current buffer
try
silent undojoin | silent Fmt
catch
endtry
endif
" Restore the saved cursor/view info.
call winrestview(view)
endfunction
command! GoFmt call GoFmt()
I just have this in my .vimrc:
au BufWritePost *.go !gofmt -w %
Automatically runs gofmt on the file when I save. It doesn't actually reformat it in the buffer so it doesn't interrupt what I'm looking at, but it's correctly formatted on disk so all check ins are properly formatted. If you want to see the correctly formatted code looks like you can just do :e .
Doesn't do anything to my undo/redo history either
You can install the vim plugins from the default repository. Alternatively, a pathogen friendly mirror is here:
https://github.com/jnwhiteh/vim-golang
Then you can use the :Fmt command to safely do a go fmt!

Why might Vim quit when the ‘:bdelete’ command is run?

According to the answer of this question, the :bd command should not quit Vim (gVim) when it is the last buffer remaining. Unfortunately, it does close gVim in my case. Did I understand something wrong about :bd?
I am also using a preconfigured vimrc file. Maybe a setting in there has that side affect, but I couldn’t find it.
Try doing the following:
:set eventignore=all | bd | set eventignore=
If this won't quit vim then you have some plugin that defines an autocommand that quits vim when no more buffers are present in the list, so after that try doing
verbose autocmd BufWinLeave,BufLeave,BufDelete,BufUnload,BufWipeout
This will show you all autocommands attached to given events (these are events that are executed when buffer is deleted) and where they were defined. Note that I do not have any autocommands attached to these events that are defined by plugins in standart vim distribution.
Update: I do not see anything bad in your output. You may also try
verbose autocmd BufNew,BufAdd,BufCreate,BufEnter,BufWinEnter
(because when you leave last buffer new empty one is created). If this does not show anything suspicious, start ignoring event types: if you are on linux try the following script:
for event in BufWinLeave BufLeave BufDelete BufUnload BufWipeout BufNew BufAdd BufCreate BufEnter BufWinEnter
do
event=$event vim file -c "set eventignore=$event | bd"
done
This script should iterate until you find event name that causes trouble. After this you can use execute "verbose autocmd" $event in vim to narrow number of plugins that should be checked. After you got list of autocmd groups (augroup names are shown just before event name in your output: railsPluginDetect is one of such groups), delete events in them (augroup {GroupName} | execute 'autocmd!' | augroup END) and find out which plugin to claim.
Alternatively, you can use debugger:
debug bd
, then s<CR>n<CR><CR><CR>... until vim quits; don't forget to remember what vim have shown above > prompt before quiting.

Vim - prevent saving/writing a file if it contains certain string

I'd like to prevent Vim from saving a file if it contains the following text
:style=>
This could potentially be in multiple places in the file.
As a bonus if it could come up with an error message like "stop putting styles inline!" that would be great too ;)
Thanks!
PS : I would like this prevent action to be triggered upon attempting to write the file :w
One way
to do this is to "bind" the save (:w) command to a function that checks for your pattern:
autocmd BufWriteCmd * call CheckWrite()
where your Check() function could look like this:
function! CheckWrite()
let contents=getline(1,"$")
if match(contents,":style=>") >= 0
echohl WarningMsg | echo "stop putting styles inline!" | echohl None
else
call writefile(contents, bufname("%"))
set nomodified
endif
endfunction
Note that in this case you have to provide a "save-file" mechanism yourself (probably a not so good idea, but works well).
A safer way
would be to set readonly when your pattern appears:
autocmd InsertLeave * call CheckRO()
and issue the warning when you try to save:
autocmd BufWritePre * call Warnme()
where CheckRO() and Warnme() would be something like:
function! CheckRO()
if match(getline(1,"$"),":style=>") >= 0
set ro
else
set noro
endif
endfunction
function! Warnme()
if match(getline(1,"$"),":style=>") >= 0
echohl WarningMsg | echo "stop putting styles inline!" | echohl None
endif
endfunction
Highlight
It is also probably a good idea to highlight your pattern with a hi+syntax match command:
syntax match STOPPER /:style=>/
hi STOPPER ctermbg=red
Finally, have a look at this script.
It might be more typical to enforce restrictions like this through your VCS's commit hook. See, for example, http://git-scm.com/docs/githooks.
This would leave the capabilities of your editor intact while forbidding committing offending code.

Resources