Merge pull request #490 from oraios/improve_waiting_for_cross_file_references

Improve waiting logic for cross-file references to be ready
This commit is contained in:
Michael Panchenko authored and GitHub committed 2025-08-15 13:29:16 +02:00
commit 5884e67d3b
5 files changed
+30 -24

No files matched your search

@@ -13,7 +13,6 @@ import threading
import urllib.request
import zipfile
from pathlib import Path
from time import sleep
from typing import cast
from overrides import override
@@ -22,7 +21,6 @@ from solidlsp.ls import SolidLanguageServer
from solidlsp.ls_config import LanguageServerConfig
from solidlsp.ls_exceptions import SolidLSPException
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.ls_types import Location
from solidlsp.ls_utils import PathUtils
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
@@ -739,8 +737,5 @@ class CSharpLanguageServer(SolidLanguageServer):
self.logger.log(f"Opened project files: {project_files}", logging.DEBUG)
@override
def request_references(self, relative_file_path: str, line: int, column: int) -> list[Location]:
# Like in the typescript LS, we need to wait here for the language server to
# get correct results that include cross-file references.
sleep(2)
return super().request_references(relative_file_path, line, column)
def _get_wait_time_for_cross_file_referencing(self) -> float:
return 1
@@ -7,7 +7,6 @@ import os
import pathlib
import shutil
import threading
from time import sleep
from overrides import override
from sensai.util.logging import LogTime
@@ -250,12 +249,5 @@ class TypeScriptLanguageServer(SolidLanguageServer):
self.completions_available.set()
@override
# For some reason, the LS may need longer to process this, so we just retry
def _send_references_request(self, relative_file_path: str, line: int, column: int):
# TODO: The LS doesn't return references contained in other files if it doesn't sleep. This is
# despite the LS having processed requests already. I don't know what causes this, but sleeping
# one second helps. It may be that sleeping only once is enough but that's hard to reliably test.
# It may be that even this 1sec is not enough in larger TS projects, at some point we should find what
# causes this and solve it.
sleep(1)
return super()._send_references_request(relative_file_path, line, column)
def _get_wait_time_for_cross_file_referencing(self) -> float:
return 1
@@ -9,7 +9,6 @@ import os
import pathlib
import shutil
import threading
from time import sleep
from overrides import override
@@ -231,8 +230,6 @@ class VtsLanguageServer(SolidLanguageServer):
self.server_ready.set()
self.completions_available.set()
# VTS may need longer to process references, so we include a sleep similar to TypeScript LS
@override
def _send_references_request(self, relative_file_path: str, line: int, column: int):
sleep(1)
return super()._send_references_request(relative_file_path, line, column)
def _get_wait_time_for_cross_file_referencing(self) -> float:
return 1
+17
View File
@@ -14,6 +14,7 @@ from collections.abc import Iterator
from contextlib import contextmanager
from copy import copy
from pathlib import Path, PurePath
from time import sleep
from typing import Self, Union, cast
import pathspec
@@ -323,6 +324,16 @@ class SolidLanguageServer(ABC):
self._server_context = None
self._request_timeout: float | None = None
self._has_waited_for_cross_file_references = False
def _get_wait_time_for_cross_file_referencing(self) -> float:
"""Meant to be overridden by subclasses for LS that don't have a reliable "finished initializing" signal.
LS may return incomplete results on calls to `request_references` (only references found in the same file),
if the LS is not fully initialized yet.
"""
return 0
def set_request_timeout(self, timeout: float | None) -> None:
"""
:param timeout: the timeout, in seconds, for requests to the language server.
@@ -699,6 +710,12 @@ class SolidLanguageServer(ABC):
)
raise SolidLSPException("Language Server not started")
if not self._has_waited_for_cross_file_references:
# Some LS require waiting for a while before they can return cross-file references.
# This is a workaround for such LS that don't have a reliable "finished initializing" signal.
sleep(self._get_wait_time_for_cross_file_referencing())
self._has_waited_for_cross_file_references = True
with self.open_file(relative_file_path):
try:
response = self._send_references_request(relative_file_path, line=line, column=column)
+7 -2
View File
@@ -1,6 +1,7 @@
import os
import tempfile
from pathlib import Path
from typing import cast
from unittest.mock import Mock, patch
import pytest
@@ -110,16 +111,20 @@ class TestCSharpLanguageServer:
refs = language_server.request_references(file_path, sel_start["line"], sel_start["character"] + 1)
# Should find references in both Program.cs and Models/Person.cs
ref_files = [ref.get("relativePath", "") for ref in refs]
ref_files = cast(list[str], [ref.get("relativePath", "") for ref in refs])
print(f"Found references: {refs}")
print(f"Reference files: {ref_files}")
# Check that we have references from both files
assert any("Program.cs" in ref_file for ref_file in ref_files), "Should find reference in Program.cs"
assert any(
"Models/Person.cs" in ref_file for ref_file in ref_files
os.path.join("Models", "Person.cs") in ref_file for ref_file in ref_files
), "Should find reference in Models/Person.cs where Calculator.Subtract is called"
# check for a second time, since the first call may trigger initialization and change the state of the LS
refs_second_call = language_server.request_references(file_path, sel_start["line"], sel_start["character"] + 1)
assert refs_second_call == refs, "Second call to request_references should return the same results"
@pytest.mark.csharp
class TestCSharpSolutionProjectOpening: