├── .github └── workflows │ └── ci.yml ├── LICENSE ├── doc ├── autosource.txt └── tags ├── init.vim ├── plugin └── autosource.vim ├── readme.md ├── static ├── example.gif └── security_example.gif └── tests ├── approve_file.vader └── autosource.vader /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | jobs: 13 | lint: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v2 17 | 18 | - name: install dependencies 19 | run: > 20 | sudo apt-get update -y \ 21 | && sudo apt-get upgrade -y \ 22 | && sudo apt-get install -y python3-pip \ 23 | && pip3 install --user vim-vint 24 | 25 | - name: lint 26 | run: ~/.local/bin/vint **/*.vim 27 | test: 28 | runs-on: ubuntu-latest 29 | steps: 30 | - uses: actions/checkout@v2 31 | 32 | - name: install dependencies 33 | run: > 34 | sudo apt-get update -y \ 35 | && sudo apt-get upgrade -y \ 36 | && sudo apt-get install -y git vim \ 37 | && git clone https://github.com/junegunn/vader.vim vader 38 | 39 | - name: test 40 | run : vim -Nu init.vim -c "Vader! tests/**/*.vader" > /dev/null 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 Jordan Enterkin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /doc/autosource.txt: -------------------------------------------------------------------------------- 1 | *autosource.txt* Because every project deserves its own .vimrc 2 | *autosource* *AutoSource* 3 | 4 | __ _ _ _| |_ ___ ___ ___ _ _ _ __ ___ ___ ~ 5 | / _` | | | | __/ _ \/ __|/ _ \| | | | '__/ __/ _ \ ~ 6 | | (_| | |_| | || (_) \__ \ (_) | |_| | | | (_| __/ ~ 7 | \__,_|\__,_|\__\___/|___/\___/ \__,_|_| \___\___| ~ 8 | 9 | Because every project deserves its own '.vimrc'. 10 | Looks for .vimrc files in the directory of the current file and 11 | loads them in a secure way. 12 | 13 | =============================================================================== 14 | CONTENTS *autosource-contents* 15 | 16 | 1. Introduction .................... |autosource-introduction| 17 | 2. Configuration ................... |autosource-configuration| 18 | 3. Commands ........................ |autosource-commands| 19 | 4. Contributing .................... |autosource-contributing| 20 | 4.1 How to contribute .......... |autosource-contribute| 21 | 4.2 License .................... |autosource-license| 22 | 23 | 24 | =============================================================================== 25 | 1: Introduction *autosource-introduction* 26 | 27 | AutoSource is a Vim plugin that enables per project configuration by finding 28 | each Vim configuration file (.vimrc or .vimrc.lua by default) from your home 29 | directory to the opened file. 30 | 31 | To prevent arbitrary code execution attacks, AutoSource will prompt you to 32 | approve new .vimrc files and to re-approve those which have changed. By default 33 | AutoSource will automatically approve config changes made through Vim. 34 | 35 | Why autosource? I work on many projects and each project has its' own standards 36 | and requirements. This means I can't configure Vim to handle a given language 37 | in a single way. I'll also commonly open a file in a different repo than I'm 38 | currently in to tweak something (e.g. an API response), then hop back to what I 39 | was originally doing (e.g. writing some client code that consumes said API 40 | endpoint). 41 | 42 | I wrote AutoSource because the available options (exrc and other plugins) 43 | didn't have either the functionality or security features that I wanted. 44 | AutoSource is configurable, unobtrusive, and secure. 45 | 46 | =============================================================================== 47 | 2: Configuration *autosource-configuration* 48 | 49 | g:autosource_hashdir 50 | 51 | Default "$HOME/.autosource_hashes" 52 | 53 | This directory is where AutoSource stores the hashes of your files. These 54 | hashes are used to check for changes so the plugin can prompt you for 55 | re-approval. 56 | 57 | 58 | g:autosource_disable_autocmd 59 | 60 | Default "0" 61 | 62 | If set to 1, the autocmd that triggers AutoSource will not be enabled. This 63 | can be useful if you would like more fine-grained control over when and how it 64 | is run. For example, if you only want to run it when you start Vim you can set 65 | the following autocmd: 66 | > 67 | augroup sourceparents 68 | autocmd! 69 | autocmd VimEnter * nested call AutoSource(expand(':p:h')) 70 | augroup END 71 | < 72 | 73 | g:autosource_approve_on_save 74 | 75 | Default "1" 76 | 77 | When set to 1, AutoSource will automatically approve .vimrc and .vimrc.lua 78 | files when you save them. This reduces the number of approval prompts you'll 79 | have to see while still getting prompted when the file is changed outside of 80 | Vim (e.g. someone puts a malicious .vimrc file in a repo that you've cloned). 81 | 82 | If you'd like to be approved even when you saved the config through Vim, set 83 | this option to 0. 84 | 85 | 86 | g:autosource_conf_names 87 | 88 | Default "['.vimrc', '.vimrc.lua']" 89 | 90 | These are the file names that AutoSource looks for to source. You can set this 91 | to either a string if you're only specifying a single file, or a list if you'd 92 | like to check against multiple. 93 | 94 | In order for a lua file to be sourced correctly it must end with .lua. 95 | > 96 | let g:autosource_conf_names = '.lvimrc' 97 | " or to check multiple 98 | let g:autosource_conf_names = ['.lvimrc', '.lvimrc.lua'] 99 | < 100 | 101 | g:autosource_prompt_for_new_file 102 | 103 | Default "1" 104 | 105 | The primary use-case of this option is to support automated testing. 106 | 107 | When set to 0 AutoSource will not prompt you when it detects a new file. The 108 | file will NOT be sourced. 109 | 110 | 111 | g:autosource_prompt_for_changed_file 112 | 113 | Default "1" 114 | 115 | The primary use-case of this option is to support automated testing. 116 | 117 | When set to 0 AutoSource will not prompt you when it detects when a file is 118 | changed. The file will NOT be sourced. 119 | 120 | 121 | g:autosource_search_from_root 122 | 123 | Default "1" 124 | 125 | Use to search from / instead of $HOME. 126 | 127 | =============================================================================== 128 | 3: Commands *autosource-commands* 129 | 130 | :Autosource :*Autosource* 131 | 132 | Sources parents of the current file. 133 | 134 | :AutosourceApproveFile *:AutosourceApproveFile* 135 | 136 | Approves the current file. 137 | 138 | =============================================================================== 139 | 4: Contributing *autosource-contributing* 140 | 141 | ------------------------------------------------------------------------------- 142 | 4.1: How to contribute *autosource-contribute* 143 | 144 | https://github.com/jenterkin/vim-autosource 145 | 146 | Want to see a new feature? Report a bug? Feel free to submit issues on the 147 | issues page. 148 | 149 | ------------------------------------------------------------------------------- 150 | 4.2: License *autosource-license* 151 | 152 | See `LICENSE` file. 153 | 154 | vim:tw=78:sw=4:ft=help:norl: 155 | -------------------------------------------------------------------------------- /doc/tags: -------------------------------------------------------------------------------- 1 | :AutosourceApproveFile autosource.txt /*:AutosourceApproveFile* 2 | AutoSource autosource.txt /*AutoSource* 3 | autosource autosource.txt /*autosource* 4 | autosource-commands autosource.txt /*autosource-commands* 5 | autosource-configuration autosource.txt /*autosource-configuration* 6 | autosource-contents autosource.txt /*autosource-contents* 7 | autosource-contribute autosource.txt /*autosource-contribute* 8 | autosource-contributing autosource.txt /*autosource-contributing* 9 | autosource-introduction autosource.txt /*autosource-introduction* 10 | autosource-license autosource.txt /*autosource-license* 11 | autosource.txt autosource.txt /*autosource.txt* 12 | -------------------------------------------------------------------------------- /init.vim: -------------------------------------------------------------------------------- 1 | " Used to init tests 2 | 3 | " vint: next-line -ProhibitSetNoCompatible 4 | " set nocompatible " required by Vader 5 | 6 | set runtimepath+=~. 7 | set runtimepath+=./vader 8 | 9 | source ./plugin/autosource.vim 10 | source ./vader/plugin/vader.vim 11 | 12 | set autochdir 13 | let g:autosource_disable_autocmd = 1 14 | -------------------------------------------------------------------------------- /plugin/autosource.vim: -------------------------------------------------------------------------------- 1 | " autosource.vim - AutoSource 2 | " Author: Jordan Enterkin 3 | " Version: 0.1 4 | " Licence: MIT 5 | " The MIT License (MIT) 6 | " 7 | " Copyright (c) 2021 Jordan Enterkin 8 | " 9 | " Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 10 | " 11 | " The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 12 | " 13 | " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 14 | 15 | function! s:EchoWarning(msg) 16 | echohl WarningMsg 17 | echo 'Warning' 18 | echohl None 19 | echon ': ' a:msg 20 | endfunction 21 | 22 | function! s:GetPromptForChangedConf() 23 | if exists('g:autosource_prompt_for_changed_conf') 24 | return g:autosource_prompt_for_changed_conf 25 | endif 26 | return 1 27 | endfunction 28 | 29 | function! s:GetPromptForNewConf() 30 | if exists('g:autosource_prompt_for_new_conf') 31 | return g:autosource_prompt_for_new_conf 32 | endif 33 | return 1 34 | endfunction 35 | 36 | function! s:GetAutoSourceConfNames() 37 | if exists('g:autosource_conf_names') 38 | if type(g:autosource_conf_names) !=# v:t_list 39 | return [g:autosource_conf_names] 40 | endif 41 | return g:autosource_conf_names 42 | endif 43 | return ['.vimrc', '.vimrc.lua'] 44 | endfunction 45 | 46 | function! s:GetAutoSourceApproveOnSave() 47 | if exists('g:autosource_approve_on_save') 48 | return g:autosource_approve_on_save 49 | endif 50 | return 1 51 | endfunction 52 | 53 | function! s:GetAutoSourceDisableAutoCmd() 54 | if exists('g:autosource_disable_autocmd') 55 | return g:autosource_disable_autocmd 56 | endif 57 | return 0 58 | endfunction 59 | 60 | function! s:GetSearchFromRoot() 61 | if exists('g:autosource_search_from_root') 62 | return g:autosource_search_from_root 63 | endif 64 | return 0 65 | endfunction 66 | 67 | function! s:GetAutoSourceHashDir() 68 | if exists('g:autosource_hashdir') 69 | let dir = g:autosource_hashdir 70 | else 71 | let dir = $HOME . '/.autosource_hashes' 72 | endif 73 | 74 | if isdirectory(dir) 75 | return dir 76 | else 77 | if filereadable(dir) 78 | echo dir . ' is a file. Please delete it or set `g:autosource_hashdir` to another location' 79 | else 80 | call mkdir(dir, 'p') 81 | return dir 82 | endif 83 | endif 84 | endfunction 85 | 86 | function! s:GetHashLocation(path) 87 | let filename_hash = s:HashString(a:path) 88 | return s:GetAutoSourceHashDir() . '/' . filename_hash 89 | endfunction 90 | 91 | function! s:HashFile(file) 92 | let content = join(readfile(a:file), '\n') 93 | return sha256(content) 94 | endfunction 95 | 96 | function! s:HashString(string) 97 | return sha256(a:string) 98 | endfunction 99 | 100 | function! s:GetKnownHash(path) 101 | let hash_location = s:GetHashLocation(a:path) 102 | " TODO: check if file exists, warn separately if exists and is not 103 | " readable. 104 | if !filereadable(hash_location) 105 | return '' 106 | endif 107 | let data = join(readfile(hash_location), '\n') 108 | return data 109 | endfunction 110 | 111 | function! s:SetHash(path) 112 | let found = 0 113 | let filename = split(a:path, '/')[-1] 114 | let names = s:GetAutoSourceConfNames() 115 | for name in names 116 | if filename == name 117 | let found = 1 118 | endif 119 | endfor 120 | if found ==# 0 121 | " TODO: warn 122 | call s:EchoWarning('Attempted to approve file not in g:autosource_conf_names (' . join(names, ', ') .'): ' . filename) 123 | return 124 | endif 125 | let hash_location = s:GetHashLocation(a:path) 126 | let data_hash = s:HashFile(a:path) 127 | call writefile([data_hash], hash_location) 128 | endfunction 129 | 130 | function! s:CheckHash(path) 131 | let dir = s:GetAutoSourceHashDir() 132 | let known_hash = s:GetKnownHash(a:path) 133 | 134 | " Check if new file 135 | if known_hash ==# '' 136 | if s:GetPromptForNewConf() ==# 0 137 | return 0 138 | endif 139 | let answer = confirm(a:path . ' is a new file. Would you like to allow sourcing it? (Choose no to inspect this file and re-open it to approve.)', "&yes\n&No", 2) 140 | if answer ==# 1 141 | call s:SetHash(a:path) 142 | return 1 143 | else 144 | return 0 145 | endif 146 | endif 147 | 148 | " Check if file has changed 149 | if known_hash !=# s:HashFile(a:path) 150 | if s:GetPromptForChangedConf() ==# 0 151 | return 0 152 | endif 153 | let answer = confirm(a:path . ' has been updated. Would you like to allow sourcing it? (Choose no to inspect this file and re-open it to approve.)', "&yes\n&No", 2) 154 | if answer ==# 1 155 | call s:SetHash(a:path) 156 | return 1 157 | else 158 | return 0 159 | endif 160 | endif 161 | return 1 162 | endfunction 163 | 164 | " Source all `.vimrc` files in your pwd and parents up to your home dir 165 | function! AutoSource(dir) 166 | let i = 0 167 | let crumbs = split(a:dir, '/') 168 | while i < len(crumbs) 169 | let cur = '/' . join(crumbs[0:i], '/') 170 | let i += 1 171 | 172 | if !s:GetSearchFromRoot() && cur !~ $HOME 173 | continue 174 | endif 175 | 176 | for fname in s:GetAutoSourceConfNames() 177 | let rc = cur . '/' . fname 178 | if filereadable(rc) && s:CheckHash(rc) ==# 1 179 | if rc =~? '\M.lua$' 180 | if has('nvim') 181 | exec printf('luafile %s', rc) 182 | endif 183 | else 184 | exec printf('source %s', rc) 185 | endif 186 | endif 187 | endfor 188 | endwhile 189 | endfunction 190 | 191 | " Function that autocmd calls to trigger AutoSource. Used to allow 192 | " enabling/disabling on the fly. 193 | function! s:autocmdTriggerAutoSource(dir) 194 | if s:GetAutoSourceDisableAutoCmd() !=# 1 195 | call AutoSource(a:dir) 196 | endif 197 | endfunction 198 | 199 | function! AutoSourceApproveFile(path) 200 | call s:SetHash(a:path) 201 | endfunction 202 | 203 | " Function that autocmd calls to trigger AutoSourceApproveFile. Used to allow 204 | " enabling/disabling on the fly. 205 | function! s:autocmdTriggerAutoSourceApproveFile(path) 206 | if s:GetAutoSourceApproveOnSave() ==# 1 207 | call AutoSourceApproveFile(a:path) 208 | endif 209 | endfunction 210 | 211 | augroup AutoSource 212 | autocmd! 213 | autocmd BufReadPre,BufNewFile * nested call s:autocmdTriggerAutoSource(expand(':p:h')) 214 | execute 'autocmd BufWritePost ' . join(s:GetAutoSourceConfNames(), ',') . ' call s:autocmdTriggerAutoSourceApproveFile(expand(":p"))' 215 | augroup END 216 | 217 | command! AutoSource call AutoSource(expand('%:p:h')) 218 | command! AutoSourceApproveFile call AutoSourceApproveFile(expand('%:p')) 219 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # AutoSource ![ci workflow](https://github.com/jenterkin/vim-autosource/actions/workflows/ci.yml/badge.svg) 2 | AutoSource is a Vim plugin that enables per project configuration by finding each Vim configuration file (`.vimrc` or `.vimrc.lua` by default) from your `$HOME` directory to the opened file. 3 | 4 | ![Example usage](static/example.gif) 5 | 6 | ## Security 7 | To prevent arbitrary code execution attacks, AutoSource will prompt you to approve new `.vimrc` files and to re-approve those which have changed. By default AutoSource will automatically approve config changes made through Vim. See [`g:autosource_approve_on_save`](#g:autosource_approve_on_save) for more info. 8 | 9 | ![Security example](static/security_example.gif) 10 | 11 | In this gif I answered "no" to the prompt so that it was not sourced, then opened the `.vimrc` file that was cloned with the repo to see the _very_ malicious code inside. 12 | 13 | ## Why AutoSource 14 | I work on many projects and each project has its' own standards and requirements. This means I can't configure Vim to handle a given language in a single way. I'll also commonly open a file in a different repo than I'm currently in to tweak something (e.g. an API response), then hop back to what I was originally doing (e.g. writing some client code that consumes said API endpoint). 15 | 16 | I wrote AutoSource because the available options (`exrc` and other plugins) didn't have either the functionality or security features that I wanted. AutoSource is configurable, unobtrusive, and secure. 17 | 18 | ## Installation 19 | ### Plug 20 | **[Home Page](https://github.com/junegunn/vim-plug)** 21 | 22 | ```vim 23 | Plug 'jenterkin/vim-autosource' 24 | ``` 25 | 26 | ### packer.nvim 27 | **[Home Page](https://github.com/wbthomason/packer.nvim)** 28 | 29 | ```lua 30 | use 'jenterkin/vim-autosource' 31 | ``` 32 | 33 | or if you'd like to set options after it loads: 34 | 35 | ```lua 36 | use { 37 | 'jenterkin/vim-autosource', 38 | config = function() 39 | vim.g.autosource_hashdir = '$XDG_CACHE_HOME/vim-autosource/hashes' 40 | end 41 | } 42 | ``` 43 | 44 | ## Lua files 45 | AutoSource will also look for `.vimrc.lua` files and source them with `:luafile`. 46 | 47 | ## Variables 48 | ### `g:autosource_hashdir` 49 | **Default:** `$HOME/.autosource_hashes` 50 | 51 | This directory is where AutoSource stores the hashes of your files. These hashes are used to check for changes so the plugin can prompt you for re-approval. 52 | 53 | ### `g:autosource_disable_autocmd` 54 | **Default:** `0` 55 | 56 | If set to `1`, the autocmd that triggers AutoSource will not be enabled. This can be useful if you would like more fine-grained control over when and how it is run. For example, if you only want to run it when you start Vim you can set the following `autocmd`: 57 | 58 | ```vim 59 | augroup sourceparents 60 | autocmd! 61 | autocmd VimEnter * nested call AutoSource(expand(':p:h')) 62 | augroup END 63 | ``` 64 | 65 | ### `g:autosource_approve_on_save` 66 | **Default:** `1` 67 | 68 | When set to 1, AutoSource will automatically approve `.vimrc` and `.vimrc.lua` files when you save them. This reduces the number of approval prompts you'll have to see while still getting prompted when the file is changed outside of Vim (e.g. someone puts a malicious `.vimrc` file in a repo that you've cloned). 69 | 70 | If you'd like to be approved even when you saved the config through Vim, set this option to 0. 71 | 72 | ### `g:autosource_conf_names` 73 | **Default:** `['.vimrc', '.vimrc.lua']` 74 | 75 | These are the file names that AutoSource looks for to source. You can set this to either a string if you're only specifying a single file, or a list if you'd like to check against multiple. 76 | 77 | ```vim 78 | let g:autosource_conf_names = '.lvimrc' 79 | " or to check multiple 80 | let g:autosource_conf_names = ['.lvimrc', '.lvimrc.lua'] 81 | ``` 82 | 83 | ### `g:autosource_prompt_for_new_file` 84 | **Default:** `1` 85 | 86 | The primary use-case of this option is to support automated testing. 87 | 88 | When set to `0` AutoSource will not prompt you when it detects a new file. The file will **NOT** be sourced. 89 | 90 | ### `g:autosource_prompt_for_changed_file` 91 | **Default:** `1` 92 | 93 | The primary use-case of this option is to support automated testing. 94 | 95 | When set to `0` AutoSource will not prompt you when it detects when a file is changed. The file will **NOT** be sourced. 96 | 97 | ### `g:autosource_search_from_root` 98 | **Default:** `0` 99 | 100 | Use to search from `/` instead of `$HOME`. 101 | 102 | #### Lua Support 103 | In order for a lua file to be sourced correctly it **must** end with `.lua`. 104 | 105 | ## Commands 106 | 107 | ### `:AutoSource` 108 | Sources parents of the current file. 109 | 110 | ### `:AutoSourceApproveFile` 111 | Approves the current file. 112 | 113 | ## Want to see a new feature? Report a bug? 114 | Feel free to submit issues on the [issues page](https://github.com/jenterkin/vim-autosource/issues). 115 | 116 | ## Similar Projects 117 | - [exrc.vim](https://github.com/ii14/exrc.vim) 118 | - [local_vimrc](https://github.com/LucHermitte/local_vimrc) 119 | - [nvim-projectconfig](https://github.com/windwp/nvim-projectconfig) 120 | - [vim-projectlocal](https://github.com/krisajenkins/vim-projectlocal) 121 | 122 | ## Supported Operating Systems 123 | AutoSource only supports MacOS and Linux. Windows is not actively tested. If you would like to fix any Windows-specific issues, feel free to submit a PR. 124 | -------------------------------------------------------------------------------- /static/example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenterkin/vim-autosource/569440e157d6eb37fb098dfe95252533553a56f5/static/example.gif -------------------------------------------------------------------------------- /static/security_example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jenterkin/vim-autosource/569440e157d6eb37fb098dfe95252533553a56f5/static/security_example.gif -------------------------------------------------------------------------------- /tests/approve_file.vader: -------------------------------------------------------------------------------- 1 | Before (Create Temporary Test Data): 2 | let g:autosource_disable_autocmd = 1 3 | let g:autosource_approve_on_save = 0 4 | 5 | let g:test_path = getcwd() . '/.test-bed' 6 | let g:autosource_hashdir = g:test_path . '/hashes' 7 | 8 | call mkdir(g:test_path) 9 | 10 | function! g:SetupConf(filename) 11 | let path = g:test_path . '/' . a:filename 12 | call writefile([''], path) 13 | return { 14 | \ 'path': path, 15 | \ 'filename_hash': sha256(path), 16 | \ 'data_hash': sha256(join(readfile(path), '\n')), 17 | \} 18 | endfunction 19 | 20 | After (Teardown Test Data): 21 | unlet g:autosource_hashdir 22 | unlet g:autosource_disable_autocmd 23 | unlet g:autosource_approve_on_save 24 | 25 | if exists('g:assertion_data') 26 | unlet g:assertion_data 27 | endif 28 | 29 | call delete(g:test_path, 'rf') 30 | unlet g:test_path 31 | 32 | Execute (Approve .vimrc): 33 | let g:assertion_data = g:SetupConf('.vimrc') 34 | call AutoSourceApproveFile(g:assertion_data.path) 35 | 36 | Then (Verify hash was written): 37 | Assert join(readfile(g:autosource_hashdir . '/' . g:assertion_data.filename_hash), '\n') ==# g:assertion_data.data_hash 38 | 39 | Execute (Approve invalid rc): 40 | let g:assertion_data = g:SetupConf('invalid') 41 | call AutoSourceApproveFile(g:assertion_data.path) 42 | 43 | Then (Verify the hash was not written): 44 | Assert filereadable(g:autosource_hashdir . '/' . g:assertion_data.filename_hash) ==# 0 45 | -------------------------------------------------------------------------------- /tests/autosource.vader: -------------------------------------------------------------------------------- 1 | Before (Create Temporary Test Data): 2 | let g:autosource_disable_autocmd = 1 3 | let g:autosource_approve_on_save = 0 4 | let g:autosource_prompt_for_new_conf = 0 5 | let g:autosource_prompt_for_changed_conf = 0 6 | 7 | let g:test_path = getcwd() . '/.test-bed' 8 | let g:autosource_hashdir = g:test_path . '/hashes' 9 | 10 | call mkdir(g:test_path) 11 | 12 | After (Teardown Test Data): 13 | unlet g:autosource_hashdir 14 | unlet g:autosource_disable_autocmd 15 | unlet g:autosource_approve_on_save 16 | 17 | call delete(g:test_path, 'rf') 18 | unlet g:test_path 19 | 20 | Execute (Source from File Next to a Config): 21 | let rc_file = g:test_path . '/.vimrc' 22 | call writefile(['let g:it_worked = 1'], rc_file) 23 | call AutoSourceApproveFile(rc_file) 24 | call AutoSource(g:test_path . '/other_file') 25 | 26 | Then (Verify that the Config was Sourced): 27 | Assert exists('g:it_worked') ==# 1 28 | Assert g:it_worked ==# 1 29 | unlet g:it_worked 30 | 31 | Execute (Source from Un-Approved File Next to a Config): 32 | let rc_file = g:test_path . '/.vimrc' 33 | call writefile(['let g:it_did_not_work = 1'], rc_file) 34 | call AutoSource(g:test_path . '/other_file') 35 | 36 | Then (Verify that the Config was NOT Sourced): 37 | Assert exists('g:it_did_not_work') ==# 0 38 | 39 | Execute (Source from Approved File After Un-Approved Change): 40 | let rc_file = g:test_path . '/.vimrc' 41 | call writefile(['let g:it_did_not_work = 1'], rc_file) 42 | call AutoSourceApproveFile(rc_file) 43 | call AutoSource(g:test_path . '/other_file') 44 | call writefile(['let g:it_did_not_work = 2'], rc_file) 45 | call AutoSource(g:test_path . '/other_file') 46 | 47 | Then (Verify that the Config was NOT Sourced): 48 | " Assert that it exists since it was sourced initially 49 | Assert exists('g:it_did_not_work') ==# 1 50 | " However, the value did not change sinc the new config was not approved 51 | Assert g:it_did_not_work ==# 1 52 | 53 | Execute (Source from File Under Two Configs): 54 | let first_parent_rc = g:test_path . '/a/.vimrc' 55 | let second_parent_rc = g:test_path . '/a/b/.vimrc' 56 | let work_file = g:test_path . '/a/b/c/some_file' 57 | 58 | let path = g:test_path 59 | for dir in ['a', 'b', 'c'] 60 | let path = path . '/' . dir 61 | call mkdir(path) 62 | endfor 63 | 64 | call writefile(['let g:first_parent = 1'], first_parent_rc) 65 | call writefile(['let g:second_parent = 2'], second_parent_rc) 66 | call AutoSourceApproveFile(first_parent_rc) 67 | call AutoSourceApproveFile(second_parent_rc) 68 | call AutoSource(work_file) 69 | 70 | Then (Verify Both Configs were Sourced): 71 | Assert exists('g:first_parent') ==# 1 72 | Assert exists('g:second_parent') ==# 1 73 | Assert g:first_parent ==# '1' 74 | Assert g:second_parent ==# 2 75 | unlet g:first_parent 76 | unlet g:second_parent 77 | --------------------------------------------------------------------------------