1
0
Fork 0
mirror of synced 2024-12-22 06:51:06 -05:00

Updated plugins. Switched to Ack as standard search tool (much better than grep/vimgrep)

This commit is contained in:
amix 2014-02-07 10:41:15 +00:00
parent e62adb8084
commit 8265dca5d5
76 changed files with 3855 additions and 143 deletions

View file

@ -259,7 +259,7 @@ function! s:goyo_off()
for [k, v] in items(goyo_revert) for [k, v] in items(goyo_revert)
execute printf("let &%s = %s", k, string(v)) execute printf("let &%s = %s", k, string(v))
endfor endfor
execute 'colo '. g:colors_name execute 'colo '. get(g:, 'colors_name', 'default')
if goyo_disabled_gitgutter if goyo_disabled_gitgutter
silent! GitGutterEnable silent! GitGutterEnable
@ -267,7 +267,7 @@ function! s:goyo_off()
if goyo_disabled_airline && !exists("#airline") if goyo_disabled_airline && !exists("#airline")
AirlineToggle AirlineToggle
AirlineRefresh silent! AirlineRefresh
endif endif
if goyo_disabled_powerline && !exists("#PowerlineMain") if goyo_disabled_powerline && !exists("#PowerlineMain")

View file

@ -0,0 +1 @@
*.pyc

View file

@ -0,0 +1,11 @@
Pyflakes
==========
This is just a manual dump of the vim pyflakes plugin from:
http://www.vim.org/scripts/script.php?script_id=2441
The purpose is to try to make this compatible with pathogen plugin. So creating
the dir structure and hopefully this means we can just keep the norm and git
clone the repo into the bundle directory and things will load up magically.

View file

@ -0,0 +1,80 @@
pyflakes-vim
============
A Vim plugin for checking Python code on the fly.
PyFlakes catches common Python errors like mistyping a variable name or
accessing a local before it is bound, and also gives warnings for things like
unused imports.
pyflakes-vim uses the output from PyFlakes to highlight errors in your code.
To locate errors quickly, use quickfix_ commands like :cc.
Make sure to check vim.org_ for the latest updates.
.. _pyflakes.vim: http://www.vim.org/scripts/script.php?script_id=2441
.. _vim.org: http://www.vim.org/scripts/script.php?script_id=2441
.. _quickfix: http://vimdoc.sourceforge.net/htmldoc/quickfix.html#quickfix
Quick Installation
------------------
1. Make sure your ``.vimrc`` has::
filetype on " enables filetype detection
filetype plugin on " enables filetype specific plugins
2. Download the latest release_.
3. Unzip ``pyflakes.vim`` and the ``pyflakes`` directory into
``~/.vim/ftplugin/python`` (or somewhere similar on your
`runtime path`_ that will be sourced for Python files).
.. _release: http://www.vim.org/scripts/script.php?script_id=2441
.. _runtime path: http://vimdoc.sourceforge.net/htmldoc/options.html#'runtimepath'
Installation
------------
If you downloaded this from vim.org_, then just drop the contents of the zip
file into ``~/.vim/ftplugin/python``.
Otherwise, if you're running "from source," you'll need PyFlakes on your
PYTHONPATH somewhere. I recommend getting my PyFlakes_ fork, which retains
column number information and has therfore has more specific error locations.
.. _vim.org: http://www.vim.org/scripts/script.php?script_id=2441
.. _PyFlakes: http://github.com/kevinw/pyflakes
Hacking
-------
::
git clone git://github.com/kevinw/pyflakes-vim.git
cd pyflakes-vim
git clone git://github.com/kevinw/pyflakes.git
Options
-------
Set this option to you vimrc file to disable quickfix support::
let g:pyflakes_use_quickfix = 0
The value is set to 1 by default.
TODO
----
* signs_ support (show warning and error icons to left of the buffer area)
* configuration variables
* parse or intercept useful output from the warnings module
.. _signs: http://www.vim.org/htmldoc/sign.html
Changelog
---------
Please see http://www.vim.org/scripts/script.php?script_id=2441 for a history of
all changes.

View file

@ -0,0 +1,325 @@
" pyflakes.vim - A script to highlight Python code on the fly with warnings
" from Pyflakes, a Python lint tool.
"
" Place this script and the accompanying pyflakes directory in
" .vim/ftplugin/python.
"
" See README for additional installation and information.
"
" Thanks to matlib.vim for ideas/code on interactive linting.
"
" Maintainer: Kevin Watters <kevin.watters@gmail.com>
" Version: 0.1
if !has('python')
" exit if python is not available.
finish
endif
if exists("b:did_pyflakes_plugin")
finish " only load once
else
let b:did_pyflakes_plugin = 1
endif
if !exists('g:pyflakes_builtins')
let g:pyflakes_builtins = []
endif
if !exists("b:did_python_init")
let b:did_python_init = 0
if !has('python')
echoerr "Error: the pyflakes.vim plugin requires Vim to be compiled with +python"
finish
endif
if !exists('g:pyflakes_use_quickfix')
let g:pyflakes_use_quickfix = 1
endif
python << EOF
import vim
import os.path
import sys
if sys.version_info[:2] < (2, 5):
raise AssertionError('Vim must be compiled with Python 2.5 or higher; you have ' + sys.version)
# get the directory this script is in: the pyflakes python module should be installed there.
scriptdir = os.path.join(os.path.dirname(vim.eval('expand("<sfile>")')), 'pyflakes')
sys.path.insert(0, scriptdir)
import ast
from pyflakes import checker, messages
from operator import attrgetter
import re
class loc(object):
def __init__(self, lineno, col=None):
self.lineno = lineno
self.col_offset = col
class SyntaxError(messages.Message):
message = 'could not compile: %s'
def __init__(self, filename, lineno, col, message):
messages.Message.__init__(self, filename, loc(lineno, col))
self.message_args = (message,)
class blackhole(object):
write = flush = lambda *a, **k: None
def check(buffer):
filename = buffer.name
contents = buffer[:]
# shebang usually found at the top of the file, followed by source code encoding marker.
# assume everything else that follows is encoded in the encoding.
encoding_found = False
for n, line in enumerate(contents):
if n >= 2:
break
elif re.match(r'#.*coding[:=]\s*([-\w.]+)', line):
contents = ['']*(n+1) + contents[n+1:]
break
contents = '\n'.join(contents) + '\n'
vimenc = vim.eval('&encoding')
if vimenc:
contents = contents.decode(vimenc)
builtins = set(['__file__'])
try:
builtins.update(set(eval(vim.eval('string(g:pyflakes_builtins)'))))
except Exception:
pass
try:
# TODO: use warnings filters instead of ignoring stderr
old_stderr, sys.stderr = sys.stderr, blackhole()
try:
tree = ast.parse(contents, filename or '<unknown>')
finally:
sys.stderr = old_stderr
except:
try:
value = sys.exc_info()[1]
lineno, offset, line = value[1][1:]
except IndexError:
lineno, offset, line = 1, 0, ''
if line and line.endswith("\n"):
line = line[:-1]
return [SyntaxError(filename, lineno, offset, str(value))]
else:
# pyflakes looks to _MAGIC_GLOBALS in checker.py to see which
# UndefinedNames to ignore
old_globals = getattr(checker,' _MAGIC_GLOBALS', [])
checker._MAGIC_GLOBALS = set(old_globals) | builtins
w = checker.Checker(tree, filename)
checker._MAGIC_GLOBALS = old_globals
w.messages.sort(key = attrgetter('lineno'))
return w.messages
def vim_quote(s):
return s.replace("'", "''")
EOF
let b:did_python_init = 1
endif
if !b:did_python_init
finish
endif
au BufLeave <buffer> call s:ClearPyflakes()
au BufEnter <buffer> call s:RunPyflakes()
au InsertLeave <buffer> call s:RunPyflakes()
au InsertEnter <buffer> call s:RunPyflakes()
au BufWritePost <buffer> call s:RunPyflakes()
au CursorHold <buffer> call s:RunPyflakes()
au CursorHoldI <buffer> call s:RunPyflakes()
au CursorHold <buffer> call s:GetPyflakesMessage()
au CursorMoved <buffer> call s:GetPyflakesMessage()
if !exists("*s:PyflakesUpdate")
function s:PyflakesUpdate()
silent call s:RunPyflakes()
call s:GetPyflakesMessage()
endfunction
endif
" Call this function in your .vimrc to update PyFlakes
if !exists(":PyflakesUpdate")
command PyflakesUpdate :call s:PyflakesUpdate()
endif
" Hook common text manipulation commands to update PyFlakes
" TODO: is there a more general "text op" autocommand we could register
" for here?
noremap <buffer><silent> dd dd:PyflakesUpdate<CR>
noremap <buffer><silent> dw dw:PyflakesUpdate<CR>
noremap <buffer><silent> u u:PyflakesUpdate<CR>
noremap <buffer><silent> <C-R> <C-R>:PyflakesUpdate<CR>
" WideMsg() prints [long] message up to (&columns-1) length
" guaranteed without "Press Enter" prompt.
if !exists("*s:WideMsg")
function s:WideMsg(msg)
let x=&ruler | let y=&showcmd
set noruler noshowcmd
redraw
echo strpart(a:msg, 0, &columns-1)
let &ruler=x | let &showcmd=y
endfun
endif
if !exists("*s:GetQuickFixStackCount")
function s:GetQuickFixStackCount()
let l:stack_count = 0
try
silent colder 9
catch /E380:/
endtry
try
for i in range(9)
silent cnewer
let l:stack_count = l:stack_count + 1
endfor
catch /E381:/
return l:stack_count
endtry
endfunction
endif
if !exists("*s:ActivatePyflakesQuickFixWindow")
function s:ActivatePyflakesQuickFixWindow()
try
silent colder 9 " go to the bottom of quickfix stack
catch /E380:/
endtry
if s:pyflakes_qf > 0
try
exe "silent cnewer " . s:pyflakes_qf
catch /E381:/
echoerr "Could not activate Pyflakes Quickfix Window."
endtry
endif
endfunction
endif
if !exists("*s:RunPyflakes")
function s:RunPyflakes()
highlight link PyFlakes SpellBad
if exists("b:cleared")
if b:cleared == 0
silent call s:ClearPyflakes()
let b:cleared = 1
endif
else
let b:cleared = 1
endif
let b:matched = []
let b:matchedlines = {}
let b:qf_list = []
let b:qf_window_count = -1
python << EOF
for w in check(vim.current.buffer):
vim.command('let s:matchDict = {}')
vim.command("let s:matchDict['lineNum'] = " + str(w.lineno))
vim.command("let s:matchDict['message'] = '%s'" % vim_quote(w.message % w.message_args))
vim.command("let b:matchedlines[" + str(w.lineno) + "] = s:matchDict")
vim.command("let l:qf_item = {}")
vim.command("let l:qf_item.bufnr = bufnr('%')")
vim.command("let l:qf_item.filename = expand('%')")
vim.command("let l:qf_item.lnum = %s" % str(w.lineno))
vim.command("let l:qf_item.text = '%s'" % vim_quote(w.message % w.message_args))
vim.command("let l:qf_item.type = 'E'")
if getattr(w, 'col', None) is None or isinstance(w, SyntaxError):
# without column information, just highlight the whole line
# (minus the newline)
vim.command(r"let s:mID = matchadd('PyFlakes', '\%" + str(w.lineno) + r"l\n\@!')")
else:
# with a column number, highlight the first keyword there
vim.command(r"let s:mID = matchadd('PyFlakes', '^\%" + str(w.lineno) + r"l\_.\{-}\zs\k\+\k\@!\%>" + str(w.col) + r"c')")
vim.command("let l:qf_item.vcol = 1")
vim.command("let l:qf_item.col = %s" % str(w.col + 1))
vim.command("call add(b:matched, s:matchDict)")
vim.command("call add(b:qf_list, l:qf_item)")
EOF
if g:pyflakes_use_quickfix == 1
if exists("s:pyflakes_qf")
" if pyflakes quickfix window is already created, reuse it
call s:ActivatePyflakesQuickFixWindow()
call setqflist(b:qf_list, 'r')
else
" one pyflakes quickfix window for all buffer
call setqflist(b:qf_list, '')
let s:pyflakes_qf = s:GetQuickFixStackCount()
endif
endif
let b:cleared = 0
endfunction
end
" keep track of whether or not we are showing a message
let b:showing_message = 0
if !exists("*s:GetPyflakesMessage")
function s:GetPyflakesMessage()
let s:cursorPos = getpos(".")
" Bail if RunPyflakes hasn't been called yet.
if !exists('b:matchedlines')
return
endif
" if there's a message for the line the cursor is currently on, echo
" it to the console
if has_key(b:matchedlines, s:cursorPos[1])
let s:pyflakesMatch = get(b:matchedlines, s:cursorPos[1])
call s:WideMsg(s:pyflakesMatch['message'])
let b:showing_message = 1
return
endif
" otherwise, if we're showing a message, clear it
if b:showing_message == 1
echo
let b:showing_message = 0
endif
endfunction
endif
if !exists('*s:ClearPyflakes')
function s:ClearPyflakes()
let s:matches = getmatches()
for s:matchId in s:matches
if s:matchId['group'] == 'PyFlakes'
call matchdelete(s:matchId['id'])
endif
endfor
let b:matched = []
let b:matchedlines = {}
let b:cleared = 1
endfunction
endif

View file

@ -0,0 +1,21 @@
Copyright (c) 2005 Divmod, Inc., http://www.divmod.com/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,29 @@
0.4.0 (2009-11-25):
- Fix reporting for certain SyntaxErrors which lack line number
information.
- Check for syntax errors more rigorously.
- Support checking names used with the class decorator syntax in versions
of Python which have it.
- Detect local variables which are bound but never used.
- Handle permission errors when trying to read source files.
- Handle problems with the encoding of source files.
- Support importing dotted names so as not to incorrectly report them as
redefined unused names.
- Support all forms of the with statement.
- Consider static `__all__` definitions and avoid reporting unused names
if the names are listed there.
- Fix incorrect checking of class names with respect to the names of their
bases in the class statement.
- Support the `__path__` global in `__init__.py`.
0.3.0 (2009-01-30):
- Display more informative SyntaxError messages.
- Don't hang flymake with unmatched triple quotes (only report a single
line of source for a multiline syntax error).
- Recognize __builtins__ as a defined name.
- Improve pyflakes support for python versions 2.3-2.5
- Support for if-else expressions and with statements.
- Warn instead of error on non-existant file paths.
- Check for __future__ imports after other statements.
- Add reporting for some types of import shadowing.
- Improve reporting of unbound locals

View file

@ -0,0 +1,36 @@
pyflakes
========
This version of PyFlakes_ has been improved to use Python's newer ``ast``
module, instead of ``compiler``. So code checking happens faster, and will stay
up to date with new language changes.
.. _PyFlakes: http://http://www.divmod.org/trac/wiki/DivmodPyflakes
TODO
----
Importing several modules from the same package results in unnecessary warnings:
::
import a.b
import a.c # Redefinition of unused "a" from line 1
The following construct for defining a function differently depending on some
condition results in a redefinition warning:
::
if some_condition:
def foo(): do_foo()
else:
def foo(): do_bar() # redefinition of function 'foo' from line 2
IDE Integration
---------------
* vim: pyflakes-vim_
.. _pyflakes-vim: http://github.com/kevinw/pyflakes-vim

View file

@ -0,0 +1,11 @@
- Check for methods that override other methods except that they vary by case.
- assign/increment + unbound local error not caught
def foo():
bar = 5
def meep():
bar += 2
meep()
print bar
print foo()

View file

@ -0,0 +1,2 @@
__version__ = '0.4.0'

View file

