Skip to content

Commit cba358d

Browse files
committed
simplify starting and canceling diagnostics, remove unneeded log entries, use workspace folder for discover tests
1 parent 8073972 commit cba358d

File tree

10 files changed

+167
-97
lines changed

10 files changed

+167
-97
lines changed

log.ini

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ keys: root,server,language_server,language_server_parts,jsonrpc2,jsonrpc2_messag
1010

1111
[formatters]
1212
#keys: detailed,simple,colored_simple
13-
keys: detailed,simple
13+
keys: detailed,simple,colored_detailed
1414

1515
[handlers]
16-
#keys: console, colored_console
17-
keys: console
16+
keys: console, colored_console
17+
#keys: console
1818

1919
[formatter_simple]
2020
#format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
@@ -29,7 +29,8 @@ format: %(name)s:%(levelname)s: %(message)s
2929
format: %(name)s:%(levelname)s %(threadName)s(%(thread)d) %(module)s:%(funcName)s: %(message)s (%(pathname)s:%(lineno)d)
3030

3131
[formatter_colored_detailed]
32-
format: %(name)s:%(levelname)s %(module)s:%(lineno)d: %(message)s
32+
class: coloredlogs.ColoredFormatter
33+
format: %(name)s:%(levelname)s %(threadName)s(%(thread)d) %(module)s:%(funcName)s: %(message)s (%(pathname)s:%(lineno)d)
3334

3435
[handler_console]
3536
class: StreamHandler
@@ -39,7 +40,7 @@ formatter: detailed
3940
[handler_colored_console]
4041
class: StreamHandler
4142
args: []
42-
formatter: colored_simple
43+
formatter: colored_detailed
4344

4445
[logger_root]
4546
level: INFO

poetry.lock

Lines changed: 67 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ robotframework-robocop = "^1.7.1"
5858
robotframework-tidy = "^1.5.1"
5959
PyYAML = "^6.0"
6060
types-PyYAML = "^6.0"
61+
snakeviz = "^2.1.1"
6162

6263

6364
[tool.poetry-dynamic-versioning]

robotcode/language_server/common/parts/diagnostics.py

Lines changed: 42 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
__all__ = ["DiagnosticsProtocolPart", "DiagnosticsResult"]
2828

29-
DIAGNOSTICS_DEBOUNCE = 1.5
29+
DIAGNOSTICS_DEBOUNCE = 0.75
3030

3131

3232
class PublishDiagnosticsEntry:
@@ -52,27 +52,24 @@ def __init__(
5252
self.cancel_token = cancelation_token
5353
self.done = False
5454

55-
@PublishDiagnosticsEntry._logger.call
56-
def create_task() -> None:
57-
self._future = self._factory()
55+
def _done(t: asyncio.Future[Any]) -> None:
56+
self.done = True
57+
self.done_callback(self)
5858

59-
if self._future is not None:
59+
self._future = create_sub_task(self._wait_and_run())
60+
self._future.add_done_callback(_done)
6061

61-
def _done(t: asyncio.Future[Any]) -> None:
62-
self._future = None
63-
self.done = True
64-
self.done_callback(self)
62+
async def _wait_and_run(self) -> None:
63+
await asyncio.sleep(DIAGNOSTICS_DEBOUNCE)
64+
await self._factory()
6565

66-
self._future.add_done_callback(_done)
67-
68-
self._timer_handle: asyncio.TimerHandle = asyncio.get_running_loop().call_later(
69-
DIAGNOSTICS_DEBOUNCE, create_task
70-
)
71-
72-
@_logger.call
7366
def __del__(self) -> None:
7467
if not self.done:
75-
self.cancel()
68+
try:
69+
if asyncio.get_running_loop():
70+
create_sub_task(self.cancel())
71+
except RuntimeError:
72+
pass
7673

7774
@property
7875
def future(self) -> Optional[asyncio.Future[Any]]:
@@ -85,33 +82,28 @@ def __repr__(self) -> str:
8582
return f"{type(self)}(document={repr(self.uri)}, task={repr(self.future)}, done={self.done})"
8683

8784
@_logger.call
88-
def cancel(self) -> asyncio.Future[None]:
89-
async def cancel(t: Optional[asyncio.Future[Any]]) -> None:
90-
if t is None:
91-
return
92-
93-
if not t.done() and not t.cancelled():
94-
t.cancel()
95-
try:
96-
await t
97-
except (asyncio.CancelledError, SystemExit, KeyboardInterrupt):
98-
raise
99-
100-
except BaseException as ex:
101-
self._logger.exception(ex)
102-
raise
85+
async def cancel(self) -> None:
86+
if self.future is None:
87+
return
10388

10489
if not self.done:
105-
self._timer_handle.cancel()
106-
10790
self.cancel_token.cancel()
10891

10992
self.done = True
11093

111-
try:
112-
return create_sub_task(cancel(self.future))
113-
finally:
114-
self._future = None
94+
if not self.future.done() and not self.future.cancelled():
95+
self.future.cancel()
96+
try:
97+
await self.future
98+
except (asyncio.CancelledError):
99+
pass
100+
except (SystemExit, KeyboardInterrupt):
101+
raise
102+
except BaseException as ex:
103+
self._logger.exception(ex)
104+
raise
105+
finally:
106+
self._future = None
115107

116108

117109
@dataclass
@@ -174,21 +166,30 @@ async def _cancel_entry(self, entry: Optional[PublishDiagnosticsEntry]) -> None:
174166
@language_id("robotframework")
175167
@_logger.call
176168
async def on_did_open(self, sender: Any, document: TextDocument) -> None:
177-
await self.start_publish_diagnostics_task(document)
169+
create_sub_task(self.start_publish_diagnostics_task(document))
178170

179171
@language_id("robotframework")
180172
@_logger.call
181173
async def on_did_save(self, sender: Any, document: TextDocument) -> None:
182-
await self.start_publish_diagnostics_task(document)
174+
create_sub_task(self.start_publish_diagnostics_task(document))
183175

184176
@language_id("robotframework")
185177
@_logger.call
186178
async def on_did_close(self, sender: Any, document: TextDocument) -> None:
187179
await self._cancel_entry(self._running_diagnostics.get(document.uri, None))
188180

181+
self.parent.send_notification(
182+
"textDocument/publishDiagnostics",
183+
PublishDiagnosticsParams(
184+
uri=document.document_uri,
185+
version=document._version,
186+
diagnostics=[],
187+
),
188+
)
189+
189190
@_logger.call
190191
async def on_did_change(self, sender: Any, document: TextDocument) -> None:
191-
await self.start_publish_diagnostics_task(document)
192+
create_sub_task(self.start_publish_diagnostics_task(document))
192193

193194
@_logger.call
194195
def _delete_entry(self, e: PublishDiagnosticsEntry) -> None:

robotcode/language_server/common/parts/workspace.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import asyncio
34
import uuid
45
import weakref
56
from dataclasses import dataclass
@@ -418,7 +419,8 @@ async def add_file_watchers(
418419

419420
def remove() -> None:
420421
try:
421-
create_sub_task(self.remove_file_watcher_entry(entry))
422+
if asyncio.get_running_loop():
423+
create_sub_task(self.remove_file_watcher_entry(entry))
422424
except RuntimeError:
423425
pass
424426

robotcode/language_server/robotframework/parts/diagnostics.py

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,19 @@ def __init__(self, parent: RobotLanguageServerProtocol) -> None:
4141
async def namespace_invalidated(self, sender: Any, document: TextDocument) -> None:
4242
await self.parent.diagnostics.start_publish_diagnostics_task(document)
4343

44+
@language_id("robotframework")
45+
async def collect_namespace_diagnostics(
46+
self, sender: Any, document: TextDocument, cancelation_token: CancelationToken
47+
) -> DiagnosticsResult:
48+
async def run() -> List[Diagnostic]:
49+
namespace = await self.parent.documents_cache.get_namespace(document)
50+
if namespace is None:
51+
return DiagnosticsResult(self.collect_namespace_diagnostics, None)
52+
53+
return await namespace.get_diagnostisc(cancelation_token)
54+
55+
return DiagnosticsResult(self.collect_namespace_diagnostics, await run_coroutine_in_thread(run))
56+
4457
def _create_error_from_node(self, node: ast.AST, msg: str, source: Optional[str] = None) -> Diagnostic:
4558
return Diagnostic(
4659
range=Range(
@@ -67,7 +80,7 @@ def _create_error_from_token(self, token: Token, source: Optional[str] = None) -
6780
async def collect_token_errors(
6881
self, sender: Any, document: TextDocument, cancelation_token: CancelationToken
6982
) -> DiagnosticsResult:
70-
async def collect_async() -> List[Diagnostic]:
83+
async def run() -> List[Diagnostic]:
7184
from robot.errors import VariableError
7285
from robot.parsing.lexer.tokens import Token
7386

@@ -81,6 +94,7 @@ async def collect_async() -> List[Diagnostic]:
8194

8295
try:
8396
for variable_token in token.tokenize_variables():
97+
await check_canceled()
8498
if variable_token == token:
8599
break
86100

@@ -121,14 +135,14 @@ async def collect_async() -> List[Diagnostic]:
121135

122136
return result
123137

124-
return DiagnosticsResult(self.collect_token_errors, await run_coroutine_in_thread(collect_async))
138+
return DiagnosticsResult(self.collect_token_errors, await run_coroutine_in_thread(run))
125139

126140
@language_id("robotframework")
127141
@_logger.call(entering=True, exiting=True, exception=True)
128142
async def collect_walk_model_errors(
129143
self, sender: Any, document: TextDocument, cancelation_token: CancelationToken
130144
) -> DiagnosticsResult:
131-
async def collect_async() -> List[Diagnostic]:
145+
async def run() -> List[Diagnostic]:
132146
from ..utils.ast import HasError, HasErrors
133147
from ..utils.async_ast import iter_nodes
134148

@@ -149,26 +163,5 @@ async def collect_async() -> List[Diagnostic]:
149163

150164
return DiagnosticsResult(
151165
self.collect_walk_model_errors,
152-
await run_coroutine_in_thread(collect_async),
166+
await run_coroutine_in_thread(run),
153167
)
154-
155-
@language_id("robotframework")
156-
async def collect_namespace_diagnostics(
157-
self, sender: Any, document: TextDocument, cancelation_token: CancelationToken
158-
) -> DiagnosticsResult:
159-
async def collect_async() -> List[Diagnostic]:
160-
self._logger.debug(f"start collect_namespace_diagnostics for {document}")
161-
try:
162-
namespace = await self.parent.documents_cache.get_namespace(document)
163-
if namespace is None:
164-
return DiagnosticsResult(self.collect_namespace_diagnostics, None)
165-
166-
return await namespace.get_diagnostisc(cancelation_token)
167-
except BaseException as e:
168-
self._logger.debug(f"exception in collect_namespace_diagnostics {type(e)}: {e}")
169-
raise
170-
finally:
171-
self._logger.debug("end collect_namespace_diagnostics")
172-
173-
r = await run_coroutine_in_thread(collect_async)
174-
return DiagnosticsResult(self.collect_namespace_diagnostics, r)

0 commit comments

Comments
 (0)