Skip to content

Commit f9183a1

Browse files
committed
correct loading and closing documents/library/resources
1 parent 6b40064 commit f9183a1

File tree

10 files changed

+114
-59
lines changed

10 files changed

+114
-59
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ All notable changes to the "robotcode" extension will be documented in this file
44

55
## [Unreleased]
66

7+
### added
8+
9+
- correct loading and closing documents/library/resources
10+
711
## 0.2.4
812

913
### added

robotcode/debugger/protocol.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,13 +378,15 @@ async def handle_response(self, message: Response) -> None:
378378

379379
try:
380380
if message.success:
381-
entry.future.set_result(try_convert_value(message.body, entry.result_type))
381+
if not entry.future.done():
382+
entry.future.set_result(try_convert_value(message.body, entry.result_type))
382383
else:
383384
raise DebugAdapterErrorResponseError(ErrorResponse(**message.dict()))
384385
except (SystemExit, KeyboardInterrupt):
385386
raise
386387
except BaseException as e:
387-
entry.future.set_exception(e)
388+
if not entry.future.done():
389+
entry.future.set_exception(e)
388390

389391
@_logger.call
390392
async def handle_event(self, message: Event) -> None:

robotcode/jsonrpc2/protocol.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -615,11 +615,13 @@ async def handle_response(self, message: JsonRPCResponse) -> None:
615615
return
616616

617617
try:
618-
entry.future.set_result(try_convert_value(message.result, entry.result_type))
618+
if not entry.future.done():
619+
entry.future.set_result(try_convert_value(message.result, entry.result_type))
619620
except (SystemExit, KeyboardInterrupt):
620621
raise
621622
except BaseException as e:
622-
entry.future.set_exception(e)
623+
if not entry.future.done():
624+
entry.future.set_exception(e)
623625

624626
@_logger.call
625627
async def handle_error(self, message: JsonRPCError) -> None:

robotcode/language_server/common/parts/documents.py

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,27 +75,72 @@ def __iter__(self) -> Iterator[DocumentUri]:
7575
def __hash__(self) -> int:
7676
return id(self)
7777

78-
def _create_document(self, text_document: TextDocumentItem) -> TextDocument:
79-
return TextDocument(text_document)
78+
def _create_document(
79+
self,
80+
text_document_item: Optional[TextDocumentItem] = None,
81+
*,
82+
document_uri: Optional[DocumentUri] = None,
83+
language_id: Optional[str] = None,
84+
version: Optional[int] = None,
85+
text: Optional[str] = None,
86+
) -> TextDocument:
87+
return TextDocument(
88+
text_document_item=text_document_item,
89+
document_uri=document_uri,
90+
language_id=language_id,
91+
version=version,
92+
text=text,
93+
)
94+
95+
def append_document(
96+
self,
97+
document_uri: DocumentUri,
98+
language_id: str,
99+
text: Optional[str],
100+
version: Optional[int] = None,
101+
) -> TextDocument:
102+
document = self._create_document(document_uri=document_uri, language_id=language_id, version=version, text=text)
103+
104+
self._documents[document_uri] = document
105+
return document
80106

81107
@rpc_method(name="textDocument/didOpen", param_type=DidOpenTextDocumentParams)
82108
@_logger.call
83109
async def _text_document_did_open(self, text_document: TextDocumentItem, *args: Any, **kwargs: Any) -> None:
84-
document = self._create_document(text_document)
110+
uri = str(Uri(text_document.uri).normalized())
111+
document = self.get(uri, None)
85112

86-
self._documents[str(Uri(text_document.uri).normalized())] = document
113+
if document is None:
114+
document = self._create_document(text_document)
87115

88-
await self.did_open(self, document)
116+
self._documents[uri] = document
117+
await self.did_open(self, document)
118+
else:
119+
await document.apply_full_change(text_document.version, text_document.text)
120+
121+
document.references.add(self)
89122

90123
@rpc_method(name="textDocument/didClose", param_type=DidCloseTextDocumentParams)
91124
@_logger.call
92125
async def _text_document_did_close(self, text_document: TextDocumentIdentifier, *args: Any, **kwargs: Any) -> None:
93-
document = self._documents.pop(str(Uri(text_document.uri).normalized()), None)
126+
uri = str(Uri(text_document.uri).normalized())
127+
document = self._documents.get(uri, None)
94128

