mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-18 03:25:55 +08:00
More completion refactoring. Getting the structure for filtering names right.
This commit is contained in:
@@ -162,6 +162,7 @@ class Script(object):
|
|||||||
self._evaluator, self._parser, self._user_context,
|
self._evaluator, self._parser, self._user_context,
|
||||||
self._pos, self.call_signatures
|
self._pos, self.call_signatures
|
||||||
)
|
)
|
||||||
|
debug.speed('completions end')
|
||||||
return completion.completions(path)
|
return completion.completions(path)
|
||||||
|
|
||||||
def goto_definitions(self):
|
def goto_definitions(self):
|
||||||
|
|||||||
@@ -13,6 +13,46 @@ from jedi.evaluate import compiled
|
|||||||
from jedi.evaluate.finder import global_names_dict_generator, filter_definition_names
|
from jedi.evaluate.finder import global_names_dict_generator, filter_definition_names
|
||||||
|
|
||||||
|
|
||||||
|
def get_call_signature_param_names(call_signatures):
|
||||||
|
# add named params
|
||||||
|
for call_sig in call_signatures:
|
||||||
|
# Allow protected access, because it's a public API.
|
||||||
|
module = call_sig._name.get_parent_until()
|
||||||
|
# Compiled modules typically don't allow keyword arguments.
|
||||||
|
if not isinstance(module, compiled.CompiledObject):
|
||||||
|
for p in call_sig.params:
|
||||||
|
# Allow access on _definition here, because it's a
|
||||||
|
# public API and we don't want to make the internal
|
||||||
|
# Name object public.
|
||||||
|
if p._definition.stars == 0: # no *args/**kwargs
|
||||||
|
yield p._name
|
||||||
|
|
||||||
|
|
||||||
|
def filter_names(evaluator, completion_names, needs_dot, like_name):
|
||||||
|
comp_dct = {}
|
||||||
|
for name in set(completion_names):
|
||||||
|
if settings.case_insensitive_completion \
|
||||||
|
and str(name).lower().startswith(like_name.lower()) \
|
||||||
|
or str(name).startswith(like_name):
|
||||||
|
|
||||||
|
if isinstance(name.parent, (tree.Function, tree.Class)):
|
||||||
|
# TODO I think this is a hack. It should be an
|
||||||
|
# er.Function/er.Class before that.
|
||||||
|
name = evaluator.wrap(name.parent).name
|
||||||
|
new = classes.Completion(
|
||||||
|
evaluator,
|
||||||
|
name,
|
||||||
|
needs_dot,
|
||||||
|
len(like_name)
|
||||||
|
)
|
||||||
|
k = (new.name, new.complete) # key
|
||||||
|
if k in comp_dct and settings.no_completion_duplicates:
|
||||||
|
comp_dct[k]._same_name_completions.append(new)
|
||||||
|
else:
|
||||||
|
comp_dct[k] = new
|
||||||
|
yield new
|
||||||
|
|
||||||
|
|
||||||
class Completion:
|
class Completion:
|
||||||
def __init__(self, evaluator, parser, user_context, position, call_signatures_method):
|
def __init__(self, evaluator, parser, user_context, position, call_signatures_method):
|
||||||
self._evaluator = evaluator
|
self._evaluator = evaluator
|
||||||
@@ -33,45 +73,17 @@ class Completion:
|
|||||||
completion_names = self.get_completions(user_stmt, completion_parts)
|
completion_names = self.get_completions(user_stmt, completion_parts)
|
||||||
|
|
||||||
if not completion_parts.has_dot:
|
if not completion_parts.has_dot:
|
||||||
# add named params
|
call_signatures = self._call_signatures_method()
|
||||||
for call_sig in self._call_signatures_method():
|
completion_names += get_call_signature_param_names(call_signatures)
|
||||||
# Allow protected access, because it's a public API.
|
|
||||||
module = call_sig._name.get_parent_until()
|
|
||||||
# Compiled modules typically don't allow keyword arguments.
|
|
||||||
if not isinstance(module, compiled.CompiledObject):
|
|
||||||
for p in call_sig.params:
|
|
||||||
# Allow access on _definition here, because it's a
|
|
||||||
# public API and we don't want to make the internal
|
|
||||||
# Name object public.
|
|
||||||
if p._definition.stars == 0: # no *args/**kwargs
|
|
||||||
completion_names.append(p._name)
|
|
||||||
|
|
||||||
needs_dot = not completion_parts.has_dot and completion_parts.path
|
needs_dot = not completion_parts.has_dot and completion_parts.path
|
||||||
|
|
||||||
comps = []
|
completions = filter_names(self._evaluator, completion_names,
|
||||||
comp_dct = {}
|
needs_dot, completion_parts.name)
|
||||||
for c in set(completion_names):
|
|
||||||
n = str(c)
|
|
||||||
if settings.case_insensitive_completion \
|
|
||||||
and n.lower().startswith(completion_parts.name.lower()) \
|
|
||||||
or n.startswith(completion_parts.name):
|
|
||||||
if isinstance(c.parent, (tree.Function, tree.Class)):
|
|
||||||
# TODO I think this is a hack. It should be an
|
|
||||||
# er.Function/er.Class before that.
|
|
||||||
c = self._evaluator.wrap(c.parent).name
|
|
||||||
new = classes.Completion(self._evaluator, c, needs_dot, len(completion_parts.name))
|
|
||||||
k = (new.name, new.complete) # key
|
|
||||||
if k in comp_dct and settings.no_completion_duplicates:
|
|
||||||
comp_dct[k]._same_name_completions.append(new)
|
|
||||||
else:
|
|
||||||
comp_dct[k] = new
|
|
||||||
comps.append(new)
|
|
||||||
|
|
||||||
debug.speed('completions end')
|
return sorted(completions, key=lambda x: (x.name.startswith('__'),
|
||||||
|
x.name.startswith('_'),
|
||||||
return sorted(comps, key=lambda x: (x.name.startswith('__'),
|
x.name.lower()))
|
||||||
x.name.startswith('_'),
|
|
||||||
x.name.lower()))
|
|
||||||
|
|
||||||
def get_completions(self, user_stmt, completion_parts):
|
def get_completions(self, user_stmt, completion_parts):
|
||||||
# TODO this closure is ugly. it also doesn't work with
|
# TODO this closure is ugly. it also doesn't work with
|
||||||
@@ -93,7 +105,7 @@ class Completion:
|
|||||||
if unfinished_dotted:
|
if unfinished_dotted:
|
||||||
return completion_names
|
return completion_names
|
||||||
else:
|
else:
|
||||||
return set([keywords.keyword(self._evaluator, 'import').name])
|
return [keywords.keyword(self._evaluator, 'import').name]
|
||||||
|
|
||||||
if isinstance(user_stmt, tree.Import):
|
if isinstance(user_stmt, tree.Import):
|
||||||
module = self._parser.module()
|
module = self._parser.module()
|
||||||
|
|||||||
Reference in New Issue
Block a user