Community
    • Login

    Find and Add To Selection In 7.7

    Scheduled Pinned Locked Moved General Discussion
    37 Posts 7 Posters 9.9k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • dinkumoilD
      dinkumoil @Ekopalypse
      last edited by dinkumoil

      @Ekopalypse said:

      is it really needed to do SCI_WORDRIGHTEXTEND?

      According to my tests - yes.

      If the SCI_WORDRIGHTEXTEND part is removed from the script, executing it (without an active selection) selects the word right from the cursor and marks all other instances of the word in the whole text but there are no multiple cursors.

      EkopalypseE 1 Reply Last reply Reply Quote 3
      • EkopalypseE
        Ekopalypse @dinkumoil
        last edited by

        @dinkumoil - thanks for clarifying.

        1 Reply Last reply Reply Quote 1
        • Alan KilbornA
          Alan Kilborn
          last edited by

          It automatically selects the word right from the cursor but only if there is no active selection.

          I tried the NppExec script and I found that if I run it without a selection but with the caret inside or at the start of a word, it will select from the caret to the right to just before the start of the next word, and then fail to give multiple carets; example with caret sitting on second s of highlighted sci_sendmsg:

          Imgur

          Starting with an entire word preselected (here the 2nd sci_sendmsg in the file) however works just fine:

          Imgur

          Perhaps I miss something about the case where there is no selected text first…

          1 Reply Last reply Reply Quote 2
          • dinkumoilD
            dinkumoil
            last edited by dinkumoil

            @all

            Improved version of my NppExec script:

            sci_sendmsg SCI_GETSELECTIONEMPTY
            
            if $(MSG_RESULT) == 1 then
              sci_sendmsg SCI_GETCURRENTPOS
              set local $(CurPos) ~ $(MSG_RESULT)
            
              sci_sendmsg SCI_WORDSTARTPOSITION $(CurPos) 1
            
              if $(MSG_RESULT) != $(CurPos) then
                sci_sendmsg SCI_WORDLEFT
              endif
            
              sci_sendmsg SCI_WORDRIGHTEXTEND
            endif
            
            sci_sendmsg SCI_SETSEARCHFLAGS SCFIND_WHOLEWORD 
            
            sci_sendmsg 2690
            sci_sendmsg 2689
            

            If the cursor is placed in the middle of a word without an active selection when executing the script, it is moved to the next word boundary to its left before selecting the word to the right of its new position, i.e. the word in whose mid it was placed before.

            @Alan-Kilborn
            Oh, I’ve posted before I could even see your posting…

            Alan KilbornA 1 Reply Last reply Reply Quote 3
            • Alan KilbornA
              Alan Kilborn @dinkumoil
              last edited by

              @dinkumoil said:

              Oh, I’ve posted before I could even see your posting…

              I tried the NppExec script just above and had the same result as the earlier NppExec script when no selection before running…

              dinkumoilD 1 Reply Last reply Reply Quote 2
              • dinkumoilD
                dinkumoil @Alan Kilborn
                last edited by

                @Alan-Kilborn said:

                I tried the NppExec script just above and had the same result as the earlier NppExec script when no selection before running…

                It works at my site. Did you restart Notepad++ after updating the script?

                Alan KilbornA 1 Reply Last reply Reply Quote 1
                • Alan KilbornA
                  Alan Kilborn @dinkumoil
                  last edited by

                  @dinkumoil

                  Did you restart Notepad++ after updating the script?

                  No, but I didn’t “save” it, I was just running it as a NppExec temporary script…

                  1 Reply Last reply Reply Quote 1
                  • Alan KilbornA
                    Alan Kilborn
                    last edited by

                    Totally just for fun, I managed to replicate the functionality with Pythonscript in its current (1.4) form:

                    import ctypes
                    from ctypes.wintypes import HWND
                    from ctypes import byref, wintypes, Structure, sizeof
                    
                    def get_focused_window():
                        class GUITHREADINFO(Structure):
                            _fields_ = [
                                ("cbSize", wintypes.DWORD),
                                ("flags", wintypes.DWORD),
                                ("hwndActive", wintypes.HWND),
                                ("hwndFocus", wintypes.HWND),  # <--- what we really want
                                ("hwndCapture", wintypes.HWND),
                                ("hwndMenuOwner", wintypes.HWND),
                                ("hwndMoveSize", wintypes.HWND),
                                ("hwndCaret", wintypes.HWND),
                                ("rcCaret", wintypes.RECT)
                                ]
                        guiThreadInfo = GUITHREADINFO(cbSize=sizeof(GUITHREADINFO))
                        ctypes.windll.user32.GetGUIThreadInfo(0, byref(guiThreadInfo))
                        return guiThreadInfo.hwndFocus
                    
                    current_view_hwnd = get_focused_window()
                    
                    SciLexer = ctypes.WinDLL('SciLexer.dll', use_last_error = True)
                    Scintilla_DirectFunction = SciLexer.Scintilla_DirectFunction
                    direct_pointer = SendMessage(current_view_hwnd, 2185, 0, 0)
                    
                    editor.setSearchFlags(FINDOPTION.WHOLEWORD | FINDOPTION.MATCHCASE)
                    
                    if editor.getSelectionEmpty():
                        start_of_word_pos = editor.wordStartPosition(editor.getCurrentPos(), True)
                        end_of_word_pos = editor.wordEndPosition(start_of_word_pos, True)
                        if start_of_word_pos != end_of_word_pos:
                            editor.setSelection(end_of_word_pos, start_of_word_pos)
                    
                    Scintilla_DirectFunction(direct_pointer, 2689, 1, 0)
                    
                    1 Reply Last reply Reply Quote 5
                    • dinkumoilD
                      dinkumoil
                      last edited by dinkumoil

                      Hmm, I found a strange pitfall with my code.

                      I use for testing the same snippet of source code @dail used in his posting in the other thread:

                      static std::string getWordAt(GUI::ScintillaWindow *window, int pos) {
                        int word_start = window->Call(SCI_WORDSTARTPOSITION, pos, true);
                        int word_end = window->Call(SCI_WORDENDPOSITION, pos, true);
                        return getRange(window, word_start, word_end);
                      }
                      

                      If I place the cursor before the word pos near the end of line 1 and press my keyboard shortcut everything works fine. If I do the same with placeing it before the word int near the end of line 1, the script selects the word int and the following space character and nothing more happens. It looks like the sci_sendmsg SCI_WORDRIGHTEXTEND gives a wrong result.

                      I will try to figure out what’s going on…

                      EDIT: It’s because int is followed by a space character and pos by opening parenthesis. This would make this feature nearly useless. Gonna do further investigations…

                      Alan KilbornA 1 Reply Last reply Reply Quote 2
                      • Alan KilbornA
                        Alan Kilborn @dinkumoil
                        last edited by

                        @dinkumoil

                        Yea, if you’ll take note, I had an intentional big amount of spaces to the right of the word I had my caret in for my testing. :)

                        1 Reply Last reply Reply Quote 1
                        • dinkumoilD
                          dinkumoil
                          last edited by

                          @Alan-Kilborn

                          Does your Python script work as intended or is it a problem with the algorithm used?

                          Alan KilbornA 1 Reply Last reply Reply Quote 0
                          • Alan KilbornA
                            Alan Kilborn @dinkumoil
                            last edited by

                            @dinkumoil

                            Not sure if I understand the q… The PS doesn’t use the “word-right-extend” stuff, which seems to be where the trouble lies with the NppExec scripts presented to this point…

                            I didn’t do exhaustive testing on the PS, but yea, seems to work as intended.

                            1 Reply Last reply Reply Quote 1
                            • dinkumoilD
                              dinkumoil
                              last edited by dinkumoil

                              Got it. SCI_WORDRIGHTEXTEND has to be replaced by SCI_WORDRIGHTENDEXTEND - of course. :(

                              Here is the updated (and working) version of the script:

                              sci_sendmsg SCI_GETSELECTIONEMPTY
                              
                              if $(MSG_RESULT) == 1 then
                                sci_sendmsg SCI_GETCURRENTPOS
                                set local $(CurPos) ~ $(MSG_RESULT)
                              
                                sci_sendmsg SCI_WORDSTARTPOSITION $(CurPos) 1
                              
                                if $(MSG_RESULT) != $(CurPos) then
                                  sci_sendmsg SCI_WORDLEFT
                                endif
                              
                                sci_sendmsg SCI_WORDRIGHTENDEXTEND
                              endif
                              
                              sci_sendmsg SCI_SETSEARCHFLAGS SCFIND_WHOLEWORD 
                              
                              sci_sendmsg 2690
                              sci_sendmsg 2689
                              
                              Alan KilbornA 1 Reply Last reply Reply Quote 4
                              • Alan KilbornA
                                Alan Kilborn @dinkumoil
                                last edited by

                                @dinkumoil said:

                                (and working) version of the script:

                                CONFIRMED! :)

                                1 Reply Last reply Reply Quote 2
                                • Alan KilbornA
                                  Alan Kilborn
                                  last edited by

                                  @cipher-1024 said:

                                  I was hoping to easily go one ‘find’ at a time

                                  I guess we ignored that part of the request. :)

                                  1 Reply Last reply Reply Quote 2
                                  • dailD
                                    dail
                                    last edited by

                                    Quite a while ago (before Notepad++ updated Scintilla) I found the “find and add next” functionality very useful in other editors and knew that Scintilla supported it in newer versions. I dug through the Scintilla source code and translated it to this LuaScript code:

                                    npp.AddShortcut("Selection Add Next", "Ctrl+D", function()
                                        -- From SciTEBase.cxx
                                        local flags = SCFIND_MATCHCASE -- can use 0
                                        editor:SetTargetRange(0, editor.TextLength)
                                        editor.SearchFlags = flags
                                    
                                        -- From Editor.cxx
                                        if editor.SelectionEmpty or not editor.MultipleSelection then
                                            local startWord = editor:WordStartPosition(editor.CurrentPos, true)
                                            local endWord = editor:WordEndPosition(startWord, true)
                                            editor:SetSelection(startWord, endWord)
                                        else
                                            local i = editor.MainSelection
                                            local s = editor:textrange(editor.SelectionNStart[i], editor.SelectionNEnd[i])
                                            local searchRanges = {{editor.SelectionNEnd[i], editor.TargetEnd}, {editor.TargetStart, editor.SelectionNStart[i]}}
                                            for _, range in pairs(searchRanges) do
                                                editor:SetTargetRange(range[1], range[2])
                                                if editor:SearchInTarget(s) ~= -1 then
                                                    editor:AddSelection(editor.TargetStart, editor.TargetEnd)
                                                    editor:ScrollRange(editor.TargetStart, editor.TargetEnd)
                                                    break
                                                end
                                            end
                                        end
                                    end)
                                    

                                    In theory this should be the exact functionality (well, very close at least) that SCI_MULTIPLESELECTADDNEXT provides. Should be translatable to PythonScript or NppExec as this above code was working with Scintilla v3.5.6

                                    1 Reply Last reply Reply Quote 7
                                    • guy038G
                                      guy038
                                      last edited by

                                      Hi, @cipher-1024 and All,

                                      As @dinkumoil and, probably, most of you, I’ve just studied the two new Scintilla commands SCI_MULTIPLESELECTADDNEXT and SCI_MULTIPLESELECTADDEACH ! Really impressive ;-))

                                      • Install, of course, the last v0.9 (32 bits ) version of LuaScript, on the last v7.7 version of N++

                                      • Modify, like me, the startup.lua file, as below :

                                      -- Startup script
                                      -- Changes will take effect once Notepad++ is restarted
                                      
                                      npp.AddShortcut("Selection Add Next", "Ctrl+F12", function()
                                          editor:MultipleSelectAddNext()
                                      end)
                                      
                                      npp.AddShortcut("Selection Add Each", "Shift+Ctrl+F12", function()
                                          editor:MultipleSelectAddEach()
                                      end)
                                      
                                      -- And affected the 'ALT + F12' shortcut to the 'Plugins > LuaScript > Execute Current File' option
                                      --                   ---------                   ------------------------------------------
                                      
                                      • Affect, as noticed, the Alt + F12 shortcut to the menu command Plugins > LuaScript > Execute Current File

                                      • Then, paste this simple Lua file, below, in a new tab

                                      --[[  TEST part
                                      
                                      TEST
                                      test
                                      T.*T
                                      t.*t
                                      123T.*T456
                                      123 T.*T 456
                                      123t.*t456
                                      123 t.*t 456
                                      123TEST
                                      123test
                                      123 TEST
                                      123 test
                                      TEST456
                                      test456
                                      TEST 456
                                      test 456
                                      123TEST456
                                      123test456
                                      123 TEST 456
                                      123 test 456
                                      
                                      ]]
                                      
                                      --[[  FLAGS definition :
                                      
                                      Command :  editor.SearchFlags = SCFIND_WHOLEWORD  ( or = 2 )
                                      command :  editor.SearchFlags = SCFIND_MATCHCASE  ( or = 4 )
                                      command :  editor.SearchFlags = SCFIND_WORDSTART  ( or = 2^20 )
                                      command :  editor.SearchFlags = SCFIND_REGEXP     ( or = 2^21 )
                                      
                                      Examples :
                                      
                                      editor.SearchFlags = 0                                => Mode NORMAL WITHOUT options 'Match case' and 'Whole word only'
                                      editor.SearchFlags = SCFIND_REGEXP | SCFIND_MATCHCASE => Mode 'REGULAR expression' with option 'Match case'
                                      editor.SearchFlags = 4 | 2                            => Mode NORMAL with options 'Match case' and 'Whole word only'
                                      editor.SearchFlags = SCFIND_WORDSTART                 => Mode NORMAL with option 'Not preceded with a WORD char.'
                                      ]]
                                      
                                      -- editor.SearchFlags = SCFIND_REGEXP | SCFIND_MATCHCASE
                                      -- editor.SearchFlags = 4 | 2
                                      -- editor.SearchFlags = 0
                                      
                                      --[[   TARGET definition :
                                      
                                      Command    :  editor:SetTargetRange(Offset start, Offset end) - The Go to... command ( Ctrl +G ), with
                                                                                                        the 'Offset' option, may help !
                                      
                                      or command :  editor:TargetFromSelection()                    - Do a NORMAL MAIN selection, in this SCRIPT file
                                                                                                    - Run 'editor:TargetFromSelection()' on Lua CONSOLE
                                      															  - Then, execute this Lua SCRIPT file
                                      
                                      or command :  editor:TargetWholeDocument()                    - Self-explanatory
                                      ]]
                                      
                                      -- editor:TargetWholeDocument()
                                      -- editor:SetTargetRange(69, 140)  -- TARGET, from START of line 9 to END of line 15
                                      
                                      
                                      -- And... execute the MAGIC command !
                                      
                                      editor:MultipleSelectAddEach()
                                      
                                      -- LAST TeSt line
                                      
                                      • Save it with name Test.lua

                                      As you can see, the only uncommented command is editor:MultipleSelectAddEach()

                                      • Now re-start N++ and re-open this Test.lua, if necessary

                                      • Unset the Word wrap feature ( View > Word wrap )

                                      • Zoom out till the maximum ( Ctrl + Num+ )

                                      • Click on the vertical bar to scroll down, in order that the line 8 is on top of the windows text

                                      => So, you should see, approximatively, from line 8 to line 21 ( with the default Courier New font )

                                      • Now, do a normal selection of the string t.*t, on line 10

                                      • Finally, run the command Plugins > LuaScript > Execute Current File or hit on Alt + F12 ( my shortcut )

                                      => You should see that the word test in any case, as well as the forms T.*T and t.*t are selected from line 8 till line 20, only, as well as 13 cursors appear, on the right of each selection !

                                      This means that, by default, if, either, NO flags were previously set and NO target was previously defined, the lua command editor:MultipleSelectAddEach() seems to select all matches of the string t.*t, in regular expression mode, without the Match case and Match whole word only options, in all the visible lines of the current screen !?


                                      Of course, if you uncomment the line editor:TargetWholeDocument() and redo the same actions as above, ending with the Plugins > LuaScript > Execute Current File command, this time, a lot of selections, matching the regex criteria t.*t, have appeared, in the whole document

                                      => It’s easy to see that the search is performed in a regex way as many lines, outside the test zone, with variable length, have been also selected !


                                      Now :

                                      • Comment, again, the editor:TargetWholeDocument() line

                                      • Uncomment the line editor:SetTargetRange(69, 140) -- TARGET, from START of line 9 to END of line 15

                                      • Zoom out till the maximum ( Ctrl + Num+ )

                                      • Select the string t.*t, in line 10

                                      • Click on the vertical bar to scroll down till the end of the script

                                      • Run the command Plugins > LuaScript > Execute Current File

                                      => This time, you should see the line 9 on top of the view and, both, the t.*t and test, in any case, selected from line 9 to line 15

                                      Note : for the editor:TargetFromSelection() command, refer to the explanations in comments !


                                      Now :

                                      • Comment the line editor:SetTargetRange(69, 140) -- TARGET, from START of line 9 to END of line 15

                                      • Uncomment the editor:TargetWholeDocument() line

                                      • Uncomment the editor.SearchFlags = 0 line

                                      • Select the string t.*t, in line 10

                                      • Run the command Plugins > LuaScript > Execute Current File

                                      => This time, the ranges, matching the string t.*t, in any case, are selected, only, ( from lines 5 to 10 ) Logic, as the search is perfomed in a normal insensitive way !


                                      Then :

                                      • Move the cursor at beginning of line 17, without selecting anything

                                      • Run the command Plugins > LuaScript > Execute Current File

                                      => The word TEST is now selected

                                      • Run, again, the same command Plugins > LuaScript > Execute Current File

                                      => As expected, this time, all the words TEST, in any case, are selected, included the last line, with word TeSt


                                      Now :

                                      • Comment the editor.SearchFlags = 0 line

                                      • Uncomment the editor.SearchFlags = 4 | 2 ...........

                                      • Double-click on the word test, in line 22

                                      • Run the command Plugins > LuaScript > Execute Current File

                                      => Only the true words test, in lower-case, are selected ( in lines 4, 14, 18 and 22 )


                                      Finally :

                                      • Comment the editor.SearchFlags = 4 | 2 ...........

                                      • **Uncomment the editor.SearchFlags = SCFIND_REGEXP | SCFIND_MATCHCASE

                                      • Select all line 5 contents ( T.*T )

                                      • Run the command Plugins > LuaScript > Execute Current File

                                      => As expected, the longest ranges of text of lines, beginning and ending with the upper-case letter T, are selected, even embedded in other ranges of characters !

                                      Best Regards,

                                      guy038

                                      P.S. : A last interesting test :

                                      • First, create this tiny lua script, below, which you’ll name Test_2.lua :
                                      editor.SearchFlags = 0
                                      
                                      editor:TargetWholeDocument()
                                      
                                      print ("Parameters SET !")
                                      
                                      • Then, create a dummy file, containing, 100 times, the sample text, below :
                                      This a test of MULTI-selections
                                      test of MULTI-selections
                                      1234567890This a test of MULTI-selections
                                      t.*t										This a test of MULTI-selections
                                                                                              This a test of MULTI-selections
                                      This atestof MULTI-selections
                                      This a TeSt of MULTI-selections 1234567890
                                      This a test
                                      This a test of MULTI-selections
                                      test
                                      

                                      => So, you get a 1,000 lines text, each containing the word Test, in various cases

                                      • Save it in your current directory

                                      • Move back to the beginning of this test file ( Ctrl + Home )

                                      • Execute the menu command Plugins > LuaScript > Show console

                                      • In the opened lua console, write the command winfile.dofile("Test_2.lua") and valid with the Enter key

                                      => The message Parameters SET ! confirms the good execution of the script

                                      • Then double-click on the word test, in line 1 of current file

                                      • Finally, run the menu command Plugins > LuaScript > Selection Add Each

                                      Waaaaouh ! Immediately, 1,000 words Test are selected, at once ! And, after hitting the Right arrow key, 1,000 cursors are visible and available for adding/deleting characters ;-)))

                                      This is multi-selection !!!

                                      Alan KilbornA 1 Reply Last reply Reply Quote 5
                                      • Alan KilbornA
                                        Alan Kilborn @guy038
                                        last edited by

                                        @guy038 said:

                                        This is multi-selection !!!

                                        Yes. But maybe I am not understanding the fascination. As the OP mentioned in the first posting in this thread, there’s been “workaround” ways (see the link in that first posting) to achieve this type of multiselection for a long time…and all of the above in THIS thread is still workaround.

                                        What is really needed to make this complete is a good interface within Notepad++ itself (no scripting plugins). Then, when someone posts to the Community “I can match the text I need by doing a regex-find, but how can I copy that text to a new document?”, we can finally give them a good answer. And by good I mean one that doesn’t start out with “Install a scripting plugin…”. Not that there’s anything wrong with scripting plugins, but it is just too cumbersome for someone that has a single need.

                                        EkopalypseE 1 Reply Last reply Reply Quote 3
                                        • EkopalypseE
                                          Ekopalypse @Alan Kilborn
                                          last edited by Ekopalypse

                                          @dinkumoil - I guess your nppexec script can be reduced to this

                                          sci_sendmsg SCI_SETSEARCHFLAGS SCFIND_WHOLEWORD
                                          sci_sendmsg 2690  // SCI_TARGETWHOLEDOCUMENT
                                          
                                          sci_sendmsg SCI_GETSELECTIONEMPTY
                                          if $(MSG_RESULT) == 1 then
                                            sci_sendmsg 2688  // SCI_MULTIPLESELECTADDNEXT
                                           
                                          sci_sendmsg 2689  // SCI_MULTIPLESELECTADDEACH
                                          

                                          What do you think?

                                          dinkumoilD 1 Reply Last reply Reply Quote 4
                                          • dinkumoilD
                                            dinkumoil @Ekopalypse
                                            last edited by dinkumoil

                                            @Ekopalypse said:

                                            What do you think?

                                            Except the missing endif ;) - nice catch, it works!

                                            Seems like SCI_MULTIPLESELECTADDEACH needs an active selection and SCI_MULTIPLESELECTADDNEXT doesn’t.

                                            EDIT: Seems like even the endif is not necessary, I apologize. ;)

                                            EkopalypseE 1 Reply Last reply Reply Quote 2
                                            • First post
                                              Last post
                                            The Community of users of the Notepad++ text editor.
                                            Powered by NodeBB | Contributors