# Copyright 2017-2020 Palantir Technologies, Inc.
# Copyright 2021- Python Language Server Contributors.
import logging
import re
from pylsp import hookimpl, _utils
log = logging.getLogger(__name__)
SPHINX = re.compile(r"\s*:param\s+(?P\w+):\s*(?P[^\n]+)")
EPYDOC = re.compile(r"\s*@param\s+(?P\w+):\s*(?P[^\n]+)")
GOOGLE = re.compile(r"\s*(?P\w+).*:\s*(?P[^\n]+)")
DOC_REGEX = [SPHINX, EPYDOC, GOOGLE]
@hookimpl
def pylsp_signature_help(document, position):
code_position = _utils.position_to_jedi_linecolumn(document, position)
signatures = document.jedi_script().get_signatures(**code_position)
if not signatures:
return {'signatures': []}
s = signatures[0]
# Docstring contains one or more lines of signature, followed by empty line, followed by docstring
function_sig_lines = (s.docstring().split('\n\n') or [''])[0].splitlines()
function_sig = ' '.join([line.strip() for line in function_sig_lines])
sig = {
'label': function_sig,
'documentation': _utils.format_docstring(s.docstring(raw=True))
}
# If there are params, add those
if s.params:
sig['parameters'] = [{
'label': p.name,
'documentation': _param_docs(s.docstring(), p.name)
} for p in s.params]
# We only return a single signature because Python doesn't allow overloading
sig_info = {'signatures': [sig], 'activeSignature': 0}
if s.index is not None and s.params:
# Then we know which parameter we're looking at
sig_info['activeParameter'] = s.index
return sig_info
def _param_docs(docstring, param_name):
for line in docstring.splitlines():
for regex in DOC_REGEX:
m = regex.match(line)
if not m:
continue
if m.group('param') != param_name:
continue
return m.group('doc') or ""