From 6baa3ae8e1e58d82edcc64b608c9ba3b7fa61c8b Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Fri, 27 Sep 2019 09:36:37 +0200 Subject: [PATCH] Start working on uniting parts of code of file path/dict completion --- jedi/api/completion.py | 6 +++-- jedi/api/dicts.py | 26 ---------------------- jedi/api/file_name.py | 25 ++++++--------------- jedi/api/strings.py | 50 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 46 deletions(-) delete mode 100644 jedi/api/dicts.py create mode 100644 jedi/api/strings.py diff --git a/jedi/api/completion.py b/jedi/api/completion.py index 7562c49b..5a169008 100644 --- a/jedi/api/completion.py +++ b/jedi/api/completion.py @@ -10,7 +10,7 @@ from jedi import settings from jedi.api import classes from jedi.api import helpers from jedi.api import keywords -from jedi.api.dicts import completions_for_dicts +from jedi.api.strings import completions_for_dicts from jedi.api.file_name import file_name_completions from jedi.inference import imports from jedi.inference.helpers import infer_call_of_leaf, parse_dotted_names @@ -93,7 +93,7 @@ class Completion: if string is None: string = '' bracket_leaf = leaf - if bracket_leaf.type == 'number': + if bracket_leaf.type in ('number', 'error_leaf'): string = bracket_leaf.value bracket_leaf = bracket_leaf.get_previous_leaf() @@ -113,6 +113,8 @@ class Completion: )) if completions: return completions + if string is not None: + return prefixed_completions completion_names = self._get_context_completions(leaf) diff --git a/jedi/api/dicts.py b/jedi/api/dicts.py deleted file mode 100644 index c25f7dd9..00000000 --- a/jedi/api/dicts.py +++ /dev/null @@ -1,26 +0,0 @@ -from jedi.inference.names import AbstractArbitraryName -from jedi.api.classes import Completion - -_sentinel = object() - - -class F(AbstractArbitraryName): - api_type = u'path' - is_value_name = False - - -def completions_for_dicts(inference_state, dicts, literal_string): - for dict_key in sorted(_get_python_keys(dicts)): - dict_key_str = repr(dict_key) - if dict_key_str.startswith(literal_string): - name = F(inference_state, dict_key_str[len(literal_string):]) - yield Completion(inference_state, name, stack=None, like_name_length=0) - - -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 diff --git a/jedi/api/file_name.py b/jedi/api/file_name.py index 5871fd90..51a34765 100644 --- a/jedi/api/file_name.py +++ b/jedi/api/file_name.py @@ -1,10 +1,13 @@ import os from jedi._compatibility import FileNotFoundError, force_unicode, scandir -from jedi.inference.names import AbstractArbitraryName from jedi.api import classes +from jedi.api.strings import StringName, get_quote_ending from jedi.inference.helpers import get_str_or_none -from jedi.parser_utils import get_string_quote + + +class PathName(StringName): + api_type = u'path' def file_name_completions(inference_state, module_context, start_leaf, string, @@ -39,22 +42,13 @@ def file_name_completions(inference_state, module_context, start_leaf, string, name = entry.name if name.startswith(must_start_with): if is_in_os_path_join or not entry.is_dir(): - if start_leaf.type == 'string': - quote = get_string_quote(start_leaf) - else: - assert start_leaf.type == 'error_leaf' - quote = start_leaf.value - potential_other_quote = \ - code_lines[position[0] - 1][position[1]:position[1] + len(quote)] - # Add a quote if it's not already there. - if quote != potential_other_quote: - name += quote + name += get_quote_ending(start_leaf, code_lines, position) else: name += os.path.sep yield classes.Completion( inference_state, - FileName(inference_state, name[len(must_start_with) - like_name_length:]), + PathName(inference_state, name[len(must_start_with) - like_name_length:]), stack=None, like_name_length=like_name_length ) @@ -99,11 +93,6 @@ def _add_strings(context, nodes, add_slash=False): return string -class FileName(AbstractArbitraryName): - api_type = u'path' - is_value_name = False - - def _add_os_path_join(module_context, start_leaf, bracket_start): def check(maybe_bracket, nodes): if maybe_bracket.start_pos != bracket_start: diff --git a/jedi/api/strings.py b/jedi/api/strings.py new file mode 100644 index 00000000..ce05e211 --- /dev/null +++ b/jedi/api/strings.py @@ -0,0 +1,50 @@ +""" +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. +""" +from jedi.inference.names import AbstractArbitraryName +from jedi.api.classes import Completion +from jedi.parser_utils import get_string_quote + +_sentinel = object() + + +class StringName(AbstractArbitraryName): + api_type = u'string' + is_value_name = False + + +def completions_for_dicts(inference_state, dicts, literal_string): + for dict_key in sorted(_get_python_keys(dicts)): + dict_key_str = repr(dict_key) + if dict_key_str.startswith(literal_string): + name = StringName(inference_state, dict_key_str[len(literal_string):]) + yield Completion(inference_state, name, stack=None, like_name_length=0) + + +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_quote_ending(start_leaf, code_lines, position): + if start_leaf.type == 'string': + quote = get_string_quote(start_leaf) + else: + assert start_leaf.type == 'error_leaf' + quote = start_leaf.value + potential_other_quote = \ + code_lines[position[0] - 1][position[1]:position[1] + len(quote)] + # Add a quote only if it's not already there. + if quote == potential_other_quote: + return '' + return quote