Skip to content

Commit e6bc7a2

Browse files
committed
wip: start implementing multi language support
1 parent d2bd3db commit e6bc7a2

File tree

15 files changed

+108
-44
lines changed

15 files changed

+108
-44
lines changed

robotcode/language_server/common/decorators.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
from typing import Any, Callable, List, Protocol, TypeVar, Union, runtime_checkable
1+
from typing import Any, Callable, List, Protocol, Set, TypeVar, Union, runtime_checkable
22

33
from .text_document import TextDocument
44

55
_F = TypeVar("_F", bound=Callable[..., Any])
66

77

8-
def language_id(id: str) -> Callable[[_F], _F]:
8+
def language_id(id: str, *ids: str) -> Callable[[_F], _F]:
99
def decorator(func: _F) -> _F:
10-
setattr(func, "__language_id__", id)
10+
setattr(func, "__language_id__", {id, *ids})
1111
return func
1212

1313
return decorator
1414

1515

1616
@runtime_checkable
1717
class HasLanguageId(Protocol):
18-
__language_id__: str
18+
__language_id__: Set[str]
1919

2020

2121
def trigger_characters(characters: List[str]) -> Callable[[_F], _F]:
@@ -72,10 +72,13 @@ class HasCodeActionKinds(Protocol):
7272

