Skip to content

Commit a7da85a

Browse files
committed
add resolve provides, preload packages and speed up things
1 parent 155bc04 commit a7da85a

File tree

5 files changed

+85
-29
lines changed

5 files changed

+85
-29
lines changed

pyls/hookspecs.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ def pyls_commands(config, workspace):
2626
def pyls_completions(config, workspace, document, position):
2727
pass
2828

29+
@hookspec
30+
def pyls_completion_detail(config, item):
31+
pass
2932

3033
@hookspec
3134
def pyls_definitions(config, workspace, document, position):

pyls/plugins/jedi_completion.py

Lines changed: 65 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Copyright 2017 Palantir Technologies, Inc.
22
import logging
3+
import time
34
from pyls import hookimpl, lsp, _utils
5+
from contextlib import contextmanager
6+
import signal
47

58
log = logging.getLogger(__name__)
69

@@ -38,44 +41,85 @@
3841
'statement': lsp.CompletionItemKind.Keyword,
3942
}
4043

44+
COMPLETION_CACHE = {}
45+
46+
@contextmanager
47+
def timeout(time):
48+
# Register a function to raise a TimeoutError on the signal.
49+
signal.signal(signal.SIGALRM, raise_timeout)
50+
# Schedule the signal to be sent after ``time``.
51+
signal.setitimer(signal.SIGALRM, time)
52+
53+
try:
54+
yield
55+
except TimeoutError:
56+
pass
57+
finally:
58+
# Unregister the signal so it won't be triggered
59+
# if the timeout is not reached.
60+
signal.signal(signal.SIGALRM, signal.SIG_IGN)
61+
62+
63+
def raise_timeout(signum, frame):
64+
raise TimeoutError
4165

4266
@hookimpl
4367
def pyls_completions(config, document, position):
4468
definitions = document.jedi_script(position).completions()
4569
if not definitions:
4670
return None
4771

72+
if len(definitions) > 40:
73+
definitions = definitions[:40]
74+
4875
completion_capabilities = config.capabilities.get('textDocument', {}).get('completion', {})
4976
snippet_support = completion_capabilities.get('completionItem', {}).get('snippetSupport')
5077

5178
settings = config.plugin_settings('jedi_completion', document_path=document.path)
5279
should_include_params = settings.get('include_params')
5380

54-
return [_format_completion(d, snippet_support and should_include_params) for d in definitions] or None
81+
result = [_format_completion(d, i, snippet_support and should_include_params) for i, d in enumerate(definitions)] or None
82+
return result
5583

