Squashed 'vim/bundle/editorconfig/' content from commit ecad8314b

git-subtree-dir: vim/bundle/editorconfig
git-subtree-split: ecad8314ba132eec46f28f22ff6c120c0b96596f
Buddy Sandidge 8 years ago
commit b0ebc43029

@ -0,0 +1,24 @@
root = true
[*]
end_of_line = LF
charset = utf-8
max_line_length = 80
[*.vim]
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

1
.gitignore vendored

@ -0,0 +1 @@
tags

3
.gitmodules vendored

@ -0,0 +1,3 @@
[submodule "tests/spec/plugin_tests"]
path = tests/spec/plugin_tests
url = https://github.com/editorconfig/editorconfig-plugin-tests.git

@ -0,0 +1,23 @@
language: ruby
rvm:
- 2.2.4
gemfile: tests/Gemfile
addons:
apt:
packages:
- vim-gtk
before_script:
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
script:
bundle exec rspec tests/spec/editorconfig_spec.rb
notifications:
email:
on_success: change
on_failure: always

@ -0,0 +1,5 @@
Contributors to the EditorConfig Vim Plugin:
Hong Xu
Trey Hunner
Kent Frazier

@ -0,0 +1,26 @@
Unless otherwise stated, all files are distributed under the Simplified BSD
license included below.
Copyright (c) 2011-2012 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,97 @@
# EditorConfig Vim Plugin
[![Build Status](https://travis-ci.org/editorconfig/editorconfig-vim.svg?branch=master)](https://travis-ci.org/editorconfig/editorconfig-vim)
This is an [EditorConfig][] plugin for Vim. This plugin could be found on both
[GitHub][] and [Vim online][].
## Installation
If your Vim is not compiled with `+python` feature (You can verify if the
`+python` feature is included by running `:ver`. Most Linux distributions and
with the official Windows binary have the `+python` feature enabled), please
first download the [EditorConfig core][] and follow the instructions in the
README and INSTALL files to install it. This plugin would NOT work if neither
`+python` nor EditorConfig core is available.
To install this plugin, you can use one of the following ways:
- 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".
OR
- Use [pathogen][] (the git repository of this plugin is
https://github.com/editorconfig/editorconfig-vim.git)
OR
- Use [Vundle][] by adding to your `.vimrc` Vundle plugins section:
Plugin 'editorconfig/editorconfig-vim'
Then remember to call `:PluginInstall`.
## 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)
## Recommended Options
All of the options which are supported 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:
> let g:EditorConfig_exclude_patterns = ['fugitive://.\*']
If you wanted to avoid loading EditorConfig for any remote files over ssh:
> let g:EditorConfig_exclude_patterns = ['scp://.\*']
Of course these two items could be combined into the following:
> let g:EditorConfig_exclude_patterns = ['fugitive://.\*', 'scp://.\*']
#### Exec Path
The file path to the EditorConfig core executable. You could set this value in
your |vimrc| like this:
> let g:EditorConfig_exec_path = 'Path to your EditorConfig Core executable'
## 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 guideline][]!
[EditorConfig core]: https://github.com/editorconfig/editorconfig-core
[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 guideline]: 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

@ -0,0 +1,59 @@
" Copyright (c) 2011-2012 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) " {{{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,222 @@
*editorconfig.txt*
File: editorconfig.txt
Version: 0.3.3
Maintainer: EditorConfig Team <http://editorconfig.org>
Description: EditorConfig vim plugin
License:
Copyright (c) 2011-2015 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.
CONTENTS~
*editorconfig-contents*
----------------------------------------------------------------------------
1. Overview |editorconfig-overview|
2. Installation |editorconfig-installation|
3. Commands |editorconfig-commands|
4. Settings |editorconfig-settings|
5. Advanced |editorconfig-advanced|
OVERVIEW~
*editorconfig-overview*
----------------------------------------------------------------------------
This is the EditorConfig plugin for vim.
INSTALLATION~
*editorconfig-installation*
----------------------------------------------------------------------------
Download the [EditorConfig core][] and follow the instructions in the README
and INSTALL files to install it.
Once EditorConfig core is installed, copy the `plugin/editorconfig.vim` file
to your `~/.vim/plugin` directory, `autoload/editorconfig.vim` to
`~/.vim/autoload` and `doc/editorconfig.txt` to your `~/.vim/doc` directory
to install the EditorConfig plugin.
COMMANDS~
*editorconfig-commands*
----------------------------------------------------------------------------
*:EditorConfigReload*
Command:
:EditorConfigReload
Reload the EditorConfig conf files. When `.editorconfig` files are modified,
this command could prevent you to reload the current edited file to load the
new configuration.
SETTINGS~
*editorconfig-settings*
----------------------------------------------------------------------------
*g:EditorConfig_core_mode*
Specify the mode of EditorConfig core. Generally it is OK to leave this option
empty. There are 3 modes currently: "external_command", "python_builtin",
"python_external".
python_builtin: Use the vim built-in python to run the python version
EditorConfig Core. In this mode, Python 2.5 or higher
is required.
python_external: Use an external python interpreter to run the python
version EditorConfig Core.
external_command: Run external EditorConfig Core.
If "g:EditorConfig_core_mode" is not specified, this plugin will automatically
choose a mode that could work for you. The checking sequence is:
python_builtin, external_command, python_external.
*g:EditorConfig_exclude_patterns*
This is a list contains file path patterns which will be ignored by
EditorConfig plugin. When the path of the opened buffer (i.e.
"expand('%:p')") matches any of the patterns in the list, EditorConfig will
not load for this file. The default is an empty list.
Example: Avoid loading EditorConfig for any remote files over ssh
>
let g:EditorConfig_exclude_patterns = ['scp://.*']
<
*g:EditorConfig_exec_path*
The file path to the EditorConfig core executable. You could set this value in
your |vimrc| like this:
>
let g:EditorConfig_exec_path = 'Path to your EditorConfig Core executable'
<
The default value is empty.
This plugin will search through the following executables in order:
On UNIX:
the value of g:EditorConfig_exec_path
editorconfig
/usr/local/bin/editorconfig
/usr/bin/editorconfig
/opt/bin/editorconfig
/opt/editorconfig/bin/editorconfig
editorconfig.py
/usr/local/bin/editorconfig.py
/usr/bin/editorconfig.py
/opt/bin/editorconfig.py
/opt/editorconfig/bin/editorconfig.py
On Windows:
the value of g:EditorConfig_exec_path
editorconfig
C:\editorconfig\bin\editorconfig
D:\editorconfig\bin\editorconfig
E:\editorconfig\bin\editorconfig
F:\editorconfig\bin\editorconfig
C:\Program Files\editorconfig\bin\editorconfig
D:\Program Files\editorconfig\bin\editorconfig
E:\Program Files\editorconfig\bin\editorconfig
F:\Program Files\editorconfig\bin\editorconfig
editorconfig.py
*g:EditorConfig_max_line_indicator*
The way to show the line where the maximal length is reached. Accepted values
are "line", "fill", otherwise there will be no max line indicator.
"line": the right column of the max line length column will be
highlighted, made possible by setting 'colorcolumn' to
"max_line_length + 1".
"fill": all the columns to the right of the max line length column will be
highlighted, made possible by setting 'colorcolumn' to a list of
numbers starting from "max_line_length + 1" to the number of
columns on the screen.
"none": no max line length indicator will be shown. This is the
recommended value when you do not want any indicator to be shown,
but values other than "line" or "fill" would also work as "none".
To set this option, add any of the following 3 lines to your |vimrc| file:
>
let g:EditorConfig_max_line_indicator = "line"
let g:EditorConfig_max_line_indicator = "fill"
let g:EditorConfig_max_line_indicator = "none"
<
Default to "line".
*g:EditorConfig_python_files_dir*
If the EditorConfig core mode is python_builtin or python_external (see
|g:EditorConfig_core_mode|), this variable is the directory where the plugin
looks for the python scripts. This could either be an abosolute path, or a
path relative to any of the directories in 'runtimepath'. The default value is
"plugin/editorconfig-core-py", which means all "plugin/editorconfig-core-py"
directory in 'runtimepath' will be searched.
*g:EditorConfig_preserve_formatoptions*
Set this to 1 if you don't want your formatoptions modified when
max_line_length is set:
>
let g:EditorConfig_preserve_formatoptions = 1
<
This option defaults to 0.
*g:EditorConfig_verbose*
Set this to 1 if you want debug info printed:
>
let g:EditorConfig_verbose = 1
<
ADVANCED~
*editorconfig-advanced*
----------------------------------------------------------------------------
*editorconfig-hook*
*EditorConfig#AddNewHook()*
While this plugin offers several builtin supported properties (as mentioned
here: https://github.com/editorconfig/editorconfig-vim#supported-properties),
we are also able to add our own hooks to support additional EditorConfig
properties, including those not in the EditorConfig standard. For example, we
are working on an Objective-C project, and all our "*.m" files should be
Objective-C source files. However, vim sometimes detect "*.m" files as MATLAB
source files, which causes incorrect syntax highlighting, code indentation,
etc. To solve the case, we could write the following code into the |vimrc|
file:
>
function! FiletypeHook(config)
if has_key(a:config, 'vim_filetype')
let &filetype = a:config['vim_filetype']
endif
return 0 " Return 0 to show no error happened
endfunction
call editorconfig#AddNewHook(function('FiletypeHook'))
<
And add the following code to your .editorconfig file:
>
[*.m]
vim_filetype = objc
<
Then try to open an Objective-C file, you will find the |filetype| is set to
"objc".
vim:ft=help:tw=78

@ -0,0 +1,3 @@
#!/bin/sh
zip -r editorconfig-vim-$*.zip plugin/editorconfig.vim plugin/editorconfig.py plugin/editorconfig-core-py/* doc/editorconfig.txt autoload/*.vim

@ -0,0 +1,12 @@
root = true
[*.{py,rst,txt}]
indent_style = space
trim_trailing_whitespace = true
indent_size = 4
end_of_line = LF
[*.yml]
indent_style = space
indent_size = 2
end_of_line = LF

@ -0,0 +1,11 @@
*.py[co]
*\$py.class
*.egg-info
dist
build
/Testing
/Makefile
/tests/Makefile
*.cmake
CMakeFiles
CMakeCache.txt

@ -0,0 +1,22 @@
language: python
python:
- "2.6"
- "2.7"
- "3.2"
- "3.3"
- "3.4"
- "pypy"
install:
- sudo apt-get install cmake
# test script
script:
- ctest -VV --output-on-failure .
# Notify the mailing list
notifications:
email:
on_success: change
on_failure: always

@ -0,0 +1,21 @@
# This file is used for testing only
# To perform the test, run `cmake .` at the root of the project tree followed
# by ctest .
cmake_minimum_required(VERSION 2.6)
# Do not check any compiler
project(editorconfig-core-py NONE)
find_package(PythonInterp)
if(NOT PYTHONINTERP_FOUND)
message(FETAL_ERROR
"Python interpreter is not found. If you have python installed, please run:
cmake -DPYTHON_EXECUTABLE=/path/to/python .")
endif()
enable_testing()
set(EDITORCONFIG_CMD ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/main.py)
add_subdirectory(tests)

@ -0,0 +1,192 @@
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
--------------------------------------------
1. This LICENSE AGREEMENT is between the Python Software Foundation
("PSF"), and the Individual or Organization ("Licensee") accessing and
otherwise using this software ("Python") 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 alone or in any derivative version,
provided, however, that PSF's License Agreement and PSF's notice of copyright,
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Python Software Foundation; All Rights Reserved" are retained in Python 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 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.
4. PSF is making Python 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 WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
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, Licensee
agrees to be bound by the terms and conditions of this License
Agreement.
BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
-------------------------------------------
BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
Individual or Organization ("Licensee") accessing and otherwise using
this software in source or binary form and its associated
documentation ("the Software").
2. Subject to the terms and conditions of this BeOpen Python License
Agreement, BeOpen hereby grants Licensee a non-exclusive,
royalty-free, world-wide license to reproduce, analyze, test, perform
and/or display publicly, prepare derivative works, distribute, and
otherwise use the Software alone or in any derivative version,
provided, however, that the BeOpen Python License is retained in the
Software, alone or in any derivative version prepared by Licensee.
3. BeOpen is making the Software available to Licensee on an "AS IS"
basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.
4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
5. This License Agreement will automatically terminate upon a material
breach of its terms and conditions.
6. This License Agreement shall be governed by and interpreted in all
respects by the law of the State of California, excluding conflict of
law provisions. Nothing in this License Agreement shall be deemed to
create any relationship of agency, partnership, or joint venture
between BeOpen and Licensee. This License Agreement does not grant
permission to use BeOpen trademarks or trade names in a trademark
sense to endorse or promote products or services of Licensee, or any
third party. As an exception, the "BeOpen Python" logos available at
http://www.pythonlabs.com/logos.html may be used according to the
permissions granted on that web page.
7. By copying, installing or otherwise using the software, Licensee
agrees to be bound by the terms and conditions of this License
Agreement.
CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
---------------------------------------
1. This LICENSE AGREEMENT is between the Corporation for National
Research Initiatives, having an office at 1895 Preston White Drive,
Reston, VA 20191 ("CNRI"), and the Individual or Organization
("Licensee") accessing and otherwise using Python 1.6.1 software in
source or binary form and its associated documentation.
2. Subject to the terms and conditions of this License Agreement, CNRI
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 1.6.1
alone or in any derivative version, provided, however, that CNRI's
License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
1995-2001 Corporation for National Research Initiatives; All Rights
Reserved" are retained in Python 1.6.1 alone or in any derivative
version prepared by Licensee. Alternately, in lieu of CNRI's License
Agreement, Licensee may substitute the following text (omitting the
quotes): "Python 1.6.1 is made available subject to the terms and
conditions in CNRI's License Agreement. This Agreement together with
Python 1.6.1 may be located on the Internet using the following
unique, persistent identifier (known as a handle): 1895.22/1013. This
Agreement may also be obtained from a proxy server on the Internet
using the following URL: http://hdl.handle.net/1895.22/1013".
3. In the event Licensee prepares a derivative work that is based on
or incorporates Python 1.6.1 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 1.6.1.
4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.
5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
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. This License Agreement shall be governed by the federal
intellectual property law of the United States, including without
limitation the federal copyright law, and, to the extent such
U.S. federal law does not apply, by the law of the Commonwealth of
Virginia, excluding Virginia's conflict of law provisions.
Notwithstanding the foregoing, with regard to derivative works based
on Python 1.6.1 that incorporate non-separable material that was
previously distributed under the GNU General Public License (GPL), the
law of the Commonwealth of Virginia shall govern this License
Agreement only as to issues arising under or with respect to
Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
License Agreement shall be deemed to create any relationship of
agency, partnership, or joint venture between CNRI and Licensee. This
License Agreement does not grant permission to use CNRI trademarks or
trade name in a trademark sense to endorse or promote products or
services of Licensee, or any third party.
8. By clicking on the "ACCEPT" button where indicated, or by copying,
installing or otherwise using Python 1.6.1, Licensee agrees to be
bound by the terms and conditions of this License Agreement.
ACCEPT
CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
--------------------------------------------------
Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
The Netherlands. All rights reserved.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Stichting Mathematisch
Centrum or CWI not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

@ -0,0 +1 @@
include README.rst LICENSE.txt

@ -0,0 +1,82 @@
========================
EditorConfig Python Core
========================
.. image:: https://secure.travis-ci.org/editorconfig/editorconfig-core-py.png?branch=master
:target: http://travis-ci.org/editorconfig/editorconfig-core-py
EditorConfig Python Core provides the same functionality as the
`EditorConfig C Core <https://github.com/editorconfig/editorconfig-core>`_.
EditorConfig Python core can be used as a command line program or as an
importable library.
EditorConfig Project
====================
EditorConfig makes it easy to maintain the correct coding style when switching
between different text editors and between different projects. The
EditorConfig project maintains a file format and plugins for various text
editors which allow this file format to be read and used by those editors. For
information on the file format and supported text editors, see the
`EditorConfig website <http://editorconfig.org>`_.
Installation
============
With setuptools::
sudo python setup.py install
Getting Help
============
For help with the EditorConfig core code, please write to our `mailing list
<http://groups.google.com/group/editorconfig>`_. Bugs and feature requests
should be submitted to our `issue tracker
<https://github.com/editorconfig/editorconfig/issues>`_.
If you are writing a plugin a language that can import Python libraries, you
may want to import and use the EditorConfig Python Core directly.
Using as a Library
==================
Basic example use of EditorConfig Python Core as a library:
.. code-block:: python
from editorconfig import get_properties, EditorConfigError
filename = "/home/zoidberg/humans/anatomy.md"
try:
options = get_properties(filename)
except EditorConfigError:
print "Error occurred while getting EditorConfig properties"
else:
for key, value in options.items():
print "%s=%s" % (key, value)
For details, please take a look at the `online documentation
<http://pydocs.editorconfig.org>`_.
Running Test Cases
==================
`Cmake <http://www.cmake.org>`_ has to be installed first. Run the test cases
using the following commands::
cmake .
ctest .
Use ``-DPYTHON_EXECUTABLE`` to run the tests using an alternative versions of
Python (e.g. Python 3)::
cmake -DPYTHON_EXECUTABLE=/usr/bin/python3 .
ctest .
License
=======
Unless otherwise stated, all files are distributed under the PSF license. The
odict library (editorconfig/odict.py) is distributed under the New BSD license.
See LICENSE.txt file for details on PSF license.

@ -0,0 +1,130 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/EditorConfigPythonCore.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/EditorConfigPythonCore.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/EditorConfigPythonCore"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/EditorConfigPythonCore"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

@ -0,0 +1,18 @@
==================
Command Line Usage
==================
The EditorConfig Python Core can be used from the command line in the same way
as the EditorConfig C Core.
Discovering EditorConfig properties
-----------------------------------
Installing EditorConfig Python Core should add an ``editorconfig.py`` command
to your path. This command can be used to locate and parse EditorConfig files
for a given full filepath. For example::
editorconfig.py /home/zoidberg/humans/anatomy.md
When used to retrieve EditorConfig file properties, ``editorconfig.py`` will
return discovered properties in *key=value* pairs, one on each line.

@ -0,0 +1,219 @@
# -*- coding: utf-8 -*-
#
# EditorConfig Python Core documentation build configuration file, created by
# sphinx-quickstart on Sat May 5 09:51:42 2012.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('..'))
import editorconfig
from editorconfig import __version__
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'EditorConfig Python Core'
copyright = u'2012, EditorConfig Team'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = __version__
# The full version, including alpha/beta/rc tags.
release = __version__
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'agogo'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'EditorConfigPythonCoredoc'
# -- Options for LaTeX output --------------------------------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'EditorConfigPythonCore.tex', u'EditorConfig Python Core Documentation',
u'EditorConfig Team', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'editorconfigpythoncore', u'EditorConfig Python Core Documentation',
[u'EditorConfig Team'], 1)
]

@ -0,0 +1,23 @@
==================================================================
EditorConfig Python Core -- Process EditorConfig Files With Python
==================================================================
EditorConfig is a file format for defining file-specific coding styles and a
set of plugins that allow text editors and IDEs to read this file format. For
more information on the EditorConfig project visit the
`EditorConfig Homepage`_.
The EditorConfig Python Core is a Python package for locating and parsing
EditorConfig files. This package can be used as an import by other Python code
or as a stand-alone command line program.
.. _`EditorConfig Homepage`: http://editorconfig.org
Contents:
.. toctree::
:maxdepth: 1
usage
command_line_usage
plugins

@ -0,0 +1,170 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\EditorConfigPythonCore.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\EditorConfigPythonCore.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end

@ -0,0 +1,72 @@
===============
Writing Plugins
===============
The EditorConfig Python Core can be easily used by text editor plugins written in Python or plugins that can call an external Python interpreter. The EditorConfig Python Core supports Python versions 2.2 to 2.7. Check out the `Vim`_ and `Gedit`_ plugins for example usages of the EditorConfig Python Core.
.. _`Vim`: https://github.com/editorconfig/editorconfig-vim
.. _`Gedit`: https://github.com/editorconfig/editorconfig-gedit
Use as a library
----------------
For instructions on using the EditorConfig Python Core as a Python library see :doc:`usage`.
Using with an external Python interpreter
-----------------------------------------
The EditorConfig Python Core can be used with an external Python interpreter by executing the ``main.py`` file. The ``main.py`` file can be executed like so::
python editorconfig-core-py/main.py /home/zoidberg/humans/anatomy.md
For more information on command line usage of the EditorConfig Python Core see :doc:`command_line_usage`.
Bundling EditorConfig Python Core with Plugin
---------------------------------------------
A text editor or IDE plugin will either need to bundle the EditorConfig Python
Core with the plugin installation package or the will need to assist the user
in installing the EditorConfig Python Core. Below are instructions for
bundling the EditorConfig Python Core with plugins.
Bundling as a Submodule in Git
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Git submodules allow one repository to be included inside another. A submodule
stores a remote repositry and commit to use for fetching the embedded
repository. Submodules take up very little space in the repository since they
do not actually include the code of the embedded repository directly.
To add EditorConfig Python Core as a submodule in the ``editorconfig-core-py``
directory of your repository::
git submodule add git://github.com/editorconfig/editorconfig-core-py.git editorconfig-core-py
Then every time the code is checked out the submodule directory should be
initialized and updated::
git submodule update --init
Bundling as a Subtree in Git
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Git subtrees are convenient because, unlike submodules, they do not require any
extra work to be performed when cloning the git repository. Git subtrees
include one git codebase as a subdirectory of another.
Example of using a subtree for the ``editorconfig`` directory from the
EditorConfig Python Core repository::
git remote add -f editorconfig-core-py git://github.com/editorconfig/editorconfig-core-py.git
git merge -s ours --no-commit editorconfig-core-py/master
git read-tree --prefix=editorconfig -u editorconfig-core-py/master:editorconfig
git commit
For more information on subtrees consult the `subtree merge guide`_ on Github
and `Chapter 6.7`_ in the book Pro Git.
.. _`subtree merge guide`: http://help.github.com/subtree-merge/
.. _`Chapter 6.7`: http://git-scm.com/book/ch6-7.html

@ -0,0 +1,84 @@
=====
Usage
=====
Installation
------------
First you will need to install the EditorConfig Python Core package.
To install from PyPI using pip::
pip install editorconfig
Discovering EditorConfig properties
-----------------------------------
The ``get_properties`` function can be used to discover EditorConfig properties
for a given file. Example:
.. code-block:: python
import logging
from editorconfig import get_properties, EditorConfigError
filename = "/home/zoidberg/humans/anatomy.md"
try:
options = get_properties(filename)
except EditorConfigError:
logging.warning("Error getting EditorConfig properties", exc_info=True)
else:
for key, value in options.items():
print "%s=%s" % (key, value)
The ``get_properties`` method returns a dictionary representing EditorConfig
properties found for the given file. If an error occurs while parsing a file
an exception will be raised. All raised exceptions will inherit from the
``EditorConfigError`` class.
Handling Exceptions
-------------------
All exceptions raised by EditorConfig will subclass ``EditorConfigError``. To
handle certain exceptions specially, catch them first. More exception classes
may be added in the future so it is advisable to always handle general
``EditorConfigError`` exceptions in case a future version raises an exception
that your code does not handle specifically.
Exceptions module reference
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Exceptions can be found in the ``editorconfig.exceptions`` module. These are
the current exception types:
.. autoexception:: editorconfig.exceptions.EditorConfigError
.. autoexception:: editorconfig.exceptions.ParsingError
.. autoexception:: editorconfig.exceptions.PathError
.. autoexception:: editorconfig.exceptions.VersionError
Exception handling example
~~~~~~~~~~~~~~~~~~~~~~~~~~
An example of custom exception handling:
.. code-block:: python
import logging
from editorconfig import get_properties
from editorconfig import exceptions
filename = "/home/zoidberg/myfile.txt"
try:
options = get_properties(filename)
except exceptions.ParsingError:
logging.warning("Error parsing an .editorconfig file", exc_info=True)
except exceptions.PathError:
logging.error("Invalid filename specified", exc_info=True)
except exceptions.EditorConfigError:
logging.error("An unknown EditorConfig error occurred", exc_info=True)
for key, value in options.iteritems():
print "%s=%s" % (key, value)

@ -0,0 +1,19 @@
"""EditorConfig Python Core"""
from editorconfig.versiontools import join_version
VERSION = (0, 12, 0, "final")
__all__ = ['get_properties', 'EditorConfigError', 'exceptions']
__version__ = join_version(VERSION)
def get_properties(filename):
"""Locate and parse EditorConfig files for the given filename"""
handler = EditorConfigHandler(filename)
return handler.get_configurations()
from editorconfig.handler import EditorConfigHandler
from editorconfig.exceptions import *

@ -0,0 +1,23 @@
"""EditorConfig Python2/Python3 compatibility utilities"""
import sys
__all__ = ['force_unicode', 'u']
if sys.version_info[0] == 2:
text_type = unicode
else:
text_type = str
def force_unicode(string):
if not isinstance(string, text_type):
string = text_type(string, encoding='utf-8')
return string
if sys.version_info[0] == 2:
import codecs
u = lambda s: codecs.unicode_escape_decode(s)[0]
else:
u = lambda s: s

@ -0,0 +1,27 @@
"""EditorConfig exception classes
Licensed under PSF License (see LICENSE.txt file).
"""
class EditorConfigError(Exception):
"""Parent class of all exceptions raised by EditorConfig"""
try:
from ConfigParser import ParsingError as _ParsingError
except:
from configparser import ParsingError as _ParsingError
class ParsingError(_ParsingError, EditorConfigError):
"""Error raised if an EditorConfig file could not be parsed"""
class PathError(ValueError, EditorConfigError):
"""Error raised if invalid filepath is specified"""
class VersionError(ValueError, EditorConfigError):
"""Error raised if invalid version number is specified"""

@ -0,0 +1,219 @@
"""Filename matching with shell patterns.
fnmatch(FILENAME, PATTERN) matches according to the local convention.
fnmatchcase(FILENAME, 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.)
Based on code from fnmatch.py file distributed with Python 2.6.
Licensed under PSF License (see LICENSE.txt file).
Changes to original fnmatch module:
- translate function supports ``*`` and ``**`` similarly to fnmatch C library
"""
import os
import re
__all__ = ["fnmatch", "fnmatchcase", "translate"]
_cache = {}
LEFT_BRACE = re.compile(
r"""
(?: ^ | [^\\] ) # Beginning of string or a character besides "\"
\{ # "{"
""", re.VERBOSE
)
RIGHT_BRACE = re.compile(
r"""
(?: ^ | [^\\] ) # Beginning of string or a character besides "\"
\} # "}"
""", re.VERBOSE
)
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
)
def fnmatch(name, pat):
"""Test whether FILENAME matches 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).
"""
name = os.path.normpath(name).replace(os.sep, "/")
return fnmatchcase(name, pat)
def cached_translate(pat):
if not pat in _cache:
res, num_groups = translate(pat)
regex = re.compile(res)
_cache[pat] = regex, num_groups
return _cache[pat]
def fnmatchcase(name, pat):
"""Test whether FILENAME matches PATTERN, including case.
This is a version of fnmatch() which doesn't case-normalize
its arguments.
"""
regex, num_groups = cached_translate(pat)
match = regex.match(name)
if not match:
return False
pattern_matched = True
for (num, (min_num, max_num)) in zip(match.groups(), num_groups):
if num[0] == '0' or not (min_num <= int(num) <= max_num):
pattern_matched = False
break
return pattern_matched
def translate(pat, nested=False):
"""Translate a shell PATTERN to a regular expression.
There is no way to quote meta-characters.
"""
index, length = 0, len(pat) # Current index and length of pattern
brace_level = 0
in_brackets = False
result = ''
is_escaped = False
matching_braces = (len(LEFT_BRACE.findall(pat)) ==
len(RIGHT_BRACE.findall(pat)))
numeric_groups = []
while index < length:
current_char = pat[index]
index += 1
if current_char == '*':
pos = index
if pos < length and pat[pos] == '*':
result += '.*'
else:
result += '[^/]*'
elif current_char == '?':
result += '.'
elif current_char == '[':
if in_brackets:
result += '\\['
else:
pos = index
has_slash = False
while pos < length and pat[pos] != ']':
if pat[pos] == '/' and pat[pos-1] != '\\':
has_slash = True
break
pos += 1
if has_slash:
result += '\\[' + pat[index:(pos + 1)] + '\\]'
index = pos + 2
else:
if index < length and pat[index] in '!^':
index += 1
result += '[^'
else:
result += '['
in_brackets = True
elif current_char == '-':
if in_brackets:
result += current_char
else:
result += '\\' + current_char
elif current_char == ']':
result += current_char
in_brackets = False
elif current_char == '{':
pos = index
has_comma = False
while pos < length and (pat[pos] != '}' or is_escaped):
if pat[pos] == ',' and not is_escaped:
has_comma = True
break
is_escaped = pat[pos] == '\\' and not is_escaped
pos += 1
if not has_comma and pos < length:
num_range = NUMERIC_RANGE.match(pat[index:pos])
if num_range:
numeric_groups.append(map(int, num_range.groups()))
result += "([+-]?\d+)"
else:
inner_result, inner_groups = translate(pat[index:pos],
nested=True)
result += '\\{%s\\}' % (inner_result,)
numeric_groups += inner_groups
index = pos + 1
elif matching_braces:
result += '(?:'
brace_level += 1
else:
result += '\\{'
elif current_char == ',':
if brace_level > 0 and not is_escaped:
result += '|'
else:
result += '\\,'
elif current_char == '}':
if brace_level > 0 and not is_escaped:
result += ')'
brace_level -= 1
else:
result += '\\}'
elif current_char == '/':
if pat[index:(index + 3)] == "**/":
result += "(?:/|/.*/)"
index += 3
else:
result += '/'
elif current_char != '\\':
result += re.escape(current_char)
if current_char == '\\':
if is_escaped:
result += re.escape(current_char)
is_escaped = not is_escaped
else:
is_escaped = False
if not nested:
result += '\Z(?ms)'
return result, numeric_groups

@ -0,0 +1,127 @@
"""EditorConfig file handler
Provides ``EditorConfigHandler`` class for locating and parsing
EditorConfig files relevant to a given filepath.
Licensed under PSF License (see LICENSE.txt file).
"""
import os
from editorconfig import VERSION
from editorconfig.ini import EditorConfigParser
from editorconfig.exceptions import PathError, VersionError
__all__ = ['EditorConfigHandler']
def get_filenames(path, filename):
"""Yield full filepath for filename in each directory in and above path"""
path_list = []
while True:
path_list.append(os.path.join(path, filename))
newpath = os.path.dirname(path)
if path == newpath:
break
path = newpath
return path_list
class EditorConfigHandler(object):
"""
Allows locating and parsing of EditorConfig files for given filename
In addition to the constructor a single public method is provided,
``get_configurations`` which returns the EditorConfig options for
the ``filepath`` specified to the constructor.
"""
def __init__(self, filepath, conf_filename='.editorconfig',
version=VERSION):
"""Create EditorConfigHandler for matching given filepath"""
self.filepath = filepath
self.conf_filename = conf_filename
self.version = version
self.options = None
def get_configurations(self):
"""
Find EditorConfig files and return all options matching filepath
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
"""
self.check_assertions()
path, filename = os.path.split(self.filepath)
conf_files = get_filenames(path, self.conf_filename)
# Attempt to find and parse every EditorConfig file in filetree
for filename in conf_files:
parser = EditorConfigParser(self.filepath)
parser.read(filename)
# Merge new EditorConfig file's options into current options
old_options = self.options
self.options = parser.options
if old_options:
self.options.update(old_options)
# Stop parsing if parsed file has a ``root = true`` option
if parser.root_file:
break
self.preprocess_values()
return self.options
def check_assertions(self):
"""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.")
# Raise ``VersionError`` if version specified is greater than current
if self.version is not None and self.version[:3] > VERSION[:3]:
raise VersionError(
"Required version is greater than the current version.")
def preprocess_values(self):
"""Preprocess option values for consumption by plugins"""
opts = self.options
# Lowercase option value for certain options
for name in ["end_of_line", "indent_style", "indent_size",
"insert_final_newline", "trim_trailing_whitespace",
"charset"]:
if name in opts:
opts[name] = opts[name].lower()
# Set indent_size to "tab" if indent_size is unspecified and
# indent_style is set to "tab".
if (opts.get("indent_style") == "tab" and
not "indent_size" in opts and self.version >= (0, 10, 0)):
opts["indent_size"] = "tab"
# Set tab_width to indent_size if indent_size is specified and
# tab_width is unspecified
if ("indent_size" in opts and "tab_width" not in opts and
opts["indent_size"] != "tab"):
opts["tab_width"] = opts["indent_size"]
# Set indent_size to tab_width if indent_size is "tab"
if ("indent_size" in opts and "tab_width" in opts and
opts["indent_size"] == "tab"):
opts["indent_size"] = opts["tab_width"]

@ -0,0 +1,174 @@
"""EditorConfig file parser
Based on code from ConfigParser.py file distributed with Python 2.6.
Licensed under PSF License (see LICENSE.txt 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
"""
import re
from codecs import open
import posixpath
from os import sep
from os.path import normpath, dirname
from editorconfig.exceptions import ParsingError
from editorconfig.fnmatch import fnmatch
from editorconfig.odict import OrderedDict
from editorconfig.compat import u
__all__ = ["ParsingError", "EditorConfigParser"]
class EditorConfigParser(object):
"""Parser for EditorConfig-style configuration files
Based on RawConfigParser from ConfigParser.py in Python 2.6.
"""
# Regular expressions for parsing section headers and options.
# Allow ``]`` and escaped ``;`` and ``#`` characters in section headers
SECTCRE = re.compile(
r"""
\s * # Optional whitespace
\[ # Opening square brace
(?P<header> # One or more characters excluding
( [^\#;] | \\\# | \\; ) + # unescaped # and ; characters
)
\] # Closing square brace
""", re.VERBOSE
)
# 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
OPTCRE = re.compile(
r"""
\s * # Optional whitespace
(?P<option> # One or more characters excluding
[^:=\s] # : a = characters (and first
[^:=] * # must not be whitespace)
)
\s * # Optional whitespace
(?P<vi>
[:=] # Single = or : character
)
\s * # Optional whitespace
(?P<value>
. * # One or more characters
)
$
""", re.VERBOSE
)
def __init__(self, filename):
self.filename = filename
self.options = OrderedDict()
self.root_file = False
def matches_filename(self, config_filename, glob):
"""Return True if section glob matches filename"""
config_dirname = normpath(dirname(config_filename)).replace(sep, '/')
glob = glob.replace("\\#", "#")
glob = glob.replace("\\;", ";")
if '/' in glob:
if glob.find('/') == 0:
glob = glob[1:]
glob = posixpath.join(config_dirname, glob)
else:
glob = posixpath.join('**/', glob)
return fnmatch(self.filename, glob)
def read(self, filename):
"""Read and parse single EditorConfig file"""
try:
fp = open(filename, encoding='utf-8')
except IOError:
return
self._read(fp, filename)
fp.close()
def _read(self, fp, fpname):
"""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.
"""
in_section = False
matching_section = False
optname = None
lineno = 0
e = None # None, or an exception
while True:
line = fp.readline()
if not line:
break
if lineno == 0 and line.startswith(u('\ufeff')):
line = line[1:] # Strip UTF-8 BOM
lineno = lineno + 1
# comment or blank line?
if line.strip() == '' or line[0] in '#;':
continue
# a section header or option header?
else:
# is it a section header?
mo = self.SECTCRE.match(line)
if mo:
sectname = mo.group('header')
in_section = True
matching_section = self.matches_filename(fpname, sectname)
# So sections can't start with a continuation line
optname = None
# an option line?
else:
mo = self.OPTCRE.match(line)
if mo:
optname, vi, optval = mo.group('option', 'vi', 'value')
if ';' in optval or '#' in optval:
# ';' and '#' are comment delimiters only if
# preceeded by a spacing character
m = re.search('(.*?) [;#]', optval)
if m:
optval = m.group(1)
optval = optval.strip()
# allow empty values
if optval == '""':
optval = ''
optname = self.optionxform(optname.rstrip())
if not in_section and optname == 'root':
self.root_file = (optval.lower() == 'true')
if matching_section:
self.options[optname] = optval
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
if not e:
e = ParsingError(fpname)
e.append(lineno, repr(line))
# if any parsing errors occurred, raise an exception
if e:
raise e
def optionxform(self, optionstr):
return optionstr.lower()

@ -0,0 +1,78 @@
"""EditorConfig command line interface
Licensed under PSF License (see LICENSE.txt file).
"""
import getopt
import sys
from editorconfig import __version__, VERSION
from editorconfig.compat import force_unicode
from editorconfig.versiontools import split_version
from editorconfig.handler import EditorConfigHandler
from editorconfig.exceptions import ParsingError, PathError, VersionError
def version():
print("EditorConfig Python Core Version %s" % __version__)
def usage(command, error=False):
if error:
out = sys.stderr
else:
out = sys.stdout
out.write("%s [OPTIONS] FILENAME\n" % command)
out.write('-f '
'Specify conf filename other than ".editorconfig".\n')
out.write("-b "
"Specify version (used by devs to test compatibility).\n")
out.write("-h OR --help Print this help message.\n")
out.write("-v OR --version Display version information.\n")
def main():
command_name = sys.argv[0]
try:
opts, args = getopt.getopt(list(map(force_unicode, sys.argv[1:])),
"vhb:f:", ["version", "help"])
except getopt.GetoptError as e:
print(str(e))
usage(command_name, error=True)
sys.exit(2)
version_tuple = VERSION
conf_filename = '.editorconfig'
for option, arg in opts:
if option in ('-h', '--help'):
usage(command_name)
sys.exit()
if option in ('-v', '--version'):
version()
sys.exit()
if option == '-f':
conf_filename = arg
if option == '-b':
version_tuple = split_version(arg)
if version_tuple is None:
sys.exit("Invalid version number: %s" % arg)
if len(args) < 1:
usage(command_name, error=True)
sys.exit(2)
filenames = args
multiple_files = len(args) > 1
for filename in filenames:
handler = EditorConfigHandler(filename, conf_filename, version_tuple)
try:
options = handler.get_configurations()
except (ParsingError, PathError, VersionError) as e:
print(str(e))
sys.exit(2)
if multiple_files:
print("[%s]" % filename)
for key, value in options.items():
print("%s=%s" % (key, value))

@ -0,0 +1,897 @@
"""odict.py: An Ordered Dictionary object"""
# Copyright (C) 2005 Nicola Larosa, Michael Foord
# E-mail: nico AT tekNico DOT net, fuzzyman AT voidspace DOT org DOT uk
# Copyright (c) 2003-2010, Michael Foord
# E-mail : fuzzyman AT voidspace DOT org DOT uk
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * 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.
#
# * Neither the name of Michael Foord nor the name of Voidspace
# may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# 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
# OWNER 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.
from __future__ import generators
import sys
import warnings
__docformat__ = "restructuredtext en"
__all__ = ['OrderedDict']
INTP_VER = sys.version_info[:2]
if INTP_VER < (2, 2):
raise RuntimeError("Python v.2.2 or later required")
class OrderedDict(dict):
"""
A class of dictionary that keeps the insertion order of keys.
All appropriate methods return keys, items, or values in an ordered way.
All normal dictionary methods are available. Update and comparison is
restricted to other OrderedDict objects.
Various sequence methods are available, including the ability to explicitly
mutate the key ordering.
__contains__ tests:
>>> d = OrderedDict(((1, 3),))
>>> 1 in d
1
>>> 4 in d
0
__getitem__ tests:
>>> OrderedDict(((1, 3), (3, 2), (2, 1)))[2]
1
>>> OrderedDict(((1, 3), (3, 2), (2, 1)))[4]
Traceback (most recent call last):
KeyError: 4
__len__ tests:
>>> len(OrderedDict())
0
>>> len(OrderedDict(((1, 3), (3, 2), (2, 1))))
3
get tests:
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.get(1)
3
>>> d.get(4) is None
1
>>> d.get(4, 5)
5
>>> d
OrderedDict([(1, 3), (3, 2), (2, 1)])
has_key tests:
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.has_key(1)
1
>>> d.has_key(4)
0
"""
def __init__(self, init_val=(), strict=False):
"""
Create a new ordered dictionary. Cannot init from a normal dict,
nor from kwargs, since items order is undefined in those cases.
If the ``strict`` keyword argument is ``True`` (``False`` is the
default) then when doing slice assignment - the ``OrderedDict`` you are
assigning from *must not* contain any keys in the remaining dict.
>>> OrderedDict()
OrderedDict([])
>>> OrderedDict({1: 1})
Traceback (most recent call last):
TypeError: undefined order, cannot get items from dict
>>> OrderedDict({1: 1}.items())
OrderedDict([(1, 1)])
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d
OrderedDict([(1, 3), (3, 2), (2, 1)])
>>> OrderedDict(d)
OrderedDict([(1, 3), (3, 2), (2, 1)])
"""
self.strict = strict
dict.__init__(self)
if isinstance(init_val, OrderedDict):
self._sequence = init_val.keys()
dict.update(self, init_val)
elif isinstance(init_val, dict):
# we lose compatibility with other ordered dict types this way
raise TypeError('undefined order, cannot get items from dict')
else:
self._sequence = []
self.update(init_val)
### Special methods ###
def __delitem__(self, key):
"""
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> del d[3]
>>> d
OrderedDict([(1, 3), (2, 1)])
>>> del d[3]
Traceback (most recent call last):
KeyError: 3
>>> d[3] = 2
>>> d
OrderedDict([(1, 3), (2, 1), (3, 2)])
>>> del d[0:1]
>>> d
OrderedDict([(2, 1), (3, 2)])
"""
if isinstance(key, slice):
# FIXME: efficiency?
keys = self._sequence[key]
for entry in keys:
dict.__delitem__(self, entry)
del self._sequence[key]
else:
# do the dict.__delitem__ *first* as it raises
# the more appropriate error
dict.__delitem__(self, key)
self._sequence.remove(key)
def __eq__(self, other):
"""
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d == OrderedDict(d)
True
>>> d == OrderedDict(((1, 3), (2, 1), (3, 2)))
False
>>> d == OrderedDict(((1, 0), (3, 2), (2, 1)))
False
>>> d == OrderedDict(((0, 3), (3, 2), (2, 1)))
False
>>> d == dict(d)
False
>>> d == False
False
"""
if isinstance(other, OrderedDict):
# FIXME: efficiency?
# Generate both item lists for each compare
return (self.items() == other.items())
else:
return False
def __lt__(self, other):
"""
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
>>> c < d
True
>>> d < c
False
>>> d < dict(c)
Traceback (most recent call last):
TypeError: Can only compare with other OrderedDicts
"""
if not isinstance(other, OrderedDict):
raise TypeError('Can only compare with other OrderedDicts')
# FIXME: efficiency?
# Generate both item lists for each compare
return (self.items() < other.items())
def __le__(self, other):
"""
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
>>> e = OrderedDict(d)
>>> c <= d
True
>>> d <= c
False
>>> d <= dict(c)
Traceback (most recent call last):
TypeError: Can only compare with other OrderedDicts
>>> d <= e
True
"""
if not isinstance(other, OrderedDict):
raise TypeError('Can only compare with other OrderedDicts')
# FIXME: efficiency?
# Generate both item lists for each compare
return (self.items() <= other.items())
def __ne__(self, other):
"""
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d != OrderedDict(d)
False
>>> d != OrderedDict(((1, 3), (2, 1), (3, 2)))
True
>>> d != OrderedDict(((1, 0), (3, 2), (2, 1)))
True
>>> d == OrderedDict(((0, 3), (3, 2), (2, 1)))
False
>>> d != dict(d)
True
>>> d != False
True
"""
if isinstance(other, OrderedDict):
# FIXME: efficiency?
# Generate both item lists for each compare
return not (self.items() == other.items())
else:
return True
def __gt__(self, other):
"""
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
>>> d > c
True
>>> c > d
False
>>> d > dict(c)
Traceback (most recent call last):
TypeError: Can only compare with other OrderedDicts
"""
if not isinstance(other, OrderedDict):
raise TypeError('Can only compare with other OrderedDicts')
# FIXME: efficiency?
# Generate both item lists for each compare
return (self.items() > other.items())
def __ge__(self, other):
"""
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
>>> e = OrderedDict(d)
>>> c >= d
False
>>> d >= c
True
>>> d >= dict(c)
Traceback (most recent call last):
TypeError: Can only compare with other OrderedDicts
>>> e >= d
True
"""
if not isinstance(other, OrderedDict):
raise TypeError('Can only compare with other OrderedDicts')
# FIXME: efficiency?
# Generate both item lists for each compare
return (self.items() >= other.items())
def __repr__(self):
"""
Used for __repr__ and __str__
>>> r1 = repr(OrderedDict((('a', 'b'), ('c', 'd'), ('e', 'f'))))
>>> r1
"OrderedDict([('a', 'b'), ('c', 'd'), ('e', 'f')])"
>>> r2 = repr(OrderedDict((('a', 'b'), ('e', 'f'), ('c', 'd'))))
>>> r2
"OrderedDict([('a', 'b'), ('e', 'f'), ('c', 'd')])"
>>> r1 == str(OrderedDict((('a', 'b'), ('c', 'd'), ('e', 'f'))))
True
>>> r2 == str(OrderedDict((('a', 'b'), ('e', 'f'), ('c', 'd'))))
True
"""
return '%s([%s])' % (self.__class__.__name__, ', '.join(
['(%r, %r)' % (key, self[key]) for key in self._sequence]))
def __setitem__(self, key, val):
"""
Allows slice assignment, so long as the slice is an OrderedDict
>>> d = OrderedDict()
>>> d['a'] = 'b'
>>> d['b'] = 'a'
>>> d[3] = 12
>>> d
OrderedDict([('a', 'b'), ('b', 'a'), (3, 12)])
>>> d[:] = OrderedDict(((1, 2), (2, 3), (3, 4)))
>>> d
OrderedDict([(1, 2), (2, 3), (3, 4)])
>>> d[::2] = OrderedDict(((7, 8), (9, 10)))
>>> d
OrderedDict([(7, 8), (2, 3), (9, 10)])
>>> d = OrderedDict(((0, 1), (1, 2), (2, 3), (3, 4)))
>>> d[1:3] = OrderedDict(((1, 2), (5, 6), (7, 8)))
>>> d
OrderedDict([(0, 1), (1, 2), (5, 6), (7, 8), (3, 4)])
>>> d = OrderedDict(((0, 1), (1, 2), (2, 3), (3, 4)), strict=True)
>>> d[1:3] = OrderedDict(((1, 2), (5, 6), (7, 8)))
>>> d
OrderedDict([(0, 1), (1, 2), (5, 6), (7, 8), (3, 4)])
>>> a = OrderedDict(((0, 1), (1, 2), (2, 3)), strict=True)
>>> a[3] = 4
>>> a
OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
>>> a[::1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
>>> a
OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
>>> a[:2] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)])
Traceback (most recent call last):
ValueError: slice assignment must be from unique keys
>>> a = OrderedDict(((0, 1), (1, 2), (2, 3)))
>>> a[3] = 4
>>> a
OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
>>> a[::1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
>>> a
OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
>>> a[:2] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
>>> a
OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
>>> a[::-1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
>>> a
OrderedDict([(3, 4), (2, 3), (1, 2), (0, 1)])
>>> d = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
>>> d[:1] = 3
Traceback (most recent call last):
TypeError: slice assignment requires an OrderedDict
>>> d = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
>>> d[:1] = OrderedDict([(9, 8)])
>>> d
OrderedDict([(9, 8), (1, 2), (2, 3), (3, 4)])
"""
if isinstance(key, slice):
if not isinstance(val, OrderedDict):
# FIXME: allow a list of tuples?
raise TypeError('slice assignment requires an OrderedDict')
keys = self._sequence[key]
# NOTE: Could use ``range(*key.indices(len(self._sequence)))``
indexes = range(len(self._sequence))[key]
if key.step is None:
# NOTE: new slice may not be the same size as the one being
# overwritten !
# NOTE: What is the algorithm for an impossible slice?
# e.g. d[5:3]
pos = key.start or 0
del self[key]
newkeys = val.keys()
for k in newkeys:
if k in self:
if self.strict:
raise ValueError('slice assignment must be from '
'unique keys')
else:
# NOTE: This removes duplicate keys *first*
# so start position might have changed?
del self[k]
self._sequence = (self._sequence[:pos] + newkeys +
self._sequence[pos:])
dict.update(self, val)
else:
# extended slice - length of new slice must be the same
# as the one being replaced
if len(keys) != len(val):
raise ValueError('attempt to assign sequence of size %s '
'to extended slice of size %s' % (len(val), len(keys)))
# FIXME: efficiency?
del self[key]
item_list = zip(indexes, val.items())
# smallest indexes first - higher indexes not guaranteed to
# exist
item_list.sort()
for pos, (newkey, newval) in item_list:
if self.strict and newkey in self:
raise ValueError('slice assignment must be from unique'
' keys')
self.insert(pos, newkey, newval)
else:
if key not in self:
self._sequence.append(key)
dict.__setitem__(self, key, val)
def __getitem__(self, key):
"""
Allows slicing. Returns an OrderedDict if you slice.
>>> b = OrderedDict([(7, 0), (6, 1), (5, 2), (4, 3), (3, 4), (2, 5), (1, 6)])
>>> b[::-1]
OrderedDict([(1, 6), (2, 5), (3, 4), (4, 3), (5, 2), (6, 1), (7, 0)])
>>> b[2:5]
OrderedDict([(5, 2), (4, 3), (3, 4)])
>>> type(b[2:4])
<class '__main__.OrderedDict'>
"""
if isinstance(key, slice):
# FIXME: does this raise the error we want?
keys = self._sequence[key]
# FIXME: efficiency?
return OrderedDict([(entry, self[entry]) for entry in keys])
else:
return dict.__getitem__(self, key)
__str__ = __repr__
def __setattr__(self, name, value):
"""
Implemented so that accesses to ``sequence`` raise a warning and are
diverted to the new ``setkeys`` method.
"""
if name == 'sequence':
warnings.warn('Use of the sequence attribute is deprecated.'
' Use the keys method instead.', DeprecationWarning)
# NOTE: doesn't return anything
self.setkeys(value)
else:
# FIXME: do we want to allow arbitrary setting of attributes?
# Or do we want to manage it?
object.__setattr__(self, name, value)
def __getattr__(self, name):
"""
Implemented so that access to ``sequence`` raises a warning.
>>> d = OrderedDict()
>>> d.sequence
[]
"""
if name == 'sequence':
warnings.warn('Use of the sequence attribute is deprecated.'
' Use the keys method instead.', DeprecationWarning)
# NOTE: Still (currently) returns a direct reference. Need to
# because code that uses sequence will expect to be able to
# mutate it in place.
return self._sequence
else:
# raise the appropriate error
raise AttributeError("OrderedDict has no '%s' attribute" % name)
def __deepcopy__(self, memo):
"""
To allow deepcopy to work with OrderedDict.
>>> from copy import deepcopy
>>> a = OrderedDict([(1, 1), (2, 2), (3, 3)])
>>> a['test'] = {}
>>> b = deepcopy(a)
>>> b == a
True
>>> b is a
False
>>> a['test'] is b['test']
False
"""
from copy import deepcopy
return self.__class__(deepcopy(self.items(), memo), self.strict)
### Read-only methods ###
def copy(self):
"""
>>> OrderedDict(((1, 3), (3, 2), (2, 1))).copy()
OrderedDict([(1, 3), (3, 2), (2, 1)])
"""
return OrderedDict(self)
def items(self):
"""
``items`` returns a list of tuples representing all the
``(key, value)`` pairs in the dictionary.
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.items()
[(1, 3), (3, 2), (2, 1)]
>>> d.clear()
>>> d.items()
[]
"""
return zip(self._sequence, self.values())
def keys(self):
"""
Return a list of keys in the ``OrderedDict``.
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.keys()
[1, 3, 2]
"""
return self._sequence[:]
def values(self, values=None):
"""
Return a list of all the values in the OrderedDict.
Optionally you can pass in a list of values, which will replace the
current list. The value list must be the same len as the OrderedDict.
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.values()
[3, 2, 1]
"""
return [self[key] for key in self._sequence]
def iteritems(self):
"""
>>> ii = OrderedDict(((1, 3), (3, 2), (2, 1))).iteritems()
>>> ii.next()
(1, 3)
>>> ii.next()
(3, 2)
>>> ii.next()
(2, 1)
>>> ii.next()
Traceback (most recent call last):
StopIteration
"""
def make_iter(self=self):
keys = self.iterkeys()
while True:
key = keys.next()
yield (key, self[key])
return make_iter()
def iterkeys(self):
"""
>>> ii = OrderedDict(((1, 3), (3, 2), (2, 1))).iterkeys()
>>> ii.next()
1
>>> ii.next()
3
>>> ii.next()
2
>>> ii.next()
Traceback (most recent call last):
StopIteration
"""
return iter(self._sequence)
__iter__ = iterkeys
def itervalues(self):
"""
>>> iv = OrderedDict(((1, 3), (3, 2), (2, 1))).itervalues()
>>> iv.next()
3
>>> iv.next()
2
>>> iv.next()
1
>>> iv.next()
Traceback (most recent call last):
StopIteration
"""
def make_iter(self=self):
keys = self.iterkeys()
while True:
yield self[keys.next()]
return make_iter()
### Read-write methods ###
def clear(self):
"""
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.clear()
>>> d
OrderedDict([])
"""
dict.clear(self)
self._sequence = []
def pop(self, key, *args):
"""
No dict.pop in Python 2.2, gotta reimplement it
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.pop(3)
2
>>> d
OrderedDict([(1, 3), (2, 1)])
>>> d.pop(4)
Traceback (most recent call last):
KeyError: 4
>>> d.pop(4, 0)
0
>>> d.pop(4, 0, 1)
Traceback (most recent call last):
TypeError: pop expected at most 2 arguments, got 3
"""
if len(args) > 1:
raise TypeError('pop expected at most 2 arguments, got %s' %
(len(args) + 1))
if key in self:
val = self[key]
del self[key]
else:
try:
val = args[0]
except IndexError:
raise KeyError(key)
return val
def popitem(self, i=-1):
"""
Delete and return an item specified by index, not a random one as in
dict. The index is -1 by default (the last item).
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.popitem()
(2, 1)
>>> d
OrderedDict([(1, 3), (3, 2)])
>>> d.popitem(0)
(1, 3)
>>> OrderedDict().popitem()
Traceback (most recent call last):
KeyError: 'popitem(): dictionary is empty'
>>> d.popitem(2)
Traceback (most recent call last):
IndexError: popitem(): index 2 not valid
"""
if not self._sequence:
raise KeyError('popitem(): dictionary is empty')
try:
key = self._sequence[i]
except IndexError:
raise IndexError('popitem(): index %s not valid' % i)
return (key, self.pop(key))
def setdefault(self, key, defval=None):
"""
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.setdefault(1)
3
>>> d.setdefault(4) is None
True
>>> d
OrderedDict([(1, 3), (3, 2), (2, 1), (4, None)])
>>> d.setdefault(5, 0)
0
>>> d
OrderedDict([(1, 3), (3, 2), (2, 1), (4, None), (5, 0)])
"""
if key in self:
return self[key]
else:
self[key] = defval
return defval
def update(self, from_od):
"""
Update from another OrderedDict or sequence of (key, value) pairs
>>> d = OrderedDict(((1, 0), (0, 1)))
>>> d.update(OrderedDict(((1, 3), (3, 2), (2, 1))))
>>> d
OrderedDict([(1, 3), (0, 1), (3, 2), (2, 1)])
>>> d.update({4: 4})
Traceback (most recent call last):
TypeError: undefined order, cannot get items from dict
>>> d.update((4, 4))
Traceback (most recent call last):
TypeError: cannot convert dictionary update sequence element "4" to a 2-item sequence
"""
if isinstance(from_od, OrderedDict):
for key, val in from_od.items():
self[key] = val
elif isinstance(from_od, dict):
# we lose compatibility with other ordered dict types this way
raise TypeError('undefined order, cannot get items from dict')
else:
# FIXME: efficiency?
# sequence of 2-item sequences, or error
for item in from_od:
try:
key, val = item
except TypeError:
raise TypeError('cannot convert dictionary update'
' sequence element "%s" to a 2-item sequence' % item)
self[key] = val
def rename(self, old_key, new_key):
"""
Rename the key for a given value, without modifying sequence order.
For the case where new_key already exists this raise an exception,
since if new_key exists, it is ambiguous as to what happens to the
associated values, and the position of new_key in the sequence.
>>> od = OrderedDict()
>>> od['a'] = 1
>>> od['b'] = 2
>>> od.items()
[('a', 1), ('b', 2)]
>>> od.rename('b', 'c')
>>> od.items()
[('a', 1), ('c', 2)]
>>> od.rename('c', 'a')
Traceback (most recent call last):
ValueError: New key already exists: 'a'
>>> od.rename('d', 'b')
Traceback (most recent call last):
KeyError: 'd'
"""
if new_key == old_key:
# no-op
return
if new_key in self:
raise ValueError("New key already exists: %r" % new_key)
# rename sequence entry
value = self[old_key]
old_idx = self._sequence.index(old_key)
self._sequence[old_idx] = new_key
# rename internal dict entry
dict.__delitem__(self, old_key)
dict.__setitem__(self, new_key, value)
def setitems(self, items):
"""
This method allows you to set the items in the dict.
It takes a list of tuples - of the same sort returned by the ``items``
method.
>>> d = OrderedDict()
>>> d.setitems(((3, 1), (2, 3), (1, 2)))
>>> d
OrderedDict([(3, 1), (2, 3), (1, 2)])
"""
self.clear()
# FIXME: this allows you to pass in an OrderedDict as well :-)
self.update(items)
def setkeys(self, keys):
"""
``setkeys`` all ows you to pass in a new list of keys which will
replace the current set. This must contain the same set of keys, but
need not be in the same order.
If you pass in new keys that don't match, a ``KeyError`` will be
raised.
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.keys()
[1, 3, 2]
>>> d.setkeys((1, 2, 3))
>>> d
OrderedDict([(1, 3), (2, 1), (3, 2)])
>>> d.setkeys(['a', 'b', 'c'])
Traceback (most recent call last):
KeyError: 'Keylist is not the same as current keylist.'
"""
# FIXME: Efficiency? (use set for Python 2.4 :-)
# NOTE: list(keys) rather than keys[:] because keys[:] returns
# a tuple, if keys is a tuple.
kcopy = list(keys)
kcopy.sort()
self._sequence.sort()
if kcopy != self._sequence:
raise KeyError('Keylist is not the same as current keylist.')
# NOTE: This makes the _sequence attribute a new object, instead
# of changing it in place.
# FIXME: efficiency?
self._sequence = list(keys)
def setvalues(self, values):
"""
You can pass in a list of values, which will replace the
current list. The value list must be the same len as the OrderedDict.
(Or a ``ValueError`` is raised.)
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.setvalues((1, 2, 3))
>>> d
OrderedDict([(1, 1), (3, 2), (2, 3)])
>>> d.setvalues([6])
Traceback (most recent call last):
ValueError: Value list is not the same length as the OrderedDict.
"""
if len(values) != len(self):
# FIXME: correct error to raise?
raise ValueError('Value list is not the same length as the '
'OrderedDict.')
self.update(zip(self, values))
### Sequence Methods ###
def index(self, key):
"""
Return the position of the specified key in the OrderedDict.
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.index(3)
1
>>> d.index(4)
Traceback (most recent call last):
ValueError: 4 is not in list
"""
return self._sequence.index(key)
def insert(self, index, key, value):
"""
Takes ``index``, ``key``, and ``value`` as arguments.
Sets ``key`` to ``value``, so that ``key`` is at position ``index`` in
the OrderedDict.
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.insert(0, 4, 0)
>>> d
OrderedDict([(4, 0), (1, 3), (3, 2), (2, 1)])
>>> d.insert(0, 2, 1)
>>> d
OrderedDict([(2, 1), (4, 0), (1, 3), (3, 2)])
>>> d.insert(8, 8, 1)
>>> d
OrderedDict([(2, 1), (4, 0), (1, 3), (3, 2), (8, 1)])
"""
if key in self:
# FIXME: efficiency?
del self[key]
self._sequence.insert(index, key)
dict.__setitem__(self, key, value)
def reverse(self):
"""
Reverse the order of the OrderedDict.
>>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
>>> d.reverse()
>>> d
OrderedDict([(2, 1), (3, 2), (1, 3)])
"""
self._sequence.reverse()
def sort(self, *args, **kwargs):
"""
Sort the key order in the OrderedDict.
This method takes the same arguments as the ``list.sort`` method on
your version of Python.
>>> d = OrderedDict(((4, 1), (2, 2), (3, 3), (1, 4)))
>>> d.sort()
>>> d
OrderedDict([(1, 4), (2, 2), (3, 3), (4, 1)])
"""
self._sequence.sort(*args, **kwargs)
if __name__ == '__main__':
# turn off warnings for tests
warnings.filterwarnings('ignore')
# run the code tests in doctest format
import doctest
m = sys.modules.get('__main__')
globs = m.__dict__.copy()
globs.update({
'INTP_VER': INTP_VER,
})
doctest.testmod(m, globs=globs)

@ -0,0 +1,35 @@
"""EditorConfig version tools
Provides ``join_version`` and ``split_version`` classes for converting
__version__ strings to VERSION tuples and vice versa.
"""
import re
__all__ = ['join_version', 'split_version']
_version_re = re.compile(r'^(\d+)\.(\d+)\.(\d+)(\..*)?$', re.VERBOSE)
def join_version(version_tuple):
"""Return a string representation of version from given VERSION tuple"""
version = "%s.%s.%s" % version_tuple[:3]
if version_tuple[3] != "final":
version += "-%s" % version_tuple[3]
return version
def split_version(version):
"""Return VERSION tuple for given string representation of version"""
match = _version_re.search(version)
if not match:
return None
else:
split_version = list(match.groups())
if split_version[3] is None:
split_version[3] = "final"
split_version = list(map(int, split_version[:3])) + split_version[3:]
return tuple(split_version)

@ -0,0 +1,8 @@
#!/usr/bin/env python
from editorconfig.main import main
if __name__ == "__main__":
main()

@ -0,0 +1,29 @@
from setuptools import setup
import editorconfig
setup(
name='EditorConfig',
version=editorconfig.__version__,
author='EditorConfig Team',
packages=['editorconfig'],
url='http://editorconfig.org/',
license='LICENSE.txt',
description='EditorConfig File Locator and Interpreter for Python',
long_description=open('README.rst').read(),
entry_points = {
'console_scripts': [
'editorconfig = editorconfig.main:main',
]
},
classifiers=[
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: Implementation :: PyPy',
],
)

@ -0,0 +1,42 @@
from __future__ import print_function
try:
try:
import vim
import sys
except:
vim.command('let l:ret = 2')
raise
try:
sys.path.insert(0, vim.eval('a:editorconfig_core_py_dir'))
import editorconfig
import editorconfig.exceptions as editorconfig_except
except:
vim.command('let l:ret = 3')
raise
finally:
del sys.path[0]
# `ec_` prefix is used in order to keep clean Python namespace
ec_data = {}
def ec_UseConfigFiles():
ec_data['filename'] = vim.eval("expand('%:p')")
ec_data['conf_file'] = ".editorconfig"
try:
ec_data['options'] = editorconfig.get_properties(ec_data['filename'])
except editorconfig_except.EditorConfigError as e:
if int(vim.eval('g:EditorConfig_verbose')) != 0:
print(str(e), file=sys.stderr)
vim.command('let l:ret = 1')
return
for key, value in ec_data['options'].items():
vim.command("let l:config['" + key.replace("'", "''") + "'] = " +
"'" + value.replace("'", "''") + "'")
except:
pass

@ -0,0 +1,630 @@
" Copyright (c) 2011-2015 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
" check whether this script is already loaded
if exists("g:loaded_EditorConfig")
finish
endif
let g:loaded_EditorConfig = 1
let s:saved_cpo = &cpo
set cpo&vim
let s:pyscript_path = expand('<sfile>:p:r') . '.py'
" variables {{{1
if !exists('g:EditorConfig_exec_path')
let g:EditorConfig_exec_path = ''
endif
if !exists('g:EditorConfig_python_files_dir')
let g:EditorConfig_python_files_dir = 'plugin/editorconfig-core-py'
endif
if !exists('g:EditorConfig_verbose')
let g:EditorConfig_verbose = 0
endif
if !exists('g:EditorConfig_preserve_formatoptions')
let g:EditorConfig_preserve_formatoptions = 0
endif
if !exists('g:EditorConfig_max_line_indicator')
let g:EditorConfig_max_line_indicator = 'line'
endif
if !exists('g:EditorConfig_exclude_patterns')
let g:EditorConfig_exclude_patterns = []
endif
if exists('g:EditorConfig_core_mode') && !empty(g:EditorConfig_core_mode)
let s:editorconfig_core_mode = g:EditorConfig_core_mode
else
let s:editorconfig_core_mode = ''
endif
" shellslash handling {{{1
function! s:DisableShellSlash() " {{{2
" disable shellslash for proper escaping of Windows paths
" In Windows, 'shellslash' also changes the behavior of 'shellescape'.
" It makes 'shellescape' behave like in UNIX environment. So ':setl
" noshellslash' before evaluating 'shellescape' and restore the
" settings afterwards when 'shell' does not contain 'sh' somewhere.
if has('win32') && empty(matchstr(&shell, 'sh'))
let s:old_shellslash = &l:shellslash
setlocal noshellslash
endif
endfunction " }}}
function! s:ResetShellSlash() " {{{2
" reset shellslash to the user-set value, if any
if exists('s:old_shellslash')
let &l:shellslash = s:old_shellslash
unlet! s:old_shellslash
endif
endfunction " }}}
" }}}
function! s:FindPythonInterp() " {{{1
" Find python interp. If found, return python command; if not found, return ''
if has('unix')
let l:searching_list = [
\ 'python',
\ 'python27',
\ 'python26',
\ 'python25',
\ 'python24',
\ '/usr/local/bin/python',
\ '/usr/local/bin/python27',
\ '/usr/local/bin/python26',
\ '/usr/local/bin/python25',
\ '/usr/local/bin/python24',
\ '/usr/bin/python',
\ '/usr/bin/python27',
\ '/usr/bin/python26',
\ '/usr/bin/python25',
\ '/usr/bin/python24']
elseif has('win32')
let l:searching_list = [
\ 'python',
\ 'python27',
\ 'python26',
\ 'python25',
\ 'python24',
\ 'C:\Python27\python.exe',
\ 'C:\Python26\python.exe',
\ 'C:\Python25\python.exe',
\ 'C:\Python24\python.exe']
endif
for possible_python_interp in l:searching_list
if executable(possible_python_interp)
return possible_python_interp
endif
endfor
return ''
endfunction
function! s:FindPythonFiles() " {{{1
" Find EditorConfig Core python files
call s:DisableShellSlash()
let l:python_core_files_dir = fnamemodify(
\ findfile(g:EditorConfig_python_files_dir . '/main.py',
\ ','.&runtimepath), ':p:h')
if empty(l:python_core_files_dir)
let l:python_core_files_dir = ''
else
" expand python core file path to full path, and remove the appending '/'
let l:python_core_files_dir = substitute(
\ fnamemodify(l:python_core_files_dir, ':p'), '/$', '', '')
endif
call s:ResetShellSlash()
return l:python_core_files_dir
endfunction
" Mode initialization functions {{{1
function! s:InitializeExternalCommand() " {{{2
" Initialize external_command mode
let s:EditorConfig_exec_path = ''
" User has specified an EditorConfig command. Use that one.
if exists('g:EditorConfig_exec_path') &&
\ !empty(g:EditorConfig_exec_path)
if executable(g:EditorConfig_exec_path)
let s:EditorConfig_exec_path = g:EditorConfig_exec_path
return 0
else
return 1
endif
endif
" User does not specify an EditorConfig command. Let's search for it.
if has('unix')
let l:searching_list = [
\ 'editorconfig',
\ '/usr/local/bin/editorconfig',
\ '/usr/bin/editorconfig',
\ '/opt/bin/editorconfig',
\ '/opt/editorconfig/bin/editorconfig',
\ 'editorconfig.py',
\ '/usr/local/bin/editorconfig.py',
\ '/usr/bin/editorconfig.py',
\ '/opt/bin/editorconfig.py',
\ '/opt/editorconfig/bin/editorconfig.py']
elseif has('win32')
let l:searching_list = [
\ 'editorconfig',
\ 'C:\editorconfig\bin\editorconfig',
\ 'D:\editorconfig\bin\editorconfig',
\ 'E:\editorconfig\bin\editorconfig',
\ 'F:\editorconfig\bin\editorconfig',
\ 'C:\Program Files\editorconfig\bin\editorconfig',
\ 'D:\Program Files\editorconfig\bin\editorconfig',
\ 'E:\Program Files\editorconfig\bin\editorconfig',
\ 'F:\Program Files\editorconfig\bin\editorconfig',
\ 'C:\Program Files (x86)\editorconfig\bin\editorconfig',
\ 'D:\Program Files (x86)\editorconfig\bin\editorconfig',
\ 'E:\Program Files (x86)\editorconfig\bin\editorconfig',
\ 'F:\Program Files (x86)\editorconfig\bin\editorconfig',
\ 'editorconfig.py']
endif
" search for editorconfig core executable
for possible_cmd in l:searching_list
if executable(possible_cmd)
let s:EditorConfig_exec_path = possible_cmd
break
endif
endfor
if empty(s:EditorConfig_exec_path)
return 2
endif
return 0
endfunction
function! s:InitializePythonExternal() " {{{2
" Initialize external python. Before calling this function, please make sure
" s:FindPythonFiles is called and the return value is set to
" s:editorconfig_core_py_dir
if !exists('s:editorconfig_core_py_dir') ||
\ empty(s:editorconfig_core_py_dir)
return 2
endif
" Find python interp
if !exists('g:editorconfig_python_interp') ||
\ empty('g:editorconfig_python_interp')
let s:editorconfig_python_interp = s:FindPythonInterp()
endif
if empty(s:editorconfig_python_interp) ||
\ !executable(s:editorconfig_python_interp)
return 1
endif
return 0
endfunction
function! s:InitializePythonBuiltin(editorconfig_core_py_dir) " {{{2
" Initialize builtin python. The parameter is the Python Core directory
if exists('s:builtin_python_initialized') && s:builtin_python_initialized
return 0
endif
let s:builtin_python_initialized = 1
if has('python')
let s:pyfile_cmd = 'pyfile'
let s:py_cmd = 'py'
elseif has('python3')
let s:pyfile_cmd = 'py3file'
let s:py_cmd = 'py3'
else
return 1
endif
let l:ret = 0
" The following line modifies l:ret. This is a bit confusing but
" unfortunately to be compatible with Vim 7.3, we cannot use pyeval. This
" should be changed in the future.
execute s:pyfile_cmd fnameescape(s:pyscript_path)
return l:ret
endfunction
" Do some initalization for the case that the user has specified core mode {{{1
if !empty(s:editorconfig_core_mode)
if s:editorconfig_core_mode == 'external_command'
if s:InitializeExternalCommand()
echo 'EditorConfig: Failed to initialize external_command mode'
finish
endif
else
let s:editorconfig_core_py_dir = s:FindPythonFiles()
if empty(s:editorconfig_core_py_dir)
echo 'EditorConfig: '.
\ 'EditorConfig Python Core files could not be found.'
finish
endif
if s:editorconfig_core_mode == 'python_builtin' &&
\ s:InitializePythonBuiltin(s:editorconfig_core_py_dir)
echo 'EditorConfig: Failed to initialize vim built-in python.'
finish
elseif s:editorconfig_core_mode == 'python_external' &&
\ s:InitializePythonExternal()
echo 'EditorConfig: Failed to find external Python interpreter.'
finish
endif
endif
endif
" Determine the editorconfig_core_mode we should use {{{1
while 1
" If user has specified a mode, just break
if exists('s:editorconfig_core_mode') && !empty(s:editorconfig_core_mode)
break
endif
" Find Python core files. If not found, we try external_command mode
let s:editorconfig_core_py_dir = s:FindPythonFiles()
if empty(s:editorconfig_core_py_dir) " python files are not found
if !s:InitializeExternalCommand()
let s:editorconfig_core_mode = 'external_command'
endif
break
endif
" Builtin python mode first
if !s:InitializePythonBuiltin(s:editorconfig_core_py_dir)
let s:editorconfig_core_mode = 'python_builtin'
break
endif
" Then external_command mode
if !s:InitializeExternalCommand()
let s:editorconfig_core_mode = 'external_command'
break
endif
" Finally external python mode
if !s:InitializePythonExternal()
let s:editorconfig_core_mode = 'python_external'
break
endif
break
endwhile
" No EditorConfig Core is available
if empty(s:editorconfig_core_mode)
echo "EditorConfig: ".
\ "No EditorConfig Core is available. The plugin won't work."
finish
endif
function! s:UseConfigFiles()
let l:buffer_name = expand('%:p')
" ignore buffers without a name
if empty(l:buffer_name)
return
endif
if g:EditorConfig_verbose
echo 'Applying EditorConfig on file "' . l:buffer_name . '"'
endif
" Ignore specific patterns
for pattern in g:EditorConfig_exclude_patterns
if l:buffer_name =~ pattern
return
endif
endfor
if s:editorconfig_core_mode == 'external_command'
call s:UseConfigFiles_ExternalCommand()
elseif s:editorconfig_core_mode == 'python_builtin'
call s:UseConfigFiles_Python_Builtin()
elseif s:editorconfig_core_mode == 'python_external'
call s:UseConfigFiles_Python_External()
else
echohl Error |
\ echo "Unknown EditorConfig Core: " .
\ s:editorconfig_core_mode |
\ echohl None
endif
endfunction
" command, autoload {{{1
command! EditorConfigReload call s:UseConfigFiles() " Reload EditorConfig files
augroup editorconfig
autocmd!
autocmd BufNewFile,BufReadPost,BufFilePost * call s:UseConfigFiles()
autocmd BufNewFile,BufRead .editorconfig set filetype=dosini
augroup END
" UseConfigFiles function for different mode {{{1
function! s:UseConfigFiles_Python_Builtin() " {{{2
" Use built-in python to run the python EditorConfig core
" ignore buffers that do not have a file path associated
if empty(expand('%:p'))
return 0
endif
let l:config = {}
let l:ret = 0
execute s:py_cmd 'ec_UseConfigFiles()'
if l:ret != 0
return l:ret
endif
call s:ApplyConfig(l:config)
return l:ret
endfunction
function! s:UseConfigFiles_Python_External() " {{{2
" Use external python interp to run the python EditorConfig Core
call s:DisableShellSlash()
let l:cmd = shellescape(s:editorconfig_python_interp) . ' ' .
\ shellescape(s:editorconfig_core_py_dir . '/main.py')
call s:ResetShellSlash()
call s:SpawnExternalParser(l:cmd)
return 0
endfunction
function! s:UseConfigFiles_ExternalCommand() " {{{2
" Use external EditorConfig core (The C core, or editorconfig.py)
call s:DisableShellSlash()
let l:exec_path = shellescape(s:EditorConfig_exec_path)
call s:ResetShellSlash()
call s:SpawnExternalParser(l:exec_path)
endfunction
function! s:SpawnExternalParser(cmd) " {{{2
" Spawn external EditorConfig. Used by s:UseConfigFiles_Python_External() and
" s:UseConfigFiles_ExternalCommand()
let l:cmd = a:cmd
" ignore buffers that do not have a file path associated
if empty(expand("%:p"))
return
endif
" if editorconfig is present, we use this as our parser
if !empty(l:cmd)
let l:config = {}
call s:DisableShellSlash()
let l:cmd = l:cmd . ' ' . shellescape(expand('%:p'))
call s:ResetShellSlash()
let l:parsing_result = split(system(l:cmd), '\n')
" if editorconfig core's exit code is not zero, give out an error
" message
if v:shell_error != 0
echohl ErrorMsg
echo 'Failed to execute "' . l:cmd . '". Exit code: ' .
\ v:shell_error
echo ''
echo 'Message:'
echo l:parsing_result
echohl None
return
endif
if g:EditorConfig_verbose
echo 'Output from EditorConfig core executable:'
echo l:parsing_result
endif
for one_line in l:parsing_result
let l:eq_pos = stridx(one_line, '=')
if l:eq_pos == -1 " = is not found. Skip this line
continue
endif
let l:eq_left = strpart(one_line, 0, l:eq_pos)
if l:eq_pos + 1 < strlen(one_line)
let l:eq_right = strpart(one_line, l:eq_pos + 1)
else
let l:eq_right = ''
endif
let l:config[l:eq_left] = l:eq_right
endfor
call s:ApplyConfig(l:config)
endif
endfunction
function! s:ApplyConfig(config) " {{{1
" Only process normal buffers (do not treat help files as '.txt' files)
if !empty(&buftype)
return
endif
" Set the indentation style according to the config values
if has_key(a:config, "indent_style")
if a:config["indent_style"] == "tab"
setl noexpandtab
elseif a:config["indent_style"] == "space"
setl expandtab
endif
endif
if has_key(a:config, "tab_width")
let &l:tabstop = str2nr(a:config["tab_width"])
endif
if has_key(a:config, "indent_size")
" if indent_size is 'tab', set shiftwidth to tabstop;
" if indent_size is a positive integer, set shiftwidth to the integer
" value
if a:config["indent_size"] == "tab"
let &l:shiftwidth = &l:tabstop
let &l:softtabstop = &l:shiftwidth
else
let l:indent_size = str2nr(a:config["indent_size"])
if l:indent_size > 0
let &l:shiftwidth = l:indent_size
let &l:softtabstop = &l:shiftwidth
endif
endif
endif
if has_key(a:config, "end_of_line") && &l:modifiable
if a:config["end_of_line"] == "lf"
setl fileformat=unix
elseif a:config["end_of_line"] == "crlf"
setl fileformat=dos
elseif a:config["end_of_line"] == "cr"
setl fileformat=mac
endif
endif
if has_key(a:config, "charset") && &l:modifiable
if a:config["charset"] == "utf-8"
setl fileencoding=utf-8
setl nobomb
elseif a:config["charset"] == "utf-8-bom"
setl fileencoding=utf-8
setl bomb
elseif a:config["charset"] == "latin1"
setl fileencoding=latin1
setl nobomb
elseif a:config["charset"] == "utf-16be"
setl fileencoding=utf-16be
setl bomb
elseif a:config["charset"] == "utf-16le"
setl fileencoding=utf-16le
setl bomb
endif
endif
augroup editorconfig_trim_trailing_whitespace
autocmd! BufWritePre <buffer>
if get(a:config, 'trim_trailing_whitespace', 'false') ==# 'true'
autocmd BufWritePre <buffer> call s:TrimTrailingWhitespace()
endif
augroup END
if has_key(a:config, "insert_final_newline")
if exists('+fixendofline')
if a:config["insert_final_newline"] == "false"
setl nofixendofline
else
setl fixendofline
endif
elseif exists(':SetNoEOL') == 2
if a:config["insert_final_newline"] == "false"
silent! SetNoEOL " Use the PreserveNoEOL plugin to accomplish it
endif
endif
endif
" highlight the columns following max_line_length
if has_key(a:config, 'max_line_length') &&
\ a:config['max_line_length'] != 'off'
let l:max_line_length = str2nr(a:config['max_line_length'])
if l:max_line_length >= 0
let &l:textwidth = l:max_line_length
if g:EditorConfig_preserve_formatoptions == 0
setlocal formatoptions+=tc
endif
endif
if exists('+colorcolumn')
if l:max_line_length > 0
if g:EditorConfig_max_line_indicator == 'line'
let &l:colorcolumn = l:max_line_length + 1
elseif g:EditorConfig_max_line_indicator == 'fill' &&
\ l:max_line_length < &l:columns
" Fill only if the columns of screen is large enough
let &l:colorcolumn = join(
\ range(l:max_line_length+1,&l:columns),',')
endif
endif
endif
endif
call editorconfig#ApplyHooks(a:config)
endfunction
" }}}
function! s:TrimTrailingWhitespace() " {{{{
if &l:modifiable
" don't lose user position when trimming trailing whitespace
let s:view = winsaveview()
try
silent! %s/\s\+$//e
finally
call winrestview(s:view)
endtry
endif
endfunction " }}}
let &cpo = s:saved_cpo
unlet! s:saved_cpo
" vim: fdm=marker fdc=3

@ -0,0 +1,5 @@
source 'https://rubygems.org'
gem 'rake', '~> 10.4.2'
gem 'rspec', '~> 3.4.0'
gem 'vimrunner', '~> 0.3.1'

@ -0,0 +1,27 @@
GEM
remote: https://rubygems.org/
specs:
diff-lcs (1.2.5)
rake (10.4.2)
rspec (3.4.0)
rspec-core (~> 3.4.0)
rspec-expectations (~> 3.4.0)
rspec-mocks (~> 3.4.0)
rspec-core (3.4.1)
rspec-support (~> 3.4.0)
rspec-expectations (3.4.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.4.0)
rspec-mocks (3.4.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.4.0)
rspec-support (3.4.1)
vimrunner (0.3.1)
PLATFORMS
ruby
DEPENDENCIES
rake (~> 10.4.2)
rspec (~> 3.4.0)
vimrunner (~> 0.3.1)

@ -0,0 +1,8 @@
#
# run `rake` to run tests
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec)
task :default => :spec

@ -0,0 +1,4 @@
[*.rb]
indent_style = space
indent_size = 2
end_of_line = LF

@ -0,0 +1,121 @@
require 'vimrunner'
$vim = Vimrunner.start
$vim.add_plugin(File.expand_path('../../..', __FILE__), 'plugin/editorconfig.vim')
# The base path of the testing files
BASE_PATH = File.expand_path('../plugin_tests/test_files/', __FILE__)
# file_name is the file name that should be open by Vim
# expected_values is a Hash that contains all the Vim options we need to test
def test_editorconfig(file_name, expected_values)
$vim.edit(File.join(BASE_PATH, file_name))
expected_values.each do |key, val|
expect($vim.echo("&l:#{key}")).to eq(val)
end
$vim.command 'bd!'
end
describe 'plugin/editorconfig.vim' do
after(:all) do
$vim.kill
end
describe '#all' do
it '3_space.py' do
test_editorconfig '3_space.txt',
expandtab: '1',
shiftwidth: '3',
tabstop: '3'
end
end
it '4_space.py' do
test_editorconfig '4_space.py',
expandtab: '1',
shiftwidth: '4',
tabstop: '8'
end
it 'space.txt' do
test_editorconfig 'space.txt',
expandtab: '1',
shiftwidth: $vim.echo('&l:tabstop')
end
it 'tab.txt' do
test_editorconfig 'tab.txt',
expandtab: '0'
end
it '4_tab.txt' do
test_editorconfig '4_tab.txt',
expandtab: '0',
shiftwidth: '4',
tabstop: '4'
end
it '4_tab_width_of_8' do
test_editorconfig '4_tab_width_of_8.txt',
expandtab: '0',
shiftwidth: '4',
tabstop: '8'
end
it 'lf.txt' do
test_editorconfig 'lf.txt',
fileformat: 'unix'
end
it 'crlf.txt' do
test_editorconfig 'crlf.txt',
fileformat: 'dos'
end
it 'cr.txt' do
test_editorconfig 'cr.txt',
fileformat: 'mac'
end
it 'utf-8.txt' do
test_editorconfig 'utf-8.txt',
fileencoding: 'utf-8',
bomb: '0'
end
it 'utf-8-bom.txt' do
test_editorconfig 'utf-8-bom.txt',
fileencoding: 'utf-8',
bomb: '1'
end
it 'utf-16be.txt' do
test_editorconfig 'utf-16be.txt',
fileencoding: 'utf-16'
end
it 'utf-16le.txt' do
test_editorconfig 'utf-16le.txt',
fileencoding: 'utf-16le'
end
it 'latin1.txt' do
test_editorconfig 'latin1.txt',
fileencoding: 'latin1'
end
# insert_final_newline by PreserveNoEOL tests are omitted, since they are not supported
if $vim.echo("exists('+fixendofline')") == '1'
it 'with_newline.txt' do
test_editorconfig 'with_newline.txt',
fixendofline: '1'
end
it 'without_newline.txt' do
test_editorconfig 'without_newline.txt',
fixendofline: '0'
end
end
end

@ -0,0 +1 @@
Subproject commit 3f2121e34a7baf360acbcf322c2d05f29f69cac7
Loading…
Cancel
Save