mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-13 10:16:00 +00:00
Merge pull request #85 from oraios/pr/84
Better fallbacks for missing keys (selectionRange etc). Download clang executable if needed
This commit is contained in:
4 files changed
+49
-16
No files matched your search
@@ -821,8 +821,10 @@ class LanguageServer:
|
||||
|
||||
def turn_item_into_symbol_with_children(item: GenericDocumentSymbol):
|
||||
item = cast(multilspy_types.UnifiedSymbolInformation, item)
|
||||
absolute_path = os.path.join(self.repository_root_path, relative_file_path)
|
||||
|
||||
# handle missing entries in location
|
||||
if "location" not in item:
|
||||
absolute_path = os.path.join(self.repository_root_path, relative_file_path)
|
||||
uri = pathlib.Path(absolute_path).as_uri()
|
||||
assert "range" in item
|
||||
tree_location = multilspy_types.Location(
|
||||
@@ -832,8 +834,19 @@ class LanguageServer:
|
||||
relativePath=relative_file_path,
|
||||
)
|
||||
item['location'] = tree_location
|
||||
location = item["location"]
|
||||
if "absolutePath" not in location:
|
||||
location["absolutePath"] = absolute_path
|
||||
if "relativePath" not in location:
|
||||
location["relativePath"] = relative_file_path
|
||||
if include_body:
|
||||
item['body'] = self.retrieve_symbol_body(item)
|
||||
# handle missing selectionRange
|
||||
if "selectionRange" not in item:
|
||||
if "range" in item:
|
||||
item["selectionRange"] = item["range"]
|
||||
else:
|
||||
item["selectionRange"] = item["location"]["range"]
|
||||
item[LSPConstants.CHILDREN] = item.get(LSPConstants.CHILDREN, [])
|
||||
|
||||
flat_all_symbol_list: List[multilspy_types.UnifiedSymbolInformation] = []
|
||||
@@ -1044,15 +1057,20 @@ class LanguageServer:
|
||||
Returns the list of tuples (name, kind, line, column) of all top-level symbols in the file.
|
||||
"""
|
||||
_, document_roots = await self.request_document_symbols(relative_file_path)
|
||||
return [
|
||||
(
|
||||
root["name"],
|
||||
root["kind"],
|
||||
root["selectionRange"]["start"]["line"], # type: ignore
|
||||
root["selectionRange"]["start"]["character"] # type: ignore
|
||||
)
|
||||
for root in document_roots
|
||||
]
|
||||
result = []
|
||||
for root in document_roots:
|
||||
try:
|
||||
result.append(
|
||||
( root["name"],
|
||||
root["kind"],
|
||||
root["selectionRange"]["start"]["line"],
|
||||
root["selectionRange"]["start"]["character"],)
|
||||
)
|
||||
except KeyError as e:
|
||||
raise KeyError(
|
||||
f"Could not process symbol of name {root.get('name', 'unknown')} in {relative_file_path=}"
|
||||
) from e
|
||||
return result
|
||||
|
||||
async def request_overview(self, within_relative_path: str) -> dict[str, list[tuple[str, multilspy_types.SymbolKind, int, int]]]:
|
||||
"""
|
||||
|
||||
@@ -64,13 +64,19 @@ class ClangdLanguageServer(LanguageServer):
|
||||
|
||||
clangd_ls_dir = os.path.join(os.path.dirname(__file__), "static/clangd")
|
||||
clangd_executable_path = os.path.join(clangd_ls_dir, "clangd_19.1.2", "bin", dependency["binaryName"])
|
||||
if not os.path.exists(clangd_ls_dir):
|
||||
os.makedirs(clangd_ls_dir)
|
||||
if not os.path.exists(clangd_executable_path):
|
||||
clangd_url = dependency["url"]
|
||||
logger.log(f"Clangd executable not found at {clangd_executable_path}. Downloading from {clangd_url}", logging.INFO)
|
||||
os.makedirs(clangd_ls_dir, exist_ok=True)
|
||||
if dependency["archiveType"] == "zip":
|
||||
FileUtils.download_and_extract_archive(
|
||||
logger, dependency["url"], clangd_ls_dir, dependency["archiveType"]
|
||||
logger, clangd_url, clangd_ls_dir, dependency["archiveType"]
|
||||
)
|
||||
assert os.path.exists(clangd_executable_path)
|
||||
if not os.path.exists(clangd_executable_path):
|
||||
raise FileNotFoundError(
|
||||
f"Clangd executable not found at {clangd_executable_path}.\n"
|
||||
"Make sure you have installed clangd. See https://clangd.llvm.org/installation"
|
||||
)
|
||||
os.chmod(clangd_executable_path, stat.S_IEXEC)
|
||||
|
||||
return clangd_executable_path
|
||||
|
||||
@@ -117,7 +117,10 @@ class FileUtils:
|
||||
"""
|
||||
Reads the file at the given path and returns the contents as a string.
|
||||
"""
|
||||
encodings = ["utf-8-sig", "utf-16"]
|
||||
if not os.path.exists(file_path):
|
||||
logger.log(f"File read '{file_path}' failed: File does not exist.", logging.ERROR)
|
||||
raise MultilspyException(f"File read '{file_path}' failed: File does not exist.")
|
||||
encodings = ["utf-8-sig", "utf-16", "utf-8", "latin-1"]
|
||||
try:
|
||||
for encoding in encodings:
|
||||
try:
|
||||
@@ -125,6 +128,9 @@ class FileUtils:
|
||||
return inp_file.read()
|
||||
except UnicodeError:
|
||||
continue
|
||||
# Try system default encoding as a last resort
|
||||
with open(file_path, "r") as inp_file:
|
||||
return inp_file.read()
|
||||
except Exception as exc:
|
||||
logger.log(f"File read '{file_path}' failed: {exc}", logging.ERROR)
|
||||
raise MultilspyException("File read failed.") from None
|
||||
|
||||
+4
-1
@@ -73,7 +73,10 @@ class ProjectConfig(ToStringMixin):
|
||||
|
||||
def __init__(self, config_dict: dict[str, Any], project_name: str, project_root: Path | None = None):
|
||||
self.project_name: str = project_name
|
||||
self.language: Language = Language(config_dict["language"])
|
||||
try:
|
||||
self.language: Language = Language(config_dict["language"].lower())
|
||||
except ValueError as e:
|
||||
raise ValueError(f"Invalid language: {config_dict['language']}.\nValid languages are: {[l.value for l in Language]}") from e
|
||||
if project_root is None:
|
||||
project_root = Path(config_dict["project_root"])
|
||||
self.project_root: str = str(project_root.resolve())
|
||||
|
||||
Reference in new issue
Block a user