Skip to content
Merged
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
5 changes: 5 additions & 0 deletions pyls/lsp.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ class DiagnosticSeverity(object):
Hint = 4


class InsertTextFormat(object):
PlainText = 1
Snippet = 2


class MessageType(object):
Error = 1
Warning = 2
Expand Down
41 changes: 32 additions & 9 deletions pyls/plugins/jedi_completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,39 @@


@hookimpl
def pyls_completions(document, position):
def pyls_completions(config, document, position):
definitions = document.jedi_script(position).completions()
return [{
'label': _label(d),
'kind': _kind(d),
'detail': _detail(d),
'documentation': _utils.format_docstring(d.docstring()),
'sortText': _sort_text(d),
'insertText': d.name
} for d in definitions] or None
if not definitions:
return None

settings = config.plugin_settings('jedi_completion', document_path=document.path)
include_params = settings.get('include_params', True)

completions = []
for d in definitions:
completion = {
'label': _label(d),
'kind': _kind(d),
'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:
# For completions with params, we can generate a snippet instead
completion['insertTextFormat'] = lsp.InsertTextFormat.Snippet
snippet = d.name + '('
for i, param in enumerate(d.params):
snippet += '${%s:%s}' % (i + 1, param.name)
if i < len(d.params) - 1:
snippet += ', '
snippet += ')$0'
completion['insertText'] = snippet

completions.append(completion)

return completions or None


def _label(definition):
Expand Down
44 changes: 35 additions & 9 deletions test/plugins/test_completion.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Copyright 2017 Palantir Technologies, Inc.
import os

from pyls import uris
from pyls import uris, lsp
from pyls.workspace import Document
from pyls.plugins.jedi_completion import pyls_completions as pyls_jedi_completions
from pyls.plugins.rope_completion import pyls_completions as pyls_rope_completions
Expand All @@ -26,7 +26,12 @@ class Hello():
def world(self):
return None

def everyone(self, a, b, c=None, d=2):
pass

print Hello().world

print Hello().every
"""


Expand All @@ -37,17 +42,17 @@ def test_rope_import_completion(config, workspace):
assert items is None


def test_jedi_completion():
def test_jedi_completion(config):
# Over 'i' in os.path.isabs(...)
com_position = {'line': 1, 'character': 15}
doc = Document(DOC_URI, DOC)
items = pyls_jedi_completions(doc, com_position)
items = pyls_jedi_completions(config, doc, com_position)

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

# Test we don't throw with big character
pyls_jedi_completions(doc, {'line': 1, 'character': 1000})
pyls_jedi_completions(config, doc, {'line': 1, 'character': 1000})


def test_rope_completion(config, workspace):
Expand All @@ -61,25 +66,46 @@ def test_rope_completion(config, workspace):
assert items[0]['label'] == 'isabs'


def test_jedi_completion_ordering():
def test_jedi_completion_ordering(config):
# Over the blank line
com_position = {'line': 8, 'character': 0}
doc = Document(DOC_URI, DOC)
completions = pyls_jedi_completions(doc, com_position)
completions = pyls_jedi_completions(config, doc, com_position)

items = {c['label']: c['sortText'] for c in completions}

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


def test_jedi_property_completion():
def test_jedi_property_completion(config):
# Over the 'w' in 'print Hello().world'
com_position = {'line': 15, 'character': 15}
com_position = {'line': 18, 'character': 15}
doc = Document(DOC_URI, DOC)
completions = pyls_jedi_completions(doc, com_position)
completions = pyls_jedi_completions(config, doc, com_position)

items = {c['label']: c['sortText'] for c in completions}

# Ensure we can complete the 'world' property
assert 'world' in items


def test_jedi_method_completion(config):
# Over the 'y' in 'print Hello().every'
com_position = {'line': 20, 'character': 19}
doc = Document(DOC_URI, DOC)

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

assert everyone_method['insertTextFormat'] == lsp.InsertTextFormat.Snippet
assert everyone_method['insertText'] == 'everyone(${1:a}, ${2:b}, ${3:c}, ${4:d})$0'

# Disable param snippets
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]

assert 'insertTextFormat' not in everyone_method
assert everyone_method['insertText'] == 'everyone'
5 changes: 5 additions & 0 deletions vscode-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@
"default": true,
"description": "Enable or disable the plugin."
},
"pyls.plugins.jedi_completion.include_params": {
"type": "boolean",
"default": true,
"description": "Auto-completes methods and classes with tabstops for each parameter."
},
"pyls.plugins.jedi_definition.enabled": {
"type": "boolean",
"default": true,
Expand Down