]> crepu.dev Git - config.git/blob - djavu-asus/emacs/elpy/rpc-venv/lib/python3.11/site-packages/jedi/api/strings.py
7850142c5e1470a0c6c2a3313f205defbd35fb85
[config.git] / djavu-asus / emacs / elpy / rpc-venv / lib / python3.11 / site-packages / jedi / api / strings.py
1 """
2 This module is here for string completions. This means mostly stuff where
3 strings are returned, like `foo = dict(bar=3); foo["ba` would complete to
4 `"bar"]`.
5
6 It however does the same for numbers. The difference between string completions
7 and other completions is mostly that this module doesn't return defined
8 names in a module, but pretty much an arbitrary string.
9 """
10 import re
11
12 from jedi.inference.names import AbstractArbitraryName
13 from jedi.inference.helpers import infer_call_of_leaf
14 from jedi.api.classes import Completion
15 from jedi.parser_utils import cut_value_at_position
16
17 _sentinel = object()
18
19
20 class StringName(AbstractArbitraryName):
21 api_type = 'string'
22 is_value_name = False
23
24
25 def complete_dict(module_context, code_lines, leaf, position, string, fuzzy):
26 bracket_leaf = leaf
27 if bracket_leaf != '[':
28 bracket_leaf = leaf.get_previous_leaf()
29
30 cut_end_quote = ''
31 if string:
32 cut_end_quote = get_quote_ending(string, code_lines, position, invert_result=True)
33
34 if bracket_leaf == '[':
35 if string is None and leaf is not bracket_leaf:
36 string = cut_value_at_position(leaf, position)
37
38 context = module_context.create_context(bracket_leaf)
39
40 before_node = before_bracket_leaf = bracket_leaf.get_previous_leaf()
41 if before_node in (')', ']', '}'):
42 before_node = before_node.parent
43 if before_node.type in ('atom', 'trailer', 'name'):
44 values = infer_call_of_leaf(context, before_bracket_leaf)
45 return list(_completions_for_dicts(
46 module_context.inference_state,
47 values,
48 '' if string is None else string,
49 cut_end_quote,
50 fuzzy=fuzzy,
51 ))
52 return []
53
54
55 def _completions_for_dicts(inference_state, dicts, literal_string, cut_end_quote, fuzzy):
56 for dict_key in sorted(_get_python_keys(dicts), key=lambda x: repr(x)):
57 dict_key_str = _create_repr_string(literal_string, dict_key)
58 if dict_key_str.startswith(literal_string):
59 name = StringName(inference_state, dict_key_str[:-len(cut_end_quote) or None])
60 yield Completion(
61 inference_state,
62 name,
63 stack=None,
64 like_name_length=len(literal_string),
65 is_fuzzy=fuzzy
66 )
67
68
69 def _create_repr_string(literal_string, dict_key):
70 if not isinstance(dict_key, (str, bytes)) or not literal_string:
71 return repr(dict_key)
72
73 r = repr(dict_key)
74 prefix, quote = _get_string_prefix_and_quote(literal_string)
75 if quote is None:
76 return r
77 if quote == r[0]:
78 return prefix + r
79 return prefix + quote + r[1:-1] + quote
80
81
82 def _get_python_keys(dicts):
83 for dct in dicts:
84 if dct.array_type == 'dict':
85 for key in dct.get_key_values():
86 dict_key = key.get_safe_value(default=_sentinel)
87 if dict_key is not _sentinel:
88 yield dict_key
89
90
91 def _get_string_prefix_and_quote(string):
92 match = re.match(r'(\w*)("""|\'{3}|"|\')', string)
93 if match is None:
94 return None, None
95 return match.group(1), match.group(2)
96
97
98 def _matches_quote_at_position(code_lines, quote, position):
99 string = code_lines[position[0] - 1][position[1]:position[1] + len(quote)]
100 return string == quote
101
102
103 def get_quote_ending(string, code_lines, position, invert_result=False):
104 _, quote = _get_string_prefix_and_quote(string)
105 if quote is None:
106 return ''
107
108 # Add a quote only if it's not already there.
109 if _matches_quote_at_position(code_lines, quote, position) != invert_result:
110 return ''
111 return quote