067e2361df
subrepo: subdir: "dotfiles/.vim/plugged/editorconfig-vim" merged: "d354117b" upstream: origin: "https://github.com/editorconfig/editorconfig-vim.git" branch: "master" commit: "d354117b" git-subrepo: version: "0.4.3" origin: "???" commit: "???"
183 lines
6.6 KiB
VimL
183 lines
6.6 KiB
VimL
" 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:
|