From f27048df3d9f1ff1dd5ec1b75e36e1e632d0b1b8 Mon Sep 17 00:00:00 2001 From: HelioGuilherme66 Date: Sat, 28 Oct 2023 16:54:12 +0100 Subject: [PATCH 1/9] Improve reader. DEBUG --- src/robotide/lib/robot/parsing/model.py | 5 +++++ src/robotide/lib/robot/parsing/populators.py | 2 +- src/robotide/lib/robot/parsing/robotreader.py | 20 ++++++++++++------- src/robotide/lib/robot/parsing/settings.py | 19 ++++++++++++++++-- 4 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/robotide/lib/robot/parsing/model.py b/src/robotide/lib/robot/parsing/model.py index 858bf4205..514a474ef 100644 --- a/src/robotide/lib/robot/parsing/model.py +++ b/src/robotide/lib/robot/parsing/model.py @@ -439,6 +439,7 @@ def add_resource(self, name, invalid_args=None, comment=None): return self.imports[-1] def add_variables(self, name, args=None, comment=None): + # print(f"DEBUG: RFLib model.py _SettingTable add_variables {name=}, {args=}, {comment=}") self.imports.add(Variables(self, name, args, comment=comment)) return self.imports[-1] @@ -519,6 +520,10 @@ def _old_header_matcher(self): return OldStyleSettingAndVariableTableHeaderMatcher() def add(self, name, value, comment=None): + # print(f"DEBUG: RFLib model.py VariableTable add {name=}, {value=}, {comment=}") + if not name: + return + value = [x for x in value if x != ''] self.variables.append(Variable(self, name, value, comment)) def __iter__(self): diff --git a/src/robotide/lib/robot/parsing/populators.py b/src/robotide/lib/robot/parsing/populators.py index 9cd10dc21..c8003eb28 100644 --- a/src/robotide/lib/robot/parsing/populators.py +++ b/src/robotide/lib/robot/parsing/populators.py @@ -69,7 +69,7 @@ def populate(self, path, resource=False): LOGGER.info("Parsing file '%s'." % path) source = self._open(path) try: - # print(f"DEBUG: populators populate READER={self._get_reader(path, resource)}") + # print(f"DEBUG: populators populate path={path} READER={self._get_reader(path, resource)}") self._get_reader(path, resource).read(source, self) except Exception: # print(f"DEBUG: populators populate CALLING DATAERROR") diff --git a/src/robotide/lib/robot/parsing/robotreader.py b/src/robotide/lib/robot/parsing/robotreader.py index c7d561d90..8b4d3f341 100644 --- a/src/robotide/lib/robot/parsing/robotreader.py +++ b/src/robotide/lib/robot/parsing/robotreader.py @@ -45,11 +45,13 @@ def read(self, file, populator, path=None): cells = self.split_row(line.rstrip()) # DEBUG cells = list(self._check_deprecations(cells, path, lineno)) # DEBUG Not parsing # before any table + """ if line.lstrip().startswith('#'): if cells[0] == '': # There is an initial empty cell, when # cells.pop(0) # populator.add(cells) # continue + """ if cells and cells[0].strip().startswith('*'): # For the cases of *** Comments *** if cells[0].replace('*', '').strip().lower() in ('comment', 'comments'): # print(f"DEBUG: robotreader.read detection of comments cells={cells}") @@ -64,10 +66,10 @@ def read(self, file, populator, path=None): # print(f"DEBUG: RFLib RobotReader *** section lineno={lineno} cells={cells}") elif cells and cells == ['']: comments = False - if cells and cells[0].strip().startswith('*') and not comments and \ + if cells and cells[0].strip().startswith('*') and \ populator.start_table([c.replace('*', '').strip() for c in cells]): process = table_start = True - preamble = comments = False + preamble = False # DEBUG removed condition "and not comments" comments = elif not table_start: # print(f"DEBUG: RFLib RobotReader Enter Preamble block, lineno={lineno} cells={cells}") if not preamble: @@ -83,6 +85,11 @@ def read(self, file, populator, path=None): return populator.eof() def sharp_strip(self, line): + # DEBUG + row = self._space_splitter.split(line) + # print(f"DEBUG: RFLib RobotReader sharp_strip after cells split row={row[:]}") + return row + # END DEBUG row = [] i = 0 start_d_quote = end_d_quote = False @@ -177,18 +184,18 @@ def _normalize_whitespace(string): return ' '.join(string.split()) def check_separator(self, line): - """ if line.startswith('*') and not self._cell_section: - row = line.strip('*').strip(' ') - if row in ['Keyword', 'Keywords', 'Test Case', 'Test Cases', 'Task', 'Tasks', 'Variable', 'Variables']: + row = line.strip('*').strip().lower() + if row in ['keyword', 'keywords', 'test case', 'test cases', 'task', 'tasks', 'variable', 'variables']: self._cell_section = True # self._space_splitter = re.compile(r"[ \t\xa0]{" + f"{self._spaces}" + "}|\t+") - """ if not line.startswith('*') and not line.startswith('#'): if not self._separator_check and line[:2] in self._pipe_starts: self._separator_check = True # print(f"DEBUG: RFLib RobotReader check_separator PIPE separator") return + if not self._cell_section: + return idx = 0 for idx in range(0, len(line)): if line[idx] != ' ': @@ -198,4 +205,3 @@ def check_separator(self, line): self._space_splitter = re.compile(r"[ \t\xa0]{" + f"{self._spaces}" + "}|\t+") self._separator_check = True # print(f"DEBUG: RFLib RobotReader check_separator changed spaces={self._spaces}") - return diff --git a/src/robotide/lib/robot/parsing/settings.py b/src/robotide/lib/robot/parsing/settings.py index 24e91e369..d7de2b0fa 100644 --- a/src/robotide/lib/robot/parsing/settings.py +++ b/src/robotide/lib/robot/parsing/settings.py @@ -66,6 +66,8 @@ def populate(self, value, comment=None): def _populate(self, value): # self.value.append(self._string_value(value)) + if value: + value = [x for x in value if x != ''] self.value = value def is_set(self): @@ -277,8 +279,11 @@ class ImportSetting(Setting): def __init__(self, parent, name, args=None, alias=None, comment=None): self.parent = parent - self.name = name - self.args = args or [] + self.name = name.strip() + if args: + self.args = [x for x in args if x != ''] + else: + self.args = [] self.alias = alias self._set_comment(comment) @@ -308,6 +313,12 @@ def report_invalid_syntax(self, message, level='ERROR', parent=None): class Library(ImportSetting): def __init__(self, parent, name, args=None, alias=None, comment=None): + if args: + args = [x for x in args if x != ''] + else: + args = [] + if not name and args: + name = args.pop(0) if args and not alias: args, alias = self._split_possible_alias(args) ImportSetting.__init__(self, parent, name, args, alias, comment) @@ -336,6 +347,10 @@ def __init__(self, parent, name, invalid_args=None, comment=None): class Variables(ImportSetting): def __init__(self, parent, name, args=None, comment=None): + # print(f"DEBUG: RFLib settings.py Variables __init__ {name=}, {args=}") + args = [x for x in args if x != ''] or [] + if not name and args: + name = args.pop(0) ImportSetting.__init__(self, parent, name, args, comment=comment) From 84be78de0575ecfb7eaa4cdfb33b2d46190f4b47 Mon Sep 17 00:00:00 2001 From: HelioGuilherme66 Date: Sat, 28 Oct 2023 17:36:22 +0100 Subject: [PATCH 2/9] Improve reader. --- src/robotide/lib/robot/parsing/model.py | 3 ++- src/robotide/lib/robot/parsing/settings.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/robotide/lib/robot/parsing/model.py b/src/robotide/lib/robot/parsing/model.py index 514a474ef..031b38fdf 100644 --- a/src/robotide/lib/robot/parsing/model.py +++ b/src/robotide/lib/robot/parsing/model.py @@ -523,7 +523,6 @@ def add(self, name, value, comment=None): # print(f"DEBUG: RFLib model.py VariableTable add {name=}, {value=}, {comment=}") if not name: return - value = [x for x in value if x != ''] self.variables.append(Variable(self, name, value, comment)) def __iter__(self): @@ -593,6 +592,8 @@ def __init__(self, parent, name, value, comment=None): value = '' if is_string(value): value = [value] + elif isinstance(value, list): + value = [x for x in value if x != ''] or [] self.value = value self.comment = Comment(comment) diff --git a/src/robotide/lib/robot/parsing/settings.py b/src/robotide/lib/robot/parsing/settings.py index d7de2b0fa..3602fc9b2 100644 --- a/src/robotide/lib/robot/parsing/settings.py +++ b/src/robotide/lib/robot/parsing/settings.py @@ -348,8 +348,8 @@ class Variables(ImportSetting): def __init__(self, parent, name, args=None, comment=None): # print(f"DEBUG: RFLib settings.py Variables __init__ {name=}, {args=}") - args = [x for x in args if x != ''] or [] - if not name and args: + if args and not name: + args = [x for x in args if x != ''] or [] name = args.pop(0) ImportSetting.__init__(self, parent, name, args, comment=comment) From b8c4af011b85840608069c06fd430369551c1ce9 Mon Sep 17 00:00:00 2001 From: HelioGuilherme66 Date: Sat, 28 Oct 2023 18:20:02 +0100 Subject: [PATCH 3/9] Improve reader. --- src/robotide/lib/robot/parsing/settings.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/robotide/lib/robot/parsing/settings.py b/src/robotide/lib/robot/parsing/settings.py index 3602fc9b2..8fe1bf948 100644 --- a/src/robotide/lib/robot/parsing/settings.py +++ b/src/robotide/lib/robot/parsing/settings.py @@ -177,6 +177,8 @@ def _set_initial_value(self): self.assign = () def _populate(self, value): + if value and isinstance(value, list): + value = [x for x in value if x != ''] if not self.name: self.name = value[0] if value else '' value = value[1:] @@ -204,6 +206,8 @@ def _set_initial_value(self): self.message = '' def _populate(self, value): + if value and isinstance(value, list): + value = [x for x in value if x != ''] if not self.value: self.value = value[0] if value else '' value = value[1:] @@ -348,8 +352,9 @@ class Variables(ImportSetting): def __init__(self, parent, name, args=None, comment=None): # print(f"DEBUG: RFLib settings.py Variables __init__ {name=}, {args=}") - if args and not name: + if args and isinstance(args, list): args = [x for x in args if x != ''] or [] + if args and not name: name = args.pop(0) ImportSetting.__init__(self, parent, name, args, comment=comment) From 27897732c76776b7654ba6cd4199eec49e90fe09 Mon Sep 17 00:00:00 2001 From: Helio Guilherme Date: Sun, 29 Oct 2023 02:30:01 +0000 Subject: [PATCH 4/9] Debug reading preamble, all testcase is there when Language set --- src/robotide/application/application.py | 3 ++- src/robotide/controller/filecontrollers.py | 4 ++++ src/robotide/controller/project.py | 3 +++ src/robotide/editor/texteditor.py | 1 + 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/robotide/application/application.py b/src/robotide/application/application.py index 2aca3c602..a1473a2e2 100644 --- a/src/robotide/application/application.py +++ b/src/robotide/application/application.py @@ -65,6 +65,7 @@ class RIDE(wx.App): frame = None namespace = None preferences = None + robot_version = None settings = None treeplugin = None @@ -117,10 +118,10 @@ def OnInit(self): # Overrides wx method if not self.fileexplorerplugin.opened: self.fileexplorerplugin.close_tree() self.editor = self._get_editor() + self.robot_version = self._find_robot_installation() self._load_data() self.treeplugin.populate(self.model) self.treeplugin.set_editor(self.editor) - self._find_robot_installation() self._publish_system_info() self.frame.Show() # ###### DEBUG DANGER ZONE self.SetTopWindow(self.frame) diff --git a/src/robotide/controller/filecontrollers.py b/src/robotide/controller/filecontrollers.py index 6a65a1ab9..c26c68de7 100644 --- a/src/robotide/controller/filecontrollers.py +++ b/src/robotide/controller/filecontrollers.py @@ -731,6 +731,10 @@ def longname(self): def suites(self): return () + @property + def preamble(self): + return self.data.preamble + def contains_tests(self): return bool(self.tests) diff --git a/src/robotide/controller/project.py b/src/robotide/controller/project.py index 0283068c2..edff51dda 100644 --- a/src/robotide/controller/project.py +++ b/src/robotide/controller/project.py @@ -118,6 +118,9 @@ def new_resource(self, path, parent=None): return resource_controller def load_data(self, path, load_observer=None): + from robotide.context import APP + robot_version = APP.robot_version + print(f"DEBUG: project.py Project ENTER robot version = {robot_version}") load_observer = load_observer or NullObserver() if self._load_initfile(path, load_observer): return diff --git a/src/robotide/editor/texteditor.py b/src/robotide/editor/texteditor.py index 9b5183d68..73b16084b 100644 --- a/src/robotide/editor/texteditor.py +++ b/src/robotide/editor/texteditor.py @@ -116,6 +116,7 @@ def on_open(self, event): def _open(self): datafile_controller = self.tree.get_selected_datafile_controller() if datafile_controller: + print(f"DEBUG: texteditor _open preamble={datafile_controller.preamble}") self._open_data_for_controller(datafile_controller) self._editor.store_position() From 7a6d1c194a4babdb53bb013a2f22fa4e56558ad5 Mon Sep 17 00:00:00 2001 From: HelioGuilherme66 Date: Sun, 29 Oct 2023 23:47:18 +0000 Subject: [PATCH 5/9] Improve file reader. Add debug info for preamble --- src/robotide/application/releasenotes.py | 2 +- src/robotide/editor/texteditor.py | 3 +- src/robotide/lib/robot/parsing/model.py | 1 + src/robotide/lib/robot/parsing/robotreader.py | 93 +------------------ src/robotide/lib/robot/parsing/settings.py | 42 ++++++--- src/robotide/lib/robot/writer/filewriters.py | 9 +- src/robotide/version.py | 2 +- 7 files changed, 42 insertions(+), 110 deletions(-) diff --git a/src/robotide/application/releasenotes.py b/src/robotide/application/releasenotes.py index 7ac01cb0c..6dda5e686 100644 --- a/src/robotide/application/releasenotes.py +++ b/src/robotide/application/releasenotes.py @@ -248,6 +248,6 @@ def set_content(self, html_win, content):
 python -m robotide.postinstall -install
 
