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.
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.
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.
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