Skip to content
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

Select and find next/previous uses search mode #3229

Closed
Dream-Painter opened this issue May 1, 2017 · 6 comments
Closed

Select and find next/previous uses search mode #3229

Dream-Painter opened this issue May 1, 2017 · 6 comments
Labels
verified Issues verified to be valid and reproducible, PRs that have been tested thoroughly

Comments

@Dream-Painter
Copy link

Description of the Issue

When selecting text and pressing [Shift]+[F3], or selecting "Select and find next" from the search menu will select the next instance of the selected text. But if, for instance, the selected text contains regex characters and the search mode is set to "Regular expression", then it will use the selected text as regex search string, instead of searching for the literal selected text

Steps to Reproduce the Issue

  1. use this as text (example):
P[1]
P1
P[1]
  1. select the first line "P[1]" and do select and find next
  2. if the search mode is set to Normal, the 3rd line will be selected next, if the search mode is set to regular expression, the 2nd line will be selected next.

Expected Behavior

I don't know if people use the select and find next with regular expressions, but I expect to only use the normal search mode with this. so would it be possible to have the search mode during "select and find next" either hard coded to "Normal" or have a setting for this?

Since the search mode is not visible during use of "select and find next", this makes it somewhat irritating when it is still set to anything other than Normal.

Debug Information

Notepad++ v7.3.3 (32-bit)
Build time : Mar 8 2017 - 03:37:37
Path : C:\Program Files (x86)\Notepad++\notepad++.exe
Admin mode : ON
Local Conf mode : OFF
OS : Windows 7 (64-bit)
Plugins : ComparePlugin.dll NotepadStarterPlugin.dll NppConverter.dll NppExport.dll OpenSelection.dll PluginManager.dll Python Indent.dll regrexplace.dll ReloadButton.dll XMLTools.dll

@2chg
Copy link

2chg commented Aug 2, 2018

I agree.

Since I use the RegExp-Search quite often, it is the "last mode" most of the time. And every time I try to use the Shift+F3 feature to save time, it does the quite opposite and wastes it.

I would really appreciate if the Shift-F3-Keystroke would automatically switch the search mode to normal, since everything else seems the way more uncommon intent of the user. (At least allow to enable this automatically switching in the options)

@sasumner sasumner added the verified Issues verified to be valid and reproducible, PRs that have been tested thoroughly label Aug 19, 2019
@sasumner
Copy link
Contributor

sasumner commented Aug 19, 2019

("Select and Find Next/Prev" should)...automatically switch the search mode to normal

But other Find options from the Find window affect this type of search invocation as well:

  • Match whole word only
  • Match case
  • Wrap around (admittedly, perhaps this one is not as "important" as the other 2)

Change your test data to the following and then play around with how the "Select and Find Next/Prev" searches work in conjunction with the settings listed above:

P[1]
P1
P[1]
p[1]
uP[1]
up[1]

Aren't these settings (whole-word, match case, wrap) also a problem for an unsuspecting user? The "safest" thing to do might be to automatically set the following up for a "Select and Find Next/Prev" invocation:

  • Search mode: Normal
  • Match whole word only: No
  • Match case: No
  • Wrap around: Yes

This will find the maximum amount of matches for this speedy type of searching; if the user doesn't like that, he can "slow down a bit" and do a "real" search using the actual Find window and its "Find Next" button in conjunction with "Backward direction" checkbox (or equivalently, the "<<" and ">>" buttons).

The above works well if one continues to reinvoke "Select and Find Next/Prev" for each match encountered. But if one only invokes that specific command for the first invocation and then switches to the keyboard equivalent for "Find Next", that will revert to using the Find window settings that we are trying to escape for this scenario. [I noticed that in conjunction with testing a possible code change...and I saw that the "Find what" box would change to the "lowercase" version of p[1] at times as one jumps between the matches by repeated use of "Select and Find Next/Prev" -- due to the "select" part populating it].

So for good or bad, it seems like these features (interactive Find, Select-and-Find, (keyboard)Find-next) might be inexorably tied together...

@2chg
Copy link

2chg commented Aug 20, 2019

in conjunction with "Backward direction" checkbox

I think, this would be another good candidate to "reset" for as fast search.

@sasumner
Copy link
Contributor