7373
def language_id_filter(language_id_or_document: Union[str, TextDocument]) -> Callable[[Any], bool]:
7474
def filter(c: Any) -> bool:
75-
return not isinstance(c, HasLanguageId) or c.__language_id__ == (
76-
language_id_or_document.language_id
77-
if isinstance(language_id_or_document, TextDocument)
78-
else language_id_or_document
75+
return not isinstance(c, HasLanguageId) or (
76+
(
77+
language_id_or_document.language_id
78+
if isinstance(language_id_or_document, TextDocument)
79+
else language_id_or_document
80+
)
81+
in c.__language_id__
7982
)
8083

8184
return filter

robotcode/language_server/common/parts/documents.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import asyncio
44
import os
55
import re
6+
from pathlib import Path
67
from typing import (
78
TYPE_CHECKING,
89
Any,
@@ -119,7 +120,7 @@ async def _file_watcher(self, sender: Any, changes: List[FileEvent]) -> None:
119120
loop=self.parent.loop,
120121
)
121122

122-
async def read_document_text(self, uri: Uri, language_id: Union[str, Callable[[Any], bool]]) -> str:
123+
async def read_document_text(self, uri: Uri, language_id: Union[str, Callable[[Any], bool], None]) -> str:
123124
for e in await self.on_read_document_text(
124125
self, uri, callback_filter=language_id_filter(language_id) if isinstance(language_id, str) else language_id
125126
):
@@ -128,9 +129,18 @@ async def read_document_text(self, uri: Uri, language_id: Union[str, Callable[[A
128129

129130
raise FileNotFoundError(str(uri))
130131

132+
def detect_language_id(self, path_or_uri: Union[str, os.PathLike[Any], Uri]) -> str:
133+
path = path_or_uri.to_path() if isinstance(path_or_uri, Uri) else Path(path_or_uri)
134+
135+
for lang in self.parent.languages:
136+
if path.suffix in lang.extensions:
137+
return lang.id
138+
139+
return "unknown"
140+
131141
@_logger.call
132142
async def get_or_open_document(
133-
self, path: Union[str, os.PathLike[Any]], language_id: str, version: Optional[int] = None
143+
self, path: Union[str, os.PathLike[Any]], language_id: Optional[str] = None, version: Optional[int] = None
134144
) -> TextDocument:
135145
uri = Uri.from_path(path).normalized()
136146

@@ -141,7 +151,7 @@ async def get_or_open_document(
141151
try:
142152
return await self.parent.documents.append_document(
143153
document_uri=DocumentUri(uri),
144-
language_id=language_id,
154+
language_id=language_id or self.detect_language_id(path),
145155
text=await self.read_document_text(uri, language_id),
146156
version=version,
147157
)

robotcode/language_server/common/parts/inline_value.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ def extend_capabilities(self, capabilities: ServerCapabilities) -> None:
4646
document_filters: DocumentSelector = []
4747
for e in self.collect:
4848
if isinstance(e, HasLanguageId):
49-
document_filters.append(DocumentFilter(language=e.__language_id__))
49+
for lang_id in e.__language_id__:
50+
document_filters.append(DocumentFilter(language=lang_id))
5051
capabilities.inline_value_provider = InlineValueRegistrationOptions(
5152
work_done_progress=True, document_selector=document_filters if document_filters else None
5253
)

robotcode/language_server/common/parts/workspace.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -308,21 +308,23 @@ async def _workspace_will_delete_files(self, files: List[FileDelete], *args: Any
308308
async def _workspace_did_delete_files(self, files: List[FileDelete], *args: Any, **kwargs: Any) -> None:
309309
await self.did_delete_files(self, list(f.uri for f in files))
310310

311-
async def get_configuration(self, section: Type[_TConfig], scope_uri: Union[str, Uri, None] = None) -> _TConfig:
311+
async def get_configuration(
312+
self, section: Type[_TConfig], scope_uri: Union[str, Uri, None] = None, request: bool = True
313+
) -> _TConfig:
312314
config = await self.get_configuration_raw(
313-
section=cast(HasConfigSection, section).__config_section__, scope_uri=scope_uri
315+
section=cast(HasConfigSection, section).__config_section__, scope_uri=scope_uri, request=request
314316
)
315317

316318
return from_dict(config if config is not None else {}, section)
317319

318320
async def get_configuration_raw(
319-
self, section: Optional[str], scope_uri: Union[str, Uri, None] = None
321+
self, section: Optional[str], scope_uri: Union[str, Uri, None] = None, request: bool = True
320322
) -> Optional[Any]:
321-
322323
if (
323324
self.parent.client_capabilities
324325
and self.parent.client_capabilities.workspace
325326
and self.parent.client_capabilities.workspace.configuration
327+
and request
326328
):
327329
r = await self.parent.send_request_async(
328330
"workspace/configuration",

robotcode/language_server/robotframework/configuration.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class RobotConfig(ConfigBase):
4141
log_level: Optional[str] = None
4242
mode: Optional[RpaMode] = None
4343
languages: Optional[List[str]] = None
44+
parsers: Optional[List[str]] = None
4445

4546
def get_rpa_mode(self) -> Optional[bool]:
4647
if self.mode == RpaMode.RPA:

robotcode/language_server/robotframework/diagnostics/imports_manager.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,6 @@ def __init__(self, parent_protocol: RobotLanguageServerProtocol, folder: Uri, co
500500
self.parent_protocol = parent_protocol
501501

502502
self.folder = folder
503-
get_robot_version()
504503

505504
cache_base_path = self.folder.to_path()
506505
if (
@@ -1339,7 +1338,7 @@ async def _get_document() -> TextDocument:
13391338
f"Supported extensions are {', '.join(repr(s) for s in RESOURCE_EXTENSIONS)}."
13401339
)
13411340

1342-
return await self.parent_protocol.documents.get_or_open_document(source_path, "robotframework")
1341+
return await self.parent_protocol.documents.get_or_open_document(source_path)
13431342

13441343
entry_key = _ResourcesEntryKey(source)
13451344

robotcode/language_server/robotframework/parts/discovering.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ async def generate(suite: TestSuite) -> TestItem:
251251
config = await self.get_config(workspace_folder)
252252
rpa_mode = config.get_rpa_mode() if config is not None else None
253253
languages = await self.parent.documents_cache.get_workspace_languages(workspace_folder)
254+
parsers = config.parsers if config is not None else None
254255

255256
if paths is None and config is not None:
256257
paths = config.paths
@@ -283,7 +284,14 @@ def nonexisting_paths(paths: List[str]) -> Iterator[str]:
283284

284285
valid_paths = [i for i in normalize_paths(paths)]
285286

286-
if get_robot_version() >= (6, 0):
287+
if get_robot_version() >= (6, 1):
288+
builder = TestSuiteBuilder(
289+
included_suites=suites if suites else None,
290+
rpa=rpa_mode,
291+
lang=languages,
292+
parsers=parsers,
293+
)
294+
elif get_robot_version() >= (6, 0):
287295
builder = TestSuiteBuilder(
288296
included_suites=suites if suites else None,
289297
rpa=rpa_mode,
@@ -318,12 +326,15 @@ def nonexisting_paths(paths: List[str]) -> Iterator[str]:
318326
)
319327
]
320328
else:
321-
if get_robot_version() >= (6, 0):
329+
if get_robot_version() >= (6, 1):
322330
builder = TestSuiteBuilder(
323331
included_suites=suites if suites else None,
324332
rpa=rpa_mode,
325333
lang=languages,
334+
parsers=parsers,
326335
)
336+
elif get_robot_version() >= (6, 0):
337+
builder = TestSuiteBuilder(included_suites=suites if suites else None, rpa=rpa_mode, lang=languages)
327338
else:
328339
builder = TestSuiteBuilder(included_suites=suites if suites else None, rpa=rpa_mode)
329340
return [await generate(builder.build(str(workspace_path)))]

robotcode/language_server/robotframework/parts/documents_cache.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ async def __get_document_type(self, document: TextDocument) -> DocumentType:
131131
elif suffix == ".resource":
132132
return DocumentType.RESOURCE
133133
else:
134-
return DocumentType.GENERAL
134+
return DocumentType.UNKNOWN
135135

136136
async def get_tokens(self, document: TextDocument, data_only: bool = False) -> List[Token]:
137137
if data_only:

robotcode/language_server/robotframework/parts/hover.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,11 @@ def _find_method(self, cls: Type[Any]) -> Optional[_HoverMethod]:
6666
@_logger.call
6767
async def collect(self, sender: Any, document: TextDocument, position: Position) -> Optional[Hover]:
6868

69-
result_nodes = await get_nodes_at_position(await self.parent.documents_cache.get_model(document), position)
69+
model = await self.parent.documents_cache.get_model(document)
70+
if model is None:
71+
return None
72+
73+
result_nodes = await get_nodes_at_position(model, position)
7074

7175
if not result_nodes:
7276
return None

robotcode/language_server/robotframework/parts/references.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,12 +148,12 @@ async def _find_references_in_workspace(
148148

149149
# tasks = []
150150
for doc in self.parent.documents.documents:
151-
if doc.language_id == "robotframework":
152-
result.extend(await func(doc, *args, **kwargs))
153-
if result and stop_at_first:
154-
break
151+
# if doc.language_id == "robotframework":
152+
result.extend(await func(doc, *args, **kwargs))
153+
if result and stop_at_first:
154+
break
155155

156-
# tasks.append(run_coroutine_in_thread(func, doc, *args, **kwargs))
156+
# tasks.append(run_coroutine_in_thread(func, doc, *args, **kwargs))
157157

158158
# result = await asyncio.gather(*tasks)
159159

0 commit comments

Comments
 (0)