1
0
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:
luc
2021-06-06 15:51:23 +08:00
parent 8cba9bb7a8
commit da40fe1222
37 changed files with 3551 additions and 0 deletions

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

@ -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:

View File

@ -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:

View File

@ -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: