mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-07 22:44:27 +08:00
Get dict completions mostly working
This commit is contained in:
@@ -96,20 +96,20 @@ class Completion:
|
|||||||
# The actual cursor position is not what we need to calculate
|
# The actual cursor position is not what we need to calculate
|
||||||
# everything. We want the start of the name we're on.
|
# everything. We want the start of the name we're on.
|
||||||
self._original_position = position
|
self._original_position = position
|
||||||
self._position = position[0], position[1] - len(self._like_name)
|
|
||||||
self._signatures_callback = signatures_callback
|
self._signatures_callback = signatures_callback
|
||||||
|
|
||||||
self._fuzzy = fuzzy
|
self._fuzzy = fuzzy
|
||||||
|
|
||||||
def complete(self, fuzzy):
|
def complete(self, fuzzy):
|
||||||
leaf = self._module_node.get_leaf_for_position(self._position, include_prefixes=True)
|
leaf = self._module_node.get_leaf_for_position(self._original_position, include_prefixes=True)
|
||||||
string, start_leaf = _extract_string_while_in_string(leaf, self._position)
|
string, start_leaf, quote = _extract_string_while_in_string(leaf, self._original_position)
|
||||||
|
|
||||||
prefixed_completions = complete_dict(
|
prefixed_completions = complete_dict(
|
||||||
self._module_context,
|
self._module_context,
|
||||||
leaf,
|
self._code_lines,
|
||||||
|
start_leaf or leaf,
|
||||||
self._original_position,
|
self._original_position,
|
||||||
string,
|
None if string is None else quote + string,
|
||||||
fuzzy=fuzzy,
|
fuzzy=fuzzy,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -152,6 +152,10 @@ class Completion:
|
|||||||
|
|
||||||
grammar = self._inference_state.grammar
|
grammar = self._inference_state.grammar
|
||||||
self.stack = stack = None
|
self.stack = stack = None
|
||||||
|
self._position = (
|
||||||
|
self._original_position[0],
|
||||||
|
self._original_position[1] - len(self._like_name)
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.stack = stack = helpers.get_stack_at_position(
|
self.stack = stack = helpers.get_stack_at_position(
|
||||||
@@ -430,21 +434,33 @@ def _gather_nodes(stack):
|
|||||||
|
|
||||||
def _extract_string_while_in_string(leaf, position):
|
def _extract_string_while_in_string(leaf, position):
|
||||||
if position < leaf.start_pos:
|
if position < leaf.start_pos:
|
||||||
return None, None
|
return None, None, None
|
||||||
|
|
||||||
if leaf.type == 'string':
|
if leaf.type == 'string':
|
||||||
match = re.match(r'^\w*(\'{3}|"{3}|\'|")', leaf.value)
|
match = re.match(r'^\w*(\'{3}|"{3}|\'|")', leaf.value)
|
||||||
quote = match.group(1)
|
start = match.group(0)
|
||||||
if leaf.line == position[0] and position[1] < leaf.column + match.end():
|
if leaf.line == position[0] and position[1] < leaf.column + match.end():
|
||||||
return None, None
|
return None, None, None
|
||||||
if leaf.end_pos[0] == position[0] and position[1] > leaf.end_pos[1] - len(quote):
|
if leaf.end_pos[0] == position[0] and position[1] > leaf.end_pos[1] - len(start):
|
||||||
return None, None
|
return None, None, None
|
||||||
return cut_value_at_position(leaf, position)[match.end():], leaf
|
return cut_value_at_position(leaf, position)[match.end():], leaf, start
|
||||||
|
|
||||||
leaves = []
|
leaves = []
|
||||||
while leaf is not None and leaf.line == position[0]:
|
while leaf is not None and leaf.line == position[0]:
|
||||||
if leaf.type == 'error_leaf' and ('"' in leaf.value or "'" in leaf.value):
|
if leaf.type == 'error_leaf' and ('"' in leaf.value or "'" in leaf.value):
|
||||||
return ''.join(l.get_code() for l in leaves), leaf
|
prefix_leaf = None
|
||||||
|
if not leaf.prefix:
|
||||||
|
prefix_leaf = leaf.get_previous_leaf()
|
||||||
|
if prefix_leaf is None or prefix_leaf.type != 'name' \
|
||||||
|
or not all(c in 'rubf' for c in prefix_leaf.value.lower()):
|
||||||
|
prefix_leaf = None
|
||||||
|
|
||||||
|
return (
|
||||||
|
''.join(cut_value_at_position(l, position) for l in leaves),
|
||||||
|
prefix_leaf or leaf,
|
||||||
|
('' if prefix_leaf is None else prefix_leaf.value)
|
||||||
|
+ cut_value_at_position(leaf, position),
|
||||||
|
)
|
||||||
leaves.insert(0, leaf)
|
leaves.insert(0, leaf)
|
||||||
leaf = leaf.get_previous_leaf()
|
leaf = leaf.get_previous_leaf()
|
||||||
return None, None
|
return None, None, None
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ def complete_file_name(inference_state, module_context, start_leaf, string,
|
|||||||
match = start_match(name, must_start_with)
|
match = start_match(name, must_start_with)
|
||||||
if match:
|
if match:
|
||||||
if is_in_os_path_join or not entry.is_dir():
|
if is_in_os_path_join or not entry.is_dir():
|
||||||
name += get_quote_ending(start_leaf, code_lines, position)
|
name += get_quote_ending(start_leaf.value, code_lines, position)
|
||||||
else:
|
else:
|
||||||
name += os.path.sep
|
name += os.path.sep
|
||||||
|
|
||||||
|
|||||||
@@ -23,26 +23,19 @@ class StringName(AbstractArbitraryName):
|
|||||||
is_value_name = False
|
is_value_name = False
|
||||||
|
|
||||||
|
|
||||||
def complete_dict(module_context, leaf, position, string, fuzzy):
|
def complete_dict(module_context, code_lines, leaf, position, string, fuzzy):
|
||||||
if string is None:
|
|
||||||
string = ''
|
|
||||||
bracket_leaf = leaf
|
bracket_leaf = leaf
|
||||||
end_quote = ''
|
if bracket_leaf != '[':
|
||||||
if bracket_leaf.type in ('number', 'error_leaf'):
|
bracket_leaf = leaf.get_previous_leaf()
|
||||||
string = cut_value_at_position(bracket_leaf, position)
|
|
||||||
if bracket_leaf.end_pos > position:
|
|
||||||
end_quote = _get_string_quote(string) or ''
|
|
||||||
if end_quote:
|
|
||||||
ending = cut_value_at_position(
|
|
||||||
bracket_leaf,
|
|
||||||
(position[0], position[1] + len(end_quote))
|
|
||||||
)
|
|
||||||
if not ending.endswith(end_quote):
|
|
||||||
end_quote = ''
|
|
||||||
|
|
||||||
bracket_leaf = bracket_leaf.get_previous_leaf()
|
cut_end_quote = ''
|
||||||
|
if string:
|
||||||
|
cut_end_quote = get_quote_ending(string, code_lines, position, invert_result=True)
|
||||||
|
|
||||||
if bracket_leaf == '[':
|
if bracket_leaf == '[':
|
||||||
|
if string is None and leaf is not bracket_leaf:
|
||||||
|
string = cut_value_at_position(leaf, position)
|
||||||
|
|
||||||
context = module_context.create_context(bracket_leaf)
|
context = module_context.create_context(bracket_leaf)
|
||||||
before_bracket_leaf = bracket_leaf.get_previous_leaf()
|
before_bracket_leaf = bracket_leaf.get_previous_leaf()
|
||||||
if before_bracket_leaf.type in ('atom', 'trailer', 'name'):
|
if before_bracket_leaf.type in ('atom', 'trailer', 'name'):
|
||||||
@@ -51,17 +44,17 @@ def complete_dict(module_context, leaf, position, string, fuzzy):
|
|||||||
module_context.inference_state,
|
module_context.inference_state,
|
||||||
values,
|
values,
|
||||||
'' if string is None else string,
|
'' if string is None else string,
|
||||||
end_quote,
|
cut_end_quote,
|
||||||
fuzzy=fuzzy,
|
fuzzy=fuzzy,
|
||||||
))
|
))
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def _completions_for_dicts(inference_state, dicts, literal_string, end_quote, fuzzy):
|
def _completions_for_dicts(inference_state, dicts, literal_string, cut_end_quote, fuzzy):
|
||||||
for dict_key in sorted(_get_python_keys(dicts), key=lambda x: repr(x)):
|
for dict_key in sorted(_get_python_keys(dicts), key=lambda x: repr(x)):
|
||||||
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(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, n)
|
||||||
yield Completion(
|
yield Completion(
|
||||||
inference_state,
|
inference_state,
|
||||||
@@ -78,6 +71,8 @@ def _create_repr_string(literal_string, dict_key):
|
|||||||
|
|
||||||
r = repr(dict_key)
|
r = repr(dict_key)
|
||||||
prefix, quote = _get_string_prefix_and_quote(literal_string)
|
prefix, quote = _get_string_prefix_and_quote(literal_string)
|
||||||
|
if quote is None:
|
||||||
|
return r
|
||||||
if quote == r[0]:
|
if quote == r[0]:
|
||||||
return prefix + r
|
return prefix + r
|
||||||
return prefix + quote + r[1:-1] + quote
|
return prefix + quote + r[1:-1] + quote
|
||||||
@@ -103,15 +98,14 @@ def _get_string_quote(string):
|
|||||||
return _get_string_prefix_and_quote(string)[1]
|
return _get_string_prefix_and_quote(string)[1]
|
||||||
|
|
||||||
|
|
||||||
def get_quote_ending(start_leaf, code_lines, position):
|
def _matches_quote_at_position(code_lines, quote, position):
|
||||||
if start_leaf.type == 'string':
|
string = code_lines[position[0] - 1][position[1]:position[1] + len(quote)]
|
||||||
quote = _get_string_quote(start_leaf)
|
return string == quote
|
||||||
else:
|
|
||||||
assert start_leaf.type == 'error_leaf'
|
|
||||||
quote = start_leaf.value
|
def get_quote_ending(string, code_lines, position, invert_result=False):
|
||||||
potential_other_quote = \
|
quote = _get_string_quote(string)
|
||||||
code_lines[position[0] - 1][position[1]:position[1] + len(quote)]
|
|
||||||
# Add a quote only if it's not already there.
|
# Add a quote only if it's not already there.
|
||||||
if quote == potential_other_quote:
|
if _matches_quote_at_position(code_lines, quote, position) != invert_result:
|
||||||
return ''
|
return ''
|
||||||
return quote
|
return quote
|
||||||
|
|||||||
@@ -410,7 +410,7 @@ class DirectObjectAccess(object):
|
|||||||
return [self._create_access(module), access]
|
return [self._create_access(module), access]
|
||||||
|
|
||||||
def get_safe_value(self):
|
def get_safe_value(self):
|
||||||
if type(self._obj) in (bool, bytes, float, int, str, unicode, slice):
|
if type(self._obj) in (bool, bytes, float, int, str, unicode, slice) or self._obj is None:
|
||||||
return self._obj
|
return self._obj
|
||||||
raise ValueError("Object is type %s and not simple" % type(self._obj))
|
raise ValueError("Object is type %s and not simple" % type(self._obj))
|
||||||
|
|
||||||
|
|||||||
@@ -298,15 +298,15 @@ _dict_keys_completion_tests = [
|
|||||||
('strs[b"]', 8, []),
|
('strs[b"]', 8, []),
|
||||||
('strs[r"asd', 10, ['f"']),
|
('strs[r"asd', 10, ['f"']),
|
||||||
('strs[R"asd', 10, ['f"']),
|
('strs[R"asd', 10, ['f"']),
|
||||||
('strs[f"asd', 10, ['f"']),
|
('strs[f"asd', 10, []),
|
||||||
|
|
||||||
('strs["f', 7, ['oo"]']),
|
('strs["f', 7, ['bar"', 'oo"']),
|
||||||
('strs["f"', 7, ['oo']),
|
('strs["f"', 7, ['bar', 'oo']),
|
||||||
('strs["f]', 7, ['oo"]']),
|
('strs["f]', 7, ['bar"', 'oo"']),
|
||||||
('strs["f"]', 7, ['oo']),
|
('strs["f"]', 7, ['bar', 'oo']),
|
||||||
|
|
||||||
('mixed[', 6, ['1', '1.1', 'None', "'a\sdf'", "b'foo'"]),
|
('mixed[', 6, [r"'a\\sdf'", '1', '1.1', 'None', "b'foo'", Ellipsis]),
|
||||||
('mixed[1', 6, ['', '.1']),
|
('mixed[1', 7, ['', '.1']),
|
||||||
|
|
||||||
('casted["f', 9, ['3"', 'bar"', 'oo"']),
|
('casted["f', 9, ['3"', 'bar"', 'oo"']),
|
||||||
('casted_mod["f', 13, ['3"', 'bar"', 'oo"', 'uuu"', 'ull"']),
|
('casted_mod["f', 13, ['3"', 'bar"', 'oo"', 'uuu"', 'ull"']),
|
||||||
|
|||||||
Reference in New Issue
Block a user