Buffer-local value of global variable? - vim

Many Vim's plugin's settings are specified by let g:something = value. I have a need for setting buffer-local values of some variables (actually with vim-localvimrc)
I know there's a way to outwit by using a condition (Setting buffer specific variables in Vim). But not all these autocmds are under my control, since some are set by other plugins. Is there anything like setlocal for global variable?

There are many ways to do to what you actually want (strip trailing whitespace for some projects) but I don't think there is anyway to shadow a global variable with a buffer local one (which is what you asked).
One way to do this is to add
autocmd BufWritePre /path/to/project/* call StripTrailingWhitespace()
the following to your vimrc. Which will call the function StripTrailingWhitespace for any file under /path/to/project (including subdirectories). StripTailingWhitespace is defined in spf13.
You can probably generate the path to the project dynamically by looking at the path to the local vimrc file.
Another way would be to change the condition spf13 uses to call StripTrailingWhitespace
The StripTrailingWhitespace autocmd in spf13 is defined as the following. (I added newlines so I'm not sure if this will work.)
autocmd FileType c,cpp,java,go,php,javascript,python,twig,xml,yml,perl
\ autocmd BufWritePre <buffer>
\ if !exists('g:spf13_keep_trailing_whitespace') |
\ call StripTrailingWhitespace() |
\ endif
So you would change it to !exists('g:spf13_keep_trailing_whitespace') to some other condition like checking if in whitelisted projects or check a buffer local variable.
General recommendation would be to get rid of any vim distribution. It is very hard to understand what is in them when you are first starting out. It then becomes very hard to modify them. It is generally better to start from scratch and add plugins and mappings when you find something lacking. It will take longer but you will understand everything in your vim configuration.

In your case, the plugin you are using shall accept overriding global variables with buffer local variables. Indeed it can be done by changing the condition -- in lh-vim-lib there is a lh#option#get() function that'll be easy to adapt to spf13. If you think it makes sense, contact spf13 maintainers or open an issue in the project bug tracker.
Another solution would rely on defining a local_vimrc script for each project you are working on. In some projects you'll have a :let g:spf13_keep_trailing_whitespace = 1, in other you'll have a :silent! unlet g:spf13_keep_trailing_whitespace -- usually it is accomplished with a :let g:var=0, but the current condition ignores the variable value.

Related

Is it possible to fix options in vim?

Following up on How to ensure that formatoptions *never* contains `r` or `o`?, which was poorly phrased.
Is it possible in vim to assign options in such a way that they cannot be modified by plugins or startup scripts. For example, something like:
set const final opt=value
in .vimrc would be great. I imagine this would be an error if opt is already constant, causing vim to refuse to open the buffer it is initializing when it encounters this, or possibly even exiting.
Does such a feature currently exist?
Not exactly. There are both :const and :lockvar, but they are for variables only. An option is a very different thing for VimScript.
However, you can fake this functionality with an auto-command. For example,
augroup ForbidSetOptions | au!
autocmd OptionSet formatoptions
\ if &filetype ==# 'foo'
\ echom 'You are not allowed to "set fo" for "foo" files!'
\ set formatoptions=jcroql
\ endif
augroup end
Note that we don't fall into an infinite recursion, because an auto-command is not triggered from another auto-command by default.
But note that this event is intentionally NOT triggered on startup. So you probably should consult a relevant plugin documentation instead to setup the options the way you want. Or write your own ~/.vim/after/plugin/... (or ~/.vim/after/ftplugin/...) script to undo such undesirable settings automatically.

Vim Comments Format Options Repeat Not Working

I set the comments option for a filetype to b:*. If I open such file I can verify this with set comments?. Now further I explicit set the formatoptions to use r for repeating the comment on a new line. After all calling set formatoptions? return in sum j1tcqln.
If open a new line o and write something like * This is a comment hit <CR I expect to get a * on the new line es well, cause the r option, but is doesn't.
The check if the +comments feature is available with :echo has('comments') is positive and returns 1.
Whats the problem here?
Edit:
This is my ftplugin/markdown.vim:
setlocal comments=b:*,b:-,b:+,b:>
setlocal formatoptions+=r
setlocal formatoptions-=c
echom 'Format: ' . &formatoptions
The last line leave a correct message when open a file with this type. But calling :echo &formatoptions manually afterwards, its again the false output.
It seems like no matter what I do in this ftplugin afterwards its not there anymore, even though it has been executed.
Edit:
It looks like my ftplugin gets overwritten by the default one in /usr/share/nvim/runtime/ftplguin/. Does this make sense and how can I mix them up?
Filetype plugins are sourced in this order, each potentially overriding the preceding one:
$HOME/.vim/ftplugin/markdown.vim
$VIMRUNTIME/ftplugin/markdown.vim
$HOME/.vim/after/ftplugin/markdown.vim
--- edit ---
The first location is suitable for two scenarii:
you are creating support scripts for a language not natively supported by Vim,
you want to prevent Vim from sourcing the default support script for a specific filetype (the solution in your answer).
The second location is off-limits. Four main reasons for this:
your changes can and will be overridden during future updates,
your changes may make Vim unstable,
having to sudo your way to your config will get annoying pretty quickly,
put your stuff in your $HOME.
The third location is sourced last so it allows you to selectively override default settings and add your own. This is the safest place for your own filetype-specific settings.
The solution is to add this at the header of the ftplugin file:
if exists('b:did_ftplugin') | finish | endif
let b:did_ftplugin = 1
Then is necessary cause the ftplugin in /usr/share/nvim gets loaded after and does not been executed if this variable is set.

.vimrc overridden by sys admins settings

I have a mapping in my .vimrc file to map F2 to save a file. Have done this for years. However now the system administrator has decided to override my setting with one of their mappings. If I run :scriptnames I see the order and I know which one is the offending script.
Is there a way to just ignore one startup script? I also tried creating a .vim/after/fixit.vim file which re-did the mapping but that file does not get read.
I know I could ignore all files and just load my .vimrc but I do want some of the administrator's defaults, just not all.
You can only avoid sourcing of a script if it uses the canonical inclusion guard:
:if exists('g:loaded_pluginname') | finish | endif
But it probably doesn't.
Your idea with .vim/after/fixit.vim is a good one (you haven't posted your :scriptnames output, so I can't tell for sure), but you need to include the plugin subdirectory there, too:
.vim/after/plugin/fixit.vim
Finally, as a last resort, you can define an :autocmd VimEnter (in your ~/.vimrc). That autocmd will fire after all other initializations, so you can definitely change the offending mapping in there.

Can you have different localleaders for different Vim plugins?

I started using a plugin that conflicts with my existing maps, but instead of remapping all of it's maps, I just want to add a prefix. I thought I'd be able to do this with LocalLeader.
Vimdoc says:
<LocalLeader> is just like <Leader>, except that it uses
"maplocalleader" instead of "mapleader". <LocalLeader> is to be used
for mappings which are local to a buffer.
It seems that the only way to set localleader is to set a global variable (the docs don't mention this, but b:maplocalleader didn't work):
let maplocalleader = '\\'
And I don't see how I'd cleanly unset that variable (an autocmd that clears it after plugins are setup!?)
Is there a way to do this? Or is LocalLeader only to give one global prefix and one filetype-specific prefix?
Your last hunch is correct. If the plugin uses <Leader> (and it should unless it's a filetype plugin), there's no use in messing with maplocalleader.
Remapping is canonically done via <Plug> mappings, which the plugin hopefully offers. Some plugins do define a lot of similar mappings, some of those define a g:pluginname_mappingprefix (or so) variable to save you from having to remap all mappings individually. If your plugin doesn't, maybe write a suggestion / patch to the plugin author.
While #IngoKarkat solution is a prefered one, there is a hack which lets you do what you want: the SourcePre event:
autocmd SourcePre * :let maplocalleader='\\'
autocmd SourcePre plugin-name.vim :let maplocalleader='_'
. This works for <Leader> as well. There are lots of cases when this won’t work though. You can as well use SourceCmd for this job, using something like
function s:Source(newmll)
try
let oldmll=g:maplocalleader
let g:maplocalleader=a:newmll
source <amatch>
finally
let g:maplocalleader=oldmll
endtry
endfunction
let maplocalleader='\\'
autocmd SourceCmd plugin-name.vim :call s:Source('_')
in SourceCmd is the only way I see to restore maplocalleader after plugin was sourced, but SourceCmd event here won’t be launched for any file sourced inside plugin-name.vim. For some poorly written plugins (I mean, those that emit errors while sources) putting :source inside a :try block will break execution at the point where error occurs. Should not happen most of time though. You may also want to use */ftplugin/plugin-name.vim as a pattern instead of plugin-name.vim.

