diff --git a/CONFIGURATION.md b/CONFIGURATION.md index ec2a9a6c..53d3b2f1 100644 --- a/CONFIGURATION.md +++ b/CONFIGURATION.md @@ -77,6 +77,7 @@ This server can be configured using the `workspace/didChangeConfiguration` metho | `pylsp.rope.extensionModules` | `string` | Builtin and c-extension modules that are allowed to be imported and inspected by rope. | `null` | | `pylsp.rope.ropeFolder` | `array` of unique `string` items | The name of the folder in which rope stores project configurations and data. Pass `null` for not using such a folder at all. | `null` | | `pylsp.signature.formatter` | `string` (one of: `'black'`, `'ruff'`, `None`) | Formatter to use for reformatting signatures in docstrings. | `"black"` | +| `pylsp.signature.include_docstring` | `boolean` | Include signature docstring. | `true` | | `pylsp.signature.line_length` | `number` | Maximum line length in signatures. | `88` | This documentation was generated from `pylsp/config/schema.json`. Please do not edit this file directly. diff --git a/pylsp/_utils.py b/pylsp/_utils.py index dfe84b14..c9eb6fb1 100644 --- a/pylsp/_utils.py +++ b/pylsp/_utils.py @@ -315,17 +315,24 @@ def format_docstring( contents = "" if markup_kind == "markdown": - try: - value = docstring_to_markdown.convert(contents) - except docstring_to_markdown.UnknownFormatError: - # try to escape the Markdown syntax instead: - value = escape_markdown(contents) - - if signatures: - wrapped_signatures = convert_signatures_to_markdown( - signatures, config=signature_config or {} - ) - value = wrapped_signatures + "\n\n" + value + wrapped_signatures = convert_signatures_to_markdown( + signatures if signatures is not None else [], config=signature_config or {} + ) + + if contents != "": + try: + value = docstring_to_markdown.convert(contents) + except docstring_to_markdown.UnknownFormatError: + # try to escape the Markdown syntax instead: + value = escape_markdown(contents) + + if signatures: + value = wrapped_signatures + "\n\n" + value + else: + value = contents + + if signatures: + value = wrapped_signatures return {"kind": "markdown", "value": value} value = contents diff --git a/pylsp/config/schema.json b/pylsp/config/schema.json index a0caa38a..67289d96 100644 --- a/pylsp/config/schema.json +++ b/pylsp/config/schema.json @@ -530,6 +530,11 @@ "default": "black", "description": "Formatter to use for reformatting signatures in docstrings." }, + "pylsp.signature.include_docstring": { + "type": "boolean", + "default": true, + "description": "Include signature docstring." + }, "pylsp.signature.line_length": { "type": "number", "default": 88, diff --git a/pylsp/plugins/hover.py b/pylsp/plugins/hover.py index daaae90b..a700a1a5 100644 --- a/pylsp/plugins/hover.py +++ b/pylsp/plugins/hover.py @@ -41,10 +41,19 @@ def pylsp_hover(config, document, position): "", ) + include_docstring = signature_config.get("include_docstring", True) + + # raw docstring returns only doc, without signature + docstring = definition.docstring(raw=True) + if include_docstring is False: + if signature: + docstring = "" + else: + docstring = docstring.strip().split("\n")[0].strip() + return { "contents": _utils.format_docstring( - # raw docstring returns only doc, without signature - definition.docstring(raw=True), + docstring, preferred_markup_kind, signatures=[signature] if signature else None, signature_config=signature_config, diff --git a/pylsp/plugins/signature.py b/pylsp/plugins/signature.py index 7ad5b208..45500296 100644 --- a/pylsp/plugins/signature.py +++ b/pylsp/plugins/signature.py @@ -17,6 +17,7 @@ @hookimpl def pylsp_signature_help(config, document, position): + signature_config = config.settings().get("signature", {}) code_position = _utils.position_to_jedi_linecolumn(document, position) signatures = document.jedi_script().get_signatures(**code_position) @@ -41,10 +42,15 @@ def pylsp_signature_help(config, document, position): # Docstring contains one or more lines of signature, followed by empty line, followed by docstring function_sig_lines = (docstring.split("\n\n") or [""])[0].splitlines() function_sig = " ".join([line.strip() for line in function_sig_lines]) + + signature_docstring = s.docstring(raw=True) + if signature_config.get("include_docstring", True) is False: + signature_docstring = "" + sig = { "label": function_sig, "documentation": _utils.format_docstring( - s.docstring(raw=True), markup_kind=preferred_markup_kind + signature_docstring, markup_kind=preferred_markup_kind ), } diff --git a/test/fixtures.py b/test/fixtures.py index dd10140c..258781f9 100644 --- a/test/fixtures.py +++ b/test/fixtures.py @@ -177,3 +177,17 @@ def client_server_pair() -> None: ).result(timeout=CALL_TIMEOUT_IN_SECONDS) assert shutdown_response is None client_server_pair_obj.client._endpoint.notify("exit") + + +@pytest.fixture +def workspace_with_signature_docstring_disabled(workspace) -> None: + workspace._config.update( + { + "signature": { + **workspace._config.settings().get("signature", {}), + "include_docstring": False, + }, + } + ) + + yield workspace diff --git a/test/plugins/test_hover.py b/test/plugins/test_hover.py index b507acd2..4c0d75e8 100644 --- a/test/plugins/test_hover.py +++ b/test/plugins/test_hover.py @@ -143,3 +143,17 @@ def foo(): contents = pylsp_hover(doc._config, doc, cursor_pos)["contents"] assert "A docstring for foo." in contents["value"] + + +def test_hover_without_docstring(workspace_with_signature_docstring_disabled) -> None: + # Over 'main' in def main(): + hov_position = {"line": 2, "character": 6} + + doc = Document(DOC_URI, workspace_with_signature_docstring_disabled, DOC) + + contents = { + "kind": "markdown", + "value": "```python\nmain(a: float, b: float)\n```\n", + } + + assert {"contents": contents} == pylsp_hover(doc._config, doc, hov_position) diff --git a/test/plugins/test_signature.py b/test/plugins/test_signature.py index 4a0a84ef..82a90fc2 100644 --- a/test/plugins/test_signature.py +++ b/test/plugins/test_signature.py @@ -104,3 +104,17 @@ def test_docstring_params(regex, doc) -> None: m = regex.match(doc) assert m.group("param") == "test" assert m.group("doc") == "parameter docstring" + + +def test_signature_without_docstring( + workspace_with_signature_docstring_disabled, +) -> None: + # Over '( ' in main( + sig_position = {"line": 10, "character": 5} + doc = Document(DOC_URI, workspace_with_signature_docstring_disabled, DOC) + + sig_info = signature.pylsp_signature_help(doc._config, doc, sig_position) + + sigs = sig_info["signatures"] + assert len(sigs) == 1 + assert sigs[0]["documentation"] == {"kind": "markdown", "value": ""}