Find and Add To Selection In 7.7
-
@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 2689If 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… -
@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…
-
@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?
-
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…
-
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) -
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
posnear the end of line 1 and press my keyboard shortcut everything works fine. If I do the same with placeing it before the wordintnear the end of line 1, the script selects the wordintand the following space character and nothing more happens. It looks like thesci_sendmsg SCI_WORDRIGHTEXTENDgives a wrong result.I will try to figure out what’s going on…
EDIT: It’s because
intis followed by a space character andposby opening parenthesis. This would make this feature nearly useless. Gonna do further investigations… -
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. :)
-
Does your Python script work as intended or is it a problem with the algorithm used?
-
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.
-
Got it.
SCI_WORDRIGHTEXTENDhas to be replaced bySCI_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 -
-
@cipher-1024 said:
I was hoping to easily go one ‘find’ at a time
I guess we ignored that part of the request. :)
-
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_MULTIPLESELECTADDNEXTprovides. Should be translatable to PythonScript or NppExec as this above code was working with Scintilla v3.5.6 -
Hi, @cipher-1024 and All,
As @dinkumoil and, probably, most of you, I’ve just studied the two new Scintilla commands
SCI_MULTIPLESELECTADDNEXTandSCI_MULTIPLESELECTADDEACH! Really impressive ;-))-
Install, of course, the last
v0.9 (32 bits )version of LuaScript, on the lastv7.7version of N++ -
Modify, like me, the
startup.luafile, 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 + F12shortcut to the menu commandPlugins > 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
8is on top of the windows text
=> So, you should see, approximatively, from line
8to line21( with the defaultCourier Newfont )-
Now, do a normal selection of the string
t.*t, on line10 -
Finally, run the command
Plugins > LuaScript > Execute Current Fileor hit onAlt + F12( my shortcut )
=> You should see that the word test in any case, as well as the forms
T.*Tandt.*tare selected from line8till line20, only, as well as13cursors 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 stringt.*t, in regular expression mode, without theMatch caseandMatch whole word onlyoptions, 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 thePlugins > LuaScript > Execute Current Filecommand, this time, a lot of selections, matching the regex criteriat.*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 line10 -
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
9on top of the view and, both, thet.*tandtest, in any case, selected from line9to line15Note : 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 = 0line -
Select the string
t.*t, in line10 -
Run the command
Plugins > LuaScript > Execute Current File
=> This time, the ranges, matching the string
t.*t, in any case, are selected, only, ( from lines5to10) 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 = 0line -
Uncomment the
editor.SearchFlags = 4 | 2 ........... -
Double-click on the word
test, in line22 -
Run the command
Plugins > LuaScript > Execute Current File
=> Only the true words
test, in lower-case, are selected ( in lines4,14,18and22)
Finally :
-
Comment the
editor.SearchFlags = 4 | 2 ........... -
**Uncomment the
editor.SearchFlags = SCFIND_REGEXP | SCFIND_MATCHCASE -
Select all line
5contents (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,
100times, 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,000lines 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 theEnterkey
=> The message Parameters SET ! confirms the good execution of the script
-
Then double-click on the word
test, in line1of current file -
Finally, run the menu command
Plugins > LuaScript > Selection Add Each
Waaaaouh ! Immediately,
1,000words Test are selected, at once ! And, after hitting theRight arrowkey,1,000cursors are visible and available for adding/deleting characters ;-)))This is multi-selection !!!
-
-
@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.
-
@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_MULTIPLESELECTADDEACHWhat do you think?
-
@Ekopalypse said:
What do you think?
Except the missing
endif;) - nice catch, it works!Seems like
SCI_MULTIPLESELECTADDEACHneeds an active selection andSCI_MULTIPLESELECTADDNEXTdoesn’t.EDIT: Seems like even the
endifis not necessary, I apologize. ;) -
aahhhhh - I constantly forget about using it. :-)
Yes, it works without but as the syntax defines it, it should be used, imho.
Who knows what a future update will do. -
Hi, @alan-kilborn and All,
I admit that my enthusiasm is a bit excessive ! Just because I’m rather an old guy, which knew
MS-DOS 5.0,WinWord 6andExcel 5and, even, some older goodies. So, I’m a little overwhelmed to see all these new powerful features ;-))By the way, I’m no longer surprised to create rectangular selections, over, let say,
50,000lines , with N++, for years now ! Quite similar, except that all the cursors are aligned ;-))Cheers,
guy038
-
I thought this was a three post thread and then it was done! NPP Community delivers! I wound up putting @dail 's LuaScript into the startup script for the Lua plugin and it’s working great.
Out of curiosity I tried installing NppExec on the 7.7 minimalist install and trying out @dinkumoil 's script but it would only select the current word and never go into multiedit mode. (7.7 32bit, NppExec 0.6RC3). There are no errors in the console. I don’t know if the minimalist version and my older, installed version are conflicting in some way, but I couldn’t get the script to work.
@Alan-Kilborn , thanks for the python script, unfortunately I’m still on 1.0.8 so I haven’t tried it out yet. But once I’m back to being current, I will.
My job is being inconvenient and making me do stuff, so I need to sit tight on upgrading for a bit until I have time to iron out any old plugin issues that I may run into after the upgrading. Thank you one and all. This is a great community.