@ -0,0 +1,311 @@
# -*- coding: utf-8 -*-
"""
ast
~~~
The `ast` module helps Python applications to process trees of the Python
abstract syntax grammar. The abstract syntax itself might change with
each Python release; this module helps to find out programmatically what
the current grammar looks like and allows modifications of it.
An abstract syntax tree can be generated by passing `ast.PyCF_ONLY_AST` as
a flag to the `compile()` builtin function or by using the `parse()`
function from this module. The result will be a tree of objects whose
classes all inherit from `ast.AST`.
A modified abstract syntax tree can be compiled into a Python code object
using the built-in `compile()` function.
Additionally various helper functions are provided that make working with
the trees simpler. The main intention of the helper functions and this
module in general is to provide an easy to use interface for libraries
that work tightly with the python syntax (template engines for example).
:copyright: Copyright 2008 by Armin Ronacher.
:license: Python License.
"""
from _ast import *
from _ast import __version__
def parse(expr, filename='<unknown>', mode='exec'):
"""
Parse an expression into an AST node.
Equivalent to compile(expr, filename, mode, PyCF_ONLY_AST).
"""
return compile(expr, filename, mode, PyCF_ONLY_AST)
def literal_eval(node_or_string):
"""
Safely evaluate an expression node or a string containing a Python
expression. The string or node provided may only consist of the following
Python literal structures: strings, numbers, tuples, lists, dicts, booleans,
and None.
"""
_safe_names = {'None': None, 'True': True, 'False': False}
if isinstance(node_or_string, basestring):
node_or_string = parse(node_or_string, mode='eval')
if isinstance(node_or_string, Expression):
node_or_string = node_or_string.body
def _convert(node):
if isinstance(node, Str):
return node.s
elif isinstance(node, Num):
return node.n
elif isinstance(node, Tuple):
return tuple(map(_convert, node.elts))
elif isinstance(node, List):
return list(map(_convert, node.elts))
elif isinstance(node, Dict):
return dict((_convert(k), _convert(v)) for k, v
in zip(node.keys, node.values))
elif isinstance(node, Name):
if node.id in _safe_names:
return _safe_names[node.id]
raise ValueError('malformed string')
return _convert(node_or_string)
def dump(node, annotate_fields=True, include_attributes=False):
"""
Return a formatted dump of the tree in *node*. This is mainly useful for
debugging purposes. The returned string will show the names and the values
for fields. This makes the code impossible to evaluate, so if evaluation is
wanted *annotate_fields* must be set to False. Attributes such as line
numbers and column offsets are not dumped by default. If this is wanted,
*include_attributes* can be set to True.
"""
def _format(node):
if isinstance(node, AST):
fields = [(a, _format(b)) for a, b in iter_fields(node)]
rv = '%s(%s' % (node.__class__.__name__, ', '.join(
('%s=%s' % field for field in fields)
if annotate_fields else
(b for a, b in fields)
))
if include_attributes and node._attributes:
rv += fields and ', ' or ' '
rv += ', '.join('%s=%s' % (a, _format(getattr(node, a)))
for a in node._attributes)
return rv + ')'
elif isinstance(node, list):
return '[%s]' % ', '.join(_format(x) for x in node)
return repr(node)
if not isinstance(node, AST):
raise TypeError('expected AST, got %r' % node.__class__.__name__)
return _format(node)
def copy_location(new_node, old_node):
"""
Copy source location (`lineno` and `col_offset` attributes) from
*old_node* to *new_node* if possible, and return *new_node*.
"""
for attr in 'lineno', 'col_offset':
if attr in old_node._attributes and attr in new_node._attributes \
and hasattr(old_node, attr):
setattr(new_node, attr, getattr(old_node, attr))
return new_node
def fix_missing_locations(node):
"""
When you compile a node tree with compile(), the compiler expects lineno and
col_offset attributes for every node that supports them. This is rather
tedious to fill in for generated nodes, so this helper adds these attributes
recursively where not already set, by setting them to the values of the
parent node. It works recursively starting at *node*.
"""
def _fix(node, lineno, col_offset):
if 'lineno' in node._attributes:
if not hasattr(node, 'lineno'):
node.lineno = lineno
else:
lineno = node.lineno
if 'col_offset' in node._attributes:
if not hasattr(node, 'col_offset'):
node.col_offset = col_offset
else:
col_offset = node.col_offset
for child in iter_child_nodes(node):
_fix(child, lineno, col_offset)
_fix(node, 1, 0)
return node
def add_col_end(node):
def _fix(node, next):
children = list(iter_child_nodes(node))
for i, child in enumerate(children):
next_offset = children[i+1].col_offset if i < len(children) else next.col_offset
child.col_end = next_offset
def increment_lineno(node, n=1):
"""
Increment the line number of each node in the tree starting at *node* by *n*.
This is useful to "move code" to a different location in a file.
"""
if 'lineno' in node._attributes:
node.lineno = getattr(node, 'lineno', 0) + n
for child in walk(node):
if 'lineno' in child._attributes:
child.lineno = getattr(child, 'lineno', 0) + n
return node
def iter_fields(node):
"""
Yield a tuple of ``(fieldname, value)`` for each field in ``node._fields``
that is present on *node*.
"""
if node._fields is None:
return
for field in node._fields:
try:
yield field, getattr(node, field)
except AttributeError:
pass
def iter_child_nodes(node):
"""
Yield all direct child nodes of *node*, that is, all fields that are nodes
and all items of fields that are lists of nodes.
"""
for name, field in iter_fields(node):
if isinstance(field, AST):
yield field
elif isinstance(field, list):
for item in field:
if isinstance(item, AST):
yield item
def get_docstring(node, clean=True):
"""
Return the docstring for the given node or None if no docstring can
be found. If the node provided does not have docstrings a TypeError
will be raised.
"""
if not isinstance(node, (FunctionDef, ClassDef, Module)):
raise TypeError("%r can't have docstrings" % node.__class__.__name__)
if node.body and isinstance(node.body[0], Expr) and \
isinstance(node.body[0].value, Str):
if clean:
import inspect
return inspect.cleandoc(node.body[0].value.s)
return node.body[0].value.s
def walk(node):
"""
Recursively yield all child nodes of *node*, in no specified order. This is
useful if you only want to modify nodes in place and don't care about the
context.
"""
from collections import deque
todo = deque([node])
while todo:
node = todo.popleft()
todo.extend(iter_child_nodes(node))
yield node
class NodeVisitor(object):
"""
A node visitor base class that walks the abstract syntax tree and calls a
visitor function for every node found. This function may return a value
which is forwarded by the `visit` method.
This class is meant to be subclassed, with the subclass adding visitor
methods.
Per default the visitor functions for the nodes are ``'visit_'`` +
class name of the node. So a `TryFinally` node visit function would
be `visit_TryFinally`. This behavior can be changed by overriding
the `visit` method. If no visitor function exists for a node
(return value `None`) the `generic_visit` visitor is used instead.
Don't use the `NodeVisitor` if you want to apply changes to nodes during
traversing. For this a special visitor exists (`NodeTransformer`) that
allows modifications.
"""
def visit(self, node):
"""Visit a node."""
method = 'visit_' + node.__class__.__name__
visitor = getattr(self, method, self.generic_visit)
return visitor(node)
def generic_visit(self, node):
"""Called if no explicit visitor function exists for a node."""
for field, value in iter_fields(node):
if isinstance(value, list):
for item in value:
if isinstance(item, AST):
self.visit(item)
elif isinstance(value, AST):
self.visit(value)
class NodeTransformer(NodeVisitor):
"""
A :class:`NodeVisitor` subclass that walks the abstract syntax tree and
allows modification of nodes.
The `NodeTransformer` will walk the AST and use the return value of the
visitor methods to replace or remove the old node. If the return value of
the visitor method is ``None``, the node will be removed from its location,
otherwise it is replaced with the return value. The return value may be the
original node in which case no replacement takes place.
Here is an example transformer that rewrites all occurrences of name lookups
(``foo``) to ``data['foo']``::
class RewriteName(NodeTransformer):
def visit_Name(self, node):
return copy_location(Subscript(
value=Name(id='data', ctx=Load()),
slice=Index(value=Str(s=node.id)),
ctx=node.ctx
), node)
Keep in mind that if the node you're operating on has child nodes you must
either transform the child nodes yourself or call the :meth:`generic_visit`
method for the node first.
For nodes that were part of a collection of statements (that applies to all
statement nodes), the visitor may also return a list of nodes rather than
just a single node.
Usually you use the transformer like this::
node = YourTransformer().visit(node)
"""
def generic_visit(self, node):
for field, old_value in iter_fields(node):
old_value = getattr(node, field, None)
if isinstance(old_value, list):
new_values = []
for value in old_value:
if isinstance(value, AST):
value = self.visit(value)
if value is None:
continue
elif not isinstance(value, AST):
new_values.extend(value)
continue
new_values.append(value)
old_value[:] = new_values
elif isinstance(old_value, AST):
new_node = self.visit(old_value)
if new_node is None:
delattr(node, field)
else:
setattr(node, field, new_node)
return node

View file

