From 0ee482b0582d5855caadab55ea639ed660fa287f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomek=20W=C3=B3jcik?= Date: Mon, 12 Aug 2024 20:59:17 +0200 Subject: [PATCH] Allow `jedi_hover` and `jedi_signature_help` plugins to hide docstrings. Both the plugins include a signature's docstring by the default in the content they generate. Which is cool, as long as the docstring's author doesn't moonlight as a novelist. Otherwise, the content rendered in the popup will cover the entire screen. It's annoying to say the least. This changeset allows a user to hide the docstrings by adding config flags. They default to `true` so people aren't surprised by the change. I've been running this version in ST4 with no issues for a while, so I'm submitting it as a PR. --- CONFIGURATION.md | 2 ++ pylsp/_utils.py | 22 ++++++++++++++-------- pylsp/plugins/hover.py | 14 ++++++++++++-- pylsp/plugins/signature.py | 10 +++++++++- test/plugins/test_hover.py | 24 ++++++++++++++++++++++++ test/plugins/test_signature.py | 25 +++++++++++++++++++++++++ 6 files changed, 86 insertions(+), 11 deletions(-) diff --git a/CONFIGURATION.md b/CONFIGURATION.md index bb07fce9..cc2ea93a 100644 --- a/CONFIGURATION.md +++ b/CONFIGURATION.md @@ -36,8 +36,10 @@ This server can be configured using the `workspace/didChangeConfiguration` metho | `pylsp.plugins.jedi_definition.follow_builtin_imports` | `boolean` | If follow_imports is True will decide if it follow builtin imports. | `true` | | `pylsp.plugins.jedi_definition.follow_builtin_definitions` | `boolean` | Follow builtin and extension definitions to stubs. | `true` | | `pylsp.plugins.jedi_hover.enabled` | `boolean` | Enable or disable the plugin. | `true` | +| `pylsp.plugins.jedi_hover.include_docstring` | `boolean` | Include signature docstring in the output. | `true` | | `pylsp.plugins.jedi_references.enabled` | `boolean` | Enable or disable the plugin. | `true` | | `pylsp.plugins.jedi_signature_help.enabled` | `boolean` | Enable or disable the plugin. | `true` | +| `pylsp.plugins.jedi_signature_help.include_docstring` | `boolean` | Include signature docstring in the output. | `true` | | `pylsp.plugins.jedi_symbols.enabled` | `boolean` | Enable or disable the plugin. | `true` | | `pylsp.plugins.jedi_symbols.all_scopes` | `boolean` | If True lists the names of all scopes instead of only the module namespace. | `true` | | `pylsp.plugins.jedi_symbols.include_import_symbols` | `boolean` | If True includes symbols imported from other libraries. | `true` | diff --git a/pylsp/_utils.py b/pylsp/_utils.py index 1be7e263..7629e354 100644 --- a/pylsp/_utils.py +++ b/pylsp/_utils.py @@ -225,14 +225,20 @@ 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: - value = wrap_signature("\n".join(signatures)) + "\n\n" + value + 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 = wrap_signature("\n".join(signatures)) + "\n\n" + value + else: + value = contents + + if signatures: + value = wrap_signature("\n".join(signatures)) return {"kind": "markdown", "value": value} value = contents diff --git a/pylsp/plugins/hover.py b/pylsp/plugins/hover.py index ca69d1b3..01fb8633 100644 --- a/pylsp/plugins/hover.py +++ b/pylsp/plugins/hover.py @@ -10,6 +10,7 @@ @hookimpl def pylsp_hover(config, document, position): + settings = config.plugin_settings("jedi_hover", document_path=document.path) code_position = _utils.position_to_jedi_linecolumn(document, position) definitions = document.jedi_script(use_document_path=True).infer(**code_position) word = document.word_at_position(position) @@ -40,10 +41,19 @@ def pylsp_hover(config, document, position): "", ) + include_docstring = settings.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, ) diff --git a/pylsp/plugins/signature.py b/pylsp/plugins/signature.py index 7ad5b208..7cce4a76 100644 --- a/pylsp/plugins/signature.py +++ b/pylsp/plugins/signature.py @@ -17,6 +17,9 @@ @hookimpl def pylsp_signature_help(config, document, position): + settings = config.plugin_settings( + "jedi_signature_help", document_path=document.path + ) code_position = _utils.position_to_jedi_linecolumn(document, position) signatures = document.jedi_script().get_signatures(**code_position) @@ -41,10 +44,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 settings.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/plugins/test_hover.py b/test/plugins/test_hover.py index 9674b872..7e277777 100644 --- a/test/plugins/test_hover.py +++ b/test/plugins/test_hover.py @@ -3,6 +3,8 @@ import os +import pytest + from pylsp import uris from pylsp.plugins.hover import pylsp_hover from pylsp.workspace import Document @@ -23,6 +25,17 @@ def main(): """ +@pytest.fixture +def workspace_with_hover_docstring_disabled(workspace) -> None: + workspace._config._settings["plugins"] = { + "jedi_hover": { + "include_docstring": False, + }, + } + + yield workspace + + def test_numpy_hover(workspace) -> None: # Over the blank line no_hov_position = {"line": 1, "character": 0} @@ -109,3 +122,14 @@ 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_hover_docstring_disabled) -> None: + # Over 'main' in def main(): + hov_position = {"line": 2, "character": 6} + + doc = Document(DOC_URI, workspace_with_hover_docstring_disabled, DOC) + + contents = {"kind": "markdown", "value": "```python\nmain()\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..49638aed 100644 --- a/test/plugins/test_signature.py +++ b/test/plugins/test_signature.py @@ -42,6 +42,17 @@ def main(param1=None, """ +@pytest.fixture +def workspace_with_signature_docstring_disabled(workspace) -> None: + workspace._config._settings["plugins"] = { + "jedi_signature_help": { + "include_docstring": False, + }, + } + + yield workspace + + def test_no_signature(workspace) -> None: # Over blank line sig_position = {"line": 9, "character": 0} @@ -104,3 +115,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": ""}