I can use autocmd to make my cmd to run if file of specific file type loaded. For example for python:
autocmd FileType python make me happy with python
But is there any way to make my cmd to run if loaded file is NOT of specific type? Something like:
autocmd FileType !python make me happy without python
example above doesn't work and autocmd! will remove autocmd.
Any suggestions? Thanks.
There are several possibilities:
The easy way is to call a function and make your function check the filetype (and abort, if the filetype is python).
An alternative approach is to set a flag for python filetypes and make you function check the flag.
Use the * pattern and call your code only inside an if condition checking the filetype (something similar to this):
autocmd Filetype * if &ft!="python"|put your code here|endif
The hard way is to create a pattern, that doesn't match python. Something like this should do it:
:autocmd FileType [^p],[^p][^y],[^p][^y][^t],[^p][^y][^t][^h],[^p][^y][^t][^h][^o],[^p][^y][^t][^h][^o][^n] :put your code here
(the last part is untested and should illustrate, why usually any of the other possibilities are used).
You can make an autocmd which triggered by all (*) filetype, then call a function.
In the function, you can check the ft option (&ft) to decide what should be done for certain filetype. There you can do any matching logic with the value of &ft.
Related
I've recently installed the VimWiki plug-in, and am learning about Vim's plugin architecture in general (and better using directories like after/ftplugin instead of cramming everything into my .vimrc file).
I would like to call a function prior to writing wiki files, like so:
autocmd BufWrite *.wiki call CleanMarkdown()
However, vimwiki sets its own BufWrite autocommand, which updates any tables-of-contents in the wiki file. I could clobber this autocommand with my own function that calls both the CleanMarkdown() plus whatever vimwiki is doing today, but that would be brittle in the face of possible future changes in the vimwiki plugin.
Is there a standard way to add to the list of things to do for a BufWrite autocommand?
Multiplicity of autocmds
There can be many :autocmds for any event; the command is cummulative. The corresponding :autocmd! removes certain sets of commands (depending on the arguments given to it).
If you don't specify a [group], the autocmd will be defined in the global space, and there's a high risk of getting this cleared by some :autocmd!. Therefore, it is recommended to specify a [group] (especially in plugins). With this, you avoid that another (mis-behaving) plugin or customization clobbers your autocmd.
Integrating with vimwiki plugin
As the plugin already defines its own filetype, you don't need to duplicate the filetype detection logic, i.e. the *.wiki pattern. Instead, if you put your :autocmd definition in ~/.vim/after/ftplugin/vimwiki.vim, you can use the <buffer> special pattern to make this autocmd apply only to the current (VimWiki) buffer.
augroup MyVimWikiCleanup
autocmd BufWrite <buffer> call CleanMarkdown()
augroup END
Ordering
The :autocmds are executed in the order in which they were defined. By using the after directory, yours will be executed after the plugin's.
I found this nice plugin for distraction free writing named Goyo, which is really well done.
I setup autocmds to enable Goyo based on the filetype, so if I work on a markdown or textfile Goyo gets initialized automatically. If I leave the buffer or change the filetype then Goyo gets closed. Below is how I implemented the behaviour:
autocmd FileType * :Goyo!
autocmd FileType markdown :Goyo
autocmd FileType text :Goyo
That seems to work fine. The question is, whether or not this is the way to go or if there is a better approach to solve the problem?
That's just fine and how I would implemented it, too. As you only hook into the FileType event, the toggling is only triggered when you :edit a new file, not when you recall an existing buffer with another filetype. You could do that with BufWinEnter, but it may cause too many inadvertent togglings. I guess the plugin comes with a quick toggle mapping to manually do this, anyway.
Alternative
An alternative to the autocmd FileType commands is filetype plugins (i.e. ~/.vim/ftplugin/markdown.vim etc.), which have the benefit of separating things neatly. But as you need a catch-all autocmd to turn off Goyo, and the list of filetypes is small, I would also prefer keeping things together, just like you did.
Improvements
Note that your set of commands would add a duplicate set of autocmds if you re-:source your ~/.vimrc (or whichever script you've put them in). To avoid that, you could wrap them in
augroup AutomaticGoyo
autocmd!
...
augroup END
I am using vim for a lot of languages and I am hoping to improve the ctrl + p/n autocomplete. When I am going to work with a specific one I load a file in the buffer containing the substet of language specific functions I am using like so:
:badd perl.txt
This loads the functions inside that file to the auto-complete buffer
I have one .txt file for each language I am using. I wish to automate this process by having a particular buffer loaded depending on the file type. I tried searching but cloudn't find a good answer. The only lead I have is that I might need to use filetype plugins thought not sure how. Bonus points (though not important) if the solution is just in the rc file (since it will be easy to set up new work places that way)
One possible solution:
autocmd BufNewFile,BufRead *`<extention>` badd `<dir to file>`
Example:
autocmd BufNewFile,BufRead *pl badd /home/vim_autocomplete/perl.txt
To answer the question you asked, I think that
:au FileType * badd path/to/<amatch>.txt
(untested) will work. Instead of using :badd, I would modify the 'complete' option:
:au FileType * setl complete+=k/path/to/<amatch>.txt
Either way, you can wrap the command in a test:
:au FileType * if filereadable("path/to/<amatch>.txt") | ... | endif
(equally untested). Of course, if you want a single autocommand, then (whichever approach you use) you will have to name the files after the file types.
:help :au
:help FileType
:help <amatch>
:help 'complete'
How do I get the current filetype in a vimscript, say in .vimrc or a regular plugin script?
The line
echo &filetype
returns an empty string.
In a function:
let current_filetype = &filetype
On the command line:
:echo &filetype
&filetype is empty when there's no filetype (obviously). If you try to use it when there's no buffer loaded you'll just get nothing.
edit
&filetype is only useful when you need to know the current filetype in a function executed at runtime when you are editing a buffer.
&filetype is only set when a buffer has been determined to be of some filetype. When it is executed, a script (vimrc, ftplugin, whatever) doesn't go through what it would go when it is edited: no filetype checking, no &filetype.
An example would be a function that displays the current file in a different external app depending on its filetype. Using &filetype in any other context doesn't make sense because it will be empty.
You need to consider the timing of your plugin. When your plugin script is sourced during the startup of Vim, no buffer has yet been loaded, so &filetype is empty. Therefore, something like this
let s:formatprgvarname = "g:formatprg_".&filetype
does not work! (For a filetype plugin (in ~/.vim/ftplugin/), this is different; those are sourced only when the filetype has been detected. But as I understand you want a general-purpose plugin that considers the current filetype.)
Instead, do away with the script-local variable s:formatprgvarname and resolve &filetype at the point of action; i.e. when your autoformat functionality is triggered (by mapping or custom command). If you have no such trigger, you can hook into the FileType event and set a (preferably buffer-local) variable then:
autocmd FileType * let b:formatprgvarname = "g:formatprg_".&filetype
I frequently develop on Ruby on Rails. With the recent inclusion of Tilt in RoR 3, we have file extensions like .scss.erb. How can I make the filetype = scss.erb in this case automatically, and the same for every file that has multiple extensions?
Edit: It should be scss.eruby in this case, as erb extension defaults to eruby filetype.
Edit: If it wasn't clear, I'm looking for a way to make this work dynamically for all files with multiple extensions. For example, file foo.js.html should have a filetype of js.html.
Edit again: Prince Goulash's answer doesn't take the default filetype for a particular extension.
In your vimrc:
autocmd BufRead,BufNewFile *.scss.erb setlocal filetype=scss.eruby
(see :help ftdetect, section 2).
EDIT
To set the filetype dyanamically for multiple extensions, this seems to work for me:
autocmd BufRead,BufNewFile *.*.*
\ sil exe "setlocal filetype=" . substitute(expand("%"),"^[^.]*\.","",1)
The substitute command constructs the filtype by simply stripping all text from the filename before the first .. There may be a more sophisticated way...
EDIT AGAIN
Here's another attempt. MultiExtensionFiletype() is function that uses the default filetype of the last part of the extension and prefixes it with the first part of the extension (i.e. the part sandwiched between the dots).
function MultiExtensionFiletype()
let ft_default=&filetype
let ft_prefix=substitute(matchstr(expand('%'),'\..\+\.'),'\.','','g')
sil exe "set filetype=" . ft_prefix . "." . ft_default
endfunction
The function must be called on a BufReadPost event so the initial filetype is set by ignoring the multiple extensions.
autocmd BufReadPost *.*.* call MultiExtensionFiletype()
Hopefully this answer is converging on something useful!