1
0

Start using EditorConfig with vim

This commit is contained in:
Noah 2014-07-31 12:03:54 -07:00
parent e9e5328a0d
commit cb38a29944
32 changed files with 3691 additions and 1 deletions

15
home/.editorconfig Normal file
View File

@ -0,0 +1,15 @@
# Top-most EditorConfig file
root = true
# Unix-style newlines on every file
[*]
end_of_line = lf
insert_final_newline = true
indent_style = tab
# Python files use space indents
[*.py]
indent_style = space
indent_size = 4
# format:dosini

View File

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

View File

@ -0,0 +1,276 @@
" Vim color file
"
" Author: Tomas Restrepo <tomas@winterdom.com>
" https://github.com/tomasr/molokai
"
" Note: Based on the Monokai theme for TextMate
" by Wimer Hazenberg and its darker variant
" by Hamish Stuart Macpherson
"
hi clear
if version > 580
" no guarantees for version 5.8 and below, but this makes it stop
" complaining
hi clear
if exists("syntax_on")
syntax reset
endif
endif
let g:colors_name="molokai"
if exists("g:molokai_original")
let s:molokai_original = g:molokai_original
else
let s:molokai_original = 0
endif
hi Boolean guifg=#AE81FF
hi Character guifg=#E6DB74
hi Number guifg=#AE81FF
hi String guifg=#E6DB74
hi Conditional guifg=#F92672 gui=bold
hi Constant guifg=#AE81FF gui=bold
hi Cursor guifg=#000000 guibg=#F8F8F0
hi iCursor guifg=#000000 guibg=#F8F8F0
hi Debug guifg=#BCA3A3 gui=bold
hi Define guifg=#66D9EF
hi Delimiter guifg=#8F8F8F
hi DiffAdd guibg=#13354A
hi DiffChange guifg=#89807D guibg=#4C4745
hi DiffDelete guifg=#960050 guibg=#1E0010
hi DiffText guibg=#4C4745 gui=italic,bold
hi Directory guifg=#A6E22E gui=bold
hi Error guifg=#E6DB74 guibg=#1E0010
hi ErrorMsg guifg=#F92672 guibg=#232526 gui=bold
hi Exception guifg=#A6E22E gui=bold
hi Float guifg=#AE81FF
hi FoldColumn guifg=#465457 guibg=#000000
hi Folded guifg=#465457 guibg=#000000
hi Function guifg=#A6E22E
hi Identifier guifg=#FD971F
hi Ignore guifg=#808080 guibg=bg
hi IncSearch guifg=#C4BE89 guibg=#000000
hi Keyword guifg=#F92672 gui=bold
hi Label guifg=#E6DB74 gui=none
hi Macro guifg=#C4BE89 gui=italic
hi SpecialKey guifg=#66D9EF gui=italic
hi MatchParen guifg=#000000 guibg=#FD971F gui=bold
hi ModeMsg guifg=#E6DB74
hi MoreMsg guifg=#E6DB74
hi Operator guifg=#F92672
" complete menu
hi Pmenu guifg=#66D9EF guibg=#000000
hi PmenuSel guibg=#808080
hi PmenuSbar guibg=#080808
hi PmenuThumb guifg=#66D9EF
hi PreCondit guifg=#A6E22E gui=bold
hi PreProc guifg=#A6E22E
hi Question guifg=#66D9EF
hi Repeat guifg=#F92672 gui=bold
hi Search guifg=#000000 guibg=#FFE792
" marks
hi SignColumn guifg=#A6E22E guibg=#232526
hi SpecialChar guifg=#F92672 gui=bold
hi SpecialComment guifg=#7E8E91 gui=bold
hi Special guifg=#66D9EF guibg=bg gui=italic
if has("spell")
hi SpellBad guisp=#FF0000 gui=undercurl
hi SpellCap guisp=#7070F0 gui=undercurl
hi SpellLocal guisp=#70F0F0 gui=undercurl
hi SpellRare guisp=#FFFFFF gui=undercurl
endif
hi Statement guifg=#F92672 gui=bold
hi StatusLine guifg=#455354 guibg=fg
hi StatusLineNC guifg=#808080 guibg=#080808
hi StorageClass guifg=#FD971F gui=italic
hi Structure guifg=#66D9EF
hi Tag guifg=#F92672 gui=italic
hi Title guifg=#ef5939
hi Todo guifg=#FFFFFF guibg=bg gui=bold
hi Typedef guifg=#66D9EF
hi Type guifg=#66D9EF gui=none
hi Underlined guifg=#808080 gui=underline
hi VertSplit guifg=#808080 guibg=#080808 gui=bold
hi VisualNOS guibg=#403D3D
hi Visual guibg=#403D3D
hi WarningMsg guifg=#FFFFFF guibg=#333333 gui=bold
hi WildMenu guifg=#66D9EF guibg=#000000
hi TabLineFill guifg=#1B1D1E guibg=#1B1D1E
hi TabLine guibg=#1B1D1E guifg=#808080 gui=none
if s:molokai_original == 1
hi Normal guifg=#F8F8F2 guibg=#272822
hi Comment guifg=#75715E
hi CursorLine guibg=#3E3D32
hi CursorLineNr guifg=#FD971F gui=none
hi CursorColumn guibg=#3E3D32
hi ColorColumn guibg=#3B3A32
hi LineNr guifg=#BCBCBC guibg=#3B3A32
hi NonText guifg=#75715E
hi SpecialKey guifg=#75715E
else
hi Normal guifg=#F8F8F2 guibg=#1B1D1E
hi Comment guifg=#7E8E91
hi CursorLine guibg=#293739
hi CursorLineNr guifg=#FD971F gui=none
hi CursorColumn guibg=#293739
hi ColorColumn guibg=#232526
hi LineNr guifg=#465457 guibg=#232526
hi NonText guifg=#465457
hi SpecialKey guifg=#465457
end
"
" Support for 256-color terminal
"
if &t_Co > 255
if s:molokai_original == 1
hi Normal ctermbg=234
hi CursorLine ctermbg=235 cterm=none
hi CursorLineNr ctermfg=208 cterm=none
else
hi Normal ctermfg=252 ctermbg=233
hi CursorLine ctermbg=234 cterm=none
hi CursorLineNr ctermfg=208 cterm=none
endif
hi Boolean ctermfg=135
hi Character ctermfg=144
hi Number ctermfg=135
hi String ctermfg=144
hi Conditional ctermfg=161 cterm=bold
hi Constant ctermfg=135 cterm=bold
hi Cursor ctermfg=16 ctermbg=253
hi Debug ctermfg=225 cterm=bold
hi Define ctermfg=81
hi Delimiter ctermfg=241
hi DiffAdd ctermbg=24
hi DiffChange ctermfg=181 ctermbg=239
hi DiffDelete ctermfg=162 ctermbg=53
hi DiffText ctermbg=102 cterm=bold
hi Directory ctermfg=118 cterm=bold
hi Error ctermfg=219 ctermbg=89
hi ErrorMsg ctermfg=199 ctermbg=16 cterm=bold
hi Exception ctermfg=118 cterm=bold
hi Float ctermfg=135
hi FoldColumn ctermfg=67 ctermbg=16
hi Folded ctermfg=67 ctermbg=16
hi Function ctermfg=118
hi Identifier ctermfg=208 cterm=none
hi Ignore ctermfg=244 ctermbg=232
hi IncSearch ctermfg=193 ctermbg=16
hi keyword ctermfg=161 cterm=bold
hi Label ctermfg=229 cterm=none
hi Macro ctermfg=193
hi SpecialKey ctermfg=81
hi MatchParen ctermfg=233 ctermbg=208 cterm=bold
hi ModeMsg ctermfg=229
hi MoreMsg ctermfg=229
hi Operator ctermfg=161
" complete menu
hi Pmenu ctermfg=81 ctermbg=16
hi PmenuSel ctermfg=255 ctermbg=242
hi PmenuSbar ctermbg=232
hi PmenuThumb ctermfg=81
hi PreCondit ctermfg=118 cterm=bold
hi PreProc ctermfg=118
hi Question ctermfg=81
hi Repeat ctermfg=161 cterm=bold
hi Search ctermfg=0 ctermbg=222 cterm=NONE
" marks column
hi SignColumn ctermfg=118 ctermbg=235
hi SpecialChar ctermfg=161 cterm=bold
hi SpecialComment ctermfg=245 cterm=bold
hi Special ctermfg=81
if has("spell")
hi SpellBad ctermbg=52
hi SpellCap ctermbg=17
hi SpellLocal ctermbg=17
hi SpellRare ctermfg=none ctermbg=none cterm=reverse
endif
hi Statement ctermfg=161 cterm=bold
hi StatusLine ctermfg=238 ctermbg=253
hi StatusLineNC ctermfg=244 ctermbg=232
hi StorageClass ctermfg=208
hi Structure ctermfg=81
hi Tag ctermfg=161
hi Title ctermfg=166
hi Todo ctermfg=231 ctermbg=232 cterm=bold
hi Typedef ctermfg=81
hi Type ctermfg=81 cterm=none
hi Underlined ctermfg=244 cterm=underline
hi VertSplit ctermfg=244 ctermbg=232 cterm=bold
hi VisualNOS ctermbg=238
hi Visual ctermbg=235
hi WarningMsg ctermfg=231 ctermbg=238 cterm=bold
hi WildMenu ctermfg=81 ctermbg=16
hi Comment ctermfg=59
hi CursorColumn ctermbg=236
hi ColorColumn ctermbg=236
hi LineNr ctermfg=250 ctermbg=236
hi NonText ctermfg=59
hi SpecialKey ctermfg=59
if exists("g:rehash256") && g:rehash256 == 1
hi Normal ctermfg=252 ctermbg=234
hi CursorLine ctermbg=236 cterm=none
hi CursorLineNr ctermfg=208 cterm=none
hi Boolean ctermfg=141
hi Character ctermfg=222
hi Number ctermfg=141
hi String ctermfg=222
hi Conditional ctermfg=197 cterm=bold
hi Constant ctermfg=141 cterm=bold
hi DiffDelete ctermfg=125 ctermbg=233
hi Directory ctermfg=154 cterm=bold
hi Error ctermfg=222 ctermbg=233
hi Exception ctermfg=154 cterm=bold
hi Float ctermfg=141
hi Function ctermfg=154
hi Identifier ctermfg=208
hi Keyword ctermfg=197 cterm=bold
hi Operator ctermfg=197
hi PreCondit ctermfg=154 cterm=bold
hi PreProc ctermfg=154
hi Repeat ctermfg=197 cterm=bold
hi Statement ctermfg=197 cterm=bold
hi Tag ctermfg=197
hi Title ctermfg=203
hi Visual ctermbg=238
hi Comment ctermfg=244
hi LineNr ctermfg=239 ctermbg=235
hi NonText ctermfg=239
hi SpecialKey ctermfg=239
endif
end
" Must be at the end, because of ctermbg=234 bug.
" https://groups.google.com/forum/#!msg/vim_dev/afPqwAFNdrU/nqh6tOM87QUJ
set background=dark

