mirror of
https://github.com/amix/vimrc
synced 2025-07-01 12:45:00 +08:00
feat: include editorconfig-vim plugin
Signed-off-by: luc <onion0709@gmail.com>
This commit is contained in:
@ -0,0 +1,60 @@
|
||||
" autoload/editorconfig.vim: EditorConfig native Vimscript plugin
|
||||
" Copyright (c) 2011-2019 EditorConfig Team
|
||||
" All rights reserved.
|
||||
"
|
||||
" Redistribution and use in source and binary forms, with or without
|
||||
" modification, are permitted provided that the following conditions are met:
|
||||
"
|
||||
" 1. Redistributions of source code must retain the above copyright notice,
|
||||
" this list of conditions and the following disclaimer.
|
||||
" 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
" this list of conditions and the following disclaimer in the documentation
|
||||
" and/or other materials provided with the distribution.
|
||||
"
|
||||
" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
" POSSIBILITY OF SUCH DAMAGE.
|
||||
"
|
||||
|
||||
if v:version < 700
|
||||
finish
|
||||
endif
|
||||
|
||||
let s:saved_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
" {{{1 variables
|
||||
let s:hook_list = []
|
||||
|
||||
function! editorconfig#AddNewHook(func) " {{{1
|
||||
" Add a new hook
|
||||
|
||||
call add(s:hook_list, a:func)
|
||||
endfunction
|
||||
|
||||
function! editorconfig#ApplyHooks(config) abort " {{{1
|
||||
" apply hooks
|
||||
|
||||
for Hook in s:hook_list
|
||||
let l:hook_ret = Hook(a:config)
|
||||
|
||||
if type(l:hook_ret) != type(0) && l:hook_ret != 0
|
||||
" TODO print some debug info here
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
" }}}
|
||||
|
||||
let &cpo = s:saved_cpo
|
||||
unlet! s:saved_cpo
|
||||
|
||||
" vim: fdm=marker fdc=3
|
@ -0,0 +1,147 @@
|
||||
" autoload/editorconfig_core.vim: top-level functions for
|
||||
" editorconfig-core-vimscript and editorconfig-vim.
|
||||
|
||||
" Copyright (c) 2018-2020 EditorConfig Team, including Chris White {{{1
|
||||
" All rights reserved.
|
||||
"
|
||||
" Redistribution and use in source and binary forms, with or without
|
||||
" modification, are permitted provided that the following conditions are met:
|
||||
"
|
||||
" 1. Redistributions of source code must retain the above copyright notice,
|
||||
" this list of conditions and the following disclaimer.
|
||||
" 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
" this list of conditions and the following disclaimer in the documentation
|
||||
" and/or other materials provided with the distribution.
|
||||
"
|
||||
" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
" POSSIBILITY OF SUCH DAMAGE. }}}1
|
||||
|
||||
let s:saved_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
" Variables {{{1
|
||||
|
||||
" Note: we create this variable in every script that accesses it. Normally, I
|
||||
" would put this in plugin/editorconfig.vim. However, in some of my tests,
|
||||
" the command-line testing environment did not load plugin/* in the normal
|
||||
" way. Therefore, I do the check everywhere so I don't have to special-case
|
||||
" the command line.
|
||||
|
||||
if !exists('g:editorconfig_core_vimscript_debug')
|
||||
let g:editorconfig_core_vimscript_debug = 0
|
||||
endif
|
||||
" }}}1
|
||||
|
||||
" The latest version of the specification that we support.
|
||||
" See discussion at https://github.com/editorconfig/editorconfig/issues/395
|
||||
function! editorconfig_core#version()
|
||||
return [0,13,0]
|
||||
endfunction
|
||||
|
||||
" === CLI =============================================================== {{{1
|
||||
|
||||
" For use from the command line. Output settings for in_name to
|
||||
" the buffer named out_name. If an optional argument is provided, it is the
|
||||
" name of the config file to use (default '.editorconfig').
|
||||
" TODO support multiple files
|
||||
"
|
||||
" filename (if any)
|
||||
" @param names {Dictionary} The names of the files to use for this run
|
||||
" - output [required] Where the editorconfig settings should be written
|
||||
" - target [required] A string or list of strings to process. Each
|
||||
" must be a full path.
|
||||
" - dump [optional] If present, write debug info to this file
|
||||
" @param job {Dictionary} What to do - same format as the input of
|
||||
" editorconfig_core#handler#get_configurations(),
|
||||
" except without the target member.
|
||||
|
||||
function! editorconfig_core#currbuf_cli(names, job) " out_name, in_name, ...
|
||||
let l:output = []
|
||||
|
||||
" Preprocess the job
|
||||
let l:job = deepcopy(a:job)
|
||||
|
||||
if has_key(l:job, 'version') " string to list
|
||||
let l:ver = split(editorconfig_core#util#strip(l:job.version), '\v\.')
|
||||
for l:idx in range(len(l:ver))
|
||||
let l:ver[l:idx] = str2nr(l:ver[l:idx])
|
||||
endfor
|
||||
|
||||
let l:job.version = l:ver
|
||||
endif
|
||||
|
||||
" TODO provide version output from here instead of the shell script
|
||||
" if string(a:names) ==? 'version'
|
||||
" return
|
||||
" endif
|
||||
"
|
||||
if type(a:names) != type({}) || type(a:job) != type({})
|
||||
throw 'Need two Dictionary arguments'
|
||||
endif
|
||||
|
||||
if has_key(a:names, 'dump')
|
||||
execute 'redir! > ' . fnameescape(a:names.dump)
|
||||
echom 'Names: ' . string(a:names)
|
||||
echom 'Job: ' . string(l:job)
|
||||
let g:editorconfig_core_vimscript_debug = 1
|
||||
endif
|
||||
|
||||
if type(a:names['target']) == type([])
|
||||
let l:targets = a:names.target
|
||||
else
|
||||
let l:targets = [a:names.target]
|
||||
endif
|
||||
|
||||
for l:target in l:targets
|
||||
|
||||
" Pre-process quoting weirdness so we are more flexible in the face
|
||||
" of CMake+CTest+BAT+Powershell quoting.
|
||||
|
||||
" Permit wrapping in double-quotes
|
||||
let l:target = substitute(l:target, '\v^"(.*)"$', '\1', '')
|
||||
|
||||
" Permit empty ('') entries in l:targets
|
||||
if strlen(l:target)<1
|
||||
continue
|
||||
endif
|
||||
|
||||
if has_key(a:names, 'dump')
|
||||
echom 'Trying: ' . string(l:target)
|
||||
endif
|
||||
|
||||
let l:job.target = l:target
|
||||
let l:options = editorconfig_core#handler#get_configurations(l:job)
|
||||
|
||||
if has_key(a:names, 'dump')
|
||||
echom 'editorconfig_core#currbuf_cli result: ' . string(l:options)
|
||||
endif
|
||||
|
||||
if len(l:targets) > 1
|
||||
let l:output += [ '[' . l:target . ']' ]
|
||||
endif
|
||||
|
||||
for [ l:key, l:value ] in items(l:options)
|
||||
let l:output += [ l:key . '=' . l:value ]
|
||||
endfor
|
||||
|
||||
endfor "foreach target
|
||||
|
||||
" Write the output file
|
||||
call writefile(l:output, a:names.output)
|
||||
endfunction "editorconfig_core#currbuf_cli
|
||||
|
||||
" }}}1
|
||||
|
||||
let &cpo = s:saved_cpo
|
||||
unlet! s:saved_cpo
|
||||
|
||||
" vi: set fdm=marker fo-=ro:
|
@ -0,0 +1,465 @@
|
||||
" autoload/editorconfig_core/fnmatch.vim: Globbing for
|
||||
" editorconfig-vim. Ported from the Python core's fnmatch.py.
|
||||
|
||||
" Copyright (c) 2012-2019 EditorConfig Team {{{1
|
||||
" All rights reserved.
|
||||
"
|
||||
" Redistribution and use in source and binary forms, with or without
|
||||
" modification, are permitted provided that the following conditions are met:
|
||||
"
|
||||
" 1. Redistributions of source code must retain the above copyright notice,
|
||||
" this list of conditions and the following disclaimer.
|
||||
" 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
" this list of conditions and the following disclaimer in the documentation
|
||||
" and/or other materials provided with the distribution.
|
||||
"
|
||||
" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
" POSSIBILITY OF SUCH DAMAGE. }}}1
|
||||
|
||||
"Filename matching with shell patterns.
|
||||
"
|
||||
"fnmatch(FILENAME, PATH, PATTERN) matches according to the local convention.
|
||||
"fnmatchcase(FILENAME, PATH, PATTERN) always takes case in account.
|
||||
"
|
||||
"The functions operate by translating the pattern into a regular
|
||||
"expression. They cache the compiled regular expressions for speed.
|
||||
"
|
||||
"The function translate(PATTERN) returns a regular expression
|
||||
"corresponding to PATTERN. (It does not compile it.)
|
||||
|
||||
let s:saved_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
" variables {{{1
|
||||
if !exists('g:editorconfig_core_vimscript_debug')
|
||||
let g:editorconfig_core_vimscript_debug = 0
|
||||
endif
|
||||
" }}}1
|
||||
" === Regexes =========================================================== {{{1
|
||||
let s:LEFT_BRACE = '\v%(^|[^\\])\{'
|
||||
"LEFT_BRACE = re.compile(
|
||||
" r"""
|
||||
"
|
||||
" (?: ^ | [^\\] ) # Beginning of string or a character besides "\"
|
||||
"
|
||||
" \{ # "{"
|
||||
"
|
||||
" """, re.VERBOSE
|
||||
")
|
||||
|
||||
let s:RIGHT_BRACE = '\v%(^|[^\\])\}'
|
||||
"RIGHT_BRACE = re.compile(
|
||||
" r"""
|
||||
"
|
||||
" (?: ^ | [^\\] ) # Beginning of string or a character besides "\"
|
||||
"
|
||||
" \} # "}"
|
||||
"
|
||||
" """, re.VERBOSE
|
||||
")
|
||||
|
||||
let s:NUMERIC_RANGE = '\v([+-]?\d+)' . '\.\.' . '([+-]?\d+)'
|
||||
"NUMERIC_RANGE = re.compile(
|
||||
" r"""
|
||||
" ( # Capture a number
|
||||
" [+-] ? # Zero or one "+" or "-" characters
|
||||
" \d + # One or more digits
|
||||
" )
|
||||
"
|
||||
" \.\. # ".."
|
||||
"
|
||||
" ( # Capture a number
|
||||
" [+-] ? # Zero or one "+" or "-" characters
|
||||
" \d + # One or more digits
|
||||
" )
|
||||
" """, re.VERBOSE
|
||||
")
|
||||
|
||||
" }}}1
|
||||
" === Internal functions ================================================ {{{1
|
||||
|
||||
" Dump the bytes of a:text. For debugging use.
|
||||
function! s:dump_bytes(text)
|
||||
let l:idx=0
|
||||
while l:idx < strlen(a:text)
|
||||
let l:byte_val = char2nr(a:text[l:idx])
|
||||
echom printf('%10s%-5d%02x %s', '', l:idx, l:byte_val,
|
||||
\ a:text[l:idx])
|
||||
let l:idx+=1
|
||||
endwhile
|
||||
endfunction "s:dump_bytes
|
||||
|
||||
" Dump the characters of a:text and their codepoints. For debugging use.
|
||||
function! s:dump_chars(text)
|
||||
let l:chars = split(a:text, '\zs')
|
||||
let l:idx = 0
|
||||
let l:out1 = ''
|
||||
let l:out2 = ''
|
||||
while l:idx < len(l:chars)
|
||||
let l:char = l:chars[l:idx]
|
||||
let l:out1 .= printf('%5s', l:char)
|
||||
let l:out2 .= printf('%5x', char2nr(l:char))
|
||||
let l:idx+=1
|
||||
endwhile
|
||||
|
||||
echom l:out1
|
||||
echom l:out2
|
||||
endfunction "s:dump_chars
|
||||
|
||||
" }}}1
|
||||
" === Translating globs to patterns ===================================== {{{1
|
||||
|
||||
" Used by s:re_escape: backslash-escape any character below U+0080;
|
||||
" replace all others with a %U escape.
|
||||
" See https://vi.stackexchange.com/a/19617/1430 by yours truly
|
||||
" (https://vi.stackexchange.com/users/1430/cxw).
|
||||
unlockvar s:replacement_expr
|
||||
let s:replacement_expr =
|
||||
\ '\=' .
|
||||
\ '((char2nr(submatch(1)) >= 128) ? ' .
|
||||
\ 'printf("%%U%08x", char2nr(submatch(1))) : ' .
|
||||
\ '("\\" . submatch(1))' .
|
||||
\ ')'
|
||||
lockvar s:replacement_expr
|
||||
|
||||
" Escaper for very-magic regexes
|
||||
function! s:re_escape(text)
|
||||
return substitute(a:text, '\v([^0-9a-zA-Z_])', s:replacement_expr, 'g')
|
||||
endfunction
|
||||
|
||||
"def translate(pat, nested=0):
|
||||
" Translate a shell PATTERN to a regular expression.
|
||||
" There is no way to quote meta-characters.
|
||||
function! editorconfig_core#fnmatch#translate(pat, ...)
|
||||
let l:nested = 0
|
||||
if a:0
|
||||
let l:nested = a:1
|
||||
endif
|
||||
|
||||
if g:editorconfig_core_vimscript_debug
|
||||
echom '- fnmatch#translate: pattern ' . a:pat
|
||||
echom printf(
|
||||
\ '- %d chars', strlen(substitute(a:pat, ".", "x", "g")))
|
||||
call s:dump_chars(a:pat)
|
||||
endif
|
||||
|
||||
let l:pat = a:pat " TODO remove if we wind up not needing this
|
||||
|
||||
" Note: the Python sets MULTILINE and DOTALL, but Vim has \_.
|
||||
" instead of DOTALL, and \_^ / \_$ instead of MULTILINE.
|
||||
|
||||
let l:is_escaped = 0
|
||||
|
||||
" Find out whether the pattern has balanced braces.
|
||||
let l:left_braces=[]
|
||||
let l:right_braces=[]
|
||||
call substitute(l:pat, s:LEFT_BRACE, '\=add(l:left_braces, 1)', 'g')
|
||||
call substitute(l:pat, s:RIGHT_BRACE, '\=add(l:right_braces, 1)', 'g')
|
||||
" Thanks to http://jeromebelleman.gitlab.io/posts/productivity/vimsub/
|
||||
let l:matching_braces = (len(l:left_braces) == len(l:right_braces))
|
||||
|
||||
" Unicode support (#2). Indexing l:pat[l:index] returns bytes, per
|
||||
" https://github.com/neovim/neovim/issues/68#issue-28114985 .
|
||||
" Instead, use split() per vimdoc to break the input string into an
|
||||
" array of *characters*, and process that.
|
||||
let l:characters = split(l:pat, '\zs')
|
||||
|
||||
let l:index = 0 " character index
|
||||
let l:length = len(l:characters)
|
||||
let l:brace_level = 0
|
||||
let l:in_brackets = 0
|
||||
|
||||
let l:result = ''
|
||||
let l:numeric_groups = []
|
||||
while l:index < l:length
|
||||
let l:current_char = l:characters[l:index]
|
||||
let l:index += 1
|
||||
|
||||
" if g:editorconfig_core_vimscript_debug
|
||||
" echom ' - fnmatch#translate: ' . l:current_char . '@' .
|
||||
" \ (l:index-1) . '; result ' . l:result
|
||||
" endif
|
||||
|
||||
if l:current_char ==# '*'
|
||||
let l:pos = l:index
|
||||
if l:pos < l:length && l:characters[l:pos] ==# '*'
|
||||
let l:result .= '\_.*'
|
||||
let l:index += 1 " skip the second star
|
||||
else
|
||||
let l:result .= '[^/]*'
|
||||
endif
|
||||
|
||||
elseif l:current_char ==# '?'
|
||||
let l:result .= '\_[^/]'
|
||||
|
||||
elseif l:current_char ==# '['
|
||||
if l:in_brackets
|
||||
let l:result .= '\['
|
||||
else
|
||||
let l:pos = l:index
|
||||
let l:has_slash = 0
|
||||
while l:pos < l:length && l:characters[l:pos] != ']'
|
||||
if l:characters[l:pos] ==# '/' && l:characters[l:pos-1] !=# '\'
|
||||
let has_slash = 1
|
||||
break
|
||||
endif
|
||||
let l:pos += 1
|
||||
endwhile
|
||||
if l:has_slash
|
||||
" POSIX IEEE 1003.1-2017 sec. 2.13.3: '/' cannot occur
|
||||
" in a bracket expression, so [/] matches a literal
|
||||
" three-character string '[' . '/' . ']'.
|
||||
let l:result .= '\['
|
||||
\ . s:re_escape(join(l:characters[l:index : l:pos-1], ''))
|
||||
\ . '\/'
|
||||
" escape the slash
|
||||
let l:index = l:pos + 1
|
||||
" resume after the slash
|
||||
else
|
||||
if l:index < l:length && l:characters[l:index] =~# '\v%(\^|\!)'
|
||||
let l:index += 1
|
||||
let l:result .= '[^'
|
||||
else
|
||||
let l:result .= '['
|
||||
endif
|
||||
let l:in_brackets = 1
|
||||
endif
|
||||
endif
|
||||
|
||||
elseif l:current_char ==# '-'
|
||||
if l:in_brackets
|
||||
let l:result .= l:current_char
|
||||
else
|
||||
let l:result .= '\' . l:current_char
|
||||
endif
|
||||
|
||||
elseif l:current_char ==# ']'
|
||||
if l:in_brackets && !l:is_escaped
|
||||
let l:result .= ']'
|
||||
let l:in_brackets = 0
|
||||
elseif l:is_escaped
|
||||
let l:result .= '\]'
|
||||
let l:is_escaped = 0
|
||||
else
|
||||
let l:result .= '\]'
|
||||
endif
|
||||
|
||||
elseif l:current_char ==# '{'
|
||||
let l:pos = l:index
|
||||
let l:has_comma = 0
|
||||
while l:pos < l:length && (l:characters[l:pos] !=# '}' || l:is_escaped)
|
||||
if l:characters[l:pos] ==# ',' && ! l:is_escaped
|
||||
let l:has_comma = 1
|
||||
break
|
||||
endif
|
||||
let l:is_escaped = l:characters[l:pos] ==# '\' && ! l:is_escaped
|
||||
let l:pos += 1
|
||||
endwhile
|
||||
if ! l:has_comma && l:pos < l:length
|
||||
let l:num_range =
|
||||
\ matchlist(join(l:characters[l:index : l:pos-1], ''),
|
||||
\ s:NUMERIC_RANGE)
|
||||
if len(l:num_range) > 0 " Remember the ranges
|
||||
call add(l:numeric_groups, [ 0+l:num_range[1], 0+l:num_range[2] ])
|
||||
let l:result .= '([+-]?\d+)'
|
||||
else
|
||||
let l:inner_xlat = editorconfig_core#fnmatch#translate(
|
||||
\ join(l:characters[l:index : l:pos-1], ''), 1)
|
||||
let l:inner_result = l:inner_xlat[0]
|
||||
let l:inner_groups = l:inner_xlat[1]
|
||||
let l:result .= '\{' . l:inner_result . '\}'
|
||||
let l:numeric_groups += l:inner_groups
|
||||
endif
|
||||
let l:index = l:pos + 1
|
||||
elseif l:matching_braces
|
||||
let l:result .= '%('
|
||||
let l:brace_level += 1
|
||||
else
|
||||
let l:result .= '\{'
|
||||
endif
|
||||
|
||||
elseif l:current_char ==# ','
|
||||
if l:brace_level > 0 && ! l:is_escaped
|
||||
let l:result .= '|'
|
||||
else
|
||||
let l:result .= '\,'
|
||||
endif
|
||||
|
||||
elseif l:current_char ==# '}'
|
||||
if l:brace_level > 0 && ! l:is_escaped
|
||||
let l:result .= ')'
|
||||
let l:brace_level -= 1
|
||||
else
|
||||
let l:result .= '\}'
|
||||
endif
|
||||
|
||||
elseif l:current_char ==# '/'
|
||||
if join(l:characters[l:index : (l:index + 2)], '') ==# '**/'
|
||||
let l:result .= '%(/|/\_.*/)'
|
||||
let l:index += 3
|
||||
else
|
||||
let l:result .= '\/'
|
||||
endif
|
||||
|
||||
elseif l:current_char != '\'
|
||||
let l:result .= s:re_escape(l:current_char)
|
||||
endif
|
||||
|
||||
if l:current_char ==# '\'
|
||||
if l:is_escaped
|
||||
let l:result .= s:re_escape(l:current_char)
|
||||
endif
|
||||
let l:is_escaped = ! l:is_escaped
|
||||
else
|
||||
let l:is_escaped = 0
|
||||
endif
|
||||
|
||||
endwhile
|
||||
|
||||
if ! l:nested
|
||||
let l:result .= '\_$'
|
||||
endif
|
||||
|
||||
return [l:result, l:numeric_groups]
|
||||
endfunction " #editorconfig_core#fnmatch#translate
|
||||
|
||||
let s:_cache = {}
|
||||
function! s:cached_translate(pat)
|
||||
if ! has_key(s:_cache, a:pat)
|
||||
"regex = re.compile(res)
|
||||
let s:_cache[a:pat] =
|
||||
\ editorconfig_core#fnmatch#translate(a:pat)
|
||||
" we don't compile the regex
|
||||
endif
|
||||
return s:_cache[a:pat]
|
||||
endfunction " cached_translate
|
||||
|
||||
" }}}1
|
||||
" === Matching functions ================================================ {{{1
|
||||
|
||||
function! editorconfig_core#fnmatch#fnmatch(name, path, pattern)
|
||||
"def fnmatch(name, pat):
|
||||
" """Test whether FILENAME matches PATH/PATTERN.
|
||||
"
|
||||
" Patterns are Unix shell style:
|
||||
"
|
||||
" - ``*`` matches everything except path separator
|
||||
" - ``**`` matches everything
|
||||
" - ``?`` matches any single character
|
||||
" - ``[seq]`` matches any character in seq
|
||||
" - ``[!seq]`` matches any char not in seq
|
||||
" - ``{s1,s2,s3}`` matches any of the strings given (separated by commas)
|
||||
"
|
||||
" An initial period in FILENAME is not special.
|
||||
" Both FILENAME and PATTERN are first case-normalized
|
||||
" if the operating system requires it.
|
||||
" If you don't want this, use fnmatchcase(FILENAME, PATTERN).
|
||||
" """
|
||||
"
|
||||
" Note: This throws away the backslash in '\.txt' on Cygwin, but that
|
||||
" makes sense since it's Windows under the hood.
|
||||
" We don't care about shellslash since we're going to change backslashes
|
||||
" to slashes in just a moment anyway.
|
||||
let l:localname = fnamemodify(a:name, ':p')
|
||||
|
||||
if editorconfig_core#util#is_win() " normalize
|
||||
let l:localname = substitute(tolower(l:localname), '\v\\', '/', 'g')
|
||||
let l:path = substitute(tolower(a:path), '\v\\', '/', 'g')
|
||||
let l:pattern = tolower(a:pattern)
|
||||
else
|
||||
let l:localname = l:localname
|
||||
let l:path = a:path
|
||||
let l:pattern = a:pattern
|
||||
endif
|
||||
|
||||
if g:editorconfig_core_vimscript_debug
|
||||
echom '- fnmatch#fnmatch testing <' . l:localname . '> against <' .
|
||||
\ l:pattern . '> wrt <' . l:path . '>'
|
||||
endif
|
||||
|
||||
return editorconfig_core#fnmatch#fnmatchcase(l:localname, l:path, l:pattern)
|
||||
endfunction " fnmatch
|
||||
|
||||
function! editorconfig_core#fnmatch#fnmatchcase(name, path, pattern)
|
||||
"def fnmatchcase(name, pat):
|
||||
" """Test whether FILENAME matches PATH/PATTERN, including case.
|
||||
"
|
||||
" This is a version of fnmatch() which doesn't case-normalize
|
||||
" its arguments.
|
||||
" """
|
||||
"
|
||||
let [regex, num_groups] = s:cached_translate(a:pattern)
|
||||
|
||||
let l:escaped_path = s:re_escape(a:path)
|
||||
let l:regex = '\v' . l:escaped_path . l:regex
|
||||
|
||||
if g:editorconfig_core_vimscript_debug
|
||||
echom '- fnmatch#fnmatchcase: regex ' . l:regex
|
||||
call s:dump_chars(l:regex)
|
||||
echom '- fnmatch#fnmatchcase: checking ' . a:name
|
||||
call s:dump_chars(a:name)
|
||||
endif
|
||||
|
||||
let l:match_groups = matchlist(a:name, l:regex)[1:] " [0] = full match
|
||||
|
||||
if g:editorconfig_core_vimscript_debug
|
||||
echom printf(' Got %d matches', len(l:match_groups))
|
||||
endif
|
||||
|
||||
if len(l:match_groups) == 0
|
||||
return 0
|
||||
endif
|
||||
|
||||
" Check numeric ranges
|
||||
let pattern_matched = 1
|
||||
for l:idx in range(0,len(l:match_groups))
|
||||
let l:num = l:match_groups[l:idx]
|
||||
if l:num ==# ''
|
||||
break
|
||||
endif
|
||||
|
||||
let [min_num, max_num] = num_groups[l:idx]
|
||||
if (min_num > (0+l:num)) || ((0+l:num) > max_num)
|
||||
let pattern_matched = 0
|
||||
break
|
||||
endif
|
||||
|
||||
" Reject leading zeros without sign. This is very odd ---
|
||||
" see editorconfig/editorconfig#371.
|
||||
if match(l:num, '\v^0') != -1
|
||||
let pattern_matched = 0
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
|
||||
if g:editorconfig_core_vimscript_debug
|
||||
echom '- fnmatch#fnmatchcase: ' . (pattern_matched ? 'matched' : 'did not match')
|
||||
endif
|
||||
|
||||
return pattern_matched
|
||||
endfunction " fnmatchcase
|
||||
|
||||
" }}}1
|
||||
" === Copyright notices ================================================= {{{1
|
||||
" Based on code from fnmatch.py file distributed with Python 2.6.
|
||||
" Portions Copyright (c) 2001-2010 Python Software Foundation;
|
||||
" All Rights Reserved. Licensed under PSF License (see LICENSE.PSF file).
|
||||
"
|
||||
" Changes to original fnmatch:
|
||||
"
|
||||
" - translate function supports ``*`` and ``**`` similarly to fnmatch C library
|
||||
" }}}1
|
||||
|
||||
let &cpo = s:saved_cpo
|
||||
unlet! s:saved_cpo
|
||||
|
||||
" vi: set fdm=marker:
|
@ -0,0 +1,183 @@
|
||||
" autoload/editorconfig_core/handler.vim: Main worker for
|
||||
" editorconfig-core-vimscript and editorconfig-vim.
|
||||
" Modified from the Python core's handler.py.
|
||||
|
||||
" Copyright (c) 2012-2019 EditorConfig Team {{{1
|
||||
" All rights reserved.
|
||||
"
|
||||
" Redistribution and use in source and binary forms, with or without
|
||||
" modification, are permitted provided that the following conditions are met:
|
||||
"
|
||||
" 1. Redistributions of source code must retain the above copyright notice,
|
||||
" this list of conditions and the following disclaimer.
|
||||
" 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
" this list of conditions and the following disclaimer in the documentation
|
||||
" and/or other materials provided with the distribution.
|
||||
"
|
||||
" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
" POSSIBILITY OF SUCH DAMAGE. }}}1
|
||||
|
||||
let s:saved_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
" Return full filepath for filename in each directory in and above path. {{{1
|
||||
" Input path must be an absolute path.
|
||||
" TODO shellslash/shellescape?
|
||||
function! s:get_filenames(path, config_filename)
|
||||
let l:path = a:path
|
||||
let l:path_list = []
|
||||
while 1
|
||||
call add(l:path_list, editorconfig_core#util#path_join(l:path, a:config_filename))
|
||||
let l:newpath = fnamemodify(l:path, ':h')
|
||||
if l:path ==? l:newpath || !strlen(l:path)
|
||||
break
|
||||
endif
|
||||
let l:path = l:newpath
|
||||
endwhile
|
||||
return l:path_list
|
||||
endfunction " get_filenames
|
||||
|
||||
" }}}1
|
||||
" === Main ============================================================== {{{1
|
||||
|
||||
" Find EditorConfig files and return all options matching target_filename.
|
||||
" Throws on failure.
|
||||
" @param job {Dictionary} required 'target'; optional 'config' and 'version'
|
||||
function! editorconfig_core#handler#get_configurations(job)
|
||||
" TODO? support VERSION checks?
|
||||
|
||||
" Special exceptions that may be raised by this function include:
|
||||
" - ``VersionError``: self.version is invalid EditorConfig version
|
||||
" - ``PathError``: self.filepath is not a valid absolute filepath
|
||||
" - ``ParsingError``: improperly formatted EditorConfig file found
|
||||
|
||||
let l:job = deepcopy(a:job)
|
||||
if has_key(l:job, 'config')
|
||||
let l:config_filename = l:job.config
|
||||
else
|
||||
let l:config_filename = '.editorconfig'
|
||||
let l:job.config = l:config_filename
|
||||
endif
|
||||
|
||||
if has_key(l:job, 'version')
|
||||
let l:version = l:job.version
|
||||
else
|
||||
let l:version = editorconfig_core#version()
|
||||
let l:job.version = l:version
|
||||
endif
|
||||
|
||||
let l:target_filename = l:job.target
|
||||
|
||||
"echom 'Beginning job ' . string(l:job)
|
||||
if !s:check_assertions(l:job)
|
||||
throw "Assertions failed"
|
||||
endif
|
||||
|
||||
let l:fullpath = fnamemodify(l:target_filename,':p')
|
||||
let l:path = fnamemodify(l:fullpath, ':h')
|
||||
let l:conf_files = s:get_filenames(l:path, l:config_filename)
|
||||
|
||||
" echom 'fullpath ' . l:fullpath
|
||||
" echom 'path ' . l:path
|
||||
|
||||
let l:retval = {}
|
||||
|
||||
" Attempt to find and parse every EditorConfig file in filetree
|
||||
for l:conf_fn in l:conf_files
|
||||
"echom 'Trying ' . l:conf_fn
|
||||
let l:parsed = editorconfig_core#ini#read_ini_file(l:conf_fn, l:target_filename)
|
||||
if !has_key(l:parsed, 'options')
|
||||
continue
|
||||
endif
|
||||
" echom ' Has options'
|
||||
|
||||
" Merge new EditorConfig file's options into current options
|
||||
let l:old_options = l:retval
|
||||
let l:retval = l:parsed.options
|
||||
" echom 'Old options ' . string(l:old_options)
|
||||
" echom 'New options ' . string(l:retval)
|
||||
call extend(l:retval, l:old_options, 'force')
|
||||
|
||||
" Stop parsing if parsed file has a ``root = true`` option
|
||||
if l:parsed.root
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
|
||||
call s:preprocess_values(l:job, l:retval)
|
||||
return l:retval
|
||||
endfunction " get_configurations
|
||||
|
||||
function! s:check_assertions(job)
|
||||
" TODO
|
||||
" """Raise error if filepath or version have invalid values"""
|
||||
|
||||
" # Raise ``PathError`` if filepath isn't an absolute path
|
||||
" if not os.path.isabs(self.filepath):
|
||||
" raise PathError("Input file must be a full path name.")
|
||||
|
||||
" Throw if version specified is greater than current
|
||||
let l:v = a:job.version
|
||||
let l:us = editorconfig_core#version()
|
||||
" echom 'Comparing requested version ' . string(l:v) .
|
||||
" \ ' to our version ' . string(l:us)
|
||||
if l:v[0] > l:us[0] || l:v[1] > l:us[1] || l:v[2] > l:us[2]
|
||||
throw 'Required version ' . string(l:v) .
|
||||
\ ' is greater than the current version ' . string(l:us)
|
||||
endif
|
||||
|
||||
return 1 " All OK if we got here
|
||||
endfunction " check_assertions
|
||||
|
||||
" }}}1
|
||||
|
||||
" Preprocess option values for consumption by plugins. {{{1
|
||||
" Modifies its argument in place.
|
||||
function! s:preprocess_values(job, opts)
|
||||
|
||||
" Lowercase option value for certain options
|
||||
for l:name in ['end_of_line', 'indent_style', 'indent_size',
|
||||
\ 'insert_final_newline', 'trim_trailing_whitespace',
|
||||
\ 'charset']
|
||||
if has_key(a:opts, l:name)
|
||||
let a:opts[l:name] = tolower(a:opts[l:name])
|
||||
endif
|
||||
endfor
|
||||
|
||||
" Set indent_size to "tab" if indent_size is unspecified and
|
||||
" indent_style is set to "tab", provided we are at least v0.10.0.
|
||||
if get(a:opts, 'indent_style', '') ==? "tab" &&
|
||||
\ !has_key(a:opts, 'indent_size') &&
|
||||
\ ( a:job.version[0]>0 || a:job.version[1] >=10 )
|
||||
let a:opts['indent_size'] = 'tab'
|
||||
endif
|
||||
|
||||
" Set tab_width to indent_size if indent_size is specified and
|
||||
" tab_width is unspecified
|
||||
if has_key(a:opts, 'indent_size') && !has_key(a:opts, 'tab_width') &&
|
||||
\ get(a:opts, 'indent_size', '') !=? "tab"
|
||||
let a:opts['tab_width'] = a:opts['indent_size']
|
||||
endif
|
||||
|
||||
" Set indent_size to tab_width if indent_size is "tab"
|
||||
if has_key(a:opts, 'indent_size') && has_key(a:opts, 'tab_width') &&
|
||||
\ get(a:opts, 'indent_size', '') ==? "tab"
|
||||
let a:opts['indent_size'] = a:opts['tab_width']
|
||||
endif
|
||||
endfunction " preprocess_values
|
||||
|
||||
" }}}1
|
||||
|
||||
let &cpo = s:saved_cpo
|
||||
unlet! s:saved_cpo
|
||||
|
||||
" vi: set fdm=marker fdl=1:
|
@ -0,0 +1,273 @@
|
||||
" autoload/editorconfig_core/ini.vim: Config-file parser for
|
||||
" editorconfig-core-vimscript and editorconfig-vim.
|
||||
" Modifed from the Python core's ini.py.
|
||||
|
||||
" Copyright (c) 2012-2019 EditorConfig Team {{{2
|
||||
" All rights reserved.
|
||||
"
|
||||
" Redistribution and use in source and binary forms, with or without
|
||||
" modification, are permitted provided that the following conditions are met:
|
||||
"
|
||||
" 1. Redistributions of source code must retain the above copyright notice,
|
||||
" this list of conditions and the following disclaimer.
|
||||
" 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
" this list of conditions and the following disclaimer in the documentation
|
||||
" and/or other materials provided with the distribution.
|
||||
"
|
||||
" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
" POSSIBILITY OF SUCH DAMAGE. }}}2
|
||||
|
||||
let s:saved_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
" variables {{{2
|
||||
if !exists('g:editorconfig_core_vimscript_debug')
|
||||
let g:editorconfig_core_vimscript_debug = 0
|
||||
endif
|
||||
" }}}2
|
||||
" === Constants, including regexes ====================================== {{{2
|
||||
" Regular expressions for parsing section headers and options.
|
||||
" Allow ``]`` and escaped ``;`` and ``#`` characters in section headers.
|
||||
" In fact, allow \ to escape any single character - it needs to cover at
|
||||
" least \ * ? [ ! ] { }.
|
||||
unlockvar s:SECTCRE s:OPTCRE s:MAX_SECTION_NAME s:MAX_PROPERTY_NAME s:MAX_PROPERTY_VALUE
|
||||
let s:SECTCRE = '\v^\s*\[(%([^\\#;]|\\.)+)\]'
|
||||
|
||||
" Regular expression for parsing option name/values.
|
||||
" Allow any amount of whitespaces, followed by separator
|
||||
" (either ``:`` or ``=``), followed by any amount of whitespace and then
|
||||
" any characters to eol
|
||||
let s:OPTCRE = '\v\s*([^:=[:space:]][^:=]*)\s*([:=])\s*(.*)$'
|
||||
|
||||
let s:MAX_SECTION_NAME = 4096
|
||||
let s:MAX_PROPERTY_NAME = 50
|
||||
let s:MAX_PROPERTY_VALUE = 255
|
||||
|
||||
lockvar s:SECTCRE s:OPTCRE s:MAX_SECTION_NAME s:MAX_PROPERTY_NAME s:MAX_PROPERTY_VALUE
|
||||
|
||||
" }}}2
|
||||
" === Main ============================================================== {{{1
|
||||
|
||||
" Read \p config_filename and return the options applicable to
|
||||
" \p target_filename. This is the main entry point in this file.
|
||||
function! editorconfig_core#ini#read_ini_file(config_filename, target_filename)
|
||||
let l:oldenc = &encoding
|
||||
|
||||
if !filereadable(a:config_filename)
|
||||
return {}
|
||||
endif
|
||||
|
||||
try " so &encoding will always be reset
|
||||
let &encoding = 'utf-8' " so readfile() will strip BOM
|
||||
let l:lines = readfile(a:config_filename)
|
||||
let result = s:parse(a:config_filename, a:target_filename, l:lines)
|
||||
catch
|
||||
let &encoding = l:oldenc
|
||||
" rethrow, but with a prefix since throw 'Vim...' fails.
|
||||
throw 'Could not read editorconfig file at ' . v:throwpoint . ': ' . string(v:exception)
|
||||
endtry
|
||||
|
||||
let &encoding = l:oldenc
|
||||
return result
|
||||
endfunction
|
||||
|
||||
function! s:parse(config_filename, target_filename, lines)
|
||||
" Parse a sectioned setup file.
|
||||
" The sections in setup file contains a title line at the top,
|
||||
" indicated by a name in square brackets (`[]'), plus key/value
|
||||
" options lines, indicated by `name: value' format lines.
|
||||
" Continuations are represented by an embedded newline then
|
||||
" leading whitespace. Blank lines, lines beginning with a '#',
|
||||
" and just about everything else are ignored.
|
||||
|
||||
let l:in_section = 0
|
||||
let l:matching_section = 0
|
||||
let l:optname = ''
|
||||
let l:lineno = 0
|
||||
let l:e = [] " Errors, if any
|
||||
|
||||
let l:options = {} " Options applicable to this file
|
||||
let l:is_root = 0 " Whether a:config_filename declares root=true
|
||||
|
||||
while 1
|
||||
if l:lineno == len(a:lines)
|
||||
break
|
||||
endif
|
||||
|
||||
let l:line = a:lines[l:lineno]
|
||||
let l:lineno = l:lineno + 1
|
||||
|
||||
" comment or blank line?
|
||||
if editorconfig_core#util#strip(l:line) ==# ''
|
||||
continue
|
||||
endif
|
||||
if l:line =~# '\v^[#;]'
|
||||
continue
|
||||
endif
|
||||
|
||||
" is it a section header?
|
||||
if g:editorconfig_core_vimscript_debug
|
||||
echom "Header? <" . l:line . ">"
|
||||
endif
|
||||
|
||||
let l:mo = matchlist(l:line, s:SECTCRE)
|
||||
if len(l:mo)
|
||||
let l:sectname = l:mo[1]
|
||||
let l:in_section = 1
|
||||
if strlen(l:sectname) > s:MAX_SECTION_NAME
|
||||
" Section name too long => ignore the section
|
||||
let l:matching_section = 0
|
||||
else
|
||||
let l:matching_section = s:matches_filename(
|
||||
\ a:config_filename, a:target_filename, l:sectname)
|
||||
endif
|
||||
|
||||
if g:editorconfig_core_vimscript_debug
|
||||
echom 'In section ' . l:sectname . ', which ' .
|
||||
\ (l:matching_section ? 'matches' : 'does not match')
|
||||
\ ' file ' . a:target_filename . ' (config ' .
|
||||
\ a:config_filename . ')'
|
||||
endif
|
||||
|
||||
" So sections can't start with a continuation line
|
||||
let l:optname = ''
|
||||
|
||||
" Is it an option line?
|
||||
else
|
||||
let l:mo = matchlist(l:line, s:OPTCRE)
|
||||
if len(l:mo)
|
||||
let l:optname = mo[1]
|
||||
let l:optval = mo[3]
|
||||
|
||||
if g:editorconfig_core_vimscript_debug
|
||||
echom printf('Saw raw opt <%s>=<%s>', l:optname, l:optval)
|
||||
endif
|
||||
|
||||
if l:optval =~# '\v[;#]'
|
||||
" ';' and '#' are comment delimiters only if
|
||||
" preceded by a spacing character
|
||||
let l:m = matchlist(l:optval, '\v(.{-})\s[;#]')
|
||||
if len(l:m)
|
||||
let l:optval = l:m[1]
|
||||
endif
|
||||
|
||||
" ; and # can be escaped with backslash.
|
||||
let l:optval = substitute(l:optval, '\v\\([;#])', '\1', 'g')
|
||||
|
||||
endif
|
||||
let l:optval = editorconfig_core#util#strip(l:optval)
|
||||
" allow empty values
|
||||
if l:optval ==? '""'
|
||||
let l:optval = ''
|
||||
endif
|
||||
let l:optname = s:optionxform(l:optname)
|
||||
if !l:in_section && optname ==? 'root'
|
||||
let l:is_root = (optval ==? 'true')
|
||||
endif
|
||||
if g:editorconfig_core_vimscript_debug
|
||||
echom printf('Saw opt <%s>=<%s>', l:optname, l:optval)
|
||||
endif
|
||||
|
||||
if l:matching_section &&
|
||||
\ strlen(l:optname) <= s:MAX_PROPERTY_NAME &&
|
||||
\ strlen(l:optval) <= s:MAX_PROPERTY_VALUE
|
||||
let l:options[l:optname] = l:optval
|
||||
endif
|
||||
else
|
||||
" a non-fatal parsing error occurred. set up the
|
||||
" exception but keep going. the exception will be
|
||||
" raised at the end of the file and will contain a
|
||||
" list of all bogus lines
|
||||
call add(e, "Parse error in '" . a:config_filename . "' at line " .
|
||||
\ l:lineno . ": '" . l:line . "'")
|
||||
endif
|
||||
endif
|
||||
endwhile
|
||||
|
||||
" if any parsing errors occurred, raise an exception
|
||||
if len(l:e)
|
||||
throw string(l:e)
|
||||
endif
|
||||
|
||||
return {'root': l:is_root, 'options': l:options}
|
||||
endfunction!
|
||||
|
||||
" }}}1
|
||||
" === Helpers =========================================================== {{{1
|
||||
|
||||
" Preprocess option names
|
||||
function! s:optionxform(optionstr)
|
||||
let l:result = substitute(a:optionstr, '\v\s+$', '', 'g') " rstrip
|
||||
return tolower(l:result)
|
||||
endfunction
|
||||
|
||||
" Return true if \p glob matches \p target_filename
|
||||
function! s:matches_filename(config_filename, target_filename, glob)
|
||||
" config_dirname = normpath(dirname(config_filename)).replace(sep, '/')
|
||||
let l:config_dirname = fnamemodify(a:config_filename, ':p:h') . '/'
|
||||
|
||||
if editorconfig_core#util#is_win()
|
||||
" Regardless of whether shellslash is set, make everything slashes
|
||||
let l:config_dirname =
|
||||
\ tolower(substitute(l:config_dirname, '\v\\', '/', 'g'))
|
||||
endif
|
||||
|
||||
let l:glob = substitute(a:glob, '\v\\([#;])', '\1', 'g')
|
||||
|
||||
" Take account of the path to the editorconfig file.
|
||||
" editorconfig-core-c/src/lib/editorconfig.c says:
|
||||
" "Pattern would be: /dir/of/editorconfig/file[double_star]/[section] if
|
||||
" section does not contain '/', or /dir/of/editorconfig/file[section]
|
||||
" if section starts with a '/', or /dir/of/editorconfig/file/[section] if
|
||||
" section contains '/' but does not start with '/'."
|
||||
|
||||
if stridx(l:glob, '/') != -1 " contains a slash
|
||||
if l:glob[0] ==# '/'
|
||||
let l:glob = l:glob[1:] " trim leading slash
|
||||
endif
|
||||
" This will be done by fnmatch
|
||||
" let l:glob = l:config_dirname . l:glob
|
||||
else " does not contain a slash
|
||||
let l:config_dirname = l:config_dirname[:-2]
|
||||
" Trim trailing slash
|
||||
let l:glob = '**/' . l:glob
|
||||
endif
|
||||
|
||||
if g:editorconfig_core_vimscript_debug
|
||||
echom '- ini#matches_filename: checking <' . a:target_filename .
|
||||
\ '> against <' . l:glob . '> with respect to config file <' .
|
||||
\ a:config_filename . '>'
|
||||
echom '- ini#matches_filename: config_dirname is ' . l:config_dirname
|
||||
endif
|
||||
|
||||
return editorconfig_core#fnmatch#fnmatch(a:target_filename,
|
||||
\ l:config_dirname, l:glob)
|
||||
endfunction " matches_filename
|
||||
|
||||
" }}}1
|
||||
" === Copyright notices ================================================= {{{2
|
||||
" Based on code from ConfigParser.py file distributed with Python 2.6.
|
||||
" Portions Copyright (c) 2001-2010 Python Software Foundation;
|
||||
" All Rights Reserved. Licensed under PSF License (see LICENSE.PSF file).
|
||||
"
|
||||
" Changes to original ConfigParser:
|
||||
"
|
||||
" - Special characters can be used in section names
|
||||
" - Octothorpe can be used for comments (not just at beginning of line)
|
||||
" - Only track INI options in sections that match target filename
|
||||
" - Stop parsing files with when ``root = true`` is found
|
||||
" }}}2
|
||||
|
||||
let &cpo = s:saved_cpo
|
||||
unlet! s:saved_cpo
|
||||
|
||||
" vi: set fdm=marker fdl=1:
|
@ -0,0 +1,84 @@
|
||||
" util.vim: part of editorconfig-core-vimscript and editorconfig-vim.
|
||||
" Copyright (c) 2018-2019 EditorConfig Team, including Chris White {{{1
|
||||
" All rights reserved.
|
||||
"
|
||||
" Redistribution and use in source and binary forms, with or without
|
||||
" modification, are permitted provided that the following conditions are met:
|
||||
"
|
||||
" 1. Redistributions of source code must retain the above copyright notice,
|
||||
" this list of conditions and the following disclaimer.
|
||||
" 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
" this list of conditions and the following disclaimer in the documentation
|
||||
" and/or other materials provided with the distribution.
|
||||
"
|
||||
" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
" POSSIBILITY OF SUCH DAMAGE. }}}1
|
||||
|
||||
let s:saved_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
" A verbatim copy of ingo#fs#path#Separator() {{{1
|
||||
" from https://github.com/vim-scripts/ingo-library/blob/558132e2221db3af26dc2f2c6756d092d48a459f/autoload/ingo/fs/path.vim
|
||||
" distributed under the Vim license.
|
||||
function! editorconfig_core#util#Separator()
|
||||
return (exists('+shellslash') && ! &shellslash ? '\' : '/')
|
||||
endfunction " }}}1
|
||||
|
||||
" path_join(): ('a','b')->'a/b'; ('a/','b')->'a/b'. {{{1
|
||||
function! editorconfig_core#util#path_join(a, b)
|
||||
" TODO shellescape/shellslash?
|
||||
"echom 'Joining <' . a:a . '> and <' . a:b . '>'
|
||||
"echom 'Length is ' . strlen(a:a)
|
||||
"echom 'Last char is ' . char2nr(a:a[-1])
|
||||
if a:a !~# '\v%(\/|\\)$'
|
||||
return a:a . editorconfig_core#util#Separator() . a:b
|
||||
else
|
||||
return a:a . a:b
|
||||
endif
|
||||
endfunction " }}}1
|
||||
|
||||
" is_win() by xolox {{{1
|
||||
" The following function is modified from
|
||||
" https://github.com/xolox/vim-misc/blob/master/autoload/xolox/misc/os.vim
|
||||
" Copyright (c) 2015 Peter Odding <peter@peterodding.com>
|
||||
"
|
||||
" 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:
|
||||
"
|
||||
" The above copyright notice and this permission notice shall be included in all
|
||||
" copies or substantial portions of the Software.
|
||||
"
|
||||
" 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.
|
||||
function! editorconfig_core#util#is_win()
|
||||
" Returns 1 (true) when on Microsoft Windows, 0 (false) otherwise.
|
||||
return has('win16') || has('win32') || has('win64')
|
||||
endfunction " }}}1
|
||||
|
||||
" strip() {{{1
|
||||
function! editorconfig_core#util#strip(s)
|
||||
return substitute(a:s, '\v^\s+|\s+$','','g')
|
||||
endfunction " }}}1
|
||||
|
||||
let &cpo = s:saved_cpo
|
||||
unlet! s:saved_cpo
|
||||
|
||||
" vi: set fdm=marker:
|
Reference in New Issue
Block a user