How to set a VimScript to be executed last? - vim

Problem
A setting in my vimrc (set noshowmode) is being overridden by a plugin later in the loading process.
Goal
Have a VimScript file be executed last (or at least after plugins).
What I Know
Plugin VimScripts are executed after the vimrc (Source).
The after-directory is run close to last and holds user overrides
(Source: :h after-directory).
Vim's runtimepath determines the order of what is run.
Failed Attempts
I tried appending a VimScript file (containing set noshowmode) to the
end of $VIMRUNTIME with
set runtimepath=$VIMRUNTIME,~/.vim/nosmd.vim, but this method ended up
messing up other plugins (namely vim-airline, which did not load).
I also tried creating the ~/.vim/after directory and putting my
VimScript in there, but this had no effect.

Your attempts
set runtimepath=$VIMRUNTIME,~/.vim/nosmd.vim
That cannot work. 'runtimepath' contains a list of root configuration directories; you cannot directly place script files in there. Instead, point to a directory that contains plugin/yours.vim.
I also tried creating the ~/.vim/after directory and putting my VimScript in there, but this had no effect.
You can check with :scriptnames to see whether your script was executed (and at the end of the plugin load sequence!)
Solutions
An ounce of prevention is better than any workaround. I would first try to locate the culprit who changes the 'showmode' option; a plugin shouldn't do this (or at least have a configurable option to disable it).
:verbose set showmode?
might already tell you who changed this setting.
As #romainl already commented, ~/.vim/after/plugin/myplugin.vim should work for undoing this. If it doesn't try the following autocmd (in your ~/.vimrc) as a last resort:
autocmd VimEnter * set noshowmode

Related

Vim - ftplugin settings changes not updating for existing file

It seems like there's some odd caching-like behavior going on for files that I have already opened once in Vim. I have a file foo.txt that I opened, and then I change some of the settings in ~/.vim/after/ftplugin/text.vim, but those new settings do not appear in foo.txt. I can quit vim and reopen foo.txt, or reload with :e, or even :so ~/.vim/after/ftplugin/text.vim, but none of these seem to have an effect on foo.txt's settings. If I mv foo.txt bar.txt, the settings show up for bar.txt with no issues.
EDIT
It seems I can force the settings to reload for foo.txt with the following sequence:
:so ~/.vimrc
:so ~/.vim/after/ftplugin/text.vim
Questions:
Why is this necessary / why were the other settings not picked up?
Why was sourcing ~/.vimrc not enough? It applied settings that were directly specified in ~/.vimrc, but shouldn't the ftplugins have been loaded at the line filetype plugin indent on? Why was sourcing text.vim afterwards necessary?
Vim runtime consists of a few hundred files, I'm not sure why you expect Vim to monitor them continuously. It doesn't. These files are loaded at some well-defined (and documented) points, that's all there is to it.
In particular there is no safe way to reload your configuration. You can do things like :so ~/.vimrc, but unless you specifically wrote your vimrc to take that into account, there will be drawbacks (such as autocmds piling up). If you want to be safe you have to quit Vim and start it again. That's how Vim works.
Now, for ftplugins you might get away with something like this:
:setf text
(use the actual filetype instead of text). This works for simple set fubar options. It works because under the hood setf is actually a carefully written autocmd. It still breaks for more complicated constructs (such as autocmds or file-scoped variables), for the same reasons :so ~/.vimrc has drawbacks.
A few more precisions:
.vimrc is loaded once -> for defining global stuff
same thing with .gvimrc, loaded only with gvim after the .vimrc
plugins are loaded once as well, after the vimrc files -> for global stuff as well
autoloaded plugins are loaded on demand, once, whenever a function they define is invoked
ftplugins are loaded once per buffer (and possibly multiple times! as there may be multiple buffers requiring them to be sourced) -> for definitions that shall apply only to the current buffer that triggered its loading
there are also langmap scripts, syntax scripts, indentation scripts, and even the old macros/ scripts (loaded explicitly/manually)
some plugins provides local vimrcs (basically identical to ftplugins, but loaded depending on the current directory of a buffer, instead of its filetype).
As you see, all things are loaded once, only. If you want to load them several times, you'll have to do it manually and explicitly. That's why a few of us have a :Reload command that simplifies reloading any kind of script - mine is hidden in my collection of scripts: lh-misc -> plugin/vim-maintain.vim

