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.
Related
How can I change a current working directory for a specific buffer and change it to a previous value for other buffers?
More precisely what I want to do is to have auto-commands for specific file types which will change a current working directory when a buffer containing the file type is active. And change it back when working with other buffers.
I had something like that in my vimrc:
autocmd BufEnter *.py :lcd%:p:h
autocmd BufLeave *.py :lcd-
The idea here is that I wanted to switch to file's directory when working on python files and switch to a previous directory when working on something else, e.g. text, vimL etc. Obviously, it didn't work. I also try using BufWinLeave, but it didn't change anything.
Can you point out what's wrong here? Or maybe there's an easier solution for that?
I think you could accomplish something similar with the following:
augroup CDRooter
autocmd!
autocmd BufWinEnter * if &filetype == 'python' | lcd %:p:h | else | lcd! | endif
augroup END
Note: I am not sure :lcd - will work well. Instead I use :lcd! to simply revert the window to using the global current working directory.
The basic idea is whenever you enter a window sniff the filetype and execute :lcd accordingly.
For more help see:
:h 'filetype'
:h BufWinEnter
:h :lcd
:h :augroup
:h :autocmd
:h :if
I'm trying to set a buffer-local variable to a global variable if the local variable is not defined using the following autocmd
au BufEnter * if !exists('b:Variable') | let b:Variable = g:Variable | endif
However, b:Variable is not getting defined. What am I doing incorrect here?
EDIT: To rephrase/clarify, b:Variable is being used in the file. The error is that b:Variable is not defined.
First of all, your autocommand is correct. It should work.
I see some reasons why it could fail:
g:Variable is not defined
Events are disabled, see :help eventignore (this is unlikely)
The autocommand-feature is not supported by your vim version (this is unlikely too). :version must list +autocmd.
My favorite: The autocommand is not sourced. Are you sure that your autocommand is active?
What does
:verbose autocmd BufEnter
say? If your autocommand is not listed, it is not active.
Or try something that is simpler and that gives direct feedback to see if autocommands with BufEnter generally work. For example
:au BufEnter * echom "Buffer Entered"
When I open some bash script files with vim it sometimes identifies them as conf files, that's okay, I can just correct that by setting the filetype to sh with :setf sh.
That great, except I've noticed that this doesn't fix things entirely:
Notice that shopt is properly highlighted on the left, but not on the right, where I manually set the filetype to sh.
This means that when a file is identified as bash or sh by vim, it sets the filetype to sh but then does some extra steps that I'm not doing when I set the filetype manually.
Any one know what that might be, and how I could fix it?
vim already recognizes many file types by default. Most of them work by file extensions, but in a case like this, vim will also analyze the content of the file to guess the correct type.
vim sets the filetype for specific file names like .bashrc, .tcshrc, etc. automatically. But a file with a .sh extension will be recognized as either csh, ksh or bash script. To determine what kind of script this is exactly, vim reads the first line of the file to look at the #! line.
If the first line contains the word bash, the file is identified as a bash script. Usually you see #!/bin/bash if the script is meant to be executed directly, for some other shell configuration file you should use the file extensions .bash.
The help in vim explains this as well at :help ft-bash-syntax. You can also use let g:is_bash=1 in your .vimrc to make bash syntax highlighting the default for all files with filetype=sh. If you want to look at the details, this is implemented in $VIMRUNTIME/filetype.vim.
It turns out that syntax/sh.vim includes specific highlighting for Korn, Bash and sh, you just have to tell it which you're using. This is done with b:is_kornshell, b:is_bash and b:is_sh respectively.
Depending on the situation I figure I'll use the following:
ftdetect/bash.vim:
au BufRead,BufNewFile *bash* let g:is_bash=1
au BufRead,BufNewFile *bash* setf sh
Modeline:
# vim:let g:is_bash=1:set filetype=sh:
Key Mapping
nmap <silent> <leader>b :let g:is_bash=1<cr> :setf sh<cr>
Similar to Peter Coulton's solution and documented as well as an alternative in the section "new-filetype" of the "filetype" Vim help the ~/.vim/filetype.vim file could contain the following code:
if exists("did_load_filetypes")
finish
endif
augroup filetypedetect
au! BufRead,BufNewFile *bash* let b:is_bash = 1 | setfiletype sh
augroup END
This approach has the following implications:
There is one ~/.vim/filetype.vim file instead of one for each file type under the ~/.vim/ftdetect directory.
The b:is_bash variable is set local to the buffer as opposed to global by referring to it as g:is_bash.
Try viewing the effective syntax setting
:windo echo b:current_syntax
(I kind of expect the first window to say bash, and the second to say sh...?)
Also try mucking with the synatx synchronisation:
:windo syn sync fromstart
:windo syn sync minlines=300
In general
:he syn-sync
for more information
PS.
A long shot, but some other highlighting might be interfering:
:windo se #/=''
:match none
:2match none
:3match none
what I am using now is ,
autocmd BufWritePost *.py !python PythonTidy.py % %
It really call the tidy programe and change the file, but the vim does not reload the new file.
And I do not want to install another plugin for it.
=======================
note: I found it's dangerous about this feature, PythonTidy will will output a empty file if the command faild, it means if you have syntax error, you will lose your file unless press "u" to get it,but you can't save before you fix syntax error.
I call :!PythonTidy % % manually after pylint complete now.
Use BufWritePre instead of BufWritePost and combine Vim range filtering with PythonTidy’s stdin/stdout mode.
autocmd FileType python autocmd BufWritePre <buffer> let s:saveview = winsaveview() | exe '%!python PythonTidy.py' | call winrestview(s:saveview) | unlet s:saveview
(The use of autocmd FileType python autocmd BufWritePre <buffer> makes this a bit more accurate than matching on a glob pattern: it means “any time a Python file is detected, install this autocmd for that buffer” – so it works independently of file name.)
Unfortunately this cannot preserve your cursor position if you undo the filtering. (You are filtering a whole-file range; when undoing a filter operation, the cursor jumps to the first line in the range; so you end up at the top of the file.) I was hoping to find a way to create a no-op undo state, before, so you could hit u twice and get back to the right place, but I can’t make that work as yet. Maybe someone else knows how.
hi the following fixed the cursor postion problem
function! PythonTidySaver()
let oldpos=getpos('.')
%!PythonTidy
call setpos('.',oldpos)
endfunction
autocmd! bufwritepost *.py call PythonTidySaver()
Based on :help :e:
*:e* *:edit*
:e[dit] [++opt] [+cmd] Edit the current file. This is useful to re-edit the
current file, when it has been changed outside of Vim.
This fails when changes have been made to the current
buffer and 'autowriteall' isn't set or the file can't
be written.
Also see |++opt| and |+cmd|.
{Vi: no ++opt}
So you'd need to use :e after updating the file externally. However, :! doesn't let you use | normally (see :help :!), so you need to wrap it:
autocmd BufWritePost *.py execute "!python PythonTidy.py % %" | e
(:autocmd doesn't interpret | normally either, which is why you don't need to escape it yet again.)
I turned on filetype plugin for some rails vim plugins I added, but a side effect of this seems to be that now autocommenting has been enabled in all filetypes (for instance, if I start a line with #, the next line, either by Enter in insert mode or O, etc. to enter insert mode, will also get a #).
I found a guide to disabling the auto-commenting formatoptions, and added the following to my .vimrc:
au FileType * setlocal formatoptions-=cro
However, I am still running into problems -- unless I explicitly :source .vimrc, (or enter the setlocal ... directly), it is not taking effect. I determined that this is the case because vim's ftplugins are overriding my options with their own.
I then found a second guide which talks about using an after ftplugin script to make changes after the ftplugin scripts have run, however their solution is to create symlinks for every single filetype in ~/.vim/after/ftplugin to a central file, and this seems to be kludgy to me.
Is there any way to create a generic after-ftplugin script or am I approaching this problem incorrectly? Any help would be appreciated.
How about an "after" plugin? Create a file in ~/.vim/after/plugin/ called noAutoComments.vim (or whatever) and place your autocmd in that?
Edit:
The reason this works? I'm only guessing here, but I have a feeling that the autocmd in the ~/.vimrc file is getting removed by some other file (but before the "after" files are getting sourced).
I ended up removing my ~/.vim directory and replaced my ~/.vimrc with the following 3 lines:
filetype plugin on
syntax on
au FileType * setlocal formatoptions-=cro
With only these lines in my ~/.vimrc and no ~/.vim/ directory, the autocmd seems to work as expected (Vim 7.1).
For any file that I edit:
:verbose set formatoptions?
formatoptions=ql
Last set from ~/.vimrc
I have yet to determine what file (plugin) is causing this issue however.
I've done some more investigation and it seems that the location of my autocmd within my .vimrc file determines if formatoptions will be overridden by vim's ftplugins or not. Using vim --noplugin to disable all external plugins, I found the following results:
If my vimrc looks like:
au FileType * setl fo-=cro
filetype plugin indent on
The result of :verbose set fo? is:
formatoptions=croql
Last set from /usr/share/vim/vim72/ftplugin/ruby.vim
However, if the lines in my vimrc are reversed:
filetype plugin indent on
au FileType * setl fo-=cro
The result of :verbose set fo? is:
formatoptions=ql
Last set from ~/.vimrc
... which is the desired result. So it seems that the autocmd needs to be specified after filetype plugins are enabled.
Another reason this might not be taking effect...
From :he :set-=:
When the option is a list of flags, {value} must be
exactly as they appear in the option. Remove flags
one by one to avoid problems.
I have
" Turn off auto-commenting
au FileType * setlocal formatoptions-=c
au FileType * setlocal formatoptions-=r
au FileType * setlocal formatoptions-=o
because I've run into this.
Using one of the various autocmd events to set the configuration option should work if you find the right one, but I'd start by running:
:verbose set formatoptions?
This will tell you where the option was set, which may make it easier to determine which autocmd to use. Alternatively, if you don't mind a bit of minor hacking, the way I'd probably do it is just to find out where it's set in the plugin and comment out that line (and make a note of it in case you ever upgrade the plugin). You could also contact the plugin's author and ask them to make it a configurable option.
For the available autocmd events, read this:
:help {event}
I have tried solutions proposed by many, but none of them worked for me, but I found one very simple workaround, namely, in your ~/.bash_aliases:
# vim without auto comment
alias vi="vi +'set fo-=cro'"
I was struggling with this issue and I finally works with the following lines:
syntax on
filetype on
filetype plugin on
au FileType * setlocal formatoptions-=cro
I think the key here is that the autocmd is place after the filetype plugin on.