1
0

localvimrc.vim 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878
  1. " Name: localvimrc.vim
  2. " Version: 2.7.0
  3. " Author: Markus Braun <markus.braun@krawel.de>
  4. " Summary: Vim plugin to search local vimrc files and load them.
  5. " Licence: This program is free software: you can redistribute it and/or modify
  6. " it under the terms of the GNU General Public License as published by
  7. " the Free Software Foundation, either version 3 of the License, or
  8. " (at your option) any later version.
  9. "
  10. " This program is distributed in the hope that it will be useful,
  11. " but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. " GNU General Public License for more details.
  14. "
  15. " You should have received a copy of the GNU General Public License
  16. " along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. "
  18. " Section: Plugin header {{{1
  19. " guard against multiple loads {{{2
  20. if (exists("g:loaded_localvimrc") || &cp)
  21. finish
  22. endif
  23. let g:loaded_localvimrc = 1
  24. " check for correct vim version {{{2
  25. if version < 702
  26. finish
  27. endif
  28. " define default "localvimrc_enable" {{{2
  29. let s:localvimrc_enable = 1
  30. if (exists("g:localvimrc_enable") && type(g:localvimrc_enable) == type(0))
  31. let s:localvimrc_enable = g:localvimrc_enable
  32. endif
  33. " define default "localvimrc_name" {{{2
  34. " copy to script local variable to prevent .lvimrc modifying the name option.
  35. let s:localvimrc_name = [ ".lvimrc" ]
  36. if (exists("g:localvimrc_name"))
  37. if type(g:localvimrc_name) == type("")
  38. let s:localvimrc_name = [ g:localvimrc_name ]
  39. elseif type(g:localvimrc_name) == type([])
  40. let s:localvimrc_name = g:localvimrc_name
  41. endif
  42. endif
  43. " define default "localvimrc_event" {{{2
  44. " copy to script local variable to prevent .lvimrc modifying the event option.
  45. let s:localvimrc_event = [ "BufWinEnter" ]
  46. if (exists("g:localvimrc_event") && type(g:localvimrc_event) == type([]))
  47. let s:localvimrc_event = g:localvimrc_event
  48. endif
  49. " define default "localvimrc_event_pattern" {{{2
  50. " copy to script local variable to prevent .lvimrc modifying the event pattern
  51. " option.
  52. let s:localvimrc_event_pattern = "*"
  53. if (exists("g:localvimrc_event_pattern") && type(g:localvimrc_event_pattern) == type(""))
  54. let s:localvimrc_event_pattern = g:localvimrc_event_pattern
  55. endif
  56. " define default "localvimrc_reverse" {{{2
  57. " copy to script local variable to prevent .lvimrc modifying the reverse option.
  58. let s:localvimrc_reverse = 0
  59. if (exists("g:localvimrc_reverse") && type(g:localvimrc_reverse) == type(0))
  60. let s:localvimrc_reverse = g:localvimrc_reverse
  61. endif
  62. " define default "localvimrc_count" {{{2
  63. " copy to script local variable to prevent .lvimrc modifying the count option.
  64. let s:localvimrc_count = -1
  65. if (exists("g:localvimrc_count") && type(g:localvimrc_count) == type(0))
  66. let s:localvimrc_count = g:localvimrc_count
  67. endif
  68. " define default "localvimrc_file_directory_only" {{{2
  69. " copy to script local variable to prevent .lvimrc modifying the file
  70. " directory only option.
  71. let s:localvimrc_file_directory_only = 0
  72. if (exists("g:localvimrc_file_directory_only") && type(g:localvimrc_file_directory_only) == type(0))
  73. let s:localvimrc_file_directory_only = g:localvimrc_file_directory_only
  74. endif
  75. " define default "localvimrc_sandbox" {{{2
  76. " copy to script local variable to prevent .lvimrc disabling the sandbox again.
  77. let s:localvimrc_sandbox = 1
  78. if (exists("g:localvimrc_sandbox") && type(g:localvimrc_sandbox) == type(0))
  79. let s:localvimrc_sandbox = g:localvimrc_sandbox
  80. endif
  81. " define default "localvimrc_ask" {{{2
  82. " copy to script local variable to prevent .lvimrc modifying the ask option.
  83. let s:localvimrc_ask = 1
  84. if (exists("g:localvimrc_ask") && type(g:localvimrc_ask) == type(0))
  85. let s:localvimrc_ask = g:localvimrc_ask
  86. endif
  87. " define default "localvimrc_whitelist" {{{2
  88. " copy to script local variable to prevent .lvimrc modifying the whitelist.
  89. let s:localvimrc_whitelist = [ "^$" ] " this never matches a file
  90. if (exists("g:localvimrc_whitelist"))
  91. if type(g:localvimrc_whitelist) == type("")
  92. let s:localvimrc_whitelist = [ g:localvimrc_whitelist ]
  93. elseif type(g:localvimrc_whitelist) == type([])
  94. let s:localvimrc_whitelist = g:localvimrc_whitelist
  95. endif
  96. endif
  97. " define default "localvimrc_blacklist" {{{2
  98. " copy to script local variable to prevent .lvimrc modifying the blacklist.
  99. let s:localvimrc_blacklist = [ "^$" ] " this never matches a file
  100. if (exists("g:localvimrc_blacklist"))
  101. if type(g:localvimrc_blacklist) == type("")
  102. let s:localvimrc_blacklist = [ g:localvimrc_blacklist ]
  103. elseif type(g:localvimrc_blacklist) == type([])
  104. let s:localvimrc_blacklist = g:localvimrc_blacklist
  105. endif
  106. endif
  107. " define default "localvimrc_persistent" {{{2
  108. " copy to script local variable to prevent .lvimrc modifying the persistent
  109. " option.
  110. let s:localvimrc_persistent = 0
  111. if (exists("g:localvimrc_persistent") && type(g:localvimrc_persistent) == type(0))
  112. let s:localvimrc_persistent = g:localvimrc_persistent
  113. endif
  114. " define default "localvimrc_persistence_file" {{{2
  115. " copy to script local variable to prevent .lvimrc modifying the persistence
  116. " file.
  117. if has("win16") || has("win32") || has("win64") || has("win95")
  118. let s:localvimrc_persistence_file = expand('$HOME') . "/_localvimrc_persistent"
  119. else
  120. let s:localvimrc_persistence_file = expand('$HOME') . "/.localvimrc_persistent"
  121. endif
  122. if (exists("g:localvimrc_persistence_file") && type(g:localvimrc_persistence_file) == type(""))
  123. let s:localvimrc_persistence_file = g:localvimrc_persistence_file
  124. endif
  125. " define default "localvimrc_autocmd" {{{2
  126. " copy to script local variable to prevent .lvimrc modifying the autocommand
  127. " option.
  128. let s:localvimrc_autocmd = 1
  129. if (exists("g:localvimrc_autocmd") && type(g:localvimrc_autocmd) == type(0))
  130. let s:localvimrc_autocmd = g:localvimrc_autocmd
  131. endif
  132. " define default "localvimrc_debug" {{{2
  133. if (!exists("g:localvimrc_debug"))
  134. let g:localvimrc_debug = 0
  135. endif
  136. " initialize data dictionary {{{2
  137. " key: localvimrc file
  138. " value: [ answer, sandbox_answer, checksum ]
  139. let s:localvimrc_data = {}
  140. " initialize sourced dictionary {{{2
  141. " key: localvimrc file
  142. " value: [ list of files triggered sourcing ]
  143. let s:localvimrc_sourced = {}
  144. " initialize persistence file checksum {{{2
  145. let s:localvimrc_persistence_file_checksum = ""
  146. " initialize persistent data {{{2
  147. let s:localvimrc_persistent_data = {}
  148. " initialize processing finish flag {{{2
  149. let s:localvimrc_finish = 0
  150. " Section: Autocmd setup {{{1
  151. if has("autocmd")
  152. augroup localvimrc
  153. autocmd!
  154. for event in s:localvimrc_event
  155. " call s:LocalVimRC() when creating or reading any file
  156. exec "autocmd ".event." ".s:localvimrc_event_pattern." call s:LocalVimRC()"
  157. endfor
  158. augroup END
  159. endif
  160. " Section: Functions {{{1
  161. " Function: s:LocalVimRC() {{{2
  162. "
  163. " search all local vimrc files from current directory up to root directory and
  164. " source them in reverse order.
  165. "
  166. function! s:LocalVimRC()
  167. " begin marker
  168. call s:LocalVimRCDebug(1, "==================================================")
  169. " print version
  170. call s:LocalVimRCDebug(1, "localvimrc.vim " . g:loaded_localvimrc)
  171. " finish immediately if localvimrc is disabled
  172. if s:localvimrc_enable == 0
  173. return
  174. endif
  175. " read persistent information
  176. call s:LocalVimRCReadPersistent()
  177. " only consider normal buffers (skip especially CommandT's GoToFile buffer)
  178. " NOTE: in general the buftype is not set for new buffers (BufWinEnter),
  179. " e.g. for help files via plugins (pydoc)
  180. if !empty(&buftype)
  181. call s:LocalVimRCDebug(1, "not a normal buffer, exiting")
  182. return
  183. endif
  184. " directory of current file (correctly escaped)
  185. let l:directory = fnameescape(expand("%:p:h"))
  186. if empty(l:directory)
  187. let l:directory = fnameescape(getcwd())
  188. endif
  189. call s:LocalVimRCDebug(2, "searching directory \"" . l:directory . "\"")
  190. " check if the local vimrc file shall be searched just in the files
  191. " directory or in the whole tree
  192. if s:localvimrc_file_directory_only == 1
  193. let l:search_option = ""
  194. else
  195. let l:search_option = ";"
  196. endif
  197. " generate a list of all local vimrc files with absolute file names along path to root
  198. let l:rcfiles = []
  199. for l:rcname in s:localvimrc_name
  200. for l:rcfile in findfile(l:rcname, l:directory . l:search_option, -1)
  201. let l:rcfile_unresolved = fnamemodify(l:rcfile, ":p")
  202. let l:rcfile_resolved = resolve(l:rcfile_unresolved)
  203. call insert(l:rcfiles, { "resolved": l:rcfile_resolved, "unresolved": l:rcfile_unresolved } )
  204. endfor
  205. endfor
  206. call s:LocalVimRCDebug(1, "found files: " . string(l:rcfiles))
  207. " shrink list of found files
  208. if (s:localvimrc_count >= 0 && s:localvimrc_count < len(l:rcfiles))
  209. call remove(l:rcfiles, 0, len(l:rcfiles) - s:localvimrc_count - 1)
  210. endif
  211. " reverse order of found files if reverse loading is requested
  212. if (s:localvimrc_reverse != 0)
  213. call reverse(l:rcfiles)
  214. endif
  215. call s:LocalVimRCDebug(1, "candidate files: " . string(l:rcfiles))
  216. " source all found local vimrc files in l:rcfiles variable
  217. let s:localvimrc_finish = 0
  218. let l:answer = ""
  219. let l:sandbox_answer = ""
  220. let l:sourced_files = []
  221. for l:rcfile_dict in l:rcfiles
  222. " get values from dictionary
  223. let l:rcfile = l:rcfile_dict["resolved"]
  224. let l:rcfile_unresolved = l:rcfile_dict["unresolved"]
  225. call s:LocalVimRCDebug(2, "processing \"" . l:rcfile . "\"")
  226. let l:rcfile_load = "unknown"
  227. if filereadable(l:rcfile)
  228. " extract information
  229. if has_key(s:localvimrc_data, l:rcfile)
  230. if len(s:localvimrc_data[l:rcfile]) == 2
  231. let [ l:stored_answer, l:stored_checksum ] = s:localvimrc_data[l:rcfile]
  232. let l:stored_sandbox_answer = ""
  233. elseif len(s:localvimrc_data[l:rcfile]) == 3
  234. let [ l:stored_answer, l:stored_sandbox_answer, l:stored_checksum ] = s:localvimrc_data[l:rcfile]
  235. else
  236. let l:stored_answer = ""
  237. let l:stored_sandbox_answer = ""
  238. let l:stored_checksum = ""
  239. endif
  240. else
  241. let l:stored_answer = ""
  242. let l:stored_sandbox_answer = ""
  243. let l:stored_checksum = ""
  244. endif
  245. call s:LocalVimRCDebug(3, "stored information: answer = '" . l:stored_answer . "' sandbox answer = '" . l:stored_sandbox_answer . "' checksum = '" . l:stored_checksum . "'")
  246. " check if checksum is the same
  247. let l:checksum_is_same = s:LocalVimRCCheckChecksum(l:rcfile, l:stored_checksum)
  248. " reset answers if checksum changed
  249. if (!l:checksum_is_same)
  250. call s:LocalVimRCDebug(2, "checksum mismatch, not reusing answer")
  251. let l:stored_answer = ""
  252. let l:stored_sandbox_answer = ""
  253. else
  254. call s:LocalVimRCDebug(2, "reuse previous answer = '" . l:stored_answer . "' sandbox answer = '" . l:stored_sandbox_answer . "'")
  255. endif
  256. " check if whitelisted
  257. if (l:rcfile_load == "unknown")
  258. if s:LocalVimRCMatchAny(l:rcfile, s:localvimrc_whitelist)
  259. call s:LocalVimRCDebug(2, l:rcfile . " is whitelisted")
  260. let l:rcfile_load = "yes"
  261. endif
  262. endif
  263. " check if blacklisted
  264. if (l:rcfile_load == "unknown")
  265. if s:LocalVimRCMatchAny(l:rcfile, s:localvimrc_blacklist)
  266. call s:LocalVimRCDebug(2, l:rcfile . " is blacklisted")
  267. let l:rcfile_load = "no"
  268. endif
  269. endif
  270. " check if an answer has been given for the same file
  271. if !empty(l:stored_answer)
  272. " check the answer
  273. if (l:stored_answer =~? '^y$')
  274. let l:rcfile_load = "yes"
  275. elseif (l:stored_answer =~? '^n$')
  276. let l:rcfile_load = "no"
  277. endif
  278. endif
  279. " ask if in interactive mode
  280. if (l:rcfile_load == "unknown")
  281. if (s:localvimrc_ask == 1)
  282. if (l:answer !~? "^a$")
  283. call s:LocalVimRCDebug(2, "need to ask")
  284. let l:answer = ""
  285. let l:message = ""
  286. while (l:answer !~? '^[ynaq]$')
  287. if (s:localvimrc_persistent == 0)
  288. let l:message .= "localvimrc: source " . l:rcfile . "? ([y]es/[n]o/[a]ll/[s]how/[q]uit) "
  289. elseif (s:localvimrc_persistent == 1)
  290. let l:message .= "localvimrc: source " . l:rcfile . "? ([y]es/[n]o/[a]ll/[s]how/[q]uit ; persistent [Y]es/[N]o/[A]ll) "
  291. else
  292. let l:message .= "localvimrc: source " . l:rcfile . "? ([y]es/[n]o/[a]ll/[s]how/[q]uit) "
  293. endif
  294. " turn off possible previous :silent command to force this
  295. " message to be printed
  296. unsilent let l:answer = inputdialog(l:message)
  297. call s:LocalVimRCDebug(2, "answer is \"" . l:answer . "\"")
  298. if empty(l:answer)
  299. call s:LocalVimRCDebug(2, "aborting on empty answer")
  300. let l:answer = "q"
  301. endif
  302. " add the content of the file for repeating the question
  303. let l:message = ""
  304. if (l:answer =~? "^s$")
  305. let l:message .= "localvimrc: >>>>>>>> start content of " . l:rcfile . "\n"
  306. let l:content_max = 10
  307. let l:content = readfile(l:rcfile, "", l:content_max + 1)
  308. for l:line in l:content
  309. let l:message .= "localvimrc: " . l:line . "\n"
  310. endfor
  311. if len(l:content) > l:content_max
  312. let l:message .= "localvimrc: ======== TRUNCATED AFTER " . l:content_max . " LINES!\n"
  313. endif
  314. let l:message .= "localvimrc: <<<<<<<< end content of " . l:rcfile . "\n"
  315. endif
  316. endwhile
  317. endif
  318. " make answer upper case if persistence is 2 ("force")
  319. if (s:localvimrc_persistent == 2)
  320. let l:answer = toupper(l:answer)
  321. endif
  322. " store y/n answers
  323. if (l:answer =~? "^y$")
  324. let l:stored_answer = l:answer
  325. elseif (l:answer =~? "^n$")
  326. let l:stored_answer = l:answer
  327. elseif (l:answer =~# "^a$")
  328. let l:stored_answer = "y"
  329. elseif (l:answer =~# "^A$")
  330. let l:stored_answer = "Y"
  331. endif
  332. " check the answer
  333. if (l:answer =~? '^[ya]$')
  334. let l:rcfile_load = "yes"
  335. elseif (l:answer =~? "^q$")
  336. call s:LocalVimRCDebug(1, "ended processing files")
  337. break
  338. endif
  339. endif
  340. endif
  341. " load unconditionally if in non-interactive mode
  342. if (l:rcfile_load == "unknown")
  343. if (s:localvimrc_ask == 0)
  344. let l:rcfile_load = "yes"
  345. endif
  346. endif
  347. " should this rc file be loaded?
  348. if (l:rcfile_load == "yes")
  349. " store name and directory of file
  350. let g:localvimrc_file = resolve(expand("<afile>:p"))
  351. let g:localvimrc_file_dir = fnamemodify(g:localvimrc_file, ":h")
  352. call s:LocalVimRCDebug(3, "g:localvimrc_file = " . g:localvimrc_file . ", g:localvimrc_file_dir = " . g:localvimrc_file_dir)
  353. " store name and directory of script
  354. let g:localvimrc_script = l:rcfile
  355. let g:localvimrc_script_dir = fnamemodify(g:localvimrc_script, ":h")
  356. call s:LocalVimRCDebug(3, "g:localvimrc_script = " . g:localvimrc_script . ", g:localvimrc_script_dir = " . g:localvimrc_script_dir)
  357. " store name and directory of unresolved script
  358. let g:localvimrc_script_unresolved = l:rcfile_unresolved
  359. let g:localvimrc_script_dir_unresolved = fnamemodify(g:localvimrc_script_unresolved, ":h")
  360. call s:LocalVimRCDebug(3, "g:localvimrc_script_unresolved = " . g:localvimrc_script_unresolved . ", g:localvimrc_script_dir_unresolved = " . g:localvimrc_script_dir_unresolved)
  361. " reset if checksum changed
  362. if (!l:checksum_is_same)
  363. if has_key(s:localvimrc_sourced, l:rcfile)
  364. unlet s:localvimrc_sourced[l:rcfile]
  365. call s:LocalVimRCDebug(2, "resetting 'sourced' information")
  366. endif
  367. endif
  368. " detect if this local vimrc file had been loaded
  369. let g:localvimrc_sourced_once = 0
  370. let g:localvimrc_sourced_once_for_file = 0
  371. if has_key(s:localvimrc_sourced, l:rcfile)
  372. let g:localvimrc_sourced_once = 1
  373. if index(s:localvimrc_sourced[l:rcfile], g:localvimrc_file) >= 0
  374. let g:localvimrc_sourced_once_for_file = 1
  375. else
  376. call add(s:localvimrc_sourced[l:rcfile], g:localvimrc_file)
  377. endif
  378. else
  379. let s:localvimrc_sourced[l:rcfile] = [ g:localvimrc_file ]
  380. endif
  381. call s:LocalVimRCDebug(3, "g:localvimrc_sourced_once = " . g:localvimrc_sourced_once . ", g:localvimrc_sourced_once_for_file = " . g:localvimrc_sourced_once_for_file)
  382. " generate command
  383. let l:command = "source " . fnameescape(l:rcfile)
  384. " emit an autocommand before sourcing
  385. if (s:localvimrc_autocmd == 1)
  386. call s:LocalVimRCUserAutocommand('LocalVimRCPre')
  387. endif
  388. " add 'sandbox' if requested
  389. if (s:localvimrc_sandbox != 0)
  390. call s:LocalVimRCDebug(2, "using sandbox")
  391. try
  392. " execute the command
  393. exec "sandbox " . l:command
  394. call s:LocalVimRCDebug(1, "sourced " . l:rcfile)
  395. catch ^Vim\%((\a\+)\)\=:E48
  396. call s:LocalVimRCDebug(1, "unable to use sandbox on '" . l:rcfile . "'")
  397. if (s:localvimrc_ask == 1)
  398. if (l:sandbox_answer !~? "^a$")
  399. if l:stored_sandbox_answer != ""
  400. let l:sandbox_answer = l:stored_sandbox_answer
  401. call s:LocalVimRCDebug(2, "reuse previous sandbox answer \"" . l:stored_sandbox_answer . "\"")
  402. else
  403. call s:LocalVimRCDebug(2, "need to ask")
  404. let l:sandbox_answer = ""
  405. while (l:sandbox_answer !~? '^[ynaq]$')
  406. if (s:localvimrc_persistent == 0)
  407. let l:message = "localvimrc: unable to use 'sandbox' for " . l:rcfile . ".\nlocalvimrc: Source it anyway? ([y]es/[n]o/[a]ll/[q]uit) "
  408. elseif (s:localvimrc_persistent == 1)
  409. 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) "
  410. else
  411. let l:message = "localvimrc: unable to use 'sandbox' for " . l:rcfile . ".\nlocalvimrc: Source it anyway? ([y]es/[n]o/[a]ll/[q]uit) "
  412. endif
  413. " turn off possible previous :silent command to force this
  414. " message to be printed
  415. unsilent let l:sandbox_answer = inputdialog(l:message)
  416. call s:LocalVimRCDebug(2, "sandbox answer is \"" . l:sandbox_answer . "\"")
  417. if empty(l:sandbox_answer)
  418. call s:LocalVimRCDebug(2, "aborting on empty sandbox answer")
  419. let l:sandbox_answer = "q"
  420. endif
  421. endwhile
  422. endif
  423. endif
  424. " make sandbox_answer upper case if persistence is 2 ("force")
  425. if (s:localvimrc_persistent == 2)
  426. let l:sandbox_answer = toupper(l:sandbox_answer)
  427. endif
  428. " store y/n answers
  429. if (l:sandbox_answer =~? "^y$")
  430. let l:stored_sandbox_answer = l:sandbox_answer
  431. elseif (l:sandbox_answer =~? "^n$")
  432. let l:stored_sandbox_answer = l:sandbox_answer
  433. elseif (l:sandbox_answer =~# "^a$")
  434. let l:stored_sandbox_answer = "y"
  435. elseif (l:sandbox_answer =~# "^A$")
  436. let l:stored_sandbox_answer = "Y"
  437. endif
  438. " check the sandbox_answer
  439. if (l:sandbox_answer =~? '^[ya]$')
  440. " execute the command
  441. exec l:command
  442. call s:LocalVimRCDebug(1, "sourced " . l:rcfile)
  443. elseif (l:sandbox_answer =~? "^q$")
  444. call s:LocalVimRCDebug(1, "ended processing files")
  445. break
  446. endif
  447. endif
  448. endtry
  449. else
  450. " execute the command
  451. exec l:command
  452. call s:LocalVimRCDebug(1, "sourced " . l:rcfile)
  453. endif
  454. " emit an autocommands after sourcing
  455. if (s:localvimrc_autocmd == 1)
  456. call s:LocalVimRCUserAutocommand('LocalVimRCPost')
  457. endif
  458. call add(l:sourced_files, l:rcfile)
  459. " remove global variables again
  460. unlet g:localvimrc_file
  461. unlet g:localvimrc_file_dir
  462. unlet g:localvimrc_script
  463. unlet g:localvimrc_script_dir
  464. unlet g:localvimrc_script_unresolved
  465. unlet g:localvimrc_script_dir_unresolved
  466. unlet g:localvimrc_sourced_once
  467. unlet g:localvimrc_sourced_once_for_file
  468. else
  469. call s:LocalVimRCDebug(1, "skipping " . l:rcfile)
  470. endif
  471. " calculate checksum for each processed file
  472. let l:stored_checksum = s:LocalVimRCCalcChecksum(l:rcfile)
  473. " store information again
  474. let s:localvimrc_data[l:rcfile] = [ l:stored_answer, l:stored_sandbox_answer, l:stored_checksum ]
  475. " check if sourcing of files should be ended by variable set by
  476. " local vimrc file
  477. if (s:localvimrc_finish != 0)
  478. break
  479. endif
  480. endif
  481. endfor
  482. " store information about source local vimrc files in buffer local variable
  483. if exists("b:localvimrc_sourced_files")
  484. call extend(l:sourced_files, b:localvimrc_sourced_files)
  485. endif
  486. if exists("*uniq")
  487. call uniq(sort(l:sourced_files))
  488. else
  489. let l:sourced_files_uniq = {}
  490. for l:file in l:sourced_files
  491. let l:sourced_files_uniq[l:file] = 1
  492. endfor
  493. let l:sourced_files = sort(keys(l:sourced_files_uniq))
  494. endif
  495. let b:localvimrc_sourced_files = l:sourced_files
  496. " make information persistent
  497. call s:LocalVimRCWritePersistent()
  498. " end marker
  499. call s:LocalVimRCDebug(1, "==================================================")
  500. endfunction
  501. " Function: s:LocalVimRCUserAutocommand(event) {{{2
  502. "
  503. function! s:LocalVimRCUserAutocommand(event)
  504. if exists('#User#'.a:event)
  505. call s:LocalVimRCDebug(1, 'executing User autocommand '.a:event)
  506. if v:version >= 704 || (v:version == 703 && has('patch442'))
  507. exec 'doautocmd <nomodeline> User ' . a:event
  508. else
  509. exec 'doautocmd User ' . a:event
  510. endif
  511. endif
  512. endfunction
  513. " Function: s:LocalVimRCMatchAny(str, patterns) {{{2
  514. "
  515. " check if any of the regular expressions given in the list patterns matches the
  516. " string. If there is a match, return value is "1". If there is no match,
  517. " return value is "0".
  518. "
  519. function! s:LocalVimRCMatchAny(str, patterns)
  520. for l:pattern in a:patterns
  521. if (match(a:str, l:pattern) != -1)
  522. return 1
  523. endif
  524. endfor
  525. return 0
  526. endfunction
  527. " Function: s:LocalVimRCCalcChecksum(filename) {{{2
  528. "
  529. " calculate checksum and store it in dictionary
  530. "
  531. function! s:LocalVimRCCalcChecksum(file)
  532. let l:checksum = getfsize(a:file) . getfperm(a:file) . getftime(a:file)
  533. call s:LocalVimRCDebug(3, "checksum calc -> " . fnameescape(a:file) . " : " . l:checksum)
  534. return l:checksum
  535. endfunction
  536. " Function: s:LocalVimRCCheckChecksum(filename, checksum) {{{2
  537. "
  538. " Check checksum in dictionary. Return "0" if it does not exist, "1" otherwise
  539. "
  540. function! s:LocalVimRCCheckChecksum(file, checksum)
  541. let l:return = 0
  542. let l:checksum = s:LocalVimRCCalcChecksum(a:file)
  543. if (a:checksum == l:checksum)
  544. let l:return = 1
  545. endif
  546. return l:return
  547. endfunction
  548. " Function: s:LocalVimRCReadPersistent() {{{2
  549. "
  550. " read decision variables from persistence file
  551. "
  552. function! s:LocalVimRCReadPersistent()
  553. if (s:localvimrc_persistent >= 1)
  554. " check if persistence file is readable
  555. if filereadable(s:localvimrc_persistence_file)
  556. " check if reading is needed
  557. let l:checksum = s:LocalVimRCCalcChecksum(s:localvimrc_persistence_file)
  558. if l:checksum != s:localvimrc_persistence_file_checksum
  559. " read persistence file
  560. let l:serialized = readfile(s:localvimrc_persistence_file)
  561. call s:LocalVimRCDebug(3, "read persistent data: " . string(l:serialized))
  562. " deserialize stored persistence information
  563. for l:line in l:serialized
  564. let l:columns = split(l:line, '[^\\]\zs|\|^|', 1)
  565. if len(l:columns) != 3 && len(l:columns) != 4
  566. call s:LocalVimRCDebug(1, "error in persistence file")
  567. call s:LocalVimRCError("error in persistence file")
  568. else
  569. if len(l:columns) == 3
  570. let [ l:key, l:answer, l:checksum ] = l:columns
  571. let l:sandbox = ""
  572. elseif len(l:columns) == 4
  573. let [ l:key, l:answer, l:sandbox, l:checksum ] = l:columns
  574. endif
  575. let l:key = substitute(l:key, '\\|', '|', "g")
  576. let l:answer = substitute(l:answer, '\\|', '|', "g")
  577. let l:sandbox = substitute(l:sandbox, '\\|', '|', "g")
  578. let l:checksum = substitute(l:checksum, '\\|', '|', "g")
  579. let s:localvimrc_data[l:key] = [ l:answer, l:sandbox, l:checksum ]
  580. endif
  581. endfor
  582. else
  583. call s:LocalVimRCDebug(3, "persistence file did not change")
  584. endif
  585. else
  586. call s:LocalVimRCDebug(1, "unable to read persistence file '" . s:localvimrc_persistence_file . "'")
  587. endif
  588. endif
  589. endfunction
  590. " Function: s:LocalVimRCWritePersistent() {{{2
  591. "
  592. " write decision variables to persistence file
  593. "
  594. function! s:LocalVimRCWritePersistent()
  595. if (s:localvimrc_persistent >= 1)
  596. " select only data relevant for persistence
  597. let l:persistent_data = filter(copy(s:localvimrc_data), 'v:val[0] =~# "^[YN]$" || v:val[1] =~# "^[YN]$"')
  598. " if there are answers to store and global variables are enabled for viminfo
  599. if (len(l:persistent_data) > 0)
  600. if l:persistent_data != s:localvimrc_persistent_data
  601. " check if persistence file is writable
  602. if filereadable(s:localvimrc_persistence_file) && filewritable(s:localvimrc_persistence_file) ||
  603. \ !filereadable(s:localvimrc_persistence_file) && filewritable(fnamemodify(s:localvimrc_persistence_file, ":h"))
  604. let l:serialized = [ ]
  605. for [ l:key, l:value ] in items(l:persistent_data)
  606. if len(l:value) == 2
  607. let [ l:answer, l:checksum ] = l:value
  608. let l:sandbox = ""
  609. elseif len(l:value) == 3
  610. let [ l:answer, l:sandbox, l:checksum ] = l:value
  611. else
  612. let l:answer = ""
  613. let l:sandbox = ""
  614. let l:checksum = ""
  615. endif
  616. " delete none persisten answers
  617. if l:answer !~# "^[YN]$"
  618. let l:answer = ""
  619. endif
  620. if l:sandbox !~# "^[YN]$"
  621. let l:sandbox = ""
  622. endif
  623. call add(l:serialized, escape(l:key, '|') . "|" . escape(l:answer, '|') . "|" . escape(l:sandbox, '|') . "|" . escape(l:checksum, '|'))
  624. endfor
  625. call s:LocalVimRCDebug(3, "write persistent data: " . string(l:serialized))
  626. " check if there is a exising persistence file
  627. if filereadable(s:localvimrc_persistence_file)
  628. " first write backup file to avoid lost persistence information
  629. " on write errors if partition is full. Done this way because
  630. " write/rename approach causes permission problems with sudo.
  631. let l:backup_name = s:localvimrc_persistence_file . "~"
  632. let l:backup_content = readfile(s:localvimrc_persistence_file, "b")
  633. if writefile(l:backup_content, l:backup_name, "b") == 0
  634. if writefile(l:serialized, s:localvimrc_persistence_file) == 0
  635. call delete(l:backup_name)
  636. else
  637. call s:LocalVimRCError("error while writing persistence file, backup stored in '" . l:backup_name . "'")
  638. endif
  639. else
  640. call s:LocalVimRCError("unable to write persistence file backup '" . l:backup_name . "'")
  641. endif
  642. else
  643. " there is no persistence file to backup, just write new one
  644. if writefile(l:serialized, s:localvimrc_persistence_file) != 0
  645. call s:LocalVimRCError("unable to write persistence file '" . s:localvimrc_persistence_file . "'")
  646. endif
  647. endif
  648. else
  649. call s:LocalVimRCError("unable to write persistence file '" . s:localvimrc_persistence_file . "'")
  650. endif
  651. " store persistence file checksum
  652. let s:localvimrc_persistence_file_checksum = s:LocalVimRCCalcChecksum(s:localvimrc_persistence_file)
  653. endif
  654. let s:localvimrc_persistent_data = l:persistent_data
  655. endif
  656. else
  657. " delete persistence file
  658. if filewritable(s:localvimrc_persistence_file)
  659. call delete(s:localvimrc_persistence_file)
  660. endif
  661. endif
  662. " remove old persistence data
  663. if exists("g:LOCALVIMRC_ANSWERS")
  664. unlet g:LOCALVIMRC_ANSWERS
  665. endif
  666. if exists("g:LOCALVIMRC_CHECKSUMS")
  667. unlet g:LOCALVIMRC_CHECKSUMS
  668. endif
  669. endfunction
  670. " Function: s:LocalVimRCClear() {{{2
  671. "
  672. " clear all stored data
  673. "
  674. function! s:LocalVimRCClear()
  675. let s:localvimrc_data = {}
  676. call s:LocalVimRCDebug(3, "cleared local data")
  677. let s:localvimrc_persistence_file_checksum = ""
  678. call s:LocalVimRCDebug(3, "cleared persistence file checksum")
  679. let s:localvimrc_persistent_data = {}
  680. call s:LocalVimRCDebug(3, "cleared persistent data")
  681. if filewritable(s:localvimrc_persistence_file)
  682. call delete(s:localvimrc_persistence_file)
  683. call s:LocalVimRCDebug(3, "deleted persistence file")
  684. endif
  685. endfunction
  686. " Function: LocalVimRCEnable() {{{2
  687. "
  688. " enable processing of local vimrc files
  689. "
  690. function! s:LocalVimRCEnable()
  691. " if this call really enables the plugin load the local vimrc files for the
  692. " current buffer
  693. if s:localvimrc_enable == 0
  694. call s:LocalVimRCDebug(1, "enable processing of local vimrc files")
  695. let s:localvimrc_enable = 1
  696. call s:LocalVimRC()
  697. endif
  698. endfunction
  699. " Function: LocalVimRCDisable() {{{2
  700. "
  701. " disable processing of local vimrc files
  702. "
  703. function! s:LocalVimRCDisable()
  704. call s:LocalVimRCDebug(1, "disable processing of local vimrc files")
  705. let s:localvimrc_enable = 0
  706. endfunction
  707. " Function: LocalVimRCFinish() {{{2
  708. "
  709. " finish processing of local vimrc files
  710. "
  711. function! LocalVimRCFinish()
  712. call s:LocalVimRCDebug(1, "will finish sourcing files after this file")
  713. let s:localvimrc_finish = 1
  714. endfunction
  715. " Function: s:LocalVimRCError(text) {{{2
  716. "
  717. " output error message
  718. "
  719. function! s:LocalVimRCError(text)
  720. echohl ErrorMsg | echom "localvimrc: " . a:text | echohl None
  721. endfunction
  722. " Function: s:LocalVimRCDebug(level, text) {{{2
  723. "
  724. " output debug message, if this message has high enough importance
  725. "
  726. function! s:LocalVimRCDebug(level, text)
  727. if (g:localvimrc_debug >= a:level)
  728. echom "localvimrc: " . a:text
  729. endif
  730. endfunction
  731. " Function: s:LocalVimRCEdit() {{{2
  732. "
  733. " open the local vimrc file for the current buffer in an split window for
  734. " editing. If more than one local vimrc file has been sourced, the user
  735. " can decide which file to edit.
  736. "
  737. function! s:LocalVimRCEdit()
  738. if exists("b:localvimrc_sourced_files")
  739. let l:items = len(b:localvimrc_sourced_files)
  740. if l:items == 0
  741. call s:LocalVimRCError("No local vimrc file has been sourced")
  742. elseif l:items == 1
  743. " edit the only sourced file
  744. let l:file = b:localvimrc_sourced_files[0]
  745. elseif l:items > 1
  746. " build message for asking the user
  747. let l:message = [ "Select local vimrc file to edit:" ]
  748. call extend(l:message, map(copy(b:localvimrc_sourced_files), 'v:key+1 . " " . v:val'))
  749. " ask the user which one should be edited
  750. let l:answer = inputlist(l:message)
  751. if l:answer =~ '^\d\+$' && l:answer > 0 && l:answer <= l:items
  752. let l:file = b:localvimrc_sourced_files[l:answer-1]
  753. endif
  754. endif
  755. if exists("l:file")
  756. execute 'silent! split ' . fnameescape(l:file)
  757. endif
  758. endif
  759. endfunction
  760. " Section: Commands {{{1
  761. command! LocalVimRC call s:LocalVimRC()
  762. command! LocalVimRCClear call s:LocalVimRCClear()
  763. command! LocalVimRCEdit call s:LocalVimRCEdit()
  764. command! LocalVimRCEnable call s:LocalVimRCEnable()
  765. command! LocalVimRCDisable call s:LocalVimRCDisable()
  766. " vim600: foldmethod=marker foldlevel=0 :