@ -0,0 +1,625 @@
# -*- test-case-name: pyflakes -*-
# (c) 2005-2010 Divmod, Inc.
# See LICENSE file for details
import __builtin__
import os.path
import _ast
from pyflakes import messages
# utility function to iterate over an AST node's children, adapted
# from Python 2.6's standard ast module
try:
import ast
iter_child_nodes = ast.iter_child_nodes
except (ImportError, AttributeError):
def iter_child_nodes(node, astcls=_ast.AST):
"""
Yield all direct child nodes of *node*, that is, all fields that are nodes
and all items of fields that are lists of nodes.
"""
for name in node._fields:
field = getattr(node, name, None)
if isinstance(field, astcls):
yield field
elif isinstance(field, list):
for item in field:
yield item
class Binding(object):
"""
Represents the binding of a value to a name.
The checker uses this to keep track of which names have been bound and
which names have not. See L{Assignment} for a special type of binding that
is checked with stricter rules.
@ivar used: pair of (L{Scope}, line-number) indicating the scope and
line number that this binding was last used
"""
def __init__(self, name, source):
self.name = name
self.source = source
self.used = False
def __str__(self):
return self.name
def __repr__(self):
return '<%s object %r from line %r at 0x%x>' % (self.__class__.__name__,
self.name,
self.source.lineno,
id(self))
class UnBinding(Binding):
'''Created by the 'del' operator.'''
class Importation(Binding):
"""
A binding created by an import statement.
@ivar fullName: The complete name given to the import statement,
possibly including multiple dotted components.
@type fullName: C{str}
"""
def __init__(self, name, source):
self.fullName = name
name = name.split('.')[0]
super(Importation, self).__init__(name, source)
class Argument(Binding):
"""
Represents binding a name as an argument.
"""
class Assignment(Binding):
"""
Represents binding a name with an explicit assignment.
The checker will raise warnings for any Assignment that isn't used. Also,
the checker does not consider assignments in tuple/list unpacking to be
Assignments, rather it treats them as simple Bindings.
"""
class FunctionDefinition(Binding):
pass
class ExportBinding(Binding):
"""
A binding created by an C{__all__} assignment. If the names in the list
can be determined statically, they will be treated as names for export and
additional checking applied to them.
The only C{__all__} assignment that can be recognized is one which takes
the value of a literal list containing literal strings. For example::
__all__ = ["foo", "bar"]
Names which are imported and not otherwise used but appear in the value of
C{__all__} will not have an unused import warning reported for them.
"""
def names(self):
"""
Return a list of the names referenced by this binding.
"""
names = []
if isinstance(self.source, _ast.List):
for node in self.source.elts:
if isinstance(node, _ast.Str):
names.append(node.s)
return names
class Scope(dict):
importStarred = False # set to True when import * is found
def __repr__(self):
return '<%s at 0x%x %s>' % (self.__class__.__name__, id(self), dict.__repr__(self))
def __init__(self):
super(Scope, self).__init__()
class ClassScope(Scope):
pass
class FunctionScope(Scope):
"""
I represent a name scope for a function.
@ivar globals: Names declared 'global' in this function.
"""
def __init__(self):
super(FunctionScope, self).__init__()
self.globals = {}
class ModuleScope(Scope):
pass
# Globally defined names which are not attributes of the __builtin__ module.
_MAGIC_GLOBALS = ['__file__', '__builtins__']
class Checker(object):
"""
I check the cleanliness and sanity of Python code.
@ivar _deferredFunctions: Tracking list used by L{deferFunction}. Elements
of the list are two-tuples. The first element is the callable passed
to L{deferFunction}. The second element is a copy of the scope stack
at the time L{deferFunction} was called.
@ivar _deferredAssignments: Similar to C{_deferredFunctions}, but for
callables which are deferred assignment checks.
"""
nodeDepth = 0
traceTree = False
def __init__(self, tree, filename='(none)'):
self._deferredFunctions = []
self._deferredAssignments = []
self.dead_scopes = []
self.messages = []
self.filename = filename
self.scopeStack = [ModuleScope()]
self.futuresAllowed = True
self.handleChildren(tree)
self._runDeferred(self._deferredFunctions)
# Set _deferredFunctions to None so that deferFunction will fail
# noisily if called after we've run through the deferred functions.
self._deferredFunctions = None
self._runDeferred(self._deferredAssignments)
# Set _deferredAssignments to None so that deferAssignment will fail
# noisly if called after we've run through the deferred assignments.
self._deferredAssignments = None
del self.scopeStack[1:]
self.popScope()
self.check_dead_scopes()
def deferFunction(self, callable):
'''
Schedule a function handler to be called just before completion.
This is used for handling function bodies, which must be deferred
because code later in the file might modify the global scope. When
`callable` is called, the scope at the time this is called will be
restored, however it will contain any new bindings added to it.
'''
self._deferredFunctions.append((callable, self.scopeStack[:]))
def deferAssignment(self, callable):
"""
Schedule an assignment handler to be called just after deferred
function handlers.
"""
self._deferredAssignments.append((callable, self.scopeStack[:]))
def _runDeferred(self, deferred):
"""
Run the callables in C{deferred} using their associated scope stack.
"""
for handler, scope in deferred:
self.scopeStack = scope
handler()
def scope(self):
return self.scopeStack[-1]
scope = property(scope)
def popScope(self):
self.dead_scopes.append(self.scopeStack.pop())
def check_dead_scopes(self):
"""
Look at scopes which have been fully examined and report names in them
which were imported but unused.
"""
for scope in self.dead_scopes:
export = isinstance(scope.get('__all__'), ExportBinding)
if export:
all = scope['__all__'].names()
if os.path.split(self.filename)[1] != '__init__.py':
# Look for possible mistakes in the export list
undefined = set(all) - set(scope)
for name in undefined:
self.report(
messages.UndefinedExport,
scope['__all__'].source,
name)
else:
all = []
# Look for imported names that aren't used.
for importation in scope.itervalues():
if isinstance(importation, Importation):
if not importation.used and importation.name not in all:
self.report(
messages.UnusedImport,
importation.source,
importation.name)
def pushFunctionScope(self):
self.scopeStack.append(FunctionScope())
def pushClassScope(self):
self.scopeStack.append(ClassScope())
def report(self, messageClass, *args, **kwargs):
self.messages.append(messageClass(self.filename, *args, **kwargs))
def handleChildren(self, tree):
for node in iter_child_nodes(tree):
self.handleNode(node, tree)
def isDocstring(self, node):
"""
Determine if the given node is a docstring, as long as it is at the
correct place in the node tree.
"""
return isinstance(node, _ast.Str) or \
(isinstance(node, _ast.Expr) and
isinstance(node.value, _ast.Str))
def handleNode(self, node, parent):
node.parent = parent
if self.traceTree:
print ' ' * self.nodeDepth + node.__class__.__name__
self.nodeDepth += 1
if self.futuresAllowed and not \
(isinstance(node, _ast.ImportFrom) or self.isDocstring(node)):
self.futuresAllowed = False
nodeType = node.__class__.__name__.upper()
try:
handler = getattr(self, nodeType)
handler(node)
finally:
self.nodeDepth -= 1
if self.traceTree:
print ' ' * self.nodeDepth + 'end ' + node.__class__.__name__
def ignore(self, node):
pass
# "stmt" type nodes
RETURN = DELETE = PRINT = WHILE = IF = WITH = RAISE = TRYEXCEPT = \
TRYFINALLY = ASSERT = EXEC = EXPR = handleChildren
CONTINUE = BREAK = PASS = ignore
# "expr" type nodes
BOOLOP = BINOP = UNARYOP = IFEXP = DICT = SET = YIELD = COMPARE = \
CALL = REPR = ATTRIBUTE = SUBSCRIPT = LIST = TUPLE = handleChildren
NUM = STR = ELLIPSIS = ignore
# "slice" type nodes
SLICE = EXTSLICE = INDEX = handleChildren
# expression contexts are node instances too, though being constants
LOAD = STORE = DEL = AUGLOAD = AUGSTORE = PARAM = ignore
# same for operators
AND = OR = ADD = SUB = MULT = DIV = MOD = POW = LSHIFT = RSHIFT = \
BITOR = BITXOR = BITAND = FLOORDIV = INVERT = NOT = UADD = USUB = \
EQ = NOTEQ = LT = LTE = GT = GTE = IS = ISNOT = IN = NOTIN = ignore
# additional node types
COMPREHENSION = EXCEPTHANDLER = KEYWORD = handleChildren
def addBinding(self, loc, value, reportRedef=True):
'''Called when a binding is altered.
- `loc` is the location (an object with lineno and optionally
col_offset attributes) of the statement responsible for the change
- `value` is the optional new value, a Binding instance, associated
with the binding; if None, the binding is deleted if it exists.
- if `reportRedef` is True (default), rebinding while unused will be
reported.
'''
if (isinstance(self.scope.get(value.name), FunctionDefinition)
and isinstance(value, FunctionDefinition)):
self.report(messages.RedefinedFunction,
loc, value.name, self.scope[value.name].source)
if not isinstance(self.scope, ClassScope):
for scope in self.scopeStack[::-1]:
existing = scope.get(value.name)
if (isinstance(existing, Importation)
and not existing.used
and (not isinstance(value, Importation) or value.fullName == existing.fullName)
and reportRedef):
self.report(messages.RedefinedWhileUnused,
loc, value.name, scope[value.name].source)
if isinstance(value, UnBinding):
try:
del self.scope[value.name]
except KeyError:
self.report(messages.UndefinedName, loc, value.name)
else:
self.scope[value.name] = value
def GLOBAL(self, node):
"""
Keep track of globals declarations.
"""
if isinstance(self.scope, FunctionScope):
self.scope.globals.update(dict.fromkeys(node.names))
def LISTCOMP(self, node):
# handle generators before element
for gen in node.generators:
self.handleNode(gen, node)
self.handleNode(node.elt, node)
GENERATOREXP = SETCOMP = LISTCOMP
# dictionary comprehensions; introduced in Python 2.7
def DICTCOMP(self, node):
for gen in node.generators:
self.handleNode(gen, node)
self.handleNode(node.key, node)
self.handleNode(node.value, node)
def FOR(self, node):
"""
Process bindings for loop variables.
"""
vars = []
def collectLoopVars(n):
if isinstance(n, _ast.Name):
vars.append(n.id)
elif isinstance(n, _ast.expr_context):
return
else:
for c in iter_child_nodes(n):
collectLoopVars(c)
collectLoopVars(node.target)
for varn in vars:
if (isinstance(self.scope.get(varn), Importation)
# unused ones will get an unused import warning
and self.scope[varn].used):
self.report(messages.ImportShadowedByLoopVar,
node, varn, self.scope[varn].source)
self.handleChildren(node)
def NAME(self, node):
"""
Handle occurrence of Name (which can be a load/store/delete access.)
"""
# Locate the name in locals / function / globals scopes.
if isinstance(node.ctx, (_ast.Load, _ast.AugLoad)):
# try local scope
importStarred = self.scope.importStarred
try:
self.scope[node.id].used = (self.scope, node)
except KeyError:
pass
else:
return
# try enclosing function scopes
for scope in self.scopeStack[-2:0:-1]:
importStarred = importStarred or scope.importStarred
if not isinstance(scope, FunctionScope):
continue
try:
scope[node.id].used = (self.scope, node)
except KeyError:
pass
else:
return
# try global scope
importStarred = importStarred or self.scopeStack[0].importStarred
try:
self.scopeStack[0][node.id].used = (self.scope, node)
except KeyError:
if ((not hasattr(__builtin__, node.id))
and node.id not in _MAGIC_GLOBALS
and not importStarred):
if (os.path.basename(self.filename) == '__init__.py' and
node.id == '__path__'):
# the special name __path__ is valid only in packages
pass
else:
self.report(messages.UndefinedName, node, node.id)
elif isinstance(node.ctx, (_ast.Store, _ast.AugStore)):
# if the name hasn't already been defined in the current scope
if isinstance(self.scope, FunctionScope) and node.id not in self.scope:
# for each function or module scope above us
for scope in self.scopeStack[:-1]:
if not isinstance(scope, (FunctionScope, ModuleScope)):
continue
# if the name was defined in that scope, and the name has
# been accessed already in the current scope, and hasn't
# been declared global
if (node.id in scope
and scope[node.id].used
and scope[node.id].used[0] is self.scope
and node.id not in self.scope.globals):
# then it's probably a mistake
self.report(messages.UndefinedLocal,
scope[node.id].used[1],
node.id,
scope[node.id].source)
break
if isinstance(node.parent,
(_ast.For, _ast.comprehension, _ast.Tuple, _ast.List)):
binding = Binding(node.id, node)
elif (node.id == '__all__' and
isinstance(self.scope, ModuleScope)):
binding = ExportBinding(node.id, node.parent.value)
else:
binding = Assignment(node.id, node)
if node.id in self.scope:
binding.used = self.scope[node.id].used
self.addBinding(node, binding)
elif isinstance(node.ctx, _ast.Del):
if isinstance(self.scope, FunctionScope) and \
node.id in self.scope.globals:
del self.scope.globals[node.id]
else:
self.addBinding(node, UnBinding(node.id, node))
else:
# must be a Param context -- this only happens for names in function
# arguments, but these aren't dispatched through here
raise RuntimeError(
"Got impossible expression context: %r" % (node.ctx,))
def FUNCTIONDEF(self, node):
# the decorators attribute is called decorator_list as of Python 2.6
if hasattr(node, 'decorators'):
for deco in node.decorators:
self.handleNode(deco, node)
else:
for deco in node.decorator_list:
self.handleNode(deco, node)
self.addBinding(node, FunctionDefinition(node.name, node))
self.LAMBDA(node)
def LAMBDA(self, node):
for default in node.args.defaults:
self.handleNode(default, node)
def runFunction():
args = []
def addArgs(arglist):
for arg in arglist:
if isinstance(arg, _ast.Tuple):
addArgs(arg.elts)
else:
if arg.id in args:
self.report(messages.DuplicateArgument,
node, arg.id)
args.append(arg.id)
self.pushFunctionScope()
addArgs(node.args.args)
# vararg/kwarg identifiers are not Name nodes
if node.args.vararg:
args.append(node.args.vararg)
if node.args.kwarg:
args.append(node.args.kwarg)
for name in args:
self.addBinding(node, Argument(name, node), reportRedef=False)
if isinstance(node.body, list):
# case for FunctionDefs
for stmt in node.body:
self.handleNode(stmt, node)
else:
# case for Lambdas
self.handleNode(node.body, node)
def checkUnusedAssignments():
"""
Check to see if any assignments have not been used.
"""
for name, binding in self.scope.iteritems():
if (not binding.used and not name in self.scope.globals
and isinstance(binding, Assignment)):
self.report(messages.UnusedVariable,
binding.source, name)
self.deferAssignment(checkUnusedAssignments)
self.popScope()
self.deferFunction(runFunction)
def CLASSDEF(self, node):
"""
Check names used in a class definition, including its decorators, base
classes, and the body of its definition. Additionally, add its name to
the current scope.
"""
# decorator_list is present as of Python 2.6
for deco in getattr(node, 'decorator_list', []):
self.handleNode(deco, node)
for baseNode in node.bases:
self.handleNode(baseNode, node)
self.pushClassScope()
for stmt in node.body:
self.handleNode(stmt, node)
self.popScope()
self.addBinding(node, Binding(node.name, node))
def ASSIGN(self, node):
self.handleNode(node.value, node)
for target in node.targets:
self.handleNode(target, node)
def AUGASSIGN(self, node):
# AugAssign is awkward: must set the context explicitly and visit twice,
# once with AugLoad context, once with AugStore context
node.target.ctx = _ast.AugLoad()
self.handleNode(node.target, node)
self.handleNode(node.value, node)
node.target.ctx = _ast.AugStore()
self.handleNode(node.target, node)
def IMPORT(self, node):
for alias in node.names:
name = alias.asname or alias.name
importation = Importation(name, node)
self.addBinding(node, importation)
def IMPORTFROM(self, node):
if node.module == '__future__':
if not self.futuresAllowed:
self.report(messages.LateFutureImport, node,
[n.name for n in node.names])
else:
self.futuresAllowed = False
for alias in node.names:
if alias.name == '*':
self.scope.importStarred = True
self.report(messages.ImportStarUsed, node, node.module)
continue
name = alias.asname or alias.name
importation = Importation(name, node)
if node.module == '__future__':
importation.used = (self.scope, node)
self.addBinding(node, importation)

View file

@ -0,0 +1,96 @@
# (c) 2005 Divmod, Inc. See LICENSE file for details
class Message(object):
message = ''
message_args = ()
def __init__(self, filename, loc, use_column=True):
self.filename = filename
self.lineno = loc.lineno
self.col = getattr(loc, 'col_offset', None) if use_column else None
def __str__(self):
return '%s:%s: %s' % (self.filename, self.lineno, self.message % self.message_args)
class UnusedImport(Message):
message = '%r imported but unused'
def __init__(self, filename, loc, name):
Message.__init__(self, filename, loc, use_column=False)
self.message_args = (name,)
class RedefinedWhileUnused(Message):
message = 'redefinition of unused %r from line %r'
def __init__(self, filename, loc, name, orig_loc):
Message.__init__(self, filename, loc)
self.message_args = (name, orig_loc.lineno)
class ImportShadowedByLoopVar(Message):
message = 'import %r from line %r shadowed by loop variable'
def __init__(self, filename, loc, name, orig_loc):
Message.__init__(self, filename, loc)
self.message_args = (name, orig_loc.lineno)
class ImportStarUsed(Message):
message = "'from %s import *' used; unable to detect undefined names"
def __init__(self, filename, loc, modname):
Message.__init__(self, filename, loc)
self.message_args = (modname,)
class UndefinedName(Message):
message = 'undefined name %r'
def __init__(self, filename, loc, name):
Message.__init__(self, filename, loc)
self.message_args = (name,)
class UndefinedExport(Message):
message = 'undefined name %r in __all__'
def __init__(self, filename, loc, name):
Message.__init__(self, filename, loc)
self.message_args = (name,)
class UndefinedLocal(Message):
message = "local variable %r (defined in enclosing scope on line %r) referenced before assignment"
def __init__(self, filename, loc, name, orig_loc):
Message.__init__(self, filename, loc)
self.message_args = (name, orig_loc.lineno)
class DuplicateArgument(Message):
message = 'duplicate argument %r in function definition'
def __init__(self, filename, loc, name):
Message.__init__(self, filename, loc)
self.message_args = (name,)
class RedefinedFunction(Message):
message = 'redefinition of function %r from line %r'
def __init__(self, filename, loc, name, orig_loc):
Message.__init__(self, filename, loc)
self.message_args = (name, orig_loc.lineno)
class LateFutureImport(Message):
message = 'future import(s) %r after other statements'
def __init__(self, filename, loc, names):
Message.__init__(self, filename, loc)
self.message_args = (names,)
class UnusedVariable(Message):
"""
Indicates that a variable has been explicity assigned to but not actually
used.
"""
message = 'local variable %r is assigned to but never used'
def __init__(self, filename, loc, names):
Message.__init__(self, filename, loc)
self.message_args = (names,)

View file

@ -0,0 +1,90 @@
"""
Implementation of the command-line I{pyflakes} tool.
"""
import sys
import os
import _ast
checker = __import__('pyflakes.checker').checker
def check(codeString, filename):
"""
Check the Python source given by C{codeString} for flakes.
@param codeString: The Python source to check.
@type codeString: C{str}
@param filename: The name of the file the source came from, used to report
errors.
@type filename: C{str}
@return: The number of warnings emitted.
@rtype: C{int}
"""
# First, compile into an AST and handle syntax errors.
try:
tree = compile(codeString, filename, "exec", _ast.PyCF_ONLY_AST)
except SyntaxError, value:
msg = value.args[0]
(lineno, offset, text) = value.lineno, value.offset, value.text
# If there's an encoding problem with the file, the text is None.
if text is None:
# Avoid using msg, since for the only known case, it contains a
# bogus message that claims the encoding the file declared was
# unknown.
print >> sys.stderr, "%s: problem decoding source" % (filename, )
else:
line = text.splitlines()[-1]
if offset is not None:
offset = offset - (len(text) - len(line))
print >> sys.stderr, '%s:%d: %s' % (filename, lineno, msg)
print >> sys.stderr, line
if offset is not None:
print >> sys.stderr, " " * offset, "^"
return 1
else:
# Okay, it's syntactically valid. Now check it.
w = checker.Checker(tree, filename)
w.messages.sort(lambda a, b: cmp(a.lineno, b.lineno))
for warning in w.messages:
print warning
return len(w.messages)
def checkPath(filename):
"""
Check the given path, printing out any warnings detected.
@return: the number of warnings printed
"""
try:
return check(file(filename, 'U').read() + '\n', filename)
except IOError, msg:
print >> sys.stderr, "%s: %s" % (filename, msg.args[1])
return 1
def main():
warnings = 0
args = sys.argv[1:]
if args:
for arg in args:
if os.path.isdir(arg):
for dirpath, dirnames, filenames in os.walk(arg):
for filename in filenames:
if filename.endswith('.py'):
warnings += checkPath(os.path.join(dirpath, filename))
else:
warnings += checkPath(arg)
else:
warnings += check(sys.stdin.read(), '<stdin>')
raise SystemExit(warnings > 0)

View file

@ -0,0 +1,27 @@
import textwrap
import _ast
from twisted.trial import unittest
from pyflakes import checker
class Test(unittest.TestCase):
def flakes(self, input, *expectedOutputs, **kw):
ast = compile(textwrap.dedent(input), "<test>", "exec",
_ast.PyCF_ONLY_AST)
w = checker.Checker(ast, **kw)
outputs = [type(o) for o in w.messages]
expectedOutputs = list(expectedOutputs)
outputs.sort()
expectedOutputs.sort()
self.assert_(outputs == expectedOutputs, '''\
for input:
%s
expected outputs:
%s
but got:
%s''' % (input, repr(expectedOutputs), '\n'.join([str(o) for o in w.messages])))
return w

View file