View File

@ -0,0 +1,173 @@
*editorconfig.txt*
File: editorconfig.txt
Version: 0.3.2
Maintainer: EditorConfig Team <http://editorconfig.org>
Description: EditorConfig vim plugin
License:
Copyright (c) 2011-2013 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 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.
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_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_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_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

View File

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

View File

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

View File

@ -0,0 +1,47 @@
language: python
# We support from Python 2.4 to 2.7. However, 2.4 and 2.5 are not supported by
# travis, so they are not listed here
python:
- "2.6"
- "2.7"
- "3.2"
- "3.3"
# For testing with JYTHON=true, we will use Jython 2.2 instead of the python
# version provided by Travis CI
env:
- JYTHON=true
- JYTHON=false
matrix:
exclude:
- python: "2.5"
env: JYTHON=true
- python: "2.6"
env: JYTHON=true
- python: "3.2"
env: JYTHON=true
- python: "3.3"
env: JYTHON=true
# we need cmake, and jython if JYTHON=true
install:
- sudo apt-get install cmake
- export JYTHON_URL='http://downloads.sourceforge.net/project/jython/jython/2.2.1/jython_installer-2.2.1.jar'
- if [ "$JYTHON" == "true" ]; then wget $JYTHON_URL -O jython_installer.jar; java -jar jython_installer.jar -s -d $HOME/jython; export PATH=$HOME/jython:$PATH;jython --version; fi
# Before run the test case, we need to make jython run some code
before_script:
- if [ "$JYTHON" == "true" ]; then jython -c "print ''"; fi
# test script
script:
- if [ "$JYTHON" == "true" ]; then cmake -DPYTHON_EXECUTABLE="$(which jython)" . ; else cmake . ; fi
- ctest -VV --output-on-failure .
# Notify the mailing list
notifications:
email:
on_success: change
on_failure: always