-

RIDE {VERSION} was released on 26/Oct/2023.

+

RIDE {VERSION} was released on 29/Oct/2023.

""" diff --git a/src/robotide/editor/texteditor.py b/src/robotide/editor/texteditor.py index 73b16084b..5aaa6288f 100644 --- a/src/robotide/editor/texteditor.py +++ b/src/robotide/editor/texteditor.py @@ -116,7 +116,8 @@ def on_open(self, event): def _open(self): datafile_controller = self.tree.get_selected_datafile_controller() if datafile_controller: - print(f"DEBUG: texteditor _open preamble={datafile_controller.preamble}") + if hasattr(datafile_controller, 'preamble'): # DEBUG: Is failing at resource files + print(f"DEBUG: texteditor _open preamble={datafile_controller.preamble}") self._open_data_for_controller(datafile_controller) self._editor.store_position() diff --git a/src/robotide/lib/robot/parsing/model.py b/src/robotide/lib/robot/parsing/model.py index 031b38fdf..85a3fb94a 100644 --- a/src/robotide/lib/robot/parsing/model.py +++ b/src/robotide/lib/robot/parsing/model.py @@ -239,6 +239,7 @@ def __init__(self, source=None, settings=None): self.testcase_table = TestCaseTable(self) self.keyword_table = KeywordTable(self) self.settings = settings + self._preamble = [] self._tab_size = self.settings.get('txt number of spaces', 2) if self.settings else 2 _TestData.__init__(self, source=source) diff --git a/src/robotide/lib/robot/parsing/robotreader.py b/src/robotide/lib/robot/parsing/robotreader.py index 8b4d3f341..adf5173fe 100644 --- a/src/robotide/lib/robot/parsing/robotreader.py +++ b/src/robotide/lib/robot/parsing/robotreader.py @@ -25,47 +25,26 @@ class RobotReader(object): def __init__(self, spaces=2): self._spaces = spaces - # self._space_splitter = re.compile(r"[ \t\xa0]{"+f"{self._spaces}"+"}|\t+") # Only change when is cell_section self._space_splitter = re.compile(r"[ \t\xa0]{2}|\t+") self._pipe_splitter = re.compile(r"[ \t\xa0]+\|(?=[ \t\xa0]+)") self._pipe_starts = ('|', '| ', '|\t', u'|\xa0') self._pipe_ends = (' |', '\t|', u'\xa0|') self._separator_check = False self._cell_section = False - # print(f"DEBUG: RFLib RobotReader init spaces={self._spaces}") def read(self, file, populator, path=None): path = path or getattr(file, 'name', '') _ = path - process = table_start = preamble = comments = False + process = table_start = preamble = False # print(f"DEBUG: RFLib RobotReader start Reading file") for lineno, line in enumerate(Utf8Reader(file).readlines(), start=1): if not self._separator_check: self.check_separator(line.rstrip()) cells = self.split_row(line.rstrip()) - # DEBUG cells = list(self._check_deprecations(cells, path, lineno)) - # DEBUG Not parsing # before any table - """ - if line.lstrip().startswith('#'): - if cells[0] == '': # There is an initial empty cell, when # - cells.pop(0) - # populator.add(cells) - # continue - """ if cells and cells[0].strip().startswith('*'): # For the cases of *** Comments *** if cells[0].replace('*', '').strip().lower() in ('comment', 'comments'): # print(f"DEBUG: robotreader.read detection of comments cells={cells}") process = True - comments = True - # if not preamble: - # cells.insert(0, '') - else: - # if comments: - # cells.insert(0, '') # Last comments block - comments = False - # print(f"DEBUG: RFLib RobotReader *** section lineno={lineno} cells={cells}") - elif cells and cells == ['']: - comments = False if cells and cells[0].strip().startswith('*') and \ populator.start_table([c.replace('*', '').strip() for c in cells]): process = table_start = True @@ -76,82 +55,13 @@ def read(self, file, populator, path=None): preamble = True populator.add_preamble(line) elif process and not preamble: - # We modify, insert cell, to avoid being a new test case, keyword... - # if comments: # and cells[0] != '': - # cells.insert(0, '') - # # print(f"DEBUG: robotreader.read in comments cells={cells}") - # print(f"DEBUG: robotreader.read original line={line}\nparser={cells}") populator.add(cells) return populator.eof() def sharp_strip(self, line): - # DEBUG row = self._space_splitter.split(line) # print(f"DEBUG: RFLib RobotReader sharp_strip after cells split row={row[:]}") return row - # END DEBUG - row = [] - i = 0 - start_d_quote = end_d_quote = False - start_s_quote = end_s_quote = False - index = len(line) - while i < len(line): - if line[i] == '"': - if end_d_quote: - start_d_quote = True - end_d_quote = False - elif start_d_quote: - end_d_quote = True - else: - start_d_quote = True - if line[i] == "'": - if end_s_quote: - start_s_quote = True - end_s_quote = False - elif start_s_quote: - end_s_quote = True - else: - start_s_quote = True - if line[i] == '#' and not start_d_quote and not start_s_quote: - if i == 0: - index = 0 - break - try: - if i > 0 and line[i-1] != '\\' and (line[i+1] == ' ' or line[i+1] == '#'): - index = i - # print(f"DEBUG: RFLib RobotReader sharp_strip BREAK at # index={index}") - break - except IndexError: - i += 1 - continue - i += 1 - if index < len(line): - cells = self._space_splitter.split(line[:index]) - row.extend(cells) - row.append(line[index:]) - else: - row = self._space_splitter.split(line) - # print(f"DEBUG: RFLib RobotReader sharp_strip after cells split index={index} row={row[:]}") - # Remove empty cells after first non-empty - first_non_empty = -1 - if row: - for i, v in enumerate(row): - if v != '': - first_non_empty = i - break - # print(f"DEBUG: RFLib RobotReader sharp_strip row first_non_empty={first_non_empty}") - if first_non_empty != -1: - for i in range(len(row)-1, first_non_empty, -1): - if row[i] == '': - # print(f"DEBUG: RFLib RobotReader sharp_strip popping ow i ={i} row[i]={row[i]}") - row.pop(i) - # Remove initial empty cell - if len(row) > 1 and first_non_empty > 1 and row[0] == '' and row[1] != '': # don't cancel indentation - # print(f"DEBUG: RFLib RobotReader sharp_strip removing initial empty cell - # first_non_empty={first_non_empty}") - row.pop(0) - # print(f"DEBUG: RFLib RobotReader sharp_strip returning row={row[:]}") - return row def split_row(self, row): if row[:2] in self._pipe_starts: @@ -188,7 +98,6 @@ def check_separator(self, line): row = line.strip('*').strip().lower() if row in ['keyword', 'keywords', 'test case', 'test cases', 'task', 'tasks', 'variable', 'variables']: self._cell_section = True - # self._space_splitter = re.compile(r"[ \t\xa0]{" + f"{self._spaces}" + "}|\t+") if not line.startswith('*') and not line.startswith('#'): if not self._separator_check and line[:2] in self._pipe_starts: self._separator_check = True diff --git a/src/robotide/lib/robot/parsing/settings.py b/src/robotide/lib/robot/parsing/settings.py index 8fe1bf948..5258a0b34 100644 --- a/src/robotide/lib/robot/parsing/settings.py +++ b/src/robotide/lib/robot/parsing/settings.py @@ -66,8 +66,8 @@ def populate(self, value, comment=None): def _populate(self, value): # self.value.append(self._string_value(value)) - if value: - value = [x for x in value if x != ''] + if value and isinstance(value, list): + value = [x.strip() for x in value if x != ''] self.value = value def is_set(self): @@ -81,11 +81,13 @@ def report_invalid_syntax(self, message, level='ERROR'): self.parent.report_invalid_syntax(message, level) def _string_value(self, value): - return value if is_string(value) else ' '.join(value) + if value and isinstance(value, list): + value = [x.strip() for x in value if x != ''] + return value.strip() if is_string(value) else ' '.join(value) def _concat_string_with_value(self, string, value): if string: - return string + ' ' + self._string_value(value) + return string.strip() + ' ' + self._string_value(value) return self._string_value(value) def as_list(self): @@ -114,12 +116,14 @@ def __init__(self, separator): def join_string_with_value(self, string, value): if string: - return string + self._separator + self.string_value(value) + return string.strip() + self._separator + self.string_value(value) return self.string_value(value) def string_value(self, value): if is_string(value): - return value + return value.strip() + if value and isinstance(value, list): + value = [x.strip() for x in value if x != ''] return self._separator.join(value) @@ -132,7 +136,9 @@ def _populate(self, value): self.value = self._concat_string_with_value(self.value, value) def _string_value(self, value): - return value if is_string(value) else ''.join(value) + if value and isinstance(value, list): + value = [x.strip() for x in value if x != ''] + return value.strip() if is_string(value) else ''.join(value) def _data_as_list(self): return [self.setting_name, self.value] @@ -178,7 +184,7 @@ def _set_initial_value(self): def _populate(self, value): if value and isinstance(value, list): - value = [x for x in value if x != ''] + value = [x.strip() for x in value if x != ''] if not self.name: self.name = value[0] if value else '' value = value[1:] @@ -207,7 +213,7 @@ def _set_initial_value(self): def _populate(self, value): if value and isinstance(value, list): - value = [x for x in value if x != ''] + value = [x.strip() for x in value if x != ''] if not self.value: self.value = value[0] if value else '' value = value[1:] @@ -237,6 +243,8 @@ def _set_initial_value(self): self.value = None def _populate(self, value): + if value and isinstance(value, list): + value = [x.strip() for x in value if x != ''] self.value = (self.value or []) + value def is_set(self): @@ -263,6 +271,14 @@ class Metadata(Setting): def __init__(self, parent, name, value, comment=None, joined=False): self.parent = parent + if value and isinstance(value, list): + value = [x.strip() for x in value if x != ''] + if not name.strip(): + if value and not value[1:]: + value = value[0].split(' ') + value = [x.strip() for x in value if x != ''] + name = value[0] + value = value[1:] self.name = name joiner = StringValueJoiner('' if joined else ' ') self.value = joiner.join_string_with_value('', value) @@ -285,7 +301,7 @@ def __init__(self, parent, name, args=None, alias=None, comment=None): self.parent = parent self.name = name.strip() if args: - self.args = [x for x in args if x != ''] + self.args = [x.strip() for x in args if x != ''] else: self.args = [] self.alias = alias @@ -318,7 +334,7 @@ class Library(ImportSetting): def __init__(self, parent, name, args=None, alias=None, comment=None): if args: - args = [x for x in args if x != ''] + args = [x.strip() for x in args if x != ''] else: args = [] if not name and args: @@ -353,7 +369,7 @@ class Variables(ImportSetting): def __init__(self, parent, name, args=None, comment=None): # print(f"DEBUG: RFLib settings.py Variables __init__ {name=}, {args=}") if args and isinstance(args, list): - args = [x for x in args if x != ''] or [] + args = [x.strip() for x in args if x != ''] or [] if args and not name: name = args.pop(0) ImportSetting.__init__(self, parent, name, args, comment=comment) @@ -373,6 +389,8 @@ def _add(self, meta): @staticmethod def _parse_name_and_value(value): + if value: + value = [x.strip() for x in value if x != ''] name = value[0] if value else '' return name, value[1:] diff --git a/src/robotide/lib/robot/writer/filewriters.py b/src/robotide/lib/robot/writer/filewriters.py index 4c30789d7..130f826e6 100644 --- a/src/robotide/lib/robot/writer/filewriters.py +++ b/src/robotide/lib/robot/writer/filewriters.py @@ -60,9 +60,12 @@ def _write_table(self, table, is_last): self._write_rows(self._formatter.format_table(table)) if not is_last: # DEBUG: make this configurable # print(f"DEBUG: lib.robot.writer _DataFileWritter write_table empty_row table={table.type}") - if table.type == 'variable' and len(list(table)[-1].as_list()) == 0: - # DEBUG: This is workaround for newline being added ALWAYS to VariableTable - return + try: + if table.type == 'variable' and len(list(table)[-1].as_list()) == 0: + # DEBUG: This is workaround for newline being added ALWAYS to VariableTable + return + except IndexError: + pass self._write_empty_row(table) def _write_header(self, table): diff --git a/src/robotide/version.py b/src/robotide/version.py index 92faca02a..5fe319ba9 100644 --- a/src/robotide/version.py +++ b/src/robotide/version.py @@ -14,4 +14,4 @@ # limitations under the License. # # Automatically generated by `tasks.py`. -VERSION = 'v2.0.8dev28' +VERSION = 'v2.0.8dev29' From 28a632289969047f976334e730b249d1b53f356b Mon Sep 17 00:00:00 2001 From: HelioGuilherme66 Date: Mon, 30 Oct 2023 00:45:26 +0000 Subject: [PATCH 6/9] Add comment on Release Notes about unstable saving from Text Editor --- src/robotide/application/releasenotes.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/robotide/application/releasenotes.py b/src/robotide/application/releasenotes.py index 6dda5e686..9cfafa48e 100644 --- a/src/robotide/application/releasenotes.py +++ b/src/robotide/application/releasenotes.py @@ -152,6 +152,8 @@ def set_content(self, html_win, content):
  • This version supports Python 3.6 up to 3.11.
  • There are some changes, or known issues:
      +
    • Saving on Text Editor by pressing Ctrl-S must be done twice, file may stay with modified indication. Confirm if file +changes when pressing Apply or by moving to the Editor tab.
    • On Text Editor, pressing Ctrl when the caret/cursor is near a Keyword will show a detachable window with the documentation, at Mouse Pointer position.
    • RIDE tray icon now shows a context menu with options Show, Hide and Close.
    • Highlighting and navigation of selected Project Explorer items, in Text Editor.
    • From 8940a3c3fd88baa8c92e6140c7921e991e548f3f Mon Sep 17 00:00:00 2001 From: HelioGuilherme66 Date: Tue, 31 Oct 2023 02:44:44 +0000 Subject: [PATCH 7/9] More debug of changes detection on Save from Text Editor --- src/robotide/controller/project.py | 5 +- src/robotide/editor/texteditor.py | 102 +++++++++++++++++++---------- 2 files changed, 72 insertions(+), 35 deletions(-) diff --git a/src/robotide/controller/project.py b/src/robotide/controller/project.py index edff51dda..388bcea07 100644 --- a/src/robotide/controller/project.py +++ b/src/robotide/controller/project.py @@ -119,7 +119,10 @@ def new_resource(self, path, parent=None): def load_data(self, path, load_observer=None): from robotide.context import APP - robot_version = APP.robot_version + try: + robot_version = APP.robot_version + except AttributeError: + robot_version = b'6.1.1' # It is failing at unit tests print(f"DEBUG: project.py Project ENTER robot version = {robot_version}") load_observer = load_observer or NullObserver() if self._load_initfile(path, load_observer): diff --git a/src/robotide/editor/texteditor.py b/src/robotide/editor/texteditor.py index 5aaa6288f..6c2637b29 100644 --- a/src/robotide/editor/texteditor.py +++ b/src/robotide/editor/texteditor.py @@ -29,8 +29,8 @@ from ..controller.macrocontrollers import WithStepsController from ..namespace.suggesters import SuggestionSource from ..pluginapi import Plugin, action_info_collection, TreeAwarePluginMixin -from ..publish.messages import (RideSaving, RideTreeSelection, RideNotebookTabChanging, RideDataChanged, RideOpenSuite, - RideDataChangedToDirty) +from ..publish.messages import (RideSaved, RideTreeSelection, RideNotebookTabChanging, RideDataChanged, RideOpenSuite, + RideDataChangedToDirty, RideBeforeSaving, RideSaving, RideDataDirtyCleared) from ..preferences.editors import read_fonts from ..publish import RideSettingsChanged, PUBLISHER from ..publish.messages import RideMessage @@ -54,6 +54,7 @@ def __init__(self, application): Plugin.__init__(self, application) self._editor_component = None self._tab = None + self._save_flag = 0 # See self.reformat = application.settings.get('reformat', False) self._register_shortcuts() @@ -116,6 +117,7 @@ def on_open(self, event): def _open(self): datafile_controller = self.tree.get_selected_datafile_controller() if datafile_controller: + self._save_flag = 0 if hasattr(datafile_controller, 'preamble'): # DEBUG: Is failing at resource files print(f"DEBUG: texteditor _open preamble={datafile_controller.preamble}") self._open_data_for_controller(datafile_controller) @@ -123,11 +125,17 @@ def _open(self): def on_saving(self, message): _ = message + print(f"DEBUG: textedit OnSaving ENTER {message=}") + return if self.is_focused(): - self._editor.is_saving = False - self._editor.content_save() + if not self._editor.is_saving: + print(f"DEBUG: textedit OnSaving FOCUSED {message} saving={self._editor.is_saving}") + self._apply_txt_changes_to_model() + else: + self._editor.is_saving = False + # # message.Skip() elif isinstance(message, RideSaving): - # print(f"DEBUG: textedit OnSaving Open Saved from other {message=} isfocused={self.is_focused()}") + print(f"DEBUG: textedit OnSaving Open Saved from other {message=} isfocused={self.is_focused()}") self._open() # Was saved from other Editor def on_data_changed(self, message): @@ -140,7 +148,32 @@ def on_data_changed(self, message): self._editor.set_editor_caret_position() if isinstance(message, RideNotebookTabChanging): return - if self._editor.dirty and not self._apply_txt_changes_to_model(): + if self.is_focused() and self._save_flag == 0 and isinstance(message, RideSaving): # Workaround for remarked dirty with Ctrl-S + self._save_flag = 1 + print(f"DEBUG: textedit on_data_changed FOCUSED {message} {self._save_flag=}") + return + if self.is_focused() and self._save_flag == 1 and isinstance(message, RideDataDirtyCleared): + self._save_flag = 2 + print(f"DEBUG: textedit on_data_changed FOCUSED {message} {self._save_flag=}") + return + if self.is_focused() and self._save_flag == 2 and isinstance(message, RideSaved): + self._save_flag = 3 + wx.CallAfter(self._editor.mark_file_dirty, False) + print(f"DEBUG: textedit on_data_changed FOCUSED {message} {self._save_flag=}") + return + if self.is_focused() and self._save_flag == 3 and isinstance(message, RideDataChangedToDirty): + self._save_flag = 4 + wx.CallAfter(self._editor.mark_file_dirty, False) + print(f"DEBUG: textedit on_data_changed FOCUSED {message} mark_file_dirty(False)") + return + if self.is_focused() and isinstance(message, RideBeforeSaving): # or isinstance(message, RideSaving)): + print(f"DEBUG: textedit on_data_changed FOCUSED {message} saving={self._editor.is_saving}\n" + f"dirty={self._editor.dirty}") + self._editor.is_saving = False + # Prepare counter for Workaround for remarked dirty with Ctrl-S + self._save_flag = 0 + self._apply_txt_changes_to_model() + # if self._editor.dirty and not self._apply_txt_changes_to_model(): return self._refresh_timer.Start(500, True) # For performance reasons only run after all the data changes @@ -154,8 +187,8 @@ def _on_timer(self, event): @staticmethod def _should_process_data_changed_message(message): - return isinstance(message, RideDataChanged) and \ - not isinstance(message, RideDataChangedToDirty) + return isinstance(message, (RideDataChanged, RideBeforeSaving, RideSaved, RideSaving, + RideDataChangedToDirty, RideDataDirtyCleared)) def on_tree_selection(self, message): self._editor.store_position() @@ -203,7 +236,7 @@ def on_tab_change(self, message): if message.newtab == self.title: self._open() self._editor.set_editor_caret_position() - self._editor._dirty = 1 + # self._editor._dirty = 1 try: self._set_read_only(self._editor.source_editor.readonly) except Exception as e: # DEBUG: When using only Text Editor exists error in message topic @@ -212,7 +245,7 @@ def on_tab_change(self, message): self._editor.remove_and_store_state() self._editor_component.is_saving = False self._editor_component.content_save() - self._editor._dirty = 0 + # self._editor._dirty = 0 def on_tab_changed(self, event): _ = event @@ -390,7 +423,7 @@ def __init__(self, plugin, parent, title, data_validator): self.reformat = self.source_editor_parent.app.settings.get('reformat', False) self._create_ui(title) self._data = None - self._dirty = 1 # 0 is False and 1 is True, when changed on this editor + # self._dirty = 1 # 0 is False and 1 is True, when changed on this editor self._position = 0 # Start at 0 if first time access self.restore_start_pos = self._position self.restore_end_pos = self._position @@ -528,8 +561,9 @@ def set_editor_caret_position(self): @property def dirty(self): - return self._dirty == 1 and (self._data.wrapper_data.is_dirty or self.source_editor.IsModified()) + # return self._dirty == 1 and (self._data.wrapper_data.is_dirty or self.source_editor.IsModified()) # return self._dirty == 1 # self.source_editor.IsModified() and self._dirty == 1 + return self._data.wrapper_data.is_dirty or self.source_editor.IsModified() @property def datafile_controller(self): @@ -812,9 +846,9 @@ def write_ident(self): self.source_editor.WriteText(spaces) def reset(self): - self._dirty = 0 + # self._dirty = 0 if self._data and not self._data.wrapper_data.is_dirty: - self._mark_file_dirty(False) + self.mark_file_dirty(False) def content_save(self, *args): _ = args @@ -917,7 +951,7 @@ def on_key(self, *args): def cut(self): self.source_editor.Cut() - self._mark_file_dirty(self.source_editor.GetModify()) + self.mark_file_dirty(self.source_editor.GetModify()) def copy(self): self.source_editor.Copy() @@ -926,7 +960,7 @@ def paste(self): focus = wx.Window.FindFocus() if focus == self.source_editor: self.source_editor.Paste() - self._mark_file_dirty(self.source_editor.GetModify()) + self.mark_file_dirty(self.source_editor.GetModify()) def select_all(self): self.source_editor.SelectAll() @@ -934,12 +968,12 @@ def select_all(self): def undo(self): self.source_editor.Undo() self.store_position() - self._mark_file_dirty(self.source_editor.GetModify()) # self._dirty == 1 and + self.mark_file_dirty(self.source_editor.GetModify()) # self._dirty == 1 and def redo(self): self.source_editor.Redo() self.store_position() - self._mark_file_dirty(self.source_editor.GetModify()) + self.mark_file_dirty(self.source_editor.GetModify()) def remove_and_store_state(self): if self.source_editor: @@ -987,7 +1021,7 @@ def on_editor_key(self, event): return keycode = event.GetKeyCode() keyvalue = event.GetUnicodeKey() - self._dirty = 1 + # self._dirty = 1 # print(f"DEBUG: TextEditor key up focused={self.is_focused()} modify {self.source_editor.GetModify()}") if keycode == wx.WXK_DELETE: # DEBUG on Windows we only get here, single Text Editor selected = self.source_editor.GetSelection() @@ -997,14 +1031,14 @@ def on_editor_key(self, event): self.source_editor.DeleteRange(selected[0], 1) else: self.source_editor.DeleteRange(selected[0], selected[1] - selected[0]) - self._mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.IsModified()) if keycode in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]: - self._mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.IsModified()) return if keyvalue == wx.WXK_NONE and keycode in [wx.WXK_CONTROL, wx.WXK_RAW_CONTROL]: self.source_editor.hide_kw_doc() if self.is_focused(): # DEBUG and keycode != wx.WXK_CONTROL and keyvalue >= ord(' ') and self.dirty: - self._mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.IsModified()) event.Skip() def on_key_down(self, event): @@ -1021,10 +1055,10 @@ def on_key_down(self, event): return keycode = event.GetUnicodeKey() raw_key = event.GetKeyCode() - self._dirty = 1 + # self._dirty = 1 # print(f"DEBUG: TextEditor on_key_down event={event} raw_key={raw_key} wx.WXK_C ={wx.WXK_CONTROL}") if event.GetKeyCode() == wx.WXK_DELETE: - self._mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.IsModified()) return if raw_key != wx.WXK_CONTROL: # We need to clear doc as soon as possible self.source_editor.hide_kw_doc() @@ -1033,14 +1067,14 @@ def on_key_down(self, event): self._showing_list = False wx.CallAfter(self.write_ident) # DEBUG: Make this configurable? event.Skip() - self._mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.IsModified()) return selected = self.source_editor.GetSelection() if selected[0] == selected[1]: self.write_ident() else: self.indent_block() - self._mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.IsModified()) elif event.GetKeyCode() == wx.WXK_TAB and event.ShiftDown(): selected = self.source_editor.GetSelection() if selected[0] == selected[1]: @@ -1052,7 +1086,7 @@ def on_key_down(self, event): self.source_editor.SetSelection(pos, pos) else: self.deindent_block() - self._mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.IsModified()) elif event.GetKeyCode() in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]: if not self._showing_list: self.auto_indent() @@ -1060,16 +1094,16 @@ def on_key_down(self, event): self._showing_list = False wx.CallAfter(self.write_ident) # DEBUG: Make this configurable? event.Skip() - self._mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.IsModified()) elif keycode in (ord('1'), ord('2'), ord('5')) and event.ControlDown(): self.execute_variable_creator(list_variable=(keycode == ord('2')), dict_variable=(keycode == ord('5'))) self.store_position() - self._mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.IsModified()) elif (not IS_WINDOWS and not IS_MAC and keycode in (ord('v'), ord('V')) and event.ControlDown() and not event.ShiftDown()): # We need to ignore this in Linux, because it does double-action - self._mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.IsModified()) return elif keycode in (ord('g'), ord('G')) and event.ControlDown(): if event.ShiftDown(): @@ -1079,7 +1113,7 @@ def on_key_down(self, event): return elif keycode in (ord('d'), ord('D')) and event.ControlDown() and not event.ShiftDown(): # We need to ignore because Scintilla does Duplicate line - self._mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.IsModified()) return elif event.ControlDown() and raw_key == wx.WXK_CONTROL: # This must be the last branch to activate actions before doc @@ -1088,7 +1122,7 @@ def on_key_down(self, event): event.Skip() else: # if self.dirty and keycode >= ord(' '): - self._mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.IsModified()) event.Skip() # These commands are duplicated by global actions @@ -1784,10 +1818,10 @@ def on_settings_changed(self, message): if setting == 'reformat': self.reformat = self.source_editor_parent.app.settings.get('reformat', False) - def _mark_file_dirty(self, dirty=True): + def mark_file_dirty(self, dirty=True): if not self.is_focused(): # DEBUG: Was marking file clean from Grid Editor return - if self._data and self._dirty == 1: + if self._data: # and self._dirty == 1: if dirty: self._data.mark_data_dirty() else: From b8a60d770935e12567195d5e4f0422e41f999c2e Mon Sep 17 00:00:00 2001 From: HelioGuilherme66 Date: Wed, 1 Nov 2023 00:22:28 +0000 Subject: [PATCH 8/9] Fix modified after saved from Text Editor --- src/robotide/editor/texteditor.py | 61 +++++++++++++------------------ 1 file changed, 25 insertions(+), 36 deletions(-) diff --git a/src/robotide/editor/texteditor.py b/src/robotide/editor/texteditor.py index 6c2637b29..ad1afe8fa 100644 --- a/src/robotide/editor/texteditor.py +++ b/src/robotide/editor/texteditor.py @@ -143,38 +143,27 @@ def on_data_changed(self, message): try: # print(f"DEBUG: textedit OnDataChanged message={message}") if self._should_process_data_changed_message(message): - if isinstance(message, RideOpenSuite): + if isinstance(message, RideOpenSuite): # Not reached self._editor.reset() self._editor.set_editor_caret_position() - if isinstance(message, RideNotebookTabChanging): + if isinstance(message, RideNotebookTabChanging): # Not reached return if self.is_focused() and self._save_flag == 0 and isinstance(message, RideSaving): # Workaround for remarked dirty with Ctrl-S self._save_flag = 1 - print(f"DEBUG: textedit on_data_changed FOCUSED {message} {self._save_flag=}") - return if self.is_focused() and self._save_flag == 1 and isinstance(message, RideDataDirtyCleared): self._save_flag = 2 - print(f"DEBUG: textedit on_data_changed FOCUSED {message} {self._save_flag=}") - return if self.is_focused() and self._save_flag == 2 and isinstance(message, RideSaved): self._save_flag = 3 wx.CallAfter(self._editor.mark_file_dirty, False) - print(f"DEBUG: textedit on_data_changed FOCUSED {message} {self._save_flag=}") - return - if self.is_focused() and self._save_flag == 3 and isinstance(message, RideDataChangedToDirty): - self._save_flag = 4 - wx.CallAfter(self._editor.mark_file_dirty, False) - print(f"DEBUG: textedit on_data_changed FOCUSED {message} mark_file_dirty(False)") - return - if self.is_focused() and isinstance(message, RideBeforeSaving): # or isinstance(message, RideSaving)): - print(f"DEBUG: textedit on_data_changed FOCUSED {message} saving={self._editor.is_saving}\n" - f"dirty={self._editor.dirty}") + # DEBUG: This is the unwanted chnge after saving but excluded in this block for performance + # if self.is_focused() and self._save_flag == 3 and isinstance(message, RideDataChangedToDirty): + # self._save_flag = 4 + # wx.CallAfter(self._editor.mark_file_dirty, False) + if self.is_focused() and isinstance(message, RideBeforeSaving): self._editor.is_saving = False - # Prepare counter for Workaround for remarked dirty with Ctrl-S + # Reset counter for Workaround for remarked dirty with Ctrl-S self._save_flag = 0 self._apply_txt_changes_to_model() - # if self._editor.dirty and not self._apply_txt_changes_to_model(): - return self._refresh_timer.Start(500, True) # For performance reasons only run after all the data changes except AttributeError: @@ -187,8 +176,8 @@ def _on_timer(self, event): @staticmethod def _should_process_data_changed_message(message): - return isinstance(message, (RideDataChanged, RideBeforeSaving, RideSaved, RideSaving, - RideDataChangedToDirty, RideDataDirtyCleared)) + return isinstance(message, (RideDataChanged, RideBeforeSaving, RideSaved, RideSaving, RideDataDirtyCleared))\ + and not isinstance(message, RideDataChangedToDirty) def on_tree_selection(self, message): self._editor.store_position() @@ -561,9 +550,9 @@ def set_editor_caret_position(self): @property def dirty(self): - # return self._dirty == 1 and (self._data.wrapper_data.is_dirty or self.source_editor.IsModified()) - # return self._dirty == 1 # self.source_editor.IsModified() and self._dirty == 1 - return self._data.wrapper_data.is_dirty or self.source_editor.IsModified() + # return self._dirty == 1 and (self._data.wrapper_data.is_dirty or self.source_editor.GetModify()) + # return self._dirty == 1 # self.source_editor.GetModify() and self._dirty == 1 + return self._data.wrapper_data.is_dirty # or self.source_editor.GetModify() @property def datafile_controller(self): @@ -1031,14 +1020,14 @@ def on_editor_key(self, event): self.source_editor.DeleteRange(selected[0], 1) else: self.source_editor.DeleteRange(selected[0], selected[1] - selected[0]) - self.mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.GetModify()) if keycode in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]: - self.mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.GetModify()) return if keyvalue == wx.WXK_NONE and keycode in [wx.WXK_CONTROL, wx.WXK_RAW_CONTROL]: self.source_editor.hide_kw_doc() if self.is_focused(): # DEBUG and keycode != wx.WXK_CONTROL and keyvalue >= ord(' ') and self.dirty: - self.mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.GetModify()) event.Skip() def on_key_down(self, event): @@ -1058,7 +1047,7 @@ def on_key_down(self, event): # self._dirty = 1 # print(f"DEBUG: TextEditor on_key_down event={event} raw_key={raw_key} wx.WXK_C ={wx.WXK_CONTROL}") if event.GetKeyCode() == wx.WXK_DELETE: - self.mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.GetModify()) return if raw_key != wx.WXK_CONTROL: # We need to clear doc as soon as possible self.source_editor.hide_kw_doc() @@ -1067,14 +1056,14 @@ def on_key_down(self, event): self._showing_list = False wx.CallAfter(self.write_ident) # DEBUG: Make this configurable? event.Skip() - self.mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.GetModify()) return selected = self.source_editor.GetSelection() if selected[0] == selected[1]: self.write_ident() else: self.indent_block() - self.mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.GetModify()) elif event.GetKeyCode() == wx.WXK_TAB and event.ShiftDown(): selected = self.source_editor.GetSelection() if selected[0] == selected[1]: @@ -1086,7 +1075,7 @@ def on_key_down(self, event): self.source_editor.SetSelection(pos, pos) else: self.deindent_block() - self.mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.GetModify()) elif event.GetKeyCode() in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]: if not self._showing_list: self.auto_indent() @@ -1094,16 +1083,16 @@ def on_key_down(self, event): self._showing_list = False wx.CallAfter(self.write_ident) # DEBUG: Make this configurable? event.Skip() - self.mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.GetModify()) elif keycode in (ord('1'), ord('2'), ord('5')) and event.ControlDown(): self.execute_variable_creator(list_variable=(keycode == ord('2')), dict_variable=(keycode == ord('5'))) self.store_position() - self.mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.GetModify()) elif (not IS_WINDOWS and not IS_MAC and keycode in (ord('v'), ord('V')) and event.ControlDown() and not event.ShiftDown()): # We need to ignore this in Linux, because it does double-action - self.mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.GetModify()) return elif keycode in (ord('g'), ord('G')) and event.ControlDown(): if event.ShiftDown(): @@ -1113,7 +1102,7 @@ def on_key_down(self, event): return elif keycode in (ord('d'), ord('D')) and event.ControlDown() and not event.ShiftDown(): # We need to ignore because Scintilla does Duplicate line - self.mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.GetModify()) return elif event.ControlDown() and raw_key == wx.WXK_CONTROL: # This must be the last branch to activate actions before doc @@ -1122,7 +1111,7 @@ def on_key_down(self, event): event.Skip() else: # if self.dirty and keycode >= ord(' '): - self.mark_file_dirty(self.source_editor.IsModified()) + self.mark_file_dirty(self.source_editor.GetModify()) event.Skip() # These commands are duplicated by global actions From f5e0496c960364305b42e2e6878713a10f1aa1e5 Mon Sep 17 00:00:00 2001 From: HelioGuilherme66 Date: Wed, 1 Nov 2023 01:17:35 +0000 Subject: [PATCH 9/9] Clean up to prepare release. --- CHANGELOG.adoc | 1 + src/robotide/application/CHANGELOG.html | 2 ++ src/robotide/application/releasenotes.py | 5 ++--- src/robotide/controller/project.py | 2 ++ src/robotide/editor/texteditor.py | 19 ++----------------- 5 files changed, 9 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 5e0a08438..3ad4d271b 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -23,6 +23,7 @@ Force Tags settings, after Robot Framework 7.0 === Fixed +- - Fixed resource files dissapearing from Project tree on Windows - Fixed missing indication of link for User Keyword, when pressing ``Ctrl`` in Grid Editor - Fixed exception when finding GREY color for excluded files and directories in Project Tree diff --git a/src/robotide/application/CHANGELOG.html b/src/robotide/application/CHANGELOG.html index ebe021677..7c1dc7a2d 100644 --- a/src/robotide/application/CHANGELOG.html +++ b/src/robotide/application/CHANGELOG.html @@ -20,6 +20,8 @@
    • Added support for JSON variables, by using the installed Robot Framework import method

    1.2. Fixed

    • +Fixed escaped spaces showing in Text Editor on commented cells +
    • Fixed resource files dissapearing from Project tree on Windows
    • Fixed missing indication of link for User Keyword, when pressing ``Ctrl`` in Grid Editor diff --git a/src/robotide/application/releasenotes.py b/src/robotide/application/releasenotes.py index 9cfafa48e..391d83e3b 100644 --- a/src/robotide/application/releasenotes.py +++ b/src/robotide/application/releasenotes.py @@ -152,8 +152,6 @@ def set_content(self, html_win, content):
      • This version supports Python 3.6 up to 3.11.
      • There are some changes, or known issues:
          -
        • Saving on Text Editor by pressing Ctrl-S must be done twice, file may stay with modified indication. Confirm if file -changes when pressing Apply or by moving to the Editor tab.
        • On Text Editor, pressing Ctrl when the caret/cursor is near a Keyword will show a detachable window with the documentation, at Mouse Pointer position.
        • RIDE tray icon now shows a context menu with options Show, Hide and Close.
        • Highlighting and navigation of selected Project Explorer items, in Text Editor.
        • @@ -170,6 +168,7 @@ def set_content(self, html_win, content):

        New Features and Fixes Highlights

          +
        • Fixed escaped spaces showing in Text Editor on commented cells
        • Improved keywords documentation search, by adding current dir to search
        • Improved Move up/down, Alt-UpArrow/Alt-DownArrow in Text Editor, to have proper indentation and selection
        • Added auto update check when development version is installed
        • @@ -250,6 +249,6 @@ def set_content(self, html_win, content):
           python -m robotide.postinstall -install
           
          -

          RIDE {VERSION} was released on 29/Oct/2023.

          +

          RIDE {VERSION} was released on 1/Nov/2023.

    """ diff --git a/src/robotide/controller/project.py b/src/robotide/controller/project.py index 388bcea07..d11b21e8e 100644 --- a/src/robotide/controller/project.py +++ b/src/robotide/controller/project.py @@ -118,12 +118,14 @@ def new_resource(self, path, parent=None): return resource_controller def load_data(self, path, load_observer=None): + """ DEBUG: To be used in Localization from robotide.context import APP try: robot_version = APP.robot_version except AttributeError: robot_version = b'6.1.1' # It is failing at unit tests print(f"DEBUG: project.py Project ENTER robot version = {robot_version}") + """ load_observer = load_observer or NullObserver() if self._load_initfile(path, load_observer): return diff --git a/src/robotide/editor/texteditor.py b/src/robotide/editor/texteditor.py index ad1afe8fa..7a454c64e 100644 --- a/src/robotide/editor/texteditor.py +++ b/src/robotide/editor/texteditor.py @@ -71,7 +71,6 @@ def _editor(self): def enable(self): self._tab = self._editor self.register_actions(action_info_collection(_EDIT, self._tab, self._tab)) - # DEBUG Disable own saving self.subscribe(self.on_saving, RideSaving) self.subscribe(self.on_tree_selection, RideTreeSelection) self.subscribe(self.on_data_changed, RideMessage) self.subscribe(self.on_tab_change, RideNotebookTabChanging) @@ -92,7 +91,6 @@ def f(event): self.register_shortcut('CtrlCmd-A', focused(lambda e: self._editor.select_all())) # No system needs this key binding, because is already global # self.register_shortcut('CtrlCmd-V', focused(lambda e: self._editor.paste())) - # self.register_shortcut('CtrlCmd-S', focused(lambda e: self.on_saving(e))) self.register_shortcut('CtrlCmd-F', focused(lambda e: self._editor.search_field.SetFocus())) # To avoid double actions these moved to on_key_down # self.register_shortcut('CtrlCmd-G', focused(lambda e: self._editor.on_find(e))) @@ -118,26 +116,13 @@ def _open(self): datafile_controller = self.tree.get_selected_datafile_controller() if datafile_controller: self._save_flag = 0 + """ DEBUG: To be used in Localization if hasattr(datafile_controller, 'preamble'): # DEBUG: Is failing at resource files print(f"DEBUG: texteditor _open preamble={datafile_controller.preamble}") self._open_data_for_controller(datafile_controller) + """ self._editor.store_position() - def on_saving(self, message): - _ = message - print(f"DEBUG: textedit OnSaving ENTER {message=}") - return - if self.is_focused(): - if not self._editor.is_saving: - print(f"DEBUG: textedit OnSaving FOCUSED {message} saving={self._editor.is_saving}") - self._apply_txt_changes_to_model() - else: - self._editor.is_saving = False - # # message.Skip() - elif isinstance(message, RideSaving): - print(f"DEBUG: textedit OnSaving Open Saved from other {message=} isfocused={self.is_focused()}") - self._open() # Was saved from other Editor - def on_data_changed(self, message): """ This block is now inside try/except to avoid errors from unit test """ try: