Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show completions with and without params #699

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 22 additions & 22 deletions pyls/plugins/jedi_completion.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Copyright 2017 Palantir Technologies, Inc.
import logging
from itertools import chain
import parso
from pyls import hookimpl, lsp, _utils

Expand Down Expand Up @@ -56,7 +57,8 @@ def pyls_completions(config, document, position):
should_include_params = settings.get('include_params')
include_params = (snippet_support and should_include_params and
use_snippets(document, position))
return [_format_completion(d, include_params) for d in definitions] or None

return list(chain.from_iterable(_format_completions(d, include_params) for d in definitions))


def use_snippets(document, position):
Expand All @@ -81,39 +83,37 @@ def use_snippets(document, position):
return tokens.children[0].type not in _IMPORTS


def _format_completion(d, include_params=True):
def _format_completions(d, include_params):
yield _format_completion(d, False)
if include_params and hasattr(d, 'params'):
yield _format_completion(d, True)


def _format_completion(d, include_params):
completion = {
'label': _label(d),
'label': d.name,
'kind': _TYPE_MAP.get(d.type),
'detail': _detail(d),
'documentation': _utils.format_docstring(d.docstring()),
'sortText': _sort_text(d),
'insertText': d.name
}

if include_params and hasattr(d, 'params') and d.params:
positional_args = [param for param in d.params if '=' not in param.description]

if include_params:
# For completions with params, we can generate a snippet instead
completion['insertTextFormat'] = lsp.InsertTextFormat.Snippet
snippet = d.name + '('
for i, param in enumerate(positional_args):
name = param.name if param.name != '/' else '\\/'
snippet += '${%s:%s}' % (i + 1, name)
if i < len(positional_args) - 1:
snippet += ', '
snippet += ')$0'
completion['insertText'] = snippet

return completion

def fix_name(name):
return '\\/' if name == '/' else name

def _label(definition):
if definition.type in ('function', 'method') and hasattr(definition, 'params'):
params = ', '.join([param.name for param in definition.params])
return '{}({})'.format(definition.name, params)
names = [fix_name(param.name) for param in d.params if '=' not in param.description]
snippets = ('${{{}:{}}}'.format(i + 1, p) for i, p in enumerate(names))
completion.update(
insertTextFormat=lsp.InsertTextFormat.Snippet,
label='{}({})'.format(d.name, ', '.join(names)),
insertText='{}({})$0'.format(d.name, ', '.join(snippets))
)

return definition.name
return completion


def _detail(definition):
Expand Down
21 changes: 12 additions & 9 deletions test/plugins/test_completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def test_jedi_completion(config):
items = pyls_jedi_completions(config, doc, com_position)

assert items
assert items[0]['label'] == 'isabs(path)'
assert items[0]['label'] == 'isabs'

# Test we don't throw with big character
pyls_jedi_completions(config, doc, {'line': 1, 'character': 1000})
Expand All @@ -84,7 +84,7 @@ def test_jedi_completion_ordering(config):
items = {c['label']: c['sortText'] for c in completions}

# And that 'hidden' functions come after unhidden ones
assert items['hello()'] < items['_a_hello()']
assert items['hello'] < items['_a_hello']


def test_jedi_property_completion(config):
Expand All @@ -108,7 +108,7 @@ def test_jedi_method_completion(config):
config.update({'plugins': {'jedi_completion': {'include_params': True}}})

completions = pyls_jedi_completions(config, doc, com_position)
everyone_method = [completion for completion in completions if completion['label'] == 'everyone(a, b, c, d)'][0]
everyone_method = [completion for completion in completions if completion['label'] == 'everyone(a, b)'][0]

# Ensure we only generate snippets for positional args
assert everyone_method['insertTextFormat'] == lsp.InsertTextFormat.Snippet
Expand All @@ -118,7 +118,7 @@ def test_jedi_method_completion(config):
config.update({'plugins': {'jedi_completion': {'include_params': False}}})

completions = pyls_jedi_completions(config, doc, com_position)
everyone_method = [completion for completion in completions if completion['label'] == 'everyone(a, b, c, d)'][0]
everyone_method = [completion for completion in completions if completion['label'] == 'everyone'][0]

assert 'insertTextFormat' not in everyone_method
assert everyone_method['insertText'] == 'everyone'
Expand Down Expand Up @@ -170,8 +170,11 @@ def test_snippets_completion(config):

com_position = {'line': 1, 'character': len(doc_snippets)}
completions = pyls_jedi_completions(config, doc, com_position)
out = 'defaultdict(${1:default_factory}, ${2:iterable}, ${3:kwargs})$0'
assert completions[0]['insertText'] == out
assert len(completions) == 2
assert completions[0]['insertText'] == 'defaultdict'
assert completions[0]['label'] == 'defaultdict'
assert completions[1]['insertText'] == 'defaultdict(${1:default_factory}, ${2:iterable}, ${3:kwargs})$0'
assert completions[1]['label'] == 'defaultdict(default_factory, iterable, kwargs)'


def test_snippet_parsing(config):
Expand All @@ -183,7 +186,7 @@ def test_snippet_parsing(config):
config.update({'plugins': {'jedi_completion': {'include_params': True}}})
completions = pyls_jedi_completions(config, doc, completion_position)
out = 'logical_and(${1:x1}, ${2:x2}, ${3:\\/}, ${4:*})$0'
assert completions[0]['insertText'] == out
assert completions[1]['insertText'] == out


def test_multiline_snippets(config):
Expand Down Expand Up @@ -217,7 +220,7 @@ def test_multistatement_snippet(config):
doc = Document(DOC_URI, document)
position = {'line': 0, 'character': len(document)}
completions = pyls_jedi_completions(config, doc, position)
assert completions[0]['insertText'] == 'date(${1:year}, ${2:month}, ${3:day})$0'
assert completions[1]['insertText'] == 'date(${1:year}, ${2:month}, ${3:day})$0'


def test_jedi_completion_extra_paths(config, tmpdir):
Expand Down Expand Up @@ -248,7 +251,7 @@ def spam():
# After 'foo.s' with extra paths
com_position = {'line': 1, 'character': 5}
completions = pyls_jedi_completions(config, doc, com_position)
assert completions[0]['label'] == 'spam()'
assert completions[0]['label'] == 'spam'


@pytest.mark.skipif(PY2 or not LINUX or not CI, reason="tested on linux and python 3 only")
Expand Down