diff --git a/pylspclient/lsp_client.py b/pylspclient/lsp_client.py index 3528af0..a431886 100644 --- a/pylspclient/lsp_client.py +++ b/pylspclient/lsp_client.py @@ -8,13 +8,13 @@ SymbolInformation, LocationLink, Location, -) -from .lsp_pydantic_strcuts import ( Position, SignatureHelp, CompletionContext, CompletionItem, CompletionList, + WorkspaceEdit, + TextEdit, ) @@ -261,3 +261,26 @@ def definition( return [Location.model_validate(result) for result in result_dict] except ValidationError: return [LocationLink.model_validate(result) for result in result_dict] + + def rename(self, text_document: TextDocumentIdentifier, position: Position, new_name: str) -> WorkspaceEdit: + """Send a rename request to the language server at the specified position.""" + response = self.lsp_endpoint.call_method( + "textDocument/rename", + textDocument=text_document, + position=position.dict(), + newName=new_name, + ) + + # Parse response into WorkspaceEdit using Pydantic + changes = { + uri: [ + TextEdit( + range_start=Position(**edit["range"]["start"]), + range_end=Position(**edit["range"]["end"]), + new_text=edit["newText"] + ) + for edit in edits + ] + for uri, edits in response.get("changes", {}).items() + } + return WorkspaceEdit(changes=changes) diff --git a/pylspclient/lsp_endpoint.py b/pylspclient/lsp_endpoint.py index ff2f921..771673a 100644 --- a/pylspclient/lsp_endpoint.py +++ b/pylspclient/lsp_endpoint.py @@ -67,7 +67,7 @@ def run(self) -> None: # a call for notify if method not in self.notify_callbacks: # Have nothing to do with this. - print("Notify method not found: {method}.".format(method=method)) + print("Notify method not found: {method}, {params}".format(method=method, params=params)) else: self.notify_callbacks[method](params) else: diff --git a/pylspclient/lsp_pydantic_strcuts.py b/pylspclient/lsp_pydantic_strcuts.py index fe54870..f1e168b 100644 --- a/pylspclient/lsp_pydantic_strcuts.py +++ b/pylspclient/lsp_pydantic_strcuts.py @@ -1,4 +1,4 @@ -from typing import Optional, List, Union +from typing import Dict, Optional, List, Union from enum import Enum, IntEnum from pydantic import BaseModel, HttpUrl @@ -240,3 +240,11 @@ class CompletionItem(BaseModel): class CompletionList(BaseModel): isIncomplete: bool items: List[CompletionItem] + +class TextEdit(BaseModel): + range_start: Position + range_end: Position + new_text: str + +class WorkspaceEdit(BaseModel): + changes: Dict[str, List[TextEdit]] diff --git a/tests/test_pylsp_integration.py b/tests/test_pylsp_integration.py index beeb82e..a442a96 100644 --- a/tests/test_pylsp_integration.py +++ b/tests/test_pylsp_integration.py @@ -2,7 +2,6 @@ from os import path, listdir import pytest import subprocess -import threading import pylspclient from pylspclient.lsp_pydantic_strcuts import TextDocumentIdentifier, TextDocumentItem, LanguageIdentifier, Position, Range, CompletionTriggerKind, CompletionContext @@ -18,18 +17,6 @@ def from_uri(path: str) -> str: return path.replace("uri://", "").replace("uri:", "") -class ReadPipe(threading.Thread): - def __init__(self, pipe): - threading.Thread.__init__(self) - self.pipe = pipe - - def run(self): - line = self.pipe.readline().decode('utf-8') - while line: - print(line) - line = self.pipe.readline().decode('utf-8') - - @pytest.fixture def server_process() -> subprocess.Popen: pylsp_cmd = ["python", "-m", "pylsp"] @@ -188,3 +175,13 @@ def test_completion(lsp_client: pylspclient.LspClient): context = CompletionContext(triggerKind=CompletionTriggerKind.Invoked) completion_result = lsp_client.completion(TextDocumentIdentifier(uri=uri), position, context) assert all([i.insertText.startswith(to_complete) for i in completion_result.items]) + + +def test_rename(lsp_client: pylspclient.LspClient): + add_dir(lsp_client, DEFAULT_ROOT) + file_path = "lsp_client.py" + relative_file_path = path.join(DEFAULT_ROOT, file_path) + uri = to_uri(relative_file_path) + file_content = open(relative_file_path, "r").read() + position = string_in_text_to_position(file_content, "call_method") + lsp_client.rename(TextDocumentIdentifier(uri=uri), position, "call_method2")