Start working on uniting parts of code of file path/dict completion

This commit is contained in:
Dave Halter
2019-09-27 09:36:37 +02:00
parent 88ebb3e140
commit 6baa3ae8e1
4 changed files with 61 additions and 46 deletions

View File

@@ -10,7 +10,7 @@ from jedi import settings
from jedi.api import classes from jedi.api import classes
from jedi.api import helpers from jedi.api import helpers
from jedi.api import keywords 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.api.file_name import file_name_completions
from jedi.inference import imports from jedi.inference import imports
from jedi.inference.helpers import infer_call_of_leaf, parse_dotted_names from jedi.inference.helpers import infer_call_of_leaf, parse_dotted_names
@@ -93,7 +93,7 @@ class Completion:
if string is None: if string is None:
string = '' string = ''
bracket_leaf = leaf bracket_leaf = leaf
if bracket_leaf.type == 'number': if bracket_leaf.type in ('number', 'error_leaf'):
string = bracket_leaf.value string = bracket_leaf.value
bracket_leaf = bracket_leaf.get_previous_leaf() bracket_leaf = bracket_leaf.get_previous_leaf()
@@ -113,6 +113,8 @@ class Completion:
)) ))
if completions: if completions:
return completions return completions
if string is not None:
return prefixed_completions
completion_names = self._get_context_completions(leaf) completion_names = self._get_context_completions(leaf)

View File

@@ -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

View File

@@ -1,10 +1,13 @@
import os import os
from jedi._compatibility import FileNotFoundError, force_unicode, scandir from jedi._compatibility import FileNotFoundError, force_unicode, scandir
from jedi.inference.names import AbstractArbitraryName
from jedi.api import classes 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.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, 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 name = entry.name
if name.startswith(must_start_with): if name.startswith(must_start_with):
if is_in_os_path_join or not entry.is_dir(): if is_in_os_path_join or not entry.is_dir():
if start_leaf.type == 'string': name += get_quote_ending(start_leaf, code_lines, position)
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
else: else:
name += os.path.sep name += os.path.sep
yield classes.Completion( yield classes.Completion(
inference_state, 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, stack=None,
like_name_length=like_name_length like_name_length=like_name_length
) )
@@ -99,11 +93,6 @@ def _add_strings(context, nodes, add_slash=False):
return string 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 _add_os_path_join(module_context, start_leaf, bracket_start):
def check(maybe_bracket, nodes): def check(maybe_bracket, nodes):
if maybe_bracket.start_pos != bracket_start: if maybe_bracket.start_pos != bracket_start:

50
jedi/api/strings.py Normal file
View File

@@ -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