mirror of
https://github.com/tiennm99/serena.git
synced 2026-08-10 18:23:19 +00:00
Merge branch 'main' into feature/web-server-logs
This commit is contained in:
+20
-36
@@ -17,11 +17,10 @@ if TYPE_CHECKING:
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass(eq=False)
|
||||
@dataclass
|
||||
class SymbolLocation:
|
||||
"""
|
||||
Represents the location of a symbol, including the line where the identifier
|
||||
is defined and the end line of the symbol's body
|
||||
Represents the (start) location of a symbol identifier, which, within Serena, uniquely identifies the symbol.
|
||||
"""
|
||||
|
||||
relative_path: str | None
|
||||
@@ -38,16 +37,6 @@ class SymbolLocation:
|
||||
the column number in which the symbol identifier is defined (if the symbol is a function, class, etc.);
|
||||
may be None for some types of symbols (e.g. SymbolKind.File)
|
||||
"""
|
||||
end_line: int | None = None
|
||||
"""
|
||||
the line in which the symbol's body ends. For methods that search based on SymbolLocation,
|
||||
the end line is not needed, as it is unused by the language server in the search.
|
||||
However, the end_line will typically be included in the results of search methods,
|
||||
and thus be provided to the user in the response to such requests.
|
||||
This is useful for the LLMs, especially the less intelligent ones, as they often fail
|
||||
to perform symbolic operations and when falling back to line-editing tools, will just make up
|
||||
an end line.
|
||||
"""
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.relative_path is not None:
|
||||
@@ -59,17 +48,6 @@ class SymbolLocation:
|
||||
def has_position_in_file(self) -> bool:
|
||||
return self.relative_path is not None and self.line is not None and self.column is not None
|
||||
|
||||
def matches_identifier_location(self, other: Self) -> bool:
|
||||
"""
|
||||
Checks if this instance matches a symbol identifier location.
|
||||
Since symbol identifiers are only concerned with the start position,
|
||||
the end_line is not taken into account.
|
||||
"""
|
||||
if self.relative_path is None:
|
||||
# not defined locations don't match anything
|
||||
return False
|
||||
return self.relative_path == other.relative_path and self.line == other.line and self.column == other.column
|
||||
|
||||
|
||||
class Symbol(ToStringMixin):
|
||||
_NAME_PATH_SEP = "/"
|
||||
@@ -140,7 +118,10 @@ class Symbol(ToStringMixin):
|
||||
|
||||
@property
|
||||
def location(self) -> SymbolLocation:
|
||||
return SymbolLocation(relative_path=self.relative_path, line=self.line, column=self.column, end_line=self.end_line)
|
||||
"""
|
||||
:return: the start location of the actual symbol identifier
|
||||
"""
|
||||
return SymbolLocation(relative_path=self.relative_path, line=self.line, column=self.column)
|
||||
|
||||
@property
|
||||
def body_start_position(self) -> Position | None:
|
||||
@@ -164,23 +145,24 @@ class Symbol(ToStringMixin):
|
||||
return end_pos
|
||||
return None
|
||||
|
||||
def get_body_line_numbers(self) -> tuple[int | None, int | None]:
|
||||
start_pos = self.body_start_position
|
||||
end_pos = self.body_end_position
|
||||
start_line = start_pos["line"] if start_pos else None
|
||||
end_line = end_pos["line"] if end_pos else None
|
||||
return start_line, end_line
|
||||
|
||||
@property
|
||||
def line(self) -> int | None:
|
||||
"""The line in which the symbol identifier is defined (start line)."""
|
||||
"""
|
||||
:return: the line in which the symbol identifier is defined.
|
||||
"""
|
||||
if "selectionRange" in self.symbol_root:
|
||||
return self.symbol_root["selectionRange"]["start"]["line"]
|
||||
else:
|
||||
# line is expected to be undefined for some types of symbols (e.g. SymbolKind.File)
|
||||
return None
|
||||
|
||||
@property
|
||||
def end_line(self) -> int | None:
|
||||
"""The end line of the symbol body, also contained in the `body_end_position`."""
|
||||
body_end_position = self.body_end_position
|
||||
if body_end_position is not None:
|
||||
return body_end_position["line"]
|
||||
return None
|
||||
|
||||
@property
|
||||
def column(self) -> int | None:
|
||||
if "selectionRange" in self.symbol_root:
|
||||
@@ -293,7 +275,7 @@ class Symbol(ToStringMixin):
|
||||
self, kind: bool = False, location: bool = False, depth: int = 0, include_body: bool = False, include_children_body: bool = False
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
Convert the symbol to a dictionary.
|
||||
Converts the symbol to a dictionary.
|
||||
|
||||
:param kind: whether to include the kind of the symbol
|
||||
:param location: whether to include the location of the symbol
|
||||
@@ -312,6 +294,8 @@ class Symbol(ToStringMixin):
|
||||
|
||||
if location:
|
||||
result["location"] = self.location.to_dict()
|
||||
body_start_line, body_end_line = self.get_body_line_numbers()
|
||||
result["body_location"] = {"start_line": body_start_line, "end_line": body_end_line}
|
||||
|
||||
if include_body:
|
||||
if self.body is None:
|
||||
@@ -379,7 +363,7 @@ class SymbolManager:
|
||||
symbol_dicts, roots = self.lang_server.request_document_symbols(location.relative_path, include_body=False)
|
||||
for symbol_dict in symbol_dicts:
|
||||
symbol = Symbol(symbol_dict)
|
||||
if symbol.location.matches_identifier_location(location):
|
||||
if symbol.location == location:
|
||||
return symbol
|
||||
return None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user