56-
57-
def _format_completion(d, include_params=True):
58-
completion = {
59-
'label': _label(d),
60-
'kind': _TYPE_MAP.get(d.type),
61-
'detail': _detail(d),
84+
@hookimpl
85+
def pyls_completion_detail(config, item):
86+
d = COMPLETION_CACHE.get(item)
87+
if d:
88+
completion = {
89+
'label': '', #_label(d),
90+
'kind': _TYPE_MAP[d.type],
91+
'detail': '', #_detail(d),
6292
'documentation': _utils.format_docstring(d.docstring()),
63-
'sortText': _sort_text(d),
93+
'sortText': '', #_sort_text(d),
94+
'insertText': d.name
95+
}
96+
return completion
97+
else:
98+
print('Completion missing')
99+
return None
100+
101+
def _format_completion(d, i, include_params=True):
102+
COMPLETION_CACHE[d.name] = d
103+
completion = {
104+
'label': '', #_label(d),
105+
'kind': '',
106+
'detail': '', #_detail(d),
107+
'documentation': _utils.format_docstring(d.docstring()) if i == 0 else '',
108+
'sortText': '', #_sort_text(d),
64109
'insertText': d.name
65110
}
66-
67-
if include_params and hasattr(d, 'params') and d.params:
68-
positional_args = [param for param in d.params if '=' not in param.description]
69-
70-
# For completions with params, we can generate a snippet instead
71-
completion['insertTextFormat'] = lsp.InsertTextFormat.Snippet
72-
snippet = d.name + '('
73-
for i, param in enumerate(positional_args):
74-
snippet += '${%s:%s}' % (i + 1, param.name)
75-
if i < len(positional_args) - 1:
76-
snippet += ', '
77-
snippet += ')$0'
78-
completion['insertText'] = snippet
111+
# if include_params and hasattr(d, 'params') and d.params:
112+
# positional_args = [param for param in d.params if '=' not in param.description]
113+
114+
# # For completions with params, we can generate a snippet instead
115+
# completion['insertTextFormat'] = lsp.InsertTextFormat.Snippet
116+
# snippet = d.name + '('
117+
# for i, param in enumerate(positional_args):
118+
# snippet += '${%s:%s}' % (i + 1, param.name)
119+
# if i < len(positional_args) - 1:
120+
# snippet += ', '
121+
# snippet += ')$0'
122+
# completion['insertText'] = snippet
79123

80124
return completion
81125

pyls/plugins/preload_imports.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,11 @@
55
log = logging.getLogger(__name__)
66

77
MODULES = [
8-
"OpenGL", "PIL",
9-
"array", "audioop", "binascii", "cPickle", "cStringIO", "cmath", "collections",
8+
"numpy", "tensorflow", "sklearn", "array", "binascii", "cmath", "collections",
109
"datetime", "errno", "exceptions", "gc", "imageop", "imp", "itertools",
1110
"marshal", "math", "matplotlib", "mmap", "mpmath", "msvcrt", "networkx", "nose", "nt",
12-
"numpy", "operator", "os", "os.path", "pandas", "parser", "rgbimg", "scipy", "signal",
13-
"skimage", "sklearn", "statsmodels", "strop", "sympy", "sys", "thread", "time",
14-
"wx", "xxsubtype", "zipimport", "zlib"
11+
"operator", "os", "os.path", "pandas", "parser", "scipy", "signal",
12+
"skimage", "statsmodels", "strop", "sympy", "sys", "thread", "time", "wx", "zlib"
1513
]
1614

1715

pyls/python_ls.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ def shutdown_server(*args):
6868
'SHUTDOWN_CALL': shutdown_server}
6969
)
7070

71+
socketserver.TCPServer.allow_reuse_address = True
7172
server = socketserver.TCPServer((bind_addr, port), wrapper_class)
72-
server.allow_reuse_address = True
7373

7474
try:
7575
log.info('Serving %s on (%s, %s)', handler_class.__name__, bind_addr, port)
@@ -159,7 +159,7 @@ def capabilities(self):
159159
'resolveProvider': False, # We may need to make this configurable
160160
},
161161
'completionProvider': {
162-
'resolveProvider': False, # We know everything ahead of time
162+
'resolveProvider': True,
163163
'triggerCharacters': ['.']
164164
},
165165
'documentFormattingProvider': True,
@@ -236,10 +236,14 @@ def code_lens(self, doc_uri):
236236
def completions(self, doc_uri, position):
237237
completions = self._hook('pyls_completions', doc_uri, position=position)
238238
return {
239-
'isIncomplete': False,
239+
'isIncomplete': True,
240240
'items': flatten(completions)
241241
}
242242

243+
def completion_detail(self, item):
244+
detail = self._hook('pyls_completion_detail', item=item)
245+
return detail
246+
243247
def definitions(self, doc_uri, position):
244248
return flatten(self._hook('pyls_definitions', doc_uri, position=position))
245249

@@ -318,6 +322,9 @@ def m_text_document__code_lens(self, textDocument=None, **_kwargs):
318322
def m_text_document__completion(self, textDocument=None, position=None, **_kwargs):
319323
return self.completions(textDocument['uri'], position)
320324

325+
def m_completion_item__resolve(self, label=None, **_kwargs):
326+
return self.completion_detail(label)
327+
321328
def m_text_document__definition(self, textDocument=None, position=None, **_kwargs):
322329
return self.definitions(textDocument['uri'], position)
323330

pyls/workspace.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,10 @@ def __init__(self, uri, source=None, version=None, local=True, extra_sys_path=No
113113
self._extra_sys_path = extra_sys_path or []
114114
self._rope_project_builder = rope_project_builder
115115

116+
jedi.settings.cache_directory = '.cache/jedi/'
117+
jedi.settings.use_filesystem_cache = True
118+
jedi.api.preload_module(['numpy', 'matplotlib.pyplot', 'tensorflow'])
119+
116120
def __str__(self):
117121
return str(self.uri)
118122

0 commit comments

Comments
 (0)