@ -0,0 +1,673 @@
from sys import version_info
from pyflakes import messages as m
from pyflakes.test import harness
class Test(harness.Test):
def test_unusedImport(self):
self.flakes('import fu, bar', m.UnusedImport, m.UnusedImport)
self.flakes('from baz import fu, bar', m.UnusedImport, m.UnusedImport)
def test_aliasedImport(self):
self.flakes('import fu as FU, bar as FU', m.RedefinedWhileUnused, m.UnusedImport)
self.flakes('from moo import fu as FU, bar as FU', m.RedefinedWhileUnused, m.UnusedImport)
def test_usedImport(self):
self.flakes('import fu; print fu')
self.flakes('from baz import fu; print fu')
def test_redefinedWhileUnused(self):
self.flakes('import fu; fu = 3', m.RedefinedWhileUnused)
self.flakes('import fu; del fu', m.RedefinedWhileUnused)
self.flakes('import fu; fu, bar = 3', m.RedefinedWhileUnused)
self.flakes('import fu; [fu, bar] = 3', m.RedefinedWhileUnused)
def test_redefinedByFunction(self):
self.flakes('''
import fu
def fu():
pass
''', m.RedefinedWhileUnused)
def test_redefinedInNestedFunction(self):
"""
Test that shadowing a global name with a nested function definition
generates a warning.
"""
self.flakes('''
import fu
def bar():
def baz():
def fu():
pass
''', m.RedefinedWhileUnused, m.UnusedImport)
def test_redefinedByClass(self):
self.flakes('''
import fu
class fu:
pass
''', m.RedefinedWhileUnused)
def test_redefinedBySubclass(self):
"""
If an imported name is redefined by a class statement which also uses
that name in the bases list, no warning is emitted.
"""
self.flakes('''
from fu import bar
class bar(bar):
pass
''')
def test_redefinedInClass(self):
"""
Test that shadowing a global with a class attribute does not produce a
warning.
"""
self.flakes('''
import fu
class bar:
fu = 1
print fu
''')
def test_usedInFunction(self):
self.flakes('''
import fu
def fun():
print fu
''')
def test_shadowedByParameter(self):
self.flakes('''
import fu
def fun(fu):
print fu
''', m.UnusedImport)
self.flakes('''
import fu
def fun(fu):
print fu
print fu
''')
def test_newAssignment(self):
self.flakes('fu = None')
def test_usedInGetattr(self):
self.flakes('import fu; fu.bar.baz')
self.flakes('import fu; "bar".fu.baz', m.UnusedImport)
def test_usedInSlice(self):
self.flakes('import fu; print fu.bar[1:]')
def test_usedInIfBody(self):
self.flakes('''
import fu
if True: print fu
''')
def test_usedInIfConditional(self):
self.flakes('''
import fu
if fu: pass
''')
def test_usedInElifConditional(self):
self.flakes('''
import fu
if False: pass
elif fu: pass
''')
def test_usedInElse(self):
self.flakes('''
import fu
if False: pass
else: print fu
''')
def test_usedInCall(self):
self.flakes('import fu; fu.bar()')
def test_usedInClass(self):
self.flakes('''
import fu
class bar:
bar = fu
''')
def test_usedInClassBase(self):
self.flakes('''
import fu
class bar(object, fu.baz):
pass
''')
def test_notUsedInNestedScope(self):
self.flakes('''
import fu
def bleh():
pass
print fu
''')
def test_usedInFor(self):
self.flakes('''
import fu
for bar in range(9):
print fu
''')
def test_usedInForElse(self):
self.flakes('''
import fu
for bar in range(10):
pass
else:
print fu
''')
def test_redefinedByFor(self):
self.flakes('''
import fu
for fu in range(2):
pass
''', m.RedefinedWhileUnused)
def test_shadowedByFor(self):
"""
Test that shadowing a global name with a for loop variable generates a
warning.
"""
self.flakes('''
import fu
fu.bar()
for fu in ():
pass
''', m.ImportShadowedByLoopVar)
def test_shadowedByForDeep(self):
"""
Test that shadowing a global name with a for loop variable nested in a
tuple unpack generates a warning.
"""
self.flakes('''
import fu
fu.bar()
for (x, y, z, (a, b, c, (fu,))) in ():
pass
''', m.ImportShadowedByLoopVar)
def test_usedInReturn(self):
self.flakes('''
import fu
def fun():
return fu
''')
def test_usedInOperators(self):
self.flakes('import fu; 3 + fu.bar')
self.flakes('import fu; 3 % fu.bar')
self.flakes('import fu; 3 - fu.bar')
self.flakes('import fu; 3 * fu.bar')
self.flakes('import fu; 3 ** fu.bar')
self.flakes('import fu; 3 / fu.bar')
self.flakes('import fu; 3 // fu.bar')
self.flakes('import fu; -fu.bar')
self.flakes('import fu; ~fu.bar')
self.flakes('import fu; 1 == fu.bar')
self.flakes('import fu; 1 | fu.bar')
self.flakes('import fu; 1 & fu.bar')
self.flakes('import fu; 1 ^ fu.bar')
self.flakes('import fu; 1 >> fu.bar')
self.flakes('import fu; 1 << fu.bar')
def test_usedInAssert(self):
self.flakes('import fu; assert fu.bar')
def test_usedInSubscript(self):
self.flakes('import fu; fu.bar[1]')
def test_usedInLogic(self):
self.flakes('import fu; fu and False')
self.flakes('import fu; fu or False')
self.flakes('import fu; not fu.bar')
def test_usedInList(self):
self.flakes('import fu; [fu]')
def test_usedInTuple(self):
self.flakes('import fu; (fu,)')
def test_usedInTry(self):
self.flakes('''
import fu
try: fu
except: pass
''')
def test_usedInExcept(self):
self.flakes('''
import fu
try: fu
except: pass
''')
def test_redefinedByExcept(self):
self.flakes('''
import fu
try: pass
except Exception, fu: pass
''', m.RedefinedWhileUnused)
def test_usedInRaise(self):
self.flakes('''
import fu
raise fu.bar
''')
def test_usedInYield(self):
self.flakes('''
import fu
def gen():
yield fu
''')
def test_usedInDict(self):
self.flakes('import fu; {fu:None}')
self.flakes('import fu; {1:fu}')
def test_usedInParameterDefault(self):
self.flakes('''
import fu
def f(bar=fu):
pass
''')
def test_usedInAttributeAssign(self):
self.flakes('import fu; fu.bar = 1')
def test_usedInKeywordArg(self):
self.flakes('import fu; fu.bar(stuff=fu)')
def test_usedInAssignment(self):
self.flakes('import fu; bar=fu')
self.flakes('import fu; n=0; n+=fu')
def test_usedInListComp(self):
self.flakes('import fu; [fu for _ in range(1)]')
self.flakes('import fu; [1 for _ in range(1) if fu]')
def test_redefinedByListComp(self):
self.flakes('import fu; [1 for fu in range(1)]', m.RedefinedWhileUnused)
def test_usedInTryFinally(self):
self.flakes('''
import fu
try: pass
finally: fu
''')
self.flakes('''
import fu
try: fu
finally: pass
''')
def test_usedInWhile(self):
self.flakes('''
import fu
while 0:
fu
''')
self.flakes('''
import fu
while fu: pass
''')
def test_usedInGlobal(self):
self.flakes('''
import fu
def f(): global fu
''', m.UnusedImport)
def test_usedInBackquote(self):
self.flakes('import fu; `fu`')
def test_usedInExec(self):
self.flakes('import fu; exec "print 1" in fu.bar')
def test_usedInLambda(self):
self.flakes('import fu; lambda: fu')
def test_shadowedByLambda(self):
self.flakes('import fu; lambda fu: fu', m.UnusedImport)
def test_usedInSliceObj(self):
self.flakes('import fu; "meow"[::fu]')
def test_unusedInNestedScope(self):
self.flakes('''
def bar():
import fu
fu
''', m.UnusedImport, m.UndefinedName)
def test_methodsDontUseClassScope(self):
self.flakes('''
class bar:
import fu
def fun(self):
fu
''', m.UnusedImport, m.UndefinedName)
def test_nestedFunctionsNestScope(self):
self.flakes('''
def a():
def b():
fu
import fu
''')
def test_nestedClassAndFunctionScope(self):
self.flakes('''
def a():
import fu
class b:
def c(self):
print fu
''')
def test_importStar(self):
self.flakes('from fu import *', m.ImportStarUsed)
def test_packageImport(self):
"""
If a dotted name is imported and used, no warning is reported.
"""
self.flakes('''
import fu.bar
fu.bar
''')
def test_unusedPackageImport(self):
"""
If a dotted name is imported and not used, an unused import warning is
reported.
"""
self.flakes('import fu.bar', m.UnusedImport)
def test_duplicateSubmoduleImport(self):
"""
If a submodule of a package is imported twice, an unused import warning
and a redefined while unused warning are reported.
"""
self.flakes('''
import fu.bar, fu.bar
fu.bar
''', m.RedefinedWhileUnused)
self.flakes('''
import fu.bar
import fu.bar
fu.bar
''', m.RedefinedWhileUnused)
def test_differentSubmoduleImport(self):
"""
If two different submodules of a package are imported, no duplicate
import warning is reported for the package.
"""
self.flakes('''
import fu.bar, fu.baz
fu.bar, fu.baz
''')
self.flakes('''
import fu.bar
import fu.baz
fu.bar, fu.baz
''')
def test_assignRHSFirst(self):
self.flakes('import fu; fu = fu')
self.flakes('import fu; fu, bar = fu')
self.flakes('import fu; [fu, bar] = fu')
self.flakes('import fu; fu += fu')
def test_tryingMultipleImports(self):
self.flakes('''
try:
import fu
except ImportError:
import bar as fu
''')
test_tryingMultipleImports.todo = ''
def test_nonGlobalDoesNotRedefine(self):
self.flakes('''
import fu
def a():
fu = 3
return fu
fu
''')
def test_functionsRunLater(self):
self.flakes('''
def a():
fu
import fu
''')
def test_functionNamesAreBoundNow(self):
self.flakes('''
import fu
def fu():
fu
fu
''', m.RedefinedWhileUnused)
def test_ignoreNonImportRedefinitions(self):
self.flakes('a = 1; a = 2')
def test_importingForImportError(self):
self.flakes('''
try:
import fu
except ImportError:
pass
''')
test_importingForImportError.todo = ''
def test_importedInClass(self):
'''Imports in class scope can be used through self'''
self.flakes('''
class c:
import i
def __init__(self):
self.i
''')
test_importedInClass.todo = 'requires evaluating attribute access'
def test_futureImport(self):
'''__future__ is special'''
self.flakes('from __future__ import division')
self.flakes('''
"docstring is allowed before future import"
from __future__ import division
''')
def test_futureImportFirst(self):
"""
__future__ imports must come before anything else.
"""
self.flakes('''
x = 5
from __future__ import division
''', m.LateFutureImport)
self.flakes('''
from foo import bar
from __future__ import division
bar
''', m.LateFutureImport)
class TestSpecialAll(harness.Test):
"""
Tests for suppression of unused import warnings by C{__all__}.
"""
def test_ignoredInFunction(self):
"""
An C{__all__} definition does not suppress unused import warnings in a
function scope.
"""
self.flakes('''
def foo():
import bar
__all__ = ["bar"]
''', m.UnusedImport, m.UnusedVariable)
def test_ignoredInClass(self):
"""
An C{__all__} definition does not suppress unused import warnings in a
class scope.
"""
self.flakes('''
class foo:
import bar
__all__ = ["bar"]
''', m.UnusedImport)
def test_warningSuppressed(self):
"""
If a name is imported and unused but is named in C{__all__}, no warning
is reported.
"""
self.flakes('''
import foo
__all__ = ["foo"]
''')
def test_unrecognizable(self):
"""
If C{__all__} is defined in a way that can't be recognized statically,
it is ignored.
"""
self.flakes('''
import foo
__all__ = ["f" + "oo"]
''', m.UnusedImport)
self.flakes('''
import foo
__all__ = [] + ["foo"]
''', m.UnusedImport)
def test_unboundExported(self):
"""
If C{__all__} includes a name which is not bound, a warning is emitted.
"""
self.flakes('''
__all__ = ["foo"]
''', m.UndefinedExport)
# Skip this in __init__.py though, since the rules there are a little
# different.
for filename in ["foo/__init__.py", "__init__.py"]:
self.flakes('''
__all__ = ["foo"]
''', filename=filename)
def test_usedInGenExp(self):
"""
Using a global in a generator expression results in no warnings.
"""
self.flakes('import fu; (fu for _ in range(1))')
self.flakes('import fu; (1 for _ in range(1) if fu)')
def test_redefinedByGenExp(self):
"""
Re-using a global name as the loop variable for a generator
expression results in a redefinition warning.
"""
self.flakes('import fu; (1 for fu in range(1))', m.RedefinedWhileUnused)
def test_usedAsDecorator(self):
"""
Using a global name in a decorator statement results in no warnings,
but using an undefined name in a decorator statement results in an
undefined name warning.
"""
self.flakes('''
from interior import decorate
@decorate
def f():
return "hello"
''')
self.flakes('''
from interior import decorate
@decorate('value')
def f():
return "hello"
''')
self.flakes('''
@decorate
def f():
return "hello"
''', m.UndefinedName)
class Python26Tests(harness.Test):
"""
Tests for checking of syntax which is valid in PYthon 2.6 and newer.
"""
if version_info < (2, 6):
skip = "Python 2.6 required for class decorator tests."
def test_usedAsClassDecorator(self):
"""
Using an imported name as a class decorator results in no warnings,
but using an undefined name as a class decorator results in an
undefined name warning.
"""
self.flakes('''
from interior import decorate
@decorate
class foo:
pass
''')
self.flakes('''
from interior import decorate
@decorate("foo")
class bar:
pass
''')
self.flakes('''
@decorate
class foo:
pass
''', m.UndefinedName)

View file

