mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-12 20:15:56 +00:00
Merge pull request #1075 from oraios/fix/batch_hover_optimization
Fix: the request_info for a batch of symbols was actually never optimized
This commit is contained in:
5 files changed
+46
-42
No files matched your search
+24
-21
@@ -11,6 +11,7 @@ from sensai.util.string import ToStringMixin
|
||||
|
||||
import serena.jetbrains.jetbrains_types as jb
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls import LSPFileBuffer
|
||||
from solidlsp.ls import ReferenceInSymbol as LSPReferenceInSymbol
|
||||
from solidlsp.ls_types import Position, SymbolKind, UnifiedSymbolInformation
|
||||
|
||||
@@ -549,14 +550,14 @@ class LanguageServerSymbolRetriever:
|
||||
self._ls_manager: LanguageServerManager = ls_manager
|
||||
self.agent = agent
|
||||
|
||||
def _request_info(self, relative_file_path: str, line: int, column: int) -> str | None:
|
||||
def _request_info(self, relative_file_path: str, line: int, column: int, file_buffer: LSPFileBuffer | None = None) -> str | None:
|
||||
"""Retrieves information (in a sanitized format) about the symbol at the desired location,
|
||||
typically containing the docstring and signature.
|
||||
|
||||
Returns None if no information is available.
|
||||
"""
|
||||
lang_server = self.get_language_server(relative_file_path)
|
||||
hover_info = lang_server.request_hover(relative_file_path=relative_file_path, line=line, column=column)
|
||||
hover_info = lang_server.request_hover(relative_file_path=relative_file_path, line=line, column=column, file_buffer=file_buffer)
|
||||
if hover_info is None:
|
||||
return None
|
||||
|
||||
@@ -651,26 +652,28 @@ class LanguageServerSymbolRetriever:
|
||||
t0_file = perf_counter() if debug_enabled else 0.0
|
||||
file_hover_lookups = 0
|
||||
|
||||
for sym in file_symbols:
|
||||
# Check budget before starting a new hover request
|
||||
# symbol_info_budget_seconds=0 disables the budget mechanism (the first inequality)
|
||||
if 0 < symbol_info_budget_seconds <= hover_spent_seconds:
|
||||
skipped_due_to_budget += 1
|
||||
info = None
|
||||
# log once when budget exceeded
|
||||
if skipped_due_to_budget == 1:
|
||||
log.debug("Skipping further hover operations due to budget exceeded")
|
||||
else:
|
||||
line = sym.line
|
||||
column = sym.column
|
||||
assert line is not None and column is not None # for mypy, we filtered invalid symbols above
|
||||
t0_hover = perf_counter()
|
||||
info = self._request_info(file_path, line, column)
|
||||
hover_spent_seconds += perf_counter() - t0_hover
|
||||
file_hover_lookups += 1
|
||||
total_hover_lookups += 1
|
||||
ls = self.get_language_server(file_path)
|
||||
with ls.open_file(file_path) as file_buffer:
|
||||
for sym in file_symbols:
|
||||
# Check budget before starting a new hover request
|
||||
# symbol_info_budget_seconds=0 disables the budget mechanism (the first inequality)
|
||||
if 0 < symbol_info_budget_seconds <= hover_spent_seconds:
|
||||
skipped_due_to_budget += 1
|
||||
info = None
|
||||
# log once when budget exceeded
|
||||
if skipped_due_to_budget == 1:
|
||||
log.debug("Skipping further hover operations due to budget exceeded")
|
||||
else:
|
||||
line = sym.line
|
||||
column = sym.column
|
||||
assert line is not None and column is not None # for mypy, we filtered invalid symbols above
|
||||
t0_hover = perf_counter()
|
||||
info = self._request_info(file_path, line, column, file_buffer=file_buffer)
|
||||
hover_spent_seconds += perf_counter() - t0_hover
|
||||
file_hover_lookups += 1
|
||||
total_hover_lookups += 1
|
||||
|
||||
info_by_symbol[sym] = info
|
||||
info_by_symbol[sym] = info
|
||||
|
||||
if debug_enabled:
|
||||
file_elapsed_ms = (perf_counter() - t0_file) * 1000
|
||||
|
||||
@@ -1055,7 +1055,9 @@ class ALLanguageServer(SolidLanguageServer):
|
||||
return document_symbols
|
||||
|
||||
@override
|
||||
def request_hover(self, relative_file_path: str, line: int, column: int) -> ls_types.Hover | None:
|
||||
def request_hover(
|
||||
self, relative_file_path: str, line: int, column: int, file_buffer: LSPFileBuffer | None = None
|
||||
) -> ls_types.Hover | None:
|
||||
"""
|
||||
Override to inject original AL object name (with type and ID) into hover responses.
|
||||
|
||||
@@ -1065,7 +1067,7 @@ class ALLanguageServer(SolidLanguageServer):
|
||||
# Normalize path separators for cross-platform compatibility (backslash → forward slash)
|
||||
relative_file_path = self._normalize_path(relative_file_path)
|
||||
|
||||
hover = super().request_hover(relative_file_path, line, column)
|
||||
hover = super().request_hover(relative_file_path, line, column, file_buffer=file_buffer)
|
||||
|
||||
if hover is None:
|
||||
return None
|
||||
|
||||
@@ -15,7 +15,7 @@ from typing import Any, cast
|
||||
|
||||
from overrides import override
|
||||
|
||||
from solidlsp.ls import DocumentSymbols, LanguageServerDependencyProvider, SolidLanguageServer
|
||||
from solidlsp.ls import DocumentSymbols, LanguageServerDependencyProvider, LSPFileBuffer, SolidLanguageServer
|
||||
from solidlsp.ls_config import LanguageServerConfig
|
||||
from solidlsp.ls_exceptions import SolidLSPException
|
||||
from solidlsp.ls_types import Hover, UnifiedSymbolInformation
|
||||
@@ -206,14 +206,14 @@ class CSharpLanguageServer(SolidLanguageServer):
|
||||
return symbols
|
||||
|
||||
@override
|
||||
def request_hover(self, relative_file_path: str, line: int, column: int) -> Hover | None:
|
||||
def request_hover(self, relative_file_path: str, line: int, column: int, file_buffer: LSPFileBuffer | None = None) -> Hover | None:
|
||||
"""
|
||||
Override to inject original Roslyn symbol names (with type annotations) into hover responses.
|
||||
|
||||
When hovering over a symbol whose name was normalized, we prepend the original
|
||||
full name (e.g., 'Add(int, int) : int') to the hover content.
|
||||
"""
|
||||
hover = super().request_hover(relative_file_path, line, column)
|
||||
hover = super().request_hover(relative_file_path, line, column, file_buffer=file_buffer)
|
||||
|
||||
if hover is None:
|
||||
return None
|
||||
|
||||
@@ -849,7 +849,7 @@ class EclipseJDTLS(SolidLanguageServer):
|
||||
log.info("Startup complete")
|
||||
|
||||
@override
|
||||
def _request_hover(self, uri: str, line: int, column: int) -> ls_types.Hover | None:
|
||||
def _request_hover(self, file_buffer: LSPFileBuffer, line: int, column: int) -> ls_types.Hover | None:
|
||||
# Eclipse JDTLS lazily loads javadocs on first hover request, then caches them.
|
||||
# This means the first request often returns incomplete info (just the signature),
|
||||
# while subsequent requests return the full javadoc.
|
||||
@@ -879,12 +879,12 @@ class EclipseJDTLS(SolidLanguageServer):
|
||||
return (1, len(contents))
|
||||
|
||||
max_retries = 5
|
||||
best_result = super()._request_hover(uri, line, column)
|
||||
best_result = super()._request_hover(file_buffer, line, column)
|
||||
best_score = content_score(best_result)
|
||||
|
||||
for _ in range(max_retries):
|
||||
sleep(0.05)
|
||||
new_result = super()._request_hover(uri, line, column)
|
||||
new_result = super()._request_hover(file_buffer, line, column)
|
||||
new_score = content_score(new_result)
|
||||
if new_score > best_score:
|
||||
best_result = new_result
|
||||
|
||||
+12
-13
@@ -756,6 +756,8 @@ class SolidLanguageServer(ABC):
|
||||
be opened in the LS later by calling the `ensure_open_in_ls` method on the returned LSPFileBuffer.
|
||||
"""
|
||||
if file_buffer is not None:
|
||||
expected_uri = pathlib.Path(os.path.join(self.repository_root_path, relative_file_path)).as_uri()
|
||||
assert file_buffer.uri == expected_uri, f"Inconsistency between provided {file_buffer.uri=} and {expected_uri=}"
|
||||
if open_in_ls:
|
||||
file_buffer.ensure_open_in_ls()
|
||||
yield file_buffer
|
||||
@@ -1555,7 +1557,9 @@ class SolidLanguageServer(ABC):
|
||||
else:
|
||||
return self.request_dir_overview(within_relative_path)
|
||||
|
||||
def request_hover(self, relative_file_path: str, line: int, column: int) -> ls_types.Hover | None:
|
||||
def request_hover(
|
||||
self, relative_file_path: str, line: int, column: int, file_buffer: LSPFileBuffer | None = None
|
||||
) -> ls_types.Hover | None:
|
||||
"""
|
||||
Raise a [textDocument/hover](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_hover) request to the Language Server
|
||||
to find the hover information at the given line and column in the given file. Wait for the response and return the result.
|
||||
@@ -1563,24 +1567,19 @@ class SolidLanguageServer(ABC):
|
||||
:param relative_file_path: The relative path of the file that has the hover information
|
||||
:param line: The line number of the symbol
|
||||
:param column: The column number of the symbol
|
||||
:param file_buffer: The file buffer to use for the request. If not provided, the file will be read from disk.
|
||||
Can be used for optimizing number of file reads in downstream code
|
||||
"""
|
||||
with self.open_file(relative_file_path):
|
||||
uri = pathlib.Path(os.path.join(self.repository_root_path, relative_file_path)).as_uri()
|
||||
return self._request_hover(uri, line, column)
|
||||
with self._open_file_context(relative_file_path, file_buffer=file_buffer) as fb:
|
||||
return self._request_hover(fb, line, column)
|
||||
|
||||
def _request_hover(self, uri: str, line: int, column: int) -> ls_types.Hover | None:
|
||||
def _request_hover(self, file_buffer: LSPFileBuffer, line: int, column: int) -> ls_types.Hover | None:
|
||||
"""
|
||||
Internal method that performs the actual hover request.
|
||||
The file must already be open when calling this method.
|
||||
Subclasses can override this to customize hover behavior (e.g., retries).
|
||||
|
||||
:param uri: The URI of the file
|
||||
:param line: The line number of the symbol
|
||||
:param column: The column number of the symbol
|
||||
Performs the actual hover request.
|
||||
"""
|
||||
response = self.server.send.hover(
|
||||
{
|
||||
"textDocument": {"uri": uri},
|
||||
"textDocument": {"uri": file_buffer.uri},
|
||||
"position": {
|
||||
"line": line,
|
||||
"character": column,
|
||||
|
||||
Reference in new issue
Block a user