Skip to content

Commit 59bbe28

Browse files
When saving in Text Editor the cursor remains at position
1 parent 7771dd6 commit 59bbe28

File tree

9 files changed

+63
-21
lines changed

9 files changed

+63
-21
lines changed

CHANGELOG.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ and this project adheres to http://semver.org/spec/v2.0.0.html[Semantic Versioni
1414
- Added on Text Editor, folding margin with markers style configurable with ``fold symbols`` in settings.cfg.
1515

1616
=== Changed
17+
- When saving in Text Editor, the cursor remains at position, instead of jumping to Tree selection.
1718
- Improved autocompletion lists, by using existing words in Test Suite file (still needs more improvements).
1819
- Create directories when needed in New Project dialog.
1920
- Improved the recognition of BDD/Gherkin prefixes when localized in autocomplete on Grid Editor.

README.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ Likewise, the current version of wxPython, is 4.2.2, but RIDE is known to work w
4040

4141
`pip install -U robotframework-ride`
4242

43-
(3.8 <= python <= 3.13) Install current development version (**2.2dev10**) with:
43+
(3.8 <= python <= 3.13) Install current development version (**2.2dev13**) with:
4444

4545
`pip install -U https://github.com/robotframework/RIDE/archive/develop.zip`
4646

src/robotide/application/CHANGELOG.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
</li><li class="listitem">
88
Added on Text Editor, folding margin with markers style configurable with ``fold symbols`` in settings.cfg.
99
</li></ul></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="_changed"></a>1.2. Changed</h3></div></div></div><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">
10+
When saving in Text Editor, the cursor remains at position, instead of jumping to Tree selection.
11+
</li><li class="listitem">
1012
Improved autocompletion lists, by using existing words in Test Suite file (still needs more improvements).
1113
</li><li class="listitem">
1214
Create directories when needed in New Project dialog.

src/robotide/application/releasenotes.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ def set_content(self, html_win, content):
168168
</ul>
169169
<p><strong>New Features and Fixes Highlights</strong></p>
170170
<ul class="simple">
171+
<li>When saving in Text Editor, the cursor remains at position, instead of jumping to Tree selection.</li>
171172
<li>Improved autocompletion lists, by using existing words in Test Suite file (still needs more improvements).</li>
172173
<li>Fixed not set text color on row labels in Grid Editor. Now the General <b>secondary foreground</b> is applied.</li>
173174
<li>Added on Text Editor, tab indentation markers and <b>tab markers</b> boolean setting with default <b>True</b>.</li>
@@ -233,7 +234,7 @@ def set_content(self, html_win, content):
233234
<pre class="literal-block">python -m robotide.postinstall -install</pre>
234235
<p>or</p>
235236
<pre class="literal-block">ride_postinstall.py -install</pre>
236-
<p>RIDE {VERSION} was released on 17/March/2025.</p>
237+
<p>RIDE {VERSION} was released on 22/March/2025.</p>
237238
<!-- <br/>
238239
<h3>May The Fourth Be With You!</h3>
239240
<h3>Celebrate the bank holiday, 10th June, Day of Portugal, Portuguese Communities and Camões!!</h3>

src/robotide/editor/texteditor.py

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ def read_language(content):
8888
def obtain_language(existing, content):
8989
try:
9090
set_lang = shared_memory.ShareableList(name="language")
91-
except AttributeError: # Unittests fails here
91+
except Exception as e: # AttributeError: # Unittests fails here
92+
print(f"DEBUG: texteditor.py obtain_language EXCEPTION: {e}")
9293
set_lang = []
9394
doc_lang = read_language(content)
9495
adoc_lang = []
@@ -384,6 +385,7 @@ def __init__(self, application):
384385
self._tab = None
385386
self._doc_language = None
386387
self._save_flag = 0
388+
self.jump = True
387389
self.reformat = application.settings.get('reformat', False)
388390
self._register_shortcuts()
389391

@@ -443,6 +445,7 @@ def on_open(self, event):
443445
self._open()
444446