@ -0,0 +1,575 @@
# (c) 2005-2010 Divmod, Inc.
# See LICENSE file for details
"""
Tests for various Pyflakes behavior.
"""
from sys import version_info
from pyflakes import messages as m
from pyflakes.test import harness
class Test(harness.Test):
def test_duplicateArgs(self):
self.flakes('def fu(bar, bar): pass', m.DuplicateArgument)
def test_localReferencedBeforeAssignment(self):
self.flakes('''
a = 1
def f():
a; a=1
f()
''', m.UndefinedName)
test_localReferencedBeforeAssignment.todo = 'this requires finding all assignments in the function body first'
def test_redefinedFunction(self):
"""
Test that shadowing a function definition with another one raises a
warning.
"""
self.flakes('''
def a(): pass
def a(): pass
''', m.RedefinedFunction)
def test_redefinedClassFunction(self):
"""
Test that shadowing a function definition in a class suite with another
one raises a warning.
"""
self.flakes('''
class A:
def a(): pass
def a(): pass
''', m.RedefinedFunction)
def test_functionDecorator(self):
"""
Test that shadowing a function definition with a decorated version of
that function does not raise a warning.
"""
self.flakes('''
from somewhere import somedecorator
def a(): pass
a = somedecorator(a)
''')
def test_classFunctionDecorator(self):
"""
Test that shadowing a function definition in a class suite with a
decorated version of that function does not raise a warning.
"""
self.flakes('''
class A:
def a(): pass
a = classmethod(a)
''')
def test_unaryPlus(self):
'''Don't die on unary +'''
self.flakes('+1')
def test_undefinedBaseClass(self):
"""
If a name in the base list of a class definition is undefined, a
warning is emitted.
"""
self.flakes('''
class foo(foo):
pass
''', m.UndefinedName)
def test_classNameUndefinedInClassBody(self):
"""
If a class name is used in the body of that class's definition and
the name is not already defined, a warning is emitted.
"""
self.flakes('''
class foo:
foo
''', m.UndefinedName)
def test_classNameDefinedPreviously(self):
"""
If a class name is used in the body of that class's definition and
the name was previously defined in some other way, no warning is
emitted.
"""
self.flakes('''
foo = None
class foo:
foo
''')
def test_comparison(self):
"""
If a defined name is used on either side of any of the six comparison
operators, no warning is emitted.
"""
self.flakes('''
x = 10
y = 20
x < y
x <= y
x == y
x != y
x >= y
x > y
''')
def test_identity(self):
"""
If a deefined name is used on either side of an identity test, no
warning is emitted.
"""
self.flakes('''
x = 10
y = 20
x is y
x is not y
''')
def test_containment(self):
"""
If a defined name is used on either side of a containment test, no
warning is emitted.
"""
self.flakes('''
x = 10
y = 20
x in y
x not in y
''')
def test_loopControl(self):
"""
break and continue statements are supported.
"""
self.flakes('''
for x in [1, 2]:
break
''')
self.flakes('''
for x in [1, 2]:
continue
''')
def test_ellipsis(self):
"""
Ellipsis in a slice is supported.
"""
self.flakes('''
[1, 2][...]
''')
def test_extendedSlice(self):
"""
Extended slices are supported.
"""
self.flakes('''
x = 3
[1, 2][x,:]
''')
class TestUnusedAssignment(harness.Test):
"""
Tests for warning about unused assignments.
"""
def test_unusedVariable(self):
"""
Warn when a variable in a function is assigned a value that's never
used.
"""
self.flakes('''
def a():
b = 1
''', m.UnusedVariable)
def test_assignToGlobal(self):
"""
Assigning to a global and then not using that global is perfectly
acceptable. Do not mistake it for an unused local variable.
"""
self.flakes('''
b = 0
def a():
global b
b = 1
''')
def test_assignToMember(self):
"""
Assigning to a member of another object and then not using that member
variable is perfectly acceptable. Do not mistake it for an unused
local variable.
"""
# XXX: Adding this test didn't generate a failure. Maybe not
# necessary?
self.flakes('''
class b:
pass
def a():
b.foo = 1
''')
def test_assignInForLoop(self):
"""
Don't warn when a variable in a for loop is assigned to but not used.
"""
self.flakes('''
def f():
for i in range(10):
pass
''')
def test_assignInListComprehension(self):
"""
Don't warn when a variable in a list comprehension is assigned to but
not used.
"""
self.flakes('''
def f():
[None for i in range(10)]
''')
def test_generatorExpression(self):
"""
Don't warn when a variable in a generator expression is assigned to but not used.
"""
self.flakes('''
def f():
(None for i in range(10))
''')
def test_assignmentInsideLoop(self):
"""
Don't warn when a variable assignment occurs lexically after its use.
"""
self.flakes('''
def f():
x = None
for i in range(10):
if i > 2:
return x
x = i * 2
''')
def test_tupleUnpacking(self):
"""
Don't warn when a variable included in tuple unpacking is unused. It's
very common for variables in a tuple unpacking assignment to be unused
in good Python code, so warning will only create false positives.
"""
self.flakes('''
def f():
(x, y) = 1, 2
''')
def test_listUnpacking(self):
"""
Don't warn when a variable included in list unpacking is unused.
"""
self.flakes('''
def f():
[x, y] = [1, 2]
''')
def test_closedOver(self):
"""
Don't warn when the assignment is used in an inner function.
"""
self.flakes('''
def barMaker():
foo = 5
def bar():
return foo
return bar
''')
def test_doubleClosedOver(self):
"""
Don't warn when the assignment is used in an inner function, even if
that inner function itself is in an inner function.
"""
self.flakes('''
def barMaker():
foo = 5
def bar():
def baz():
return foo
return bar
''')
class Python25Test(harness.Test):
"""
Tests for checking of syntax only available in Python 2.5 and newer.
"""
if version_info < (2, 5):
skip = "Python 2.5 required for if-else and with tests"
def test_ifexp(self):
"""
Test C{foo if bar else baz} statements.
"""
self.flakes("a = 'moo' if True else 'oink'")
self.flakes("a = foo if True else 'oink'", m.UndefinedName)
self.flakes("a = 'moo' if True else bar", m.UndefinedName)
def test_withStatementNoNames(self):
"""
No warnings are emitted for using inside or after a nameless C{with}
statement a name defined beforehand.
"""
self.flakes('''
from __future__ import with_statement
bar = None
with open("foo"):
bar
bar
''')
def test_withStatementSingleName(self):
"""
No warnings are emitted for using a name defined by a C{with} statement
within the suite or afterwards.
"""
self.flakes('''
from __future__ import with_statement
with open('foo') as bar:
bar
bar
''')
def test_withStatementAttributeName(self):
"""
No warnings are emitted for using an attribute as the target of a
C{with} statement.
"""
self.flakes('''
from __future__ import with_statement
import foo
with open('foo') as foo.bar:
pass
''')
def test_withStatementSubscript(self):
"""
No warnings are emitted for using a subscript as the target of a
C{with} statement.
"""
self.flakes('''
from __future__ import with_statement
import foo
with open('foo') as foo[0]:
pass
''')
def test_withStatementSubscriptUndefined(self):
"""
An undefined name warning is emitted if the subscript used as the
target of a C{with} statement is not defined.
"""
self.flakes('''
from __future__ import with_statement
import foo
with open('foo') as foo[bar]:
pass
''', m.UndefinedName)
def test_withStatementTupleNames(self):
"""
No warnings are emitted for using any of the tuple of names defined by
a C{with} statement within the suite or afterwards.
"""
self.flakes('''
from __future__ import with_statement
with open('foo') as (bar, baz):
bar, baz
bar, baz
''')
def test_withStatementListNames(self):
"""
No warnings are emitted for using any of the list of names defined by a
C{with} statement within the suite or afterwards.
"""
self.flakes('''
from __future__ import with_statement
with open('foo') as [bar, baz]:
bar, baz
bar, baz
''')
def test_withStatementComplicatedTarget(self):
"""
If the target of a C{with} statement uses any or all of the valid forms
for that part of the grammar (See
U{http://docs.python.org/reference/compound_stmts.html#the-with-statement}),
the names involved are checked both for definedness and any bindings
created are respected in the suite of the statement and afterwards.
"""
self.flakes('''
from __future__ import with_statement
c = d = e = g = h = i = None
with open('foo') as [(a, b), c[d], e.f, g[h:i]]:
a, b, c, d, e, g, h, i
a, b, c, d, e, g, h, i
''')
def test_withStatementSingleNameUndefined(self):
"""
An undefined name warning is emitted if the name first defined by a
C{with} statement is used before the C{with} statement.
"""
self.flakes('''
from __future__ import with_statement
bar
with open('foo') as bar:
pass
''', m.UndefinedName)
def test_withStatementTupleNamesUndefined(self):
"""
An undefined name warning is emitted if a name first defined by a the
tuple-unpacking form of the C{with} statement is used before the
C{with} statement.
"""
self.flakes('''
from __future__ import with_statement
baz
with open('foo') as (bar, baz):
pass
''', m.UndefinedName)
def test_withStatementSingleNameRedefined(self):
"""
A redefined name warning is emitted if a name bound by an import is
rebound by the name defined by a C{with} statement.
"""
self.flakes('''
from __future__ import with_statement
import bar
with open('foo') as bar:
pass
''', m.RedefinedWhileUnused)
def test_withStatementTupleNamesRedefined(self):
"""
A redefined name warning is emitted if a name bound by an import is
rebound by one of the names defined by the tuple-unpacking form of a
C{with} statement.
"""
self.flakes('''
from __future__ import with_statement
import bar
with open('foo') as (bar, baz):
pass
''', m.RedefinedWhileUnused)
def test_withStatementUndefinedInside(self):
"""
An undefined name warning is emitted if a name is used inside the
body of a C{with} statement without first being bound.
"""
self.flakes('''
from __future__ import with_statement
with open('foo') as bar:
baz
''', m.UndefinedName)
def test_withStatementNameDefinedInBody(self):
"""
A name defined in the body of a C{with} statement can be used after
the body ends without warning.
"""
self.flakes('''
from __future__ import with_statement
with open('foo') as bar:
baz = 10
baz
''')
def test_withStatementUndefinedInExpression(self):
"""
An undefined name warning is emitted if a name in the I{test}
expression of a C{with} statement is undefined.
"""
self.flakes('''
from __future__ import with_statement
with bar as baz:
pass
''', m.UndefinedName)
self.flakes('''
from __future__ import with_statement
with bar as bar:
pass
''', m.UndefinedName)
class Python27Test(harness.Test):
"""
Tests for checking of syntax only available in Python 2.7 and newer.
"""
if version_info < (2, 7):
skip = "Python 2.7 required for dict/set comprehension tests"
def test_dictComprehension(self):
"""
Dict comprehensions are properly handled.
"""
self.flakes('''
a = {1: x for x in range(10)}
''')
def test_setComprehensionAndLiteral(self):
"""
Set comprehensions are properly handled.
"""
self.flakes('''
a = {1, 2, 3}
b = {x for x in range(10)}
''')

View file

@ -0,0 +1,185 @@
"""
Tests for L{pyflakes.scripts.pyflakes}.
"""
import sys
from StringIO import StringIO
from twisted.python.filepath import FilePath
from twisted.trial.unittest import TestCase
from pyflakes.scripts.pyflakes import checkPath
def withStderrTo(stderr, f):
"""
Call C{f} with C{sys.stderr} redirected to C{stderr}.
"""
(outer, sys.stderr) = (sys.stderr, stderr)
try:
return f()
finally:
sys.stderr = outer
class CheckTests(TestCase):
"""
Tests for L{check} and L{checkPath} which check a file for flakes.
"""
def test_missingTrailingNewline(self):
"""
Source which doesn't end with a newline shouldn't cause any
exception to be raised nor an error indicator to be returned by
L{check}.
"""
fName = self.mktemp()
FilePath(fName).setContent("def foo():\n\tpass\n\t")
self.assertFalse(checkPath(fName))
def test_checkPathNonExisting(self):
"""
L{checkPath} handles non-existing files.
"""
err = StringIO()
count = withStderrTo(err, lambda: checkPath('extremo'))
self.assertEquals(err.getvalue(), 'extremo: No such file or directory\n')
self.assertEquals(count, 1)
def test_multilineSyntaxError(self):
"""
Source which includes a syntax error which results in the raised
L{SyntaxError.text} containing multiple lines of source are reported
with only the last line of that source.
"""
source = """\
def foo():
'''
def bar():
pass
def baz():
'''quux'''
"""
# Sanity check - SyntaxError.text should be multiple lines, if it
# isn't, something this test was unprepared for has happened.
def evaluate(source):
exec source
exc = self.assertRaises(SyntaxError, evaluate, source)
self.assertTrue(exc.text.count('\n') > 1)
sourcePath = FilePath(self.mktemp())
sourcePath.setContent(source)
err = StringIO()
count = withStderrTo(err, lambda: checkPath(sourcePath.path))
self.assertEqual(count, 1)
self.assertEqual(
err.getvalue(),
"""\
%s:8: invalid syntax
'''quux'''
^
""" % (sourcePath.path,))
def test_eofSyntaxError(self):
"""
The error reported for source files which end prematurely causing a
syntax error reflects the cause for the syntax error.
"""
source = "def foo("
sourcePath = FilePath(self.mktemp())
sourcePath.setContent(source)
err = StringIO()
count = withStderrTo(err, lambda: checkPath(sourcePath.path))
self.assertEqual(count, 1)
self.assertEqual(
err.getvalue(),
"""\
%s:1: unexpected EOF while parsing
def foo(
^
""" % (sourcePath.path,))
def test_nonDefaultFollowsDefaultSyntaxError(self):
"""
Source which has a non-default argument following a default argument
should include the line number of the syntax error. However these
exceptions do not include an offset.
"""
source = """\
def foo(bar=baz, bax):
pass
"""
sourcePath = FilePath(self.mktemp())
sourcePath.setContent(source)
err = StringIO()
count = withStderrTo(err, lambda: checkPath(sourcePath.path))
self.assertEqual(count, 1)
self.assertEqual(
err.getvalue(),
"""\
%s:1: non-default argument follows default argument
def foo(bar=baz, bax):
""" % (sourcePath.path,))
def test_nonKeywordAfterKeywordSyntaxError(self):
"""
Source which has a non-keyword argument after a keyword argument should
include the line number of the syntax error. However these exceptions
do not include an offset.
"""
source = """\
foo(bar=baz, bax)
"""
sourcePath = FilePath(self.mktemp())
sourcePath.setContent(source)
err = StringIO()
count = withStderrTo(err, lambda: checkPath(sourcePath.path))
self.assertEqual(count, 1)
self.assertEqual(
err.getvalue(),
"""\
%s:1: non-keyword arg after keyword arg
foo(bar=baz, bax)
""" % (sourcePath.path,))
def test_permissionDenied(self):
"""
If the a source file is not readable, this is reported on standard
error.
"""
sourcePath = FilePath(self.mktemp())
sourcePath.setContent('')
sourcePath.chmod(0)
err = StringIO()
count = withStderrTo(err, lambda: checkPath(sourcePath.path))
self.assertEquals(count, 1)
self.assertEquals(
err.getvalue(), "%s: Permission denied\n" % (sourcePath.path,))
def test_misencodedFile(self):
"""
If a source file contains bytes which cannot be decoded, this is
reported on stderr.
"""
source = u"""\
# coding: ascii
x = "\N{SNOWMAN}"
""".encode('utf-8')
sourcePath = FilePath(self.mktemp())
sourcePath.setContent(source)
err = StringIO()
count = withStderrTo(err, lambda: checkPath(sourcePath.path))
self.assertEquals(count, 1)
self.assertEquals(
err.getvalue(), "%s: problem decoding source\n" % (sourcePath.path,))

View file

@ -0,0 +1,265 @@
from _ast import PyCF_ONLY_AST
from twisted.trial.unittest import TestCase
from pyflakes import messages as m, checker
from pyflakes.test import harness
class Test(harness.Test):
def test_undefined(self):
self.flakes('bar', m.UndefinedName)
def test_definedInListComp(self):
self.flakes('[a for a in range(10) if a]')
def test_functionsNeedGlobalScope(self):
self.flakes('''
class a:
def b():
fu
fu = 1
''')
def test_builtins(self):
self.flakes('range(10)')
def test_magicGlobalsFile(self):
"""
Use of the C{__file__} magic global should not emit an undefined name
warning.
"""
self.flakes('__file__')
def test_magicGlobalsBuiltins(self):
"""
Use of the C{__builtins__} magic global should not emit an undefined
name warning.
"""
self.flakes('__builtins__')
def test_magicGlobalsName(self):
"""
Use of the C{__name__} magic global should not emit an undefined name
warning.
"""
self.flakes('__name__')
def test_magicGlobalsPath(self):
"""
Use of the C{__path__} magic global should not emit an undefined name
warning, if you refer to it from a file called __init__.py.
"""
self.flakes('__path__', m.UndefinedName)
self.flakes('__path__', filename='package/__init__.py')
def test_globalImportStar(self):
'''Can't find undefined names with import *'''
self.flakes('from fu import *; bar', m.ImportStarUsed)
def test_localImportStar(self):
'''A local import * still allows undefined names to be found in upper scopes'''
self.flakes('''
def a():
from fu import *
bar
''', m.ImportStarUsed, m.UndefinedName)
def test_unpackedParameter(self):
'''Unpacked function parameters create bindings'''
self.flakes('''
def a((bar, baz)):
bar; baz
''')
def test_definedByGlobal(self):
'''"global" can make an otherwise undefined name in another function defined'''
self.flakes('''
def a(): global fu; fu = 1
def b(): fu
''')
test_definedByGlobal.todo = ''
def test_globalInGlobalScope(self):
"""
A global statement in the global scope is ignored.
"""
self.flakes('''
global x
def foo():
print x
''', m.UndefinedName)
def test_del(self):
'''del deletes bindings'''
self.flakes('a = 1; del a; a', m.UndefinedName)
def test_delGlobal(self):
'''del a global binding from a function'''
self.flakes('''
a = 1
def f():
global a
del a
a
''')
def test_delUndefined(self):
'''del an undefined name'''
self.flakes('del a', m.UndefinedName)
def test_globalFromNestedScope(self):
'''global names are available from nested scopes'''
self.flakes('''
a = 1
def b():
def c():
a
''')
def test_laterRedefinedGlobalFromNestedScope(self):
"""
Test that referencing a local name that shadows a global, before it is
defined, generates a warning.
"""
self.flakes('''
a = 1
def fun():
a
a = 2
return a
''', m.UndefinedLocal)
def test_laterRedefinedGlobalFromNestedScope2(self):
"""
Test that referencing a local name in a nested scope that shadows a
global declared in an enclosing scope, before it is defined, generates
a warning.
"""
self.flakes('''
a = 1
def fun():
global a
def fun2():
a
a = 2
return a
''', m.UndefinedLocal)
def test_intermediateClassScopeIgnored(self):
"""
If a name defined in an enclosing scope is shadowed by a local variable
and the name is used locally before it is bound, an unbound local
warning is emitted, even if there is a class scope between the enclosing
scope and the local scope.
"""
self.flakes('''
def f():
x = 1
class g:
def h(self):
a = x
x = None
print x, a
print x
''', m.UndefinedLocal)
def test_doubleNestingReportsClosestName(self):
"""
Test that referencing a local name in a nested scope that shadows a
variable declared in two different outer scopes before it is defined
in the innermost scope generates an UnboundLocal warning which
refers to the nearest shadowed name.
"""
exc = self.flakes('''
def a():
x = 1
def b():
x = 2 # line 5
def c():
x
x = 3
return x
return x
return x
''', m.UndefinedLocal).messages[0]
self.assertEqual(exc.message_args, ('x', 5))
def test_laterRedefinedGlobalFromNestedScope3(self):
"""
Test that referencing a local name in a nested scope that shadows a
global, before it is defined, generates a warning.
"""
self.flakes('''
def fun():
a = 1
def fun2():
a
a = 1
return a
return a
''', m.UndefinedLocal)
def test_nestedClass(self):
'''nested classes can access enclosing scope'''
self.flakes('''
def f(foo):
class C:
bar = foo
def f(self):
return foo
return C()
f(123).f()
''')
def test_badNestedClass(self):
'''free variables in nested classes must bind at class creation'''
self.flakes('''
def f():
class C:
bar = foo
foo = 456
return foo
f()
''', m.UndefinedName)
def test_definedAsStarArgs(self):
'''star and double-star arg names are defined'''
self.flakes('''
def f(a, *b, **c):
print a, b, c
''')
def test_definedInGenExp(self):
"""
Using the loop variable of a generator expression results in no
warnings.
"""
self.flakes('(a for a in xrange(10) if a)')
class NameTests(TestCase):
"""
Tests for some extra cases of name handling.
"""
def test_impossibleContext(self):
"""
A Name node with an unrecognized context results in a RuntimeError being
raised.
"""
tree = compile("x = 10", "<test>", "exec", PyCF_ONLY_AST)
# Make it into something unrecognizable.
tree.body[0].targets[0].ctx = object()
self.assertRaises(RuntimeError, checker.Checker, tree)

