Skip to content

Commit 5e7434c

Browse files
committed
implement set variable in debugger
1 parent b445651 commit 5e7434c

File tree

4 files changed

+88
-9
lines changed

4 files changed

+88
-9
lines changed

robotcode/debug_adapter/launcher/debugger.py

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ class EvaluateResult(NamedTuple):
4747
memory_reference: Optional[str] = None
4848

4949

50+
class SetVariableResult(NamedTuple):
51+
value: str
52+
type: Optional[str]
53+
variables_reference: Optional[int] = None
54+
named_variables: Optional[int] = None
55+
indexed_variables: Optional[int] = None
56+
57+
5058
class State(Enum):
5159
Stopped = 0
5260
Running = 1
@@ -668,24 +676,19 @@ def get_variables(
668676
if entry is not None:
669677
context = entry.context()
670678
if context is not None:
671-
672679
if entry.global_id() == variables_reference:
673680
result += [
674681
Variable(name=k, value=repr(v), type=repr(type(v)))
675682
for k, v in context.variables._global.as_dict().items()
676683
]
677684
elif entry.suite_id() == variables_reference:
678-
# current_index = context.variables._scopes.index(context.variables._suite)
679-
# globals = context.variables._scopes[max(current_index - 1, 0)].as_dict()
680685
globals = context.variables._global.as_dict()
681686
result += [
682687
Variable(name=k, value=repr(v), type=repr(type(v)))
683688
for k, v in context.variables._suite.as_dict().items()
684689
if k not in globals or globals[k] != v
685690
]
686691
elif entry.test_id() == variables_reference:
687-
# current_index = context.variables._scopes.index(context.variables._test)
688-
# globals = context.variables._scopes[max(current_index - 1, 0)].as_dict()
689692
globals = context.variables._suite.as_dict()
690693
result += [
691694
Variable(name=k, value=repr(v), type=repr(type(v)))
@@ -703,7 +706,7 @@ def get_variables(
703706

704707
return result
705708

706-
VARS_RE = re.compile(r"^[$@&%]\{.*\}$")
709+
IS_VARIABLE_RE = re.compile(r"^[$@&%]\{.*\}$")
707710

708711
def evaluate(
709712
self,
@@ -734,7 +737,7 @@ def evaluate(
734737
vars = (
735738
evaluate_context.variables.current if frame_id is not None else evaluate_context.variables._global
736739
)
737-
if self.VARS_RE.match(expression.strip()):
740+
if self.IS_VARIABLE_RE.match(expression.strip()):
738741
result = vars.replace_string(expression)
739742
else:
740743
result = evaluate_expression(vars.replace_string(expression), vars.store)
@@ -748,3 +751,32 @@ def evaluate(
748751
result = e
749752

750753
return EvaluateResult(repr(result), repr(type(result)))
754+
755+
def set_variable(
756+
self, variables_reference: int, name: str, value: str, format: Optional[ValueFormat] = None
757+
) -> SetVariableResult:
758+
from robot.variables.evaluation import evaluate_expression
759+
760+
entry = next(
761+
(
762+
v
763+
for v in self.stack_frames
764+
if variables_reference in [v.global_id(), v.local_id(), v.suite_id(), v.test_id()]
765+
),
766+
None,
767+
)
768+
769+
if entry is not None:
770+
context = entry.context()
771+
if context is not None:
772+
variables = context.variables.current
773+
774+
if (name[2:-1] if self.IS_VARIABLE_RE.match(name) else name) not in variables:
775+
raise NameError(f"Variable '{name}' not found.")
776+
777+
evaluated_value = evaluate_expression(variables.replace_string(value), variables.store)
778+
variables[name] = evaluated_value
779+
780+
return SetVariableResult(repr(evaluated_value), repr(type(value)))
781+
782+
raise ReferenceError("Invalid variable reference.")

robotcode/debug_adapter/launcher/server.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
ScopesResponseBody,
2525
SetBreakpointsArguments,
2626
SetBreakpointsResponseBody,
27+
SetVariableArguments,
28+
SetVariableResponseBody,
2729
StackTraceArguments,
2830
StackTraceResponseBody,
2931
StepInArguments,
@@ -217,7 +219,6 @@ async def _evaluate(
217219
frame_id: Optional[int] = None,
218220
context: Union[EvaluateArgumentContext, str, None] = None,
219221
format: Optional[ValueFormat] = None,
220-
**kwargs: Any,
221222
) -> EvaluateResponseBody:
222223
result = Debugger.instance().evaluate(expression, frame_id, context, format)
223224
return EvaluateResponseBody(
@@ -230,6 +231,24 @@ async def _evaluate(
230231
memory_reference=result.memory_reference,
231232
)
232233

234+
@rpc_method(name="setVariable", param_type=SetVariableArguments)
235+
async def _set_variable(
236+
self,
237+
arguments: SetVariableArguments,
238+
variables_reference: int,
239+
name: str,
240+
value: str,
241+
format: Optional[ValueFormat] = None,
242+
) -> SetVariableResponseBody:
243+
result = Debugger.instance().set_variable(variables_reference, name, value, format)
244+
return SetVariableResponseBody(
245+
value=result.value,
246+
type=result.type,
247+
variables_reference=result.variables_reference,
248+
named_variables=result.named_variables,
249+
indexed_variables=result.indexed_variables,
250+
)
251+
233252

234253
class LaucherServer(JsonRPCServer[LauncherServerProtocol]):
235254
def __init__(

robotcode/debug_adapter/server.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,11 @@ async def _initialize(self, arguments: InitializeRequestArguments) -> Capabiliti
8585
supports_evaluate_for_hovers=True,
8686
# supports_loaded_sources_request=True,
8787
supports_terminate_request=True,
88-
# supports_data_breakpoints=True
88+
# supports_data_breakpoints=True,
89+
supports_log_points=True,
90+
supports_set_expression=True,
91+
supports_set_variable=True,
92+
supports_value_formatting_options=True,
8993
)
9094

9195
@rpc_method(name="launch", param_type=LaunchRequestArguments)

robotcode/debug_adapter/types.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,3 +708,27 @@ class EvaluateResponseBody(Model):
708708

709709
class EvaluateResponse(Response):
710710
body: VariablesResponseBody
711+
712+
713+
class SetVariableArguments(Model):
714+
variables_reference: int
715+
name: str
716+
value: str
717+
format: Optional[ValueFormat] = None
718+
719+
720+
class SetVariableRequest(Request):
721+
command: str = Field("setVariable", const=True)
722+
arguments: SetVariableArguments
723+
724+
725+
class SetVariableResponseBody(Model):
726+
value: str
727+
type: Optional[str]
728+
variables_reference: Optional[int] = None
729+
named_variables: Optional[int] = None
730+
indexed_variables: Optional[int] = None
731+
732+
733+
class SetVariableResponse(Response):
734+
body: SetVariableResponseBody

0 commit comments

Comments
 (0)