-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PR: Implement "Replace in selection" in the Editor #4638
Conversation
Supports replacing all instances of the search text with the replace text in a selection of text. Changes find/replace dialog to add buttons for "replace in selection" and "replace all" and removes the "replace all" checkbox. Tweaks behavior of automatically filling the searchbox depending on whether multiple lines were selected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I test it and works as expected, and I think the workflow is intuitive.
spyder/widgets/findreplace.py
Outdated
@@ -226,32 +238,36 @@ def toggle_highlighting(self, state): | |||
else: | |||
self.clear_matches() | |||
|
|||
def show(self): | |||
def show(self, hide_replace = True): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove spaces around keyword argument:
def show(self, hide_replace=True)
spyder/widgets/findreplace.py
Outdated
@@ -267,7 +283,7 @@ def hide(self): | |||
|
|||
def show_replace(self): | |||
"""Show replace widgets""" | |||
self.show() | |||
self.show(hide_replace = False) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove spaces around keyword argument:
self.show(self, hide_replace=True)
spyder/widgets/findreplace.py
Outdated
self.refresh() | ||
else: | ||
self.search_text.lineEdit().selectAll() | ||
if hide_replace or len(text.splitlines())<=1: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe a comment for explaining this behavior is missing: "When selecting several lines, and replace box is activated the text won't be replaced for the selection"
|
||
|
||
@Slot() | ||
def replace_find_selection(self, focus_replace_text=False): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if using a custom search is the best way, because the other searching methods use the findText function of QWebEngineView
(they also use python regex when regex checkbox is activated).
Although I'm not sure if this could be implemented using QWebEngineView.findText
because it doesn't support searching in a selection, also multiple selection should be managed adding more complexity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True that there is a small risk that there are different results for the two regex implementations. I think the risk is relatively small because we don't highlight find results when the user chooses a selection. And there's always UNDO...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually a bigger inconsistency is that I didn't implement the whole word restriction. DOH! And it might ultimately be simpler to use the QT implementation because python's re doesn't handle whole words. Let me give this some thought over the weekend.
spyder/widgets/findreplace.py
Outdated
@@ -329,7 +345,8 @@ def find_previous(self): | |||
def text_has_been_edited(self, text): | |||
"""Find text has been edited (this slot won't be triggered when | |||
setting the search pattern combo box text programmatically""" | |||
self.find(changed=True, forward=True, start_highlight_timer=True) | |||
if not self.replace_widgets[0].isVisible() or len(to_text_string(self.editor.get_selected_text()).splitlines())<=1: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a comment for explaining this behavior too: "When selecting several lines, and replace box is activated, dynamically search is deactivated, for avoid changing the selection."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, this line is way to long. Please break it using a \
I think this plugin need a refactoring (not as part of this PR) the different searching functions |
Ok, but that's for Spyder 4. |
spyder/widgets/findreplace.py
Outdated
cursor.beginEditBlock() | ||
seltxt = to_text_string(self.editor.get_selected_text()) | ||
if not pattern: | ||
replacement = re.sub(re.escape(search_text), re.escape(replace_text), seltxt, flags=re_flags) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line is also too long. Please make it in 79 columns
@rlaverde, did you test this locally to see if it's working as expected? |
yes |
Handles whole word restriction on matches and more fully deactivates dynamic search when user changes the find/replace options when the replace box is activated and a multiple lines in the editor are selected.
The latest changes handle the whole word option and take care of deactivating the dynamic search multiple line selections. In my testing I noticed a few little bugs in the way that the original implementation of "replace all" works. I haven't fixed that here, but that could be the subject of a different PR. |
Our tests are failing because you left a
Could you fix them here too? I mean, if they are simple enough, we could use the opportunity to fix them. |
They aren't trivial to fix. They stem from the mixed use of QT and python re in the original implementation. Sorry about the print statement. Removed it. |
Ok, no problem. Please open an issue about them so we don't forget to fix them.
No problem, that's why we have a test to check for no print's. |
spyder/widgets/findreplace.py
Outdated
#If whole words is checked we need to check that each match | ||
#is actually a whole word before replacing | ||
word_flags = 0 if case else re.IGNORECASE | ||
replacement = re.sub(pattern, _word_replacer, seltxt, flags=re_flags) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why _word_replacer
is needed? I think this could be achieved changing the pattern, like other functions do:
if words:
pattern = r"\b{}\b".format(pattern)
Good point. I think I mistakenly thought the original find implementation
was rejecting any matches if there were spaces in the search term but it
doesn't look like that's the case. It does seem to match the "\b...\b"
But if someone puts in "\" as their regex then they will be replacing
instances of "\b" that start with a whole word. But maybe it is enough to
make sure the pattern compiles before enclosing it in \b?
On Jun 27, 2017 5:47 PM, "Rafael Laverde" <[email protected]> wrote:
*@rlaverde* commented on this pull request.
------------------------------
In spyder/widgets/findreplace.py
<#4638 (comment)>:
+ pattern = search_text if self.re_button.isChecked() else None
+ case = self.case_button.isChecked()
+ words = self.words_button.isChecked()
+ re_flags = re.MULTILINE if case else re.IGNORECASE|re.MULTILINE
+
+ cursor = self.editor.textCursor()
+ cursor.beginEditBlock()
+ seltxt = to_text_string(self.editor.get_selected_text())
+ if not pattern:
+ pattern = re.escape(search_text)
+ replace_text = re.escape(replace_text)
+ if words:
+ #If whole words is checked we need to check that each match
+ #is actually a whole word before replacing
+ word_flags = 0 if case else re.IGNORECASE
+ replacement = re.sub(pattern, _word_replacer, seltxt,
flags=re_flags)
Why _word_replacer is needed? I think that this could be achieved changing
the pattern, like other functions do:
if words:
pattern = r"\b{}\b".format(patern)
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#4638 (review)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAFd5YJdXoJasXlo9veB_W3s_ZhhS8l0ks5sIXhzgaJpZM4OCUNE>
.
|
@rlaverde, please take a decision about this one. We could leave it for 3.2.1 if you prefer. |
Yes, I also think that will be enough, please implement it using "\b...\b"
I think this could be in 3.2, Only the change for whole words is missing. |
I should be able to do it this evening (US Eastern time).
…On Jul 4, 2017 5:01 PM, "Carlos Cordoba" ***@***.***> wrote:
@spillz <https://github.com/spillz>, please address @rlaverde
<https://github.com/rlaverde> comment ASAP if you want to see this in
3.2. You have until tomorrow (Wednesday) to do that.
Else I'll move this for 3.2.1.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#4638 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAFd5VKBp3b6NJeOA2by4nOanA2GBfg4ks5sKqhFgaJpZM4OCUNE>
.
|
That's fine. Thanks a lot for taking the time to do it. |
…lways show and focus replace box after pressing Ctrl+R
@rlaverde, please take a look at this one and approve it, if it's ready. |
Thanks for your work @spillz! |
Fixes #358
Supports replacing all instances of the search text with the replace text in a selection of text. Changes find/replace dialog to add buttons for "replace in selection" and "replace all" and removes the "replace all" checkbox. Tweaks behavior of automatically filling the searchbox depending on whether multiple lines were selected.
A refinement would be to either add shortcuts for the three buttons or combine the three buttons into one and use radio/combo to control scope.