View file

@ -0,0 +1,28 @@
#!/usr/bin/python
# (c) 2005-2009 Divmod, Inc. See LICENSE file for details
from distutils.core import setup
setup(
name="pyflakes",
license="MIT",
version="0.4.0",
description="passive checker of Python programs",
author="Phil Frost",
maintainer="Moe Aboulkheir",
maintainer_email="moe@divmod.com",
url="http://www.divmod.org/trac/wiki/DivmodPyflakes",
packages=["pyflakes", "pyflakes.scripts", "pyflakes.test"],
scripts=["bin/pyflakes"],
long_description="""Pyflakes is program to analyze Python programs and detect various errors. It
works by parsing the source file, not importing it, so it is safe to use on
modules with side effects. It's also much faster.""",
classifiers=[
"Development Status :: 6 - Mature",
"Environment :: Console",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python",
"Topic :: Software Development",
"Topic :: Utilities",
])

View file

@ -0,0 +1,124 @@
diff --git a/README.rst b/README.rst
index 5f8467f..acff657 100644
--- a/README.rst
+++ b/README.rst
@@ -8,11 +8,13 @@ accessing a local before it is bound, and also gives warnings for things like
unused imports.
pyflakes-vim uses the output from PyFlakes to highlight errors in your code.
+To locate errors quickly, use quickfix_ commands:
Make sure to check vim.org_ for the latest updates.
.. _pyflakes.vim: http://www.vim.org/scripts/script.php?script_id=2441
.. _vim.org: http://www.vim.org/scripts/script.php?script_id=2441
+.. _quickfix: http://vimdoc.sourceforge.net/htmldoc/quickfix.html#quickfix
Quick Installation
------------------
@@ -57,12 +59,10 @@ Hacking
TODO
----
* signs_ support (show warning and error icons to left of the buffer area)
- * quickfix_ support (allow jumping forward and back through the error list)
* configuration variables
* parse or intercept useful output from the warnings module
.. _signs: http://www.vim.org/htmldoc/sign.html
-.. _quickfix: http://vimdoc.sourceforge.net/htmldoc/quickfix.html
Changelog
---------
diff --git a/pyflakes.vim b/pyflakes.vim
index 8aa508b..d6699bc 100644
--- a/pyflakes.vim
+++ b/pyflakes.vim
@@ -159,6 +159,42 @@ if !exists("*s:WideMsg")
endfun
endif
+if !exists("*s:GetQuickFixStackCount")
+ function s:GetQuickFixStackCount()
+ let l:stack_count = 0
+ try
+ silent colder 9
+ catch /E380:/
+ endtry
+
+ try
+ for i in range(9)
+ silent cnewer
+ let l:stack_count = l:stack_count + 1
+ endfor
+ catch /E381:/
+ return l:stack_count
+ endtry
+ endfunction
+endif
+
+if !exists("*s:ActivatePyflakesQuickFixWindow")
+ function s:ActivatePyflakesQuickFixWindow()
+ try
+ silent colder 9 " go to the bottom of quickfix stack
+ catch /E380:/
+ endtry
+
+ if s:pyflakes_qf > 0
+ try
+ exe "silent cnewer " . s:pyflakes_qf
+ catch /E381:/
+ echoerr "Could not activate Pyflakes Quickfix Window."
+ endtry
+ endif
+ endfunction
+endif
+
if !exists("*s:RunPyflakes")
function s:RunPyflakes()
highlight link PyFlakes SpellBad
@@ -174,12 +210,23 @@ if !exists("*s:RunPyflakes")
let b:matched = []
let b:matchedlines = {}
+
+ let b:qf_list = []
+ let b:qf_window_count = -1
+
python << EOF
for w in check(vim.current.buffer):
vim.command('let s:matchDict = {}')
vim.command("let s:matchDict['lineNum'] = " + str(w.lineno))
vim.command("let s:matchDict['message'] = '%s'" % vim_quote(w.message % w.message_args))
vim.command("let b:matchedlines[" + str(w.lineno) + "] = s:matchDict")
+
+ vim.command("let l:qf_item = {}")
+ vim.command("let l:qf_item.bufnr = bufnr('%')")
+ vim.command("let l:qf_item.filename = expand('%')")
+ vim.command("let l:qf_item.lnum = %s" % str(w.lineno))
+ vim.command("let l:qf_item.text = '%s'" % vim_quote(w.message % w.message_args))
+ vim.command("let l:qf_item.type = 'E'")
if w.col is None or isinstance(w, SyntaxError):
# without column information, just highlight the whole line
@@ -189,8 +236,21 @@ for w in check(vim.current.buffer):
# with a column number, highlight the first keyword there
vim.command(r"let s:mID = matchadd('PyFlakes', '^\%" + str(w.lineno) + r"l\_.\{-}\zs\k\+\k\@!\%>" + str(w.col) + r"c')")
+ vim.command("let l:qf_item.vcol = 1")
+ vim.command("let l:qf_item.col = %s" % str(w.col + 1))
+
vim.command("call add(b:matched, s:matchDict)")
+ vim.command("call add(b:qf_list, l:qf_item)")
EOF
+ if exists("s:pyflakes_qf")
+ " if pyflakes quickfix window is already created, reuse it
+ call s:ActivatePyflakesQuickFixWindow()
+ call setqflist(b:qf_list, 'r')
+ else
+ " one pyflakes quickfix window for all buffer
+ call setqflist(b:qf_list, '')
+ let s:pyflakes_qf = s:GetQuickFixStackCount()
+ endif
let b:cleared = 0
endfunction
end

View file

@ -3,8 +3,8 @@
" @Website: http://www.vim.org/account/profile.php?user_id=4037 " @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt) " @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Created: 2007-05-01. " @Created: 2007-05-01.
" @Last Change: 2013-09-26. " @Last Change: 2013-12-03.
" @Revision: 0.1.1297 " @Revision: 0.1.1310
" :filedoc: " :filedoc:
" A prototype used by |tlib#input#List|. " A prototype used by |tlib#input#List|.
@ -161,12 +161,14 @@ else
let self.width_filename = min([ let self.width_filename = min([
\ get(self, 'width_filename', &co), \ get(self, 'width_filename', &co),
\ empty(g:tlib#input#filename_max_width) ? &co : eval(g:tlib#input#filename_max_width), \ empty(g:tlib#input#filename_max_width) ? &co : eval(g:tlib#input#filename_max_width),
\ max(map(copy(self.base), 'strwidth(fnamemodify(v:val, ":t"))')) \ max(map(copy(self.base), 'strwidth(matchstr(v:val, "[^\\/]*$"))'))
\ ]) \ ])
" TLogVAR self.width_filename " TLogVAR self.width_filename
exec 'syntax match TLibFilename /[^\/]\+$/ contained containedin=TLibDir'
exec 'syntax match TLibDir /\%>'. (1 + self.width_filename) .'c \(|\|\[[^]]*\]\) \zs\(\(\a:\|\.\.\|\.\.\..\{-}\)\?[\/][^&<>*|]\{-}\)\?[^\/]\+$/ contained containedin=TLibMarker contains=TLibFilename' exec 'syntax match TLibDir /\%>'. (1 + self.width_filename) .'c \(|\|\[[^]]*\]\) \zs\(\(\a:\|\.\.\|\.\.\..\{-}\)\?[\/][^&<>*|]\{-}\)\?[^\/]\+$/ contained containedin=TLibMarker contains=TLibFilename'
exec 'syntax match TLibMarker /\%>'. (1 + self.width_filename) .'c \(|\|\[[^]]*\]\) \S.*$/ contains=TLibDir' exec 'syntax match TLibMarker /\%>'. (1 + self.width_filename) .'c \(|\|\[[^]]*\]\) \S.*$/ contains=TLibDir'
" exec 'syntax match TLibDir /\(|\|\[.\{-}\]\) \zs\(\(\a:\|\.\.\|\.\.\..\{-}\)\?[\/][^&<>*|]\{-}\)\?[^\/]\+$/ contained containedin=TLibMarker contains=TLibFilename'
" exec 'syntax match TLibMarker /\(|\|\[.\{-}\]\) \S.*$/ contains=TLibDir'
exec 'syntax match TLibFilename /[^\/]\+$/ contained containedin=TLibDir'
hi def link TLibMarker Special hi def link TLibMarker Special
hi def link TLibDir Directory hi def link TLibDir Directory
hi def link TLibFilename NonText hi def link TLibFilename NonText
@ -206,8 +208,9 @@ else
" TLogVAR use_indicators " TLogVAR use_indicators
if use_indicators if use_indicators
call insert(marker, '[') call insert(marker, '[')
if g:tlib_inputlist_filename_indicators
let bnr = bufnr(a:file) let bnr = bufnr(a:file)
" TLogVAR a:file, bnr, self.bufnr TLogVAR a:file, bnr, self.bufnr
if bnr != -1 if bnr != -1
if bnr == self.bufnr if bnr == self.bufnr
call add(marker, '%') call add(marker, '%')
@ -225,6 +228,7 @@ else
" endif " endif
" echom "DBG" a:file string(get(self,'filename_indicators')) " echom "DBG" a:file string(get(self,'filename_indicators'))
endif endif
endif
if has_key(self, 'filename_indicators') && has_key(self.filename_indicators, a:file) if has_key(self, 'filename_indicators') && has_key(self.filename_indicators, a:file)
if len(marker) > 1 if len(marker) > 1
call add(marker, '|') call add(marker, '|')

View file

@ -3,8 +3,8 @@
" @Website: http://www.vim.org/account/profile.php?user_id=4037 " @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt) " @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Created: 2007-06-24. " @Created: 2007-06-24.
" @Last Change: 2013-09-26. " @Last Change: 2013-11-05.
" @Revision: 0.1.240 " @Revision: 0.1.242
" :filedoc: " :filedoc:
@ -444,6 +444,7 @@ endf
function! tlib#agent#EditFileInTab(world, selected) "{{{3 function! tlib#agent#EditFileInTab(world, selected) "{{{3
" TLogVAR a:selected
call a:world.CloseScratch() call a:world.CloseScratch()
call tlib#file#With('tabedit', 'tab sbuffer', a:selected, a:world) call tlib#file#With('tabedit', 'tab sbuffer', a:selected, a:world)
return tlib#agent#Exit(a:world, a:selected) return tlib#agent#Exit(a:world, a:selected)

View file

@ -4,7 +4,7 @@
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt) " @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Created: 2007-06-30. " @Created: 2007-06-30.
" @Last Change: 2013-09-25. " @Last Change: 2013-09-25.
" @Revision: 0.0.141 " @Revision: 0.0.142
if &cp || exists("loaded_tlib_file_autoload") if &cp || exists("loaded_tlib_file_autoload")
finish finish
@ -36,12 +36,12 @@ function! tlib#file#Split(filename) "{{{3
endf endf
" :display: tlib#file#Join(filename_parts, ?strip_slashes=0) " :display: tlib#file#Join(filename_parts, ?strip_slashes=1)
" EXAMPLES: > " EXAMPLES: >
" tlib#file#Join(['foo', 'bar', 'filename.txt']) " tlib#file#Join(['foo', 'bar', 'filename.txt'])
" => 'foo/bar/filename.txt' " => 'foo/bar/filename.txt'
function! tlib#file#Join(filename_parts, ...) "{{{3 function! tlib#file#Join(filename_parts, ...) "{{{3
TVarArg 'strip_slashes' TVarArg ['strip_slashes', 1]
" TLogVAR a:filename_parts, strip_slashes " TLogVAR a:filename_parts, strip_slashes
if strip_slashes if strip_slashes
" let rx = tlib#rx#Escape(g:tlib#dir#sep) .'$' " let rx = tlib#rx#Escape(g:tlib#dir#sep) .'$'

View file

@ -3,8 +3,8 @@
" @Website: http://www.vim.org/account/profile.php?user_id=4037 " @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt) " @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Created: 2007-07-18. " @Created: 2007-07-18.
" @Last Change: 2013-10-16. " @Last Change: 2013-11-11.
" @Revision: 0.0.242 " @Revision: 0.0.251
if &cp || exists("loaded_tlib_scratch_autoload") if &cp || exists("loaded_tlib_scratch_autoload")
finish finish
@ -65,7 +65,7 @@ function! tlib#scratch#UseScratch(...) "{{{3
else else
let cmd = 'buffer!' let cmd = 'buffer!'
endif endif
" TLogVAR cmd " TLogVAR cmd, bn
silent exec 'noautocmd keepalt keepj' cmd bn silent exec 'noautocmd keepalt keepj' cmd bn
endif endif
else else
@ -77,7 +77,7 @@ function! tlib#scratch#UseScratch(...) "{{{3
else else
let cmd = 'edit' let cmd = 'edit'
endif endif
" TLogVAR cmd " TLogVAR cmd, id
silent exec 'noautocmd keepalt keepj' cmd escape(id, '%#\ ') silent exec 'noautocmd keepalt keepj' cmd escape(id, '%#\ ')
" silent exec 'split '. id " silent exec 'split '. id
endif endif
@ -100,7 +100,7 @@ function! tlib#scratch#UseScratch(...) "{{{3
endif endif
endif endif
let keyargs.scratch = bufnr('%') let keyargs.scratch = bufnr('%')
" TLogVAR 2, winnr(), bufnr('%'), bufname("%") " TLogVAR 2, winnr(), bufnr('%'), bufname("%"), keyargs.scratch
return keyargs.scratch return keyargs.scratch
endf endf

View file

@ -1495,7 +1495,7 @@ tlib#file#Split(filename)
< <
*tlib#file#Join()* *tlib#file#Join()*
tlib#file#Join(filename_parts, ?strip_slashes=0) tlib#file#Join(filename_parts, ?strip_slashes=1)
EXAMPLES: > EXAMPLES: >
tlib#file#Join(['foo', 'bar', 'filename.txt']) tlib#file#Join(['foo', 'bar', 'filename.txt'])
=> 'foo/bar/filename.txt' => 'foo/bar/filename.txt'

View file

@ -4,7 +4,7 @@
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt) " @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Created: 2007-04-10. " @Created: 2007-04-10.
" @Last Change: 2013-09-25. " @Last Change: 2013-09-25.
" @Revision: 746 " @Revision: 748
" GetLatestVimScripts: 1863 1 tlib.vim " GetLatestVimScripts: 1863 1 tlib.vim
if &cp || exists("loaded_tlib") if &cp || exists("loaded_tlib")
@ -14,7 +14,7 @@ if v:version < 700 "{{{2
echoerr "tlib requires Vim >= 7" echoerr "tlib requires Vim >= 7"
finish finish
endif endif
let loaded_tlib = 106 let loaded_tlib = 107
let s:save_cpo = &cpo let s:save_cpo = &cpo
set cpo&vim set cpo&vim

