the script is updated. → viewtopic.php?p=391320#p391320 ← click this link
1, there was certain inaccuracy in "non-word" character(s) handling for the "improvised shorthand" feature, and now got fixed.
2, there was a loophole in the "matches highlighting" under a very specific condition when the search term contains nothing else but only negation(s) (whereas negation is a word/string/pattern which starts with a minus sign "-"), and now got fixed.
that's it for now.
Text Filter
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
Thank you for the fixes.
Maybe in your post of the code, delete the rtf file because it's not needed anymore. Just a cosmetic thing
Maybe in your post of the code, delete the rtf file because it's not needed anymore. Just a cosmetic thing
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
planet-seven-e: font size can be changed on the spot.
to increase font size: either hold the {ctrl} key down and roll up the mouse wheel while the mouse pointer is currently on top of the big text/edit box (the one in richedit) i.e. ctrl+wheelup, or press the plus key {+} (or {=}) while the big text/edit box is in focus.
to decrease font size: either hold the {ctrl} key down and roll down the mouse wheel while the mouse pointer is currently on top of the big text/edit box (the one in richedit) i.e. ctrl+wheeldown, or press the minus key {-} while the big text/edit box is in focus.
2021Apr18: planet-seven-f added a feature to glance the committed level(s) and can directly fall back to the one you select. it lets you review brief information about the steps that you've taken all the way to the current level, and may save you some keystrokes if you want to get a leap back to an earlier level at once. just right click on the back button, that's it.
and some minor changes as well.
2021Apr24: planet-seven-g added an overall rightclick menu which should have covered all the features available. (right click on the back button or edit box or window ribbon would show their own menu nonetheless.)
2021May5: planet-seven-h added a treeview gui for "assorted matches". you can find it in the rightclick menu. (it's available there only when "assorted matches" is shown though.) the treeview gui is owned by its caller, that is, the text filter gui. and hence, closing of the text filter gui will also close the treeview gui as well.
the script is updated.
to increase font size: either hold the {ctrl} key down and roll up the mouse wheel while the mouse pointer is currently on top of the big text/edit box (the one in richedit) i.e. ctrl+wheelup, or press the plus key {+} (or {=}) while the big text/edit box is in focus.
to decrease font size: either hold the {ctrl} key down and roll down the mouse wheel while the mouse pointer is currently on top of the big text/edit box (the one in richedit) i.e. ctrl+wheeldown, or press the minus key {-} while the big text/edit box is in focus.
2021Apr18: planet-seven-f added a feature to glance the committed level(s) and can directly fall back to the one you select. it lets you review brief information about the steps that you've taken all the way to the current level, and may save you some keystrokes if you want to get a leap back to an earlier level at once. just right click on the back button, that's it.
and some minor changes as well.
2021Apr24: planet-seven-g added an overall rightclick menu which should have covered all the features available. (right click on the back button or edit box or window ribbon would show their own menu nonetheless.)
2021May5: planet-seven-h added a treeview gui for "assorted matches". you can find it in the rightclick menu. (it's available there only when "assorted matches" is shown though.) the treeview gui is owned by its caller, that is, the text filter gui. and hence, closing of the text filter gui will also close the treeview gui as well.
the script is updated.
Code: Select all
Version = Planet-Seven-H
SetWorkingDir %A_ScriptDir%
RE_Dll := DllCall("LoadLibrary", "Str", "Msftedit.dll", "Ptr")
OnMessage(0x201, "EventHandler") ;WM_LBUTTONDOWN
OnMessage(0x202, "EventHandler") ;WM_LBUTTONUP
IfExist, tfWork.rtf
FileDelete, tfWork.rtf
IfExist, tfHelp.rtf
FileDelete, tfHelp.rtf
HelpPage=
(
{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Arial;}{\f1\fnil\fcharset0 Consolas;}}
{\colortbl ;\red255\green0\blue0;\red155\green0\blue211;\red0\green77\blue187;\red0\green176\blue80;\red0\green0\blue255;}
{\*\generator Riched20 10.0.19041}\viewkind4\uc1
\pard\sa200\sl276\slmult1\b\fs36\lang9 H e l p _ P a g e\b0\par
\par
\cf1\b F1\cf0\b0 - to toggle this help page\par
\par
\b Basic syntax by example:\b0\par
\pard\li720\sa200\sl276\slmult1 coexisting words/strings/patterns -unwanted\par
for instance, \cf2\b\f1 d.*d -the and -oo \\ws\cf0\b0\f0\par
(the 5 segments (space separated) above can go all at once, and yet, they can also be entered one by one. that's the so-called multilevel approach, instead.)\par
\pard\sa200\sl276\slmult1\par
\b Feature keys:\b0\par
\pard\li720\sa200\sl276\slmult1\cf3\b Alt+a\cf0\b0 - to show assorted matches and toggle between chronological and alphabetical order.\par
\cf3\b WheelDown\cf0\b0 - to find the next match (downward) from the caret position (given that, the mouse pointer is currently outside both text/edit boxes.)\par
\cf3\b WheelUp\cf0\b0 - to find the next match (upward) from the caret position (given that, the mouse pointer is currently outside both text/edit boxes.)\par
\cf3\b Alt+v\cf0\b0 - to paste clipboard content into the big text/edit box.\par
\cf3\b Ctrl+o\cf0\b0 - to open a file.\par
\cf3\b Ctrl+r\cf0\b0 - to reload the file.\par
\cf3\b Rightclick\cf0\b0 "Back" button - to glance committed levels and select one to fall back to.\par
\cf3\b Esc\cf0\b0 - to quit/exit/leave. same as closing the window.\par
\cf3\b Tab\cf0\b0 - to change focus between the text/edit boxes (just try it.)\par
\par
these below only work when the \ul big\ulnone text/edit box is in focus:\par
\pard\li1440\sa200\sl276\slmult1\cf3\b f\cf0\b0 - to find the next match (downward) from the caret position.\par
\cf3\b Shift+f\cf0\b0 - to find the next match (upward) from the caret position.\par
\i (note: "the line" refers to the current line, that's where the caret is on.)\i0\par
\cf3\b Enter\cf0\b0 - to copy the line.\par
\cf3\b Space\cf0\b0 - to page down\par
\cf3\b Shift+Space\cf0\b0 - to page up\par
\cf3\b s\cf0\b0 - to move the caret to the beginning/start of the line.\par
\cf3\b e\cf0\b0 - to move the caret to the end of the line.\par
\cf3\b t\cf0\b0 - to move the caret to the top of the text.\par
\cf3\b b\cf0\b0 - to move the caret to the bottom of the text.\par
\cf3\b + or =\cf0\b0 - to increase font size (same as \cf3\b Ctrl+WheelUp\cf0\b0 ).\par
\cf3\b minus "-"\cf0\b0 - to decrease font size (same as \cf3\b Ctrl+WheelDown\cf0\b0 ).\par
\i (side note: "caret" may be known as "cursor" to some people.)\i0\par
\pard\sa200\sl276\slmult1\par
\tab these below only work when the \ul small\ulnone text/edit box is in focus:\par
\pard\li1440\sa200\sl276\slmult1\cf3\b Enter\cf0\b0 - to commit a level (which makes the current result becoming the base/source of the next level.) same as clicking the button Go.\par
\pard\sa200\sl276\slmult1\par
\pard\li720\sa200\sl276\slmult1\cf3\b Backtick (``)\cf0\b0 - since users mostly use this tool to locate the specific line of text and copy it for whatever subsequent actions to be taken, which typically involves Tab and then Enter (if the first line is the one wanted), backtick is an alternative which can supersede both keys by just hit backtick twice instead.\par
\pard\sa200\sl276\slmult1\par
The \b improvised shorthand\b0 feature:\par
\pard\li720\sa200\sl276\slmult1 this feature can be triggered through "\cf2\b\\/\cf0\b0 " (a \b backslash\b0 followed by a \b slash\b0 ), a "regex like" syntax style, which toggle it on or off. so, enter "\cf2\b\\/tr\cf0\b0 " will bring you those lines contained "\cf4\i the road\cf0\i0 ", "\cf4\i two roads\cf0\i0 ", as well as "\cf4\i them really\cf0\i0 " out of the poem, whereas enter "\cf2\b oo \\/a?a\cf0\b0 " or "\cf2\b\\/a?a\\/ oo\cf0\b0 " will return you these two lines "\cf4\i And looked down one as far as I could\cf0\i0 " and "\cf4\i Then took the other, as just as fair,\cf0\i0 " in which, the "\cf2\b ?\cf0\b0 " represents any valid character regex recognized it as "word" element. Besides, the space has been cared so that the toggle works across it. for instance, enter "\cf2\b\\/tr yw\cf0\b0 " or "\cf2\b\\/yw tr\cf0\b0 " will show this line "\cf4\i Two roads diverged in a yellow wood,\cf0\i0 " where the space is still a separator as always, even though the shorthand feature is toggled on.\par
\pard\sa200\sl276\slmult1\par
\tab three more elements of the shorthand syntax:\par
\par
\pard\fi-360\li1800\sa200\sl276\slmult1 1, \b extra qualifier\b0 (within a single word);\par
2, \b escape character\b0 (between words);\par
3, a single \b character\b0 representing any "\b non-word\b0 " one (between words).\par
\pard\sa200\sl276\slmult1\par
\pard\li720\sa200\sl276\slmult1 the most basic usage of improvised shorthand is to match the specific "phrase" by just entering the first letter of each word constituted it (for instance, "\cf2\b sameto\cf0\b0 " can match "\cf4\i some are more equal than others\cf0\i0 ") yet sometimes we may want to further narrow down the result. if "\cf2\b slh\cf0\b0 " brings you both "\cf4\i she likes him\cf0\i0 " and "\cf4\i she loves him\cf0\i0 ", an extra qualifier to pinpoint one may be useful. it could simply be a "v" for this example hence "\cf2\b slv/h\cf0\b0 " (in which, the "/" after the "v" tells the system that it's just an extra qualifier to the "l", not for a word starts with "v",) returns you "\cf4\i she loves him\cf0\i0 " only. likewise, you may sometimes want to tell the system exactly what the word should be ending with, for instance, if "\cf2\b ioy\cf0\b0 " brings you both "\cf4\i i owe you\cf0\i0 " and "\cf4\i i own you\cf0\i0 ", "\cf2\b ioe//y\cf0\b0 " (in which, the "//" after the "e" tells the system that it's a word ending character, that is, "oe//" represents a word starts with "o" and ends with "e") returns you "\cf4\i i owe you\cf0\i0 " only. and no matter how rare (and impractical) it may be, you may have multiple of these qualifiers for a word, such as, "\cf2\b cm/c/e//d//\cf0\b0 " can match the word "\cf4\i complicated\cf0\i0 " whereas "\cf2\b td/i/u//s//\cf0\b0 " can match the word "\cf4\i tedious\cf0\i0 ".\par
\par
a \b backslash\b0 "\cf2\b\\\cf0\b0 " may be used to escape a single character after it. its target should be a "word" character because you don't need to escape otherwise. for all "non-word" character, just enter them directly except "\\" itself which requires a \b double backslash\b0 "\cf2\b\\\\\cf0\b0 " for a single one. for regex syntax such as "\\s", it becomes "\\\\s" (not "\\\\\\s" you may presume.) in other words, all escaped character will only be matched barely itself. for \ul consecutive\ulnone "word" characters that need to be escaped, enclose them in the \cf2\b\\Q\cf0\b0 \cf2\b\\E\cf0\b0 pair, similar idea as in regex. one thing to note though, escaped character may affect the word immediately after it, for instance, "\cf2\b z\\xy\cf0\b0 " may bring you "\cf4\i zebra xylophone\cf0\i0 " rather than "\cf4\i zombie x yesterday\cf0\i0 ".\par
\par
an \b apostrophe\b0 "\cf2\b\f1 '\cf0\b0\f0 " may be used to represent any "non-word" character. that is, same as "\\\\W" (the regex syntax "\\W" for a "non-word" character). it may be useful at the (beginning and/or ending) ends of the "phrase" if it can further narrow down the result or you simply want it to be a part of the match.\par
\pard\sa200\sl276\slmult1\par
The \b matches highlighting\b0 feature:\par
\pard\li720\sa200\sl276\slmult1 the \ul default behavior\ulnone is to highlight no more than a thousand matches (which can improve the response time when too many matches are found.) it can nonetheless be overridden by a long press of your left mouse button on one of the available gui buttons (i.e. go or refresh or back), whereas long press means press it down and hold on for \ul one second or longer\ulnone . therefore, highlighting will cover the whole thing even if the total number of matches is over \ul one thousand\ulnone . this \ul long-press-to-override\ulnone is not a toggle, it's just an \ul one-off\ulnone thing, so do it every time you want more than the default.\par
\pard\sa200\sl276\slmult1\par
End of this help page.\par
}
)
StringReplace, HelpPage, HelpPage, `n, `r`n, All
Haystack=
(
The Road Not Taken
BY ROBERT FROST
Two roads diverged in a yellow wood,
And sorry I could not travel both
And be one traveler, long I stood
And looked down one as far as I could
To where it bent in the undergrowth;
Then took the other, as just as fair,
And having perhaps the better claim,
Because it was grassy and wanted wear;
Though as for that the passing there
Had worn them really about the same,
And both that morning equally lay
In leaves no step had trodden black.
Oh, I kept the first for another day!
Yet knowing how way leads on to way,
I doubted if I should ever come back.
I shall be telling this with a sigh
Somewhere ages and ages hence:
Two roads diverged in a wood, and I—
I took the one less traveled by,
And that has made all the difference.
)
n := 1, pn := n - 1, Haystack%n% := Haystack%pn% := Haystack, NeedleHistory := ""
regFayt := regCase := regWwrap := 1, regWhole := regLinum := fromWordWrap := fromAssortment := 0
theGui:
Gui, tf:New, +HwndHGUI
Gui, +Delimiter`n
Gui, +Resize +MinSize +MaximizeBox
Gui, Font, s10, Arial New
Gui, Add, Text,, O p t i o n s:
begFayt := regFayt ? "Checked" : ""
Gui, Add, Checkbox, ym vFayt %begFayt% Tabstop gtfFaytHdlr, Instant Filter (aka Find As You Type)
begCase := regCase ? "Checked" : ""
Gui, Add, Checkbox, ym vCase %begCase% Tabstop gtfOptsHdlr, Case Insensitive
begWhole := regWhole ? "Checked" : ""
Gui, Add, Checkbox, ym vWhole %begWhole% Tabstop gtfOptsHdlr, Whole Word
begLinum := regLinum ? "Checked" : ""
Gui, Add, Checkbox, ym vLinum %begLinum% Tabstop gtfLineHdlr, Line Number
beg_Wrap := regWwrap ? "Checked" : ""
Gui, Add, Checkbox, ym vWwrap %beg_Wrap% Tabstop gtfWrapHdlr, Word Wrap
Gui, Font, s18, Arial New
Gui, Add, Text, xm Section, Filter:
w := A_ScreenWidth - 330
Gui, Add, ComboBox, w%w% ys vNeedleCB gtfFpatHdlr +hwndhEdit1
Gui, Add, Button, h38 ys Default, Go
Gui, Font, s10, Arial New
Gui, Add, Button, h38 ys, Refresh
Gui, Font, s18, Arial New
Gui, Add, Button, h38 ys, Back
h := A_ScreenHeight - 143, w := A_ScreenWidth - 30
begWwrap := regWwrap ? "+Wrap" : "+HScroll"
Gui, Font, s18, Consolas
Gui, Add, Custom, ClassRICHEDIT50W x10 h%h% w%w% %begWwrap% +VScroll +hwndHRE +0x0004 ;ES_MULTILINE
h := A_ScreenHeight - 66, w := A_ScreenWidth - 6
Gui, Show, h%h% w%w%, The Text Filter,, The Text Filter (Version: %Version%) - Level %n% ( Base %blc% Lines ) %SelectedFile%
RE := GetTomDoc(HRE)
RenewGui:
If regWwrap
SendMessage, 1101, 1, 0x0044, , % "ahk_id " . HRE ;turn ReadOnly Off w/o HScroll
Else SendMessage, 1101, 1, 0x00C4, , % "ahk_id " . HRE ;turn ReadOnly Off w/ HScroll
SendMessage, 0x0443, 0, 0xFFFFEE, , % "ahk_id " . HRE ;light Up BackgroundColor
If fromAssortment
fromAssortment := False
Else ControlSetText, RICHEDIT50W1, % Haystack%n%, A
ControlGetText, Hays, RICHEDIT50W1, A
StringReplace, Hays, Hays, `r`n, `n, All ;for RichEdit
StrReplace(Haystack, "`n",, oc), oc += StrLen(Haystack) and SubStr(Haystack, 0) != "`n" ? 1 : 0, lsl := StrLen(oc), indent := (lsl + 2) * 10
RE.Range(0, StrLen(Hays)).SetIndents(-indent, indent, 0)
If fromWordWrap
sPat := Needle%n%, fromWordWrap := False
Else ControlGetText, sPat, Edit1, A
If StrLen(sPat)
{ Gosub, MakerFnm
If StrLen(r) and RegExMatch(Hays, r)
{ Progress, zh0 w300 c10 fs18, `nHang On...`n,, Working On Matches Highlighting, Segoe UI
mpos := 1, mlen := 0
While, (mpos := RegExMatch(Hays, r, nm, mpos + mlen)) and (A_Index < 1000 or lbduration > 1000)
mlen := StrLen(nm), RE.Range(mpos - 1, mpos + mlen - 1).Font.BackColor := 0x00FFFF, npos := mpos
lbduration := 0
Progress, Off
}
}
SendMessage, 0x0443, 0, 0xF0F0F0, , % "ahk_id " . HRE ;tune Down BackgroundColor
If regWwrap
SendMessage, 1101, 1, 0x0844, , % "ahk_id " . HRE ;turn ReadOnly On w/o HScroll
Else SendMessage, 1101, 1, 0x08C4, , % "ahk_id " . HRE ;turn ReadOnly On w/ HScroll
ControlFocus, Edit1, A
SetWinTitle:
Gosub, tfCount_bl
WinSetTitle, The Text Filter,, The Text Filter (Version: %Version%) - Level %n% ( Base %blc% Lines ) %SelectedFile%
Return
tfCount_bl:
StrReplace(Haystack%n%, "`n",, blc), blc += StrLen(Haystack%n%) and SubStr(Haystack%n%, 0) != "`n" ? 1 : 0
Return
RClickMenu:
ControlGetText, Hays, RICHEDIT50W1, A
MouseGetPos, rbx, rby, mow, moc
If (mow = HGUI) and rby > 30
If (moc = "Button8")
Goto, ShowTrail
Else If (moc not = "Edit1")
{ Menu, myMenu, Add
Menu, myMenu, DeleteAll
Menu, myMenu, Add, Show Assorted Matches, MenuHandler
If SubStr(Hays, 1, 19) = "Assorted Matches:`t("
Menu, myMenu, Add, Put Assorted Matches In TreeView, MenuHandler
Menu, myMenu, Add
Menu, myMenu, Add, Increase Font Size, MenuHandler
Menu, myMenu, Add, Decrease Font Size, MenuHandler
Menu, myMenu, Add
Menu, myMenu, Add, Paste Into The Base, MenuHandler
Menu, myMenu, Add, Open A File, MenuHandler
Menu, myMenu, Add, Reload The File, MenuHandler
Menu, myMenu, Add
Menu, myMenu, Add, List Global Variables, MenuHandler
If (moc = "RICHEDIT50W1")
{ Menu, myMenu, Add
Menu, myMenu, Add, Copy The Line, MenuHandler
Menu, myMenu, Add, Go To Rightmost Of The Line, MenuHandler
Menu, myMenu, Add, Go To Leftmost Of The Line, MenuHandler
Menu, myMenu, Add, Go To The Bottom, MenuHandler
Menu, myMenu, Add, Go To The Top, MenuHandler
Menu, myMenu, Add, Page Down, MenuHandler
Menu, myMenu, Add, Page Up, MenuHandler
}
Menu, myMenu, Add
Menu, myMenu, Add, Downward Find Next Match, MenuHandler
Menu, myMenu, Add, Upward Find Next Match, MenuHandler
Menu, myMenu, Add
Menu, myMenu, Add, Override The 1K Default, MenuHandler
Menu, myMenu, Add
Menu, myMenu, Add, Show/Hide Help Page, MenuHandler
Menu, myMenu, Show
}
Return
MenuHandler:
If A_ThisMenuItem = Show Assorted Matches
Goto, !a
Else If A_ThisMenuItem = Put Assorted Matches In TreeView
Goto, AssTreeView
Else If A_ThisMenuItem = Increase Font Size
Goto, +
Else If A_ThisMenuItem = Decrease Font Size
Goto, -
Else If A_ThisMenuItem = Paste Into The Base
Goto, !v
Else If A_ThisMenuItem = Open A File
Goto, ^o
Else If A_ThisMenuItem = Reload The File
Goto, ^r
Else If A_ThisMenuItem = List Global Variables
{ Gui, tf:Destroy
Haystack := ListGlobalVars(), Haystack1 := Haystack0 := Haystack, Needle1 := "", n := 1, pn := n - 1
Goto, theGui
}Else If A_ThisMenuItem = Copy The Line
{ MouseMove, rbx, rby
Send, {LButton}
Goto, ~Enter
}Else If A_ThisMenuItem = Go To Rightmost Of The Line
{ MouseMove, rbx, rby
Send, {LButton}{End}
}Else If A_ThisMenuItem = Go To Leftmost Of The Line
{ MouseMove, rbx, rby
Send, {LButton}{Home}
}Else If A_ThisMenuItem = Go To The Bottom
{ MouseMove, rbx, rby
Send, {LButton}^{End}
}Else If A_ThisMenuItem = Go To The Top
{ MouseMove, rbx, rby
Send, {LButton}^{Home}
}Else If A_ThisMenuItem = Page Down
{ MouseMove, rbx, rby
Send, {LButton}{PgDn}
}Else If A_ThisMenuItem = Page Up
{ MouseMove, rbx, rby
Send, {LButton}{PgUp}
}Else If A_ThisMenuItem = Downward Find Next Match
{ ControlFocus, RICHEDIT50W1, A
Goto, NextMatch
}Else If A_ThisMenuItem = Upward Find Next Match
{ ControlFocus, RICHEDIT50W1, A
Uffm := True ;Upward FNM From Menu
Goto, NextMatch
}Else If A_ThisMenuItem = Override The 1K Default
{ lbduration := 1234
Goto, RenewGui
}Else If A_ThisMenuItem = Show/Hide Help Page
Goto, F1
Return
ShowTrail:
Menu, myTrail, Add
Menu, myTrail, DeleteAll
While, A_Index < n
{ tn := n - A_Index, theNeedle := Needle%tn%, bn := n, n := tn
Gosub, tfCount_bl
n := bn
Menu, myTrail, Add, Level &%tn% remains %blc% lines after this filter: %theNeedle%, BtsLevel
}
bn := n, n := 0
Gosub, tfCount_bl
n := bn
Menu, myTrail, Add, Origin %blc% lines (Level &0), BtsLevel
Menu, myTrail, Show
Return
BtsLevel:
n -= A_ThisMenuItemPos
If n < 1
Haystack1 := Haystack0, Needle1 := "", n := 1
pn := n - 1
ControlSetText, Edit1, % Needle%n%, The Text Filter
Gosub, RenewGui
Return
tfFaytHdlr:
regFayt := Fayt()
If regFayt
If (Haystack%n% != Haystack%pn%)
{ Needle%n% := Fpat()
theHaystack := Haystack%n%, theNeedle := Needle%n%
n += 1, pn := n - 1
Haystack%n% := theHaystack, Needle%n% := theNeedle
Gosub, SetWinTitle
}
tfOptsHdlr:
ControlFocus, Edit1, A
Goto, tfFpatHdlr
tfLineHdlr:
If regLinum := Linum()
{ Progress, zh0 w300 c10 fs18, `nHang On...`n,, Working On Line Numbering, Segoe UI
StrReplace(Haystack, "`n",, oc), oc += StrLen(Haystack) and SubStr(Haystack, 0) != "`n" ? 1 : 0, lsl := StrLen(oc)
HaystackN =
Loop, Parse, Haystack, `n
HaystackN .= SubStr(StrRepeat(A_Space, lsl) A_Index, 1-lsl) ":" A_Space A_LoopField "`n"
Progress, Off
Haystack0 := HaystackN
}Else Haystack0 := Haystack
Loop, % n
{ nn := A_Index, pn := nn - 1
Haystack%nn% := RegExReplace(Haystack%pn%, Maker(Needle%nn%))
}
Goto, RenewGui
tfWrapHdlr:
fromWordWrap := True
regWwrap := Wwrap()
Needle%n% := Fpat()
Gui, tf:Destroy
Gosub, theGui
ControlSetText, Edit1, % Needle%n%, A
Send, {End}
Return
tfButtonGo:
ControlFocus, Edit1, A
Progress, zh0 w380 c10 fs18, `nCommitting This Level`n,, Prompt, Segoe UI
CommitLevel = 1
tfFpatHdlr:
If not regFayt and not CommitLevel
Return
Gui, Submit, NoHide
regCase := Case(), regWhole := Whole()
Needle%n% := Fpat()
If not StrLen(Needle%n%) and CommitLevel
{ CommitLevel = 0
Goto, tfButtonBack
}
theHaystack := RegExReplace(Haystack%pn%, Maker(Needle%n%))
If CommitLevel
{ If not StrLen(NeedleHistory)
NeedleHistory := Needle%n%, Added := 1
Else If not RegExMatch(NeedleHistory, (regCase ? "i" : "") "m`a)^\Q" Needle%n% "\E$")
NeedleHistory := Needle%n% "`n" NeedleHistory, Added := 1
Else Added := 0
If Added
{ GuiControl,, NeedleCB, `n%NeedleHistory%
ControlSetText, Edit1, % Needle%n%
}
If (theHaystack = Haystack%pn%)
{ Progress, Off
MsgBox, Result No Change Thus Not Anew Level
}Else
{ If not regFayt
Haystack%n% := theHaystack
Gosub, tfCount_bl
If (blc < 2) and not (Needle%n% == Needle%pn%)
Progress, zh0 w450 c10 fs18, `nUltimate/Empty Result Reached`nThus Level Not Advanced`n,, Prompt, Segoe UI
Else
{ n += 1, pn := n - 1
Haystack%n% := theHaystack
Send, ^a
}
}
CommitLevel = 0
Sleep, 500
Progress, Off
}Else Haystack%n% := theHaystack
Gosub, RenewGui
If not regFayt and not StrLen(Haystack%n%)
{ Progress, zh0 w450 c10 fs18, `nEmpty Result Reached`n`nFalling Back Now`n,, Prompt, Segoe UI
Sleep, 1000
Haystack%n% := Haystack%pn%
ControlSetText, Edit1, % Needle%pn%
Gosub, RenewGui
Send, ^a
Progress, Off
}
Return
Maker(t) {
t := tw4sh(t), r := (Case() ? "i" : "") "m`a)^(?!"
Loop, Parse, t, % A_Space
If SubStr(A_LoopField, 1, 1) = "-"
r .= "(?!.*(" (Whole() ? "\b" : "") SubStr(A_LoopField, 2) (Whole() ? "\b" : "") "))"
Else r .= "(?=.*(" (Whole() ? "\b" : "") A_LoopField (Whole() ? "\b" : "") "))"
r .= ").*\R?"
Return r
}
tfButtonRefresh:
Goto, RenewGui
tfButtonBack:
ControlFocus, Edit1, A
Needle%n% := Fpat()
If (n = 1) and (Haystack1 != Haystack0)
Haystack1 := Haystack0, Needle1 := ""
Else If (Haystack%n% = Haystack%pn%) and (Needle%n% = Needle%pn%)
If n > 2
n -= 2, pn := n - 1
Else If n = 2
n := 1, pn := n - 1, Haystack1 := Haystack0, Needle1 := ""
Else n = 0
Else n -= 1, pn := n - 1
If n
{ ControlSetText, Edit1, % Needle%n%
Gosub, RenewGui
Send, ^a
If (n = 1) and (Haystack1 = Haystack0)
{ Progress, zh0 w380 c10 fs18, `nReturned To The Origin`n,, Prompt, Segoe UI
Sleep, 500
Progress, Off
}Else
{ Progress, zh0 w380 c10 fs18, `nReturned To Level %n%`n,, Prompt, Segoe UI
Sleep, 500
Progress, Off
}
Return
}Else Goto, tfGuiClose
tfGuiSize:
If A_EventInfo = 1
Return
GuiControl, Move, RICHEDIT50W1, % "h" (A_GuiHeight - 97) " w" (A_GuiWidth - 14)
Return
tfGuiEscape:
tfGuiClose:
IfExist, tfWork.rtf
FileDelete, tfWork.rtf
IfExist, tfHelp.rtf
FileDelete, tfHelp.rtf
ExitApp
EventHandler(wParam, lParam, msg, hwnd) {
static lbdowntime := 0
global lbduration := 0
If msg = 0x201 ;WM_LBUTTONDOWN
lbdowntime := A_TickCount
Else If msg = 0x202 ;WM_LBUTTONUP
lbduration := A_TickCount - lbdowntime
Return
}
GetTomDoc(HRE) { ;written by "@just me"
Static IID_ITextDocument := "{8CC497C0-A1DF-11CE-8098-00AA0047BE5D}"
DocObj := 0
If DllCall("SendMessage", "Ptr", HRE, "UInt", 0x043C, "Ptr", 0, "PtrP", IRichEditOle, "UInt") ;EM_GETOLEINTERFACE
{ DocObj := ComObject(9, ComObjQuery(IRichEditOle, IID_ITextDocument), 1) ; ITextDocument
ObjRelease(IRichEditOle)
}
Return DocObj
}
Fpat() {
ControlGetText, Fpat, Edit1
Return Fpat
}
Fayt() {
GuiControlGet, Fayt,, Button1
Return Fayt
}
Case() {
GuiControlGet, Case,, Button2
Return Case
}
Whole() {
GuiControlGet, Whole,, Button3
Return Whole
}
Linum() {
GuiControlGet, Linum,, Button4
Return Linum
}
Wwrap() {
GuiControlGet, Wwrap,, Button5
Return Wwrap
}
tw4sh(t) {
tog := "\/", va := "?\\'\w", ph := "[^" va "\n]", tar := "\" tog ph "*?\K[" va "]", ph := "[^\w\n]"
If mpos:=RegExMatch(t, tar) ;contained toggle (on)
{ pb := "[^\w\n]", sh := "((?<=^|" ph ")", st := "(?=(\W|$)))"
skip_c := skip_w := yb := False
r := StrReplace(SubStr(t, 1, mpos - 1), tog) sh, rr := xx := ""
Loop
{ c := SubStr(t, mpos, 1), cc := SubStr(t, mpos + 1, 1)
If skip_c
skip_c--
Else If SubStr(t, mpos, StrLen(tog)) = tog ;toggle (off) encountered
{ flush(r, xx, pb, yb, st), rr := xx := ""
mpos += StrLen(tog), npos := mpos
If mpos:=RegExMatch(t, tar,, npos) ;found next toggle (on)
r .= StrReplace(SubStr(t, npos, mpos - npos), tog) sh, rr := xx := ""
Else
{ r .= SubStr(t, npos)
Break
}
Continue
}Else If RegExMatch(c, "\w") or (c = "?") ;valid character
{ If rr
If not skip_w and ((cc not = "/") or StrLen(xx))
flush(r, xx, pb, yb)
Else If (cc = "/") and not StrLen(xx)
{ If SubStr(t, mpos + 2, 1) = "/"
skip_w := skip_w ? skip_w : True, skip_c++
skip_c++
}Else{}
Else If StrLen(rr)
r .= xx sh, rr := xx := ""
r .= (c = "?") ? (skip_w ? "\w" : ("\w+?", yb++)) : c (skip_w ? "" : ("\w*?", yb++)), skip_w -= skip_w ? 1 : 0, rr := True
}Else If (c = A_Space) and rr
flush(r, xx, pb, yb, st), xx := A_Space, rr := 0
Else If (c = "'")
xx .= "\W"
Else If (c = "\") and skip_w not < 0
If (cc == "Q")
skip_c++, skip_w := -1, flush(r, xx, pb, yb)
Else If (cc == "E")
skip_c++, skip_w := False
Else If (cc = c)
xx .= c
Else If RegExMatch(cc, "\w")
skip_c++, xx .= cc
Else skip_c++, xx .= c cc
Else xx .= c
mpos++
If (mpos > StrLen(t)) ;exceeded
{ If rr
flush(r, xx, pb, yb, st), rr := xx := ""
Break
}
}
}Else r := t
Return r
}
flush(ByRef r, ByRef xx, pb, ByRef yb, st := "") {
mb := "[^,;\w\n.?!]+?", ss := SubStr(xx, -1), sc := (ss == "\W") or (ss == "\s") or (ss == "\t") or (ss == "\r") or (ss == "\n"), r .= xx ? (RegExMatch(SubStr(xx, 1, 1), "\w") ? mb : pb "*?") xx (st ? ")" : (RegExMatch(ss, "\\?\w$") and not sc ? "" : pb "*?")) : (st ? st : (yb ? (mb, yb--) : "")), xx := ""
}
escrx(h) {
e := "\().[]*+?{}^$|"
Loop, Parse, e
If InStr(h, A_LoopField)
h := StrReplace(h, A_LoopField, "\" A_LoopField)
Return h
}
StrRepeat(string, times) {
Loop, %times%
output .= string
Return output
}
FocusedControl() {
ControlGetFocus, foco, A
Return foco
}
#If, WinActive("The Text Filter") and FocusedControl() = "Edit1"
`::
Tab::ControlFocus, RICHEDIT50W1, A
#If, WinActive("The Text Filter") and FocusedControl() = "RICHEDIT50W1"
Tab::ControlFocus, Edit1, A
~Space::PgDn
~+Space::PgUp
~s::Home
~e::End
~t::^Home
~b::^End
-::
MouseGetPos, mpx, mpy,, moc
If (moc not = "RICHEDIT50W1")
MouseMove, 400, 200
Send, ^{WheelDown}
If (moc not = "RICHEDIT50W1")
MouseMove, mpx, mpy
Return
+::
=::
MouseGetPos, mpx, mpy,, moc
If (moc not = "RICHEDIT50W1")
MouseMove, 400, 200
Send, ^{WheelUp}
If (moc not = "RICHEDIT50W1")
MouseMove, mpx, mpy
Return
`::
~Enter::
ControlGetText, Hays, RICHEDIT50W1, A
StringReplace, Hays, Hays, `r`n, `n, All ;for RichEdit
slcs := RE.Selection.Start, slce := RE.Selection.End
mpos := slce + 1
While, mpos > 1 and SubStr(Hays, mpos - 1, 1) not = "`n"
mpos--
slcs := mpos, mpos := slce + 1, pmax := StrLen(Hays)
While, mpos <= pmax and not InStr("`r`n", SubStr(Hays, mpos, 1))
mpos++
Clipboard := mpos > pmax ? SubStr(Hays, slcs) : SubStr(Hays, slcs, mpos - slcs)
TakeThis:
Clipboard := RegExReplace(Clipboard, "^\t?(?: *?\d+?: )?(.*)$", "$1")
MsgBox,,, Has Put This Line Into Clipboard, 3
Goto, tfGuiClose
~f::
~+f::
NextMatch:
ControlGettext, sPat, Edit1, A
If StrLen(sPat)
Gosub, MakerFnm
Else
{ sPat := RE.Selection.Text
r := StrLen(sPat) ? (regCase ? "i)" : "") (regWhole ? "\b" : "") escrx(sPat) (regWhole ? "\b" : "") : ""
}
If StrLen(r)
{ ControlGettext, Hays, RICHEDIT50W1, A
StringReplace, Hays, Hays, `r`n, `n, All ;for RichEdit
If RegExMatch(Hays, r)
{ StartHere:
Gosub, Compute_cp
If RegExMatch(A_ThisHotkey, "WheelUp|\+f") or Uffm
{ Gosub, ReverseWay
mpos -= 1
}Else mpos := RegExMatch(Hays, r, nm, cp) - 1
If mpos >= 0
{ cp := mpos + StrLen(nm)
RE.Range(mpos, cp).Select
}Else If (mpos < 0) and not RegExMatch(A_ThisHotkey, "WheelUp|\+f") and not Uffm
{ RE.Range(0, 0).Select
Goto, StartHere
}
}Else MsgBox, Target Not Found
}
Uffm := False ;Upward FNM From Menu
Return
MakerFnm:
sPat := tw4sh(sPat), r := ""
Loop, Parse, sPat, % A_Space
If SubStr(A_LoopField, 1, 1) != "-"
r .= "(" (regWhole ? "\b" : "") A_LoopField (regWhole ? "\b" : "") ")|"
If StrLen(r)
{ If SubStr(r, 0) = "|"
r := SubStr(r, 1, StrLen(r) - 1)
r := (regCase ? "i" : "") "m`a)" r
}
Return
Compute_cp:
slcs := RE.Selection.Start, slce := RE.Selection.End, slcs++, slce++
cp := RegExMatch(A_ThisHotkey, "WheelUp|\+f") or Uffm ? slcs : slce
Return
ReverseWay:
If cp > 1
{ mpos := 0, pmax := cp - 1
Loop
{ npos := RegExMatch(Hays, r, pm, mpos+1)
If npos between 1 and %pmax%
mpos := npos, nm := pm
Else Break
}
If (npos > pmax) and mpos > 0
Return
}
mpos := cp - 1, pmax := StrLen(Hays)
Loop
{ npos := RegExMatch(Hays, r, pm, mpos+1)
If npos between %cp% and %pmax%
mpos := npos, nm := pm
Else Break
}
Return
#If, WinActive("TreeView Of Assorted Matches") and FocusedControl() = "SysTreeView321"
`::
~Enter::Gosub, ButtonEnter
#IfWinActive, The Text Filter
F1::
ControlGetText, Hays, RICHEDIT50W1, A
If SubStr(Hays, 1, 17) = "H e l p _ P a g e"
IfExist, tfWork.rtf
RE.Open("tfWork.rtf", 0x01, 0)
Else ControlSetText, RICHEDIT50W1, %B4Help%, A
Else
{ B4Help := Hays
IfExist, tfWork.rtf
RE.Save(0, 0, 0)
Else RE.Save("tfWork.rtf", 0x01, 0)
IfExist, tfHelp.rtf
FileDelete, tfHelp.rtf
FileAppend, %HelpPage%, tfHelp.rtf
RE.Open("tfHelp.rtf", 0x01, 0)
}
Return
~Wheelup::
~Wheeldown::
MouseGetPos,,,, moc
If not StrLen(moc) or not InStr("Edit1|RICHEDIT50W1", moc)
{ ControlFocus, RICHEDIT50W1, A
Goto, NextMatch
}Else Return
!a::
fromAssortment := True
ControlGetText, Hays, RICHEDIT50W1, A
If SubStr(Hays, 1, 19) = "Assorted Matches:`t("
{ If SubStr(Hays, 20, 12) = "Alphabetical"
ControlSetText, RICHEDIT50W1, %AssHays%, A
Else
ControlSetText, RICHEDIT50W1, %AAssHays%, A
Gosub, RenewGui
Return
}
If not StrLen(Haystack%n%)
Return
ControlGetText, sPat, Edit1, A
If not StrLen(sPat)
Return
Gosub, MakerFnm
If not StrLen(r)
Return
Progress, zh0 w300 c10 fs18, `nHang On...`n,, Working On Assortment, Segoe UI
rn = `r`n
UniqMatches := [], Seq := 0
Loop, Parse, Haystack%n%, `n
{ mpos = 1
worknm:
npos := RegExMatch(A_LoopField, r, nm, mpos)
If npos
{ If UniqMatches.HasKey(nm)
Ums := UniqMatches[nm], AssHays%Ums% .= InStr(AssHays%Ums%, A_LoopField) ? "" : rn "`t" A_LoopField
Else
Seq++, UniqMatches[nm] := Seq, AssHays%Seq% := nm rn "`t" A_LoopField
mpos := npos + StrLen(nm)
Goto, worknm
}
}
If Seq
{ UniqHays := gAAssHays := "", umNoSort := []
For k, v in UniqMatches
UniqHays .= rn StrRepeat(A_Space, 3) A_Index ".`t" k, gAAssHays .= rn A_Index ". " AssHays%v%, umNoSort[v] ? umNoSort[v].Insert(k) : umNoSort[v] := k
AAssHays := "Assorted Matches:`t(Alphabetical Order)" UniqHays rn StrRepeat("-", 50) gAAssHays
UniqHays := gAssHays := ""
For k, v in umNoSort
UniqHays .= rn StrRepeat(A_Space, 3) k ".`t" v, gAssHays .= rn A_Index ". " AssHays%k%
AssHays := "Assorted Matches:`t(Chronological Order)" UniqHays rn StrRepeat("-", 50) gAssHays
StringReplace, AssHays, AssHays, `r`n, `n, All ;for RichEdit
StringReplace, AAssHays, AAssHays, `r`n, `n, All ;for RichEdit
ControlSetText, RICHEDIT50W1, %AssHays%, A
Gosub, RenewGui
}
Progress, Off
Return
AssTreeView:
ControlGetText, Hays, RICHEDIT50W1, A
parwin := WinExist("A")
Gui, tvass:New, +Resize +MinSize +MaximizeBox +Owner%parwin%
Gui, Font, s18, Consolas
Gui, Add, Text,, % SubStr(Hays, 20, 12) = "Alphabetical" ? "Assorted Matches: (Alphabetical Order)" : "Assorted Matches: (Chronological Order)"
;Gui, Add, Button, Hidden Default, Enter
Gui, Add, TreeView, AltSubmit Section xm w545 gassTV
Seq := 0, aHays := StrReplace(SubStr(Hays, 20, 12) = "Alphabetical" ? gAAssHays : gAssHays, "`r`n", "`n")
Loop, Parse, aHays, `n
If StrLen(A_LoopField)
If RegExMatch(A_LoopField, "^ *\d+\.[ \t]")
Seq++, P%Seq% := TV_Add(A_LoopField), Num := 0
Else Num++, P%Seq%C%Num% := TV_Add(A_LoopField, P%Seq%)
Gui, Show, x97 y539 h283, TreeView Of Assorted Matches
GuiControl, Focus, assTV
Return
tvassGuiSize:
If A_EventInfo = 1
Return
GuiControl, Move, SysTreeView321, % "h" (A_GuiHeight - 76) " w" (A_GuiWidth - 46)
Return
assTV:
If InStr("DoubleClick|S|K|Normal", A_GuiEvent)
TV_GetText(theOne, TV_GetSelection())
If A_GuiEvent = DoubleClick
Goto, ButtonEnter
Return
ButtonEnter:
StringReplace, theOne, theOne, `r, , All
Clipboard := theOne
Goto, TakeThis
Return
!v:: ;paste Clipboard content into the Haystack
If StrLen(Clipboard)
{ Gui, tf:Destroy
Haystack1 := Haystack0 := Haystack := Clipboard, Needle1 := "", n := 1, pn := n - 1
Goto, theGui
}
Return
^o:: ;open file
SelectedFile =
FileSelectFile, SelectedFile
^r:: ;reload file
If SelectedFile
{ Gui, tf:Destroy
FileRead, Haystack, % SelectedFile
Haystack1 := Haystack0 := Haystack, Needle1 := "", n := 1, pn := n - 1
Goto, theGui
}Else Return
~RButton::Gosub, RClickMenu
#IfWinActive
ListGlobalVars() { ;written by Lexikos
static hwndEdit, pSFW, pSW, bkpSFW, bkpSW
If !hwndEdit
{ dhw := A_DetectHiddenWindows
DetectHiddenWindows, On
Process, Exist
ControlGet, hwndEdit, Hwnd,, Edit1, ahk_class AutoHotkey ahk_pid %ErrorLevel%
DetectHiddenWindows, %dhw%
astr := A_IsUnicode ? "astr":"str"
ptr := A_PtrSize=8 ? "ptr":"uint"
hmod := DllCall("GetModuleHandle", "str", "user32.dll")
pSFW := DllCall("GetProcAddress", ptr, hmod, astr, "SetForegroundWindow")
pSW := DllCall("GetProcAddress", ptr, hmod, astr, "ShowWindow")
DllCall("VirtualProtect", ptr, pSFW, ptr, 8, "uint", 0x40, "uint*", 0)
DllCall("VirtualProtect", ptr, pSW, ptr, 8, "uint", 0x40, "uint*", 0)
bkpSFW := NumGet(pSFW+0, 0, "int64")
bkpSW := NumGet(pSW+0, 0, "int64")
}
If (A_PtrSize=8)
{ NumPut(0x0000C300000001B8, pSFW+0, 0, "int64") ;return TRUE
NumPut(0x0000C300000001B8, pSW+0, 0, "int64") ;return TRUE
}Else
{ NumPut(0x0004C200000001B8, pSFW+0, 0, "int64") ;return TRUE
NumPut(0x0008C200000001B8, pSW+0, 0, "int64") ;return TRUE
}
ListVars
NumPut(bkpSFW, pSFW+0, 0, "int64")
NumPut(bkpSW, pSW+0, 0, "int64")
ControlGetText, text,, ahk_id %hwndEdit%
RegExMatch(text, "sm)(?<=^Global Variables \(alphabetical\)`r`n-{50}`r`n).*", text)
Return text
}
Last edited by SundayProgrammer on 05 May 2021, 00:12, edited 4 times in total.
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
the script is updated. → viewtopic.php?p=393548#p393548 ← click this link
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
^([[:blank:]]*\d+:[[:space:]])?[[:blank:]]*(#if\w*((,?[[:blank:]]*|[[:blank:]]+).+)?$|\K.+?::|\K[a-z]\w*:|\K\w+\(.*?\)[[:blank:]]*\{)
instant index pagewhich contains just #if, hotkeys/hotstrings/labels, and functions. i found it quite useful in navigation within the code (typically when it consists so many lines), and as a quick overview of the whole.
it looks like this
please, if you have other usage examples, share. thanks.
instant index pagewhich contains just #if, hotkeys/hotstrings/labels, and functions. i found it quite useful in navigation within the code (typically when it consists so many lines), and as a quick overview of the whole.
it looks like this
Spoiler
please, if you have other usage examples, share. thanks.
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
the script is updated. → viewtopic.php?p=393548#p393548 ← click this link
planet-seven-g added an overall rightclick menu which should have covered all the features available.
planet-seven-g added an overall rightclick menu which should have covered all the features available.
Re: Text Filter
SundayProgrammer wrote: ↑24 Apr 2021, 23:20added an overall rightclick menu which should have covered all the features available.
- Kellyzkorner_NJ
- Posts: 84
- Joined: 20 Oct 2017, 18:33
Re: Text Filter
I have a question for the newest version of this wonderful script, I used it on my really large main AHK script (55000 + lines) and since the results were very long, I'm needing to scroll down to see the next page. On every wheeldown I get the message 'Target Not Found', which I know is by design but is there a way to turn that off for the situations where you just want to scroll through results? I don't want to comment out the whole msgbox so I don't lose the functionality altogether. Thanks very much and thank you for your time on working on this. It is making and will make a lot of people happy I'm sure!
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
hi @Kellyzkorner_NJKellyzkorner_NJ wrote: ↑28 Apr 2021, 12:13I have a question for the newest version of this wonderful script, I used it on my really large main AHK script (55000 + lines) and since the results were very long, I'm needing to scroll down to see the next page. On every wheeldown I get the message 'Target Not Found', which I know is by design but is there a way to turn that off for the situations where you just want to scroll through results? I don't want to comment out the whole msgbox so I don't lose the functionality altogether. Thanks very much and thank you for your time on working on this. It is making and will make a lot of people happy I'm sure!
it seems to me that you triggered the "wheel search mode" by "accident". the trigger of the "wheel search mode" all depends on where your mouse pointer is currently at when you roll your mouse wheel. if it resides within the "main" box (the richedit control), it won't trigger the "wheel search mode". otherwise, it will "find next match" in your mouse wheel rolling direction, that's the behavior of the "wheel search mode".
the "wheel search mode" was devised as a quick way to reveal the exact location of each match. if it doesn't make sense to you (or you found it confusing more than convenient), just disable it as shown below.
see illustration
in fact, i seldom use it since the "matches highlighting" was implemented. it was kept because (a) it doesn't bother me to leave it there aside; (b) i still use "search by selection" which shares the same piece of code; (c) i can use it just in case.besides, i think removing the "target not found" msgbox is absolutely fine as one may not need to be prompted explicitly imo. you may remove it as shown below.
see illustration
the "wheel search mode" is not a new feature, it's been there since "planet-two".thank you for letting me know the issues you faced, i need it for improvement and also for a better design in the future.
thanks.
- Kellyzkorner_NJ
- Posts: 84
- Joined: 20 Oct 2017, 18:33
Re: Text Filter
@SundayProgrammer Thank you for the clarification and examples, I’ll do that. I LOVE the yellow highlighting and the right click. You’re very welcome. Have a great rest of your day!
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
the script is updated. → viewtopic.php?p=393548#p393548 ← click this link
planet-seven-h added a treeview gui for "assorted matches".
planet-seven-h added a treeview gui for "assorted matches".
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
star-zero
this new version is an overhaul of the coding. basically no new features, not yet. i've packed almost everything into a class object. and hopefully, it's much more convenient to put it into other script now, if one may want to do so.
its entrance is the start method, which uses just one parameter. four kinds are defined: (1) "load clipboard"; or (2) "load file thefilename"; or (3) a text string, on itself becomes the haystack; or (4) not to supply a parameter, which will pick up whatever left off in the object's memory.
besides, multiple instances coexisting are possible now. thus each instance/window will have its own unique id. and be shown on the window title ribbon. this id is equivalent to the object variable name. examples: as in (i) tf.start() and (ii) w1 := new tf, w1.start("hello world"), where tf (of "i") and w1 (of "ii") are the so-called id respectively.
the hotkeys part can all be removed (if one may want to do so) without problem, except two labels (subroutines), the pastehaysub and the openfilesub, which are hardcoded in the class to be accessing to. and also please keep the rbutton hotkey, so that, some of the features can have at least a way to be accessed when all keyboard-wise hotkeys are gone.
2021-6-2: star-zero-a made some adjustments.
2021-6-4: star-zero-b found a bug, and fixed.
2021-6-7: star-zero-c made three tweaks:
(a) added the "copy selection" ability to the existing feature "copy the line" (thus it becomes "copy the line/selection" now.) so, if some text is selected in the big text/edit box (the "richedit50w1"), it will be copied instead of the entire line. selection or selected text refers to the result of mouse lbutton drag or keyboard shift+arrows (and the likes) or mix-of-both shift+click operation. please note a subtle difference between "copy selection" and "copy the line" when it was accessed through rightclick menu. that is, the former doesn't care where the mouse pointer was at when the rbutton was clicked. coz selection was made, just copy it, that's all. whereas the later assumed the mouse pointer was placed on the line to be copied though, when the rbutton was clicked.
(b) added certain checking for the "find selection" (an associated feature within the "find next match") so that the small text/edit box (the "edit1") need not be cleared beforehand. kinda prioritized "selection" over "edit1" for the "find next match" operation. however, this change applies only to the wheel search mode and those through rightclick menu, whereas the keyboard hotkey "f" and "+f" remained same as before.
(c) right click now caters drag operation that may be used in other scripts. as a result, the rightclick menu will not be shown if it's a rbutton drag operation.
....................
that's it for now.
this new version is an overhaul of the coding. basically no new features, not yet. i've packed almost everything into a class object. and hopefully, it's much more convenient to put it into other script now, if one may want to do so.
its entrance is the start method, which uses just one parameter. four kinds are defined: (1) "load clipboard"; or (2) "load file thefilename"; or (3) a text string, on itself becomes the haystack; or (4) not to supply a parameter, which will pick up whatever left off in the object's memory.
besides, multiple instances coexisting are possible now. thus each instance/window will have its own unique id. and be shown on the window title ribbon. this id is equivalent to the object variable name. examples: as in (i) tf.start() and (ii) w1 := new tf, w1.start("hello world"), where tf (of "i") and w1 (of "ii") are the so-called id respectively.
the hotkeys part can all be removed (if one may want to do so) without problem, except two labels (subroutines), the pastehaysub and the openfilesub, which are hardcoded in the class to be accessing to. and also please keep the rbutton hotkey, so that, some of the features can have at least a way to be accessed when all keyboard-wise hotkeys are gone.
2021-6-2: star-zero-a made some adjustments.
2021-6-4: star-zero-b found a bug, and fixed.
2021-6-7: star-zero-c made three tweaks:
(a) added the "copy selection" ability to the existing feature "copy the line" (thus it becomes "copy the line/selection" now.) so, if some text is selected in the big text/edit box (the "richedit50w1"), it will be copied instead of the entire line. selection or selected text refers to the result of mouse lbutton drag or keyboard shift+arrows (and the likes) or mix-of-both shift+click operation. please note a subtle difference between "copy selection" and "copy the line" when it was accessed through rightclick menu. that is, the former doesn't care where the mouse pointer was at when the rbutton was clicked. coz selection was made, just copy it, that's all. whereas the later assumed the mouse pointer was placed on the line to be copied though, when the rbutton was clicked.
(b) added certain checking for the "find selection" (an associated feature within the "find next match") so that the small text/edit box (the "edit1") need not be cleared beforehand. kinda prioritized "selection" over "edit1" for the "find next match" operation. however, this change applies only to the wheel search mode and those through rightclick menu, whereas the keyboard hotkey "f" and "+f" remained same as before.
(c) right click now caters drag operation that may be used in other scripts. as a result, the rightclick menu will not be shown if it's a rbutton drag operation.
that's it for now.
Code: Select all
SetWorkingDir %A_ScriptDir%
RE_Dll := DllCall("LoadLibrary", "Str", "Msftedit.dll", "Ptr")
thePoem=
(
The Road Not Taken
BY ROBERT FROST
Two roads diverged in a yellow wood,
And sorry I could not travel both
And be one traveler, long I stood
And looked down one as far as I could
To where it bent in the undergrowth;
Then took the other, as just as fair,
And having perhaps the better claim,
Because it was grassy and wanted wear;
Though as for that the passing there
Had worn them really about the same,
And both that morning equally lay
In leaves no step had trodden black.
Oh, I kept the first for another day!
Yet knowing how way leads on to way,
I doubted if I should ever come back.
I shall be telling this with a sigh
Somewhere ages and ages hence:
Two roads diverged in a wood, and I—
I took the one less traveled by,
And that has made all the difference.
)
; tf.start("Load Clipboard")
; msgbox
; tf.start("Load File log.txt")
; msgbox
tf.start(thePoem)
; msgbox
; tf.start() ;from what's leftoff in the object's memory
;multiple instances can be coexisting as below
; w1 := new tf, w1.start("Load Clipboard")
; w2 := new tf, w2.start("Load File log.txt")
; w3 := new tf, w3.start(thePoem)
; msgbox
; w3.start() ;from what's leftoff in the object's memory
Return
FocusedControl() {
ControlGetFocus, foco, A
Return foco
}
#If, WinActive("The Text Filter") and FocusedControl() = "Edit1"
`::
Tab::ControlFocus, RICHEDIT50W1, A
#If, WinActive("The Text Filter") and FocusedControl() = "RICHEDIT50W1"
Tab::ControlFocus, Edit1, A
Space::PgDn
+Space::PgUp
s::Home
e::End
t::^Home
b::^End
-::%_cwi_%.DecrFontSize()
+::
=::%_cwi_%.IncrFontSize()
`::
Enter::%_cwi_%.TakeThisLine()
f::%_cwi_%.FindNextMatch()
+f::%_cwi_%.FindNextMatch(1)
#If, WinActive("TreeView Of Assorted Matches") and FocusedControl() = "SysTreeView321"
`::
Enter::%_cwi_%.tvButtonEnter()
#IfWinActive, The Text Filter
F1::%_cwi_%.ToggleHelpPage(_cwi_)
~WheelUp::
~WheelDown::%_cwi_%.WheelSearchMode()
!a::%_cwi_%.ShowAssMatches()
^t::%_cwi_%.AssTreeView(_cwi_)
!v::Gosub, PasteHaySub
^o::Gosub, OpenFileSub
^r::%_cwi_%.ReloadFile()
~RButton::%_cwi_%.RClickMenu()
#IfWinActive
PasteHaySub:
If _uii_ := %_cwi_%.PasteIntoHaystack()
%_uii_% := new tf, %_uii_%.start("Load Clipboard")
Return
OpenFileSub:
If _OpFi_ := %_cwi_%.OpenFile()
{ RegExMatch(_OpFi_, "^\w+(?=\t)", _uii_), RegExMatch(_OpFi_, "\t\K.+$", _usf_)
%_uii_% := new tf, %_uii_%.start("Load File " _usf_)
}
Return
WM_ACTIVATE(wParam) {
global _cwi_
If (wParam > 0)
If WinActive("The Text Filter") or WinActive("TreeView Of Assorted Matches")
{ WinGetTitle, t, A
If RegExMatch(t, "\| *?(\w*?) *?\|", m) and StrLen(m1)
_cwi_ := m1
Else _cwi_ := "Oops..."
}Else _cwi_ := "Other Windows"
}
EventHandler(wParam, lParam, msg, hwnd) {
static lbdowntime := 0
global lbduration := 0
If msg = 0x201 ;WM_LBUTTONDOWN
lbdowntime := A_TickCount
Else If msg = 0x202 ;WM_LBUTTONUP
lbduration := A_TickCount - lbdowntime
Return
}
Class tf {
static o := {}
v := {}
start(Param := "") {
OnMessage(0x6, "WM_ACTIVATE")
OnMessage(0x201, "EventHandler") ;WM_LBUTTONDOWN
OnMessage(0x202, "EventHandler") ;WM_LBUTTONUP
this.id := this.GetObjVarNam(), v := this.ov := (this.id = this.__class ? "o" : "v")
this[v].Version := "Star-Zero-C"
If StrLen(Param)
{ this[v].SelectedFile := ""
If Param = Load Clipboard
this[v].Haystack := Clipboard
Else If SubStr(Param, 1, 9) = "Load File"
this[v].Haystack := this.FileRead(SubStr(Param, 11))
Else this[v].Haystack := Param
this[v].Haystack := StrReplace(this[v].Haystack, "`r`n", "`n")
this[v].Fayt := this[v].Case := this[v].Wwrap := True, this[v].Whole := this[v].Linum := False, this[v].n := 1, this[v].Hs[0] := this[v].GetAddress("Haystack"), this[v].Hs[1] := this[v].Haystack
}
this.BuildGui(this.id), WM_ACTIVATE(1), this.CleanUp(this.id)
}
FileRead(theFile) {
FileRead, theHays, % this[this.ov].SelectedFile := theFile
Return theHays
}
HsP(n) {
If (n > 1)
Return this[this.ov].Hs[n - 1]
Else Return StrGet(this[this.ov].Hs[0])
}
NeeP(n) {
If (n > 1)
Return this[this.ov].Needle[n - 1]
Else Return ""
}
GetObjVarNam() {
r := "(\w+?):.+?\{address: " Format("0x{:X}", &this) "\}"
Return RegExMatch(this.ListGlobalVars(), r, m) ? m1 : ""
}
BuildGui(id) {
global NeedleCB
static Fayt, Case, Whole, Linum, Wwrap
v := this.ov
Gui, %id%:New, +Labeltf.Gui_On
Gui, +Delimiter`n
Gui, +Resize +MinSize +MaximizeBox
Gui, Font, s10, Arial New
Gui, Add, Text,, O p t i o n s:
begFayt := this[v].Fayt ? "Checked" : ""
Gui, Add, Checkbox, ym vFayt %begFayt% Tabstop, Instant Filter (aka Find As You Type)
OnSuch := this.Fayt_OnToggle.Bind(this)
GuiControl +g, Button1, % OnSuch
begCase := this[v].Case ? "Checked" : ""
Gui, Add, Checkbox, ym vCase %begCase% Tabstop, Case Insensitive
OnSuch := this.Case_OnToggle.Bind(this)
GuiControl +g, Button2, % OnSuch
begWhole := this[v].Whole ? "Checked" : ""
Gui, Add, Checkbox, ym vWhole %begWhole% Tabstop, Whole Word
OnSuch := this.Whole_OnToggle.Bind(this)
GuiControl +g, Button3, % OnSuch
begLinum := this[v].Linum ? "Checked" : ""
Gui, Add, Checkbox, ym vLinum %begLinum% Tabstop, Line Number
OnSuch := this.Linum_OnToggle.Bind(this)
GuiControl +g, Button4, % OnSuch
beg_Wrap := this[v].Wwrap ? "Checked" : ""
Gui, Add, Checkbox, ym vWwrap %beg_Wrap% Tabstop, Word Wrap
OnSuch := this.Wwrap_OnToggle.Bind(this)
GuiControl +g, Button5, % OnSuch
Gui, Font, s18, Arial New
Gui, Add, Text, xm Section, Filter:
w := A_ScreenWidth - 330
Gui, Add, ComboBox, w%w% ys vNeedleCB +hwndhEdit1
OnSuch := this.Fpat_OnTyping.Bind(this)
GuiControl +g, %hEdit1%, % OnSuch
Gui, Add, Button, h38 ys Default, Go
OnSuch := this.Go_OnClick.Bind(this)
GuiControl +g, Button6, % OnSuch
Gui, Font, s10, Arial New
Gui, Add, Button, h38 ys, Refresh
OnSuch := this.Refresh_OnClick.Bind(this)
GuiControl +g, Button7, % OnSuch
Gui, Font, s18, Arial New
Gui, Add, Button, h38 ys, Back
OnSuch := this.Back_OnClick.Bind(this)
GuiControl +g, Button8, % OnSuch
h := A_ScreenHeight - 143, w := A_ScreenWidth - 30, begWwrap := this[v].Wwrap ? "+Wrap" : "+HScroll"
Gui, Font, s18, Consolas
Gui, Add, Custom, ClassRICHEDIT50W x10 h%h% w%w% %begWwrap% +VScroll +hwndHRE +0x804 ;ES_READONLY = 0x800, ES_MULTILINE = 0x4
h := A_ScreenHeight - 66, w := A_ScreenWidth - 6
Gui, Show, h%h% w%w%, The Text Filter
this.HRE := HRE, this.RE := this.GetTomDoc(HRE)
this.RenewGui() ;show content
}
Gui_OnSize() {
If A_EventInfo = 1
Return
GuiControl, Move, RICHEDIT50W1, % "h" (A_GuiHeight - 97) " w" (A_GuiWidth - 14)
}
Gui_OnEscape() {
Gui, %A_Gui%:Destroy
IfExist, tf_%A_Gui%Work.rtf
FileDelete, tf_%A_Gui%Work.rtf
IfExist, tfHelp.rtf
FileDelete, tfHelp.rtf
}
Gui_OnClose() {
Gui, %A_Gui%:Destroy
IfExist, tf_%A_Gui%Work.rtf
FileDelete, tf_%A_Gui%Work.rtf
IfExist, tfHelp.rtf
FileDelete, tfHelp.rtf
}
CleanUp(id) {
IfExist, tf_%id%Work.rtf
FileDelete, tf_%id%Work.rtf
IfExist, tfHelp.rtf
FileDelete, tfHelp.rtf
}
GetTomDoc(HRE) { ;written by "@just me"
Static IID_ITextDocument := "{8CC497C0-A1DF-11CE-8098-00AA0047BE5D}"
DocObj := 0
If DllCall("SendMessage", "Ptr", HRE, "UInt", 0x043C, "Ptr", 0, "PtrP", IRichEditOle, "UInt") ;EM_GETOLEINTERFACE
{ DocObj := ComObject(9, ComObjQuery(IRichEditOle, IID_ITextDocument), 1) ; ITextDocument
ObjRelease(IRichEditOle)
}
Return DocObj
}
Fayt_OnToggle() {
v := this.ov, n := this[v].n
If not (this[v].Fayt := this.Fayt())
If (this[v].Hs[n] != this.HsP(n))
{ this[v].Needle[n] := this.Fpat(), theHaystack := this[v].Hs[n]
n := (this[v].n += 1), this[v].Hs[n] := theHaystack
this.UpdateTitle()
}
ControlFocus, Edit1, A
this.Fpat_OnTyping()
}
Case_OnToggle() {
this[this.ov].Case := this.Case()
ControlFocus, Edit1, A
this.Fpat_OnTyping()
}
Whole_OnToggle() {
this[this.ov].Whole := this.Whole()
ControlFocus, Edit1, A
this.Fpat_OnTyping()
}
Linum_OnToggle() {
v := this.ov
If this[v].Linum := this.Linum()
{ Progress, zh0 w300 c10 fs18, `nHang On...`n,, Working On Line Numbering, Segoe UI
lsl := StrLen(this.LineCount())
HsN =
Loop, Parse, % this[v].Haystack, `n`r
HsN .= SubStr(this.StrRepeat(A_Space, lsl) A_Index, 1 - lsl) ":" A_Space A_LoopField "`n"
Progress, Off
this[v].HaystackN := HsN, this[v].Hs[0] := this[v].GetAddress("HaystackN")
}Else this[v].Hs[0] := this[v].GetAddress("Haystack")
Loop, % this[v].n
this[v].Hs[A_Index] := RegExReplace(this.HsP(A_Index), this.Maker(this[v].Needle[A_Index]))
this.RenewGui(this.Fpat())
}
Wwrap_OnToggle() {
v := this.ov, this[v].Wwrap := this.Wwrap(), n := this[v].n, this[v].Needle[n] := this.Fpat()
this.BuildGui(this.id)
; this.RenewGui(this[v].Needle[n])
GuiControl,, NeedleCB, % "`n" this[v].NeedleHistory
ControlSetText, Edit1, % this[v].Needle[n], A
this.RenewGui(this[v].Needle[n])
Send, {End}
}
Fpat_OnTyping() {
v := this.ov
If not this[v].Fayt and not this[v].CommitLevel
Return
Gui, Submit, NoHide
n := this[v].n, this[v].Needle[n] := theNeedle := this.Fpat()
If not StrLen(theNeedle) and this[v].CommitLevel
{ this[v].CommitLevel := False, this.Back_OnClick()
Return
}
theHaystack := RegExReplace(this.HsP(n), this.Maker(theNeedle))
If this[v].CommitLevel
{ If not StrLen(this[v].NeedleHistory)
this[v].NeedleHistory := theNeedle, Added := True
Else If not RegExMatch(this[v].NeedleHistory, (this[v].Case ? "i" : "") "m`a)^\Q" theNeedle "\E$")
this[v].NeedleHistory := theNeedle "`n" this[v].NeedleHistory, Added := True
Else Added := False
If Added
{ GuiControl,, NeedleCB, % "`n" this[v].NeedleHistory
ControlSetText, Edit1, % theNeedle
}
If (theHaystack = this.HsP(n))
Progress, zh0 w450 c10 fs18, `nResult No Change Thus Not Anew Level`n,, Prompt, Segoe UI
Else
{ If not this[v].Fayt
this[v].Hs[n] := theHaystack
If (this.LineCount(n) < 2) and not (theNeedle == this.NeeP(n))
Progress, zh0 w450 c10 fs18, `nUltimate/Empty Result Reached`nThus Level Not Advanced`n,, Prompt, Segoe UI
Else
{ n := (this[v].n += 1), this[v].Hs[n] := theHaystack
Send, ^a
}
}
this[v].CommitLevel := False
Sleep, 500
Progress, Off
}Else this[v].Hs[n] := theHaystack
this.RenewGui(theNeedle)
If not this[v].Fayt and not StrLen(this[v].Hs[n])
{ Progress, zh0 w450 c10 fs18, `nEmpty Result Reached`n`nFalling Back Now`n,, Prompt, Segoe UI
Sleep, 1000
this[v].Hs[n] := this.HsP(n)
ControlSetText, Edit1, % this.NeeP(n)
this.RenewGui(this.Fpat())
Send, ^a
Progress, Off
}
}
Maker(t) {
v := this.ov, t := this.tw4sh(t), r := (this[v].Case ? "i" : "") "m`a)^(?!"
Loop, Parse, t, % A_Space
If SubStr(A_LoopField, 1, 1) = "-"
r .= "(?!.*(" (this[v].Whole ? "\b" : "") SubStr(A_LoopField, 2) (this[v].Whole ? "\b" : "") "))"
Else r .= "(?=.*(" (this[v].Whole ? "\b" : "") A_LoopField (this[v].Whole ? "\b" : "") "))"
r .= ").*\R?"
Return r
}
Go_OnClick() {
ControlFocus, Edit1, A
Progress, zh0 w380 c10 fs18, `nCommitting This Level`n,, Prompt, Segoe UI
this[this.ov].CommitLevel := True, this.Fpat_OnTyping()
}
Refresh_OnClick() {
this.RenewGui(this[this.ov].Needle[this[this.ov].n] := this.Fpat(), "retain")
}
Back_OnClick() {
ControlFocus, Edit1, A
v := this.ov, n := this[v].n, this[v].Needle[n] := this.Fpat()
If (n = 1) and (this[v].Hs[n] != this.HsP(n))
this[v].Hs[n] := this.HsP(n), this[v].Needle[n] := ""
Else If (this[v].Hs[n] = this.HsP(n)) and (this[v].Needle[n] = this.NeeP(n))
If (n > 2)
n := (this[v].n -= 2)
Else If (n = 2)
n := this[v].n := 1, this[v].Hs[n] := this.HsP(n), this[v].Needle[n] := ""
Else n := this[v].n := 0
Else n := (this[v].n -= 1)
If n
{ ControlSetText, Edit1, % this[v].Needle[n]
this.RenewGui(this[v].Needle[n])
Send, ^a
If (n = 1) and (this[v].Hs[n] = this.HsP(n))
{ Progress, zh0 w380 c10 fs18, `nReturned To The Origin`n,, Prompt, Segoe UI
Sleep, 500
Progress, Off
}Else
{ Progress, zh0 w380 c10 fs18, `nReturned To Level %n%`n,, Prompt, Segoe UI
Sleep, 500
Progress, Off
}
}Else this.Gui_OnClose()
}
Fpat() {
GuiControlGet, Fpat,, Edit1
If not StrLen(Fpat)
ControlGetText, Fpat, Edit1
Return Fpat
}
Fayt() {
GuiControlGet, Fayt,, Button1
If not StrLen(Fayt)
ControlGetText, Fayt, Button1
Return Fayt
}
Case() {
GuiControlGet, Case,, Button2
If not StrLen(Case)
ControlGetText, Case, Button2
Return Case
}
Whole() {
GuiControlGet, Whole,, Button3
If not StrLen(Whole)
ControlGetText, Whole, Button3
Return Whole
}
Linum() {
GuiControlGet, Linum,, Button4
If not StrLen(Linum)
ControlGetText, Linum, Button4
Return Linum
}
Wwrap() {
GuiControlGet, Wwrap,, Button5
If not StrLen(Wwrap)
ControlGetText, Wwrap, Button5
Return Wwrap
}
RenewGui(theNee := "", AMt := "") {
global lbduration
v := this.ov, n := this[v].n
If this.Fpat() not = theNee
Goto, WorkInterrupt
this.ToggleReadOnly(this.HRE, this[v].Wwrap)
If (AMt = "retain")
theHays := this.RE.Range(0, 999999999).Text
Else If StrLen(AMt)
theHays := this[v][AMt]
Else theHays := this[v].Hs[n]
ControlSetText, RICHEDIT50W1, %theHays%, A
indent := (StrLen(this.LineCount()) + 2) * 10, this.RE.Range(0, StrLen(theHays)).SetIndents(-indent, indent, 0)
If this.Fpat() not = theNee
Goto, WIP_Interrupt
If StrLen(theNee) and StrLen(r := this.MakerC(theNee)) and RegExMatch(theHays, r) ;RegExReplace(theHays, r,, mc) and (not this[v].Fayt or AMt = "retain" or mc < StrLen(theNee) * 100)
{ Progress, zh0 w300 c10 fs18, `nHang On...`n,, Working On Matches Highlighting, Segoe UI
mpos := 1, mlen := 0
While, (mpos := RegExMatch(theHays, r, nm, mpos + mlen)) and (A_Index < 1000 or lbduration > 1000)
mlen := StrLen(nm), this.RE.Range(mpos - 1, mpos + mlen - 1).Font.BackColor := 0x00FFFF, npos := mpos
lbduration := 0
Progress, Off
}
WIP_Interrupt:
this.ToggleReadOnly(this.HRE, this[v].Wwrap)
ControlFocus, Edit1, A
this.UpdateTitle()
WorkInterrupt:
If this.Fpat() not = theNee
this.Fpat_OnTyping()
}
UpdateTitle() {
WinSetTitle, The Text Filter, % ("", v := this.ov, Version := this[v].Version, id := this.id, n := this[v].n, lc := this.LineCount(n), SelectedFile := this[v].SelectedFile), The Text Filter (Version: %Version%) | %id% | Level %n% | Line Count: %lc% | %SelectedFile%
}
LineCount(n := 0) {
If n is digit
theHays := this.HsP(n + 1)
Else theHays := n
StrReplace(theHays, "`n",, lc), lc += StrLen(theHays) and SubStr(theHays, 0) != "`n" ? 1 : 0
Return lc
}
ToggleReadOnly(HRE, Wwrap) {
ControlGet, Style, Style,,, ahk_id %HRE%
If not (Style & 0x800)
SendMessage, 0x443, 0, 0xF0F0F0,, ahk_id %HRE% ;tune Down BackgroundColor
SendMessage, 1101, 1, (Style & 0x800) ? (Wwrap ? 0x44 : 0xC4) : (Wwrap ? 0x844 : 0x8C4),, ahk_id %HRE% ;ES_READONLY = 0x800
If (Style & 0x800)
SendMessage, 0x443, 0, 0xFFFFEE,, ahk_id %HRE% ;light Up BackgroundColor
}
MakerC(theNee) {
theNee := this.tw4sh(theNee), r := "", v := this.ov
Loop, Parse, theNee, % A_Space
If SubStr(A_LoopField, 1, 1) != "-"
r .= "(" (this[v].Whole ? "\b" : "") A_LoopField (this[v].Whole ? "\b" : "") ")|"
If StrLen(r)
{ If SubStr(r, 0) = "|"
r := SubStr(r, 1, StrLen(r) - 1)
r := (this[v].Case ? "i" : "") "m`a)" r
}
Return r
}
IncrFontSize() {
MouseGetPos, mpx, mpy,, moc
If (moc not = "RICHEDIT50W1")
MouseMove, 400, 200
Send, ^{WheelUp}
If (moc not = "RICHEDIT50W1")
MouseMove, mpx, mpy
}
DecrFontSize() {
MouseGetPos, mpx, mpy,, moc
If (moc not = "RICHEDIT50W1")
MouseMove, 400, 200
Send, ^{WheelDown}
If (moc not = "RICHEDIT50W1")
MouseMove, mpx, mpy
}
TakeThisLine() {
slcs := this.RE.Selection.Start, slce := this.RE.Selection.End, Hays := this.RE.Range(0, 999999999).Text
If (slce > slcs)
{ Clipboard := SubStr(Hays, slcs + 1, slce - slcs)
Progress, zh0 w380 c10 fs18, `nSelection Copied`n,, Prompt, Segoe UI
Sleep, 500
Progress, Off
Return
}
mpos := slce + 1
While, mpos > 1 and not InStr("`r`n", SubStr(Hays, mpos - 1, 1))
mpos--
slcs := mpos, mpos := slce + 1, pmax := StrLen(Hays)
While, mpos <= pmax and not InStr("`r`n", SubStr(Hays, mpos, 1))
mpos++
this.FinalTouch(mpos > pmax ? SubStr(Hays, slcs) : SubStr(Hays, slcs, mpos - slcs))
}
FinalTouch(theOne) {
Clipboard := RegExReplace(theOne, "^\t?(?: *?\d+?: )?(.*)$", "$1")
MsgBox,,, Has Put This Line Into Clipboard, 3
}
FindNextMatch(Reverse := 0) {
If StrLen(sPat := this.Fpat())
r := this.MakerC(sPat)
Else r := "nothing to be matched this"
slcs := this.RE.Selection.Start, slce := this.RE.Selection.End
If (slce > slcs) and (RegExMatch(A_ThisHotkey, "^\+?f$") and StrLen(sPat) ? False : not RegExMatch(this.RE.Selection.Text, r))
r := this.MakerS(this.RE.Selection.Text)
If StrLen(r) and RegExMatch(Hays := this.RE.Range(0, 999999999).Text, r)
{ StartHere:
slcs := this.RE.Selection.Start, slce := this.RE.Selection.End, slcs++, slce++
cp := Reverse ? slcs : slce
If Reverse
{ If cp > 1
{ mpos := 0, pmax := cp - 1
Loop
{ npos := RegExMatch(Hays, r, pm, mpos + 1)
If npos between 1 and %pmax%
mpos := npos, nm := pm
Else Break
}
found := (npos > pmax) and mpos > 0
}
If not found
{ mpos := cp - 1, pmax := StrLen(Hays)
Loop
{ npos := RegExMatch(Hays, r, pm, mpos + 1)
If npos between %cp% and %pmax%
mpos := npos, nm := pm
Else Break
}
}
}Else mpos := RegExMatch(Hays, r, nm, cp)
mpos--
If mpos >= 0
{ cp := mpos + StrLen(nm)
this.RE.Range(mpos, cp).Select
}Else If (mpos < 0) and not Reverse
{ this.RE.Range(0, 0).Select
Goto, StartHere
}
}
}
MakerS(st) {
Return (StrLen(st), v := this.ov) ? (this[v].Case ? "i)" : "") (this[v].Whole ? "\b" : "") this.escrx(st) (this[v].Whole ? "\b" : "") : ""
}
WheelSearchMode() {
MouseGetPos,,,, moc
If not StrLen(moc) or not InStr("Edit1|RICHEDIT50W1", moc)
{ ControlFocus, RICHEDIT50W1, A
this.FindNextMatch(InStr(A_ThisHotkey, "WheelUp"))
}
}
ShowAssMatches() {
If this.RE.Range(0, 19).Text = "Assorted Matches:`t("
{ sPat := this.Fpat()
If this.RE.Range(19, 31).Text = "Alphabetical"
this.RenewGui(sPat, "AssHays")
Else this.RenewGui(sPat, "AAssHays")
Return
}
z := this.ov, n := this[z].n
If not StrLen(this[z].Hs[n]) or not StrLen(sPat := this.Fpat()) or not StrLen(r := this.MakerC(sPat))
Return
Progress, zh0 w300 c10 fs18, `nHang On...`n,, Working On Assortment, Segoe UI
UniqMatches := [], Seq := 0
Loop, Parse, % this[z].Hs[n], `n`r
{ mpos = 1
worknm:
npos := RegExMatch(A_LoopField, r, nm, mpos)
If npos
{ If UniqMatches.HasKey(nm)
Ums := UniqMatches[nm], AssHays%Ums% .= InStr(AssHays%Ums%, A_LoopField) ? "" : "`n`t" A_LoopField
Else
Seq++, UniqMatches[nm] := Seq, AssHays%Seq% := nm "`n`t" A_LoopField
mpos := npos + StrLen(nm)
Goto, worknm
}
}
If Seq
{ UniqHays := tvAAssHays := "", umNoSort := []
For k, v in UniqMatches
UniqHays .= "`n" this.StrRepeat(A_Space, 3) A_Index ".`t" k, tvAAssHays .= "`n" A_Index ". " AssHays%v%, umNoSort[v] ? umNoSort[v].Insert(k) : umNoSort[v] := k
AAssHays := "Assorted Matches:`t(Alphabetical Order)" UniqHays "`n" this.StrRepeat("-", 50) tvAAssHays
UniqHays := tvAssHays := ""
For k, v in umNoSort
UniqHays .= "`n" this.StrRepeat(A_Space, 3) k ".`t" v, tvAssHays .= "`n" A_Index ". " AssHays%k%
AssHays := "Assorted Matches:`t(Chronological Order)" UniqHays "`n" this.StrRepeat("-", 50) tvAssHays
this[z].AssHays := AssHays, this[z].AAssHays := AAssHays, this[z].tvAssHays := tvAssHays, this[z].tvAAssHays := tvAAssHays
this.RenewGui(sPat, "AssHays")
}
Progress, Off
}
AssTreeView(id) {
If this.RE.Range(0, 19).Text not = "Assorted Matches:`t("
Return
parwin := WinExist("A")
Gui, tvass:New, +Owner%parwin%
Gui, +Resize +MinSize +MaximizeBox
Gui, +Labeltf.tvGui_On
Gui, Font, s18, Consolas
Gui, Add, Text,, % this.RE.Range(19, 31).Text = "Alphabetical" ? "Assorted Matches: (Alphabetical Order)" : "Assorted Matches: (Chronological Order)"
;Gui, Add, Button, Hidden Default, Enter
Gui, Add, TreeView, AltSubmit Section xm w545
OnSuch := this.tvEventHdlr.Bind(this)
GuiControl +g, SysTreeView321, % OnSuch
Seq := 0, aHays := this.RE.Range(19, 31).Text = "Alphabetical" ? this[this.ov].tvAAssHays : this[this.ov].tvAssHays, lc := this.LineCount(aHays) - 1
Loop, Parse, aHays, `n`r
If StrLen(A_LoopField)
If RegExMatch(A_LoopField, "^ *\d+\.[ \t]")
Seq++, P%Seq% := TV_Add(A_LoopField), Num := 0
Else Num++, P%Seq%C%Num% := TV_Add(A_LoopField, P%Seq%)
Gui, Show, x97 y539 h283, TreeView Of Assorted Matches | %id% | Line Count: %lc%
GuiControl, Focus, SysTreeView321
}
tvGui_OnSize() {
If A_EventInfo = 1
Return
GuiControl, Move, SysTreeView321, % "h" (A_GuiHeight - 76) " w" (A_GuiWidth - 46)
}
tvGui_OnEscape() {
Gui, %A_Gui%:Destroy
}
tvGui_OnClose() {
Gui, %A_Gui%:Destroy
}
tvEventHdlr() {
If InStr("DoubleClick|S|K|Normal", A_GuiEvent)
TV_GetText(theOne, TV_GetSelection())
this[this.ov].theOne := theOne
If A_GuiEvent = DoubleClick
this.tvButtonEnter()
}
tvButtonEnter() {
this.FinalTouch(this[this.ov].theOne)
}
PasteIntoHaystack() {
global _cwi_
If StrLen(Clipboard)
{ InputBox, id, Object Instance Identification, No space is allowed and please keep it short. Accept the given ID means not to create a new window but replace the content of the current one.,,,,,,,, % _cwi_
If not ErrorLevel and StrLen(id)
{ If RegExMatch(id, "\W")
id := RegExReplace(id, "\W")
If (id = _cwi_)
this.start("Load Clipboard")
Else Return id
}
}Else MsgBox, Clipboard is empty
}
OpenFile() {
global _cwi_
FileSelectFile, SelectedFile
If StrLen(SelectedFile)
{ InputBox, id, Object Instance Identification, No space is allowed and please keep it short. Accept the given ID means not to create a new window but replace the content of the current one.,,,,,,,, % _cwi_
If not ErrorLevel and StrLen(id)
{ If RegExMatch(id, "\W")
id := RegExReplace(id, "\W")
If (id = _cwi_)
this.start("Load File " SelectedFile), this[this.ov].SelectedFile := SelectedFile
Else Return id "`t" SelectedFile
}
}
}
ReloadFile() {
If StrLen(SelectedFile := this[this.ov].SelectedFile)
this.start("Load File " SelectedFile)
}
RClickMenu() {
global lbduration
MouseGetPos, xb4, yb4
While, GetKeyState("RButton", "P")
Continue
MouseGetPos, rbx, rby, mow, moc
If Abs(rbx - xb4) > 10 or Abs(rby - yb4) > 10
Return
If (mow = (HGUI := WinExist("A"))) and rby > 30
If (moc = "Button8")
this.ShowTrail()
Else If (moc not = "Edit1")
{ Menu, myMenu, Add
Menu, myMenu, DeleteAll
Menu, myMenu, Add, Show Assorted Matches, MenuHandler
If this.RE.Range(0, 19).Text = "Assorted Matches:`t("
Menu, myMenu, Add, Put Assorted Matches In TreeView, MenuHandler
Menu, myMenu, Add
Menu, myMenu, Add, Increase Font Size, MenuHandler
Menu, myMenu, Add, Decrease Font Size, MenuHandler
Menu, myMenu, Add
Menu, myMenu, Add, Paste Into The Base, MenuHandler
Menu, myMenu, Add, Open A File, MenuHandler
Menu, myMenu, Add, Reload The File, MenuHandler
Menu, myMenu, Add
Menu, myMenu, Add, List Global Variables, MenuHandler
If (moc = "RICHEDIT50W1")
{ Menu, myMenu, Add
Menu, myMenu, Add, Copy The Line/Selection, MenuHandler
Menu, myMenu, Add, Go To Rightmost Of The Line, MenuHandler
Menu, myMenu, Add, Go To Leftmost Of The Line, MenuHandler
Menu, myMenu, Add, Go To The Bottom, MenuHandler
Menu, myMenu, Add, Go To The Top, MenuHandler
Menu, myMenu, Add, Page Down, MenuHandler
Menu, myMenu, Add, Page Up, MenuHandler
}
Menu, myMenu, Add
Menu, myMenu, Add, Downward Find Next Match, MenuHandler
Menu, myMenu, Add, Upward Find Next Match, MenuHandler
Menu, myMenu, Add
Menu, myMenu, Add, Override The 1K Default, MenuHandler
Menu, myMenu, Add
Menu, myMenu, Add, Show/Hide Help Page, MenuHandler
Menu, myMenu, Show
}
Return
MenuHandler:
WinWaitActive, ahk_id %HGUI%
If A_ThisMenuItem = Show Assorted Matches
this.ShowAssMatches()
Else If A_ThisMenuItem = Put Assorted Matches In TreeView
this.AssTreeView(this.id)
Else If A_ThisMenuItem = Increase Font Size
this.IncrFontSize()
Else If A_ThisMenuItem = Decrease Font Size
this.DecrFontSize()
Else If A_ThisMenuItem = Paste Into The Base
Gosub, PasteHaySub
Else If A_ThisMenuItem = Open A File
Gosub, OpenFileSub
Else If A_ThisMenuItem = Reload The File
this.ReloadFile()
Else If A_ThisMenuItem = List Global Variables
this.start(this.ListGlobalVars())
Else If A_ThisMenuItem = Copy The Line/Selection
{ If this.RE.Selection.End = this.RE.Selection.Start
MouseClick, Left, rbx, rby
this.TakeThisLine()
}Else If A_ThisMenuItem = Go To Rightmost Of The Line
{ MouseClick, Left, rbx, rby
Send, {End}
}Else If A_ThisMenuItem = Go To Leftmost Of The Line
{ MouseClick, Left, rbx, rby
Send, {Home}
}Else If A_ThisMenuItem = Go To The Bottom
{ MouseClick, Left, rbx, rby
Send, ^{End}
}Else If A_ThisMenuItem = Go To The Top
{ MouseClick, Left, rbx, rby
Send, ^{Home}
}Else If A_ThisMenuItem = Page Down
{ MouseClick, Left, rbx, rby
Send, {PgDn}
}Else If A_ThisMenuItem = Page Up
{ MouseClick, Left, rbx, rby
Send, {PgUp}
}Else If A_ThisMenuItem = Downward Find Next Match
{ ControlFocus, RICHEDIT50W1, A
this.FindNextMatch()
}Else If A_ThisMenuItem = Upward Find Next Match
{ ControlFocus, RICHEDIT50W1, A
this.FindNextMatch(1)
}Else If A_ThisMenuItem = Override The 1K Default
lbduration := 1234, this.RenewGui(this.Fpat(), "retain")
Else If A_ThisMenuItem = Show/Hide Help Page
this.ToggleHelpPage(this.id)
Return
}
ShowTrail() {
HGUI := WinExist("A"), v := this.ov, n := this[v].n
Menu, myTrail, Add
Menu, myTrail, DeleteAll
While, A_Index < n
{ tn := n - A_Index, theNeedle := this[v].Needle[tn], lc := this.LineCount(tn)
Menu, myTrail, Add, Level &%tn% remains %lc% lines after this filter: %theNeedle%, BtsLevel
}
lc := this.LineCount()
Menu, myTrail, Add, Origin %lc% lines (Level &0), BtsLevel
Menu, myTrail, Show
Return
BtsLevel:
WinWaitActive, ahk_id %HGUI%
n -= A_ThisMenuItemPos
If n < 1
n := this[v].n := 1, this[v].Hs[n] := this.HsP(n), this[v].Needle[n] := ""
Else this[v].n := n
ControlSetText, Edit1, % this[v].Needle[n]
this.RenewGui(this[v].Needle[n])
Return
}
ToggleHelpPage(id) {
theFile = tf_%id%Work.rtf
If this.RE.Range(0, 17).Text = "H e l p _ P a g e"
IfExist, %theFile%
this.RE.Open(theFile, 0x01, 0)
Else this.RenewGui(this.Fpat())
Else
{ IfExist, %theFile%
this.RE.Save(0, 0, 0)
Else this.RE.Save(theFile, 0x01, 0)
IfExist, tfHelp.rtf
FileDelete, tfHelp.rtf
FileAppend, % this.HelpPage(), tfHelp.rtf
this.RE.Open("tfHelp.rtf", 0x01, 0)
}
}
tw4sh(t) {
tog := "\/", va := "?\\'\w", ph := "[^" va "\n]", tar := "\" tog ph "*?\K[" va "]", ph := "[^\w\n]"
If mpos:=RegExMatch(t, tar) ;contained toggle (on)
{ pb := "[^\w\n]", sh := "((?<=^|" ph ")", st := "(?=(\W|$)))"
skip_c := skip_w := yb := False
r := StrReplace(SubStr(t, 1, mpos - 1), tog) sh, rr := xx := ""
Loop
{ c := SubStr(t, mpos, 1), cc := SubStr(t, mpos + 1, 1)
If skip_c
skip_c--
Else If SubStr(t, mpos, StrLen(tog)) = tog ;toggle (off) encountered
{ this.flush(r, xx, pb, yb, st), rr := xx := ""
mpos += StrLen(tog), npos := mpos
If mpos:=RegExMatch(t, tar,, npos) ;found next toggle (on)
r .= StrReplace(SubStr(t, npos, mpos - npos), tog) sh, rr := xx := ""
Else
{ r .= SubStr(t, npos)
Break
}
Continue
}Else If RegExMatch(c, "\w") or (c = "?") ;valid character
{ If rr
If not skip_w and ((cc not = "/") or StrLen(xx))
this.flush(r, xx, pb, yb)
Else If (cc = "/") and not StrLen(xx)
{ If SubStr(t, mpos + 2, 1) = "/"
skip_w := skip_w ? skip_w : True, skip_c++
skip_c++
}Else{}
Else If StrLen(rr)
r .= xx sh, rr := xx := ""
r .= (c = "?") ? (skip_w ? "\w" : ("\w+?", yb++)) : c (skip_w ? "" : ("\w*?", yb++)), skip_w -= skip_w ? 1 : 0, rr := True
}Else If (c = A_Space) and rr
this.flush(r, xx, pb, yb, st), xx := A_Space, rr := 0
Else If (c = "'")
xx .= "\W"
Else If (c = "\") and skip_w not < 0
If (cc == "Q")
skip_c++, skip_w := -1, this.flush(r, xx, pb, yb)
Else If (cc == "E")
skip_c++, skip_w := False
Else If (cc = c)
xx .= c
Else If RegExMatch(cc, "\w")
skip_c++, xx .= cc
Else skip_c++, xx .= c cc
Else xx .= c
mpos++
If (mpos > StrLen(t)) ;exceeded
{ If rr
this.flush(r, xx, pb, yb, st), rr := xx := ""
Break
}
}
}Else r := t
Return r
}
flush(ByRef r, ByRef xx, pb, ByRef yb, st := "") {
mb := "[^,;\w\n.?!]+?", ss := SubStr(xx, -1), sc := (ss == "\W") or (ss == "\s") or (ss == "\t") or (ss == "\r") or (ss == "\n"), r .= xx ? (RegExMatch(SubStr(xx, 1, 1), "\w") ? mb : pb "*?") xx (st ? ")" : (RegExMatch(ss, "\\?\w$") and not sc ? "" : pb "*?")) : (st ? st : (yb ? (mb, yb--) : "")), xx := ""
}
StrRepeat(string, times) {
Loop, %times%
output .= string
Return output
}
escrx(h) {
e := "\().[]*+?{}^$|"
Loop, Parse, e
If InStr(h, A_LoopField)
h := StrReplace(h, A_LoopField, "\" A_LoopField)
Return h
}
ListGlobalVars() { ;written by Lexikos
static hwndEdit, pSFW, pSW, bkpSFW, bkpSW
If !hwndEdit
{ dhw := A_DetectHiddenWindows
DetectHiddenWindows, On
Process, Exist
ControlGet, hwndEdit, Hwnd,, Edit1, ahk_class AutoHotkey ahk_pid %ErrorLevel%
DetectHiddenWindows, %dhw%
astr := A_IsUnicode ? "astr":"str"
ptr := A_PtrSize=8 ? "ptr":"uint"
hmod := DllCall("GetModuleHandle", "str", "user32.dll")
pSFW := DllCall("GetProcAddress", ptr, hmod, astr, "SetForegroundWindow")
pSW := DllCall("GetProcAddress", ptr, hmod, astr, "ShowWindow")
DllCall("VirtualProtect", ptr, pSFW, ptr, 8, "uint", 0x40, "uint*", 0)
DllCall("VirtualProtect", ptr, pSW, ptr, 8, "uint", 0x40, "uint*", 0)
bkpSFW := NumGet(pSFW+0, 0, "int64")
bkpSW := NumGet(pSW+0, 0, "int64")
}
If (A_PtrSize=8)
{ NumPut(0x0000C300000001B8, pSFW+0, 0, "int64") ;return TRUE
NumPut(0x0000C300000001B8, pSW+0, 0, "int64") ;return TRUE
}Else
{ NumPut(0x0004C200000001B8, pSFW+0, 0, "int64") ;return TRUE
NumPut(0x0008C200000001B8, pSW+0, 0, "int64") ;return TRUE
}
ListVars
NumPut(bkpSFW, pSFW+0, 0, "int64")
NumPut(bkpSW, pSW+0, 0, "int64")
ControlGetText, text,, ahk_id %hwndEdit%
RegExMatch(text, "sm)(?<=^Global Variables \(alphabetical\)`r`n-{50}`r`n).*", text)
Return text
}
HelpPage() {
HelpPage=
(
{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Arial;}{\f1\fnil\fcharset0 Consolas;}}
{\colortbl ;\red255\green0\blue0;\red155\green0\blue211;\red0\green77\blue187;\red0\green176\blue80;\red0\green0\blue255;}
{\*\generator Riched20 10.0.19041}\viewkind4\uc1
\pard\sa200\sl276\slmult1\b\fs36\lang9 H e l p _ P a g e\b0\par
\par
\cf1\b F1\cf0\b0 - to toggle this help page\par
\par
\b Basic syntax by example:\b0\par
\pard\li720\sa200\sl276\slmult1 coexisting words/strings/patterns -unwanted\par
for instance, \cf2\b\f1 d.*d -the and -oo \\ws\cf0\b0\f0\par
(the 5 segments (space separated) above can go all at once, and yet, they can also be entered one by one. that's the so-called multilevel approach, instead.)\par
\pard\sa200\sl276\slmult1\par
\b Feature keys:\b0\par
\pard\li720\sa200\sl276\slmult1\cf3\b Alt+a\cf0\b0 - to show assorted matches and toggle between chronological and alphabetical order.\par
\cf3\b Ctrl+t\cf0\b0 - to put assorted matches into a treeview gui which may ease the exploration when the list is long and involved multiple groups.\par
\cf3\b WheelDown\cf0\b0 - to find the next match (downward) from the caret position (given that, the mouse pointer is currently outside both text/edit boxes.)\par
\cf3\b WheelUp\cf0\b0 - to find the next match (upward) from the caret position (given that, the mouse pointer is currently outside both text/edit boxes.)\par
\cf3\b Alt+v\cf0\b0 - to paste clipboard content into the big text/edit box.\par
\cf3\b Ctrl+o\cf0\b0 - to open a file.\par
\cf3\b Ctrl+r\cf0\b0 - to reload the file.\par
\cf3\b Rightclick\cf0\b0 "Back" button - to glance committed levels and select one to fall back to.\par
\cf3\b Esc\cf0\b0 - to quit/exit/leave. same as closing the window.\par
\cf3\b Tab\cf0\b0 - to change focus between the text/edit boxes (just try it.)\par
\par
these below only work when the \ul big\ulnone text/edit box is in focus:\par
\pard\li1440\sa200\sl276\slmult1\cf3\b f\cf0\b0 - to find the next match (downward) from the caret position.\par
\cf3\b Shift+f\cf0\b0 - to find the next match (upward) from the caret position.\par
\i (note: "the line" refers to the current line, that's where the caret is on.)\i0\par
\cf3\b Enter\cf0\b0 - to copy the line.\par
\cf3\b Space\cf0\b0 - to page down\par
\cf3\b Shift+Space\cf0\b0 - to page up\par
\cf3\b s\cf0\b0 - to move the caret to the beginning/start of the line.\par
\cf3\b e\cf0\b0 - to move the caret to the end of the line.\par
\cf3\b t\cf0\b0 - to move the caret to the top of the text.\par
\cf3\b b\cf0\b0 - to move the caret to the bottom of the text.\par
\cf3\b + or =\cf0\b0 - to increase font size (same as \cf3\b Ctrl+WheelUp\cf0\b0 ).\par
\cf3\b minus "-"\cf0\b0 - to decrease font size (same as \cf3\b Ctrl+WheelDown\cf0\b0 ).\par
\i (side note: "caret" may be known as "cursor" to some people.)\i0\par
\pard\sa200\sl276\slmult1\par
\tab these below only work when the \ul small\ulnone text/edit box is in focus:\par
\pard\li1440\sa200\sl276\slmult1\cf3\b Enter\cf0\b0 - to commit a level (which makes the current result becoming the base/source of the next level.) same as clicking the button Go.\par
\pard\sa200\sl276\slmult1\par
\pard\li720\sa200\sl276\slmult1\cf3\b Backtick (``)\cf0\b0 - since users mostly use this tool to locate the specific line of text and copy it for whatever subsequent actions to be taken, which typically involves Tab and then Enter (if the first line is the one wanted), backtick is an alternative which can supersede both keys by just hit backtick twice instead.\par
\pard\sa200\sl276\slmult1\par
The \b improvised shorthand\b0 feature:\par
\pard\li720\sa200\sl276\slmult1 this feature can be triggered through "\cf2\b\\/\cf0\b0 " (a \b backslash\b0 followed by a \b slash\b0 ), a "regex like" syntax style, which toggle it on or off. so, enter "\cf2\b\\/tr\cf0\b0 " will bring you those lines contained "\cf4\i the road\cf0\i0 ", "\cf4\i two roads\cf0\i0 ", as well as "\cf4\i them really\cf0\i0 " out of the poem, whereas enter "\cf2\b oo \\/a?a\cf0\b0 " or "\cf2\b\\/a?a\\/ oo\cf0\b0 " will return you these two lines "\cf4\i And looked down one as far as I could\cf0\i0 " and "\cf4\i Then took the other, as just as fair,\cf0\i0 " in which, the "\cf2\b ?\cf0\b0 " represents any valid character regex recognized it as "word" element. Besides, the space has been cared so that the toggle works across it. for instance, enter "\cf2\b\\/tr yw\cf0\b0 " or "\cf2\b\\/yw tr\cf0\b0 " will show this line "\cf4\i Two roads diverged in a yellow wood,\cf0\i0 " where the space is still a separator as always, even though the shorthand feature is toggled on.\par
\pard\sa200\sl276\slmult1\par
\tab three more elements of the shorthand syntax:\par
\par
\pard\fi-360\li1800\sa200\sl276\slmult1 1, \b extra qualifier\b0 (within a single word);\par
2, \b escape character\b0 (between words);\par
3, a single \b character\b0 representing any "\b non-word\b0 " one (between words).\par
\pard\sa200\sl276\slmult1\par
\pard\li720\sa200\sl276\slmult1 the most basic usage of improvised shorthand is to match the specific "phrase" by just entering the first letter of each word constituted it (for instance, "\cf2\b sameto\cf0\b0 " can match "\cf4\i some are more equal than others\cf0\i0 ") yet sometimes we may want to further narrow down the result. if "\cf2\b slh\cf0\b0 " brings you both "\cf4\i she likes him\cf0\i0 " and "\cf4\i she loves him\cf0\i0 ", an extra qualifier to pinpoint one may be useful. it could simply be a "v" for this example hence "\cf2\b slv/h\cf0\b0 " (in which, the "/" after the "v" tells the system that it's just an extra qualifier to the "l", not for a word starts with "v",) returns you "\cf4\i she loves him\cf0\i0 " only. likewise, you may sometimes want to tell the system exactly what the word should be ending with, for instance, if "\cf2\b ioy\cf0\b0 " brings you both "\cf4\i i owe you\cf0\i0 " and "\cf4\i i own you\cf0\i0 ", "\cf2\b ioe//y\cf0\b0 " (in which, the "//" after the "e" tells the system that it's a word ending character, that is, "oe//" represents a word starts with "o" and ends with "e") returns you "\cf4\i i owe you\cf0\i0 " only. and no matter how rare (and impractical) it may be, you may have multiple of these qualifiers for a word, such as, "\cf2\b cm/c/e//d//\cf0\b0 " can match the word "\cf4\i complicated\cf0\i0 " whereas "\cf2\b td/i/u//s//\cf0\b0 " can match the word "\cf4\i tedious\cf0\i0 ".\par
\par
a \b backslash\b0 "\cf2\b\\\cf0\b0 " may be used to escape a single character after it. its target should be a "word" character because you don't need to escape otherwise. for all "non-word" character, just enter them directly except "\\" itself which requires a \b double backslash\b0 "\cf2\b\\\\\cf0\b0 " for a single one. for regex syntax such as "\\s", it becomes "\\\\s" (not "\\\\\\s" you may presume.) in other words, all escaped character will only be matched barely itself. for \ul consecutive\ulnone "word" characters that need to be escaped, enclose them in the \cf2\b\\Q\cf0\b0 \cf2\b\\E\cf0\b0 pair, similar idea as in regex. one thing to note though, escaped character may affect the word immediately after it, for instance, "\cf2\b z\\xy\cf0\b0 " may bring you "\cf4\i zebra xylophone\cf0\i0 " rather than "\cf4\i zombie x yesterday\cf0\i0 ".\par
\par
an \b apostrophe\b0 "\cf2\b\f1 '\cf0\b0\f0 " may be used to represent any "non-word" character. that is, same as "\\\\W" (the regex syntax "\\W" for a "non-word" character). it may be useful at the (beginning and/or ending) ends of the "phrase" if it can further narrow down the result or you simply want it to be a part of the match.\par
\pard\sa200\sl276\slmult1\par
The \b matches highlighting\b0 feature:\par
\pard\li720\sa200\sl276\slmult1 the \ul default behavior\ulnone is to highlight no more than a thousand matches (which can improve the response time when too many matches are found.) it can nonetheless be overridden by a long press of your left mouse button on one of the available gui buttons (i.e. go or refresh or back), whereas long press means press it down and hold on for \ul one second or longer\ulnone . therefore, highlighting will cover the whole thing even if the total number of matches is over \ul one thousand\ulnone . this \ul long-press-to-override\ulnone is not a toggle, it's just an \ul one-off\ulnone thing, so do it every time you want more than the default.\par
\pard\sa200\sl276\slmult1\par
End of this help page.\par
}
)
Return HelpPage
}
} ;end of class
Last edited by SundayProgrammer on 07 Jun 2021, 03:38, edited 2 times in total.
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
the script is updated. → viewtopic.php?p=402780#p402780 ← click this link
star-zero-a made some adjustments.
star-zero-a made some adjustments.
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
the script is updated. → viewtopic.php?p=402780#p402780 ← click this link
star-zero-b found a bug, and fixed.
|
|
today, i want to share a way to overview the object properties and methods out of the script, and also as an example of how "assorted matches" can help.
(this|%?\w+%?)(\.\w+|\[[^[\]]+\])+(\(([^()]*)?\))?|^[[:blank:]]*\K\w+(\(([^()]*)?\))
noted that, the regex isn't 100% accurate. it catched slightly more than supposed, but it's good enough for the job with just 5% (for the time being) unwanted matches.
|
cheers.
star-zero-b found a bug, and fixed.
|
|
today, i want to share a way to overview the object properties and methods out of the script, and also as an example of how "assorted matches" can help.
(this|%?\w+%?)(\.\w+|\[[^[\]]+\])+(\(([^()]*)?\))?|^[[:blank:]]*\K\w+(\(([^()]*)?\))
noted that, the regex isn't 100% accurate. it catched slightly more than supposed, but it's good enough for the job with just 5% (for the time being) unwanted matches.
|
here is the result
|cheers.
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
the script is updated. → viewtopic.php?p=402780#p402780 ← click this link
star-zero-c made three tweaks.
star-zero-c made three tweaks.
- Kellyzkorner_NJ
- Posts: 84
- Joined: 20 Oct 2017, 18:33
Re: Text Filter
Hello, Just to let you know, I'm trying the most recent C version, I'm getting an, Error: The following variable name contains an illegal character: "Other Windows" It points to a line that has %_cwi_%.WheelSearchMode()
I typed that manually so, if it's wrong it's my fault. This comes up every time I try to scroll. This is a large file I'm searching, 55000+ lines, if that makes a difference.
One other thing (hopefully it's not there and I missed it), it would be great if you could click a line in the Text Filter screen results and hit a hotkey and have it open said file and navigate to that line in the physical file.
Thanks again for this great script.
I typed that manually so, if it's wrong it's my fault. This comes up every time I try to scroll. This is a large file I'm searching, 55000+ lines, if that makes a difference.
One other thing (hopefully it's not there and I missed it), it would be great if you could click a line in the Text Filter screen results and hit a hotkey and have it open said file and navigate to that line in the physical file.
Thanks again for this great script.
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
hi @Kellyzkorner_NJ, thank you for letting me know the error. i myself did hit this a few times during testing, but can never repeat it immediately. are you having this problem consistently?Kellyzkorner_NJ wrote: ↑07 Jun 2021, 12:12Hello, Just to let you know, I'm trying the most recent C version, I'm getting an, Error: The following variable name contains an illegal character: "Other Windows" It points to a line that has %_cwi_%.WheelSearchMode()
by the way, the _cwi_ (current window id) global variable is set by the wm_activate function via onmessage. the "other windows" message simply means the active window is other than those created from the "tf" object (the text filter and its associated windows).
i believe 55000+ lines isn't a problem.Kellyzkorner_NJ wrote: ↑07 Jun 2021, 12:12I typed that manually so, if it's wrong it's my fault. This comes up every time I try to scroll. This is a large file I'm searching, 55000+ lines, if that makes a difference.
i'm actually working on a similar feature right now. i call it "context peeking". don't know if it can fit your need though.Kellyzkorner_NJ wrote: ↑07 Jun 2021, 12:12One other thing (hopefully it's not there and I missed it), it would be great if you could click a line in the Text Filter screen results and hit a hotkey and have it open said file and navigate to that line in the physical file.
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
star-one
added a new feature, context peeking, which provides an integrated way of reviewing the context of any lines in your shortlisted result.
firstly, it needs the line numbers as the integration keys. so, it's only available when line numbering is turned on.
it shows a sub-window which contains all the lines from the origin. you double-click/triple-click a line (or select some text out of a line) and the sub-window will be scrolled automatically to show the line at the middle (as much as possible) of the box.
four buttons are provided, in which, "maximize" and "restore" are toggles, just give them a try to see what they toggle about.
when finished, you may just minimize it instead of closing it. so that, you can "double-click" whenever needed. and the sub-window will be brought up automatically in response.
2021-6-10 star-one-a forgot to test assorted matches and its treeview with context peeking. and they didn't work, as things always do, without particularly sweating over. anyhow, they are fixed now.
2021-6-13 star-one-b added a new feature, made some adjustments, and fixed a bug.
made some adjustments so that the "find next match" still works when the "context peeking" is on.
fixed a bug which occurred when context peeking operates in multi-instance
scenario.
added a new feature, a 3-tier search mechanism. and since i think the way it works may be confusing to some users, it's arranged in an extended class out of "tf". as a result, one has to start from that extended class to use it. for instance, stf.start() applies this 3-tier search mechanism whereas tf.start() remains same as before.
the way how "tf" works, as it always does, is the first tier. the difference happens when it found no matches, it then turns to interpret the search pattern as word(s) with missing characters, and to see if putting flexibility between each character can bring some matches. that's the second tier. if it still found no matches, it therefore turns to assume there is not only missing characters but also some characters may be miss placed, hence to see if putting flexibility in characters order can bring some matches. that's the third tier.
for example, try "ien" and "rnf" with the poem. although both bring you this line "And that has made all the difference." the former is a tier 2 result whereas the later is a tier 3 result.
that's it for now.
added a new feature, context peeking, which provides an integrated way of reviewing the context of any lines in your shortlisted result.
firstly, it needs the line numbers as the integration keys. so, it's only available when line numbering is turned on.
it shows a sub-window which contains all the lines from the origin. you double-click/triple-click a line (or select some text out of a line) and the sub-window will be scrolled automatically to show the line at the middle (as much as possible) of the box.
four buttons are provided, in which, "maximize" and "restore" are toggles, just give them a try to see what they toggle about.
when finished, you may just minimize it instead of closing it. so that, you can "double-click" whenever needed. and the sub-window will be brought up automatically in response.
2021-6-10 star-one-a forgot to test assorted matches and its treeview with context peeking. and they didn't work, as things always do, without particularly sweating over. anyhow, they are fixed now.
2021-6-13 star-one-b added a new feature, made some adjustments, and fixed a bug.
made some adjustments so that the "find next match" still works when the "context peeking" is on.
fixed a bug which occurred when context peeking operates in multi-instance
scenario.
added a new feature, a 3-tier search mechanism. and since i think the way it works may be confusing to some users, it's arranged in an extended class out of "tf". as a result, one has to start from that extended class to use it. for instance, stf.start() applies this 3-tier search mechanism whereas tf.start() remains same as before.
the way how "tf" works, as it always does, is the first tier. the difference happens when it found no matches, it then turns to interpret the search pattern as word(s) with missing characters, and to see if putting flexibility between each character can bring some matches. that's the second tier. if it still found no matches, it therefore turns to assume there is not only missing characters but also some characters may be miss placed, hence to see if putting flexibility in characters order can bring some matches. that's the third tier.
for example, try "ien" and "rnf" with the poem. although both bring you this line "And that has made all the difference." the former is a tier 2 result whereas the later is a tier 3 result.
that's it for now.
Code: Select all
SetWorkingDir %A_ScriptDir%
RE_Dll := DllCall("LoadLibrary", "Str", "Msftedit.dll", "Ptr")
thePoem=
(
The Road Not Taken
BY ROBERT FROST
Two roads diverged in a yellow wood,
And sorry I could not travel both
And be one traveler, long I stood
And looked down one as far as I could
To where it bent in the undergrowth;
Then took the other, as just as fair,
And having perhaps the better claim,
Because it was grassy and wanted wear;
Though as for that the passing there
Had worn them really about the same,
And both that morning equally lay
In leaves no step had trodden black.
Oh, I kept the first for another day!
Yet knowing how way leads on to way,
I doubted if I should ever come back.
I shall be telling this with a sigh
Somewhere ages and ages hence:
Two roads diverged in a wood, and I—
I took the one less traveled by,
And that has made all the difference.
)
; tf.start("Load Clipboard")
; msgbox
; tf.start("Load File log.txt")
; msgbox
tf.start(thePoem), stf.start(thePoem)
; msgbox
; tf.start() ;from what's leftoff in the object's memory
;multiple instances can be coexisting as below
; w1 := new tf, w1.start("Load Clipboard")
; w2 := new tf, w2.start("Load File log.txt")
; w3 := new tf, w3.start(thePoem)
; msgbox
; w3.start() ;from what's leftoff in the object's memory
Return
Class stf extends tf {
FlexRxR(ByRef Hays, Nee) {
v := this.ov
If Resu := RegExReplace(Hays, this.Maker(Nee))
Return (Resu, this[v].r := Nee)
Loop, Parse, Nee
{ If A_Index > 1
r .= t A_LoopField
Else r := A_LoopField
t := RegExMatch(A_LoopField, "\w") ? "\w{0,3}" : ""
}
If Resu := RegExReplace(Hays, this.Maker(r))
Return (Resu, this[v].r := r)
Loop, Parse, Nee
{ If A_Index > 1
r .= t A_LoopField
Else r := A_LoopField
t := RegExMatch(A_LoopField, "\w") ? "[\w'\-+]*" : ""
}
If Resu := RegExReplace(Hays, this.Maker(r))
Return (Resu, this[v].r := r)
Loop, Parse, Nee, % ("", r := "")
r .= RegExMatch(A_LoopField, "\w") ? "(?=[\w'\-+]*" A_LoopField ")" : ""
If StrLen(r)
r .= "\b[\w'\-+]*\b"
Else Return ""
If Resu := RegExReplace(Hays, this.Maker(r))
Return (Resu, this[v].r := r)
Else Return ("", this[v].r := "")
}
} ;end of class
FocusedControl() {
ControlGetFocus, foco, A
Return foco
}
#If, WinActive("The Text Filter") and FocusedControl() = "Edit1"
`::
Tab::ControlFocus, RICHEDIT50W1, A
#If, WinActive("The Text Filter") and FocusedControl() = "RICHEDIT50W1"
Tab::ControlFocus, Edit1, A
Space::PgDn
+Space::PgUp
s::Home
e::End
t::^Home
b::^End
-::%_cwi_%.DecrFontSize()
+::
=::%_cwi_%.IncrFontSize()
`::
Enter::%_cwi_%.TakeThisLine()
f::%_cwi_%.FindNextMatch()
+f::%_cwi_%.FindNextMatch(1)
#If, WinActive("TreeView Of Assorted Matches") and FocusedControl() = "SysTreeView321"
`::
Enter::%_cwi_%.tvButtonEnter()
#If, WinActive("Context Peeking") and FocusedControl() = "RICHEDIT50W1"
~WheelUp::
~WheelDown::%_cwi_%.WheelSearchMode()
#IfWinActive, The Text Filter
F1::%_cwi_%.ToggleHelpPage(_cwi_)
~WheelUp::
~WheelDown::%_cwi_%.WheelSearchMode()
!a::%_cwi_%.ShowAssMatches()
^t::%_cwi_%.AssTreeView(_cwi_)
^p::%_cwi_%.ContextPeek(_cwi_)
!v::Gosub, PasteHaySub
^o::Gosub, OpenFileSub
^r::%_cwi_%.ReloadFile()
~RButton::%_cwi_%.RClickMenu()
#IfWinActive
PasteHaySub:
If _uii_ := %_cwi_%.PasteIntoHaystack()
%_uii_% := new tf, %_uii_%.start("Load Clipboard")
Return
OpenFileSub:
If _OpFi_ := %_cwi_%.OpenFile()
{ RegExMatch(_OpFi_, "^\w+(?=\t)", _uii_), RegExMatch(_OpFi_, "\t\K.+$", _usf_)
%_uii_% := new tf, %_uii_%.start("Load File " _usf_)
}
Return
WM_ACTIVATE(wParam) {
global _cwi_
If (wParam > 0)
If WinActive("The Text Filter") or WinActive("TreeView Of Assorted Matches") or WinActive("Context Peeking")
{ WinGetTitle, t, A
If RegExMatch(t, "\| *?(\w*?) *?\|", m) and StrLen(m1)
_cwi_ := m1
Else _cwi_ := "Oops..."
}Else _cwi_ := "Other Windows"
}
EventHandler(wParam, lParam, msg, hwnd) {
static lbdowntime := 0
global lbduration := 0
If msg = 0x201 ;WM_LBUTTONDOWN
lbdowntime := A_TickCount
Else If msg = 0x202 ;WM_LBUTTONUP
lbduration := A_TickCount - lbdowntime
Return
}
Class tf {
static o := {}
v := {}
start(Param := "") {
OnMessage(0x6, "WM_ACTIVATE")
OnMessage(0x201, "EventHandler") ;WM_LBUTTONDOWN
OnMessage(0x202, "EventHandler") ;WM_LBUTTONUP
this.id := this.GetObjVarNam(), v := this.ov := (this.id = this.__class ? "o" : "v")
this[v].Version := "Star-One-B"
If StrLen(Param)
{ this[v].SelectedFile := ""
If Param = Load Clipboard
this[v].Haystack := Clipboard
Else If SubStr(Param, 1, 9) = "Load File"
this[v].Haystack := this.FileRead(SubStr(Param, 11))
Else this[v].Haystack := Param
this[v].Haystack := StrReplace(this[v].Haystack, "`r`n", "`n")
this[v].Fayt := this[v].Case := this[v].Wwrap := True, this[v].Whole := this[v].Linum := False, this[v].n := 1, this[v].Hs[0] := this[v].GetAddress("Haystack"), this[v].Hs[1] := this[v].Haystack
}
this.BuildGui(this.id), WM_ACTIVATE(1), this.CleanUp(this.id)
}
FileRead(theFile) {
FileRead, theHays, % this[this.ov].SelectedFile := theFile
Return theHays
}
HsP(n) {
If (n > 1)
Return this[this.ov].Hs[n - 1]
Else Return StrGet(this[this.ov].Hs[0])
}
NeeP(n) {
If (n > 1)
Return this[this.ov].Needle[n - 1]
Else Return ""
}
GetObjVarNam() {
r := "(\w+?):.+?\{address: " Format("0x{:X}", &this) "\}"
Return RegExMatch(this.ListGlobalVars(), r, m) ? m1 : ""
}
BuildGui(id) {
global NeedleCB
static Fayt, Case, Whole, Linum, Wwrap
v := this.ov
Gui, %id%:New, +Labeltf.Gui_On
Gui, +Delimiter`n
Gui, +Resize +MinSize +MaximizeBox
Gui, Font, s10, Arial New
Gui, Add, Text,, O p t i o n s:
begFayt := this[v].Fayt ? "Checked" : ""
Gui, Add, Checkbox, ym vFayt %begFayt% Tabstop, Instant Filter (aka Find As You Type)
OnSuch := this.Fayt_OnToggle.Bind(this)
GuiControl +g, Button1, % OnSuch
begCase := this[v].Case ? "Checked" : ""
Gui, Add, Checkbox, ym vCase %begCase% Tabstop, Case Insensitive
OnSuch := this.Case_OnToggle.Bind(this)
GuiControl +g, Button2, % OnSuch
begWhole := this[v].Whole ? "Checked" : ""
Gui, Add, Checkbox, ym vWhole %begWhole% Tabstop, Whole Word
OnSuch := this.Whole_OnToggle.Bind(this)
GuiControl +g, Button3, % OnSuch
begLinum := this[v].Linum ? "Checked" : ""
Gui, Add, Checkbox, ym vLinum %begLinum% Tabstop, Line Number
OnSuch := this.Linum_OnToggle.Bind(this)
GuiControl +g, Button4, % OnSuch
beg_Wrap := this[v].Wwrap ? "Checked" : ""
Gui, Add, Checkbox, ym vWwrap %beg_Wrap% Tabstop, Word Wrap
OnSuch := this.Wwrap_OnToggle.Bind(this)
GuiControl +g, Button5, % OnSuch
Gui, Font, s18, Arial New
Gui, Add, Text, xm Section, Filter:
w := A_ScreenWidth - 330
Gui, Add, ComboBox, w%w% ys vNeedleCB +hwndhEdit1
OnSuch := this.Fpat_OnTyping.Bind(this)
GuiControl +g, %hEdit1%, % OnSuch
Gui, Add, Button, h38 ys Default, Go
OnSuch := this.Go_OnClick.Bind(this)
GuiControl +g, Button6, % OnSuch
Gui, Font, s10, Arial New
Gui, Add, Button, h38 ys, Refresh
OnSuch := this.Refresh_OnClick.Bind(this)
GuiControl +g, Button7, % OnSuch
Gui, Font, s18, Arial New
Gui, Add, Button, h38 ys, Back
OnSuch := this.Back_OnClick.Bind(this)
GuiControl +g, Button8, % OnSuch
h := A_ScreenHeight - 143, w := A_ScreenWidth - 30, begWwrap := this[v].Wwrap ? "+Wrap" : "+HScroll"
Gui, Font, s18, Consolas
Gui, Add, Custom, ClassRICHEDIT50W x10 h%h% w%w% %begWwrap% +VScroll +hwndHRE +0x804 ;ES_READONLY = 0x800, ES_MULTILINE = 0x4
OnSuch := this.RE_OnEvent.Bind(this)
GuiControl +g, %HRE%, % OnSuch
h := A_ScreenHeight - 64, w := A_ScreenWidth - 6
Gui, Show, h%h% w%w%, The Text Filter
this.HRE := HRE, this.RE := this.GetTomDoc(HRE)
this.RenewGui() ;show content
}
RE_OnEvent() {
v := this.ov
If this[v].Linum and WinActive("The Text Filter") and WinExist("Context Peeking | " this.id) and not this[v].eFlag and StrLen(this.RE.Selection.Text)
{ this[v].eFlag := True
n := this[v].n
slcs := this.RE.Selection.Start, slce := this.RE.Selection.End, SelBegChar := this.RE.Range(slcs, slcs + 1).Text, SelEndChar := this.RE.Range(slce - 1, slce).Text, Hays := this.RE.Range(0, 999999999).Text
If InStr(A_Priorkey, "WheelUp")
this.RE.Range(slcs, slcs).Select
Else maybe := InStr("`r`n", SelEndChar) ? 1 : 0, this.RE.Range(slce - maybe, slce - maybe).Select
Sleep, 500
maybe := InStr("`r`n", SelBegChar) and (SelEndChar = A_Space) ? 2 : 1, mpos := this.ULoNLoCR(Hays, slcs + maybe)
slcs := mpos, mpos := this.DLoNLoCR(Hays, slce + 1)
this.RE_PeekContext(mpos > StrLen(Hays) ? SubStr(Hays, slcs) : SubStr(Hays, slcs, mpos - slcs))
this[v].eFlag := False
}
}
RE_PeekContext(theOne) {
cpLnum := RegExReplace(theOne, "^\t? *?(\d+?):.*$", "$1")
If cpLnum is digit
Hays := this[this.ov].HaystackN, cpLend := RegExMatch(RegExReplace(Hays, "`n",,, cpLnum - 1), "`n") + cpLnum - 1, mpos := this.ULoNLoCR(Hays, cpLend), cpLbeg := mpos - 1, this.CP.Range(cpLbeg, cpLend).Select, this.cpScroIntoView()
}
Gui_OnSize() {
If A_EventInfo = 1
Return
GuiControl, Move, RICHEDIT50W1, % "h" (A_GuiHeight - 95) " w" (A_GuiWidth - 14)
}
Gui_OnEscape() {
Gui, %A_Gui%:Destroy
IfExist, tf_%A_Gui%Work.rtf
FileDelete, tf_%A_Gui%Work.rtf
IfExist, tfHelp.rtf
FileDelete, tfHelp.rtf
}
Gui_OnClose() {
Gui, %A_Gui%:Destroy
IfExist, tf_%A_Gui%Work.rtf
FileDelete, tf_%A_Gui%Work.rtf
IfExist, tfHelp.rtf
FileDelete, tfHelp.rtf
}
CleanUp(id) {
IfExist, tf_%id%Work.rtf
FileDelete, tf_%id%Work.rtf
IfExist, tfHelp.rtf
FileDelete, tfHelp.rtf
}
GetTomDoc(HRE) { ;written by "@just me"
Static IID_ITextDocument := "{8CC497C0-A1DF-11CE-8098-00AA0047BE5D}"
DocObj := 0
If DllCall("SendMessage", "Ptr", HRE, "UInt", 0x043C, "Ptr", 0, "PtrP", IRichEditOle, "UInt") ;EM_GETOLEINTERFACE
{ DocObj := ComObject(9, ComObjQuery(IRichEditOle, IID_ITextDocument), 1) ; ITextDocument
ObjRelease(IRichEditOle)
}
Return DocObj
}
Fayt_OnToggle() {
v := this.ov, n := this[v].n
If not (this[v].Fayt := this.Fayt())
If (this[v].Hs[n] != this.HsP(n))
{ this[v].Needle[n] := this.Fpat(), theHaystack := this[v].Hs[n]
n := (this[v].n += 1), this[v].Hs[n] := theHaystack
this.UpdateTitle()
}
ControlFocus, Edit1, A
this.Fpat_OnTyping()
}
Case_OnToggle() {
this[this.ov].Case := this.Case()
ControlFocus, Edit1, A
this.Fpat_OnTyping()
}
Whole_OnToggle() {
this[this.ov].Whole := this.Whole()
ControlFocus, Edit1, A
this.Fpat_OnTyping()
}
Linum_OnToggle() {
v := this.ov
If this[v].Linum := this.Linum()
{ Progress, zh0 w300 c10 fs18, `nHang On...`n,, Working On Line Numbering, Segoe UI
lsl := StrLen(this.LineCount())
HsN =
Loop, Parse, % this[v].Haystack, `n`r
HsN .= SubStr(this.StrRepeat(A_Space, lsl) A_Index, 1 - lsl) ":" A_Space A_LoopField "`n"
Progress, Off
this[v].HaystackN := HsN, this[v].Hs[0] := this[v].GetAddress("HaystackN")
}Else this[v].Hs[0] := this[v].GetAddress("Haystack")
Loop, % this[v].n
this[v].Hs[A_Index] := IsFunc(this.FlexRxR) ? this.FlexRxR(this.HsP(A_Index), this[v].Needle[A_Index]) : RegExReplace(this.HsP(A_Index), this.Maker(this[v].Needle[A_Index]))
this.RenewGui(this.Fpat())
}
Wwrap_OnToggle() {
v := this.ov, this[v].Wwrap := this.Wwrap(), n := this[v].n, this[v].Needle[n] := this.Fpat()
this.BuildGui(this.id)
; this.RenewGui(this[v].Needle[n])
GuiControl,, NeedleCB, % "`n" this[v].NeedleHistory
ControlSetText, Edit1, % this[v].Needle[n], A
this.RenewGui(this[v].Needle[n])
Send, {End}
}
Fpat_OnTyping() {
v := this.ov
If not this[v].Fayt and not this[v].CommitLevel
Return
Gui, Submit, NoHide
n := this[v].n, this[v].Needle[n] := theNeedle := this.Fpat()
If not StrLen(theNeedle) and this[v].CommitLevel
{ this[v].CommitLevel := False, this.Back_OnClick()
Progress, Off
Return
}
theHaystack := IsFunc(this.FlexRxR) ? this.FlexRxR(this.HsP(n), theNeedle) : RegExReplace(this.HsP(n), this.Maker(theNeedle))
If this[v].CommitLevel
{ If not StrLen(this[v].NeedleHistory)
this[v].NeedleHistory := theNeedle, Added := True
Else If not RegExMatch(this[v].NeedleHistory, (this[v].Case ? "i" : "") "m`a)^\Q" theNeedle "\E$")
this[v].NeedleHistory := theNeedle "`n" this[v].NeedleHistory, Added := True
Else Added := False
If Added
{ GuiControl,, NeedleCB, % "`n" this[v].NeedleHistory
ControlSetText, Edit1, % theNeedle
}
If (theHaystack = this.HsP(n))
Progress, zh0 w450 c10 fs18, `nResult No Change Thus Not Anew Level`n,, Prompt, Segoe UI
Else
{ If not this[v].Fayt
this[v].Hs[n] := theHaystack
If (this.LineCount(n) < 2) and not (theNeedle == this.NeeP(n))
Progress, zh0 w450 c10 fs18, `nUltimate/Empty Result Reached`nThus Level Not Advanced`n,, Prompt, Segoe UI
Else
{ n := (this[v].n += 1), this[v].Hs[n] := theHaystack
Send, ^a
}
}
this[v].CommitLevel := False
Sleep, 500
Progress, Off
}Else this[v].Hs[n] := theHaystack
this.RenewGui(theNeedle)
If not this[v].Fayt and not StrLen(this[v].Hs[n])
{ Progress, zh0 w450 c10 fs18, `nEmpty Result Reached`n`nFalling Back Now`n,, Prompt, Segoe UI
Sleep, 1000
this[v].Hs[n] := this.HsP(n)
ControlSetText, Edit1, % this.NeeP(n)
this.RenewGui(this.Fpat())
Send, ^a
Progress, Off
}
}
Maker(t) {
v := this.ov, t := this.tw4sh(t), r := (this[v].Case ? "i" : "") "m`a)^(?!"
Loop, Parse, t, % A_Space
If SubStr(A_LoopField, 1, 1) = "-"
r .= "(?!.*(" (this[v].Whole ? "\b" : "") SubStr(A_LoopField, 2) (this[v].Whole ? "\b" : "") "))"
Else r .= "(?=.*(" (this[v].Whole ? "\b" : "") A_LoopField (this[v].Whole ? "\b" : "") "))"
r .= ").*\R?"
Return r
}
Go_OnClick() {
ControlFocus, Edit1, A
Progress, zh0 w380 c10 fs18, `nCommitting This Level`n,, Prompt, Segoe UI
this[this.ov].CommitLevel := True, this.Fpat_OnTyping()
}
Refresh_OnClick() {
this.RenewGui(this[this.ov].Needle[this[this.ov].n] := this.Fpat(), "retain")
}
Back_OnClick() {
ControlFocus, Edit1, A
v := this.ov, n := this[v].n, this[v].Needle[n] := this.Fpat()
If (n = 1) and (this[v].Hs[n] != this.HsP(n))
this[v].Hs[n] := this.HsP(n), this[v].Needle[n] := ""
Else If (this[v].Hs[n] = this.HsP(n)) and (this[v].Needle[n] = this.NeeP(n))
If (n > 2)
n := (this[v].n -= 2)
Else If (n = 2)
n := this[v].n := 1, this[v].Hs[n] := this.HsP(n), this[v].Needle[n] := ""
Else n := this[v].n := 0
Else n := (this[v].n -= 1)
If n
{ ControlSetText, Edit1, % this[v].Needle[n]
this.RenewGui(this[v].Needle[n])
Send, ^a
If (n = 1) and (this[v].Hs[n] = this.HsP(n))
{ Progress, zh0 w380 c10 fs18, `nReturned To The Origin`n,, Prompt, Segoe UI
Sleep, 500
Progress, Off
}Else
{ Progress, zh0 w380 c10 fs18, `nReturned To Level %n%`n,, Prompt, Segoe UI
Sleep, 500
Progress, Off
}
}Else this.Gui_OnClose()
}
Fpat() {
GuiControlGet, Fpat,, Edit1
If not StrLen(Fpat)
ControlGetText, Fpat, Edit1
Return Fpat
}
Fayt() {
GuiControlGet, Fayt,, Button1
If not StrLen(Fayt)
ControlGetText, Fayt, Button1
Return Fayt
}
Case() {
GuiControlGet, Case,, Button2
If not StrLen(Case)
ControlGetText, Case, Button2
Return Case
}
Whole() {
GuiControlGet, Whole,, Button3
If not StrLen(Whole)
ControlGetText, Whole, Button3
Return Whole
}
Linum() {
GuiControlGet, Linum,, Button4
If not StrLen(Linum)
ControlGetText, Linum, Button4
Return Linum
}
Wwrap() {
GuiControlGet, Wwrap,, Button5
If not StrLen(Wwrap)
ControlGetText, Wwrap, Button5
Return Wwrap
}
RenewGui(theNee := "", AMt := "") {
global lbduration
v := this.ov, n := this[v].n
If this.Fpat() not = theNee
Goto, WorkInterrupt
this.ToggleReadOnly(this.HRE, this[v].Wwrap)
If (AMt = "retain")
theHays := this.RE.Range(0, 999999999).Text
Else If StrLen(AMt)
theHays := this[v][AMt]
Else theHays := this[v].Hs[n]
ControlSetText, RICHEDIT50W1, %theHays%, A
indent := (StrLen(this.LineCount()) + 2) * 10, this.RE.Range(0, StrLen(theHays)).SetIndents(-indent, indent, 0)
If this.Fpat() not = theNee
Goto, WIP_Interrupt
r := this.MakerC(IsFunc(this.FlexRxR) ? this[v].r : theNee)
If StrLen(theNee) and StrLen(r) and RegExMatch(theHays, r) ;RegExReplace(theHays, r,, mc) and (not this[v].Fayt or AMt = "retain" or mc < StrLen(theNee) * 100)
{ Progress, zh0 w300 c10 fs18, `nHang On...`n,, Working On Matches Highlighting, Segoe UI
mpos := 1, mlen := 0
While, (mpos := RegExMatch(theHays, r, nm, mpos + mlen)) and (A_Index < 1000 or lbduration > 1000)
mlen := StrLen(nm), this.RE.Range(mpos - 1, mpos + mlen - 1).Font.BackColor := 0x00FFFF, npos := mpos
lbduration := 0
Progress, Off
}
WIP_Interrupt:
this.ToggleReadOnly(this.HRE, this[v].Wwrap)
ControlFocus, Edit1, A
this.UpdateTitle()
WorkInterrupt:
If this.Fpat() not = theNee
this.Fpat_OnTyping()
}
UpdateTitle() {
WinSetTitle, The Text Filter, % ("", v := this.ov, Version := this[v].Version, id := this.id, n := this[v].n, lc := this.LineCount(n), SelectedFile := this[v].SelectedFile), The Text Filter (Version: %Version%) | %id% | Level %n% | Line Count: %lc% | %SelectedFile%
}
LineCount(n := 0) {
If n is digit
theHays := this.HsP(n + 1)
Else theHays := n
StrReplace(theHays, "`n",, lc), lc += StrLen(theHays) and SubStr(theHays, 0) != "`n" ? 1 : 0
Return lc
}
ToggleReadOnly(HRE, Wwrap) {
ControlGet, Style, Style,,, ahk_id %HRE%
If not (Style & 0x800)
SendMessage, 0x443, 0, 0xF0F0F0,, ahk_id %HRE% ;tune Down BackgroundColor
SendMessage, 1101, 1, (Style & 0x800) ? (Wwrap ? 0x44 : 0xC4) : (Wwrap ? 0x844 : 0x8C4),, ahk_id %HRE% ;ES_READONLY = 0x800
If (Style & 0x800)
SendMessage, 0x443, 0, 0xFFFFEE,, ahk_id %HRE% ;light Up BackgroundColor
}
MakerC(theNee) {
theNee := this.tw4sh(theNee), r := "", v := this.ov
Loop, Parse, theNee, % A_Space
If SubStr(A_LoopField, 1, 1) != "-"
r .= "(" (this[v].Whole ? "\b" : "") A_LoopField (this[v].Whole ? "\b" : "") ")|"
If StrLen(r)
{ If SubStr(r, 0) = "|"
r := SubStr(r, 1, StrLen(r) - 1)
r := (this[v].Case ? "i" : "") "m`a)" r
}
Return r
}
IncrFontSize() {
MouseGetPos, mpx, mpy,, moc
If (moc not = "RICHEDIT50W1")
MouseMove, 400, 200
Send, ^{WheelUp}
If (moc not = "RICHEDIT50W1")
MouseMove, mpx, mpy
}
DecrFontSize() {
MouseGetPos, mpx, mpy,, moc
If (moc not = "RICHEDIT50W1")
MouseMove, 400, 200
Send, ^{WheelDown}
If (moc not = "RICHEDIT50W1")
MouseMove, mpx, mpy
}
TakeThisLine() {
slcs := this.RE.Selection.Start, slce := this.RE.Selection.End, Hays := this.RE.Range(0, 999999999).Text
If (slce > slcs)
{ Clipboard := SubStr(Hays, slcs + 1, slce - slcs)
Progress, zh0 w380 c10 fs18, `nSelection Copied`n,, Prompt, Segoe UI
Sleep, 500
Progress, Off
Return
}
mpos := this.ULoNLoCR(Hays, slce + 1)
slcs := mpos, mpos := this.DLoNLoCR(Hays, slce + 1)
this.FinalTouch(mpos > StrLen(Hays) ? SubStr(Hays, slcs) : SubStr(Hays, slcs, mpos - slcs))
}
ULoNLoCR(hays, mpos) {
While, mpos > 1 and not InStr("`r`n", SubStr(hays, mpos - 1, 1))
mpos--
Return mpos
}
DLoNLoCR(hays, mpos) {
pmax := StrLen(hays)
While, mpos <= pmax and not InStr("`r`n", SubStr(hays, mpos, 1))
mpos++
Return mpos
}
FinalTouch(theOne) {
Clipboard := RegExReplace(theOne, "^\t?(?: *?\d+?: )?(.*)$", "$1")
MsgBox,,, Has Put This Line Into Clipboard, 3
}
FindNextMatch(Reverse := 0) {
If StrLen(sPat := this.Fpat())
r := this.MakerC(IsFunc(this.FlexRxR) ? this[this.ov].r : sPat)
Else r := "nothing to be matched this"
slcs := this.RE.Selection.Start, slce := this.RE.Selection.End
If (slce > slcs) and (RegExMatch(A_ThisHotkey, "^\+?f$") and StrLen(sPat) ? False : not RegExMatch(this.RE.Selection.Text, r))
r := this.MakerS(this.RE.Selection.Text)
If StrLen(r) and RegExMatch(Hays := this.RE.Range(0, 999999999).Text, r)
{ StartHere:
slcs := this.RE.Selection.Start, slce := this.RE.Selection.End, slcs++, slce++
cp := Reverse ? slcs : slce
If Reverse
{ If cp > 1
{ mpos := 0, pmax := cp - 1
Loop
{ npos := RegExMatch(Hays, r, pm, mpos + 1)
If npos between 1 and %pmax%
mpos := npos, nm := pm
Else Break
}
found := (npos > pmax) and mpos > 0
}
If not found
{ mpos := cp - 1, pmax := StrLen(Hays)
Loop
{ npos := RegExMatch(Hays, r, pm, mpos + 1)
If npos between %cp% and %pmax%
mpos := npos, nm := pm
Else Break
}
}
}Else mpos := RegExMatch(Hays, r, nm, cp)
mpos--
If mpos >= 0
{ cp := mpos + StrLen(nm)
this.RE.Range(mpos, cp).Select
}Else If (mpos < 0) and not Reverse
{ this.RE.Range(0, 0).Select
Goto, StartHere
}
}
}
MakerS(st) {
Return (StrLen(st), v := this.ov) ? (this[v].Case ? "i)" : "") (this[v].Whole ? "\b" : "") this.escrx(st) (this[v].Whole ? "\b" : "") : ""
}
WheelSearchMode() {
MouseGetPos,,,, moc
If not StrLen(moc) or not InStr("Edit1|RICHEDIT50W1", moc)
{ IfWinNotActive, The Text Filter
{ WinActivate % "ahk_id " this[this.ov].ParWin
WinWaitActive
}
ControlFocus, RICHEDIT50W1, A
this.FindNextMatch(InStr(A_ThisHotkey, "WheelUp"))
}
}
ShowAssMatches() {
If this.RE.Range(0, 19).Text = "Assorted Matches:`t("
{ sPat := this.Fpat()
If this.RE.Range(19, 31).Text = "Alphabetical"
this.RenewGui(sPat, "AssHays")
Else this.RenewGui(sPat, "AAssHays")
Return
}
z := this.ov, n := this[z].n
If not StrLen(this[z].Hs[n]) or not StrLen(sPat := this.Fpat()) or not StrLen(r := this.MakerC(sPat))
Return
r := IsFunc(this.FlexRxR) ? this.MakerC(this[z].r) : r
Progress, zh0 w300 c10 fs18, `nHang On...`n,, Working On Assortment, Segoe UI
UniqMatches := [], Seq := 0
Loop, Parse, % this[z].Hs[n], `n`r
{ mpos = 1
worknm:
npos := RegExMatch(A_LoopField, r, nm, mpos)
If npos
{ If UniqMatches.HasKey(nm)
Ums := UniqMatches[nm], AssHays%Ums% .= InStr(AssHays%Ums%, A_LoopField) ? "" : "`n`t" A_LoopField
Else
Seq++, UniqMatches[nm] := Seq, AssHays%Seq% := nm "`n`t" A_LoopField
mpos := npos + StrLen(nm)
Goto, worknm
}
}
If Seq
{ UniqHays := tvAAssHays := "", umNoSort := []
For k, v in UniqMatches
UniqHays .= "`n" this.StrRepeat(A_Space, 3) A_Index ".`t" k, tvAAssHays .= "`n" A_Index ". " AssHays%v%, umNoSort[v] ? umNoSort[v].Insert(k) : umNoSort[v] := k
AAssHays := "Assorted Matches:`t(Alphabetical Order)" UniqHays "`n" this.StrRepeat("-", 50) tvAAssHays
UniqHays := tvAssHays := ""
For k, v in umNoSort
UniqHays .= "`n" this.StrRepeat(A_Space, 3) k ".`t" v, tvAssHays .= "`n" A_Index ". " AssHays%k%
AssHays := "Assorted Matches:`t(Chronological Order)" UniqHays "`n" this.StrRepeat("-", 50) tvAssHays
this[z].AssHays := AssHays, this[z].AAssHays := AAssHays, this[z].tvAssHays := tvAssHays, this[z].tvAAssHays := tvAAssHays
this.RenewGui(sPat, "AssHays")
}
Progress, Off
}
AssTreeView(id) {
If this.RE.Range(0, 19).Text not = "Assorted Matches:`t("
Return
parwin := this[v].ParWin := WinExist("A")
Gui, tv%id%:New, +Owner%parwin%
Gui, +Resize +MinSize +MaximizeBox
Gui, +Labeltf.tvGui_On
Gui, Font, s18, Consolas
Gui, Add, Text,, % this.RE.Range(19, 31).Text = "Alphabetical" ? "Assorted Matches: (Alphabetical Order)" : "Assorted Matches: (Chronological Order)"
;Gui, Add, Button, Hidden Default, Enter
Gui, Add, TreeView, AltSubmit Section xm w545
OnSuch := this.tvEventHdlr.Bind(this)
GuiControl +g, SysTreeView321, % OnSuch
Seq := 0, aHays := this.RE.Range(19, 31).Text = "Alphabetical" ? this[this.ov].tvAAssHays : this[this.ov].tvAssHays, lc := this.LineCount(aHays) - 1
Loop, Parse, aHays, `n`r
If StrLen(A_LoopField)
If RegExMatch(A_LoopField, "^ *\d+\.[ \t]")
Seq++, P%Seq% := TV_Add(A_LoopField), Num := 0
Else Num++, P%Seq%C%Num% := TV_Add(A_LoopField, P%Seq%)
Gui, Show, x97 y539 h283, TreeView Of Assorted Matches | %id% | Line Count: %lc%
GuiControl, Focus, SysTreeView321
}
tvGui_OnSize() {
If A_EventInfo = 1
Return
GuiControl, Move, SysTreeView321, % "h" (A_GuiHeight - 76) " w" (A_GuiWidth - 46)
}
tvGui_OnEscape() {
Gui, %A_Gui%:Destroy
}
tvGui_OnClose() {
Gui, %A_Gui%:Destroy
}
tvEventHdlr() {
If InStr("DoubleClick|S|K|Normal", A_GuiEvent)
TV_GetText(theOne, TV_GetSelection())
this[this.ov].theOne := theOne
If A_GuiEvent = DoubleClick
IfWinExist, % "Context Peeking | " this.id
this.RE_PeekContext(theOne)
Else this.tvButtonEnter()
}
tvButtonEnter() {
this.FinalTouch(this[this.ov].theOne)
}
PasteIntoHaystack() {
global _cwi_
If StrLen(Clipboard)
{ InputBox, id, Object Instance Identification, No space is allowed and please keep it short. Accept the given ID means not to create a new window but replace the content of the current one.,,,,,,,, % _cwi_
If not ErrorLevel and StrLen(id)
{ If RegExMatch(id, "\W")
id := RegExReplace(id, "\W")
If (id = _cwi_)
this.start("Load Clipboard")
Else Return id
}
}Else MsgBox, Clipboard is empty
}
OpenFile() {
global _cwi_
FileSelectFile, SelectedFile
If StrLen(SelectedFile)
{ InputBox, id, Object Instance Identification, No space is allowed and please keep it short. Accept the given ID means not to create a new window but replace the content of the current one.,,,,,,,, % _cwi_
If not ErrorLevel and StrLen(id)
{ If RegExMatch(id, "\W")
id := RegExReplace(id, "\W")
If (id = _cwi_)
this.start("Load File " SelectedFile), this[this.ov].SelectedFile := SelectedFile
Else Return id "`t" SelectedFile
}
}
}
ReloadFile() {
If StrLen(SelectedFile := this[this.ov].SelectedFile)
this.start("Load File " SelectedFile)
}
RClickMenu() {
global lbduration
MouseGetPos, xb4, yb4
While, GetKeyState("RButton", "P")
Continue
MouseGetPos, rbx, rby, mow, moc
If Abs(rbx - xb4) > 10 or Abs(rby - yb4) > 10
Return
If (mow = (HGUI := WinExist("A"))) and rby > 30
If (moc = "Button8")
this.ShowTrail()
Else If (moc not = "Edit1")
{ Menu, myMenu, Add
Menu, myMenu, DeleteAll
Menu, myMenu, Add, Show Assorted Matches, MenuHandler
If this.RE.Range(0, 19).Text = "Assorted Matches:`t("
Menu, myMenu, Add, Put Assorted Matches In TreeView, MenuHandler
If this[this.ov].Linum and not WinExist("Context Peeking | " this.id)
{ Menu, myMenu, Add
Menu, myMenu, Add, Context Peeking, MenuHandler
}
Menu, myMenu, Add
Menu, myMenu, Add, Increase Font Size, MenuHandler
Menu, myMenu, Add, Decrease Font Size, MenuHandler
Menu, myMenu, Add
Menu, myMenu, Add, Paste Into The Base, MenuHandler
Menu, myMenu, Add, Open A File, MenuHandler
Menu, myMenu, Add, Reload The File, MenuHandler
Menu, myMenu, Add
Menu, myMenu, Add, List Global Variables, MenuHandler
If (moc = "RICHEDIT50W1")
{ Menu, myMenu, Add
Menu, myMenu, Add, Copy The Line/Selection, MenuHandler
Menu, myMenu, Add, Go To Rightmost Of The Line, MenuHandler
Menu, myMenu, Add, Go To Leftmost Of The Line, MenuHandler
Menu, myMenu, Add, Go To The Bottom, MenuHandler
Menu, myMenu, Add, Go To The Top, MenuHandler
Menu, myMenu, Add, Page Down, MenuHandler
Menu, myMenu, Add, Page Up, MenuHandler
}
Menu, myMenu, Add
Menu, myMenu, Add, Downward Find Next Match, MenuHandler
Menu, myMenu, Add, Upward Find Next Match, MenuHandler
Menu, myMenu, Add
Menu, myMenu, Add, Override The 1K Default, MenuHandler
Menu, myMenu, Add
Menu, myMenu, Add, Show/Hide Help Page, MenuHandler
Menu, myMenu, Show
}
Return
MenuHandler:
WinWaitActive, ahk_id %HGUI%
If A_ThisMenuItem = Show Assorted Matches
this.ShowAssMatches()
Else If A_ThisMenuItem = Put Assorted Matches In TreeView
this.AssTreeView(this.id)
Else If A_ThisMenuItem = Context Peeking
this.ContextPeek(this.id)
Else If A_ThisMenuItem = Increase Font Size
this.IncrFontSize()
Else If A_ThisMenuItem = Decrease Font Size
this.DecrFontSize()
Else If A_ThisMenuItem = Paste Into The Base
Gosub, PasteHaySub
Else If A_ThisMenuItem = Open A File
Gosub, OpenFileSub
Else If A_ThisMenuItem = Reload The File
this.ReloadFile()
Else If A_ThisMenuItem = List Global Variables
this.start(this.ListGlobalVars())
Else If A_ThisMenuItem = Copy The Line/Selection
{ If this.RE.Selection.End = this.RE.Selection.Start
MouseClick, Left, rbx, rby
this.TakeThisLine()
}Else If A_ThisMenuItem = Go To Rightmost Of The Line
{ MouseClick, Left, rbx, rby
Send, {End}
}Else If A_ThisMenuItem = Go To Leftmost Of The Line
{ MouseClick, Left, rbx, rby
Send, {Home}
}Else If A_ThisMenuItem = Go To The Bottom
{ MouseClick, Left, rbx, rby
Send, ^{End}
}Else If A_ThisMenuItem = Go To The Top
{ MouseClick, Left, rbx, rby
Send, ^{Home}
}Else If A_ThisMenuItem = Page Down
{ MouseClick, Left, rbx, rby
Send, {PgDn}
}Else If A_ThisMenuItem = Page Up
{ MouseClick, Left, rbx, rby
Send, {PgUp}
}Else If A_ThisMenuItem = Downward Find Next Match
{ ControlFocus, RICHEDIT50W1, A
this.FindNextMatch()
}Else If A_ThisMenuItem = Upward Find Next Match
{ ControlFocus, RICHEDIT50W1, A
this.FindNextMatch(1)
}Else If A_ThisMenuItem = Override The 1K Default
lbduration := 1234, this.RenewGui(this.Fpat(), "retain")
Else If A_ThisMenuItem = Show/Hide Help Page
this.ToggleHelpPage(this.id)
Return
}
ShowTrail() {
HGUI := WinExist("A"), v := this.ov, n := this[v].n
Menu, myTrail, Add
Menu, myTrail, DeleteAll
While, A_Index < n
{ tn := n - A_Index, theNeedle := this[v].Needle[tn], lc := this.LineCount(tn)
Menu, myTrail, Add, Level &%tn% remains %lc% lines after this filter: %theNeedle%, BtsLevel
}
lc := this.LineCount()
Menu, myTrail, Add, Origin %lc% lines (Level &0), BtsLevel
Menu, myTrail, Show
Return
BtsLevel:
WinWaitActive, ahk_id %HGUI%
n -= A_ThisMenuItemPos
If n < 1
n := this[v].n := 1, this[v].Hs[n] := this.HsP(n), this[v].Needle[n] := ""
Else this[v].n := n
ControlSetText, Edit1, % this[v].Needle[n]
this.RenewGui(this[v].Needle[n])
Return
}
ToggleHelpPage(id) {
theFile = tf_%id%Work.rtf
If this.RE.Range(0, 17).Text = "H e l p _ P a g e"
IfExist, %theFile%
this.RE.Open(theFile, 0x01, 0)
Else this.RenewGui(this.Fpat())
Else
{ IfExist, %theFile%
this.RE.Save(0, 0, 0)
Else this.RE.Save(theFile, 0x01, 0)
IfExist, tfHelp.rtf
FileDelete, tfHelp.rtf
FileAppend, % this.HelpPage(), tfHelp.rtf
this.RE.Open("tfHelp.rtf", 0x01, 0)
}
}
ContextPeek(id) {
v := this.ov
If not this[v].Linum
Return
parwin := this[v].ParWin := WinExist("A")
Gui, cp%id%:New, +Owner%parwin%
Gui, +Resize +MinSize +MaximizeBox
Gui, +Labeltf.cpGui_On
Gui, Font, s12, Arial New
Gui, Add, Button,, Close
OnSuch := this.cpBclose.Bind(this)
GuiControl +g, Button1, % OnSuch
Gui, Add, Button, ys, Maximize
OnSuch := this.cpBmaxim.Bind(this)
GuiControl +g, Button2, % OnSuch
Gui, Add, Button, ys, Restore
OnSuch := this.cpBresto.Bind(this)
GuiControl +g, Button3, % OnSuch
Gui, Add, Button, ys, Minimize
OnSuch := this.cpBminim.Bind(this)
GuiControl +g, Button4, % OnSuch
Gui, Font, s18, Consolas
Gui, Add, Custom, ClassRICHEDIT50W xm Section +Wrap +VScroll +hwndHCP +0x804 ;ES_READONLY = 0x800, ES_MULTILINE = 0x4
OnSuch := this.cpEventHdlr.Bind(this)
GuiControl +g, RICHEDIT50W1, % OnSuch
x := A_ScreenWidth/2, h := A_ScreenHeight - 94, w := A_ScreenWidth - 6, lc := this.LineCount()
Gui, Show, x%x% y51 h%h% w%w%, Context Peeking | %id% | Line Count: %lc%
Progress, zh0 w300 c10 fs18, `nHang On...`n,, Loading Origin, Segoe UI
GuiControl,, RICHEDIT50W1, % this[v].HaystackN
GuiControl, Focus, RICHEDIT50W1
this.HCP := HCP, this.CP := this.GetTomDoc(HCP)
this.ToggleReadOnly(this.HCP, this[v].Wwrap)
indent := (StrLen(lc) + 2) * 10, this.CP.Range(0, StrLen(this[v].HaystackN)).SetIndents(-indent, indent, 0)
SendMessage, 0x443, 0, 0xF0F0F0,, ahk_id %HCP% ;tune Down BackgroundColor
this.ToggleReadOnly(this.HCP, this[v].Wwrap)
Progress, Off
}
cpScroIntoView() {
GuiControlGet, gCPg, Pos, % this.HCP
this.CP.Selection.ScrollIntoView(0), slcs := this.CP.Selection.Start, slce := this.CP.Selection.End
this.CP.Range(cp := this.CfromP(this.HCP, 1, this.PfromC(this.HCP, slcs) + gCPgH / 2), cp).Select
WinActivate, % "Context Peeking | " this.id
WinWaitActive
this.CP.Range(slcs, slce).Select
}
CfromP(hE, x := -1, y := -1) {
VarSetCapacity(RECT, 16, 0)
SendMessage 0xB2,, &RECT,, ahk_id %hE% ;EM_GETRECT
LefP := NumGet(RECT, 0, "Int"), TopP := NumGet(RECT, 4, "Int"), RigP := NumGet(RECT, 8, "Int"), BotP := NumGet(RECT, 12, "Int")
VarSetCapacity(PoL, 8, 0), NumPut(x < 0 ? RigP : x, PoL,, "Int"), NumPut(y < 0 ? BotP : y, PoL, 4, "Int")
SendMessage 0xD7,, &PoL,, ahk_id %hE% ;EM_CHARFROMPOS
Return ErrorLevel
}
PfromC(hE, i) {
VarSetCapacity(PoL, 8, 0)
SendMessage 0xD6, &PoL, i,, ahk_id %hE% ;EM_POSFROMCHAR
Return NumGet(PoL, 4, "Int")
}
cpGui_OnSize() {
If A_EventInfo = 1
Return
GuiControl, Move, RICHEDIT50W1, % "h" (A_GuiHeight - 65) " w" (A_GuiWidth - 30)
}
cpGui_OnEscape() {
Gui, %A_Gui%:Destroy
}
cpGui_OnClose() {
Gui, %A_Gui%:Destroy
}
cpBclose() {
Gui, %A_Gui%:Destroy
}
cpBmaxim() {
WinGet, wMM, MinMax, A
If wMM = 1 ;already maximized
WinRestore, A
Else WinMaximize, A
GuiControl, Focus, RICHEDIT50W1
}
cpBresto() {
static x := A_ScreenWidth/2, h := A_ScreenHeight - 94, w := A_ScreenWidth - 6
WinGet, wMM, MinMax, A
If wMM = 0 ;already restored
{ WinGetPos, GuiX,,,, A
If (GuiX + x >= A_ScreenWidth)
Gui, Show, x-5 y51 h%h% w%w%
Else Gui, Show, x%x% y51 h%h% w%w%
}Else WinRestore, A
GuiControl, Focus, RICHEDIT50W1
}
cpBminim() {
WinMinimize, A
GuiControl, Focus, RICHEDIT50W1
}
cpEventHdlr() {
IfWinActive, Context Peeking
; { WinGet, wMM, MinMax, A
; If wMM > -1 ;not minimized
{ Sleep, 500
GuiControl, Focus, RICHEDIT50W1
}
; }
}
tw4sh(t) {
tog := "\/", va := "?\\'\w", ph := "[^" va "\n]", tar := "\" tog ph "*?\K[" va "]", ph := "[^\w\n]"
If mpos:=RegExMatch(t, tar) ;contained toggle (on)
{ pb := "[^\w\n]", sh := "((?<=^|" ph ")", st := "(?=(\W|$)))"
skip_c := skip_w := yb := False
r := StrReplace(SubStr(t, 1, mpos - 1), tog) sh, rr := xx := ""
Loop
{ c := SubStr(t, mpos, 1), cc := SubStr(t, mpos + 1, 1)
If skip_c
skip_c--
Else If SubStr(t, mpos, StrLen(tog)) = tog ;toggle (off) encountered
{ this.flush(r, xx, pb, yb, st), rr := xx := ""
mpos += StrLen(tog), npos := mpos
If mpos:=RegExMatch(t, tar,, npos) ;found next toggle (on)
r .= StrReplace(SubStr(t, npos, mpos - npos), tog) sh, rr := xx := ""
Else
{ r .= SubStr(t, npos)
Break
}
Continue
}Else If RegExMatch(c, "\w") or (c = "?") ;valid character
{ If rr
If not skip_w and ((cc not = "/") or StrLen(xx))
this.flush(r, xx, pb, yb)
Else If (cc = "/") and not StrLen(xx)
{ If SubStr(t, mpos + 2, 1) = "/"
skip_w := skip_w ? skip_w : True, skip_c++
skip_c++
}Else{}
Else If StrLen(rr)
r .= xx sh, rr := xx := ""
r .= (c = "?") ? (skip_w ? "\w" : ("\w+?", yb++)) : c (skip_w ? "" : ("\w*?", yb++)), skip_w -= skip_w ? 1 : 0, rr := True
}Else If (c = A_Space) and rr
this.flush(r, xx, pb, yb, st), xx := A_Space, rr := 0
Else If (c = "'")
xx .= "\W"
Else If (c = "\") and skip_w not < 0
If (cc == "Q")
skip_c++, skip_w := -1, this.flush(r, xx, pb, yb)
Else If (cc == "E")
skip_c++, skip_w := False
Else If (cc = c)
xx .= c
Else If RegExMatch(cc, "\w")
skip_c++, xx .= cc
Else skip_c++, xx .= c cc
Else xx .= c
mpos++
If (mpos > StrLen(t)) ;exceeded
{ If rr
this.flush(r, xx, pb, yb, st), rr := xx := ""
Break
}
}
}Else r := t
Return r
}
flush(ByRef r, ByRef xx, pb, ByRef yb, st := "") {
mb := "[^,;\w\n.?!]+?", ss := SubStr(xx, -1), sc := (ss == "\W") or (ss == "\s") or (ss == "\t") or (ss == "\r") or (ss == "\n"), r .= xx ? (RegExMatch(SubStr(xx, 1, 1), "\w") ? mb : pb "*?") xx (st ? ")" : (RegExMatch(ss, "\\?\w$") and not sc ? "" : pb "*?")) : (st ? st : (yb ? (mb, yb--) : "")), xx := ""
}
StrRepeat(string, times) {
Loop, %times%
output .= string
Return output
}
escrx(h) {
e := "\().[]*+?{}^$|"
Loop, Parse, e
If InStr(h, A_LoopField)
h := StrReplace(h, A_LoopField, "\" A_LoopField)
Return h
}
ListGlobalVars() { ;written by Lexikos
static hwndEdit, pSFW, pSW, bkpSFW, bkpSW
If !hwndEdit
{ dhw := A_DetectHiddenWindows
DetectHiddenWindows, On
Process, Exist
ControlGet, hwndEdit, Hwnd,, Edit1, ahk_class AutoHotkey ahk_pid %ErrorLevel%
DetectHiddenWindows, %dhw%
astr := A_IsUnicode ? "astr":"str"
ptr := A_PtrSize=8 ? "ptr":"uint"
hmod := DllCall("GetModuleHandle", "str", "user32.dll")
pSFW := DllCall("GetProcAddress", ptr, hmod, astr, "SetForegroundWindow")
pSW := DllCall("GetProcAddress", ptr, hmod, astr, "ShowWindow")
DllCall("VirtualProtect", ptr, pSFW, ptr, 8, "uint", 0x40, "uint*", 0)
DllCall("VirtualProtect", ptr, pSW, ptr, 8, "uint", 0x40, "uint*", 0)
bkpSFW := NumGet(pSFW+0, 0, "int64")
bkpSW := NumGet(pSW+0, 0, "int64")
}
If (A_PtrSize=8)
{ NumPut(0x0000C300000001B8, pSFW+0, 0, "int64") ;return TRUE
NumPut(0x0000C300000001B8, pSW+0, 0, "int64") ;return TRUE
}Else
{ NumPut(0x0004C200000001B8, pSFW+0, 0, "int64") ;return TRUE
NumPut(0x0008C200000001B8, pSW+0, 0, "int64") ;return TRUE
}
ListVars
NumPut(bkpSFW, pSFW+0, 0, "int64")
NumPut(bkpSW, pSW+0, 0, "int64")
ControlGetText, text,, ahk_id %hwndEdit%
RegExMatch(text, "sm)(?<=^Global Variables \(alphabetical\)`r`n-{50}`r`n).*", text)
Return text
}
HelpPage() {
HelpPage=
(
{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Arial;}{\f1\fnil\fcharset0 Consolas;}}
{\colortbl ;\red255\green0\blue0;\red155\green0\blue211;\red0\green77\blue187;\red0\green176\blue80;\red0\green0\blue255;}
{\*\generator Riched20 10.0.19041}\viewkind4\uc1
\pard\sa200\sl276\slmult1\b\fs36\lang9 H e l p _ P a g e\b0\par
\par
\cf1\b F1\cf0\b0 - to toggle this help page\par
\par
\b Basic syntax by example:\b0\par
\pard\li720\sa200\sl276\slmult1 coexisting words/strings/patterns -unwanted\par
for instance, \cf2\b\f1 d.*d -the and -oo \\ws\cf0\b0\f0\par
(the 5 segments (space separated) above can go all at once, and yet, they can also be entered one by one. that's the so-called multilevel approach, instead.)\par
\pard\sa200\sl276\slmult1\par
\b Feature keys:\b0\par
\pard\li720\sa200\sl276\slmult1\cf3\b Alt+a\cf0\b0 - to show assorted matches and toggle between chronological and alphabetical order.\par
\cf3\b Ctrl+t\cf0\b0 - to put assorted matches into a treeview gui which may ease the exploration when the list is long and involved multiple groups.\par
\cf3\b Ctrl+p\cf0\b0 - to bring up context peeking gui which provides an integrated way of reviewing the context of any lines in the shortlisted result.\par
\cf3\b WheelDown\cf0\b0 - to find the next match (downward) from the caret position (given that, the mouse pointer is currently outside both text/edit boxes.)\par
\cf3\b WheelUp\cf0\b0 - to find the next match (upward) from the caret position (given that, the mouse pointer is currently outside both text/edit boxes.)\par
\cf3\b Alt+v\cf0\b0 - to paste clipboard content into the big text/edit box.\par
\cf3\b Ctrl+o\cf0\b0 - to open a file.\par
\cf3\b Ctrl+r\cf0\b0 - to reload the file.\par
\cf3\b Rightclick\cf0\b0 "Back" button - to glance committed levels and select one to fall back to.\par
\cf3\b Esc\cf0\b0 - to quit/exit/leave. same as closing the window.\par
\cf3\b Tab\cf0\b0 - to change focus between the text/edit boxes (just try it.)\par
\par
these below only work when the \ul big\ulnone text/edit box is in focus:\par
\pard\li1440\sa200\sl276\slmult1\cf3\b f\cf0\b0 - to find the next match (downward) from the caret position.\par
\cf3\b Shift+f\cf0\b0 - to find the next match (upward) from the caret position.\par
\i (note: "the line" refers to the current line, that's where the caret is on.)\i0\par
\cf3\b Enter\cf0\b0 - to copy the line.\par
\cf3\b Space\cf0\b0 - to page down\par
\cf3\b Shift+Space\cf0\b0 - to page up\par
\cf3\b s\cf0\b0 - to move the caret to the beginning/start of the line.\par
\cf3\b e\cf0\b0 - to move the caret to the end of the line.\par
\cf3\b t\cf0\b0 - to move the caret to the top of the text.\par
\cf3\b b\cf0\b0 - to move the caret to the bottom of the text.\par
\cf3\b + or =\cf0\b0 - to increase font size (same as \cf3\b Ctrl+WheelUp\cf0\b0 ).\par
\cf3\b minus "-"\cf0\b0 - to decrease font size (same as \cf3\b Ctrl+WheelDown\cf0\b0 ).\par
\i (side note: "caret" may be known as "cursor" to some people.)\i0\par
\pard\sa200\sl276\slmult1\par
\tab these below only work when the \ul small\ulnone text/edit box is in focus:\par
\pard\li1440\sa200\sl276\slmult1\cf3\b Enter\cf0\b0 - to commit a level (which makes the current result becoming the base/source of the next level.) same as clicking the button Go.\par
\pard\sa200\sl276\slmult1\par
\pard\li720\sa200\sl276\slmult1\cf3\b Backtick (``)\cf0\b0 - since users mostly use this tool to locate the specific line of text and copy it for whatever subsequent actions to be taken, which typically involves Tab and then Enter (if the first line is the one wanted), backtick is an alternative which can supersede both keys by just hit backtick twice instead.\par
\pard\sa200\sl276\slmult1\par
The \b improvised shorthand\b0 feature:\par
\pard\li720\sa200\sl276\slmult1 this feature can be triggered through "\cf2\b\\/\cf0\b0 " (a \b backslash\b0 followed by a \b slash\b0 ), a "regex like" syntax style, which toggle it on or off. so, enter "\cf2\b\\/tr\cf0\b0 " will bring you those lines contained "\cf4\i the road\cf0\i0 ", "\cf4\i two roads\cf0\i0 ", as well as "\cf4\i them really\cf0\i0 " out of the poem, whereas enter "\cf2\b oo \\/a?a\cf0\b0 " or "\cf2\b\\/a?a\\/ oo\cf0\b0 " will return you these two lines "\cf4\i And looked down one as far as I could\cf0\i0 " and "\cf4\i Then took the other, as just as fair,\cf0\i0 " in which, the "\cf2\b ?\cf0\b0 " represents any valid character regex recognized it as "word" element. Besides, the space has been cared so that the toggle works across it. for instance, enter "\cf2\b\\/tr yw\cf0\b0 " or "\cf2\b\\/yw tr\cf0\b0 " will show this line "\cf4\i Two roads diverged in a yellow wood,\cf0\i0 " where the space is still a separator as always, even though the shorthand feature is toggled on.\par
\pard\sa200\sl276\slmult1\par
\tab three more elements of the shorthand syntax:\par
\par
\pard\fi-360\li1800\sa200\sl276\slmult1 1, \b extra qualifier\b0 (within a single word);\par
2, \b escape character\b0 (between words);\par
3, a single \b character\b0 representing any "\b non-word\b0 " one (between words).\par
\pard\sa200\sl276\slmult1\par
\pard\li720\sa200\sl276\slmult1 the most basic usage of improvised shorthand is to match the specific "phrase" by just entering the first letter of each word constituted it (for instance, "\cf2\b sameto\cf0\b0 " can match "\cf4\i some are more equal than others\cf0\i0 ") yet sometimes we may want to further narrow down the result. if "\cf2\b slh\cf0\b0 " brings you both "\cf4\i she likes him\cf0\i0 " and "\cf4\i she loves him\cf0\i0 ", an extra qualifier to pinpoint one may be useful. it could simply be a "v" for this example hence "\cf2\b slv/h\cf0\b0 " (in which, the "/" after the "v" tells the system that it's just an extra qualifier to the "l", not for a word starts with "v",) returns you "\cf4\i she loves him\cf0\i0 " only. likewise, you may sometimes want to tell the system exactly what the word should be ending with, for instance, if "\cf2\b ioy\cf0\b0 " brings you both "\cf4\i i owe you\cf0\i0 " and "\cf4\i i own you\cf0\i0 ", "\cf2\b ioe//y\cf0\b0 " (in which, the "//" after the "e" tells the system that it's a word ending character, that is, "oe//" represents a word starts with "o" and ends with "e") returns you "\cf4\i i owe you\cf0\i0 " only. and no matter how rare (and impractical) it may be, you may have multiple of these qualifiers for a word, such as, "\cf2\b cm/c/e//d//\cf0\b0 " can match the word "\cf4\i complicated\cf0\i0 " whereas "\cf2\b td/i/u//s//\cf0\b0 " can match the word "\cf4\i tedious\cf0\i0 ".\par
\par
a \b backslash\b0 "\cf2\b\\\cf0\b0 " may be used to escape a single character after it. its target should be a "word" character because you don't need to escape otherwise. for all "non-word" character, just enter them directly except "\\" itself which requires a \b double backslash\b0 "\cf2\b\\\\\cf0\b0 " for a single one. for regex syntax such as "\\s", it becomes "\\\\s" (not "\\\\\\s" you may presume.) in other words, all escaped character will only be matched barely itself. for \ul consecutive\ulnone "word" characters that need to be escaped, enclose them in the \cf2\b\\Q\cf0\b0 \cf2\b\\E\cf0\b0 pair, similar idea as in regex. one thing to note though, escaped character may affect the word immediately after it, for instance, "\cf2\b z\\xy\cf0\b0 " may bring you "\cf4\i zebra xylophone\cf0\i0 " rather than "\cf4\i zombie x yesterday\cf0\i0 ".\par
\par
an \b apostrophe\b0 "\cf2\b\f1 '\cf0\b0\f0 " may be used to represent any "non-word" character. that is, same as "\\\\W" (the regex syntax "\\W" for a "non-word" character). it may be useful at the (beginning and/or ending) ends of the "phrase" if it can further narrow down the result or you simply want it to be a part of the match.\par
\pard\sa200\sl276\slmult1\par
The \b matches highlighting\b0 feature:\par
\pard\li720\sa200\sl276\slmult1 the \ul default behavior\ulnone is to highlight no more than a thousand matches (which can improve the response time when too many matches are found.) it can nonetheless be overridden by a long press of your left mouse button on one of the available gui buttons (i.e. go or refresh or back), whereas long press means press it down and hold on for \ul one second or longer\ulnone . therefore, highlighting will cover the whole thing even if the total number of matches is over \ul one thousand\ulnone . this \ul long-press-to-override\ulnone is not a toggle, it's just an \ul one-off\ulnone thing, so do it every time you want more than the default.\par
\pard\sa200\sl276\slmult1\par
End of this help page.\par
}
)
Return HelpPage
}
} ;end of class
Last edited by SundayProgrammer on 13 Jun 2021, 08:19, edited 1 time in total.
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
the script is updated. → viewtopic.php?p=404344#p404344 ← click this link
star-one-a fix for omission.
star-one-a fix for omission.
Return to “Scripts and Functions (v1)”
Who is online
Users browsing this forum: No registered users and 216 guests