mirror of
https://github.com/gryf/.vim.git
synced 2025-12-17 11:30:29 +01:00
Commented changes in plugins, updated vimwiki, repaired zoom plugin, added
buffergator, updated pythonhelper, removed leftovers
This commit is contained in:
@@ -13,8 +13,6 @@ setlocal softtabstop=4
|
||||
setlocal tabstop=4
|
||||
setlocal textwidth=78
|
||||
setlocal colorcolumn=+1
|
||||
" overwrite status line
|
||||
setlocal statusline=%<%F\ %{TagInStatusLine()}\ %h%m%r%=%(%l,%c%V%)\ %3p%%
|
||||
|
||||
set wildignore+=*.pyc
|
||||
|
||||
|
||||
@@ -1,311 +0,0 @@
|
||||
# -*- 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
|
||||
@@ -1,9 +1,7 @@
|
||||
" File: pythonhelper.vim
|
||||
" Author: Michal Vitecek <fuf-at-mageo-dot-cz>
|
||||
" Version: 0.81
|
||||
" Last Modified: Oct 24, 2002
|
||||
"
|
||||
" Modified by Marius Gedminas <mgedmin@b4net.lt>
|
||||
" Version: 0.83
|
||||
" Last Modified: Jan 4, 2010
|
||||
"
|
||||
" Overview
|
||||
" --------
|
||||
@@ -20,12 +18,6 @@
|
||||
" support by issuing command :ver and looking for +python in the list of
|
||||
" features.
|
||||
"
|
||||
" Note: The script displays current tag on the status line only in NORMAL
|
||||
" mode. This is because CursorHold event is fired up only in this mode.
|
||||
" However if you badly need to know what tag you are in even in INSERT or
|
||||
" VISUAL mode, contact me on the above specified email address and I'll send
|
||||
" you a patch that enables firing up CursorHold event in those modes as well.
|
||||
"
|
||||
" Installation
|
||||
" ------------
|
||||
" 1. Make sure your Vim has python feature on (+python). If not, you will need
|
||||
@@ -33,30 +25,26 @@
|
||||
" 2. Copy script pythonhelper.vim to the $HOME/.vim/plugin directory
|
||||
" 3. Run Vim and open any python file.
|
||||
"
|
||||
" Marius Gedminas <marius@gedmin.as>:
|
||||
" 4. change 'statusline' to include
|
||||
" %{TagInStatusLine()}
|
||||
"
|
||||
if has("python")
|
||||
python << EOS
|
||||
|
||||
# import of required modules {{{
|
||||
import vim
|
||||
import time
|
||||
import sys
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
import vim
|
||||
# }}}
|
||||
|
||||
|
||||
# global dictionaries of tags and their line numbers, keys are buffer numbers {{{
|
||||
TAGS = {}
|
||||
TAGLINENUMBERS = {}
|
||||
BUFFERTICKS = {}
|
||||
TAGS = {}
|
||||
TAGLINENUMBERS = {}
|
||||
BUFFERTICKS = {}
|
||||
# }}}
|
||||
|
||||
|
||||
# class PythonTag() {{{
|
||||
class PythonTag:
|
||||
class PythonTag(object):
|
||||
# DOC {{{
|
||||
"""A simple storage class representing a python tag.
|
||||
"""
|
||||
@@ -65,17 +53,17 @@ class PythonTag:
|
||||
|
||||
# STATIC VARIABLES {{{
|
||||
|
||||
# tag type IDs {{{
|
||||
TAGTYPE_CLASS = 0
|
||||
TAGTYPE_METHOD = 1
|
||||
TAGTYPE_FUNCTION = 2
|
||||
# possible tag types {{{
|
||||
TT_CLASS = 0
|
||||
TT_METHOD = 1
|
||||
TT_FUNCTION = 2
|
||||
# }}}
|
||||
|
||||
# tag type names {{{
|
||||
typeName = {
|
||||
TAGTYPE_CLASS : "class",
|
||||
TAGTYPE_METHOD : "method",
|
||||
TAGTYPE_FUNCTION : "function",
|
||||
TAG_TYPE_NAME = {
|
||||
TT_CLASS : "class",
|
||||
TT_METHOD : "method",
|
||||
TT_FUNCTION : "function",
|
||||
}
|
||||
# }}}
|
||||
|
||||
@@ -84,9 +72,9 @@ class PythonTag:
|
||||
|
||||
# METHODS {{{
|
||||
|
||||
def __init__(self, type, name, fullName, lineNumber, indentLevel, parentTag):
|
||||
def __init__(self, type, name, fullName, lineNumber, indentLevel):
|
||||
# DOC {{{
|
||||
"""Initializes instances of class PythonTag().
|
||||
"""Initializes instances of PythonTag().
|
||||
|
||||
Parameters
|
||||
|
||||
@@ -103,12 +91,13 @@ class PythonTag:
|
||||
# }}}
|
||||
|
||||
# CODE {{{
|
||||
self.type = type
|
||||
self.name = name
|
||||
self.fullName = fullName
|
||||
self.lineNumber = lineNumber
|
||||
self.indentLevel = indentLevel
|
||||
self.parentTag = parentTag
|
||||
# remember the settings {{{
|
||||
self.type = type
|
||||
self.name = name
|
||||
self.fullName = fullName
|
||||
self.lineNumber = lineNumber
|
||||
self.indentLevel = indentLevel
|
||||
# }}}
|
||||
# }}}
|
||||
|
||||
|
||||
@@ -119,10 +108,11 @@ class PythonTag:
|
||||
# }}}
|
||||
|
||||
# CODE {{{
|
||||
return "%s (%s) [%s, %u, %u]" % (self.name, PythonTag.typeName[self.type],
|
||||
return "%s (%s) [%s, %u, %u]" % (self.name, PythonTag.TAG_TYPE_NAME[self.type],
|
||||
self.fullName, self.lineNumber, self.indentLevel,)
|
||||
# }}}
|
||||
|
||||
|
||||
__repr__ = __str__
|
||||
|
||||
|
||||
@@ -131,10 +121,9 @@ class PythonTag:
|
||||
|
||||
|
||||
# class SimplePythonTagsParser() {{{
|
||||
class SimplePythonTagsParser:
|
||||
class SimplePythonTagsParser(object):
|
||||
# DOC {{{
|
||||
"""Provides a simple python tag parser. Returns list of PythonTag()
|
||||
instances.
|
||||
"""Provides a simple python tag parser.
|
||||
"""
|
||||
# }}}
|
||||
|
||||
@@ -143,13 +132,12 @@ class SimplePythonTagsParser:
|
||||
|
||||
# how many chars a single tab represents (visually)
|
||||
TABSIZE = 8
|
||||
|
||||
# regexp used to get indentation and strip comments
|
||||
commentsIndentStripRE = re.compile('([ \t]*)([^\n#]*).*')
|
||||
# regexp used to get class name
|
||||
classRE = re.compile('class[ \t]+([a-zA-Z0-9_]+)[ \t]*([(:].*|$)')
|
||||
# regexp used to get method or function name
|
||||
methodRE = re.compile('def[ \t]+([^(]+).*')
|
||||
# regexp used to extract indentation and strip comments
|
||||
COMMENTS_INDENT_RE = re.compile('([ \t]*)([^\n#]*).*')
|
||||
# regexp used to extract a class name
|
||||
CLASS_RE = re.compile('class[ \t]+([^(:]+).*')
|
||||
# regexp used to extract a method or function name
|
||||
METHOD_RE = re.compile('def[ \t]+([^(]+).*')
|
||||
|
||||
# }}}
|
||||
|
||||
@@ -158,7 +146,7 @@ class SimplePythonTagsParser:
|
||||
|
||||
def __init__(self, source):
|
||||
# DOC {{{
|
||||
"""Initializes the instance of class SimplePythonTagsParser().
|
||||
"""Initializes instances of SimplePythonTagsParser().
|
||||
|
||||
Parameters
|
||||
|
||||
@@ -169,8 +157,8 @@ class SimplePythonTagsParser:
|
||||
|
||||
# CODE {{{
|
||||
# make sure source has readline() method {{{
|
||||
if (not(hasattr(source, 'readline') and
|
||||
callable(source.readline))):
|
||||
if ((hasattr(source, 'readline') == 0) or
|
||||
(callable(source.readline) == 0)):
|
||||
raise AttributeError("Source must have callable readline method.")
|
||||
# }}}
|
||||
|
||||
@@ -181,19 +169,23 @@ class SimplePythonTagsParser:
|
||||
|
||||
def getTags(self):
|
||||
# DOC {{{
|
||||
"""Determines all the tags for the buffer. Returns tuple in format
|
||||
"""Determines all the tags for the buffer. Returns a tuple in format
|
||||
(tagLineNumbers, tags,).
|
||||
"""
|
||||
# }}}
|
||||
|
||||
# CODE {{{
|
||||
tagLineNumbers = []
|
||||
tags = {}
|
||||
# initialize the resulting list of the tag line numbers and the tag information {{{
|
||||
tagLineNumbers = []
|
||||
tags = {}
|
||||
# }}}
|
||||
|
||||
# list (stack) of all currently active tags
|
||||
tagsStack = []
|
||||
# initalize local auxiliary variables {{{
|
||||
tagsStack = []
|
||||
lineNumber = 0
|
||||
# }}}
|
||||
|
||||
lineNumber = 0
|
||||
# go through all the lines in the source and localize all python tags in it {{{
|
||||
while 1:
|
||||
# get next line
|
||||
line = self.source.readline()
|
||||
@@ -203,57 +195,73 @@ class SimplePythonTagsParser:
|
||||
break
|
||||
# }}}
|
||||
|
||||
# increase the line number
|
||||
lineNumber += 1
|
||||
lineMatch = self.commentsIndentStripRE.match(line)
|
||||
lineContents = lineMatch.group(2)
|
||||
# class tag {{{
|
||||
tagMatch = self.classRE.match(lineContents)
|
||||
|
||||
# extract the line indentation characters and its content {{{
|
||||
lineMatch = self.COMMENTS_INDENT_RE.match(line)
|
||||
lineContent = lineMatch.group(2)
|
||||
# }}}
|
||||
|
||||
# handle the class tag {{{
|
||||
# match for the class tag
|
||||
tagMatch = self.CLASS_RE.match(lineContent)
|
||||
|
||||
# if the class tag has been found, store some information on it {{{
|
||||
if (tagMatch):
|
||||
currentTag = self.getPythonTag(tagsStack, lineNumber, lineMatch.group(1),
|
||||
tagMatch.group(1), self.tagClassTypeDecidingMethod)
|
||||
tagLineNumbers.append(lineNumber)
|
||||
tags[lineNumber] = currentTag
|
||||
# }}}
|
||||
# function/method/none tag {{{
|
||||
# }}}
|
||||
# handle the function/method/none tag {{{
|
||||
else:
|
||||
tagMatch = self.methodRE.match(lineContents)
|
||||
# match for the method/function tag
|
||||
tagMatch = self.METHOD_RE.match(lineContent)
|
||||
|
||||
# if the method/function tag has been found, store some information on it {{{
|
||||
if (tagMatch):
|
||||
currentTag = self.getPythonTag(tagsStack, lineNumber, lineMatch.group(1),
|
||||
tagMatch.group(1), self.tagFunctionTypeDecidingMethod)
|
||||
tagLineNumbers.append(lineNumber)
|
||||
tags[lineNumber] = currentTag
|
||||
# }}}
|
||||
# }}}
|
||||
# }}}
|
||||
|
||||
# return the tags data for the source
|
||||
return (tagLineNumbers, tags,)
|
||||
# }}}
|
||||
|
||||
|
||||
def getPreviousTag(self, tagsStack):
|
||||
def getParentTag(self, tagsStack):
|
||||
# DOC {{{
|
||||
"""Returns the previous tag (instance of PythonTag()) from the
|
||||
specified tag list if possible. If not, returns None.
|
||||
"""Returns the parent/enclosing tag (instance of PythonTag()) from the
|
||||
specified tag list. If no such parent tag exists, returns None.
|
||||
|
||||
Parameters
|
||||
|
||||
tagsStack -- list (stack) of currently active PythonTag() instances
|
||||
tagsStack -- list (stack) of currently open PythonTag() instances
|
||||
"""
|
||||
# }}}
|
||||
|
||||
# CODE {{{
|
||||
# determine the parent tag {{{
|
||||
if (len(tagsStack)):
|
||||
previousTag = tagsStack[-1]
|
||||
parentTag = tagsStack[-1]
|
||||
else:
|
||||
previousTag = None
|
||||
parentTag = None
|
||||
# }}}
|
||||
|
||||
# return the tag
|
||||
return previousTag
|
||||
return parentTag
|
||||
# }}}
|
||||
|
||||
|
||||
def computeIndentLevel(self, indentChars):
|
||||
def computeIndentationLevel(indentChars):
|
||||
# DOC {{{
|
||||
"""Computes indent level from the specified string.
|
||||
"""Computes the indentation level from the specified string.
|
||||
|
||||
Parameters
|
||||
|
||||
@@ -262,15 +270,21 @@ class SimplePythonTagsParser:
|
||||
# }}}
|
||||
|
||||
# CODE {{{
|
||||
# initialize the indentation level
|
||||
indentLevel = 0
|
||||
|
||||
# compute the indentation level (expand tabs) {{{
|
||||
for char in indentChars:
|
||||
if (char == '\t'):
|
||||
indentLevel += self.TABSIZE
|
||||
indentLevel += SimplePythonTagsParser.TABSIZE
|
||||
else:
|
||||
indentLevel += 1
|
||||
# }}}
|
||||
|
||||
# return the computed indentation level
|
||||
return indentLevel
|
||||
# }}}
|
||||
computeIndentationLevel = staticmethod(computeIndentationLevel)
|
||||
|
||||
|
||||
def getPythonTag(self, tagsStack, lineNumber, indentChars, tagName, tagTypeDecidingMethod):
|
||||
@@ -290,58 +304,81 @@ class SimplePythonTagsParser:
|
||||
tagName -- short name of the current tag
|
||||
|
||||
tagTypeDecidingMethod -- reference to method that is called to
|
||||
determine type of the current tag
|
||||
determine the type of the current tag
|
||||
"""
|
||||
# }}}
|
||||
|
||||
# CODE {{{
|
||||
indentLevel = self.computeIndentLevel(indentChars)
|
||||
previousTag = self.getPreviousTag(tagsStack)
|
||||
# code for enclosed tag {{{
|
||||
while (previousTag):
|
||||
if (previousTag.indentLevel >= indentLevel):
|
||||
# compute the indentation level
|
||||
indentLevel = self.computeIndentationLevel(indentChars)
|
||||
# get the parent tag
|
||||
parentTag = self.getParentTag(tagsStack)
|
||||
|
||||
# handle an enclosed tag {{{
|
||||
while (parentTag):
|
||||
# if the indent level of the parent tag is greater than of the current tag, use parent tag of the parent tag {{{
|
||||
if (parentTag.indentLevel >= indentLevel):
|
||||
del tagsStack[-1]
|
||||
# }}}
|
||||
# otherwise we have all information on the current tag and can return it {{{
|
||||
else:
|
||||
tagType = tagTypeDecidingMethod(previousTag.type)
|
||||
tag = PythonTag(tagType, tagName, "%s.%s" % (previousTag.fullName, tagName,), lineNumber, indentLevel, previousTag)
|
||||
tagsStack.append(tag)
|
||||
return tag
|
||||
previousTag = self.getPreviousTag(tagsStack)
|
||||
# create the tag
|
||||
tag = PythonTag(tagTypeDecidingMethod(parentTag.type), tagName, "%s.%s" % (parentTag.fullName, tagName,), lineNumber, indentLevel)
|
||||
|
||||
# break the loop
|
||||
break
|
||||
# }}}
|
||||
|
||||
# use parent tag of the parent tag
|
||||
parentTag = self.getParentTag(tagsStack)
|
||||
# }}}
|
||||
# code for tag in top indent level {{{
|
||||
# handle a top-indent level tag {{{
|
||||
else:
|
||||
tagType = tagTypeDecidingMethod(None)
|
||||
tag = PythonTag(tagType, tagName, tagName, lineNumber, indentLevel, None)
|
||||
tagsStack.append(tag)
|
||||
return tag
|
||||
# create the tag
|
||||
tag = PythonTag(tagTypeDecidingMethod(None), tagName, tagName, lineNumber, indentLevel)
|
||||
# }}}
|
||||
|
||||
# add the tag to the list of tags
|
||||
tagsStack.append(tag)
|
||||
|
||||
# return the tag
|
||||
return tag
|
||||
# }}}
|
||||
|
||||
|
||||
def tagClassTypeDecidingMethod(self, previousTagsType):
|
||||
def tagClassTypeDecidingMethod(self, parentTagType):
|
||||
# DOC {{{
|
||||
"""Returns tag type of the current tag based on its previous tag (super
|
||||
tag) for classes.
|
||||
|
||||
Parameters
|
||||
|
||||
parentTagType -- type of the enclosing/parent tag
|
||||
"""
|
||||
# }}}
|
||||
|
||||
# CODE {{{
|
||||
return PythonTag.TAGTYPE_CLASS
|
||||
# is always class no matter what
|
||||
return PythonTag.TT_CLASS
|
||||
# }}}
|
||||
|
||||
|
||||
def tagFunctionTypeDecidingMethod(self, previousTagsType):
|
||||
def tagFunctionTypeDecidingMethod(self, parentTagType):
|
||||
# DOC {{{
|
||||
"""Returns tag type of the current tag based on its previous tag (super
|
||||
tag) for functions/methods.
|
||||
|
||||
Parameters
|
||||
|
||||
parentTagType -- type of the enclosing/parent tag
|
||||
"""
|
||||
# }}}
|
||||
|
||||
# CODE {{{
|
||||
if (previousTagsType == PythonTag.TAGTYPE_CLASS):
|
||||
return PythonTag.TAGTYPE_METHOD
|
||||
if (parentTagType == PythonTag.TT_CLASS):
|
||||
return PythonTag.TT_METHOD
|
||||
else:
|
||||
return PythonTag.TAGTYPE_FUNCTION
|
||||
return PythonTag.TT_FUNCTION
|
||||
# }}}
|
||||
|
||||
|
||||
@@ -350,7 +387,7 @@ class SimplePythonTagsParser:
|
||||
|
||||
|
||||
# class VimReadlineBuffer() {{{
|
||||
class VimReadlineBuffer:
|
||||
class VimReadlineBuffer(object):
|
||||
# DOC {{{
|
||||
"""A simple wrapper class around vim's buffer that provides readline
|
||||
method.
|
||||
@@ -362,7 +399,7 @@ class VimReadlineBuffer:
|
||||
|
||||
def __init__(self, vimBuffer):
|
||||
# DOC {{{
|
||||
"""Initializes the instance of class VimReadlineBuffer().
|
||||
"""Initializes instances of VimReadlineBuffer().
|
||||
|
||||
Parameters
|
||||
|
||||
@@ -371,9 +408,13 @@ class VimReadlineBuffer:
|
||||
# }}}
|
||||
|
||||
# CODE {{{
|
||||
self.vimBuffer = vimBuffer
|
||||
self.currentLine = -1
|
||||
self.bufferLines = len(vimBuffer)
|
||||
# remember the settings
|
||||
self.vimBuffer = vimBuffer
|
||||
|
||||
# initialize instance attributes {{{
|
||||
self.currentLine = -1
|
||||
self.bufferLines = len(vimBuffer)
|
||||
# }}}
|
||||
# }}}
|
||||
|
||||
|
||||
@@ -385,6 +426,7 @@ class VimReadlineBuffer:
|
||||
# }}}
|
||||
|
||||
# CODE {{{
|
||||
# increase the current line counter
|
||||
self.currentLine += 1
|
||||
|
||||
# notify end of file if we reached beyond the last line {{{
|
||||
@@ -392,9 +434,10 @@ class VimReadlineBuffer:
|
||||
return ''
|
||||
# }}}
|
||||
|
||||
# return the line with added newline (vim stores the lines without newline)
|
||||
# return the line with an added newline (vim stores the lines without it)
|
||||
return "%s\n" % (self.vimBuffer[self.currentLine],)
|
||||
# }}}
|
||||
|
||||
|
||||
# }}}
|
||||
# }}}
|
||||
@@ -402,8 +445,8 @@ class VimReadlineBuffer:
|
||||
|
||||
def getNearestLineIndex(row, tagLineNumbers):
|
||||
# DOC {{{
|
||||
"""Returns index of line in tagLineNumbers list that is nearest to the
|
||||
current cursor row.
|
||||
"""Returns the index of line in 'tagLineNumbers' list that is nearest to the
|
||||
specified cursor row.
|
||||
|
||||
Parameters
|
||||
|
||||
@@ -414,27 +457,33 @@ def getNearestLineIndex(row, tagLineNumbers):
|
||||
# }}}
|
||||
|
||||
# CODE {{{
|
||||
nearestLineNumber = -1
|
||||
nearestLineIndex = -1
|
||||
i = 0
|
||||
for lineNumber in tagLineNumbers:
|
||||
# initialize local auxiliary variables {{{
|
||||
nearestLineNumber = -1
|
||||
nearestLineIndex = -1
|
||||
# }}}
|
||||
|
||||
# go through all tag line numbers and find the one nearest to the specified row {{{
|
||||
for lineIndex, lineNumber in enumerate(tagLineNumbers):
|
||||
# if the current line is nearer the current cursor position, take it {{{
|
||||
if (nearestLineNumber < lineNumber <= row):
|
||||
nearestLineNumber = lineNumber
|
||||
nearestLineIndex = i
|
||||
nearestLineNumber = lineNumber
|
||||
nearestLineIndex = lineIndex
|
||||
# }}}
|
||||
|
||||
# if we've got past the current cursor position, let's end the search {{{
|
||||
if (lineNumber >= row):
|
||||
break
|
||||
# }}}
|
||||
i += 1
|
||||
# }}}
|
||||
|
||||
# return index of the line with the nearest tag
|
||||
return nearestLineIndex
|
||||
# }}}
|
||||
|
||||
|
||||
def getTags(bufferNumber, changedTick):
|
||||
# DOC {{{
|
||||
"""Reads the tags for the specified buffer number. Returns tuple
|
||||
"""Reads the tags for the specified buffer number. Returns a tuple
|
||||
(taglinenumber[buffer], tags[buffer],).
|
||||
|
||||
Parameters
|
||||
@@ -447,10 +496,11 @@ def getTags(bufferNumber, changedTick):
|
||||
# }}}
|
||||
|
||||
# CODE {{{
|
||||
global TAGLINENUMBERS, TAGS, BUFFERTICKS
|
||||
# define global variables
|
||||
global TAGLINENUMBERS, TAGS, BUFFERTICKS
|
||||
|
||||
# return immediately if there's no need to update the tags {{{
|
||||
if ((BUFFERTICKS.has_key(bufferNumber)) and (BUFFERTICKS[bufferNumber] == changedTick)):
|
||||
if (BUFFERTICKS.get(bufferNumber, None) == changedTick):
|
||||
return (TAGLINENUMBERS[bufferNumber], TAGS[bufferNumber],)
|
||||
# }}}
|
||||
|
||||
@@ -460,12 +510,12 @@ def getTags(bufferNumber, changedTick):
|
||||
# }}}
|
||||
|
||||
# update the global variables {{{
|
||||
TAGS[bufferNumber] = tags
|
||||
TAGLINENUMBERS[bufferNumber] = tagLineNumbers
|
||||
BUFFERTICKS[bufferNumber] = changedTick
|
||||
TAGS[bufferNumber] = tags
|
||||
TAGLINENUMBERS[bufferNumber] = tagLineNumbers
|
||||
BUFFERTICKS[bufferNumber] = changedTick
|
||||
# }}}
|
||||
|
||||
# return the tags data
|
||||
# return the tuple (tagLineNumbers, tags,)
|
||||
return (tagLineNumbers, tags,)
|
||||
# }}}
|
||||
|
||||
@@ -484,12 +534,12 @@ def findTag(bufferNumber, changedTick):
|
||||
# }}}
|
||||
|
||||
# CODE {{{
|
||||
# try to find the best tag {{{
|
||||
try:
|
||||
# get the tags data for the current buffer {{{
|
||||
# get the tags data for the current buffer
|
||||
tagLineNumbers, tags = getTags(bufferNumber, changedTick)
|
||||
# }}}
|
||||
|
||||
# link to vim internal data {{{
|
||||
# link to vim's internal data {{{
|
||||
currentBuffer = vim.current.buffer
|
||||
currentWindow = vim.current.window
|
||||
row, col = currentWindow.cursor
|
||||
@@ -497,66 +547,97 @@ def findTag(bufferNumber, changedTick):
|
||||
|
||||
# get the index of the nearest line
|
||||
nearestLineIndex = getNearestLineIndex(row, tagLineNumbers)
|
||||
|
||||
# if any line was found, try to find if the tag is appropriate {{{
|
||||
# (ie. the cursor can be below the last tag but on a code that has nothing
|
||||
# to do with the tag, because it's indented differently, in such case no
|
||||
# appropriate tag has been found.)
|
||||
if (nearestLineIndex > -1):
|
||||
nearestLineNumber = tagLineNumbers[nearestLineIndex]
|
||||
tagInfo = tags[nearestLineNumber]
|
||||
# walk through all the lines in range (nearestTagLine, cursorRow) {{{
|
||||
for i in xrange(nearestLineNumber + 1, row):
|
||||
line = currentBuffer[i]
|
||||
# count the indentation of the line, if it's lower that the tag's, the found tag is wrong {{{
|
||||
if (len(line)):
|
||||
while (nearestLineIndex > -1):
|
||||
# get the line number of the nearest tag
|
||||
nearestLineNumber = tagLineNumbers[nearestLineIndex]
|
||||
|
||||
# walk through all the lines in range (nearestTagLine, cursorRow) {{{
|
||||
for lineNumber in xrange(nearestLineNumber + 1, row):
|
||||
# get the current line
|
||||
line = currentBuffer[lineNumber]
|
||||
|
||||
# count the indentation of the line, if it's lower than the tag's, the tag is invalid {{{
|
||||
if (len(line)):
|
||||
# initialize local auxiliary variables {{{
|
||||
lineStart = 0
|
||||
i = 0
|
||||
# }}}
|
||||
|
||||
# compute the indentation of the line {{{
|
||||
lineStart = 0
|
||||
j = 0
|
||||
while ((j < len(line)) and (line[j].isspace())):
|
||||
if (line[j] == '\t'):
|
||||
lineStart += SimplePythonTagsParser.TABSIZE
|
||||
else:
|
||||
lineStart += 1
|
||||
j += 1
|
||||
# if the line contains only spaces, it doesn't count {{{
|
||||
if (j == len(line)):
|
||||
while ((i < len(line)) and (line[i].isspace())):
|
||||
# move the start of the line code {{{
|
||||
if (line[i] == '\t'):
|
||||
lineStart += SimplePythonTagsParser.TABSIZE
|
||||
else:
|
||||
lineStart += 1
|
||||
# }}}
|
||||
|
||||
# go to the next character on the line
|
||||
i += 1
|
||||
# }}}
|
||||
|
||||
# if the line contains only spaces, skip it {{{
|
||||
if (i == len(line)):
|
||||
continue
|
||||
# }}}
|
||||
# if the next character is # (python comment), this line doesn't count {{{
|
||||
if (line[j] == '#'):
|
||||
# if the next character is a '#' (python comment), skip the line {{{
|
||||
if (line[i] == '#'):
|
||||
continue
|
||||
# }}}
|
||||
|
||||
# if the line's indentation starts before or at the nearest tag's one, the tag is invalid {{{
|
||||
if (lineStart <= tags[nearestLineNumber].indentLevel):
|
||||
nearestLineIndex -= 1
|
||||
break
|
||||
# }}}
|
||||
# if the line's indentation starts before or at the nearest tag's one, the tag is wrong {{{
|
||||
while tagInfo is not None and lineStart <= tagInfo.indentLevel:
|
||||
tagInfo = tagInfo.parentTag
|
||||
# }}}
|
||||
# }}}
|
||||
# }}}
|
||||
# }}}
|
||||
# the tag is appropriate, so use it {{{
|
||||
else:
|
||||
break
|
||||
# }}}
|
||||
# }}}
|
||||
# no appropriate tag has been found {{{
|
||||
else:
|
||||
tagInfo = None
|
||||
nearestLineNumber = -1
|
||||
# }}}
|
||||
|
||||
# describe the cursor position (what tag it's in) {{{
|
||||
# describe the cursor position (what tag the cursor is on) {{{
|
||||
# reset the description
|
||||
tagDescription = ""
|
||||
if tagInfo is not None:
|
||||
## tagDescription = "[in %s (%s)]" % (tagInfo.fullName, PythonTag.typeName[tagInfo.type],)
|
||||
tagDescription = "[%s]" % (tagInfo.fullName, )
|
||||
|
||||
# if an appropriate tag has been found, set the description accordingly {{{
|
||||
if (nearestLineNumber > -1):
|
||||
tagInfo = tags[nearestLineNumber]
|
||||
tagDescription = "[in %s (%s)]" % (tagInfo.fullName, PythonTag.TAG_TYPE_NAME[tagInfo.type],)
|
||||
# }}}
|
||||
# }}}
|
||||
|
||||
# update the variable for the status line so it will be updated next time
|
||||
# update the variable for the status line so it get updated with the new description
|
||||
vim.command("let w:PHStatusLine=\"%s\"" % (tagDescription,))
|
||||
except:
|
||||
# spit out debugging information {{{
|
||||
# }}}
|
||||
|
||||
# handle possible exceptions {{{
|
||||
except Exception:
|
||||
# bury into the traceback {{{
|
||||
ec, ei, tb = sys.exc_info()
|
||||
while (tb != None):
|
||||
if (tb.tb_next == None):
|
||||
break
|
||||
tb = tb.tb_next
|
||||
# }}}
|
||||
|
||||
# spit out the error {{{
|
||||
print "ERROR: %s %s %s:%u" % (ec.__name__, ei, tb.tb_frame.f_code.co_filename, tb.tb_lineno,)
|
||||
time.sleep(0.5)
|
||||
# }}}
|
||||
# }}}
|
||||
# }}}
|
||||
|
||||
|
||||
def deleteTags(bufferNumber):
|
||||
@@ -570,8 +651,10 @@ def deleteTags(bufferNumber):
|
||||
# }}}
|
||||
|
||||
# CODE {{{
|
||||
global TAGS, TAGLINENUMBERS, BUFFERTICKS
|
||||
# define global variables
|
||||
global TAGS, TAGLINENUMBERS, BUFFERTICKS
|
||||
|
||||
# try to delete the tags for the buffer {{{
|
||||
try:
|
||||
del TAGS[bufferNumber]
|
||||
del TAGLINENUMBERS[bufferNumber]
|
||||
@@ -579,6 +662,7 @@ def deleteTags(bufferNumber):
|
||||
except:
|
||||
pass
|
||||
# }}}
|
||||
# }}}
|
||||
|
||||
|
||||
EOS
|
||||
@@ -617,33 +701,63 @@ function! TagInStatusLine()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
|
||||
function! PHPreviousClassMethod()
|
||||
call search('^[ \t]*\(class\|def\)\>', 'bw')
|
||||
endfunction
|
||||
|
||||
|
||||
function! PHNextClassMethod()
|
||||
call search('^[ \t]*\(class\|def\)\>', 'w')
|
||||
endfunction
|
||||
|
||||
|
||||
function! PHPreviousClass()
|
||||
call search('^[ \t]*class\>', 'bw')
|
||||
endfunction
|
||||
|
||||
|
||||
function! PHNextClass()
|
||||
call search('^[ \t]*class\>', 'w')
|
||||
endfunction
|
||||
|
||||
|
||||
function! PHPreviousMethod()
|
||||
call search('^[ \t]*def\>', 'bw')
|
||||
endfunction
|
||||
|
||||
|
||||
function! PHNextMethod()
|
||||
call search('^[ \t]*def\>', 'w')
|
||||
endfunction
|
||||
|
||||
" }}}
|
||||
|
||||
|
||||
" event binding, vim customizing {{{
|
||||
|
||||
" autocommands binding
|
||||
if v:version >= 700
|
||||
autocmd CursorMoved * call PHCursorHold()
|
||||
else
|
||||
autocmd CursorHold * call PHCursorHold()
|
||||
endif
|
||||
autocmd CursorHold * call PHCursorHold()
|
||||
autocmd CursorHoldI * call PHCursorHold()
|
||||
autocmd BufDelete * silent call PHBufferDelete()
|
||||
|
||||
"" " time that determines after how long time of no activity the CursorHold event
|
||||
"" " is fired up
|
||||
"" set updatetime=1000
|
||||
""
|
||||
"" " color of the current tag in the status line (bold cyan on black)
|
||||
"" highlight User1 gui=bold guifg=cyan guibg=black
|
||||
"" " color of the modified flag in the status line (bold black on red)
|
||||
"" highlight User2 gui=bold guifg=black guibg=red
|
||||
"" " the status line will be displayed for every window
|
||||
"" set laststatus=2
|
||||
"" " set the status line to display some useful information
|
||||
"" set stl=%-f%r\ %2*%m%*\ \ \ \ %1*%{TagInStatusLine()}%*%=[%l:%c]\ \ \ \ [buf\ %n]
|
||||
" time that determines after how long time of no activity the CursorHold event
|
||||
" is fired up
|
||||
set updatetime=1000
|
||||
|
||||
" color of the current tag in the status line (bold cyan on black)
|
||||
" gryf: i don't like coloring apart from current colorscheme. keep it simple.
|
||||
"highlight User1 gui=bold guifg=cyan guibg=black
|
||||
" color of the modified flag in the status line (bold black on red)
|
||||
" gryf: i don't like coloring apart from current colorscheme. keep it simple.
|
||||
"highlight User2 gui=bold guifg=black guibg=red
|
||||
" the status line will be displayed for every window
|
||||
set laststatus=2
|
||||
" set the status line to display some useful information
|
||||
"set stl=%-f%r\ %2*%m%*\ \ \ \ %1*%{TagInStatusLine()}%*%=[%l:%c]\ \ \ \ [buf\ %n]
|
||||
" gryf: I like my status bar. Don't change it. Just add information.
|
||||
setlocal statusline=%<%F\ \ \ %{TagInStatusLine()}\ %h%m%r%=%(%l,%c%V%)\ %3p%%
|
||||
|
||||
" }}}
|
||||
|
||||
" vim:foldmethod=marker
|
||||
endif " has("python")
|
||||
|
||||
Reference in New Issue
Block a user