set tags=tags in gvimrc not working, unless set it explicitly

I have a problem to set my tags file correctly. It use to work without problem after I reinstalled the system. error message like
E433: No tags file
E426: tag not found: Pids
accurs when I press ctrl+].
I have this line in my .gvimrc file
set tags=~/projectdirectory/tags
and tags-exuberant installed properly.
It works fine when I type :set tags=~/projectdirectory/tags in gvim
I also tried use set tags=~/projectdirectory/tags;/
All other .gvimrc settings function well. How this could be possible?
UPDATE:
I have solved the problem, it is because I have multiple tags setting in ~/.gvimrc, vim take the last one in current session.
You can check the actual effective value (after starting GVIM) via
:verbose set tags?
The option might have been overwritten by a later :set command, or a plugin.
Even if you only use GVIM, it's recommended to put the general settings into ~/.vimrc (which is also sourced in GVIM), and keep ~/.gvimrc reserved for GUI-specific settings. An important difference between the two is that the latter is only sourced at the very end, so it's unsuitable for configuring plugins.

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

Vim In-File Commands

I'm after a means by which I can add additional commands to a text file via vim. For example, just as you can do something like this:
# vim:syntax=foo
I'd like to do something like:
# vim:option call matchadd('Special', '\(REQUIRED\|OPTIONAL\)')
Any ideas? I know I can write a syntax file, but this is not what I'm after for now.
Vim modeline syntax (see :help modeline) is not intended to specify commands
to execute during file opening. That is exactly what autocommands is for (see
:help autocommand). What you are trying to do should be an autocommand
similar the following.
autocmd FileType foo call matchadd('Special', '\(REQUIRED\|OPTIONAL\)')
or
autocmd BufReadPost *.foo call matchadd('Special', '\(REQUIRED\|OPTIONAL\)')
(Here instead of *.foo you can use any pattern that matches path or filename
(or both) of the target file.)
If the configuration you are setting up is local to some files or a project,
and you don't want to pollute your .vimrc with those autocmds, use
localvimrc plugin. It allows you to have a "local" .vimrc file next to
your target file or project folder. Script stored in that .lvimrc is
executed when you open files in the same directory where the "local" .vimrc
is, or in its subdirectories. Autocommands shown above (or any other
configurations) can be stored in a .lvimrc file local the project. For
details about localvimrc configuration see the homepage of the plugin.
This isn't an answer to your question, but I have also searched for Truth, and this question here is the closest one to it:
Vim: How to execute selected text as vim commands
It isn't automatic, but potentially only one keypress away it's close enough. :)
My ModelineCommands plugin extends Vim's built-in modelines to execute any Ex command(s) when a file is opened. A set of configurable validators examine the commands and can verify the correctness of an optional command digest, in order to prevent the execution of potentially malicious commands from unknown sources. (That's the main reason why Vim doesn't offer this feature!) This way, you could restrict the commands to only simple :let, or have the plugin query you to confirm execution of anything that isn't signed with your own secret key.

Correct pattern for a VIM autocommand?

I have a windows directory (U:\S) that contains files that must not be
changed. Their read-only bit cannot be set, so they must remain writeable.
As I have to look into some of the file's content rather regurarly with VIM, I want to make sure that I don't accidentally change the file's conent.
So, I put the following line into my .vimrc conifugration file:
autocmd InsertEnter u:/s/* call confirm("File should not be changed")
which seemed to work fine.
But then, I have also directory named U:\supportTerminal that contains files
that I have to change. When I edit a file within that directory, the file pattern u:/s/* for some reason matches and my warning pops up.
I tried playing around with some pattern, but I found none that only matches within u:\s but not within u:\supportTerminal
So, how could I go about what I want?
That makes for a bug, which you should report to vim-dev at vim.org. In linux I don't have this behaviour: it matches nicely.
As a temporary workaround,
:au BufRead u:/s/* set readonly
:au! BufRead u:/supportTerminal/*
should first make the general rule and then remove the one dir as an exception. Not sure whether this works in Windows GVim properly. Should this fail, other hack would be:
:au BufRead u:/supportTerminal/* set noreadonly
PS: As mentioned in the comments above, setting vim's own setting readonly works better to prevent accidental edits. User can't :write files with RO flag on, but it can be circumvented by setting noreadonly if needed.

Resources