Skip to content

Commit b9a3f10

Browse files
committed
refactor: move code_actions and support unions with enums and string in dataclasses
1 parent 1602b71 commit b9a3f10

File tree

7 files changed

+49
-35
lines changed

7 files changed

+49
-35
lines changed

packages/core/src/robotcode/core/dataclasses.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,11 @@ def from_dict(
228228

229229
continue
230230

231+
if inspect.isclass(origin or t) and issubclass(origin or t, enum.Enum):
232+
for v in cast(Iterable[Any], t):
233+
if v.value == value:
234+
return cast(_T, v)
235+
231236
if (
232237
t is Any
233238
or t is Ellipsis # type: ignore

packages/debugger/src/robotcode/debugger/debugger.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,7 +1406,7 @@ def evaluate(
14061406
return EvaluateResult(result="")
14071407

14081408
if (
1409-
(context == EvaluateArgumentContext.REPL or context == EvaluateArgumentContext.REPL.value)
1409+
(context == EvaluateArgumentContext.REPL)
14101410
and expression.startswith("#")
14111411
and expression[1:].strip() == "exprmode"
14121412
):
@@ -1436,7 +1436,6 @@ def evaluate(
14361436
if (
14371437
isinstance(context, EvaluateArgumentContext)
14381438
and context != EvaluateArgumentContext.REPL
1439-
or context != EvaluateArgumentContext.REPL.value
14401439
or self.expression_mode
14411440
):
14421441
if expression.startswith("! "):

packages/language_server/src/robotcode/language_server/common/decorators.py

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

3+
from robotcode.core.lsp.types import CodeActionKind
4+
35
from .text_document import TextDocument
46

57
_F = TypeVar("_F", bound=Callable[..., Any])
@@ -66,9 +68,9 @@ class HasAllCommitCharacters(Protocol):
6668
CODE_ACTION_KINDS_ATTR = "__code_action_kinds__"
6769

6870

69-
def code_action_kinds(characters: List[str]) -> Callable[[_F], _F]:
71+
def code_action_kinds(kinds: List[Union[CodeActionKind, str]]) -> Callable[[_F], _F]:
7072
def decorator(func: _F) -> _F:
71-
setattr(func, CODE_ACTION_KINDS_ATTR, characters)
73+
setattr(func, CODE_ACTION_KINDS_ATTR, kinds)
7274
return func
7375

7476
return decorator
@@ -93,23 +95,23 @@ def filter(c: Any) -> bool:
9395
return filter
9496

9597

96-
COMMAND_NAME_ATTR = "__command_name__"
98+
COMMAND_ID_ATTR = "__command_name__"
9799

98100

99-
def command(name: str) -> Callable[[_F], _F]:
101+
def command(id: str) -> Callable[[_F], _F]:
100102
def decorator(func: _F) -> _F:
101-
setattr(func, COMMAND_NAME_ATTR, name)
103+
setattr(func, COMMAND_ID_ATTR, id)
102104
return func
103105

104106
return decorator
105107

106108

107109
def is_command(func: Callable[..., Any]) -> bool:
108-
return hasattr(func, COMMAND_NAME_ATTR)
110+
return hasattr(func, COMMAND_ID_ATTR)
109111

110112

111-
def get_command_name(func: Callable[..., Any]) -> str:
112-
if hasattr(func, COMMAND_NAME_ATTR):
113-
return str(getattr(func, COMMAND_NAME_ATTR))
113+
def get_command_id(func: Callable[..., Any]) -> str:
114+
if hasattr(func, COMMAND_ID_ATTR):
115+
return str(getattr(func, COMMAND_ID_ATTR))
114116

115117
raise TypeError(f"{func} is not a command.")

packages/language_server/src/robotcode/language_server/common/parts/commands.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
ServerCapabilities,
1818
)
1919
from robotcode.jsonrpc2.protocol import JsonRPCErrorException, rpc_method
20-
from robotcode.language_server.common.decorators import get_command_name, is_command
20+
from robotcode.language_server.common.decorators import get_command_id, is_command
2121
from robotcode.language_server.common.has_extend_capabilities import HasExtendCapabilities
2222
from robotcode.language_server.common.parts.protocol_part import LanguageServerProtocolPart
2323

@@ -44,7 +44,7 @@ def __init__(self, parent: LanguageServerProtocol) -> None:
4444
self.commands: Dict[str, CommandEntry] = {}
4545

4646
def register(self, callback: _FUNC_TYPE, name: Optional[str] = None) -> str:
47-
name = name or get_command_name(callback)
47+
name = name or get_command_id(callback)
4848

4949
command = f"{self.PREFIX}.{name}"
5050

@@ -64,7 +64,7 @@ def register_all(self, instance: object) -> None:
6464
self.register(cast(_FUNC_TYPE, method))
6565

6666
def get_command_name(self, callback: _FUNC_TYPE, name: Optional[str] = None) -> str:
67-
name = name or get_command_name(callback)
67+
name = name or get_command_id(callback)
6868

6969
return f"{self.PREFIX}.{name}"
7070

packages/language_server/src/robotcode/language_server/robotframework/parts/code_action_fixes.py renamed to packages/language_server/src/robotcode/language_server/robotframework/parts/code_action_quick_fixes.py

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@
2020
TextDocumentEdit,
2121
WorkspaceEdit,
2222
)
23+
from robotcode.core.utils.inspect import iter_methods
2324
from robotcode.language_server.common.decorators import code_action_kinds, command, language_id
2425
from robotcode.language_server.common.text_document import TextDocument
2526
from robotcode.language_server.robotframework.utils.ast_utils import Token, get_node_at_position, range_from_node
26-
from robotcode.language_server.robotframework.utils.async_ast import AsyncVisitor
27+
from robotcode.language_server.robotframework.utils.async_ast import Visitor
2728

2829
from .model_helper import ModelHelperMixin
2930
from .protocol_part import RobotLanguageServerProtocolPart
@@ -32,9 +33,6 @@
3233
from robotcode.language_server.robotframework.protocol import RobotLanguageServerProtocol # pragma: no cover
3334

3435

35-
CODEACTIONKIND_QUICKFIX_CREATEKEYWORD = f"{CodeActionKind.QUICK_FIX.value}.createKeyword"
36-
37-
3836
KEYWORD_WITH_ARGS_TEMPLATE = Template(
3937
"""\
4038
${name}
@@ -55,17 +53,17 @@
5553
)
5654

5755

58-
class FindKeywordSectionVisitor(AsyncVisitor):
56+
class FindKeywordSectionVisitor(Visitor):
5957
def __init__(self) -> None:
6058
self.keyword_sections: List[ast.AST] = []
6159

62-
async def visit_KeywordSection(self, node: ast.AST) -> None: # noqa: N802
60+
def visit_KeywordSection(self, node: ast.AST) -> None: # noqa: N802
6361
self.keyword_sections.append(node)
6462

6563

66-
async def find_keyword_sections(node: ast.AST) -> Optional[List[ast.AST]]:
64+
def find_keyword_sections(node: ast.AST) -> Optional[List[ast.AST]]:
6765
visitor = FindKeywordSectionVisitor()
68-
await visitor.visit(node)
66+
visitor.visit(node)
6967
return visitor.keyword_sections if visitor.keyword_sections else None
7068

7169

@@ -80,14 +78,23 @@ def __init__(self, parent: RobotLanguageServerProtocol) -> None:
8078
self.parent.commands.register_all(self)
8179

8280
@language_id("robotframework")
83-
@code_action_kinds(
84-
[
85-
CODEACTIONKIND_QUICKFIX_CREATEKEYWORD,
86-
]
87-
)
88-
@_logger.call
81+
@code_action_kinds([CodeActionKind.QUICK_FIX])
8982
async def collect(
9083
self, sender: Any, document: TextDocument, range: Range, context: CodeActionContext
84+
) -> Optional[List[Union[Command, CodeAction]]]:
85+
result = []
86+
for method in iter_methods(self, lambda m: m.__name__.startswith("code_action_")):
87+
code_actions = await method(self, document, range, context)
88+
if code_actions:
89+
result.extend(code_actions)
90+
91+
if result:
92+
return result
93+
94+
return None
95+
96+
async def code_action_create_keyword(
97+
self, sender: Any, document: TextDocument, range: Range, context: CodeActionContext
9198
) -> Optional[List[Union[Command, CodeAction]]]:
9299
kw_not_found_in_diagnostics = next((d for d in context.diagnostics if d.code == "KeywordNotFoundError"), None)
93100

@@ -98,11 +105,11 @@ async def collect(
98105
return [
99106
CodeAction(
100107
"Create Keyword",
101-
kind=CodeActionKind.QUICK_FIX.value + ".createKeyword",
108+
kind=CodeActionKind.QUICK_FIX,
102109
command=Command(
103-
"Create Keyword",
104-
self.parent.commands.get_command_name(self.create_keyword),
105-
[document.document_uri, range, context],
110+
self.parent.commands.get_command_name(self.create_keyword_command),
111+
self.parent.commands.get_command_name(self.create_keyword_command),
112+
[document.document_uri, range],
106113
),
107114
diagnostics=[kw_not_found_in_diagnostics],
108115
)
@@ -111,7 +118,7 @@ async def collect(
111118
return None
112119

113120
@command("robotcode.createKeyword")
114-
async def create_keyword(self, document_uri: DocumentUri, range: Range, context: CodeActionContext) -> None:
121+
async def create_keyword_command(self, document_uri: DocumentUri, range: Range) -> None:
115122
from robot.parsing.lexer import Token as RobotToken
116123
from robot.parsing.model.statements import (
117124
Fixture,
@@ -162,7 +169,7 @@ async def create_keyword(self, document_uri: DocumentUri, range: Range, context:
162169
else KEYWORD_TEMPLATE.substitute(name=keyword)
163170
)
164171

165-
keyword_sections = await find_keyword_sections(model)
172+
keyword_sections = find_keyword_sections(model)
166173
keyword_section = keyword_sections[-1] if keyword_sections else None
167174

168175
if keyword_section is not None:

packages/language_server/src/robotcode/language_server/robotframework/protocol.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from ..__version__ import __version__
1616
from .configuration import RobotConfig
1717
from .parts.code_action_documentation import RobotCodeActionDocumentationProtocolPart
18-
from .parts.code_action_fixes import RobotCodeActionFixesProtocolPart
18+
from .parts.code_action_quick_fixes import RobotCodeActionFixesProtocolPart
1919
from .parts.codelens import RobotCodeLensProtocolPart
2020
from .parts.completion import RobotCompletionProtocolPart
2121
from .parts.debugging_utils import RobotDebuggingUtilsProtocolPart

tests/robotcode/core/test_dataclasses.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ def test_encode_with_optional_field_and_none_as_default_value() -> None:
203203
('"first"', EnumData, EnumData.FIRST),
204204
('"second"', EnumData, EnumData.SECOND),
205205
('["first", "second"]', List[EnumData], [EnumData.FIRST, EnumData.SECOND]),
206+
('["first", "second", "ninety"]', List[Union[EnumData, str]], [EnumData.FIRST, EnumData.SECOND, "ninety"]),
206207
],
207208
)
208209
def test_decode_simple(expr: Any, type: Any, expected: str) -> None:

0 commit comments

Comments
 (0)