├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── autoload ├── editorconfig.vim └── editorconfig │ ├── c_include_path.vim │ ├── charset.vim │ ├── end_of_line.vim │ ├── indent_size.vim │ ├── indent_style.vim │ ├── insert_final_newline.vim │ ├── max_line_length.vim │ ├── root.vim │ ├── spell_language.vim │ ├── tab_width.vim │ └── trim_trailing_whitespace.vim ├── doc └── editorconfig.txt ├── ftdetect └── editorconfig.vim ├── ftplugin └── editorconfig.vim └── plugin └── editorconfig.vim /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.vim] 4 | insert_final_newline = true 5 | indent_style = space 6 | indent_size = 2 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | doc/tags 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 sgur 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vim-editorconfig 2 | 3 | Yet another Vim plugin for [EditorConfig](http://editorconfig.org) 4 | 5 | ## **Importants** 6 | 7 | - [editorconfig/editorconfig-vim](https://github.com/editorconfig/editorconfig-vim) 8 | 9 | The official [editorconfig-vim](https://github.com/editorconfig/editorconfig-vim) 10 | has no external dependencies. It doesn't require `if_python` interface anymore. 11 | 12 | See [#119](https://github.com/editorconfig/editorconfig-vim/pull/119) for details. 13 | 14 | ## Description 15 | 16 | ### Supported Properties 17 | 18 | - `charset` 19 | - `end_of_line` 20 | - `indent_size` 21 | - `indent_style` 22 | - `insert_final_newline` 23 | - `max_line_length` 24 | - `root` 25 | - `tab_width` 26 | - `trim_trailing_whitespace` 27 | 28 | Properties below are enabled only in this plugin: 29 | 30 | - `c_include_path` 31 | - `spell_language` 32 | 33 | Usage 34 | ----- 35 | 36 | 1. Install the plugin 37 | 2. Locate `.editorconfig` 38 | 3. Edit some files 39 | 40 | Options 41 | ------- 42 | 43 | ### g:editorconfig\_blacklist 44 | 45 | Exclude regexp patterns for filetypes or filepaths 46 | 47 | ```vim 48 | let g:editorconfig_blacklist = { 49 | \ 'filetype': ['git.*', 'fugitive'], 50 | \ 'pattern': ['\.un~$']} 51 | ``` 52 | 53 | ### g:editorconfig\_root\_chdir 54 | 55 | Automatically `:lcd` If `root = true` exists in `.editorconfig`. 56 | 57 | ### g:editorconfig\_verbose 58 | 59 | Show verbose messages 60 | 61 | ```vim 62 | let g:editorconfig_verbose = 1 " 0 by default 63 | ``` 64 | 65 | Install 66 | ------- 67 | 68 | Use your favorite plugin manager. 69 | 70 | License 71 | ------- 72 | 73 | MIT License 74 | 75 | Author 76 | ------ 77 | 78 | sgur 79 | 80 | -------------------------------------------------------------------------------- /autoload/editorconfig.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | 3 | let s:save_cpo = &cpo 4 | set cpo&vim 5 | 6 | let s:editorconfig = '.editorconfig' 7 | 8 | let s:scriptdir = expand(':p:r') 9 | 10 | " {{{1 Interfaces 11 | 12 | " >>> let g:editorconfig_blacklist = {'filetype': [], 'pattern': []} 13 | " >>> call editorconfig#load() 14 | " 15 | function! editorconfig#load() abort 16 | augroup plugin-editorconfig-local 17 | autocmd! * 18 | augroup END 19 | if !&modifiable 20 | " Ignore nomodifiable files 21 | return 22 | endif 23 | let filepath = expand('%:p') 24 | if s:blacklist(filepath, &filetype) 25 | return 26 | endif 27 | let rule = s:scan(fnamemodify(filepath, ':h')) 28 | if len(rule) > 0 && has_key(rule[0][1], 'root') 29 | let filepath = s:trim_root(filepath, rule[0][1]['root']) 30 | endif 31 | let props = s:filter_matched(rule, filepath) 32 | if empty(props) | return | endif 33 | call s:fill_defaults(props) 34 | let b:editorconfig = props 35 | let unsupported = s:apply(props) 36 | if empty(unsupported) 37 | return 38 | endif 39 | for key in unsupported 40 | let b:editorconfig[key] = 'UNSUPPORTED' 41 | endfor 42 | if get(g:, 'editorconfig_verbose', 0) 43 | echohl WarningMsg | echomsg 'editorconfig: Unsupported property:' join(unsupported, ',') | echohl NONE 44 | endif 45 | endfunction 46 | 47 | function! editorconfig#omnifunc(findstart, base) abort 48 | if a:findstart 49 | let pos = match(getline('.'), '\%' . col('.') . 'c\k\+\zs\s*=') 50 | return pos+1 51 | else 52 | return filter(sort(s:properties()), 'stridx(v:val, a:base) == 0') 53 | endif 54 | endfunction 55 | 56 | " {{{1 Inner functions 57 | 58 | " if `root = true` then dirname is located at s:scan(...)[0] 59 | " >>> let s:root = s:scan(expand('%:p:h'))[0] 60 | " >>> echo type(s:root) isdirectory(s:root[1].root) 61 | " 3 1 62 | 63 | " >>> let [s:pattern, s:config] = s:scan(expand('%:p:h'))[1] 64 | " >>> echo s:pattern 65 | " *.vim 66 | 67 | " >>> echo s:config.insert_final_newline s:config.indent_style s:config.indent_size 68 | " true space 2 69 | 70 | function! s:scan(path) abort "{{{ 71 | let editorconfig = findfile(s:editorconfig, fnameescape(a:path) . ';') 72 | if empty(editorconfig) || !filereadable(editorconfig) || a:path is# fnamemodify(a:path, ':h') 73 | return [] 74 | endif 75 | let base_path = fnamemodify(editorconfig, ':p:h') 76 | let [is_root, _] = s:parse(s:trim(readfile(editorconfig))) 77 | if is_root 78 | return [['*', {'root': base_path}]] + _ 79 | endif 80 | return s:scan(fnamemodify(base_path, ':h')) + _ 81 | endfunction "}}} 82 | 83 | " Parse lines into rule lists 84 | " >>> let [s:is_root, s:lists] = s:parse(['root = false', '[*]', 'indent_size = 2']) 85 | " >>> echo s:is_root 86 | " 0 87 | " >>> echo s:lists[0][0] 88 | " * 89 | " >>> echo s:lists[0][1] 90 | " {'indent_size': 2} 91 | " >>> let g:editorconfig_verbose = 1 92 | " >>> echo s:parse(['root = false', '[*', 'indent_size = 2']) 93 | " Vim(echoerr):editorconfig: failed to parse [* 94 | " >>> let g:editorconfig_verbose = 0 95 | " >>> echo s:parse(['root = false', '[*', 'indent_size = 2']) 96 | " [0, []] 97 | 98 | function! s:parse(lines) abort "{{{ 99 | let [unparsed, is_root] = s:parse_properties(a:lines) 100 | let _ = [] 101 | while len(unparsed) > 0 102 | let [unparsed, pattern] = s:parse_pattern(unparsed) 103 | let [unparsed, properties] = s:parse_properties(unparsed) 104 | let _ += [[pattern, properties]] 105 | endwhile 106 | return [get(is_root, 'root', 'false') ==# 'true', _] 107 | endfunction "}}} 108 | 109 | " Parse file glob pattern 110 | " >>> echo s:parse_pattern([]) 111 | " [[], ''] 112 | " >>> echo s:parse_pattern(['[*.vim]', 'abc']) 113 | " [['abc'], '*.vim'] 114 | " >>> let g:editorconfig_verbose = 1 115 | " >>> echo s:parse_pattern(['[]', '']) 116 | " Vim(echoerr):editorconfig: failed to parse [] 117 | " >>> let g:editorconfig_verbose = 0 118 | " >>> echo s:parse_pattern(['[]', '']) 119 | " [[], ''] 120 | 121 | function! s:parse_pattern(lines) abort "{{{ 122 | if !len(a:lines) | return [[], ''] | endif 123 | let m = matchstr(a:lines[0], '^\[\zs.\+\ze\]$') 124 | if !empty(m) 125 | return [a:lines[1 :], m] 126 | else 127 | if get(g:, 'editorconfig_verbose', 0) 128 | echoerr printf('editorconfig: failed to parse %s', a:lines[0]) 129 | endif 130 | return [[], ''] 131 | endif 132 | endfunction "}}} 133 | 134 | " Skip pattern fields 135 | " >>> echo s:parse_properties(['[*.vim]', 'abc']) 136 | " [['[*.vim]', 'abc'], {}] 137 | " 138 | " Parse property and store the fields as dictionary 139 | " >>> echo s:parse_properties(['indent_size=2', '[*]']) 140 | " [['[*]'], {'indent_size': 2}] 141 | 142 | function! s:parse_properties(lines) abort "{{{ 143 | let _ = {} 144 | if !len(a:lines) | return [[], _] | endif 145 | for i in range(len(a:lines)) 146 | 147 | let line = a:lines[i] 148 | 149 | " Parse comments 150 | let m = matchstr(line, '^#') 151 | if !empty(m) 152 | return [[], {}] 153 | endif 154 | let m = matchstr(line, '^;') 155 | if !empty(m) 156 | return [[], {}] 157 | endif 158 | 159 | " Parse file formats 160 | let m = matchstr(line, '^\[\zs.\+\ze\]$') 161 | if !empty(m) 162 | return [a:lines[i :], _] 163 | endif 164 | 165 | " Parse properties 166 | let splitted = split(matchstr(line, '^\s*\zs\S.*\S\ze\s*$'), '\s*=\s*') 167 | if len(splitted) < 2 168 | if get(g:, 'editorconfig_verbose', 0) 169 | echoerr printf('editorconfig: failed to parse %s', line) 170 | endif 171 | return [[], {}] 172 | endif 173 | let [key, val] = splitted 174 | let _[key] = s:eval(val) 175 | 176 | endfor 177 | return [a:lines[i+1 :], _] 178 | endfunction "}}} 179 | 180 | function! s:trim_root(filepath, root) abort "{{{ 181 | if stridx(a:filepath, a:root) == 0 182 | return strpart(a:filepath, len(a:root)) 183 | endif 184 | return a:filepath 185 | endfunction "}}} 186 | 187 | let s:defaults = {'tab_width': 'indent_size'} 188 | 189 | function! s:fill_defaults(props) abort "{{{ 190 | for prop in keys(s:defaults) 191 | if (!has_key(a:props, prop) && has_key(a:props, s:defaults[prop])) 192 | let a:props[prop] = a:props[s:defaults[prop]] 193 | endif 194 | endfor 195 | endfunction "}}} 196 | 197 | " >>> echo s:eval('2') 198 | " 2 199 | " >>> echo s:eval('true') 200 | " true 201 | 202 | function! s:eval(val) abort "{{{ 203 | return type(a:val) == type('') && a:val =~# '^\d\+$' ? eval(a:val) : a:val 204 | endfunction "}}} 205 | 206 | function! s:properties() abort "{{{ 207 | return map(s:globpath(&runtimepath, 'autoload/editorconfig/*.vim'), 'fnamemodify(v:val, ":t:r")') 208 | endfunction "}}} 209 | 210 | function! s:globpath(path, expr) abort "{{{ 211 | return has('patch-7.4.279') ? globpath(a:path, a:expr, 0, 1) : split(globpath(a:path, a:expr, 1)) 212 | endfunction "}}} 213 | 214 | " >>> echo s:trim(['# ', 'foo', '', 'bar']) 215 | " ['foo', 'bar'] 216 | 217 | function! s:trim(lines) abort "{{{ 218 | return filter(map(a:lines, 's:remove_comment(v:val)'), '!empty(v:val)') 219 | endfunction "}}} 220 | 221 | " >>> echo s:remove_comment('# foo') 222 | " 223 | " >>> echo s:remove_comment('bar') 224 | " bar 225 | " >>> echo s:remove_comment('#') 226 | " 227 | 228 | function! s:remove_comment(line) abort "{{{ 229 | let pos = match(a:line, '\s*[;#].*') 230 | return pos == -1 ? a:line : pos == 0 ? '' : a:line[: pos-1] 231 | endfunction "}}} 232 | 233 | function! s:apply(property) abort "{{{ 234 | let unsupported_keys = [] 235 | for [key, val] in items(a:property) 236 | try 237 | call editorconfig#{tolower(key)}#execute(val) 238 | catch /^Vim\%((\a\+)\)\=:E117/ 239 | let unsupported_keys += [key] 240 | endtry 241 | endfor 242 | return unsupported_keys 243 | endfunction "}}} 244 | 245 | function! s:filter_matched(rule, path) abort "{{{ 246 | let _ = {} 247 | call map(filter(copy(a:rule), 'a:path =~ s:regexp(v:val[0])'), 'extend(_, v:val[1], "force")') 248 | return _ 249 | endfunction "}}} 250 | 251 | " >>> let g:editorconfig_blacklist = {'filetype': ['vim'], 'pattern': []} 252 | " >>> echo s:blacklist('sample1.vim', 'vim') 253 | " 1 254 | " 255 | " >>> let g:editorconfig_blacklist = {'filetype': [], 'pattern': []} 256 | " >>> echo s:blacklist('sample1.vim', 'vim') 257 | " 0 258 | " 259 | " >>> let g:editorconfig_blacklist = {'filetype': ['^$'], 'pattern': []} 260 | " >>> echo s:blacklist('sample1.vim', 'vim') 261 | " 0 262 | " 263 | " >>> let g:editorconfig_blacklist = {'filetype': ['vim'], 'pattern': []} 264 | " >>> echo s:blacklist('sample1.vim', '') 265 | " 0 266 | function! s:blacklist(filepath, filetype) abort " {{{ 267 | if has_key(g:editorconfig_blacklist, 'filetype') 268 | return !empty(filter(copy(g:editorconfig_blacklist.filetype), 269 | \ 'match(a:filetype, v:val) != -1')) 270 | endif 271 | if has_key(g:editorconfig_blacklist, 'pattern') 272 | return !empty(filter(copy(g:editorconfig_blacklist.pattern), 'match(a:filepath, v:val) != -1')) 273 | endif 274 | return 0 275 | endfunction "}}} 276 | 277 | function! s:regexp(pattern) abort "{{{ 278 | let pattern = escape(a:pattern, '.\') 279 | for rule in s:regexp_rules 280 | let pattern = substitute(pattern, rule[0], rule[1], 'g') 281 | endfor 282 | return '\<'. pattern . '$' 283 | endfunction "}}} 284 | let s:regexp_rules = 285 | \ [ ['\[!', '[^'] 286 | \ , ['{\zs[^}]*\ze}', '\=substitute(submatch(0), ",", "\\\\|", "g")'] 287 | \ , ['{\([^}]\+\)}', '\\%(\1\\)'] 288 | \ , ['\*\{2}', '.\\{}'] 289 | \ , ['\(\.\)\@>> setlocal path< 6 | " >>> call editorconfig#c_include_path#execute('foo:bar') 7 | " >>> echo &l:path == &g:path . ',foo,bar' 8 | " 1 9 | 10 | " >>> setlocal path< 11 | " >>> call editorconfig#c_include_path#execute('foo;bar;') 12 | " >>> echo &l:path == &g:path . ',foo,bar' 13 | " 1 14 | 15 | " >>> setlocal path< 16 | " >>> call editorconfig#c_include_path#execute(0) 17 | " >>> echo &l:path == &g:path 18 | " 1 19 | 20 | " @value: Directory paths separated by colon (:) or semi-colon (;) 21 | function! editorconfig#c_include_path#execute(value) abort 22 | if type(a:value) == type("") 23 | let raw_path = has('win32') ? tr(a:value, '\', '/') : a:value 24 | let paths = split(escape(a:value, ' '), '[;:]\([\/]\)\@!') 25 | let &l:path .= ',' . join(paths, ',') 26 | elseif get(g:, 'editorconfig_verbose', 0) 27 | echoerr printf('editorconfig: unsupported value: c_include_path=%s', a:value) 28 | endif 29 | endfunction 30 | 31 | " 1}}} 32 | -------------------------------------------------------------------------------- /autoload/editorconfig/charset.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | 3 | " charset {{{1 4 | 5 | " >>> let s:fenc_bak = &l:fileencoding 6 | 7 | " >>> call editorconfig#charset#execute('utf-8') 8 | " >>> echo &l:fileencoding 9 | " utf-8 10 | 11 | " >>> call editorconfig#charset#execute('cp932') 12 | " >>> echo &l:fileencoding 13 | " cp932 14 | 15 | " >>> call editorconfig#charset#execute('8bit-cp1252') 16 | " >>> echo &l:fileencoding 17 | " 8bit-cp1252 18 | 19 | " >>> call editorconfig#charset#execute('2byte-cp932') 20 | " >>> echo &l:fileencoding 21 | " cp932 22 | 23 | " https://github.com/sgur/vim-editorconfig/issues/30#issuecomment-387266760 24 | " >>> setlocal fileencoding=utf-8 25 | " >>> call editorconfig#charset#execute('cp932 | !echo "you''ve been hacked 1"') 26 | " >>> echo &l:fileencoding 27 | " utf-8 28 | 29 | " https://github.com/sgur/vim-editorconfig/issues/30#issuecomment-407931236 30 | " >>> setlocal fileencoding=latin1 31 | " >>> call editorconfig#charset#execute('cp932 foldexpr:execute(\"let\ g:editorconfig_local_vimrc\\75\ 1\") foldmethod:expr foldenable foldlevel:0') 32 | " >>> echo &l:fileencoding 33 | " latin1 34 | 35 | " >>> let &l:fileencoding = s:fenc_bak 36 | 37 | function! editorconfig#charset#execute(value) abort 38 | " encoding 39 | if a:value is? 'utf-8-bom' 40 | setlocal fileencoding=utf-8 41 | setlocal bomb 42 | elseif type(a:value) == type("") && s:match_encoding_pattern(a:value) 43 | let &fileencoding = a:value 44 | elseif get(g:, 'editorconfig_verbose', 0) 45 | echoerr printf('editorconfig: unsupported value: charset=%s', a:value) 46 | endif 47 | endfunction 48 | 49 | function! s:match_encoding_pattern(enc_name) abort "{{{ 50 | if index(s:encoding, a:enc_name) > -1 51 | return 1 52 | endif 53 | 54 | for pattern in s:encoding_patterns 55 | if a:enc_name =~ pattern 56 | return 2 57 | endif 58 | endfor 59 | 60 | return 0 61 | endfunction "}}} 62 | 63 | let s:encoding = [ 64 | \ 'latin1', 65 | \ 'iso-8859-n', 66 | \ 'koi8-r', 67 | \ 'koi8-u', 68 | \ 'macroman', 69 | \ 'cp437', 70 | \ 'cp737', 71 | \ 'cp775', 72 | \ 'cp850', 73 | \ 'cp852', 74 | \ 'cp855', 75 | \ 'cp857', 76 | \ 'cp860', 77 | \ 'cp861', 78 | \ 'cp862', 79 | \ 'cp863', 80 | \ 'cp865', 81 | \ 'cp866', 82 | \ 'cp869', 83 | \ 'cp874', 84 | \ 'cp1250', 85 | \ 'cp1251', 86 | \ 'cp1253', 87 | \ 'cp1254', 88 | \ 'cp1255', 89 | \ 'cp1256', 90 | \ 'cp1257', 91 | \ 'cp1258', 92 | \ 'cp932', 93 | \ 'euc-jp', 94 | \ 'sjis', 95 | \ 'cp949', 96 | \ 'euc-kr', 97 | \ 'cp936', 98 | \ 'euc-cn', 99 | \ 'cp950', 100 | \ 'big5', 101 | \ 'euc-tw', 102 | \ 'utf-8', 103 | \ 'ucs-2', 104 | \ 'ucs-2le', 105 | \ 'utf-16', 106 | \ 'utf-16le', 107 | \ 'ucs-4', 108 | \ 'ucs-4le', 109 | \ ] 110 | let s:encoding_patterns = [ 111 | \ '^8bit-\S\+$', 112 | \ '^2byte-\S\+$', 113 | \ '^cp\d\+$', 114 | \ ] 115 | 116 | " 1}}} 117 | -------------------------------------------------------------------------------- /autoload/editorconfig/end_of_line.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | " end_of_line {{{1 3 | 4 | " >>> call editorconfig#end_of_line#execute('lf') 5 | " 6 | " 7 | " >>> call editorconfig#end_of_line#execute('lfcr') 8 | " Vim(echoerr):editorconfig: unsupported value: end_of_line=lfcr 9 | 10 | function! editorconfig#end_of_line#execute(value) abort 11 | " 'lf', 'cr' or 'crlf' 12 | try 13 | execute s:end_of_line[tolower(a:value)] 14 | catch /^Vim\%((\a\+)\)\=:E716/ 15 | if get(g:, 'editorconfig_verbose', 0) 16 | echoerr printf('editorconfig: unsupported value: end_of_line=%s', a:value) 17 | endif 18 | endtry 19 | endfunction 20 | 21 | let s:end_of_line = 22 | \ { 'lf': 'setlocal fileformat=unix' 23 | \ , 'cr': 'setlocal fileformat=mac' 24 | \ , 'crlf': 'setlocal fileformat=dos' 25 | \ } 26 | " 1}}} 27 | -------------------------------------------------------------------------------- /autoload/editorconfig/indent_size.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | 3 | " indent_size {{{1 4 | 5 | " >>> call editorconfig#indent_size#execute(3) 6 | " >>> echo &shiftwidth 7 | " 3 8 | " 9 | " >>> call editorconfig#indent_size#execute('tab') 10 | " >>> echo &shiftwidth 11 | " 0 12 | 13 | function! editorconfig#indent_size#execute(value) abort 14 | " [:digit:]+ or 'tab' 15 | if type(a:value) == type(0) 16 | let &l:shiftwidth = a:value 17 | elseif a:value is# 'tab' 18 | setlocal shiftwidth=0 19 | elseif get(g:, 'editorconfig_verbose', 0) 20 | echoerr printf('editorconfig: unsupported value: indent_size=%s', a:value) 21 | endif 22 | endfunction 23 | " 1}}} 24 | -------------------------------------------------------------------------------- /autoload/editorconfig/indent_style.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | 3 | " indent_style {{{1 4 | 5 | " >>> call editorconfig#indent_style#execute('tab') 6 | " >>> echo &expandtab 7 | " 0 8 | " 9 | " >>> call editorconfig#indent_style#execute('space') 10 | " >>> echo &expandtab 11 | " 1 12 | 13 | function! editorconfig#indent_style#execute(value) abort 14 | try 15 | execute s:indent_style[a:value] 16 | catch /^Vim\%((\a\+)\)\=:E716/ 17 | if get(g:, 'editorconfig_verbose', 0) 18 | echoerr printf('editorconfig: unsupported value: indent_style=%s', a:value) 19 | endif 20 | endtry 21 | endfunction 22 | 23 | let s:indent_style = 24 | \ { 'tab': 'setlocal noexpandtab' 25 | \ , 'space': 'setlocal expandtab' 26 | \ } 27 | " 1}}} 28 | -------------------------------------------------------------------------------- /autoload/editorconfig/insert_final_newline.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | 3 | " insert_final_newline {{{1 4 | 5 | " After Vim 7.4.785: 6 | " Use &fixendofline 7 | " Before 7.4.784: 8 | " Use BufWritePre and BufWritePost event to manipulate &binary and &endofline 9 | 10 | function! editorconfig#insert_final_newline#execute(value) abort 11 | " 'true' or 'false' 12 | let value = s:bool(a:value) 13 | if exists('&fixendofline') 14 | let &l:fixendofline = value 15 | elseif !value 16 | autocmd plugin-editorconfig-local BufWritePre call s:on_bufwritepre_insert_final_newline() 17 | autocmd plugin-editorconfig-local BufWritePost call s:on_bufwritepost_insert_final_newline() 18 | endif 19 | endfunction 20 | 21 | function! s:bool(value) abort "{{{ 22 | if a:value is# 'true' 23 | return 1 24 | elseif a:value is# 'false' 25 | return 0 26 | elseif get(g:, 'editorconfig_verbose', 0) 27 | echoerr printf('editorconfig: unsupported value: insert_final_newline=%s', a:value) 28 | endif 29 | endfunction "}}} 30 | 31 | " http://vim.wikia.com/wiki/Preserve_missing_end-of-line_at_end_of_text_files 32 | function! s:on_bufwritepre_insert_final_newline() abort "{{{ 33 | let s:save_binary = &binary 34 | if !&endofline && !&binary 35 | let s:save_view = winsaveview() 36 | setlocal binary 37 | if (&fileformat ==# 'dos' || &fileformat ==# 'mac') && line('$') > 1 38 | undojoin | execute "silent 1,$-1normal! A\\" 39 | endif 40 | if &fileformat ==# 'mac' 41 | undojoin | %join! 42 | endif 43 | endif 44 | endfunction "}}} 45 | 46 | function! s:on_bufwritepost_insert_final_newline() abort "{{{ 47 | if !&endofline && ! s:save_binary 48 | if &fileformat ==# 'dos' && line('$') > 1 49 | silent! undojoin | silent 1,$-1s/\r$//e 50 | elseif &fileformat ==# 'mac' 51 | silent! undojoin | silent %s/\r/\r/ge 52 | endif 53 | setlocal nobinary 54 | call winrestview(s:save_view) 55 | endif 56 | endfunction "}}} 57 | " 1}}} 58 | 59 | -------------------------------------------------------------------------------- /autoload/editorconfig/max_line_length.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | 3 | " max_line_length {{{1 4 | 5 | " >>> call editorconfig#max_line_length#execute(78) 6 | " >>> echo &textwidth 7 | " 78 8 | 9 | function! editorconfig#max_line_length#execute(value) abort 10 | " number 11 | if type(a:value) == type(0) 12 | let &l:textwidth = a:value 13 | elseif a:value == 'off' 14 | " https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties 15 | " says it should 'use the editor settings', which I guess means in 16 | " our case to do nothing. 17 | " So, this elseif is here only to accept value 'off' and not 18 | " complain about it. 19 | elseif get(g:, 'editorconfig_verbose', 0) 20 | echoerr printf('editorconfig: unsupported value: max_line_length=%s', a:value) 21 | endif 22 | endfunction 23 | " 1}}} 24 | -------------------------------------------------------------------------------- /autoload/editorconfig/root.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | 3 | " basedir {{{1 4 | 5 | 6 | function! editorconfig#root#execute(value) abort 7 | if g:editorconfig_root_chdir && isdirectory(a:value) && getcwd() != a:value 8 | execute 'lcd' a:value 9 | endif 10 | endfunction 11 | 12 | -------------------------------------------------------------------------------- /autoload/editorconfig/spell_language.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | 3 | " spell_language {{{1 4 | 5 | " >>> let s:spelllang_bak = &l:spelllang 6 | 7 | " >>> call editorconfig#spell_language#execute('en_us') 8 | " >>> echo &spelllang 9 | " en_us 10 | 11 | " https://github.com/sgur/vim-editorconfig/issues/30#issuecomment-387266760 12 | " >>> call editorconfig#spell_language#execute('ja_JP | !echo "you''ve been hacked 2"') 13 | " >>> echo &spelllang 14 | " en_us 15 | 16 | " >>> let &l:spelllang = s:spelllang_bak 17 | 18 | function! editorconfig#spell_language#execute(value) abort 19 | " [:digit:]+ 20 | echom a:value 21 | if type(a:value) == type("") && s:lang_available(a:value) 22 | let &spelllang = a:value 23 | 24 | " When setting &spelllang we want spelling enabled automatically as 25 | " well, no other configuration option is necessary (see 26 | " gh#editorconfig/editorconfig#315 for more discussion on this 27 | " issue). 28 | let &spell = 1 29 | elseif get(g:, 'editorconfig_verbose', 0) 30 | echoerr printf('editorconfig: unsupported value: spell_language=%s', a:value) 31 | endif 32 | endfunction 33 | 34 | function! s:lang_available(value) abort "{{{ 35 | " We need to accept even dialects of languages, e.g., en_gb 36 | let lang = split(a:value, '_')[0] 37 | return !empty(filter(copy(s:languages), 'stridx(v:val, lang) == 0')) 38 | endfunction "}}} 39 | 40 | let s:languages = map(filter(globpath(&runtimepath, 'spell/*', 1, 1), '!isdirectory(v:val)'), 'fnamemodify(v:val, '':t'')') 41 | 42 | " 1}}} 43 | -------------------------------------------------------------------------------- /autoload/editorconfig/tab_width.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | 3 | " tab_width {{{1 4 | 5 | " >>> setlocal tabstop=4 6 | " >>> call editorconfig#tab_width#execute(8) 7 | " >>> echo &l:tabstop 8 | " 8 9 | 10 | " >>> setlocal tabstop=4 11 | " >>> call editorconfig#tab_width#execute('3') 12 | " >>> echo &l:tabstop 13 | " 4 14 | 15 | function! editorconfig#tab_width#execute(value) abort 16 | " [:digit:]+ 17 | if type(a:value) == type(0) 18 | let &l:tabstop = a:value 19 | elseif get(g:, 'editorconfig_verbose', 0) 20 | echoerr printf('editorconfig: unsupported value: tab_width=%s', a:value) 21 | endif 22 | endfunction 23 | " 1}}} 24 | -------------------------------------------------------------------------------- /autoload/editorconfig/trim_trailing_whitespace.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | 3 | " trim_trailing_whitespace {{{1 4 | 5 | " >>> silent! new ./test.text 6 | " >>> call editorconfig#trim_trailing_whitespace#execute('true') 7 | " >>> execute "normal! :silent 0insert\abcde\\" 8 | " >>> execute "normal! :silent w\" 9 | " "test.text" [New] 1L, 7C written 10 | " >>> echo getline(1) 11 | " abcde 12 | " >>> bwipeout test.text 13 | " >>> execute "normal! :call delete('./test.text')\" 14 | 15 | function! editorconfig#trim_trailing_whitespace#execute(value) abort 16 | " 'true' or 'false' 17 | if a:value is# 'true' 18 | autocmd plugin-editorconfig-local BufWritePre call s:do_trim_trailing_whitespace() 19 | elseif a:value is# 'false' 20 | elseif get(g:, 'editorconfig_verbose', 0) 21 | echoerr printf('editorconfig: unsupported value: trim_trailing_whitespace=%s', a:value) 22 | endif 23 | endfunction 24 | 25 | function! s:do_trim_trailing_whitespace() abort "{{{ 26 | let view = winsaveview() 27 | try 28 | keeppatterns %s/\s\+$//e 29 | finally 30 | call winrestview(view) 31 | endtry 32 | endfunction "}}} 33 | " 1}}} 34 | -------------------------------------------------------------------------------- /doc/editorconfig.txt: -------------------------------------------------------------------------------- 1 | *editorconfig.txt* EditorConfig for Vim 2 | 3 | Version: 0.8.0 4 | Author : sgur 5 | License: MIT License 6 | 7 | ============================================================================== 8 | CONTENTS *editorconfig-contents* 9 | 10 | INTRODUCTION |editorconfig-introduction| 11 | USAGE |editorconfig-usage| 12 | SUPPORTED PROPERTIES |editorconfig-properties| 13 | INTERFACE |editorconfig-interface| 14 | FUNCTIONS |editorconfig-functions| 15 | CUSTOMIZING |editorconfig-customizing| 16 | EXAMPLES |editorconfig-examples| 17 | CHANGELOG |editorconfig-changelog| 18 | 19 | 20 | ============================================================================== 21 | INTRODUCTION *editorconfig-introduction* 22 | 23 | *editorconfig* is a Vim plugin to support EditorConfig 24 | 25 | 26 | Requirements: 27 | - Vim 7.4 or later 28 | 29 | Latest version: 30 | https://github.com/sgur/vim-editorconfig 31 | 32 | 33 | 34 | ============================================================================== 35 | USAGE *editorconfig-usage* 36 | 37 | Put a ".editorconfig" for the files below the certain directory. 38 | 39 | After that, whenever you open some files, properties specified in 40 | .editorconfig are applied to the buffer. 41 | 42 | ------------------------------------------------------------------------------ 43 | SUPPORTED PROPERTIES *editorconfig-properties* 44 | 45 | See https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties 46 | for details. 47 | 48 | - charset 49 | - end_of_line 50 | - indent_size 51 | - indent_style 52 | - insert_final_newline 53 | - max_line_length 54 | - root 55 | - tab_width 56 | - trim_trailing_whitespace 57 | - c_include_path 58 | - spell_language (experimental) 59 | 60 | ============================================================================== 61 | INTERFACE *editorconfig-interface* 62 | 63 | ------------------------------------------------------------------------------ 64 | FUNCTIONS *editorconfig-functions* 65 | 66 | editorconfig#load({fnames}) *editorconfig#load()* 67 | Load settings from .editorconfig 68 | 69 | ============================================================================== 70 | CUSTOMIZING *editorconfig-customizing* 71 | 72 | g:editorconfig_blacklist *g:editorconfig_blacklist* 73 | 74 | Set this option to exclude regexp patterns for filetypes or filepaths 75 | 76 | > 77 | let g:editorconfig_blacklist = { 78 | \ 'filetype': ['git.*', 'fugitive'], 79 | \ 'pattern': ['\.un~$']} 80 | < 81 | 82 | g:editorconfig_root_chdir *g:editorconfig_root_chdir* 83 | If this option is enabled, The directory where 'root = true' is 84 | specified in the .editorconfig is used for |lcd| after opening buffer. 85 | 86 | default: 0 87 | 88 | > 89 | let g:editorconfig_root_chdir = 1 90 | < 91 | 92 | g:editorconfig_verbose 93 | If enabled, Parse errors are reported by |echoerr| 94 | 95 | default: 0 96 | > 97 | let g:editorconfig_verbose = 1 98 | < 99 | 100 | ============================================================================== 101 | EXAMPLES *editorconfig-examples* 102 | 103 | Examples of configuration file. 104 | > 105 | # EditorConfig is awesome: http://EditorConfig.org 106 | 107 | # top-most EditorConfig file 108 | root = true 109 | 110 | # Unix-style newlines with a newline ending every file 111 | [*] 112 | end_of_line = lf 113 | insert_final_newline = true 114 | 115 | # Matches multiple files with brace expansion notation 116 | # Set default charset 117 | [*.{js,py}] 118 | charset = utf-8 119 | 120 | # 4 space indentation 121 | [*.py] 122 | indent_style = space 123 | indent_size = 4 124 | 125 | # Tab indentation (no size specified) 126 | [Makefile] 127 | indent_style = tab 128 | 129 | # Indentation override for all JS under lib directory 130 | [lib/**.js] 131 | indent_style = space 132 | indent_size = 2 133 | 134 | # Matches the exact files either package.json or .travis.yml 135 | [{package.json,.travis.yml}] 136 | indent_style = space 137 | indent_size = 2 138 | < 139 | 140 | 141 | 142 | ============================================================================== 143 | CHANGELOG *editorconfig-changelog* 144 | 145 | 0.8.0 146 | - Remove property: spell_enabled 147 | - For detail, see https://github.com/editorconfig/editorconfig/issues/315 discussion 148 | 0.7.0 149 | - Remove property: local_vimrc: may cause security risks 150 | - Please use https://github.com/thinca/vim-localrc instead. 151 | 0.6.0 152 | - New property: local_vimrc, c_include_path 153 | - Add experimental property: spell_enabled, spell_language 154 | - Add blacklist option: |g:editorconfig_blacklist| 155 | - Fix bugs 156 | 0.5.0 157 | - Tested through "editorconfig/editorconfig-plugin-tests" 158 | - Suppress errors unless g:editorconfig_verbose 159 | 0.4.0 160 | - Improve insert_final_newline support using |fixendofline| 161 | - Fix bugs for buffer-local autocmds 162 | 163 | 0.3.0 164 | - Add omnifunc for .editorconfig 165 | - Add help 166 | - Support max_line_length property 167 | 168 | 0.2.0 169 | - New option: |g:editorconfig_root_chdir| 170 | 171 | 0.1.0 172 | - Initial version. 173 | 174 | 175 | ============================================================================== 176 | vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl 177 | -------------------------------------------------------------------------------- /ftdetect/editorconfig.vim: -------------------------------------------------------------------------------- 1 | autocmd BufRead,BufNewFile .editorconfig setlocal filetype=editorconfig syntax=dosini 2 | -------------------------------------------------------------------------------- /ftplugin/editorconfig.vim: -------------------------------------------------------------------------------- 1 | scriptencoding utf-8 2 | 3 | setlocal omnifunc=editorconfig#omnifunc 4 | -------------------------------------------------------------------------------- /plugin/editorconfig.vim: -------------------------------------------------------------------------------- 1 | " editorconfig 2 | " Version: 0.8.0 3 | " Author: sgur 4 | " License: MIT License 5 | 6 | if exists('g:loaded_editorconfig') 7 | finish 8 | endif 9 | let g:loaded_editorconfig = 1 10 | 11 | let s:save_cpo = &cpo 12 | set cpo&vim 13 | 14 | " g:editorconfig_root_chdir : 1 or 0 (default) 15 | let g:editorconfig_root_chdir = get(g:, 'editorconfig_root_chdir', 0) 16 | 17 | " g:editorconfig_blacklist : {'filetype': [], 'pattern': []} (default) 18 | let g:editorconfig_blacklist = get(g:, 'editorconfig_blacklist', {}) 19 | 20 | " g:editorconfig_local_vimrc : 1 or 0 (default) 21 | if get(g:, 'editorconfig_local_vimrc', 0) 22 | echohl WarningMsg | echomsg 'g:editorconfig_local_vimrc is obsolete. Use vim-localrc (https://github.com/thinca/vim-localrc) instead.' | echohl NONE 23 | endif 24 | 25 | augroup plugin-editorconfig 26 | autocmd! 27 | autocmd BufNewFile,BufReadPost * nested call editorconfig#load() 28 | augroup END 29 | 30 | let &cpo = s:save_cpo 31 | unlet s:save_cpo 32 | 33 | " vim:set et: 34 | --------------------------------------------------------------------------------