mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-06 22:14:27 +08:00
Make sure to avoid duplicates in completions
This commit is contained in:
@@ -60,6 +60,11 @@ def filter_names(inference_state, completion_names, stack, like_name, fuzzy):
|
|||||||
yield new
|
yield new
|
||||||
|
|
||||||
|
|
||||||
|
def _remove_duplicates(completions, other_completions):
|
||||||
|
names = {d.name for d in other_completions}
|
||||||
|
return [c for c in completions if c.name not in names]
|
||||||
|
|
||||||
|
|
||||||
def get_user_context(module_context, position):
|
def get_user_context(module_context, position):
|
||||||
"""
|
"""
|
||||||
Returns the scope in which the user resides. This includes flows.
|
Returns the scope in which the user resides. This includes flows.
|
||||||
@@ -128,14 +133,15 @@ class Completion:
|
|||||||
|
|
||||||
completion_names = self._complete_python(leaf)
|
completion_names = self._complete_python(leaf)
|
||||||
|
|
||||||
completions = filter_names(self._inference_state, completion_names,
|
completions = list(filter_names(self._inference_state, completion_names,
|
||||||
self.stack, self._like_name, fuzzy)
|
self.stack, self._like_name, fuzzy))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
prefixed_completions +
|
# Removing duplicates mostly to remove False/True/None duplicates.
|
||||||
sorted(completions, key=lambda x: (x.name.startswith('__'),
|
_remove_duplicates(prefixed_completions, completions)
|
||||||
x.name.startswith('_'),
|
+ sorted(completions, key=lambda x: (x.name.startswith('__'),
|
||||||
x.name.lower()))
|
x.name.startswith('_'),
|
||||||
|
x.name.lower()))
|
||||||
)
|
)
|
||||||
|
|
||||||
def _complete_python(self, leaf):
|
def _complete_python(self, leaf):
|
||||||
@@ -211,9 +217,12 @@ class Completion:
|
|||||||
|
|
||||||
completion_names = []
|
completion_names = []
|
||||||
current_line = self._code_lines[self._position[0] - 1][:self._position[1]]
|
current_line = self._code_lines[self._position[0] - 1][:self._position[1]]
|
||||||
if not current_line or current_line[-1] in ' \t.;' \
|
|
||||||
and current_line[-3:] != '...':
|
completion_names += self._complete_keywords(
|
||||||
completion_names += self._complete_keywords(allowed_transitions)
|
allowed_transitions,
|
||||||
|
only_values=not (not current_line or current_line[-1] in ' \t.;'
|
||||||
|
and current_line[-3:] != '...')
|
||||||
|
)
|
||||||
|
|
||||||
if any(t in allowed_transitions for t in (PythonTokenTypes.NAME,
|
if any(t in allowed_transitions for t in (PythonTokenTypes.NAME,
|
||||||
PythonTokenTypes.INDENT)):
|
PythonTokenTypes.INDENT)):
|
||||||
@@ -293,10 +302,11 @@ class Completion:
|
|||||||
return complete_param_names(context, function_name.value, decorators)
|
return complete_param_names(context, function_name.value, decorators)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def _complete_keywords(self, allowed_transitions):
|
def _complete_keywords(self, allowed_transitions, only_values):
|
||||||
for k in allowed_transitions:
|
for k in allowed_transitions:
|
||||||
if isinstance(k, str) and k.isalpha():
|
if isinstance(k, str) and k.isalpha():
|
||||||
yield keywords.KeywordName(self._inference_state, k)
|
if not only_values or k in ('True', 'False', 'None'):
|
||||||
|
yield keywords.KeywordName(self._inference_state, k)
|
||||||
|
|
||||||
def _complete_global_scope(self):
|
def _complete_global_scope(self):
|
||||||
context = get_user_context(self._module_context, self._position)
|
context = get_user_context(self._module_context, self._position)
|
||||||
|
|||||||
@@ -55,12 +55,12 @@ def _completions_for_dicts(inference_state, dicts, literal_string, cut_end_quote
|
|||||||
dict_key_str = _create_repr_string(literal_string, dict_key)
|
dict_key_str = _create_repr_string(literal_string, dict_key)
|
||||||
if dict_key_str.startswith(literal_string):
|
if dict_key_str.startswith(literal_string):
|
||||||
n = dict_key_str[len(literal_string):-len(cut_end_quote) or None]
|
n = dict_key_str[len(literal_string):-len(cut_end_quote) or None]
|
||||||
name = StringName(inference_state, n)
|
name = StringName(inference_state, dict_key_str[:-len(cut_end_quote) or None])
|
||||||
yield Completion(
|
yield Completion(
|
||||||
inference_state,
|
inference_state,
|
||||||
name,
|
name,
|
||||||
stack=None,
|
stack=None,
|
||||||
like_name_length=0,
|
like_name_length=len(literal_string),
|
||||||
is_fuzzy=fuzzy
|
is_fuzzy=fuzzy
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -305,8 +305,9 @@ _dict_keys_completion_tests = [
|
|||||||
('strs["f]', 7, ['bar"', 'oo"']),
|
('strs["f]', 7, ['bar"', 'oo"']),
|
||||||
('strs["f"]', 7, ['bar', 'oo']),
|
('strs["f"]', 7, ['bar', 'oo']),
|
||||||
|
|
||||||
('mixed[', 6, [r"'a\\sdf'", '1', '1.1', 'None', "b'foo'", Ellipsis]),
|
('mixed[', 6, [r"'a\\sdf'", '1', '1.1', "b'foo'", Ellipsis]),
|
||||||
('mixed[1', 7, ['', '.1']),
|
('mixed[1', 7, ['', '.1']),
|
||||||
|
('mixed[Non', 9, ['e']),
|
||||||
|
|
||||||
('casted["f', 9, ['3"', 'bar"', 'oo"']),
|
('casted["f', 9, ['3"', 'bar"', 'oo"']),
|
||||||
('casted["f"', 9, ['3', 'bar', 'oo']),
|
('casted["f"', 9, ['3', 'bar', 'oo']),
|
||||||
@@ -317,6 +318,7 @@ _dict_keys_completion_tests = [
|
|||||||
('keywords["', None, ['a"']),
|
('keywords["', None, ['a"']),
|
||||||
('keywords[Non', None, ['e']),
|
('keywords[Non', None, ['e']),
|
||||||
('keywords[Fa', None, ['lse']),
|
('keywords[Fa', None, ['lse']),
|
||||||
|
('keywords[Tr', None, ['ue']),
|
||||||
('keywords[str', None, ['', 's']),
|
('keywords[str', None, ['', 's']),
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -337,14 +339,11 @@ def test_dict_keys_completions(Script, added_code, column, expected, skip_pre_py
|
|||||||
keywords = {None: 1, False: 2, "a": 3}
|
keywords = {None: 1, False: 2, "a": 3}
|
||||||
''')
|
''')
|
||||||
line = None
|
line = None
|
||||||
if isinstance(column, tuple):
|
|
||||||
raise NotImplementedError
|
|
||||||
line, column = column
|
|
||||||
comps = Script(code + added_code, line=line, column=column).completions()
|
comps = Script(code + added_code, line=line, column=column).completions()
|
||||||
if Ellipsis in expected:
|
if Ellipsis in expected:
|
||||||
# This means that global completions are part of this, so filter all of
|
# This means that global completions are part of this, so filter all of
|
||||||
# that out.
|
# that out.
|
||||||
comps = [c for c in comps if not c._name.is_value_name]
|
comps = [c for c in comps if not c._name.is_value_name and not c.is_keyword]
|
||||||
expected = [e for e in expected if e is not Ellipsis]
|
expected = [e for e in expected if e is not Ellipsis]
|
||||||
|
|
||||||
assert [c.complete for c in comps] == expected
|
assert [c.complete for c in comps] == expected
|
||||||
|
|||||||
Reference in New Issue
Block a user