445447
def _open(self):
448+
# print(f"DEBUG: texteditor.py TextEditorPlugin _open ENTER curpos={self._editor._position}")
446449
datafile_controller = self.tree.get_selected_datafile_controller()
447450
if datafile_controller:
448451
self._save_flag = 0
@@ -496,13 +499,16 @@ def _check_message(self, message: RideMessage) -> None:
496499
self._save_flag = 2
497500
if self.is_focused() and self._save_flag == 2 and isinstance(message, RideSaved):
498501
self._save_flag = 3
499-
wx.CallAfter(self._editor.mark_file_dirty, False)
502+
print(f"DEBUG: textedit.py TextEditorPlugin _check_message call undirty, {message}")
503+
# wx.CallAfter(self._editor.mark_file_dirty, False)
504+
self._editor.mark_file_dirty(False)
505+
self.tree._data_undirty(message)
500506
# DEBUG: This is the unwanted chnge after saving but excluded in this block for performance
501507
# if self.is_focused() and self._save_flag == 3 and isinstance(message, RideDataChangedToDirty):
502508
# self._save_flag = 4
503509
# wx.CallAfter(self._editor.mark_file_dirty, False)
504510
if isinstance(message, RideBeforeSaving):
505-
self._editor.is_saving = False
511+
# self._editor.is_saving = False
506512
# Reset counter for Workaround for remarked dirty with Ctrl-S
507513
self._save_flag = 0
508514
self._apply_txt_changes_to_model()
@@ -511,7 +517,7 @@ def on_data_changed(self, message):
511517
""" This block is now inside try/except to avoid errors from unit test """
512518
try:
513519
if self.is_focused() and isinstance(message, RideDataChangedToDirty):
514-
# print("DEBUG: textedit OnDataChanged returning RideDataChangedToDirty")
520+
# print(f"DEBUG: textedit OnDataChanged returning RideDataChangedToDirty {self._save_flag=}")
515521
return
516522
if self._should_process_data_changed_message(message):
517523
# print(f"DEBUG: textedit after _should_process_data_changed_message save_flag={self._save_flag}")
@@ -532,21 +538,29 @@ def _should_process_data_changed_message(message):
532538
# and not isinstance(message, RideDataChangedToDirty))
533539

534540
def on_tree_selection(self, message):
541+
if not self.is_focused():
542+
return
535543
# print(f"DEBUG: texteditor.py TextEditorPlugin on_tree_selection ENTER {message=} type={type(message.item)}")
536544
self._editor.store_position()
545+
# self.jump = True
537546
if self.is_focused():
538547
next_datafile_controller = message.item and message.item.datafile_controller
539548
if self._editor.datafile_controller == message.item.datafile_controller == next_datafile_controller:
540-
# print(f"DEBUG: OnTreeSelection Same FILE item type={type(message.item)}")
549+
# print(f"DEBUG: OnTreeSelection Same FILE item type={type(message.item)}\n"
550+
# f"value of {self._save_flag=}")
541551
self._editor.locate_tree_item(message.item)
552+
self.jump = True
542553
return
543554
if self._editor.dirty and not self._apply_txt_changes_to_model():
544555
if self._editor.datafile_controller != next_datafile_controller:
545556
self.tree.select_controller_node(self._editor.datafile_controller)
546557
self._editor.set_editor_caret_position()
547558
return
548559
if next_datafile_controller:
560+
self.jump = True
549561
self._open_data_for_controller(next_datafile_controller)
562+
# print(f"DEBUG: OnTreeSelection OTHER FILE item type={type(message.item)}\n"
563+
# f"value of {self._save_flag=}")
550564
wx.CallAfter(self._editor.locate_tree_item, message.item)
551565
self._set_read_only(message)
552566
self._editor.set_editor_caret_position()
@@ -588,7 +602,8 @@ def on_tab_change(self, message):
588602
self._set_read_only(self._editor.source_editor.readonly)
589603
except Exception as e: # DEBUG: When using only Text Editor exists error in message topic
590604
print(e)
591-
wx.CallAfter(self._editor.source_editor.on_style, None) # DEBUG Text Edit, styles were not applied
605+
# wx.CallAfter(self._editor.source_editor.on_style, None) # DEBUG Text Edit, styles were not applied
606+
self._editor.source_editor.on_style(None)
592607
self._editor.Refresh()
593608
elif message.oldtab == self.title:
594609
self._editor.remove_and_store_state()
@@ -600,8 +615,12 @@ def on_tab_changed(self, event):
600615
event.Skip()
601616

602617
def _apply_txt_changes_to_model(self):
603-
self._editor.is_saving = False
604-
# print(f"DEBUG: textedit.py _apply_txt_changes_to_model CALL content_save lang={self._doc_language}")
618+
if not self.is_focused() and not self._editor.dirty:
619+
return
620+
# self._editor.is_saving = False
621+
# self._editor.store_position()
622+
# print(f"DEBUG: textedit.py _apply_txt_changes_to_model CALL content_save lang={self._doc_language}"
623+
# f" curpos={self._editor._position}")
605624
if not self._editor.content_save(lang=self._doc_language):
606625
return False
607626
self._editor.reset()
@@ -945,7 +964,7 @@ def __init__(self, plugin, parent, title, data_validator):
945964
self._words_cache = set() # Actual cache of words to add to suggestions
946965
self._stored_text = None
947966
self._ctrl_action = None
948-
self.is_saving = False # To avoid double calls to save
967+
# self.is_saving = False # To avoid double calls to save
949968
self.old_information_popup = None
950969
PUBLISHER.subscribe(self.on_settings_changed, RideSettingsChanged)
951970
PUBLISHER.subscribe(self.on_tab_change, RideNotebookTabChanging)
@@ -1068,7 +1087,7 @@ def set_editor_caret_position(self):
10681087
return
10691088
position = self._position
10701089
self.source_editor.SetFocus()
1071-
# print(f"DEBUG: texteditor.py SourceEditor position={position}")
1090+
# print(f"DEBUG: texteditor.py SourceEditor set_editor_caret_position position={position}")
10721091
if position:
10731092
self.source_editor.SetCurrentPos(position)
10741093
self.source_editor.SetSelection(self.restore_start_pos, self.restore_end_pos)
@@ -1153,12 +1172,16 @@ def _show_search_results(self, position, txt):
11531172

11541173
def locate_tree_item(self, item):
11551174
""" item is object received from message """
1175+
if not self.plugin.jump:
1176+
self.plugin.jump = True
1177+
return
11561178
from wx.stc import STC_FIND_REGEXP
11571179
search_end = len(self.source_editor.utf8_text)
11581180
section_start = 0
11591181
name_to_locate = r'^'+item.name+r'.*$'
11601182
position = self.source_editor.FindText(section_start, search_end, name_to_locate, STC_FIND_REGEXP)
1161-
# print(f"DEBUG: TextEditor locate_tree_item name_to_locate={name_to_locate} position={position}")
1183+
# print(f"DEBUG: TextEditor locate_tree_item name_to_locate={name_to_locate} position={position}\n"
1184+
# f"curpos={self._position} {self.is_saving=}")
11621185
if position[0] != -1:
11631186
# DEBUG: Make colours configurable?
11641187
self.source_editor.SetSelBackground(True, Colour('orange'))
@@ -1320,7 +1343,7 @@ def open(self, data):
13201343
self.language = self._data._language
13211344
else:
13221345
self.language = ['en']
1323-
# print(f"DEBUG: texteditor.py SourceEditor open ENTER language={self.language}")
1346+
# print(f"DEBUG: texteditor.py SourceEditor open ENTER language={self.language} curpos={self._position}")
13241347
try:
13251348
if hasattr(self._data, 'wrapper_data'):
13261349
if isinstance(self._data.wrapper_data, ResourceFileController):
@@ -1492,14 +1515,15 @@ def reset(self):
14921515

14931516
def content_save(self, **args):
14941517
self.store_position()
1495-
if self.dirty and not self.is_saving:
1496-
self.is_saving = True
1518+
# print(f"DEBUG: TextEditor.py SourceEditor content_save curpos={self._position}")
1519+
if self.dirty:
14971520
# print(f"DEBUG: TextEditor.py SourceEditor content_save content={self.source_editor.utf8_text}\n"
14981521
# f"self.language={self.language} data={self._data}"
14991522
# f" calling validate_and_update with lang={args['lang']}")
1523+
self.plugin.jump = False
15001524
if not self._data_validator.validate_and_update(self._data, self.source_editor.utf8_text,
15011525
lang=self.language): # args['lang']
1502-
self.is_saving = False
1526+
self.plugin.jump = True
15031527
return False
15041528
return True
15051529

@@ -1541,7 +1565,7 @@ def on_paste(self, event):
15411565
@staticmethod
15421566
def on_insert(event):
15431567
__ = event
1544-
print(f"DEBUG: TextEditor called on_insert event={event}\n TO BE IMPLEMENTED")
1568+
# print(f"DEBUG: TextEditor called on_insert event={event}\n TO BE IMPLEMENTED")
15451569
# self.insert_row()
15461570

15471571
@staticmethod
@@ -1768,6 +1792,7 @@ def on_key_down(self, event):
17681792
# This must be the last branch to activate actions before doc
17691793
# DEBUG: coords = self._get_screen_coordinates()
17701794
self.source_editor.show_kw_doc()
1795+
self.mark_file_dirty(self.source_editor.GetModify())
17711796
event.Skip()
17721797

17731798
# These commands are duplicated by global actions

src/robotide/lib/compat/pygments/robotframework.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,10 @@ class _Table:
557557
def __init__(self, prev_tokenizer=None, new_lang=None):
558558
if self.new_lang is None:
559559
if new_lang is None:
560-
set_lang = shared_memory.ShareableList(name="language")
560+
try:
561+
set_lang = shared_memory.ShareableList(name="language")
562+
except FileNotFoundError:
563+
set_lang = ['En']
561564
self.new_lang = Language.from_name(set_lang[0].replace('_', '-'))
562565
else:
563566
self.new_lang = new_lang

src/robotide/spec/iteminfo.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,16 @@ def __init__(self, name, value):
143143
VariableInfo.__init__(self, name, value, self.SOURCE)
144144

145145
def __eq__(self, other):
146+
if isinstance(other, str):
147+
return self.longname.lower() == other.lower()
146148
return self.longname.lower() == other.longname.lower()
147149

148150
def __hash__(self):
149151
return hash(repr(self))
150152

151153
def __lt__(self, other):
154+
if isinstance(other, str):
155+
return self.longname.lower() < other.lower()
152156
return self.longname.lower() < other.longname.lower()
153157

154158

src/robotide/ui/treeplugin.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ def __init__(self, parent, action_registerer, settings=None):
234234
self._execution_results = None
235235
self._resources = []
236236
self._right_click = False
237+
self.dirty = False
237238
# DEBUG: This menu is not working because is being attached to main frame
238239
# self._menu = wx.Menu()
239240
# self._menu.Append(wx.ID_CLOSE, item="&Close", helpString="Closes panel")
@@ -707,10 +708,14 @@ def delete_node(self, node):
707708
wx.CallAfter(self.SelectItem, parent)
708709

709710
def _data_dirty(self, message):
710-
self.controller.mark_controller_dirty(message.datafile)
711+
# print("DEBUG: TreePlugin tree _data_dirty ENTER")
712+
if not self.dirty:
713+
self.dirty = True
714+
self.controller.mark_controller_dirty(message.datafile)
711715

712716
def _data_undirty(self, message):
713717
_ = message
718+
# print("DEBUG: TreePlugin tree _data_undirty")
714719
self.unset_dirty()
715720

716721
def unset_dirty(self):
@@ -719,6 +724,7 @@ def unset_dirty(self):
719724
handler = self.controller.get_handler(node)
720725
if text.startswith('*') and not handler.controller.dirty:
721726
self.SetItemText(node, text[1:])
727+
self.dirty = False
722728

723729
def select_node_by_data(self, controller):
724730
"""Find and select the tree item associated with the given controller.

src/robotide/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@
1515
#
1616
# Automatically generated by `tasks.py`.
1717

18-
VERSION = 'v2.2dev12'
18+
VERSION = 'v2.2dev13'

0 commit comments

Comments
 (0)