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.
Related
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.
Let's say I have the following in my .vimrc:
au bufenter * RainbowParenthesesToggle
However I'm on a unfamiliar machine and I haven't installed all of my plugins yet. This means when I start up Vim I get this error message:
E492: Not an editor command: RainbowParenthesesToggle
How can I guard against this, or what if statement do I want to wrap these calls in to avoid getting this error message when I start Vim?
suppress
The easiest would be to just suppress the error message via :silent! (note the !):
:au bufenter * silent! RainbowParenthesesToggle
check each time
It's cleaner (especially for an autocmd that runs on each BufEnter) to avoid the call. The existence of a command can be checked with exists(':RainbowParenthesesToggle') == 2.
:au bufenter * if exists(':RainbowParenthesesToggle') == 2 | RainbowParenthesesToggle | endif
avoid definition
It would be best to check only once, and avoid defining the autocmd at all. The problem is that your ~/.vimrc is sourced before the plugins! There are two ways around this:
1) Explicitly source the plugin before the check:
runtime! plugin/rainbowparentheses.vim
if exists(':RainbowParenthesesToggle') == 2
au bufenter * RainbowParenthesesToggle
endif
2) Move the definition and conditional to a location that is sourced after the plugins. ~/.vim/after/plugin/rainbowparentheses.vim would be a good place for this.
You can check for the command using exists():
au bufenter * if exists(":RainbowParenthesesToggle") | RainbowParenthesesToggle | endif
(I have no such command defined myself, so I can verify that this works. :) )
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!
How should I load colorscheme so that I can use lucius colorscheme only on my local machine?
http://www.vim.org/scripts/script.php?script_id=2536
This colorscheme declares a few functions to change color styles. So I tried to write my setting as following not to harm remote environment that using same vimrc file:
silent! colorscheme lucius | LuciusBlackHighContrast
But it seems like the silent! always returns success, it turns out the line giving me an error: E492: Not an editor command: LuciusBlackHighContrast.
I just wanted to make it like: colorscheme lucius >/dev/null && LuciusBlackHighContrast.
All suggestions are appreciated.
The bar is just a separator, not a boolean operator; and both colorscheme and silent! are commands, not returning any value. This is not bash :) Try this:
let v:errmsg = ""
silent! colorscheme lucius
if v:errmsg == ""
LuciusBlackHighContrast
endif
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.