View File

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

View File

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

View File

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

View File

@ -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 (Python 3, Jython, etc.)::
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.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,19 @@
"""EditorConfig Python Core"""
from editorconfig.versiontools import join_version
VERSION = (0, 11, 3, "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 *

View File

@ -0,0 +1,18 @@
"""EditorConfig Python2/Python3/Jython compatibility utilities"""
import sys
import types
__all__ = ['slice', 'u']
if sys.version_info[0] == 2:
slice = types.SliceType
else:
slice = slice
if sys.version_info[0] == 2:
import codecs
u = lambda s: codecs.unicode_escape_decode(s)[0]
else:
u = lambda s: s

View File

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

View File

@ -0,0 +1,126 @@
"""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 = {}
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 fnmatchcase(name, pat):
"""Test whether FILENAME matches PATTERN, including case.
This is a version of fnmatch() which doesn't case-normalize
its arguments.
"""
if not pat in _cache:
res = translate(pat)
_cache[pat] = re.compile(res)
return _cache[pat].match(name) is not None
def translate(pat):
"""Translate a shell PATTERN to a regular expression.
There is no way to quote meta-characters.
"""
i, n = 0, len(pat)
res = ''
escaped = False
while i < n:
c = pat[i]
i = i + 1
if c == '*':
j = i
if j < n and pat[j] == '*':
res = res + '.*'
else:
res = res + '[^/]*'
elif c == '?':
res = res + '.'
elif c == '[':
j = i
if j < n and pat[j] == '!':
j = j + 1
if j < n and pat[j] == ']':
j = j + 1
while j < n and (pat[j] != ']' or escaped):
escaped = pat[j] == '\\' and not escaped
j = j + 1
if j >= n:
res = res + '\\['
else:
stuff = pat[i:j]
i = j + 1
if stuff[0] == '!':
stuff = '^' + stuff[1:]
elif stuff[0] == '^':
stuff = '\\' + stuff
res = '%s[%s]' % (res, stuff)
elif c == '{':
j = i
groups = []
while j < n and pat[j] != '}':
k = j
while k < n and (pat[k] not in (',', '}') or escaped):
escaped = pat[k] == '\\' and not escaped
k = k + 1
group = pat[j:k]
for char in (',', '}', '\\'):
group = group.replace('\\' + char, char)
groups.append(group)
j = k
if j < n and pat[j] == ',':
j = j + 1
if j < n and pat[j] == '}':
groups.append('')
if j >= n or len(groups) < 2:
res = res + '\\{'
else:
res = '%s(%s)' % (res, '|'.join(map(re.escape, groups)))
i = j + 1
else:
res = res + re.escape(c)
return res + '\Z(?ms)'

View File

@ -0,0 +1,126 @@
"""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"]

View File

@ -0,0 +1,150 @@
"""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 normcase, 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*\[' # [
r'(?P<header>([^#;]|\\#|\\;)+)' # very permissive!
r'\]' # ]
)
# 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*(?P<option>[^:=\s][^:=]*)'
r'\s*(?P<vi>[:=])\s*'
r'(?P<value>.*)$'
)
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 = normcase(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()

View File

@ -0,0 +1,76 @@
"""EditorConfig command line interface
Licensed under PSF License (see LICENSE.txt file).
"""
import getopt
import sys
from editorconfig import __version__, VERSION
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(sys.argv[1:], "vhb:f:", ["version", "help"])
except getopt.GetoptError:
print(str(sys.exc_info()[1])) # For Python 2/3 compatibility
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):
print(str(sys.exc_info()[1])) # For Python 2/3 compatibility
sys.exit(2)
if multiple_files:
print("[%s]" % filename)
for key, value in options.items():
print("%s=%s" % (key, value))

View File

@ -0,0 +1,899 @@
"""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
from editorconfig.compat import slice
__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)