Quickest Way to Revert Spaces to TABs in VIM

I have always been one to replace TABs in VIM with x amount of spaces (usually 4).
Four lines I almost always use in my .vimrc config file are:
set tabstop=4
set shiftwidth=4
set expandtab
syntax on
Basically, there are moments when I NEED to use a single TAB (such as Makefiles), and I don't know how else to work around that other than leaving the file, editing my .vimrc, and then reloading the file of interest.
That said, what is the quickest way (from within VIM) to revert it back to using TABS, and then reverting back to my original settings? I'm looking for the least-hassle, least-keystrokes solution.
VIM will automatically enable the TAB for a makefile, assuming you name it "makefile," as opposed to "Makefile." Not sure why VIM still doesn't detect the type with a lower-uppercase difference, but such is life. (#Sedrik)
That aside, other alternative solutions are:
Filetype Binding (#ThorstenS #tungd):
autocmd FileType make setlocal noexpandtab
RealTime Switch (#ThorstenS):
Assuming the .vimrc configuration mentioned in the question, do:
:set noet (to switch from spaces to TAB)
and :set et (to switch back)
Just use the magical escape key available in insert mode.
On the *NIX's it is ^V by default when you are in insert mode. On Windows, you need to find out what the magical escape character is - ^V is taken for something else; I think it may be ^Q or ^S?
So! In your makefile:
this: this.c
<C-V><Tab>cc this.c
where the usual meanings apply:
means hit ctrl-V (you should see a ^ hiding away under the cursor)
- hit the tab key. Bingo.
Works for me.
Note: if you use vim settings or startup code which smashes tabs as you read a file, this obviously is a short-term fix. I prefer to learn how to use the retab command to ensure a file is tab-clean, because I don't like a file to be touched unless I consciously choose to do so.
Just type set noexpandtab . Perhaps you bind this to a function key.
Only this configuration helped me solve this problem.
filetype plugin indent on
filetype detect
autocmd FileType make set noexpandtab
Vim defaults to tabstop=8 and noexpandtab, so the defaults are well suited to working with Makefiles. If your .vimrc uses custom options for tabstop, expandtab, etc., one simple solution is to bypass your .vimrc while working with Makefiles.
From the manpage (emphasis mine):
-u {vimrc} Use the commands in the file {vimrc} for initializations. All the other initializations are skipped. Use this to edit a special kind of files. It can also be used to skip all initializations by giving the name "NONE". See ":help initialization" within vim for more details.
Since I can never remember the necessary flag/value/formatting, I've created a Bash alias which remembers for me: alias vimnone='vim -u NONE'
You can create a custom configuration per file type.
mkdir -p ~/.vim/after/indent
echo 'set noexpandtab' >> ~/.vim/after/indent/make.vim
Basically, here we created a new indent configuration for makefiles that will be loaded after other scripts.
source

Resources