95129
if document is not None:
130+
document.references.remove(self)
131+
132+
await self.close_document(document)
133+
134+
async def close_document(self, document: TextDocument) -> None:
135+
if len(document.references) == 0:
136+
self._documents.pop(str(document.uri), None)
137+
96138
await self.did_close(self, document)
139+
97140
await document.clear()
98141
del document
142+
else:
143+
document.version = None
99144

100145
gc.collect()
101146

robotcode/language_server/common/text_document.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def __init__(
5757
super().__init__()
5858

5959
self._lock = asyncio.Lock()
60+
self._references: weakref.WeakSet[Any] = weakref.WeakSet()
6061

6162
self.document_uri = (
6263
text_document_item.uri
@@ -86,6 +87,10 @@ def __init__(
8687

8788
self._loop = asyncio.get_event_loop()
8889

90+
@property
91+
def references(self) -> weakref.WeakSet[Any]:
92+
return self._references
93+
8994
def __del__(self) -> None:
9095
self._clear()
9196

robotcode/language_server/robotframework/diagnostics/imports_manager.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import ast
44
import asyncio
5-
import gc
65
import weakref
76
from collections import OrderedDict
87
from concurrent.futures import ProcessPoolExecutor
@@ -220,13 +219,12 @@ def __init__(
220219
self,
221220
name: str,
222221
parent: ImportsManager,
223-
get_document_coroutine: Callable[[], Coroutine[Any, Any, Tuple[TextDocument, bool]]],
222+
get_document_coroutine: Callable[[], Coroutine[Any, Any, TextDocument]],
224223
) -> None:
225224
super().__init__()
226225
self.name = name
227226
self.parent = parent
228227
self._get_document_coroutine = get_document_coroutine
229-
self._delete_on_validate_document = False
230228
self.references: weakref.WeakSet[Any] = weakref.WeakSet()
231229
self.file_watchers: List[FileWatcherEntry] = []
232230
self._document: Optional[TextDocument] = None
@@ -265,8 +263,16 @@ async def check_file_changed(self, changes: List[FileEvent]) -> Optional[FileCha
265263

266264
return None
267265

266+
def __close_document(self, document: TextDocument) -> None:
267+
asyncio.run_coroutine_threadsafe(self.parent.parent_protocol.documents.close_document(document), self._loop)
268+
268269
async def _update(self) -> None:
269-
self._document, self._delete_on_validate_document = await self._get_document_coroutine()
270+
self._document = await self._get_document_coroutine()
271+
272+
for r in self.references:
273+
self._document.references.add(r)
274+
275+
weakref.finalize(r, self.__close_document, self._document)
270276

271277
if self._document.version is None:
272278
self.file_watchers.append(
@@ -286,12 +292,6 @@ async def _invalidate(self) -> None:
286292

287293
await self._remove_file_watcher()
288294

289-
if self._delete_on_validate_document:
290-
if self._document is not None:
291-
await self._document.clear()
292-
del self._document
293-
gc.collect()
294-
295295
self._document = None
296296

297297
async def _remove_file_watcher(self) -> None:
@@ -376,7 +376,7 @@ async def resource_document_changed(self, sender: Any, document: TextDocument) -
376376
resource_changed: List[LibraryDoc] = []
377377

378378
async with self._resources_lock:
379-
for r_key, r_entry in self._resources.items():
379+
for r_entry in self._resources.values():
380380
lib_doc: Optional[LibraryDoc] = None
381381
try:
382382
if not await r_entry.is_valid():
@@ -635,7 +635,7 @@ async def find_file(self, name: str, base_dir: str, file_type: str = "Resource")
635635
async def _get_entry_for_resource_import(self, name: str, base_dir: str, sentinel: Any = None) -> _ResourcesEntry:
636636
source = await self.find_file(name, base_dir, "Resource")
637637

638-
async def _get_document() -> Tuple[TextDocument, bool]:
638+
async def _get_document() -> TextDocument:
639639
from robot.utils import FileReader
640640

641641
self._logger.debug(lambda: f"Load resource {name} from source {source}")
@@ -648,16 +648,18 @@ async def _get_document() -> Tuple[TextDocument, bool]:
648648
f"Supported extensions are {', '.join(repr(s) for s in RESOURCE_EXTENSIONS)}."
649649
)
650650

651-
source_uri = DocumentUri(Uri.from_path(source_path))
651+
source_uri = DocumentUri(Uri.from_path(source_path).normalized())
652652

653653
result = self.parent_protocol.documents.get(source_uri, None)
654654
if result is not None:
655-
return result, False
655+
return result
656656

657657
with FileReader(source_path) as reader:
658658
text = str(reader.read())
659659

660-
return TextDocument(document_uri=source_uri, language_id="robot", version=None, text=text), True
660+
return self.parent_protocol.documents.append_document(
661+
document_uri=source_uri, language_id="robotframework", text=text
662+
)
661663

662664
async with self._resources_lock:
663665
entry_key = _ResourcesEntryKey(source)

robotcode/language_server/robotframework/diagnostics/library_doc.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -408,14 +408,13 @@ def to_markdown(self, add_signature: bool = True, only_doc: bool = True) -> str:
408408
if any(v for v in self.inits.values() if v.args):
409409
result += "\n\n---\n".join(i.to_markdown() for i in self.inits.values())
410410

411-
if self.doc:
412-
if result:
413-
result += "\n\n---\n"
414-
result += (
415-
MarkDownFormatter().format(self.get_full_doc(only_doc))
416-
if self.doc_format == DEFAULT_DOC_FORMAT
417-
else self.doc
418-
)
411+
if result:
412+
result += "\n\n---\n"
413+
result += (
414+
MarkDownFormatter().format(self.get_full_doc(only_doc))
415+
if self.doc_format == DEFAULT_DOC_FORMAT
416+
else self.doc
417+
)
419418

420419
return result
421420

robotcode/language_server/robotframework/diagnostics/namespace.py

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -704,28 +704,27 @@ async def get_library_doc(self) -> LibraryDoc:
704704
async def _ensure_initialized(self) -> None:
705705
async with self._initialize_lock:
706706
if not self._initialzed:
707-
try:
708-
imports = await self.get_imports()
709-
710-
if self.document is not None:
711-
712-
old_imports = self.document.get_data(Namespace)
713-
if old_imports is None:
714-
self.document.set_data(Namespace, imports)
715-
elif old_imports != imports:
716-
new_imports = []
717-
for e in old_imports:
718-
if e in imports:
719-
new_imports.append(e)
720-
for e in imports:
721-
if e not in new_imports:
722-
new_imports.append(e)
723-
self.document.set_data(Namespace, new_imports)
724-
725-
await self._import_default_libraries()
726-
await self._import_imports(imports, str(Path(self.source).parent), top_level=True)
727-
finally:
728-
self._initialzed = True
707+
imports = await self.get_imports()
708+
709+
if self.document is not None:
710+
711+
old_imports = self.document.get_data(Namespace)
712+
if old_imports is None:
713+
self.document.set_data(Namespace, imports)
714+
elif old_imports != imports:
715+
new_imports = []
716+
for e in old_imports:
717+
if e in imports:
718+
new_imports.append(e)
719+
for e in imports:
720+
if e not in new_imports:
721+
new_imports.append(e)
722+
self.document.set_data(Namespace, new_imports)
723+
724+
await self._import_default_libraries()
725+
await self._import_imports(imports, str(Path(self.source).parent), top_level=True)
726+
727+
self._initialzed = True
729728

730729
async def get_imports(self) -> List[Import]:
731730
if self._imports is None:

robotcode/language_server/robotframework/parts/discovering.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def get_document(self, uri: DocumentUri) -> TextDocument:
6161
with FileReader(Uri(uri).to_path()) as reader:
6262
text = str(reader.read())
6363

64-
return TextDocument(document_uri=uri, language_id="robot", version=None, text=text)
64+
return TextDocument(document_uri=uri, language_id="robotframework", version=None, text=text)
6565

6666
def get_tests_from_workspace_threading(self, paths: Optional[List[str]]) -> List[TestItem]:
6767
from robot.output.logger import LOGGER

robotcode/language_server/robotframework/parts/documents_cache.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import asyncio
55
import enum
66
import io
7-
import logging
87
import weakref
98
from typing import (
109
TYPE_CHECKING,
@@ -76,8 +75,6 @@ async def get_tokens(
7675
async def __get_tokens(
7776
self, document: TextDocument, cancelation_token: Optional[CancelationToken] = None
7877
) -> List[Token]:
79-
logging.info(f"get tokens {document.uri}")
80-
8178
document_type = await self.get_document_type(document)
8279
if document_type == DocumentType.INIT:
8380
return await self.get_init_tokens(document, cancelation_token)

0 commit comments

Comments
 (0)