18 from ..
import robotapi, utils
19 from .basecontroller
import _BaseController
20 from .cellinfo
import (CellPosition, CellType, CellInfo, CellContent, ContentType)
21 from ..namespace.local_namespace
import LocalNamespace
22 from ..utils
import variablematcher
30 _GIVEN_WHEN_THEN_MATCHER = re.compile(
r'^(given|when|then|and|but)\s*',
34 self.
_init_init(parent, step)
44 if isinstance(self.
_step_step, list):
45 while index < len(self.
_step_step)
and self.
_step_step[index] ==
'':
46 self.
indentindent.append(
'')
51 for index
in range(0, len(cells)):
52 if cells[index] ==
'':
56 self.
_step_step.args = self.
_step_step.comment= []
60 display_name = property
66 datafile_controller = property
69 return self.
parentparent.datafile_controller
76 return args[:-1] + [
'${EMPTY}']
if args
and args[-1] ==
'' else args
93 return (fst.assign == snd.assign
and
94 fst.name == snd.name
and
99 if len(values) <= col:
106 if content.type == ContentType.COMMENTED:
111 assignments = property
114 return self.
_step_step.assign
118 if assignment.replace(
'=',
'').strip() == value.replace(
'=',
'').strip():
120 if value.strip().endswith(
'='):
129 if self.
parentparent.has_template():
131 column -= len(self.
_step_step.assign)
132 value_at_col = self.
get_valueget_value(col)
142 args = info.arguments
145 args_amount = len(args)
148 if column > keyword_col
and self.
get_valueget_value(keyword_col) ==
"FOR" and self.
is_assigningis_assigning(value_at_col):
150 if column <= keyword_col
and self.
is_assigningis_assigning(value_at_col):
152 if col < keyword_col:
154 if not info
and not self.
is_assigningis_assigning(value_at_col)\
162 if col <= keyword_col + mandatory_args_amount:
163 return CellPosition(CellType.MANDATORY, args[col-keyword_col - 1])
164 if col >= keyword_col + args_amount - mandatory_args_amount
and self.
_last_argument_is_varargs_last_argument_is_varargs(args):
166 if keyword_col + mandatory_args_amount < col <= keyword_col + args_amount:
167 return CellPosition(CellType.OPTIONAL, args[col-keyword_col-1])
171 defaults = [arg
for arg
in args
if '=' in arg]
172 n = args_amount - len(defaults)
178 return args[-1].startswith(
'*')
182 for idx, value
in enumerate(self.
argsargsargs):
185 if variablematcher.is_list_variable(value)
and \
186 not variablematcher.is_list_variable_subitem(value):
188 if robotapi.is_dict_var(value)
and \
189 not variablematcher.is_dict_var_access(value):
198 if isinstance(last_none_empty, int)
and last_none_empty < col:
200 if variablematcher.is_variable(value):
202 return CellContent(ContentType.UNKNOWN_VARIABLE, value)
206 ContentType.USER_KEYWORD, value,
210 ContentType.LIBRARY_KEYWORD, value,
217 if position.type == CellType.ASSIGN:
221 except AttributeError:
225 inner_value = value[2:-1]
226 modified = re.split(
r'\W', inner_value, 1)[0]
229 '%s{%s}' % (value[0], modified))
232 index = self.
parentparent.index_of_step(self.
_step_step)
238 for i
in reversed(range(len(values))):
239 if values[i].strip() !=
'':
257 return any(variablematcher.value_contains_variable(item, name)
258 for item
in self.
as_listas_list())
261 return any(variablematcher.value_contains_variable(item,
"%s=" % name)
262 for item
in self.
as_listas_list())
269 if isinstance(expected, str):
270 return utils.eq(item, expected)
or (
274 return expected.match(item)
282 for index, value
in enumerate(self.
argsargsargs):
285 value, new_name, old_name)
289 if not old_prefix_matcher:
291 old_prefix = old_prefix_matcher.group(0)
293 if old_match_matcher
and old_match_matcher.group(0) == old_prefix:
295 return old_prefix + new_match
301 return self.
parentparent.datafile
307 return self.
_step_step.name
313 return self.
_step_step.assign
319 return self.
_step_step.args
325 return self.
_step_step.vars
327 def change(self, col, new_value, delete=False):
329 if col >= len(cells):
330 cells = cells + [
'' for _
in range(col - len(cells) + 1)]
331 cells[col] = new_value
336 self.
_recreate_recreate(cells, comment, delete)
343 self.
changechange(col, new_value)
354 for i
in range(min(col + 1, len(self.
as_listas_list()))):
355 if self.
get_valueget_value(i).startswith(
'#'):
369 _keyword_column = property
372 return self.
_step_step.inner_kw_pos
379 if 0 < len(cells) == index:
380 self.
_step_step.inner_kw_pos = index - 1
383 if index < len(cells)
and cells[index] ==
'':
385 while index < len(cells)
and (len(cells[index]) > 0
and cells[index][0]
in [
'$',
'@',
'&',
'%']):
387 self.
_step_step.inner_kw_pos = index
401 self.
shift_leftshift_left(index_of_comment,
True)
407 if len(cells) > from_column:
410 cells = cells[:from_column] + [
''] + cells[from_column:]
412 self.
_recreate_recreate(cells, comment, delete)
418 while not delete
and from_column > 0
and cells[from_column] !=
'':
420 if not delete
and from_column == 0
and cells[from_column] !=
'':
423 if len(cells) > from_column:
426 cells = cells[:from_column] + cells[from_column + 1:]
428 self.
_recreate_recreate(cells, comment, delete=delete)
433 while index < len(cells)
and cells[index] ==
'':
438 steps = self.
parentparent.get_raw_steps()
439 index = steps.index(self.
_step_step)
440 if not new_step
or not new_step.as_list():
446 current_indent = new_step.first_non_empty_cell()
447 delta_indent = upper_indent - current_indent
453 for _
in range(1, delta_indent):
455 new_step =
robotapi.Step(e_list + new_step.as_list(indent=
True))
457 elif delta_indent < 0
and len(new_step.as_list()) > 1:
458 for _
in range(delta_indent, 0):
459 if new_step.as_list()[0] ==
'':
461 elif delta_indent == 0
and len(steps[index-1].
as_list()) > upper_indent:
462 if steps[index-1].
as_list()[upper_indent-1]
in [
'END'] \
463 or steps[index-1].
as_list()[upper_indent]
in [
'FOR']:
464 new_step =
robotapi.Step([
''] + new_step.as_list(indent=
True))
465 self.
parentparent.set_raw_steps(steps[:index] + [new_step] + steps[index:])
468 current_indent = len(new_step.indent)
470 delta_indent = current_indent - len(self.
_step_step.indent)
473 for _
in range(0, delta_indent):
474 if new_step.as_list()[0] ==
'':
478 self.
parentparent.set_raw_steps([new_step] + steps[index:])
481 steps = self.
parentparent.get_raw_steps()
482 index = steps.index(self.
_step_step) + 1
483 if not self.
_is_end_step_is_end_step(new_step.as_list()):
487 new_step.increase_indent()
489 if self.
_is_intended_step_is_intended_step(new_step.as_list())
and isinstance(new_step, StepController):
491 new_step.decrease_indent()
492 self.
parentparent.set_raw_steps(steps[:index] + [new_step] + steps[index:])
496 while cells != []
and cells[-1].strip() ==
'':
498 self.
_recreate_recreate(cells, delete=delete)
502 if cells != []
and cells[0].strip() ==
'':
507 self.
parentparent.data.steps.remove(self.
_step_step)
508 self.
parentparent._clear_cached_steps()
511 previous_step = self.
parentparent.step(self.
_index_index() - 1)
515 previous_step.insert_before(self.
_step_step)
518 next_step = self.
parentparent.step(self.
_index_index() + 1)
522 next_step.insert_after(self.
_step_step)
525 return self.
parentparent.index_of_step(self.
_step_step)
528 non_empty_cells = [cell
for cell
530 return len(non_empty_cells) == 1
and \
531 non_empty_cells[0].startswith(
'#')
537 return cells[-1].strip()
if cells[-1].startswith(
'#')
else None
553 return cells
and not cells[0].strip()
and any(c.strip()
for c
in cells)
and self.
_index_index() > 0
556 return cells
and (
'END' in cells)
559 def _recreate_as_partial_for_loop(self, cells, comment):
560 index = self._index()
561 self.parent.replace_step(index, PartialForLoop(
562 cells[1:] if len(cells) > 1 else [''], first_cell=cells[0], comment=comment))
563 self._recreate_next_step(index)
572 if len(self.
parentparent.steps) > index + 1:
573 next_step = self.
parentparent.step(index + 1)
574 next_step._recreate(next_step.as_list())
577 self.
parentparent.notify_steps_changed()
580 self.
indentindent.append(
'')
581 return len(self.
indentindent)
585 return len(self.
indentindent)
592 for sub_step
in self.get_raw_steps()]
595 return len(self.
_step_step)
598 class PartialForLoop(robotapi.ForLoop):
602 def __init__(self, cells, first_cell='FOR', comment=None):
604 self._first_cell = first_cell
605 robotapi.ForLoop.__init__(self, self.parent, cells, comment)
607 def as_list(self, indent=False, include_comment=False):
608 return [self._first_cell] + self._cells + [self.comment]
616 StepController.__init__(self, parent, step)
623 return self.
parentparent.name
626 assignments = property
629 return self.
_step_step.vars
633 def _keyword_column(self):
634 return self.inner_kw_pos
643 if isinstance(previous_step, ForLoopStepController):
648 self.
get_raw_stepsget_raw_steps().insert(0, previous_step._step)
649 previous_step.remove()
652 previous_step._step.steps = self.
_step_step.steps
653 self.
_step_step.steps = []
656 i = steps.index(self.
_step_step)
659 steps[i - 1] = self.
_step_step
660 steps[i] = previous_step._step
664 next_step = self.
stepstep(self.
_index_index() + 1)
666 if len(self.
_step_step.steps) == 0:
679 return self.
_step_step.steps
682 self.
_step_step.steps = steps
685 until_range = len(self.
_step_step.vars) + 1
686 flavor = self.
_step_step.flavor
693 if 'IN RANGE' not in flavor:
707 return CellInfo(content, position, for_loop=
True)
717 index_in_for_loop = self.
get_raw_stepsget_raw_steps().index(step)
718 return self.
_index_index() + index_in_for_loop + 1
724 print(f
"\nDEBUG: ForLoopStepController RAW STEPS: {self.get_raw_steps()}")
726 print(f
"\nDEBUG: ForLoopStepController PRINT STEPS: {i.as_list()}")
727 col = self.
_step_step.inner_kw_pos
736 if self.as_list()[self._keyword_column] == 'Comment':
737 kw_column = self._keyword_column
738 self.shift_right(kw_column)
739 self.change(kw_column, '')
740 self.shift_left(self._keyword_column)
747 print(f
"\nDEBUG: ForLoopStepController enter add_step step={step.as_list()}")
754 for idx
in range(0, len(cells)):
757 if cells[idx] ==
'FOR':
760 if kw_index
and not delete:
761 print(f
"\nDEBUG: ForLoopStepController returning recreate_complete_for_loop_header")
768 index = self.
_index_index()
769 print(f
"\nDEBUG: ForLoopStepController RAW STEPS: {self.get_raw_steps()}")
771 print(f
"\nDEBUG: ForLoopStepController PRINT STEPS: {i.as_list()}")
773 print(f
"\nDEBUG: ForLoopStepController returning STEP recreate: index={index}")
780 def _recreate_partial_for_loop_header(self, cells, comment):
781 if not cells or (cells[self._keyword_column].replace(' ', '').upper() != ':FOR'
782 and cells[self._keyword_column].replace(' ', '') != 'FOR'):
783 self._replace_with_new_cells(cells)
785 steps = self.get_raw_steps()
787 StepController._recreate_as_partial_for_loop(self, cells, comment)
788 self.parent.step(i).set_raw_steps(steps)
792 steps = self.
parentparent.data.steps
793 index = steps.index(self.
_step_step)
794 steps.remove(self.
_step_step)
795 self.
parentparent.data.steps = \
796 steps[:index] + self.
get_raw_stepsget_raw_steps() + steps[index:]
797 self.
_step_step.steps = []
802 if cells[0] != self.
as_listas_list()[0]:
804 in_token_index = len(self.
varsvarsvars) + 1
805 if len(cells) <= in_token_index:
807 if len(self.
as_listas_list()) <= in_token_index:
809 if cells[in_token_index] != self.
as_listas_list()[in_token_index]:
835 def _first_non_empty_cell(self):
836 cells = self.as_list()
839 while index < len(cells) and cells[index] == '':
848 def _keyword_column(self):
849 return self._first_non_empty_cell()
853 row = self._step.as_list()
862 return StepController._get_cell_position(self, col)
865 p = self.
parentparent.parent
866 index = p.index_of_step(self.
_step_step)
872 return StepController._get_content_with_type(self, col, position)
876 col = self._keyword_column
877 print(f"DEBUG: IntendedStepController comment ENTER self._keyword_column={col}")
879 self.change(col+1, 'Comment')
884 if self._step.name == 'Comment':
885 kw_column = self._keyword_column
886 self.shift_right(kw_column)
887 self.change(kw_column, '')
888 self.shift_left(self._keyword_column)
894 if (cells == []
or cells[0] ==
'')
and not delete:
896 if len(cells) > 1 and cells[1] != '':
897 for idx in range(0, len(cells)):
902 if self.
_step_step
not in self.
parentparent.get_raw_steps():
907 if self.
_step_step
not in self.
parentparent.get_raw_steps():
915 steps = self.
parentparent.steps
916 index = [s._step
for s
in steps].index(self.
_step_step)
917 for i, step
in reversed(list(enumerate(steps))):
920 step._replace_with_normal_step(i, step.as_list())
924 index_of_parent = self.
parentparent.parent.index_of_step(self.
parentparent._step)
925 self.
parentparent.parent.add_step(
926 index_of_parent + index + 2,
928 self.
parentparent.get_raw_steps().pop(index)
937 StepController.remove_empty_columns_from_end(self, delete)
def _recreate_complete_for_loop_header(self, cells)
def _build_cell_info(self, content, position)
def _get_comment(self, cells)
def _has_comment_keyword(self)
def _recreate(self, cells, comment=None, delete=False)
def index_of_step(self, step)
def notify_steps_changed(self)
def contains_keyword(self, name)
def __init__(self, parent, step)
def _get_cell_position(self, col)
def get_cell_info(self, col)
def _replace_with_new_cells(self, cells)
def _represent_valid_for_loop_header(self, cells)
def insert_after(self, new_step)
def set_raw_steps(self, steps)
def _swap_forloop_headers(self, previous_step)
def _recreate(self, cells, comment=None, delete=False)
def _replace_with_normal_step(self, index, cells=None, comment=None)
def remove_empty_columns_from_end(self, delete=True)
def _get_content_with_type(self, col, position)
def _get_cell_position(self, col)
def _get_local_namespace(self)
def _recreate_as_normal_step(self, cells, comment=None)
def get_cell_info(self, col)
def is_assigning(self, value)
def is_user_keyword(self, value)
def contains_keyword(self, name)
def is_library_keyword(self, value)
def _kw_name_replace(self, old_value, new_match, old_match)
def increase_indent(self)
def _steps_are_equal(self, fst, snd)
def _kw_name_match(self, item, expected)
def contains_variable(self, name)
def first_non_empty_cell(cells)
def _keyword_column(self)
def _has_list_or_dict_var_value_before(self, arg_index)
def contains_variable_assignment(self, name)
def _recreate(self, cells, comment=None, delete=False)
def shift_right(self, from_column, delete=False)
def get_keyword_info(self, kw)
def insert_after(self, new_step)
def _get_comment(self, cells)
def replace_keyword(self, new_name, old_name)
def _build_cell_info(self, content, position)
def _is_commented(self, col)
def shift_left(self, from_column, delete=False)
def has_only_comment(self)
def _number_of_mandatory_arguments(self, args, args_amount)
def datafile_controller(self)
def _recreate_as_intended_step(self, for_loop_step, cells, comment, index)
def remove_empty_columns_from_end(self, delete=True)
def _has_comment_keyword(self)
def _last_argument_is_varargs(self, args)
def decrease_indent(self)
def _is_partial_for_loop_step(self, cells)
def remove_empty_columns_from_beginning(self)
def change(self, col, new_value, delete=False)
def _change_last_empty_to_empty_var(self, args, comment)
def _get_content_with_type(self, col, position)
def _get_last_none_empty_col_idx(self)
def _first_non_empty_cell(self)
def _get_cell_position(self, column)
def insert_before(self, new_step)
def notify_value_changed(self)
def _get_local_namespace(self)
def _is_intended_step(self, cells)
def _is_unknow_variable(self, value, position)
def insert_value_before(self, col, new_value)
def __init__(self, parent, step)
def _is_end_step(self, cells)
def _recreate_next_step(self, index)
def recalculate_keyword_column(self)
def _init(self, parent, step)
def LocalNamespace(controller, namespace, row=None)