How to tell when a vim script is being sourced - vim

How can I tell if my script is being sourced on or after startup?
For example, I want to write a function that responds to the ttymouse setting, say CheckMouseSetting(). This setting, however, is oddly enough loaded after startup scripts are loaded -- I'm not sure why. I could use a VimEnter autocommand, but this won't activate if the user is simply sourcing this file after startup. I could have both, ie:
call CheckMouseSetting()
au * VimEnter call CheckMouseSetting()
But this is not ideal as it may produce unwanted error messages -- so, hence my question.

I would solve this with a guard variable, like the multiple inclusion guard at the start of plugin files.
function! myplugin#CheckMouseSetting()
if exists('s:hasBeenChecked')
return
endif
let s:hasBeenChecked = 1
...
If you define this function in an autoload script, you can invoke it from the VimEnter event, and alternatively instruct users who want to have this manually to call the function, which is easier than :source / :runtime, because it avoids the path issues.

Clarification: you want the function to know whether it is being sourced at startup or later, right?
I think you have a little blind spot: the simplest solution is to tell the function:
:call CheckMouseSetting('myscript')
:au * VimEnter call CheckMouseSetting('VimEnter')
In response you your comment: if you want to tell when the file is sourced (during startup or interactively) then you can add a script-local variable:
:let s:source_count = exists('s:source_count') ? s:source_count + 1 : 1
:call CheckMouseSetting('myscript', s:source_count)
If you really want a more "automatic" way to tell, then #romainl's comment is on target. (I think there was a time when I was the only one besides Bram who had ever read that section of the help.)

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.

Buffer-local value of global variable?

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.

.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.

Using vim Sessions Only With GUI?

My usage-scenario may seem a bit unusual, but here it is: When using vim (it's one of about 4 different editors I use regularly), I use it in two different situations. The first is via the GUI, in which I'll have multiple buffers and have some settings different than when I use it from the command-line (by testing "if has('gui_running')"). The other is when I need to do something short-and-quick, from the command-line, such as make a small change to a dot-file or other type of config.
What I would like to do, is have sessions enabled for the GUI, but have any command-line invocations ignore them. That is, I don't want to bring up the full existing session on a CL invocation, nor do I want it (and whatever buffer/file it involved) to alter the session that the GUI is using. As I'm fairly new to the post-vi-functionality of vim, I'm not really sure how to pull this off.
do your session magic in your .gvimrc and everything else in your .vimrc. The GUI will source both, but the CL version will only source the .vimrc.
The session magic is to set up autocommands to write your session to a file on exit, and reload it by sourcing the file upon entrance.
au VimLeave * mksession ~/.gvimsession
au VimEnter * source ~/.gvimsession
You may want to add a ! to mksession so that you won't get an override error message upon exiting everytime.
au VimLeave * mksession! ~/.gvimsession
au VimEnter * source ~/.gvimsession

Resources