mirror of https://github.com/amix/vimrc.git
parent
8cba9bb7a8
commit
da40fe1222
@ -0,0 +1,107 @@ |
||||
# appveyor.yml for editorconfig-vim. Currently only tests the core. |
||||
# Modified from https://github.com/ppalaga/ec4j/commit/1c849658fb189cd95bc41af95acd43b4f0d75a48 |
||||
# |
||||
# Copyright (c) 2017--2019 Angelo Zerr and other contributors as |
||||
# indicated by the @author tags. |
||||
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
# |
||||
# @author Chris White (cxw42) - Adapted to editorconfig-vim |
||||
|
||||
# === When to build === |
||||
# See https://www.appveyor.com/docs/how-to/filtering-commits/ |
||||
|
||||
skip_commits: |
||||
message: /\[minor\]/ |
||||
files: |
||||
- '**/*.md' |
||||
|
||||
# === Build matrix === |
||||
|
||||
# Win is default; Ubuntu is override. See |
||||
# https://www.appveyor.com/blog/2018/04/25/specialized-build-matrix-configuration-in-appveyor/ |
||||
image: |
||||
- Visual Studio 2013 |
||||
- Ubuntu1604 |
||||
|
||||
# === How to build === |
||||
|
||||
cache: |
||||
- C:\vim -> .appveyor.yml, tests\fetch-vim.bat |
||||
|
||||
environment: |
||||
VIM_EXE: C:\vim\vim\vim80\vim.exe |
||||
|
||||
for: |
||||
# Don't run the Windows build if the commit message includes "[ci-linux]" |
||||
- |
||||
matrix: |
||||
only: |
||||
- image: Visual Studio 2013 |
||||
skip_commits: |
||||
message: /\[ci-linux\]/ |
||||
|
||||
# Platform-specific configuration for Ubuntu |
||||
- |
||||
matrix: |
||||
only: |
||||
- image: Ubuntu1604 |
||||
# $APPVEYOR_BUILD_FOLDER isn't expanded in the environment section |
||||
# here, so I can't set $VIM_EXE the way I want to. Instead, |
||||
# I set $VIM_EXE in the sh-specific install steps below. |
||||
environment: |
||||
VIM_EXE: UNDEFINED |
||||
cache: |
||||
- $APPVEYOR_BUILD_FOLDER/vim -> .appveyor.yml, tests/fetch-vim.sh |
||||
|
||||
# Plus, don't run Ubuntu if the commit message includes [ci-win] |
||||
skip_commits: |
||||
message: /\[ci-win\]/ |
||||
|
||||
install: |
||||
# Ubuntu-specific setup. These carry forward to the build_script. |
||||
- sh: export VIM_EXE="$APPVEYOR_BUILD_FOLDER/vim/bin/vim" |
||||
- sh: export PATH="$PATH":$APPVEYOR_BUILD_FOLDER/vim/bin |
||||
- sh: echo "$VIM_EXE , $PATH" |
||||
|
||||
# Cross-platform - test the core |
||||
- cmake --version |
||||
- git submodule update --init --recursive |
||||
- cmd: tests\fetch-vim |
||||
- sh: tests/fetch-vim.sh |
||||
|
||||
build_script: |
||||
# Build the core tests |
||||
- cd tests |
||||
- cd core |
||||
- mkdir build |
||||
- cd build |
||||
- cmake .. |
||||
|
||||
# Note on multicore testing: |
||||
# Two cores are available per https://help.appveyor.com/discussions/questions/11179-how-many-cores-and-threads-can-be-used-in-free-appveyor-build . |
||||
# However, using -j2 seems to make each job take much longer. |
||||
|
||||
test_script: |
||||
# Run the core tests |
||||
- ctest . --output-on-failure -C Debug |
||||
|
||||
# CTestCustom specifies skipping UTF-8 tests on Windows. |
||||
- cmd: echo "Reminder - did not try UTF-8" |
||||
- sh: echo "Reminder - tried UTF-8" |
||||
|
||||
on_failure: |
||||
- echo "failed" |
||||
- cmd: type tests\core\build\Testing\Temporary\LastTest.log |
||||
- sh: cat tests/core/build/Testing/Temporary/LastTest.log |
||||
|
@ -0,0 +1,27 @@ |
||||
root = true |
||||
|
||||
[*] |
||||
end_of_line = lf |
||||
charset = utf-8 |
||||
max_line_length = 80 |
||||
|
||||
[*.{vim,sh}] |
||||
indent_style = space |
||||
indent_size = 4 |
||||
insert_final_newline = true |
||||
trim_trailing_whitespace = true |
||||
max_line_length = 80 |
||||
|
||||
[*.rb] |
||||
indent_style = space |
||||
indent_size = 2 |
||||
insert_final_newline = true |
||||
trim_trailing_whitespace = true |
||||
max_line_length = 120 |
||||
|
||||
[*.yml] |
||||
indent_style = space |
||||
indent_size = 2 |
||||
|
||||
[*.{bat,vbs,ps1}] |
||||
end_of_line = CRLF |
@ -0,0 +1,8 @@ |
||||
tags |
||||
tests/**/build |
||||
tests/**/.bundle |
||||
|
||||
# Editor backup files |
||||
*.swp |
||||
*~ |
||||
~* |
@ -0,0 +1,6 @@ |
||||
[submodule "plugin_tests"] |
||||
path = tests/plugin/spec/plugin_tests |
||||
url = https://github.com/editorconfig/editorconfig-plugin-tests.git |
||||
[submodule "core_tests"] |
||||
path = tests/core/tests |
||||
url = https://github.com/editorconfig/editorconfig-core-test.git |
@ -0,0 +1,30 @@ |
||||
# Make sure xvfb works - https://docs.travis-ci.com/user/gui-and-headless-browsers/#using-xvfb-directly |
||||
dist: trusty |
||||
|
||||
matrix: |
||||
include: |
||||
- name: "plugin" |
||||
env: TEST_WHICH=plugin |
||||
language: ruby |
||||
rvm: |
||||
- 2.2.4 |
||||
gemfile: tests/plugin/Gemfile |
||||
- name: "core" |
||||
env: TEST_WHICH=core |
||||
|
||||
addons: |
||||
apt: |
||||
packages: |
||||
- vim-gtk |
||||
|
||||
before_script: |
||||
- "export DISPLAY=:99.0" |
||||
- "sh -e /etc/init.d/xvfb start" |
||||
|
||||
script: |
||||
./tests/travis-test.sh |
||||
|
||||
notifications: |
||||
email: |
||||
on_success: change |
||||
on_failure: always |
@ -0,0 +1,6 @@ |
||||
Contributors to the EditorConfig Vim Plugin: |
||||
|
||||
Hong Xu |
||||
Trey Hunner |
||||
Kent Frazier |
||||
Chris White |
@ -0,0 +1,26 @@ |
||||
Unless otherwise stated, all files are distributed under the Simplified BSD |
||||
license included below. |
||||
|
||||
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. |
@ -0,0 +1,53 @@ |
||||
Some code in editorconfig-vim is derived from code licensed under the |
||||
PSF license. The following is the text of that license, retrieved 2019-05-05 |
||||
from https://docs.python.org/2.6/license.html#terms-and-conditions-for-accessing-or-otherwise-using-python |
||||
|
||||
PSF LICENSE AGREEMENT FOR PYTHON 2.6.9 |
||||
|
||||
1. This LICENSE AGREEMENT is between the Python Software Foundation |
||||
(``PSF''), and the Individual or Organization (``Licensee'') accessing and |
||||
otherwise using Python 2.6.9 software in source or binary form and its |
||||
associated documentation. |
||||
|
||||
2. Subject to the terms and conditions of this License Agreement, PSF |
||||
hereby grants Licensee a nonexclusive, royalty-free, world-wide |
||||
license to reproduce, analyze, test, perform and/or display publicly, |
||||
prepare derivative works, distribute, and otherwise use Python 2.6.9 |
||||
alone or in any derivative version, provided, however, that PSF's |
||||
License Agreement and PSF's notice of copyright, i.e., ``Copyright (c) |
||||
2001-2010 Python Software Foundation; All Rights Reserved'' are |
||||
retained in Python 2.6.9 alone or in any derivative version prepared |
||||
by Licensee. |
||||
|
||||
3. In the event Licensee prepares a derivative work that is based on |
||||
or incorporates Python 2.6.9 or any part thereof, and wants to make |
||||
the derivative work available to others as provided herein, then |
||||
Licensee hereby agrees to include in any such work a brief summary of |
||||
the changes made to Python 2.6.9. |
||||
|
||||
4. PSF is making Python 2.6.9 available to Licensee on an ``AS IS'' |
||||
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. |
||||
BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY |
||||
REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY |
||||
PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.6.9 WILL NOT INFRINGE |
||||
ANY THIRD PARTY RIGHTS. |
||||
|
||||
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON |
||||
2.6.9 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS |
||||
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.6.9, |
||||
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. |
||||
|
||||
6. This License Agreement will automatically terminate upon a material |
||||
breach of its terms and conditions. |
||||
|
||||
7. Nothing in this License Agreement shall be deemed to create any |
||||
relationship of agency, partnership, or joint venture between PSF and |
||||
Licensee. This License Agreement does not grant permission to use PSF |
||||
trademarks or trade name in a trademark sense to endorse or promote |
||||
products or services of Licensee, or any third party. |
||||
|
||||
8. By copying, installing or otherwise using Python 2.6.9, Licensee |
||||
agrees to be bound by the terms and conditions of this License |
||||
Agreement. |
||||
|
||||
# vi: set ft=: |
@ -0,0 +1,148 @@ |
||||
# EditorConfig Vim Plugin |
||||
|
||||
[](https://travis-ci.org/editorconfig/editorconfig-vim) |
||||
[](https://ci.appveyor.com/project/cxw42/editorconfig-vim) |
||||
|
||||
This is an [EditorConfig][] plugin for Vim. This plugin can be found on both |
||||
[GitHub][] and [Vim online][]. |
||||
|
||||
## Installation |
||||
|
||||
To install this plugin, you can use one of the following ways: |
||||
|
||||
### Install with the archive |
||||
|
||||
Download the [archive][] and extract it into your Vim runtime directory |
||||
(`~/.vim` on UNIX/Linux and `$VIM_INSTALLATION_FOLDER\vimfiles` on windows). |
||||
You should have 3 sub-directories in this runtime directory now: "autoload", |
||||
"doc" and "plugin". |
||||
|
||||
### Install as Vim8 plugin |
||||
|
||||
Install as a Vim 8 plugin. Note `local` can be any name, but some path |
||||
element must be present. On Windows, instead of `~/.vim` use |
||||
`$VIM_INSTALLATION_FOLDER\vimfiles`. |
||||
```shell |
||||
mkdir -p ~/.vim/pack/local/start |
||||
cd ~/.vim/pack/local/start |
||||
git clone https://github.com/editorconfig/editorconfig-vim.git |
||||
``` |
||||
|
||||
### Install with [pathogen][] |
||||
|
||||
Use pathogen (the git repository of this plugin is |
||||
https://github.com/editorconfig/editorconfig-vim.git) |
||||
|
||||
### Install with [Vundle][] |
||||
|
||||
Use Vundle by adding to your `.vimrc` Vundle plugins section: |
||||
|
||||
```viml |
||||
Plugin 'editorconfig/editorconfig-vim' |
||||
``` |
||||
|
||||
Then call `:PluginInstall`. |
||||
|
||||
### Install with [vim-plug][] |
||||
|
||||
Use vim-plug by adding to your `.vimrc` in your plugin section: |
||||
|
||||
```viml |
||||
Plug 'editorconfig/editorconfig-vim' |
||||
``` |
||||
|
||||
Source your `.vimrc` by calling `:source $MYVIMRC`. |
||||
|
||||
Then call `:PlugInstall`. |
||||
|
||||
### No external editorconfig core library is required |
||||
|
||||
Previous versions of this plugin also required a Python "core". |
||||
The core included the code to parse `.editorconfig` files. |
||||
This plugin **includes** the core, so you don't need to download the |
||||
core separately. |
||||
|
||||
## Supported properties |
||||
|
||||
The EditorConfig Vim plugin supports the following EditorConfig [properties][]: |
||||
|
||||
* `indent_style` |
||||
* `indent_size` |
||||
* `tab_width` |
||||
* `end_of_line` |
||||
* `charset` |
||||
* `insert_final_newline` (Feature `+fixendofline`, available on Vim 7.4.785+, |
||||
or [PreserveNoEOL][] is required for this property) |
||||
* `trim_trailing_whitespace` |
||||
* `max_line_length` |
||||
* `root` (only used by EditorConfig core) |
||||
|
||||
## Selected Options |
||||
|
||||
The supported options are documented in [editorconfig.txt][] |
||||
and can be viewed by executing the following: `:help editorconfig`. You may |
||||
need to execute `:helptags ALL` so that Vim is aware of editorconfig.txt. |
||||
|
||||
### Excluded patterns |
||||
|
||||
To ensure that this plugin works well with [Tim Pope's fugitive][], use the |
||||
following patterns array: |
||||
|
||||
```viml |
||||
let g:EditorConfig_exclude_patterns = ['fugitive://.*'] |
||||
``` |
||||
|
||||
If you wanted to avoid loading EditorConfig for any remote files over ssh: |
||||
|
||||
```viml |
||||
let g:EditorConfig_exclude_patterns = ['scp://.*'] |
||||
``` |
||||
|
||||
Of course these two items could be combined into the following: |
||||
|
||||
```viml |
||||
let g:EditorConfig_exclude_patterns = ['fugitive://.*', 'scp://.*'] |
||||
``` |
||||
|
||||
### Disable for a specific filetype |
||||
|
||||
You can disable this plugin for a specific buffer by setting |
||||
`b:EditorConfig_disable`. Therefore, you can disable the |
||||
plugin for all buffers of a specific filetype. For example, to disable |
||||
EditorConfig for all git commit messages (filetype `gitcommit`): |
||||
|
||||
```viml |
||||
au FileType gitcommit let b:EditorConfig_disable = 1 |
||||
``` |
||||
|
||||
### Disable rules |
||||
|
||||
In very rare cases, |
||||
you might need to override some project-specific EditorConfig rules in global |
||||
or local vimrc in some cases, e.g., to resolve conflicts of trailing whitespace |
||||
trimming and buffer autosaving. This is not recommended, but you can: |
||||
|
||||
```viml |
||||
let g:EditorConfig_disable_rules = ['trim_trailing_whitespace'] |
||||
``` |
||||
|
||||
You are able to disable any supported EditorConfig properties. |
||||
|
||||
## Bugs and Feature Requests |
||||
|
||||
Feel free to submit bugs, feature requests, and other issues to the |
||||
[issue tracker][]. Be sure you have read the [contribution guidelines][]! |
||||
|
||||
[EditorConfig]: http://editorconfig.org |
||||
[GitHub]: https://github.com/editorconfig/editorconfig-vim |
||||
[PreserveNoEOL]: http://www.vim.org/scripts/script.php?script_id=4550 |
||||
[Tim Pope's fugitive]: https://github.com/tpope/vim-fugitive |
||||
[Vim online]: http://www.vim.org/scripts/script.php?script_id=3934 |
||||
[Vundle]: https://github.com/gmarik/Vundle.vim |
||||
[archive]: https://github.com/editorconfig/editorconfig-vim/archive/master.zip |
||||
[contribution guidelines]: https://github.com/editorconfig/editorconfig/blob/master/CONTRIBUTING.md#submitting-an-issue |
||||
[issue tracker]: https://github.com/editorconfig/editorconfig-vim/issues |
||||
[pathogen]: https://github.com/tpope/vim-pathogen |
||||
[properties]: http://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties |
||||
[editorconfig.txt]: https://github.com/editorconfig/editorconfig-vim/blob/master/doc/editorconfig.txt |
||||
[vim-plug]: https://github.com/junegunn/vim-plug |
@ -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') . '/' |
||||