Skip to content
This repository was archived by the owner on Jan 24, 2025. It is now read-only.

Commit 7347737

Browse files
authored
Add support for notebook document completions (python-lsp#486)
1 parent 14369f8 commit 7347737

File tree

2 files changed

+72
-0
lines changed

2 files changed

+72
-0
lines changed

pylsp/python_lsp.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,36 @@ def m_text_document__code_action(
687687
def m_text_document__code_lens(self, textDocument=None, **_kwargs):
688688
return self.code_lens(textDocument["uri"])
689689

690+
def _cell_document__completion(self, cellDocument, position=None, **_kwargs):
691+
workspace = self._match_uri_to_workspace(cellDocument.notebook_uri)
692+
notebookDocument = workspace.get_maybe_document(cellDocument.notebook_uri)
693+
if notebookDocument is None:
694+
raise ValueError("Invalid notebook document")
695+
696+
cell_data = notebookDocument.cell_data()
697+
698+
# Concatenate all cells to be a single temporary document
699+
total_source = "\n".join(data["source"] for data in cell_data.values())
700+
with workspace.temp_document(total_source) as temp_uri:
701+
# update position to be the position in the temp document
702+
if position is not None:
703+
position["line"] += cell_data[cellDocument.uri]["line_start"]
704+
705+
completions = self.completions(temp_uri, position)
706+
707+
# Translate temp_uri locations to cell document locations
708+
for item in completions.get("items", []):
709+
if item.get("data", {}).get("doc_uri") == temp_uri:
710+
item["data"]["doc_uri"] = cellDocument.uri
711+
712+
return completions
713+
690714
def m_text_document__completion(self, textDocument=None, position=None, **_kwargs):
715+
# textDocument here is just a dict with a uri
716+
workspace = self._match_uri_to_workspace(textDocument["uri"])
717+
document = workspace.get_document(textDocument["uri"])
718+
if isinstance(document, Cell):
719+
return self._cell_document__completion(document, position, **_kwargs)
691720
return self.completions(textDocument["uri"], position)
692721

693722
def _cell_document__definition(self, cellDocument, position=None, **_kwargs):

test/test_notebook_document.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,3 +488,46 @@ def test_notebook_definition(client_server_pair):
488488
},
489489
}
490490
]
491+
492+
493+
@pytest.mark.skipif(IS_WIN, reason="Flaky on Windows")
494+
def test_notebook_completion(client_server_pair):
495+
"""
496+
Tests that completions work across cell boundaries for notebook document support
497+
"""
498+
client, server = client_server_pair
499+
send_initialize_request(client)
500+
501+
# Open notebook
502+
with patch.object(server._endpoint, "notify") as mock_notify:
503+
send_notebook_did_open(
504+
client, ["answer_to_life_universe_everything = 42", "answer_"]
505+
)
506+
# wait for expected diagnostics messages
507+
wait_for_condition(lambda: mock_notify.call_count >= 2)
508+
assert len(server.workspace.documents) == 3
509+
for uri in ["cell_1_uri", "cell_2_uri", "notebook_uri"]:
510+
assert uri in server.workspace.documents
511+
512+
future = client._endpoint.request(
513+
"textDocument/completion",
514+
{
515+
"textDocument": {
516+
"uri": "cell_2_uri",
517+
},
518+
"position": {"line": 0, "character": 7},
519+
},
520+
)
521+
result = future.result(CALL_TIMEOUT_IN_SECONDS)
522+
assert result == {
523+
"isIncomplete": False,
524+
"items": [
525+
{
526+
"data": {"doc_uri": "cell_2_uri"},
527+
"insertText": "answer_to_life_universe_everything",
528+
"kind": 6,
529+
"label": "answer_to_life_universe_everything",
530+
"sortText": "aanswer_to_life_universe_everything",
531+
},
532+
],
533+
}

0 commit comments

Comments
 (0)