View file

@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (C) 2013 Bailey Ling Copyright (C) 2013-2014 Bailey Ling
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the "Software"), a copy of this software and associated documentation files (the "Software"),

View file

@ -10,7 +10,7 @@ Lean &amp; mean status/tabline for vim that's light as air.
* Integrates with a variety of plugins, including: [vim-bufferline][6], [fugitive][4], [unite][9], [ctrlp][10], [minibufexpl][15], [gundo][16], [undotree][17], [nerdtree][18], [tagbar][19], [vim-gitgutter][29], [vim-signify][30], [syntastic][5], [eclim][34], [lawrencium][21], [virtualenv][31], [tmuxline][35]. * Integrates with a variety of plugins, including: [vim-bufferline][6], [fugitive][4], [unite][9], [ctrlp][10], [minibufexpl][15], [gundo][16], [undotree][17], [nerdtree][18], [tagbar][19], [vim-gitgutter][29], [vim-signify][30], [syntastic][5], [eclim][34], [lawrencium][21], [virtualenv][31], [tmuxline][35].
* Looks good with regular fonts and provides configuration points so you can use unicode or powerline symbols. * Looks good with regular fonts and provides configuration points so you can use unicode or powerline symbols.
* Optimized for speed; it loads in under a millisecond. * Optimized for speed; it loads in under a millisecond.
* Extensive suite of themes for popular colorschemes including [solarized][23] (dark and light), [tomorrow][24] (all variants), [base16][32] (all variants), [molokai][25], [jellybeans][26] and others; have a look at the [screenshots][14] in the wiki. * Extensive suite of themes for popular color schemes including [solarized][23] (dark and light), [tomorrow][24] (all variants), [base16][32] (all variants), [molokai][25], [jellybeans][26] and others; have a look at the [screenshots][14] in the wiki.
* Supports 7.2 as the minimum Vim version. * Supports 7.2 as the minimum Vim version.
* The master branch tries to be as stable as possible, and new features are merged in only after they have gone through a [full regression test][33]. * The master branch tries to be as stable as possible, and new features are merged in only after they have gone through a [full regression test][33].
* Unit testing suite. * Unit testing suite.
@ -70,6 +70,9 @@ vim-airline integrates with a variety of plugins out of the box. These extensio
#### [tmuxline][35] #### [tmuxline][35]
![image](https://f.cloud.github.com/assets/1532071/1559276/4c28fbac-4fc7-11e3-90ef-7e833d980f98.gif) ![image](https://f.cloud.github.com/assets/1532071/1559276/4c28fbac-4fc7-11e3-90ef-7e833d980f98.gif)
#### [promptline][36]
![airline-promptline-sc](https://f.cloud.github.com/assets/1532071/1871900/7d4b28a0-789d-11e3-90e4-16f37269981b.gif)
## Extras ## Extras
vim-airline also supplies some supplementary stand-alone extensions. In addition to the tabline extension mentioned earlier, there is also: vim-airline also supplies some supplementary stand-alone extensions. In addition to the tabline extension mentioned earlier, there is also:
@ -164,7 +167,7 @@ Contributions and pull requests are welcome. Please take note of the following
# License # License
MIT License. Copyright (c) 2013 Bailey Ling. MIT License. Copyright (c) 2013-2014 Bailey Ling.
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/bling/vim-airline/trend.png)](https://bitdeli.com/free "Bitdeli Badge") [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/bling/vim-airline/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
@ -204,3 +207,4 @@ MIT License. Copyright (c) 2013 Bailey Ling.
[33]: https://github.com/bling/vim-airline/wiki/Test-Plan [33]: https://github.com/bling/vim-airline/wiki/Test-Plan
[34]: http://eclim.org [34]: http://eclim.org
[35]: https://github.com/edkolev/tmuxline.vim [35]: https://github.com/edkolev/tmuxline.vim
[36]: https://github.com/edkolev/promptline.vim

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
let g:airline_statusline_funcrefs = get(g:, 'airline_statusline_funcrefs', []) let g:airline_statusline_funcrefs = get(g:, 'airline_statusline_funcrefs', [])

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
let s:prototype = {} let s:prototype = {}

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
function! airline#debug#profile1() function! airline#debug#profile1()

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
function! airline#deprecation#check() function! airline#deprecation#check()

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
let s:ext = {} let s:ext = {}
@ -20,7 +20,6 @@ endfunction
let s:script_path = tolower(resolve(expand('<sfile>:p:h'))) let s:script_path = tolower(resolve(expand('<sfile>:p:h')))
let s:filetype_overrides = { let s:filetype_overrides = {
\ 'netrw': [ 'netrw', '%f' ],
\ 'nerdtree': [ 'NERD', '' ], \ 'nerdtree': [ 'NERD', '' ],
\ 'gundo': [ 'Gundo', '' ], \ 'gundo': [ 'Gundo', '' ],
\ 'diff': [ 'diff', '' ], \ 'diff': [ 'diff', '' ],
@ -128,6 +127,10 @@ function! airline#extensions#load()
call airline#extensions#unite#init(s:ext) call airline#extensions#unite#init(s:ext)
endif endif
if exists(':NetrwSettings')
call airline#extensions#netrw#init(s:ext)
endif
if get(g:, 'loaded_vimfiler', 0) if get(g:, 'loaded_vimfiler', 0)
let g:vimfiler_force_overwrite_statusline = 0 let g:vimfiler_force_overwrite_statusline = 0
endif endif
@ -199,6 +202,10 @@ function! airline#extensions#load()
call airline#extensions#tmuxline#init(s:ext) call airline#extensions#tmuxline#init(s:ext)
endif endif
if get(g:, 'airline#extensions#promptline#enabled', 1) && exists(':PromptlineSnapshot') && len(get(g:, 'airline#extensions#promptline#snapshot_file', ''))
call airline#extensions#promptline#init(s:ext)
endif
" load all other extensions not part of the default distribution " load all other extensions not part of the default distribution
for file in split(globpath(&rtp, "autoload/airline/extensions/*.vim"), "\n") for file in split(globpath(&rtp, "autoload/airline/extensions/*.vim"), "\n")
" we have to check both resolved and unresolved paths, since it's possible " we have to check both resolved and unresolved paths, since it's possible

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
let s:has_fugitive = exists('*fugitive#head') let s:has_fugitive = exists('*fugitive#head')
@ -10,10 +10,6 @@ if !s:has_fugitive && !s:has_lawrencium && !s:has_vcscommand
finish finish
endif endif
let s:empty_message = get(g:, 'airline#extensions#branch#empty_message',
\ get(g:, 'airline_branch_empty_message', ''))
let s:symbol = get(g:, 'airline#extensions#branch#symbol', g:airline_symbols.branch)
function! airline#extensions#branch#head() function! airline#extensions#branch#head()
let head = '' let head = ''
@ -48,9 +44,12 @@ endfunction
function! airline#extensions#branch#get_head() function! airline#extensions#branch#get_head()
let head = airline#extensions#branch#head() let head = airline#extensions#branch#head()
let empty_message = get(g:, 'airline#extensions#branch#empty_message',
\ get(g:, 'airline_branch_empty_message', ''))
let symbol = get(g:, 'airline#extensions#branch#symbol', g:airline_symbols.branch)
return empty(head) return empty(head)
\ ? s:empty_message \ ? empty_message
\ : printf('%s%s', empty(s:symbol) ? '' : s:symbol.(g:airline_symbols.space), head) \ : printf('%s%s', empty(symbol) ? '' : symbol.(g:airline_symbols.space), head)
endfunction endfunction
function! s:check_in_path() function! s:check_in_path()

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
if !exists('*bufferline#get_status_string') if !exists('*bufferline#get_status_string')

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
if !get(g:, 'command_t_loaded', 0) if !get(g:, 'command_t_loaded', 0)

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
if !get(g:, 'loaded_csv', 0) && !exists(':Table') if !get(g:, 'loaded_csv', 0) && !exists(':Table')

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
if !get(g:, 'loaded_ctrlp', 0) if !get(g:, 'loaded_ctrlp', 0)

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
let s:section_truncate_width = get(g:, 'airline#extensions#default#section_truncate_width', { let s:section_truncate_width = get(g:, 'airline#extensions#default#section_truncate_width', {

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
if !exists(':ProjectCreate') if !exists(':ProjectCreate')

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
" we don't actually want this loaded :P " we don't actually want this loaded :P

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
if !get(g:, 'loaded_signify', 0) && !get(g:, 'loaded_gitgutter', 0) if !get(g:, 'loaded_signify', 0) && !get(g:, 'loaded_gitgutter', 0)

View file

@ -0,0 +1,32 @@
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2
if !exists(':NetrwSettings')
finish
endif
function! airline#extensions#netrw#apply(...)
if &ft == 'netrw'
let spc = g:airline_symbols.space
call a:1.add_section('airline_a', spc.'netrw'.spc)
if exists('*airline#extensions#branch#get_head')
call a:1.add_section('airline_b', spc.'%{airline#extensions#branch#get_head()}'.spc)
endif
call a:1.add_section('airline_c', spc.'%f'.spc)
call a:1.split()
call a:1.add_section('airline_y', spc.'%{airline#extensions#netrw#sortstring()}'.spc)
return 1
endif
endfunction
function! airline#extensions#netrw#init(ext)
let g:netrw_force_overwrite_statusline = 0
call a:ext.add_statusline_func('airline#extensions#netrw#apply')
endfunction
function! airline#extensions#netrw#sortstring()
let order = (g:netrw_sort_direction =~ 'n') ? '+' : '-'
return g:netrw_sort_by . (g:airline_symbols.space) . '[' . order . ']'
endfunction

View file

@ -0,0 +1,33 @@
" MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2
if !exists(':PromptlineSnapshot')
finish
endif
if !exists('airline#extensions#promptline#snapshot_file') || !len('airline#extensions#promptline#snapshot_file')
finish
endif
let s:prompt_snapshot_file = get(g:, 'airline#extensions#promptline#snapshot_file', '')
let s:color_template = get(g:, 'airline#extensions#promptline#color_template', 'normal')
function! airline#extensions#promptline#init(ext)
call a:ext.add_theme_func('airline#extensions#promptline#set_prompt_colors')
endfunction
function! airline#extensions#promptline#set_prompt_colors(palette)
let color_template = has_key(a:palette, s:color_template) ? s:color_template : 'normal'
let mode_palette = a:palette[color_template]
if !has_key(g:, 'promptline_symbols')
let g:promptline_symbols = {
\ 'left' : g:airline_left_sep,
\ 'right' : g:airline_right_sep,
\ 'left_alt' : g:airline_left_alt_sep,
\ 'right_alt' : g:airline_right_alt_sep}
endif
let promptline_theme = promptline#api#create_theme_from_airline(mode_palette)
call promptline#api#create_snapshot_with_theme(s:prompt_snapshot_file, promptline_theme)
endfunction

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
let g:airline#extensions#quickfix#quickfix_text = 'Quickfix' let g:airline#extensions#quickfix#quickfix_text = 'Quickfix'

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
if !exists(':SyntasticCheck') if !exists(':SyntasticCheck')

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
let s:formatter = get(g:, 'airline#extensions#tabline#formatter', 'default') let s:formatter = get(g:, 'airline#extensions#tabline#formatter', 'default')

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
let s:fmod = get(g:, 'airline#extensions#tabline#fnamemod', ':~:.') let s:fmod = get(g:, 'airline#extensions#tabline#fnamemod', ':~:.')

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
function! airline#extensions#tabline#unique_tail#format(bufnr, buffers) function! airline#extensions#tabline#unique_tail#format(bufnr, buffers)

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
let s:skip_symbol = '…' let s:skip_symbol = '…'

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
if !exists(':TagbarToggle') if !exists(':TagbarToggle')

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
if !exists(':Tmuxline') if !exists(':Tmuxline')

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
if !exists(':UndotreeToggle') if !exists(':UndotreeToggle')

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
if !get(g:, 'loaded_unite', 0) if !get(g:, 'loaded_unite', 0)

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
if !get(g:, 'virtualenv_loaded', 0) if !get(g:, 'virtualenv_loaded', 0)

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
" http://got-ravings.blogspot.com/2008/10/vim-pr0n-statusline-whitespace-flags.html " http://got-ravings.blogspot.com/2008/10/vim-pr0n-statusline-whitespace-flags.html

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
let s:is_win32term = (has('win32') || has('win64')) && !has('gui_running') let s:is_win32term = (has('win32') || has('win64')) && !has('gui_running')

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
function! s:check_defined(variable, default) function! s:check_defined(variable, default)

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
let s:parts = {} let s:parts = {}

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
call airline#init#bootstrap() call airline#init#bootstrap()

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
" generates a dictionary which defines the colors for each highlight group " generates a dictionary which defines the colors for each highlight group

View file

@ -0,0 +1,57 @@
"
" Colorscheme: Kalisi for airline. Inspired by powerline.
" 06.02.2014 Arthur Jaron
" hifreeo@gmail.com
"
" Insert mode
let s:I1 = [ '#ffffff' , '#e80000' , 23 , 231 ]
let s:I2 = [ '#c5c5c5' , '#901010' , 74 , 31 ]
let s:I3 = [ '#c5c5c5' , '#500000' , 117 , 24 ]
" Visual mode
let s:V1 = [ '#005f5f' , '#ffffff' , 23 , 231 ]
let s:V2 = [ '#5fafd7' , '#0087af' , 74 , 31 ]
let s:V3 = [ '#87d7ff' , '#005f87' , 117 , 24 ]
" Replace mode
let s:R1 = [ '#8e00da' , '#ffffff' , 23 , 231 ]
let s:R2 = [ '#8e00da' , '#ce99ff' , 74 , 31 ]
let s:R3 = [ '#ce99ff' , '#8e00da' , 117 , 24 ]
let g:airline#themes#kalisi#palette = {}
function! airline#themes#kalisi#refresh()
" Normal mode
let s:N1 = [ '#005f00' , '#afd700' , 22 , 148 ]
let s:N2 = [ '#afd700' , '#005f00' , 247 , 236 ]
let s:N3 = airline#themes#get_highlight('StatusLine')
" Tabline Plugin
let g:airline#themes#kalisi#palette.tabline = {
\ 'airline_tab': ['#A6DB29', '#005f00', 231, 29, ''],
\ 'airline_tabsel': ['#404042', '#A6DB29', 231, 36, ''],
\ 'airline_tabtype': ['#afd700', '#005f00', 231, 36, ''],
\ 'airline_tabfill': ['#ffffff', '#000000', 231, 23, ''],
\ 'airline_tabhid': ['#c5c5c5', '#404042', 231, 88, ''],
\ 'airline_tabmod': ['#ffffff', '#F1266F', 231, 88, ''],
\ }
let g:airline#themes#kalisi#palette.normal = airline#themes#generate_color_map(s:N1, s:N2, s:N3)
let g:airline#themes#kalisi#palette.visual = airline#themes#generate_color_map(s:V1, s:V2, s:V3)
let g:airline#themes#kalisi#palette.insert = airline#themes#generate_color_map(s:I1, s:I2, s:I3)
let g:airline#themes#kalisi#palette.replace = airline#themes#generate_color_map(s:R1, s:R2, s:R3)
" Inactive Mode
" let s:IA = [ '#c5c5c5' , '#505052' , 239 , 234 , '' ]
let s:IA = airline#themes#get_highlight('StatusLineNC')
let g:airline#themes#kalisi#palette.inactive = airline#themes#generate_color_map(s:IA, s:IA, s:IA)
let g:airline#themes#kalisi#palette.inactive_modified = {
\ 'statusline': [ '#F1266F' , '' , '53' , '' , '' ] ,
\ }
endfunction
call airline#themes#kalisi#refresh()

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
call airline#init#bootstrap() call airline#init#bootstrap()

View file

@ -450,6 +450,26 @@ tmuxline <https://github.com/edkolev/tmuxline.vim>
startup > startup >
airline#extensions#tmuxline#snapshot_file = "~/.tmux-statusline-colors.conf" airline#extensions#tmuxline#snapshot_file = "~/.tmux-statusline-colors.conf"
< <
------------------------------------- *airline-promptline*
promptline <https://github.com/edkolev/promptline.vim>
* configure the path to the snapshot .sh file. Mandatory option. The created
file should be sourced by the shell on login >
" in .vimrc
airline#extensions#promptline#snapshot_file = "~/.shell_prompt.sh"
" in .bashrc/.zshrc
[ -f ~/.shell_prompt.sh ] && source ~/.shell_prompt.sh
<
* enable/disable promptline integration >
let g:airline#extensions#promptline#enabled = 0
<
* configure which mode colors should be used in prompt >
let airline#extensions#promptline#color_template = 'normal' (default)
let airline#extensions#promptline#color_template = 'insert'
let airline#extensions#promptline#color_template = 'visual'
let airline#extensions#promptline#color_template = 'replace'
<
============================================================================== ==============================================================================
ADVANCED CUSTOMIZATION *airline-advanced-customization* ADVANCED CUSTOMIZATION *airline-advanced-customization*
@ -699,7 +719,7 @@ Contributions and pull requests are welcome.
============================================================================== ==============================================================================
LICENSE *airline-license* LICENSE *airline-license*
MIT License. Copyright © 2013 Bailey Ling. MIT License. Copyright © 2013-2014 Bailey Ling.
vim:tw=78:ts=8:ft=help:norl: vim:tw=78:ts=8:ft=help:norl:

View file

@ -1,4 +1,4 @@
" MIT License. Copyright (c) 2013 Bailey Ling. " MIT License. Copyright (c) 2013-2014 Bailey Ling.
" vim: et ts=2 sts=2 sw=2 " vim: et ts=2 sts=2 sw=2
if &cp || v:version < 702 || (exists('g:loaded_airline') && g:loaded_airline) if &cp || v:version < 702 || (exists('g:loaded_airline') && g:loaded_airline)

View file

@ -136,6 +136,9 @@ function! fugitive#extract_git_dir(path) abort
" checking for them since such checks are extremely slow. " checking for them since such checks are extremely slow.
break break
endif endif
if index(split($GIT_CEILING_DIRECTORIES, ':'), root) >= 0
break
endif
let dir = s:sub(root, '[\/]$', '') . '/.git' let dir = s:sub(root, '[\/]$', '') . '/.git'
let type = getftype(dir) let type = getftype(dir)
if type ==# 'dir' && fugitive#is_git_dir(dir) if type ==# 'dir' && fugitive#is_git_dir(dir)

View file

@ -14,6 +14,7 @@ additional contributions from:
* [bpugh](https://github.com/bpugh) * [bpugh](https://github.com/bpugh)
* [bruno-](https://github.com/bruno-) * [bruno-](https://github.com/bruno-)
* [darkwise](https://github.com/darkwise) * [darkwise](https://github.com/darkwise)
* [fish-face](https://github.com/fish-face)
* [henrik](https://github.com/henrik) * [henrik](https://github.com/henrik)
* [holizz](https://github.com/holizz) * [holizz](https://github.com/holizz)
* [honza](https://github.com/honza) * [honza](https://github.com/honza)

View file

@ -22,6 +22,8 @@ dependencies. SnipMate depends on [vim-addon-mw-utils][mw-utils] and
[tlib][tlib]. Since SnipMate does not ship with any snippets, we suggest [tlib][tlib]. Since SnipMate does not ship with any snippets, we suggest
looking at the [vim-snippets][vim-snippets] repository. looking at the [vim-snippets][vim-snippets] repository.
* Using [VAM][vam], add `vim-snippets` to the list of packages to be installed.
* Using [Pathogen][pathogen], run the following commands: * Using [Pathogen][pathogen], run the following commands:
% cd ~/.vim/bundle % cd ~/.vim/bundle
@ -32,8 +34,6 @@ looking at the [vim-snippets][vim-snippets] repository.
# Optional: # Optional:
% git clone https://github.com/honza/vim-snippets.git % git clone https://github.com/honza/vim-snippets.git
* Using [VAM][vam], add `vim-snippets` to the list of packages to be installed.
* Using [Vundle][vundle], add the following to your `vimrc` then run * Using [Vundle][vundle], add the following to your `vimrc` then run
`:BundleInstall` `:BundleInstall`
@ -46,6 +46,11 @@ looking at the [vim-snippets][vim-snippets] repository.
## Release Notes ## ## Release Notes ##
### Master ###
* Fix bug with mirrors in the first column
* Fix bug with tabs in indents ([#143][143])
### 0.87 - 2014-01-04 ### ### 0.87 - 2014-01-04 ###
* Stop indenting empty lines when expanding snippets * Stop indenting empty lines when expanding snippets
@ -68,3 +73,5 @@ looking at the [vim-snippets][vim-snippets] repository.
[vam]: https://github.com/marcweber/vim-addon-manager [vam]: https://github.com/marcweber/vim-addon-manager
[pathogen]: https://github.com/tpope/vim-pathogen [pathogen]: https://github.com/tpope/vim-pathogen
[vundle]: https://github.com/gmarik/vundle [vundle]: https://github.com/gmarik/vundle
[143]: https://github.com/garbas/vim-snipmate/issues/143

View file

@ -79,7 +79,7 @@ fun! snipMate#expandSnip(snip, col)
endif endif
" Insert snippet with proper indentation " Insert snippet with proper indentation
let indent = indent(lnum) + 1 let indent = match(line, '\S\|$') + 1
call setline(lnum, line . snipLines[0]) call setline(lnum, line . snipLines[0])
call append(lnum, map(snipLines[1:], "empty(v:val) ? v:val : '" . strpart(line, 0, indent - 1) . "' . v:val")) call append(lnum, map(snipLines[1:], "empty(v:val) ? v:val : '" . strpart(line, 0, indent - 1) . "' . v:val"))
@ -375,10 +375,14 @@ function! s:state_proto.update_vars(change)
let i += 1 let i += 1
endif endif
" Split the line into three parts: the mirror, what's before it, and
" what's after it. Then combine them using the new mirror string.
" Subtract one to go from column index to byte index
let theline = getline(lnum) let theline = getline(lnum)
" subtract -1 to go from column byte index to string byte index let update = strpart(theline, 0, col - 1)
" subtract another -1 to exclude the col'th element let update .= newWord
call setline(lnum, theline[0:(col-2)] . newWord . theline[(col+self.end_col-self.start_col-a:change-1):]) let update .= strpart(theline, col + self.end_col - self.start_col - a:change - 1)
call setline(lnum, update)
endfor endfor
" Reposition the cursor in case a var updates on the same line but before " Reposition the cursor in case a var updates on the same line but before

View file

@ -51,6 +51,32 @@ If you have VimL only (vim without python support) your best option is using
garbas/vim-snipmate and cope with the minor bugs found in the engine. garbas/vim-snipmate and cope with the minor bugs found in the engine.
Installation
============
First be aware that there are many options, see "Snippet engines" above.
Second be aware than there are [tons of plugin managers](http://vim-wiki.mawercer.de/wiki/topic/vim%20plugin%20managment.html)
which is why Marc Weber thinks that it doesn't make sense to repeat the same
repetitive information everywhere.
*Recommended way:*
[vim-addon-manager](vim-addon-manager) (because Marc Weber wrote it for exactly
this reason, it supports simple dependency management). Eg you're done by this
line in your .vimrc:
```
" assuming you want to use snipmate snippet engine
ActivateAddons vim-snippets snipmate
```
[vim-pi](https://bitbucket.org/vimcommunity/vim-pi/issue/90/we-really-need-a-web-interface)
Is the place to discuss plugin managers and repository resources.
About how to install snipate see [snipmate@garbas](https://github.com/garbas/vim-snipmate)
(Bundle, Pathogen, git clone - keywords to make people find this link by ctrl-f search)
I know that I should be reading the docs of the snippet engine, just let me copy paste into my .vmirc:
(See this pull request)[https://github.com/honza/vim-snippets/pull/307/files].
Policies / for contributors Policies / for contributors
=========================== ===========================
Some snippets are useful for almost all languages, so let's try to have the same Some snippets are useful for almost all languages, so let's try to have the same

View file

@ -90,7 +90,7 @@ snippet class
${0} ${0}
} }
snippet node snippet node
node "${1:`vim_snippets#Filename('', 'fqdn')`}" { node '${1:`vim_snippets#Filename('', 'fqdn')`}' {
${0} ${0}
} }
snippet case snippet case
@ -122,99 +122,99 @@ snippet [
snippet > snippet >
${1} => ${0} ${1} => ${0}
snippet p: snippet p:
"puppet://puppet/${1:module name}/${0:file name}" 'puppet://puppet/${1:module name}/${0:file name}'
# #
# Functions # Functions
snippet alert snippet alert
alert("${1:message}") alert('${1:message}')
snippet crit snippet crit
crit("${1:message}") crit('${1:message}')
snippet debug snippet debug
debug("${1:message}") debug('${1:message}')
snippet defined snippet defined
defined(${1:Resource}["${2:name}"]) defined(${1:Resource}['${2:name}'])
snippet emerg snippet emerg
emerg("${1:message}") emerg('${1:message}')
snippet extlookup Simple extlookup snippet extlookup Simple extlookup
extlookup("${1:variable}") extlookup('${1:variable}')
snippet extlookup Extlookup with defaults snippet extlookup Extlookup with defaults
extlookup("${1:variable}", "${2:default}") extlookup('${1:variable}', '${2:default}')
snippet extlookup Extlookup with defaults and custom data file snippet extlookup Extlookup with defaults and custom data file
extlookup("${1:variable}", "${2:default}", "${3:data source}") extlookup('${1:variable}', '${2:default}', '${3:data source}')
snippet fail snippet fail
fail("${1:message}") fail('${1:message}')
snippet info snippet info
info("${1:message}") info('${1:message}')
snippet inline_template snippet inline_template
inline_template("<%= ${1} %>") inline_template('<%= ${1} %>')
snippet notice snippet notice
notice("${1:message}") notice('${1:message}')
snippet realize snippet realize
realize(${1:Resource}[${2:name}]) realize(${1:Resource}[${2:name}])
snippet regsubst snippet regsubst
regsubst(${1:hay stack}, ${2:needle}, "${3:replacement}") regsubst(${1:hay stack}, ${2:needle}, '${3:replacement}')
snippet inc snippet inc
include ${1:classname} include ${1:classname}
snippet split snippet split
split(${1:hay stack}, "${2:patten}") split(${1:hay stack}, '${2:patten}')
snippet versioncmp snippet versioncmp
versioncmp("${1:version}", "${2:version}") versioncmp('${1:version}', '${2:version}')
snippet warning snippet warning
warning("${1:message}") warning('${1:message}')
# #
# Types # Types
snippet cron snippet cron
cron{ "${1:name}": cron { '${1:name}':
command => "${2}", command => '${2}',
user => "${3:root}", user => '${3:root}',
${4} => ${0} ${4} => ${0},
} }
snippet exec snippet exec
exec{ "${1:name}": exec { '${1:name}':
command => "${2:$1}", command => '${2:$1}',
user => "${3:root}", user => '${3:root}',
${4} => ${0} ${4} => ${0},
} }
snippet user snippet user
user{ "${1:user}": user { '${1:user}':
comment => "${2:$1}",
ensure => present, ensure => present,
comment => '${2:$1}',
managehome => true, managehome => true,
home => "${0:/home/$1}" home => '${0:/home/$1}',
} }
snippet group snippet group
group{ "${1:group}": group { '${1:group}':
ensure => ${0:present} ensure => ${0:present},
} }
snippet host snippet host
host{ "${1:hostname}": host { '${1:hostname}':
ip => ${0:127.0.0.1} ip => ${0:127.0.0.1},
} }
snippet mailalias snippet mailalias
mailalias{ "${1:localpart}": mailalias { '${1:localpart}':
recipient => "${0:recipient}" recipient => '${0:recipient}',
} }
snippet mount snippet mount
mount{ "${1:destination path}": mount { '${1:destination path}':
ensure => ${2:mounted}, ensure => ${2:mounted},
device => "${0:device name or path}" device => '${0:device name or path}',
} }
snippet package snippet package
package{ "${1:package name}": package { '${1:package name}':
ensure => ${0:present} ensure => ${0:present},
} }
snippet yumrepo snippet yumrepo
yumrepo{ "${1:repo name}": yumrepo { '${1:repo name}':
descr => "${2:$1}", Descr => '${2:$1}',
enabled => ${0:1} enabled => ${0:1},
} }
snippet define snippet define
@ -227,7 +227,7 @@ snippet service
ensure => running, ensure => running,
enable => true, enable => true,
require => [ Package['${2:package}'], File['${3:file}'], ], require => [ Package['${2:package}'], File['${3:file}'], ],
subscribe => [ File['${4:configfile1}'], File['${5:configfile2}'], Package['${6:package}'], ] subscribe => [ File['${4:configfile1}'], File['${5:configfile2}'], Package['${6:package}'], ],
} }
snippet file snippet file

View file

@ -35,6 +35,7 @@ vim-fugitive https://github.com/tpope/vim-fugitive
vim-airline https://github.com/bling/vim-airline vim-airline https://github.com/bling/vim-airline
goyo.vim https://github.com/junegunn/goyo.vim goyo.vim https://github.com/junegunn/goyo.vim
vim-zenroom2 https://github.com/amix/vim-zenroom2 vim-zenroom2 https://github.com/amix/vim-zenroom2
pyflakes-pathogen https://github.com/mitechie/pyflakes-pathogen
""".strip() """.strip()
GITHUB_ZIP = '%s/archive/master.zip' GITHUB_ZIP = '%s/archive/master.zip'

View file

@ -293,23 +293,21 @@ autocmd BufWrite *.coffee :call DeleteTrailingWS()
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => vimgrep searching and cope displaying " => Ack searching and cope displaying
" requires ack.vim - it's much better than vimgrep/grep
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" When you press gv you vimgrep after the selected text " When you press gv you Ack after the selected text
vnoremap <silent> gv :call VisualSelection('gv', '')<CR> vnoremap <silent> gv :call VisualSelection('gv', '')<CR>
" Open vimgrep and put the cursor in the right position " Open Ack and put the cursor in the right position
map <leader>g :vimgrep // **/*.<left><left><left><left><left><left><left> map <leader>g :Ack
" Vimgreps in the current file
map <leader><space> :vimgrep // <C-R>%<C-A><right><right><right><right><right><right><right><right><right>
" When you press <leader>r you can search and replace the selected text " When you press <leader>r you can search and replace the selected text
vnoremap <silent> <leader>r :call VisualSelection('replace', '')<CR> vnoremap <silent> <leader>r :call VisualSelection('replace', '')<CR>
" Do :help cope if you are unsure what cope is. It's super useful! " Do :help cope if you are unsure what cope is. It's super useful!
" "
" When you search with vimgrep, display your results in cope by doing: " When you search with Ack, display your results in cope by doing:
" <leader>cc " <leader>cc
" "
" To go to the next search result do: " To go to the next search result do:
@ -373,7 +371,7 @@ function! VisualSelection(direction, extra_filter) range
if a:direction == 'b' if a:direction == 'b'
execute "normal ?" . l:pattern . "^M" execute "normal ?" . l:pattern . "^M"
elseif a:direction == 'gv' elseif a:direction == 'gv'
call CmdLine("vimgrep " . '/'. l:pattern . '/' . ' **/*.' . a:extra_filter) call CmdLine("Ack \"" . l:pattern . "\" " )
elseif a:direction == 'replace' elseif a:direction == 'replace'
call CmdLine("%s" . '/'. l:pattern . '/') call CmdLine("%s" . '/'. l:pattern . '/')
elseif a:direction == 'f' elseif a:direction == 'f'