View File

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

View File

@ -0,0 +1 @@
The java binding has been moved to: https://github.com/editorconfig/editorconfig-core-java-binding

View File

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

View File

@ -0,0 +1,18 @@
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',
]
},
)

View File

@ -0,0 +1,581 @@
" 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
" 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
" 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_core_mode') && !empty(g:EditorConfig_core_mode)
let s:editorconfig_core_mode = g:EditorConfig_core_mode
else
let s:editorconfig_core_mode = ''
endif
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
" On Windows, we still use slash rather than backslash
let l:old_shellslash = &shellslash
set shellslash
let l:python_core_files_dir = substitute(
\ findfile(g:EditorConfig_python_files_dir . '/main.py',
\ ','.&runtimepath), '/main.py$', '', '')
if empty(l:python_core_files_dir)
return ''
endif
" 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'), '/$', '', '')
let &shellslash = l:old_shellslash
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
let l:ret = 0
if !has('python')
return 1
endif
python << EEOOFF
try:
import vim
import sys
except:
vim.command('let l:ret = 2')
EEOOFF
if l:ret != 0
return l:ret
endif
python << EEOOFF
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')
del sys.path[0]
ec_data = {} # used in order to keep clean Python namespace
EEOOFF
if l:ret != 0
return l:ret
endif
return 0
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()
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! editorconfig
autocmd editorconfig BufNewFile,BufReadPost * call s:UseConfigFiles()
autocmd editorconfig 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
let l:config = {}
let l:ret = 0
" ignore buffers that do not have a file path associated
if empty(expand('%:p'))
return 0
endif
python << EEOOFF
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, e:
if int(vim.eval('g:EditorConfig_verbose')) != 0:
print >> sys.stderr, str(e)
vim.command('let l:ret = 1')
EEOOFF
if l:ret != 0
return l:ret
endif
python << EEOOFF
for key, value in ec_data['options'].items():
vim.command("let l:config['" + key.replace("'", "''") + "'] = " +
"'" + value.replace("'", "''") + "'")
EEOOFF
call s:ApplyConfig(l:config)
return 0
endfunction
function! s:UseConfigFiles_Python_External() " {{{2
" Use external python interp to run the python EditorConfig Core
let l:cmd = s:editorconfig_python_interp . ' ' .
\ s:editorconfig_core_py_dir . '/main.py'
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:SpawnExternalParser(s:EditorConfig_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 = {}
" 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.
let l:old_shellslash = &l:shellslash
setlocal noshellslash
let l:cmd = l:cmd . ' ' . shellescape(expand('%:p'))
let &l:shellslash = l:old_shellslash
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
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
" 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
" use a buffer variable test because we need per buffer handling, but buffer
" local generic autocmds are not individually targetable for deletion and
" a self clearing group of buffer local autocmds clobbers all buffers but
" the one it is last defined in.
if get(a:config, 'trim_trailing_whitespace', 'false') ==# 'true'
augroup editorconfig_trim_trailing_whitespace
autocmd! editorconfig_trim_trailing_whitespace
autocmd BufWritePre * if get(b:,
\ 'editorconfig_trim_trailing_whitespace', 0) == 1
\ | :%s/\s\+$//e
\ | endif
augroup END
let b:editorconfig_trim_trailing_whitespace = 1
elseif exists('b:editorconfig_trim_trailing_whitespace')
unlet b:editorconfig_trim_trailing_whitespace
endif
if has_key(a:config, "insert_final_newline")
if a:config["insert_final_newline"] == "false"
silent! SetNoEOL " Use the PreserveNoEOL plugin to accomplish it
endif
endif
if has_key(a:config, 'max_line_length')
let l:max_line_length = str2nr(a:config['max_line_length'])
if l:max_line_length > 0
let &l:textwidth = l:max_line_length
" highlight the column
if exists('+colorcolumn')
let &l:colorcolumn = l:max_line_length
endif
endif
endif
call editorconfig#ApplyHooks(a:config)
endfunction
" }}}
let &cpo = s:saved_cpo
unlet! s:saved_cpo
" vim: fdm=marker fdc=3

View File

@ -131,7 +131,8 @@ let perl_extended_vars = 1
""""""""""""""""
" expand tabs for python code
autocmd BufRead,BufNewFile *.py set expandtab
" Using editorconfig for this instead!
"autocmd BufRead,BufNewFile *.py set expandtab
"""""""""""""""""""""""""""""""""
""" Compatibility with fish shell