" Vimball Archiver by Charles E. Campbell UseVimball finish doc/localvimrc.txt [[[1 507 *localvimrc* Localvimrc =============================================================================== Contents ~ 1. Introduction |localvimrc-introduction| 2. Commands |localvimrc-commands| 1. The |LocalVimRC| command 2. The |LocalVimRCClear| command 3. The |LocalVimRCEdit| command 3. Functions |localvimrc-functions| 1. The |LocalVimRCFinish| command 4. Variables |localvimrc-variables| 1. The |g:localvimrc_file| variable 2. The |g:localvimrc_file_dir| variable 3. The |g:localvimrc_script| variable 4. The |g:localvimrc_script_dir| variable 5. The |g:localvimrc_script_unresolved| variable 6. The |g:localvimrc_script_dir_unresolved| variable 7. The |g:localvimrc_sourced_once| variable 8. The |g:localvimrc_sourced_once_for_file| setting 5. Settings |localvimrc-settings| 1. The |g:localvimrc_name| setting 2. The |g:localvimrc_event| setting 3. The |g:localvimrc_reverse| setting 4. The |g:localvimrc_count| setting 5. The |g:localvimrc_file_directory_only| setting 6. The |g:localvimrc_sandbox| setting 7. The |g:localvimrc_ask| setting 8. The |g:localvimrc_persistent| setting 9. The |g:localvimrc_persistence_file| setting 10. The |g:localvimrc_whitelist| setting 11. The |g:localvimrc_blacklist| setting 12. The |g:localvimrc_autocmd| setting 13. The |g:localvimrc_debug| setting 6. Autocommands |localvimrc-autocommands| 1. The |LocalVimRCPre| autocommand 2. The |LocalVimRCPost| autocommand 7. Contribute |localvimrc-contribute| 8. Credits |localvimrc-credits| 9. Changelog |localvimrc-changelog| 10. References |localvimrc-references| =============================================================================== *localvimrc-introduction* Introduction ~ This plugin searches for local vimrc files in the file system tree of the currently opened file. It searches for all ".lvimrc" files from the directory of the file up to the root directory. By default those files are loaded in order from the root directory to the directory of the file. The filename and amount of loaded files are customizable through global variables. For security reasons it the plugin asks for confirmation before loading a local vimrc file and loads it using |:sandbox| command. The plugin asks once per session and local vimrc before loading it, if the file didn't change since previous loading. It is possible to define a whitelist and a blacklist of local vimrc files that are loaded or ignored unconditionally. The plugin can be found on Bitbucket [1], GitHub [2] and VIM online [3]. =============================================================================== *localvimrc-commands* Commands ~ ------------------------------------------------------------------------------- The *LocalVimRC* command Resource all local vimrc files for the current buffer. ------------------------------------------------------------------------------- The *LocalVimRCClear* command Clear all stored decisions made in the past, when the plugin asked about sourcing a local vimrc file. ------------------------------------------------------------------------------- The *LocalVimRCEdit* command Open the local vimrc file for the current buffer in an split window for editing. If more than one local vimrc file has been sourced, the user can decide which file to edit. =============================================================================== *localvimrc-functions* Functions ~ ------------------------------------------------------------------------------- The *LocalVimRCFinish* command After a call to this function the sourcing of any remaining local vimrc files will be skipped. In combination with the |g:localvimrc_reverse| option it is possible to end the processing of local vimrc files for example at the root of the project by adding the following command to the local vimrc file in the root of the project: > call LocalVimRCFinish() < =============================================================================== *localvimrc-variables* Variables ~ The plugin provides several convenience variables to make it easier to set up path dependent setting like for example makeprg. These variables are only available inside your local vimrc file because they are only unambiguous there. Adding the following lines to a local vimrc in the root directory of a project modify the behavior of |:make| to change into a build directory and call make there: > let &l:makeprg="cd ".g:localvimrc_script_dir_unresolved."/build && make" < **NOTE:** This is only possible if you disable sandbox mode. Other variables provide a way to prevent multiple execution of commands. They can be used to implement guards: > " do stuff you want to do on every buffer enter event " guard to end loading if it has been loaded for the currently edited file if g:localvimrc_sourced_once_for_file finish endif " do stuff you want to do only once for a edited file " guard to end loading if it has been loaded for the running vim instance if g:localvimrc_sourced_once finish endif " do stuff you want to do only once for a running vim instance < ------------------------------------------------------------------------------- The *g:localvimrc_file* variable Fully qualified file name of file that triggered loading the local vimrc file. ------------------------------------------------------------------------------- The *g:localvimrc_file_dir* variable Fully qualified directory of file that triggered loading the local vimrc file. ------------------------------------------------------------------------------- The *g:localvimrc_script* variable Fully qualified and resolved file name of the currently loaded local vimrc file. ------------------------------------------------------------------------------- The *g:localvimrc_script_dir* variable Fully qualified and resolved directory of the currently loaded local vimrc file. ------------------------------------------------------------------------------- The *g:localvimrc_script_unresolved* variable Fully qualified but unresolved file name of the currently loaded local vimrc file. ------------------------------------------------------------------------------- The *g:localvimrc_script_dir_unresolved* variable Fully qualified but unresolved directory of the currently loaded local vimrc file. ------------------------------------------------------------------------------- The *g:localvimrc_sourced_once* variable Set to '1' if the currently loaded local vimrc file had already been loaded in this session. Set to '0' otherwise. ------------------------------------------------------------------------------- The *g:localvimrc_sourced_once_for_file* setting Set to '1' if the currently loaded local vimrc file had already been loaded in this session for the currently edited file. Set to '0' otherwise. =============================================================================== *localvimrc-settings* Settings ~ To change settings from their default add similar line to your global |vimrc| file. > let g:option_name=option_value < ------------------------------------------------------------------------------- The *g:localvimrc_name* setting List of filenames of local vimrc files. The given name can include a directory name such as ".config/localvimrc". Previous versions of localvimrc only supported a single file as string. This is still supported for backward compatibility. - Default: '[ ".lvimrc" ]' ------------------------------------------------------------------------------- The *g:localvimrc_event* setting List of autocommand events that trigger local vimrc file loading. - Default: '[ "BufWinEnter" ]' **NOTE:** BufWinEnter is the default to enable lines like > setlocal colorcolumn=+1 < in the local vimrc file. Settings "local to window" need to be set for every time a buffer is displayed in a window. ------------------------------------------------------------------------------- The *g:localvimrc_reverse* setting Reverse behavior of loading local vimrc files. - Value '0': Load files in order from root directory to directory of the file. - Value '1': Load files in order from directory of the file to root directory. - Default: '0' ------------------------------------------------------------------------------- The *g:localvimrc_count* setting On the way from root, the last localvimrc_count files are sourced. **NOTE:** This might load files not located in the edited files directory or even not located in the projects directory. If this is of concern use the |g:localvimrc_file_directory_only| setting. - Default: '-1' (all) ------------------------------------------------------------------------------- The *g:localvimrc_file_directory_only* setting Just use local vimrc file located in the edited files directory. **NOTE:** This might end in not loading any local vimrc files at all. If limiting the number of loaded local vimrc files is of concern use the |g:localvimrc_count| setting. - Value '0': Load all local vimrc files in the tree from root to file. - Value '1': Load only file in the same directory as edited file. - Default: '0' ------------------------------------------------------------------------------- The *g:localvimrc_sandbox* setting Source the found local vimrc files in a sandbox for security reasons. - Value '0': Don't load vimrc file in a sandbox. - Value '1': Load vimrc file in a sandbox. - Default: '1' ------------------------------------------------------------------------------- The *g:localvimrc_ask* setting Ask before sourcing any local vimrc file. In a vim session the question is only asked once as long as the local vimrc file has not been changed. - Value '0': Don't ask before loading a vimrc file. - Value '1': Ask before loading a vimrc file. - Default: '1' ------------------------------------------------------------------------------- The *g:localvimrc_persistent* setting Make the decisions given when asked before sourcing local vimrc files persistent over multiple vim runs and instances. The decisions are written to the file defined by and |g:localvimrc_persistence_file|. - Value '0': Don't store and restore any decisions. - Value '1': Store and restore decisions only if the answer was given in upper case (Y/N/A). - Value '2': Store and restore all decisions. - Default: '0' ------------------------------------------------------------------------------- The *g:localvimrc_persistence_file* setting Filename used for storing persistent decisions made when asked before sourcing local vimrc files. - Default (_Unix_): "$HOME/.localvimrc_persistent" - Default (_Windows_): "$HOME/_localvimrc_persistent" ------------------------------------------------------------------------------- The *g:localvimrc_whitelist* setting If a local vimrc file matches the regular expression given by |g:localvimrc_whitelist| this file is loaded unconditionally. Files matching |g:localvimrc_whitelist| are sourced even if they are matched by |g:localvimrc_blacklist|. See |regular-expression| for patterns that are accepted. Example: > " whitelist all local vimrc files in users project foo and bar let g:localvimrc_whitelist='/home/user/projects/\(foo\|bar\)/.*' " whitelist can also use lists of patterns let g:localvimrc_whitelist=['/home/user/project1/', '/opt/project2/', '/usr/local/projects/vim-[^/]*/'] < - Default: No whitelist ------------------------------------------------------------------------------- The *g:localvimrc_blacklist* setting If a local vimrc file matches the regular expression given by |g:localvimrc_blacklist| this file is skipped unconditionally. Files matching |g:localvimrc_whitelist| are sourced even if they are matched by |g:localvimrc_blacklist|. See |regular-expression| for patterns that are accepted. Example: > " blacklist all local vimrc files in shared project directory let g:localvimrc_blacklist='/share/projects/.*' " blacklist can also use lists of patterns let g:localvimrc_blacklist=['/share/projects/.*', '/usr/share/other-projects/.*'] < - Default: No blacklist ------------------------------------------------------------------------------- The *g:localvimrc_autocmd* setting Emit autocommands |LocalVimRCPre| before and |LocalVimRCPost| after sourcing every local vimrc file. - Default: '1' ------------------------------------------------------------------------------- The *g:localvimrc_debug* setting Debug level for this script. - Default: '0' =============================================================================== *localvimrc-autocommands* Autocommands ~ If enabled localvimrc emits autocommands before and after sourcing an local vimrc file. ------------------------------------------------------------------------------- The *LocalVimRCPre* autocommand This autocommand is emitted right before sourcing each local vimrc file. ------------------------------------------------------------------------------- The *LocalVimRCPost* autocommand This autocommands is emitted right after sourcing each local vimrc file. =============================================================================== *localvimrc-contribute* Contribute ~ To contact the author (Markus Braun), please send an email to markus.braun@krawel.de If you think this plugin could be improved, fork on Bitbucket [1] or GitHub [2] and send a pull request or just tell me your ideas. =============================================================================== *localvimrc-credits* Credits ~ - Simon Howard for his hint about "sandbox" - Mark Weber for the idea of using checksums - Daniel Hahler for various patches - Justin M. Keyes for ideas to improve this plugin - Lars Winderling for whitelist/blacklist patch - Michon van Dooren for autocommands patch =============================================================================== *localvimrc-changelog* Changelog ~ v2.6.1 : 2018-02-20 - fix a bug with missing uniq() in Vim version 7.4 v2.6.0 : 2018-01-22 - add command |LocalVimRCEdit| to edit sourced local vimrc files for the current buffer. v2.5.0 : 2017-03-08 - add unit tests. - settings |g:localvimrc_whitelist| and |g:localvimrc_blacklist| now takes optionally a list of regular expressions. - add convenience variables |g:localvimrc_script_unresolved| and |g:localvimrc_script_dir_unresolved|. - add ability to view local vimrc before sourcing when |g:localvimrc_ask| is enabled. - emit autocommands before and after sourcing files. - add |g:localvimrc_file_directory_only| to limit sourcing to local vimrc files in the same directory as the edited file. - add |LocalVimRCFinish| function to stop loading of remaining local vimrc files from within a local vimrc file. v2.4.0 : 2016-02-05 - add setting |g:localvimrc_event| which defines the autocommand events that trigger local vimrc file loading. - don't lose persistence file on full partitions. - make it possible to supply a list of local vimrc filenames in |g:localvimrc_name|. - ask user when sourcing local vimrc fails and |g:localvimrc_sandbox| and |g:localvimrc_ask| is set whether the file should be sourced without sandbox. - fix a bug where local vimrc files are sourced in wrong order when some of them are symlinks to a different directory. v2.3.0 : 2014-02-06 - private persistence file to enable persistence over concurrent vim instances. - add convenience variables |g:localvimrc_sourced_once| and |g:localvimrc_sourced_once_for_file|. v2.2.0 : 2013-11-09 - remove redraw calls for better performance and fixing a bug on windows. - load local vimrc on event BufWinEnter to fix a bug with window local settings. - add |g:localvimrc_reverse| to change order of sourcing local vimrc files. - add convenience variables |g:localvimrc_file|, |g:localvimrc_file_dir|, |g:localvimrc_script| and |g:localvimrc_script_dir|. v2.1.0 : 2012-09-25 - add possibility to make decisions persistent. - use full file path when storing decisions. v2.0.0 : 2012-04-05 - added |g:localvimrc_whitelist| and |g:localvimrc_blacklist| settings. - ask only once per session and local vimrc before loading it, if it didn't change. v2758 : 2009-05-11 - source .lvimrc in a sandbox to better maintain security, configurable using |g:localvimrc_sandbox|. - ask user before sourcing any local vimrc file, configurable using |g:localvimrc_ask|. v1870 : 2007-09-28 - new configuration variable |g:localvimrc_name| to change filename. - new configuration variable |g:localvimrc_count| to limit number of loaded files. v1613 : 2007-04-05 - switched to arrays in vim 7. - escape file/path names correctly. v1.2 : 2002-10-09 - initial version =============================================================================== *localvimrc-references* References ~ [1] https://bitbucket.org/embear/localvimrc [2] https://github.com/embear/vim-localvimrc [3] http://www.vim.org/scripts/script.php?script_id=441 vim: ft=help plugin/localvimrc.vim [[[1 845 " Name: localvimrc.vim " Version: 2.6.1 " Author: Markus Braun " Summary: Vim plugin to search local vimrc files and load them. " Licence: This program is free software: you can redistribute it and/or modify " it under the terms of the GNU General Public License as published by " the Free Software Foundation, either version 3 of the License, or " (at your option) any later version. " " This program is distributed in the hope that it will be useful, " but WITHOUT ANY WARRANTY; without even the implied warranty of " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the " GNU General Public License for more details. " " You should have received a copy of the GNU General Public License " along with this program. If not, see . " " Section: Plugin header {{{1 " guard against multiple loads {{{2 if (exists("g:loaded_localvimrc") || &cp) finish endif let g:loaded_localvimrc = 1 " check for correct vim version {{{2 if version < 702 finish endif " define default "localvimrc_name" {{{2 " copy to script local variable to prevent .lvimrc modifying the name option. if (!exists("g:localvimrc_name")) let s:localvimrc_name = [ ".lvimrc" ] else if type(g:localvimrc_name) == type("") let s:localvimrc_name = [ g:localvimrc_name ] elseif type(g:localvimrc_name) == type([]) let s:localvimrc_name = g:localvimrc_name endif endif " define default "localvimrc_event" {{{2 " copy to script local variable to prevent .lvimrc modifying the name option. if (!exists("g:localvimrc_event") || !(type(g:localvimrc_event) == type([]))) let s:localvimrc_event = [ "BufWinEnter" ] else let s:localvimrc_event = g:localvimrc_event endif " define default "localvimrc_reverse" {{{2 " copy to script local variable to prevent .lvimrc modifying the reverse " option. if (!exists("g:localvimrc_reverse")) let s:localvimrc_reverse = 0 else let s:localvimrc_reverse = g:localvimrc_reverse endif " define default "localvimrc_count" {{{2 " copy to script local variable to prevent .lvimrc modifying the count option. if (!exists("g:localvimrc_count")) let s:localvimrc_count = -1 else let s:localvimrc_count = g:localvimrc_count endif " define default "localvimrc_file_directory_only" {{{2 " copy to script local variable to prevent .lvimrc modifying the file " directory only option. if (!exists("g:localvimrc_file_directory_only")) let s:localvimrc_file_directory_only = 0 else let s:localvimrc_file_directory_only = g:localvimrc_file_directory_only endif " define default "localvimrc_sandbox" {{{2 " copy to script local variable to prevent .lvimrc disabling the sandbox " again. if (!exists("g:localvimrc_sandbox")) let s:localvimrc_sandbox = 1 else let s:localvimrc_sandbox = g:localvimrc_sandbox endif " define default "localvimrc_ask" {{{2 " copy to script local variable to prevent .lvimrc modifying the ask option. if (!exists("g:localvimrc_ask")) let s:localvimrc_ask = 1 else let s:localvimrc_ask = g:localvimrc_ask endif " define default "localvimrc_whitelist" {{{2 " copy to script local variable to prevent .lvimrc modifying the whitelist. if (!exists("g:localvimrc_whitelist")) let s:localvimrc_whitelist = [ "^$" ] " this never matches a file else if type(g:localvimrc_whitelist) == type("") let s:localvimrc_whitelist = [ g:localvimrc_whitelist ] else let s:localvimrc_whitelist = g:localvimrc_whitelist endif endif " define default "localvimrc_blacklist" {{{2 " copy to script local variable to prevent .lvimrc modifying the blacklist. if (!exists("g:localvimrc_blacklist")) let s:localvimrc_blacklist = [ "^$" ] " this never matches a file else if type(g:localvimrc_blacklist) == type("") let s:localvimrc_blacklist = [ g:localvimrc_blacklist ] else let s:localvimrc_blacklist = g:localvimrc_blacklist endif endif " define default "localvimrc_persistent" {{{2 " make decisions persistent over multiple vim runs if (!exists("g:localvimrc_persistent")) let s:localvimrc_persistent = 0 else let s:localvimrc_persistent = g:localvimrc_persistent endif " define default "localvimrc_persistence_file" {{{2 " file where to store persistence information if (!exists("g:localvimrc_persistence_file")) if has("win16") || has("win32") || has("win64") || has("win95") let s:localvimrc_persistence_file = expand('$HOME') . "/_localvimrc_persistent" else let s:localvimrc_persistence_file = expand('$HOME') . "/.localvimrc_persistent" endif else let s:localvimrc_persistence_file = g:localvimrc_persistence_file endif " define default "localvimrc_autocmd" {{{2 " enable emitting of autocommands before and after sourcing a .lvimrc file if (!exists("g:localvimrc_autocmd")) let s:localvimrc_autocmd = 1 else let s:localvimrc_autocmd = g:localvimrc_autocmd endif " define default "localvimrc_debug" {{{2 if (!exists("g:localvimrc_debug")) let g:localvimrc_debug = 0 endif " initialize data dictionary {{{2 " key: localvimrc file " value: [ answer, sandbox_answer, checksum ] let s:localvimrc_data = {} " initialize sourced dictionary {{{2 " key: localvimrc file " value: [ list of files triggered sourcing ] let s:localvimrc_sourced = {} " initialize persistence file checksum {{{2 let s:localvimrc_persistence_file_checksum = "" " initialize persistent data {{{2 let s:localvimrc_persistent_data = {} " initialize processing finish flag {{{2 let s:localvimrc_finish = 0 " Section: Autocmd setup {{{1 if has("autocmd") augroup localvimrc autocmd! for event in s:localvimrc_event " call s:LocalVimRC() when creating or reading any file exec "autocmd ".event." * call s:LocalVimRC()" endfor augroup END endif " Section: Functions {{{1 " Function: s:LocalVimRC() {{{2 " " search all local vimrc files from current directory up to root directory and " source them in reverse order. " function! s:LocalVimRC() " begin marker call s:LocalVimRCDebug(1, "==================================================") " print version call s:LocalVimRCDebug(1, "localvimrc.vim " . g:loaded_localvimrc) " read persistent information call s:LocalVimRCReadPersistent() " only consider normal buffers (skip especially CommandT's GoToFile buffer) " NOTE: in general the buftype is not set for new buffers (BufWinEnter), " e.g. for help files via plugins (pydoc) if !empty(&buftype) call s:LocalVimRCDebug(1, "not a normal buffer, exiting") return endif " directory of current file (correctly escaped) let l:directory = fnameescape(expand("%:p:h")) if empty(l:directory) let l:directory = fnameescape(getcwd()) endif call s:LocalVimRCDebug(2, "searching directory \"" . l:directory . "\"") " check if the local vimrc file shall be searched just in the files " directory or in the whole tree if s:localvimrc_file_directory_only == 1 let l:search_option = "" else let l:search_option = ";" endif " generate a list of all local vimrc files with absolute file names along path to root let l:rcfiles = [] for l:rcname in s:localvimrc_name for l:rcfile in findfile(l:rcname, l:directory . l:search_option, -1) let l:rcfile_unresolved = fnamemodify(l:rcfile, ":p") let l:rcfile_resolved = resolve(l:rcfile_unresolved) call insert(l:rcfiles, { "resolved": l:rcfile_resolved, "unresolved": l:rcfile_unresolved } ) endfor endfor call s:LocalVimRCDebug(1, "found files: " . string(l:rcfiles)) " shrink list of found files if (s:localvimrc_count >= 0 && s:localvimrc_count < len(l:rcfiles)) call remove(l:rcfiles, 0, len(l:rcfiles) - s:localvimrc_count - 1) endif " reverse order of found files if reverse loading is requested if (s:localvimrc_reverse != 0) call reverse(l:rcfiles) endif call s:LocalVimRCDebug(1, "candidate files: " . string(l:rcfiles)) " source all found local vimrc files in l:rcfiles variable let s:localvimrc_finish = 0 let l:answer = "" let l:sandbox_answer = "" let l:sourced_files = [] for l:rcfile_dict in l:rcfiles " get values from dictionary let l:rcfile = l:rcfile_dict["resolved"] let l:rcfile_unresolved = l:rcfile_dict["unresolved"] call s:LocalVimRCDebug(2, "processing \"" . l:rcfile . "\"") let l:rcfile_load = "unknown" if filereadable(l:rcfile) " extract information if has_key(s:localvimrc_data, l:rcfile) if len(s:localvimrc_data[l:rcfile]) == 2 let [ l:stored_answer, l:stored_checksum ] = s:localvimrc_data[l:rcfile] let l:stored_sandbox_answer = "" elseif len(s:localvimrc_data[l:rcfile]) == 3 let [ l:stored_answer, l:stored_sandbox_answer, l:stored_checksum ] = s:localvimrc_data[l:rcfile] else let l:stored_answer = "" let l:stored_sandbox_answer = "" let l:stored_checksum = "" endif else let l:stored_answer = "" let l:stored_sandbox_answer = "" let l:stored_checksum = "" endif call s:LocalVimRCDebug(3, "stored information: answer = '" . l:stored_answer . "' sandbox answer = '" . l:stored_sandbox_answer . "' checksum = '" . l:stored_checksum . "'") " check if checksum is the same let l:checksum_is_same = s:LocalVimRCCheckChecksum(l:rcfile, l:stored_checksum) " reset answers if checksum changed if (!l:checksum_is_same) call s:LocalVimRCDebug(2, "checksum mismatch, not reusing answer") let l:stored_answer = "" let l:stored_sandbox_answer = "" else call s:LocalVimRCDebug(2, "reuse previous answer = '" . l:stored_answer . "' sandbox answer = '" . l:stored_sandbox_answer . "'") endif " check if whitelisted if (l:rcfile_load == "unknown") if s:LocalVimRCMatchAny(l:rcfile, s:localvimrc_whitelist) call s:LocalVimRCDebug(2, l:rcfile . " is whitelisted") let l:rcfile_load = "yes" endif endif " check if blacklisted if (l:rcfile_load == "unknown") if s:LocalVimRCMatchAny(l:rcfile, s:localvimrc_blacklist) call s:LocalVimRCDebug(2, l:rcfile . " is blacklisted") let l:rcfile_load = "no" endif endif " check if an answer has been given for the same file if !empty(l:stored_answer) " check the answer if (l:stored_answer =~? '^y$') let l:rcfile_load = "yes" elseif (l:stored_answer =~? '^n$') let l:rcfile_load = "no" endif endif " ask if in interactive mode if (l:rcfile_load == "unknown") if (s:localvimrc_ask == 1) if (l:answer !~? "^a$") call s:LocalVimRCDebug(2, "need to ask") let l:answer = "" let l:message = "" while (l:answer !~? '^[ynaq]$') if (s:localvimrc_persistent == 0) let l:message .= "localvimrc: source " . l:rcfile . "? ([y]es/[n]o/[a]ll/[s]how/[q]uit) " elseif (s:localvimrc_persistent == 1) let l:message .= "localvimrc: source " . l:rcfile . "? ([y]es/[n]o/[a]ll/[s]how/[q]uit ; persistent [Y]es/[N]o/[A]ll) " else let l:message .= "localvimrc: source " . l:rcfile . "? ([y]es/[n]o/[a]ll/[s]how/[q]uit) " endif " turn off possible previous :silent command to force this " message to be printed unsilent let l:answer = inputdialog(l:message) call s:LocalVimRCDebug(2, "answer is \"" . l:answer . "\"") if empty(l:answer) call s:LocalVimRCDebug(2, "aborting on empty answer") let l:answer = "q" endif " add the content of the file for repeating the question let l:message = "" if (l:answer =~? "^s$") let l:message .= "localvimrc: >>>>>>>> start content of " . l:rcfile . "\n" let l:content_max = 10 let l:content = readfile(l:rcfile, "", l:content_max + 1) for l:line in l:content let l:message .= "localvimrc: " . l:line . "\n" endfor if len(l:content) > l:content_max let l:message .= "localvimrc: ======== TRUNCATED AFTER " . l:content_max . " LINES!\n" endif let l:message .= "localvimrc: <<<<<<<< end content of " . l:rcfile . "\n" endif endwhile endif " make answer upper case if persistence is 2 ("force") if (s:localvimrc_persistent == 2) let l:answer = toupper(l:answer) endif " store y/n answers if (l:answer =~? "^y$") let l:stored_answer = l:answer elseif (l:answer =~? "^n$") let l:stored_answer = l:answer elseif (l:answer =~# "^a$") let l:stored_answer = "y" elseif (l:answer =~# "^A$") let l:stored_answer = "Y" endif " check the answer if (l:answer =~? '^[ya]$') let l:rcfile_load = "yes" elseif (l:answer =~? "^q$") call s:LocalVimRCDebug(1, "ended processing files") break endif endif endif " load unconditionally if in non-interactive mode if (l:rcfile_load == "unknown") if (s:localvimrc_ask == 0) let l:rcfile_load = "yes" endif endif " should this rc file be loaded? if (l:rcfile_load == "yes") " store name and directory of file let g:localvimrc_file = resolve(expand(":p")) let g:localvimrc_file_dir = fnamemodify(g:localvimrc_file, ":h") call s:LocalVimRCDebug(3, "g:localvimrc_file = " . g:localvimrc_file . ", g:localvimrc_file_dir = " . g:localvimrc_file_dir) " store name and directory of script let g:localvimrc_script = l:rcfile let g:localvimrc_script_dir = fnamemodify(g:localvimrc_script, ":h") call s:LocalVimRCDebug(3, "g:localvimrc_script = " . g:localvimrc_script . ", g:localvimrc_script_dir = " . g:localvimrc_script_dir) " store name and directory of unresolved script let g:localvimrc_script_unresolved = l:rcfile_unresolved let g:localvimrc_script_dir_unresolved = fnamemodify(g:localvimrc_script_unresolved, ":h") call s:LocalVimRCDebug(3, "g:localvimrc_script_unresolved = " . g:localvimrc_script_unresolved . ", g:localvimrc_script_dir_unresolved = " . g:localvimrc_script_dir_unresolved) " reset if checksum changed if (!l:checksum_is_same) if has_key(s:localvimrc_sourced, l:rcfile) unlet s:localvimrc_sourced[l:rcfile] call s:LocalVimRCDebug(2, "resetting 'sourced' information") endif endif " detect if this local vimrc file had been loaded let g:localvimrc_sourced_once = 0 let g:localvimrc_sourced_once_for_file = 0 if has_key(s:localvimrc_sourced, l:rcfile) let g:localvimrc_sourced_once = 1 if index(s:localvimrc_sourced[l:rcfile], g:localvimrc_file) >= 0 let g:localvimrc_sourced_once_for_file = 1 else call add(s:localvimrc_sourced[l:rcfile], g:localvimrc_file) endif else let s:localvimrc_sourced[l:rcfile] = [ g:localvimrc_file ] endif call s:LocalVimRCDebug(3, "g:localvimrc_sourced_once = " . g:localvimrc_sourced_once . ", g:localvimrc_sourced_once_for_file = " . g:localvimrc_sourced_once_for_file) " generate command let l:command = "source " . fnameescape(l:rcfile) " emit an autocommand before sourcing if (s:localvimrc_autocmd == 1) call s:LocalVimRCUserAutocommand('LocalVimRCPre') endif " add 'sandbox' if requested if (s:localvimrc_sandbox != 0) call s:LocalVimRCDebug(2, "using sandbox") try " execute the command exec "sandbox " . l:command call s:LocalVimRCDebug(1, "sourced " . l:rcfile) catch ^Vim\%((\a\+)\)\=:E48 call s:LocalVimRCDebug(1, "unable to use sandbox on '" . l:rcfile . "'") if (s:localvimrc_ask == 1) if (l:sandbox_answer !~? "^a$") if l:stored_sandbox_answer != "" let l:sandbox_answer = l:stored_sandbox_answer call s:LocalVimRCDebug(2, "reuse previous sandbox answer \"" . l:stored_sandbox_answer . "\"") else call s:LocalVimRCDebug(2, "need to ask") let l:sandbox_answer = "" while (l:sandbox_answer !~? '^[ynaq]$') if (s:localvimrc_persistent == 0) let l:message = "localvimrc: unable to use 'sandbox' for " . l:rcfile . ".\nlocalvimrc: Source it anyway? ([y]es/[n]o/[a]ll/[q]uit) " elseif (s:localvimrc_persistent == 1) let l:message = "localvimrc: unable to use 'sandbox' for " . l:rcfile . ".\nlocalvimrc: Source it anyway? ([y]es/[n]o/[a]ll/[q]uit ; persistent [Y]es/[N]o/[A]ll) " else let l:message = "localvimrc: unable to use 'sandbox' for " . l:rcfile . ".\nlocalvimrc: Source it anyway? ([y]es/[n]o/[a]ll/[q]uit) " endif " turn off possible previous :silent command to force this " message to be printed unsilent let l:sandbox_answer = inputdialog(l:message) call s:LocalVimRCDebug(2, "sandbox answer is \"" . l:sandbox_answer . "\"") if empty(l:sandbox_answer) call s:LocalVimRCDebug(2, "aborting on empty sandbox answer") let l:sandbox_answer = "q" endif endwhile endif endif " make sandbox_answer upper case if persistence is 2 ("force") if (s:localvimrc_persistent == 2) let l:sandbox_answer = toupper(l:sandbox_answer) endif " store y/n answers if (l:sandbox_answer =~? "^y$") let l:stored_sandbox_answer = l:sandbox_answer elseif (l:sandbox_answer =~? "^n$") let l:stored_sandbox_answer = l:sandbox_answer elseif (l:sandbox_answer =~# "^a$") let l:stored_sandbox_answer = "y" elseif (l:sandbox_answer =~# "^A$") let l:stored_sandbox_answer = "Y" endif " check the sandbox_answer if (l:sandbox_answer =~? '^[ya]$') " execute the command exec l:command call s:LocalVimRCDebug(1, "sourced " . l:rcfile) elseif (l:sandbox_answer =~? "^q$") call s:LocalVimRCDebug(1, "ended processing files") break endif endif endtry else " execute the command exec l:command call s:LocalVimRCDebug(1, "sourced " . l:rcfile) endif " emit an autocommands after sourcing if (s:localvimrc_autocmd == 1) call s:LocalVimRCUserAutocommand('LocalVimRCPost') endif call add(l:sourced_files, l:rcfile) " remove global variables again unlet g:localvimrc_file unlet g:localvimrc_file_dir unlet g:localvimrc_script unlet g:localvimrc_script_dir unlet g:localvimrc_script_unresolved unlet g:localvimrc_script_dir_unresolved unlet g:localvimrc_sourced_once unlet g:localvimrc_sourced_once_for_file else call s:LocalVimRCDebug(1, "skipping " . l:rcfile) endif " calculate checksum for each processed file let l:stored_checksum = s:LocalVimRCCalcChecksum(l:rcfile) " store information again let s:localvimrc_data[l:rcfile] = [ l:stored_answer, l:stored_sandbox_answer, l:stored_checksum ] " check if sourcing of files should be ended by variable set by " local vimrc file if (s:localvimrc_finish != 0) break endif endif endfor " store information about source local vimrc files in buffer local variable if exists("b:localvimrc_sourced_files") call extend(l:sourced_files, b:localvimrc_sourced_files) endif if exists("*uniq") call uniq(sort(l:sourced_files)) else let l:sourced_files_uniq = {} for l:file in l:sourced_files let l:sourced_files_uniq[l:file] = 1 endfor let l:sourced_files = sort(keys(l:sourced_files_uniq)) endif let b:localvimrc_sourced_files = l:sourced_files " make information persistent call s:LocalVimRCWritePersistent() " end marker call s:LocalVimRCDebug(1, "==================================================") endfunction " Function: s:LocalVimRCUserAutocommand(event) {{{2 " function! s:LocalVimRCUserAutocommand(event) if exists('#User#'.a:event) call s:LocalVimRCDebug(1, 'executing User autocommand '.a:event) if v:version >= 704 || (v:version == 703 && has('patch442')) exec 'doautocmd User ' . a:event else exec 'doautocmd User ' . a:event endif endif endfunction " Function: s:LocalVimRCMatchAny(str, patterns) {{{2 " " check if any of the regular expressions given in the list patterns matches the " string. If there is a match, return value is "1". If there is no match, " return value is "0". " function! s:LocalVimRCMatchAny(str, patterns) for l:pattern in a:patterns if (match(a:str, l:pattern) != -1) return 1 endif endfor return 0 endfunction " Function: s:LocalVimRCCalcChecksum(filename) {{{2 " " calculate checksum and store it in dictionary " function! s:LocalVimRCCalcChecksum(file) let l:checksum = getfsize(a:file) . getfperm(a:file) . getftime(a:file) call s:LocalVimRCDebug(3, "checksum calc -> " . fnameescape(a:file) . " : " . l:checksum) return l:checksum endfunction " Function: s:LocalVimRCCheckChecksum(filename, checksum) {{{2 " " Check checksum in dictionary. Return "0" if it does not exist, "1" otherwise " function! s:LocalVimRCCheckChecksum(file, checksum) let l:return = 0 let l:checksum = s:LocalVimRCCalcChecksum(a:file) if (a:checksum == l:checksum) let l:return = 1 endif return l:return endfunction " Function: s:LocalVimRCReadPersistent() {{{2 " " read decision variables from persistence file " function! s:LocalVimRCReadPersistent() if (s:localvimrc_persistent >= 1) " check if persistence file is readable if filereadable(s:localvimrc_persistence_file) " check if reading is needed let l:checksum = s:LocalVimRCCalcChecksum(s:localvimrc_persistence_file) if l:checksum != s:localvimrc_persistence_file_checksum " read persistence file let l:serialized = readfile(s:localvimrc_persistence_file) call s:LocalVimRCDebug(3, "read persistent data: " . string(l:serialized)) " deserialize stored persistence information for l:line in l:serialized let l:columns = split(l:line, '[^\\]\zs|\|^|', 1) if len(l:columns) != 3 && len(l:columns) != 4 call s:LocalVimRCDebug(1, "error in persistence file") call s:LocalVimRCError("error in persistence file") else if len(l:columns) == 3 let [ l:key, l:answer, l:checksum ] = l:columns let l:sandbox = "" elseif len(l:columns) == 4 let [ l:key, l:answer, l:sandbox, l:checksum ] = l:columns endif let l:key = substitute(l:key, '\\|', '|', "g") let l:answer = substitute(l:answer, '\\|', '|', "g") let l:sandbox = substitute(l:sandbox, '\\|', '|', "g") let l:checksum = substitute(l:checksum, '\\|', '|', "g") let s:localvimrc_data[l:key] = [ l:answer, l:sandbox, l:checksum ] endif endfor else call s:LocalVimRCDebug(3, "persistence file did not change") endif else call s:LocalVimRCDebug(1, "unable to read persistence file '" . s:localvimrc_persistence_file . "'") endif endif endfunction " Function: s:LocalVimRCWritePersistent() {{{2 " " write decision variables to persistence file " function! s:LocalVimRCWritePersistent() if (s:localvimrc_persistent >= 1) " select only data relevant for persistence let l:persistent_data = filter(copy(s:localvimrc_data), 'v:val[0] =~# "^[YN]$" || v:val[1] =~# "^[YN]$"') " if there are answers to store and global variables are enabled for viminfo if (len(l:persistent_data) > 0) if l:persistent_data != s:localvimrc_persistent_data " check if persistence file is writable if filereadable(s:localvimrc_persistence_file) && filewritable(s:localvimrc_persistence_file) || \ !filereadable(s:localvimrc_persistence_file) && filewritable(fnamemodify(s:localvimrc_persistence_file, ":h")) let l:serialized = [ ] for [ l:key, l:value ] in items(l:persistent_data) if len(l:value) == 2 let [ l:answer, l:checksum ] = l:value let l:sandbox = "" elseif len(l:value) == 3 let [ l:answer, l:sandbox, l:checksum ] = l:value else let l:answer = "" let l:sandbox = "" let l:checksum = "" endif " delete none persisten answers if l:answer !~# "^[YN]$" let l:answer = "" endif if l:sandbox !~# "^[YN]$" let l:sandbox = "" endif call add(l:serialized, escape(l:key, '|') . "|" . escape(l:answer, '|') . "|" . escape(l:sandbox, '|') . "|" . escape(l:checksum, '|')) endfor call s:LocalVimRCDebug(3, "write persistent data: " . string(l:serialized)) " check if there is a exising persistence file if filereadable(s:localvimrc_persistence_file) " first write backup file to avoid lost persistence information " on write errors if partition is full. Done this way because " write/rename approach causes permission problems with sudo. let l:backup_name = s:localvimrc_persistence_file . "~" let l:backup_content = readfile(s:localvimrc_persistence_file, "b") if writefile(l:backup_content, l:backup_name, "b") == 0 if writefile(l:serialized, s:localvimrc_persistence_file) == 0 call delete(l:backup_name) else call s:LocalVimRCError("error while writing persistence file, backup stored in '" . l:backup_name . "'") endif else call s:LocalVimRCError("unable to write persistence file backup '" . l:backup_name . "'") endif else " there is no persistence file to backup, just write new one if writefile(l:serialized, s:localvimrc_persistence_file) != 0 call s:LocalVimRCError("unable to write persistence file '" . s:localvimrc_persistence_file . "'") endif endif else call s:LocalVimRCError("unable to write persistence file '" . s:localvimrc_persistence_file . "'") endif " store persistence file checksum let s:localvimrc_persistence_file_checksum = s:LocalVimRCCalcChecksum(s:localvimrc_persistence_file) endif let s:localvimrc_persistent_data = l:persistent_data endif else " delete persistence file if filewritable(s:localvimrc_persistence_file) call delete(s:localvimrc_persistence_file) endif endif " remove old persistence data if exists("g:LOCALVIMRC_ANSWERS") unlet g:LOCALVIMRC_ANSWERS endif if exists("g:LOCALVIMRC_CHECKSUMS") unlet g:LOCALVIMRC_CHECKSUMS endif endfunction " Function: s:LocalVimRCClear() {{{2 " " clear all stored data " function! s:LocalVimRCClear() let s:localvimrc_data = {} call s:LocalVimRCDebug(3, "cleared local data") let s:localvimrc_persistence_file_checksum = "" call s:LocalVimRCDebug(3, "cleared persistence file checksum") let s:localvimrc_persistent_data = {} call s:LocalVimRCDebug(3, "cleared persistent data") if filewritable(s:localvimrc_persistence_file) call delete(s:localvimrc_persistence_file) call s:LocalVimRCDebug(3, "deleted persistence file") endif endfunction " Function: LocalVimRCFinish() {{{2 " " finish processing local vimrc files " function! LocalVimRCFinish() call s:LocalVimRCDebug(1, "will finish sourcing files after this file") let s:localvimrc_finish = 1 endfunction " Function: s:LocalVimRCError(text) {{{2 " " output error message " function! s:LocalVimRCError(text) echohl ErrorMsg | echom "localvimrc: " . a:text | echohl None endfunction " Function: s:LocalVimRCDebug(level, text) {{{2 " " output debug message, if this message has high enough importance " function! s:LocalVimRCDebug(level, text) if (g:localvimrc_debug >= a:level) echom "localvimrc: " . a:text endif endfunction " Function: s:LocalVimRCEdit() {{{2 " " open the local vimrc file for the current buffer in an split window for " editing. If more than one local vimrc file has been sourced, the user " can decide which file to edit. " function! s:LocalVimRCEdit() if exists("b:localvimrc_sourced_files") let l:items = len(b:localvimrc_sourced_files) if l:items == 0 call s:LocalVimRCError("No local vimrc file has been sourced") elseif l:items == 1 " edit the only sourced file let l:file = b:localvimrc_sourced_files[0] elseif l:items > 1 " build message for asking the user let l:message = [ "Select local vimrc file to edit:" ] call extend(l:message, map(copy(b:localvimrc_sourced_files), 'v:key+1 . " " . v:val')) " ask the user which one should be edited let l:answer = inputlist(l:message) if l:answer =~ '^\d\+$' && l:answer > 0 && l:answer <= l:items let l:file = b:localvimrc_sourced_files[l:answer-1] endif endif if exists("l:file") execute 'silent! split ' . fnameescape(l:file) endif endif endfunction " Section: Commands {{{1 command! LocalVimRC call s:LocalVimRC() command! LocalVimRCClear call s:LocalVimRCClear() command! LocalVimRCEdit call s:LocalVimRCEdit() " vim600: foldmethod=marker foldlevel=0 :