diff --git a/README.mdown b/README.mdown
index 8772c57b..eca93226 100644
--- a/README.mdown
+++ b/README.mdown
@@ -39,6 +39,7 @@ nice in Python 2. To keep things simple, some things have been held back:
- Classes: Always Python 3, therefore all classes inherit from `object`.
- Generators: No `next` method. The `__next__` method is there instead.
+ - Exceptions are only looked at in the form of `Exception as e`, no comma!
Syntax Errors and other strange stuff, that is defined differently in the
Python language, may lead to undefined behaviour of the completion. If you
diff --git a/evaluate.py b/evaluate.py
index a9c27caf..179b23b3 100644
--- a/evaluate.py
+++ b/evaluate.py
@@ -286,11 +286,24 @@ class Instance(Executable):
return names
+ @property
def parent(self):
return self.base.parent
+ @property
+ def line_nr(self):
+ return self.base.line_nr
+
+ @property
+ def indent(self):
+ return self.base.indent
+
+ @property
+ def name(self):
+ return self.base.name
+
def __repr__(self):
- return "
" % \
+ return "" % \
(self.__class__.__name__, self.base, len(self.var_args or []))
@@ -345,11 +358,15 @@ class Class(object):
names.append(i)
return names
+ @property
+ def name(self):
+ return self.base.name
+
def __getattr__(self, name):
return getattr(self.base, name)
def __repr__(self):
- return "" % (self.__class__.__name__, self.base)
+ return "" % (self.__class__.__name__, self.base)
class Execution(Executable):
@@ -537,7 +554,7 @@ class Array(object):
return self._array
def __repr__(self):
- return "" % (self.__class__.__name__, self._array)
+ return "" % (self.__class__.__name__, self._array)
class ArrayElement(object):
diff --git a/ftest.py b/ftest.py
index f92edca5..49766318 100755
--- a/ftest.py
+++ b/ftest.py
@@ -15,7 +15,7 @@ path = os.path.join(os.getcwd(), f_name)
f = open(path)
code = f.read()
for i in range(1):
- completions = functions.complete(code, 180, 200, path)
+ completions = functions.get_definitions(code, 180, 200, path)
#completions = functions.complete(code, 42, 200, path)
print '\n', ', '.join(sorted(str(c) for c in completions))
diff --git a/functions.py b/functions.py
index 580115cc..e2dff185 100644
--- a/functions.py
+++ b/functions.py
@@ -1,4 +1,5 @@
import re
+import sys
import parsing
import evaluate
@@ -10,7 +11,10 @@ __all__ = ['complete', 'goto', 'get_completion_parts', 'set_debug_function']
class NotFoundError(Exception):
""" A custom error to avoid catching the wrong errors """
- pass
+ def __init__(self, scope, path_tuple, message=None):
+ super(NotFoundError, self).__init__(message)
+ self.scope = scope
+ self.path_tuple = path_tuple
class Completion(object):
@@ -32,7 +36,7 @@ class Completion(object):
def help(self):
try:
return str(self.name.parent.docstr)
- except:
+ except AttributeError:
return ''
def get_type(self):
@@ -63,6 +67,42 @@ class Completion(object):
return self.name.names[-1]
+class Definition(object):
+ def __init__(self, scope):
+ """ The definition of a function """
+ self.scope = scope
+
+ def get_name(self):
+ return self.scope.name
+
+ def get_module(self):
+ par = self.scope
+ while True:
+ if par.parent is not None:
+ par = par.parent
+ else:
+ break
+ return par.path
+
+ def get_line(self):
+ return self.scope.line_nr
+
+ def get_indent(self):
+ return self.scope.indent
+
+ def __str__(self):
+ module = self.get_module()
+ if module[0] == '/':
+ position = '@%s' % (self.get_line())
+ else:
+ # no path - is a builtin
+ position = ''
+
+ return "%s.%s%s" % (module, self.get_name(), position)
+
+ def __repr__(self):
+ return "<%s %s>" % (self.__class__.__name__, self)
+
def get_completion_parts(path):
"""
Returns the parts for the completion
@@ -88,18 +128,14 @@ def complete(source, row, column, source_path):
:return: list of completion objects
:rtype: list
"""
- f = modules.ModuleWithCursor(source_path, source=source, row=row)
- scope = f.parser.user_scope
- path = f.get_path_until_cursor(column)
- debug.dbg('completion_start: %s in %s' % (path, scope))
-
- # just parse one statement, take it and evaluate it
- path, dot, like = get_completion_parts(path)
- r = parsing.PyFuzzyParser(path, source_path)
try:
- stmt = r.top.statements[0]
- except IndexError:
- scope_generator = evaluate.get_names_for_scope(scope)
+ scopes, path, dot, like = prepare_goto(source, row, column, source_path, True)
+ except NotFoundError:
+ # normally this would be used like this: `NotFoundError as exc`, but
+ # this guarantues backwards compatibility with Python2.5.
+ exc = sys.exc_info()[1]
+ path, dot, like = exc.path_tuple
+ scope_generator = evaluate.get_names_for_scope(exc.scope)
completions = []
for dummy, name_list in scope_generator:
completions += name_list
@@ -107,11 +143,6 @@ def complete(source, row, column, source_path):
# if isinstance(, parsing.Function):
# print c.parent
else:
- stmt.line_nr = row
- stmt.indent = column
- stmt.parent = scope
- scopes = evaluate.follow_statement(stmt, scope=scope)
-
completions = []
debug.dbg('possible scopes', scopes)
for s in scopes:
@@ -146,20 +177,40 @@ def prepare_goto(source, row, column, source_path, is_like_search):
try:
stmt = r.top.statements[0]
except IndexError:
- raise NotFoundError()
+ path_tuple = path, dot, like
+ raise NotFoundError(scope, path_tuple)
else:
stmt.line_nr = row
stmt.indent = column
stmt.parent = scope
scopes = evaluate.follow_statement(stmt, scope=scope)
- return scope, scopes
+ if is_like_search:
+ return scopes, path, dot, like
+ else:
+ return scopes
-def goto(source, row, column, source_path):
- dummy, scopes = prepare_goto(source, row, column, source_path, False)
+def get_definitions(source, row, column, source_path):
+ """
+ Returns the definitions of a the path under the cursor.
+ This is not a goto function! This follows complicated paths and returns the
+ end, not the first definition.
+ :param source: The source code of the current file
+ :type source: string
+ :param row: The row to complete in.
+ :type row: int
+ :param col: The column to complete in.
+ :type col: int
+ :param source_path: The path in the os, the current module is in.
+ :type source_path: int
+
+ :return: list of Definition objects, which are basically scopes.
+ :rtype: list
+ """
+ scopes = prepare_goto(source, row, column, source_path, False)
_clear_caches()
- return scopes
+ return [Definition(s) for s in set(scopes)]
def set_debug_function(func_cb):