Skip to content

Commit 9a3bac8

Browse files
committed
implement run the current test case from active editor
1 parent 609ec26 commit 9a3bac8

File tree

7 files changed

+356
-82
lines changed

7 files changed

+356
-82
lines changed

package.json

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
"onDebugDynamicConfigurations",
3333
"onDebugResolve:robotframework",
3434
"onLanguage:robotframework",
35-
"onCommand:robotcode.runTestcase",
36-
"onCommand:robotcode.debugTestcase",
35+
"onCommand:robotcode.runTest",
36+
"onCommand:robotcode.debugTest",
3737
"onCommand:robotcode.runSuite",
3838
"onCommand:robotcode.debugSuite"
3939
],
@@ -263,6 +263,7 @@
263263
"command": "robotcode.runSuite",
264264
"category": "RobotCode",
265265
"title": "Run Suite",
266+
"enablement": "resourceLangId == robotframework && resourceExtname == .robot || explorerResourceIsFolder",
266267
"icon": {
267268
"light": "resources/light/run_suite.svg",
268269
"dark": "resources/dark/run_suite.svg"
@@ -272,6 +273,7 @@
272273
"command": "robotcode.debugSuite",
273274
"category": "RobotCode",
274275
"title": "Debug Suite",
276+
"enablement": "resourceLangId == robotframework && resourceExtname == .robot || explorerResourceIsFolder",
275277
"icon": {
276278
"light": "resources/light/debug_suite.svg",
277279
"dark": "resources/dark/debug_suite.svg"
@@ -280,7 +282,8 @@
280282
{
281283
"command": "robotcode.runTest",
282284
"category": "RobotCode",
283-
"title": "Run Test",
285+
"title": "Run Test Case",
286+
"enablement": "resourceLangId == robotframework && resourceExtname == .robot",
284287
"icon": {
285288
"light": "resources/light/run_test.svg",
286289
"dark": "resources/dark/run_test.svg"
@@ -289,7 +292,8 @@
289292
{
290293
"command": "robotcode.debugTest",
291294
"category": "RobotCode",
292-
"title": "Debug Test",
295+
"title": "Debug Test Case",
296+
"enablement": "resourceLangId == robotframework && resourceExtname == .robot",
293297
"icon": {
294298
"light": "resources/light/debug_test.svg",
295299
"dark": "resources/dark/debug_test.svg"
@@ -298,30 +302,58 @@
298302
],
299303
"menus": {
300304
"editor/title/run": [
305+
{
306+
"command": "robotcode.runTest",
307+
"group": "robotcode@1run@1",
308+
"when": "resourceLangId == robotframework && resourceExtname == .robot && robotCode.editor.inTest && !isInDiffEditor"
309+
},
310+
{
311+
"command": "robotcode.debugTest",
312+
"group": "robotcode@2debug@1",
313+
"when": "resourceLangId == robotframework && resourceExtname == .robot && robotCode.editor.inTest && !isInDiffEditor"
314+
},
315+
{
316+
"command": "robotcode.runSuite",
317+
"group": "robotcode@1run@2",
318+
"when": "resourceLangId == robotframework && resourceExtname == .robot && !isInDiffEditor"
319+
},
320+
{
321+
"command": "robotcode.debugSuite",
322+
"group": "robotcode@2debug@2",
323+
"when": "resourceLangId == robotframework && resourceExtname == .robot && !isInDiffEditor"
324+
}
325+
],
326+
"editor/context": [
327+
{
328+
"command": "robotcode.runTest",
329+
"group": "robotcode@1run@1",
330+
"when": "resourceLangId == robotframework && resourceExtname == .robot && robotCode.editor.inTest && !isInDiffEditor"
331+
},
332+
{
333+
"command": "robotcode.debugTest",
334+
"group": "robotcode@2debug@1",
335+
"when": "resourceLangId == robotframework && resourceExtname == .robot && robotCode.editor.inTest && !isInDiffEditor"
336+
},
301337
{
302338
"command": "robotcode.runSuite",
303-
"title": "Run Testsuite",
304-
"group": "robot@1",
339+
"group": "robotcode@1run@2",
305340
"when": "resourceLangId == robotframework && resourceExtname == .robot && !isInDiffEditor"
306341
},
307342
{
308343
"command": "robotcode.debugSuite",
309-
"title": "Debug Testsuite",
310-
"group": "robot@2",
344+
"group": "robotcode@2debug@2",
311345
"when": "resourceLangId == robotframework && resourceExtname == .robot && !isInDiffEditor"
312346
}
313347
],
314348
"explorer/context": [
315349
{
316350
"command": "robotcode.runSuite",
317-
"title": "Run Testsuite",
318-
"group": "robot@1",
351+
"group": "robotcode@1",
319352
"when": "resourceLangId == robotframework && resourceExtname == .robot || explorerResourceIsFolder"
320353
},
321354
{
322355
"command": "robotcode.debugSuite",
323-
"title": "Debug Testsuite",
324-
"group": "robot@2",
356+
"group": "robotcode@2",
325357
"when": "resourceLangId == robotframework && resourceExtname == .robot || explorerResourceIsFolder"
326358
}
327359
]

robotcode/debug_adapter/server.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,6 @@ async def _launch(
177177

178178
run_args += ["--"]
179179

180-
run_args += args or []
181-
182180
if robotPythonPath:
183181
for e in robotPythonPath:
184182
run_args += ["-P", e]
@@ -187,6 +185,8 @@ async def _launch(
187185
for k, v in variables.items():
188186
run_args += ["-v", f"{k}:{v}"]
189187

188+
run_args += args or []
189+
190190
if target:
191191
run_args.append(target)
192192

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
from __future__ import annotations
2+
3+
from typing import TYPE_CHECKING, List, Optional, cast
4+
5+
from ....jsonrpc2.protocol import rpc_method
6+
from ....utils.logging import LoggingDescriptor
7+
from ....utils.uri import Uri
8+
from ...common.text_document import TextDocument
9+
from ...common.types import DocumentUri, Model, Position, TextDocumentIdentifier
10+
from ..utils.ast import get_nodes_at_position
11+
from ..utils.async_ast import walk
12+
from .protocol_part import RobotLanguageServerProtocolPart
13+
14+
if TYPE_CHECKING:
15+
from ..protocol import RobotLanguageServerProtocol
16+
17+
18+
class GetTestFromPositionParams(Model):
19+
text_document: TextDocumentIdentifier
20+
position: Position
21+
22+
23+
class GetTestsParams(Model):
24+
text_document: TextDocumentIdentifier
25+
26+
27+
class Test(Model):
28+
name: str
29+
source: TextDocumentIdentifier
30+
line_no: int
31+
32+
33+
class UtilsProtocolPart(RobotLanguageServerProtocolPart):
34+
_logger = LoggingDescriptor()
35+
36+
def __init__(self, parent: RobotLanguageServerProtocol) -> None:
37+
super().__init__(parent)
38+
39+
def get_document(self, uri: DocumentUri) -> TextDocument:
40+
from robot.utils import FileReader
41+
42+
result = self.parent.documents.get(uri, None)
43+
if result is not None:
44+
return result
45+
46+
with FileReader(Uri(uri).to_path()) as reader:
47+
text = str(reader.read())
48+
49+
return TextDocument(document_uri=uri, language_id="robot", version=None, text=text)
50+
51+
@rpc_method(name="robotcode/getTestFromPosition", param_type=GetTestFromPositionParams)
52+
async def get_test_from_position(self, text_document: TextDocumentIdentifier, position: Position) -> Optional[str]:
53+
from robot.parsing.model.blocks import TestCase
54+
55+
model = await self.parent.documents_cache.get_model(self.get_document(text_document.uri))
56+
57+
test_case = next((v for v in await get_nodes_at_position(model, position) if isinstance(v, TestCase)), None)
58+
59+
return cast(TestCase, test_case).name if test_case is not None else None
60+
61+
@rpc_method(name="robotcode/getTests", param_type=GetTestsParams)
62+
async def get_tests(self, text_document: TextDocumentIdentifier) -> List[Test]:
63+
from robot.parsing.model.blocks import TestCase
64+
65+
model = await self.parent.documents_cache.get_model(self.get_document(text_document.uri))
66+
67+
test_cases = [v async for v in walk(model) if isinstance(v, TestCase)]
68+
69+
return [Test(name=v.name, source=text_document, line_no=v.lineno) for v in test_cases if v.name is not None]

robotcode/language_server/robotframework/protocol.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from .parts.hover import RobotHoverProtocolPart
2424
from .parts.robocop_diagnostics import RobotRoboCopDiagnosticsProtocolPart
2525
from .parts.signature_help import RobotSignatureHelpProtocolPart
26+
from .parts.utils import UtilsProtocolPart
2627
from .utils.version import get_robot_version
2728

2829
if TYPE_CHECKING:
@@ -58,6 +59,7 @@ class RobotLanguageServerProtocol(LanguageServerProtocol):
5859
_robot_document_symbols = ProtocolPartDescriptor(RobotDocumentSymbolsProtocolPart)
5960
_robot_robocop_diagnostics = ProtocolPartDescriptor(RobotRoboCopDiagnosticsProtocolPart)
6061
_robot_formatting = ProtocolPartDescriptor(RobotFormattingProtocolPart)
62+
_robot_utils = ProtocolPartDescriptor(UtilsProtocolPart)
6163

6264
name = "RobotCode"
6365
version = __version__

robotcode/language_server/robotframework/utils/ast.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
from __future__ import annotations
22

33
import ast
4-
from typing import Any, Iterator, List, Optional, Protocol, Tuple, runtime_checkable
4+
from typing import (
5+
Any,
6+
AsyncIterator,
7+
Iterator,
8+
List,
9+
Optional,
10+
Protocol,
11+
Tuple,
12+
runtime_checkable,
13+
)
514

615
from ...common.types import Position, Range
716
from .async_ast import walk
@@ -127,8 +136,12 @@ def get_tokens_at_position(node: Statement, position: Position) -> List[Token]:
127136
return [t for t in node.tokens if position.is_in_range(range := range_from_token(t)) or range.end == position]
128137

129138

139+
def iter_nodes_at_position(node: ast.AST, position: Position) -> AsyncIterator[ast.AST]:
140+
return (n async for n in walk(node) if position.is_in_range(range := range_from_node(n)) or range.end == position)
141+
142+
130143
async def get_nodes_at_position(node: ast.AST, position: Position) -> List[ast.AST]:
131-
return [n async for n in walk(node) if position.is_in_range(range := range_from_node(n)) or range.end == position]
144+
return [n async for n in iter_nodes_at_position(node, position)]
132145

133146

134147
async def get_node_at_position(node: ast.AST, position: Position) -> Optional[ast.AST]:

0 commit comments

Comments
 (0)