From 448e049d9770dd6c86e32a6a9d9a11d71f010113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9lio=20Guilherme?= Date: Thu, 5 Oct 2023 22:37:47 +0100 Subject: [PATCH] Text editor fixes (#2647) * Fixes missing Ctrl-D action and improves other key actions in Text Editor * Fix not saving when changing tab from Text Editor * Improve content assistance in Text Editor --- CHANGELOG.adoc | 1 + src/robotide/application/CHANGELOG.html | 3 +- src/robotide/application/releasenotes.py | 3 +- src/robotide/editor/__init__.py | 3 +- src/robotide/editor/texteditor.py | 96 +++++++++--------------- src/robotide/version.py | 2 +- 6 files changed, 42 insertions(+), 66 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index f447232b6..cc8d81974 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -29,6 +29,7 @@ and this project adheres to http://semver.org/spec/v2.0.0.html[Semantic Versioni === Changed +- Improved content assistance in Text Editor by allowing to filter list as we type - Improved file changes detection to only consider valid formats - Improved keyword ``Find Usages`` to return more matches. Fails to find mixed spaces and ``_`` - In Grid Editor ``Ctrl-Shift-4`` now replaces escaped spaces ``\\ `` by spaces diff --git a/src/robotide/application/CHANGELOG.html b/src/robotide/application/CHANGELOG.html index 30625c483..b7b4ae49b 100644 --- a/src/robotide/application/CHANGELOG.html +++ b/src/robotide/application/CHANGELOG.html @@ -11,7 +11,8 @@
  • Added support for JSON variables, by using the installed Robot Framework import method
  • 1.2. Fixed

      -
    • Fixed resource files dissapearing from Project tree on Windows +
    • Improved content assistance in Text Editor by allowing to filter list as we type +
    • 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 6a335d87a..e37a7220e 100644 --- a/src/robotide/application/releasenotes.py +++ b/src/robotide/application/releasenotes.py @@ -168,6 +168,7 @@ def set_content(self, html_win, content):

    New Features and Fixes Highlights

      +
    • Improved content assistance in Text Editor by allowing to filter list as we type
    • Fixed resource files dissapearing from Project tree on Windows
    • Fixed missing indication of link for User Keyword, when pressing Ctrl in Grid Editor
    • Added content help pop-up on Text Editor by pressing Ctrl for text at cursor position or selected autocomplete list item
    • @@ -239,6 +240,6 @@ def set_content(self, html_win, content):
       python -m robotide.postinstall -install
       
      -

      RIDE {VERSION} was released on 23/Sep/2023.

      +

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

    """ diff --git a/src/robotide/editor/__init__.py b/src/robotide/editor/__init__.py index 97e065b18..499766e5f 100644 --- a/src/robotide/editor/__init__.py +++ b/src/robotide/editor/__init__.py @@ -143,7 +143,7 @@ def on_tab_changed(self, message): self._show_editor() def on_tab_changing(self, message): - if 'Edit' in message.oldtab: + if 'Editor' in message.oldtab: self._tab.save() def on_save_to_model(self, message): @@ -230,6 +230,7 @@ def on_insert_rows(self, event): def on_delete_rows(self, event): _ = event + print(f"DEBUG: Editor __ini__ called {event}") wx.CallAfter(self.editor.delete_rows) def on_move_rows_up(self, event): diff --git a/src/robotide/editor/texteditor.py b/src/robotide/editor/texteditor.py index 1998dc4bc..be5b510f4 100644 --- a/src/robotide/editor/texteditor.py +++ b/src/robotide/editor/texteditor.py @@ -225,13 +225,6 @@ def on_tab_change(self, message): print(e) elif message.oldtab == self.title: self._editor.remove_and_store_state() - """ - try: - self.unregister_actions() - print("DEBUG: texteditor on_tab_change after called unregister_actions ") - except Exception as e: - print(e) - """ self._editor_component.is_saving = False self._editor_component.content_save() @@ -240,7 +233,7 @@ def on_tab_changed(self, event): self._show_editor() def on_tab_changing(self, message): - if 'Edit' in message.oldtab: + if 'Editor' in message.oldtab: self._editor.is_saving = False self._editor.content_save() @@ -426,7 +419,7 @@ def __init__(self, plugin, parent, title, data_validator): self.restore_anchor = self._position self._showing_list = False self.autocomp_pos = None - self._tab_open = None + self._tab_open = self._title # When starting standalone this was not being set self._controller_for_context = None self._suggestions = None self._stored_text = None @@ -644,6 +637,8 @@ def on_content_assist(self, event): :param event: Not used :return: """ + if not self.is_focused(): # DEBUG was typing text when at Grid Editor + return _ = event if self._showing_list: self._showing_list = False # Avoid double calls @@ -652,19 +647,23 @@ def on_content_assist(self, event): selected = self.source_editor.get_selected_or_near_text() self.set_editor_caret_position() sugs = [] + length_entered = 0 if selected: for start in selected: sugs.extend(s.name for s in self._suggestions.get_suggestions(start)) # DEBUG: Here, if sugs is still [], then we can get all words from line and repeat suggestions # In another evolution, we can use database of words by frequency (considering future by project db) + sel = [s for s in selected] if selected else [] + entry_word = sel[0].split('.')[-1].strip() + length_entered = len(entry_word) # Because Libraries prefixed sugs.extend(s.name for s in self._suggestions.get_suggestions('')) if len(sugs) > 0: sugs = [s for s in sugs if s != ''] if sugs: - self.source_editor.AutoCompSetDropRestOfWord(True) + self.source_editor.AutoCompSetDropRestOfWord(False) self.source_editor.AutoCompSetIgnoreCase(True) self.source_editor.AutoCompSetSeparator(ord(';')) - self.source_editor.AutoCompShow(0, ";".join(sugs)) + self.source_editor.AutoCompShow(length_entered, ";".join(sugs)) self.autocomp_pos = self.source_editor.AutoCompPosStart() self._showing_list = True # DEBUG: self.set_editor_caret_position() @@ -842,16 +841,12 @@ def reset(self): def content_save(self, *args): _ = args - if self.is_focused(): - self.store_position() - if self.dirty and not self.is_saving: - self.is_saving = True - if not self._data_validator.validate_and_update(self._data, self.source_editor.utf8_text): - self.is_saving = False - return False - # DEBUG: Was resetting when leaving editor - # if self.is_focused(): - self.reset() + self.store_position() + if self.dirty and not self.is_saving: + self.is_saving = True + if not self._data_validator.validate_and_update(self._data, self.source_editor.utf8_text): + self.is_saving = False + return False self.GetFocus(None) return True @@ -890,15 +885,15 @@ def on_paste(self, event): _ = event self.paste() - def on_insert(self, event): + @staticmethod + def on_insert(event): _ = event - print(f"DEBUG: TextEditor called on_insert event={event}") + print(f"DEBUG: TextEditor called on_insert event={event}\n TO BE IMPLEMENTED") # self.insert_row() - def on_delete(self, event): - _ = event - # print(f"DEBUG: TextEditor called on_delete event={event}") - # self.delete() + @staticmethod + def on_delete(self, event=None): + """ Not used """ def on_insert_cells(self, event): self.insert_cell(event) @@ -1052,14 +1047,12 @@ def on_key_down(self, event): # 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: return - if self._showing_list: - print(f"DEBUG: textedit on_key_down at autocmoplete, caret={self.autocomp_pos}" - f" text is={self.source_editor.AutoCompComplete()}") if raw_key != wx.WXK_CONTROL: # We need to clear doc as soon as possible self.source_editor.hide_kw_doc() if event.GetKeyCode() == wx.WXK_TAB and not event.ControlDown() and not event.ShiftDown(): if self._showing_list: # Allows to use Tab for keyword selection self._showing_list = False + wx.CallAfter(self.write_ident) # DEBUG: Make this configurable? event.Skip() return selected = self.source_editor.GetSelection() @@ -1083,6 +1076,7 @@ def on_key_down(self, event): self.auto_indent() else: self._showing_list = False + wx.CallAfter(self.write_ident) # DEBUG: Make this configurable? event.Skip() elif keycode in (ord('1'), ord('2'), ord('5')) and event.ControlDown(): self.execute_variable_creator(list_variable=(keycode == ord('2')), @@ -1092,6 +1086,9 @@ def on_key_down(self, event): and event.ControlDown() and not event.ShiftDown()): # We need to ignore this in Linux, because it does double-action return + elif keycode in (ord('d'), ord('D')) and event.ControlDown() and not event.ShiftDown(): + # We need to ignore because Scintilla does Duplicate line + return elif event.ControlDown() and raw_key == wx.WXK_CONTROL: # This must be the last branch to activate actions before doc # DEBUG: coords = self._get_screen_coordinates() @@ -1259,23 +1256,15 @@ def move_row_down(self, event): def delete_row(self, event): _ = event start, end = self.source_editor.GetSelection() - cursor = self.source_editor.GetCurrentPos() ini_line = self.source_editor.LineFromPosition(start) - end_line = self.source_editor.LineFromPosition(end) - begpos = self.source_editor.PositionFromLine(ini_line) self.source_editor.SelectNone() if start == end: end_line = ini_line + else: + end_line = self.source_editor.LineFromPosition(end) for _ in range(ini_line, end_line + 1): self.source_editor.GotoLine(ini_line) self.source_editor.LineDelete() - # cursor position when doing block select is always the end of the selection - if ini_line != end_line: - self.source_editor.SetCurrentPos(begpos) - self.source_editor.SetAnchor(begpos) - else: - self.source_editor.SetCurrentPos(cursor) - self.source_editor.SetAnchor(cursor) self.store_position() def insert_row(self, event): @@ -1691,7 +1680,8 @@ def __init__(self, parent, readonly=False): self.Bind(stc.EVT_STC_UPDATEUI, self.on_update_ui) self.Bind(stc.EVT_STC_STYLENEEDED, self.on_style) self.Bind(stc.EVT_STC_ZOOM, self.on_zoom) - # DEBUG: self.Bind(wx.EVT_KEY_DOWN, self.on_key_pressed) + # DEBUG: + self.Bind(wx.EVT_KEY_DOWN, self.on_key_pressed) self.stylizer = RobotStylizer(self, self._settings, self.readonly) # register some images for use in the AutoComplete box. # self.RegisterImage(1, Smiles.GetBitmap()) # DEBUG was images. @@ -1715,14 +1705,13 @@ def hide_kw_doc(self): popup.hide() self._old_details = None - """ def on_key_pressed(self, event): if self.CallTipActive(): self.CallTipCancel() key = event.GetKeyCode() if key == 32 and event.ControlDown(): pos = self.GetCurrentPos() - print(f"DEBUG: TextEditor RobotDataEditor on_key_pressed pos={pos}") + # print(f"DEBUG: TextEditor RobotDataEditor on_key_pressed pos={pos}") # Tips if event.ShiftDown(): self.show_kw_doc() @@ -1735,25 +1724,8 @@ def on_key_pressed(self, event): ''' # Code completion else: - selected = self.get_selected_or_near_text(keep_cursor_pos=False) - sugs = [] - for start in selected: - sugs.extend(s.name for s in self.parent._suggestions.get_suggestions(start)) - if len(sugs) > 0: - sugs = [s for s in sugs if s != ''] - if sugs: - self.AutoCompSetDropRestOfWord(True) - self.AutoCompSetIgnoreCase(True) - self.AutoCompSetSeparator(ord(';')) - self.AutoCompShow(0, ";".join(sugs)) - else: - print(f"DEBUG: TextEditor RobotDataEditor ending, clear selection pos={pos}") - self.SetSelectionStart(pos) - self.SetSelectionEnd(pos) - self.SetInsertionPoint(pos) - else: - event.Skip() - """ + self.parent.on_content_assist(event) + event.Skip() def set_text(self, text): self.SetReadOnly(False) diff --git a/src/robotide/version.py b/src/robotide/version.py index 48a4f9d92..7a1a50030 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.8dev15' +VERSION = 'v2.0.8dev16'