@2chg Backward direction is not needed here because the "fast search" has 2 options: Select and Find Next and Select and Find Previous.

@2chg
Copy link

2chg commented Aug 20, 2019

OK, I see. The quick search ignores this directional option. My fault.

@sasumner
Copy link
Contributor

FWIW, I made a Pythonscript for the desired behavior. I call it SelectAndFindNextVolatileIndependent.py.

It can be tied to the keycombo for the native N++ command Select and Find Next or of course any other key. To get a "previous" version, copy the script to a different file (suggest: SelectAndFindPreviousVolatileIndependent.py) and assign a suitable keycombo for that one as well. In the "previous" script file, though, change backward_direction = False to backward_direction = True.

Depending upon how you like this type of search to work, change these lines to either assign True or False, individually:

match_case_on = False
whole_word_on = False
wrap_on = False

Here's the script:

# -*- coding: utf-8 -*-

from Npp import editor, notepad
import re
import string
import ctypes

def SAFNVI__main():

    backward_direction = False  # change this to True in a second script
    
    match_case_on = False
    whole_word_on = False
    wrap_on = False

    word_chars = string.ascii_uppercase + string.ascii_lowercase + string.digits + '_'

    def regex_escaped(text): return re.sub(r'([][\.^$*+?(){}\\|-])', r'\\\1', text)

    curr_pos = editor.getCurrentPos()

    const_search_text = ''
    if editor.getSelections() == 1 and not editor.getSelectionEmpty():
        const_search_text = editor.getSelText()
        orig_text_start_pos = editor.getSelectionStart()
        orig_text_end_pos = editor.getSelectionEnd()
    else:
        start_of_word_pos = editor.wordStartPosition(curr_pos, True)
        end_of_word_pos = editor.wordEndPosition(start_of_word_pos, True)
        if start_of_word_pos != end_of_word_pos:
            const_search_text = editor.getTextRange(start_of_word_pos, end_of_word_pos)
            orig_text_start_pos = start_of_word_pos
            orig_text_end_pos = end_of_word_pos

    if len(const_search_text) == 0: return

    add_word_boundary_assertions = False
    if whole_word_on and const_search_text[0] in word_chars and const_search_text[-1] in word_chars:
        add_word_boundary_assertions = True

    const_search_text = regex_escaped(const_search_text)

    if add_word_boundary_assertions: const_search_text = r'\b' + const_search_text + r'\b'

    match_list = []

    if backward_direction:
        editor.research(const_search_text, lambda m: match_list.append(m.span(0)), 0 if match_case_on else re.IGNORECASE, 0, curr_pos)  # possibly get MANY matches
    else:
        editor.research(const_search_text, lambda m: match_list.append(m.span(0)), 0 if match_case_on else re.IGNORECASE, curr_pos, editor.getTextLength(), 1)  # only 1 match possible

    # don't allow original text to be a valid match (we're already there):
    if len(match_list) > 0 and match_list[-1][0] == orig_text_start_pos and match_list[-1][1] == orig_text_end_pos: match_list.pop(-1)

    do_beep_and_flash = False

    if wrap_on and len(match_list) == 0:

        do_beep_and_flash = True

        if backward_direction:
            editor.research(const_search_text, lambda m: match_list.append(m.span(0)), 0 if match_case_on else re.IGNORECASE, curr_pos, editor.getTextLength())  # possibly get MANY matches
        else:
            editor.research(const_search_text, lambda m: match_list.append(m.span(0)), 0 if match_case_on else re.IGNORECASE, 0, curr_pos, 1)  # only 1 match possible

    # don't allow original text to be a valid match (we're already there):
    if len(match_list) > 0 and match_list[-1][0] == orig_text_start_pos and match_list[-1][1] == orig_text_end_pos: match_list.pop(-1)

    if len(match_list) == 0: return

    (match_pos_start, match_pos_end) = match_list[-1]

    if do_beep_and_flash:
        ctypes.windll.user32.MessageBeep(0xFFFFFFFF)
        notepad.flashWindow(3, 100)

    editor.setSelection(match_pos_end, match_pos_start)
    editor.scrollCaret()

SAFNVI__main()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
verified Issues verified to be valid and reproducible, PRs that have been tested thoroughly
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants