You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			112 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			112 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Python
		
	
"""
 | 
						|
This module is here for string completions. This means mostly stuff where
 | 
						|
strings are returned, like `foo = dict(bar=3); foo["ba` would complete to
 | 
						|
`"bar"]`.
 | 
						|
 | 
						|
It however does the same for numbers. The difference between string completions
 | 
						|
and other completions is mostly that this module doesn't return defined
 | 
						|
names in a module, but pretty much an arbitrary string.
 | 
						|
"""
 | 
						|
import re
 | 
						|
 | 
						|
from jedi.inference.names import AbstractArbitraryName
 | 
						|
from jedi.inference.helpers import infer_call_of_leaf
 | 
						|
from jedi.api.classes import Completion
 | 
						|
from jedi.parser_utils import cut_value_at_position
 | 
						|
 | 
						|
_sentinel = object()
 | 
						|
 | 
						|
 | 
						|
class StringName(AbstractArbitraryName):
 | 
						|
    api_type = 'string'
 | 
						|
    is_value_name = False
 | 
						|
 | 
						|
 | 
						|
def complete_dict(module_context, code_lines, leaf, position, string, fuzzy):
 | 
						|
    bracket_leaf = leaf
 | 
						|
    if bracket_leaf != '[':
 | 
						|
        bracket_leaf = 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 string is None and leaf is not bracket_leaf:
 | 
						|
            string = cut_value_at_position(leaf, position)
 | 
						|
 | 
						|
        context = module_context.create_context(bracket_leaf)
 | 
						|
 | 
						|
        before_node = before_bracket_leaf = bracket_leaf.get_previous_leaf()
 | 
						|
        if before_node in (')', ']', '}'):
 | 
						|
            before_node = before_node.parent
 | 
						|
        if before_node.type in ('atom', 'trailer', 'name'):
 | 
						|
            values = infer_call_of_leaf(context, before_bracket_leaf)
 | 
						|
            return list(_completions_for_dicts(
 | 
						|
                module_context.inference_state,
 | 
						|
                values,
 | 
						|
                '' if string is None else string,
 | 
						|
                cut_end_quote,
 | 
						|
                fuzzy=fuzzy,
 | 
						|
            ))
 | 
						|
    return []
 | 
						|
 | 
						|
 | 
						|
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)):
 | 
						|
        dict_key_str = _create_repr_string(literal_string, dict_key)
 | 
						|
        if dict_key_str.startswith(literal_string):
 | 
						|
            name = StringName(inference_state, dict_key_str[:-len(cut_end_quote) or None])
 | 
						|
            yield Completion(
 | 
						|
                inference_state,
 | 
						|
                name,
 | 
						|
                stack=None,
 | 
						|
                like_name_length=len(literal_string),
 | 
						|
                is_fuzzy=fuzzy
 | 
						|
            )
 | 
						|
 | 
						|
 | 
						|
def _create_repr_string(literal_string, dict_key):
 | 
						|
    if not isinstance(dict_key, (str, bytes)) or not literal_string:
 | 
						|
        return repr(dict_key)
 | 
						|
 | 
						|
    r = repr(dict_key)
 | 
						|
    prefix, quote = _get_string_prefix_and_quote(literal_string)
 | 
						|
    if quote is None:
 | 
						|
        return r
 | 
						|
    if quote == r[0]:
 | 
						|
        return prefix + r
 | 
						|
    return prefix + quote + r[1:-1] + quote
 | 
						|
 | 
						|
 | 
						|
def _get_python_keys(dicts):
 | 
						|
    for dct in dicts:
 | 
						|
        if dct.array_type == 'dict':
 | 
						|
            for key in dct.get_key_values():
 | 
						|
                dict_key = key.get_safe_value(default=_sentinel)
 | 
						|
                if dict_key is not _sentinel:
 | 
						|
                    yield dict_key
 | 
						|
 | 
						|
 | 
						|
def _get_string_prefix_and_quote(string):
 | 
						|
    match = re.match(r'(\w*)("""|\'{3}|"|\')', string)
 | 
						|
    if match is None:
 | 
						|
        return None, None
 | 
						|
    return match.group(1), match.group(2)
 | 
						|
 | 
						|
 | 
						|
def _matches_quote_at_position(code_lines, quote, position):
 | 
						|
    string = code_lines[position[0] - 1][position[1]:position[1] + len(quote)]
 | 
						|
    return string == quote
 | 
						|
 | 
						|
 | 
						|
def get_quote_ending(string, code_lines, position, invert_result=False):
 | 
						|
    _, quote = _get_string_prefix_and_quote(string)
 | 
						|
    if quote is None:
 | 
						|
        return ''
 | 
						|
 | 
						|
    # Add a quote only if it's not already there.
 | 
						|
    if _matches_quote_at_position(code_lines, quote, position) != invert_result:
 | 
						|
        return ''
 | 
						|
    return quote
 |