Text Filter
Re: Text Filter
Thank you @SundayProgrammer for your work/updates
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
added a new feature which i call it improvised shorthand. that is, you can look up your target (typically a piece of text included one or more words) by just the first letter of each word in it. for instance, the shorthand "tr" out of the poem will bring you those lines contained "the road", "two roads", as well as "them really". (hard to make a longer one since the poem is not long enough. you got the idea anyway, i hope.)
this feature can be triggered through "\/" (a backslash followed by a slash), a "regex like" syntax style, which toggle it on or off. so, enter "\/tr" for the example mentioned above, whereas enter "oo \/a?a" or "\/a?a\/ oo" will return you these two lines "And looked down one as far as I could" and "Then took the other, as just as fair," in which, the "?" 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 "\/tr yw" or "\/yw tr" will show this line "Two roads diverged in a yellow wood," where the space is still a separator as always, even though the shorthand feature is toggled on.
this feature can be triggered through "\/" (a backslash followed by a slash), a "regex like" syntax style, which toggle it on or off. so, enter "\/tr" for the example mentioned above, whereas enter "oo \/a?a" or "\/a?a\/ oo" will return you these two lines "And looked down one as far as I could" and "Then took the other, as just as fair," in which, the "?" 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 "\/tr yw" or "\/yw tr" will show this line "Two roads diverged in a yellow wood," where the space is still a separator as always, even though the shorthand feature is toggled on.
Code: Select all
HelpPage=
(
H e l p _ P a g e
F1 - to toggle this help page
Basic syntax by example:
coexisting words/strings/patterns -unwanted
for instance, d.*d -the and -oo \ws
(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.)
Feature keys:
Alt+a - to show assorted matches and toggle between chronological and alphabetical order.
WheelDown - to find the next match (downward) from the caret position (given that, the mouse pointer is currently outside both text/edit boxes.)
WheelUp - to find the next match (upward) from the caret position (given that, the mouse pointer is currently outside both text/edit boxes.)
Esc - to quit/exit/leave. same as closing the window.
Tab - to change focus between the text/edit boxes (just try it.)
these below only work when the big text/edit box is in focus:
f - to find the next match (downward) from the caret position.
Shift+f - to find the next match (upward) from the caret position.
(note: "the line" refers to the current line, that's where the caret is on.)
Enter - to copy the line.
Space - to page down
Shift+Space - to page up
s - to move the caret to the beginning/start of the line.
e - to move the caret to the end of the line.
t - to move the caret to the top of the text.
b - to move the caret to the bottom of the text.
(side note: "caret" may be known as "cursor" to some people.)
these below only work when the small text/edit box is in focus:
Enter - to commit a level (which makes the current result becoming the base/source of the next level.) same as clicking the button Go.
Backtick (``) - 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.
The improvised shorthand feature:
this feature can be triggered through "\/" (a backslash followed by a slash), a "regex like" syntax style, which toggle it on or off. so, enter "\/tr" will bring you those lines contained "the road", "two roads", as well as "them really" out of the poem, whereas enter "oo \/a?a" or "\/a?a\/ oo" will return you these two lines "And looked down one as far as I could" and "Then took the other, as just as fair," in which, the "?" 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 "\/tr yw" or "\/yw tr" will show this line "Two roads diverged in a yellow wood," where the space is still a separator as always, even though the shorthand feature is toggled on.
End of this help page.
)
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 := 1, regWhole := regLinum := regWwrap := 0
theGui:
Gui, tf:New
Gui, +Delimiter`n
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 - 257
Gui, Add, ComboBox, w%w% ys vNeedleCB gtfFpatHdlr +hwndhEdit1
Gui, Add, Button, h38 ys Default, Go
Gui, Add, Button, h38 ys, Back
h := A_ScreenHeight - 143, w := A_ScreenWidth - 30
begWwrap := regWwrap ? "" : "HScroll"
Gui, Font, s18, Consolas
Gui, Add, Edit, ReadOnly x10 h%h% w%w% %begWwrap% VScroll +hwndhEdit2
Gui, Show,, The Text Filter,, The Text Filter - Level %n% ( Base %blc% Lines )
ControlGet, cid, hwnd,, Edit2, A
RenewGui:
GuiControl,, Edit2, % Haystack%n%
ControlFocus, Edit1, A
SetWinTitle:
StrReplace(Haystack%n%, "`n",, blc), blc += StrLen(Haystack%n%) and SubStr(Haystack%n%, 0) != "`n" ? 1 : 0
WinSetTitle, The Text Filter,, The Text Filter - Level %n% ( Base %blc% Lines )
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:
regWwrap := Wwrap()
Needle%n% := Fpat()
Gui, tf:Destroy
Gosub, theGui
ControlSetText, Edit1, % Needle%n%, A
Send, {End} ;SendMessage, 0xB1, cp:=StrLen(Needle%n%), cp,, ahk_id %hEdit1% ;EM_SETSEL
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 InStr(NeedleHistory, Needle%n%, !regCase)
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
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 ;SendMessage, 0xB1, 0, StrLen(Needle%pn%),, ahk_id %hEdit1% ;EM_SETSEL
}
}
CommitLevel = 0
Sleep, 500
Progress, Off
}Else Haystack%n% := theHaystack
Goto, RenewGui
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
}
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
{ Gosub, RenewGui
ControlSetText, Edit1, % Needle%n%
Send, ^a ;SendMessage, 0xB1, 0, StrLen(Needle%n%),, ahk_id %hEdit1% ;EM_SETSEL
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
tfGuiEscape:
tfGuiClose:
ExitApp
Fpat() {
ControlGetText, Fpat, Edit1 ;GuiControlGet, 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 := "\/", ph := "[^\w\n]", tar := "\" tog ph "*?\K\w"
If mpos:=RegExMatch(t, tar) ;contained toggle (on)
{ pb := "[^,\w;\n.]", sh := "((?<=^|" ph ")", st := "(?=(\W|$)))"
r := StrReplace(SubStr(t, 1, mpos - 1), tog) sh, rr := xx := ""
Loop
{ c := SubStr(t, mpos, 1)
If RegExMatch(c,"\w") or (c = "?") ;valid character
{ If rr
r .= xx ? pb "*?" xx pb "*?" : pb "+?", xx := ""
Else If StrLen(rr)
r .= xx sh, rr := xx := ""
r .= (c = "?") ? "\w+?" : c "\w*?", rr := st
}Else If (c = A_Space) and rr
r .= xx ? pb "*?" xx rr : rr, xx := A_Space, rr := 0
Else xx .= "\" c
mpos++
If (mpos > StrLen(t)) ;exceeded
{ If rr
r .= xx ? pb "*?" xx rr : rr, rr := xx := ""
Break
}Else If SubStr(t, mpos, StrLen(tog)) = tog ;toggle (off) encountered
{ r .= xx ? pb "*?" xx rr : rr, 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
}
}
}
}Else r := t
;msgbox % t "`n`n" r
Return r
}
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
Return foco
}
#If, WinActive("The Text Filter") and FocusedControl() = "Edit1"
`::
Tab::ControlFocus, Edit2, A
~Bs::
~Del::
If regFayt
Goto, tfFpatHdlr
Else Return
#If, WinActive("The Text Filter") and FocusedControl() = "Edit2"
Tab::ControlFocus, Edit1, A
~Space::PgDn
~+Space::PgUp
~s::Home
~e::End
~t::^Home
~b::^End
`::
~Enter::
ControlGetText, Hays, Edit2, A
DllCall("User32\SendMessage", "Ptr", cid, "UInt", 0x00B0, "UIntP", slcs, "UIntP", slce, "Ptr")
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 := RegExReplace((mpos > pmax ? SubStr(Hays, slcs) : SubStr(Hays, slcs, mpos - slcs)), "^\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
{ ControlGet, sPat, Selected,, Edit2, A
r := StrLen(sPat) ? (regCase ? "i)" : "") (regWhole ? "\b" : "") escrx(sPat) (regWhole ? "\b" : "") : ""
}
If StrLen(r)
{ If SubStr(r, 0) = "|"
r := SubStr(r, 1, StrLen(r)-1)
ControlGettext, Hays, Edit2, A
If RegExMatch(Hays, r)
{ StartHere:
Gosub, Compute_cp
If InStr("~WheelUp,~+f", A_ThisHotkey)
{ Gosub, ReverseWay
mpos -= 1
}Else mpos := RegExMatch(Hays, r, nm, cp) - 1
If mpos >= 0
{ cp := mpos + StrLen(nm)
SendMessage, 0xB1, mpos, cp,, ahk_id %hEdit2% ;EM_SETSEL
SendMessage, 0xB7, 0, 0,, ahk_id %hEdit2% ;EM_SCROLLCARET
}Else If (mpos < 0) and not InStr("~WheelUp,~+f", A_ThisHotkey)
{ SendMessage, 0xB1, 0, 0,, ahk_id %hEdit2% ;EM_SETSEL ;Send, ^{Home}
Goto, StartHere
}
}Else MsgBox, Target Not Found
}
Return
MakerFnm:
sPat := tw4sh(sPat), r := (regCase ? "i" : "") "m`a)"
Loop, Parse, sPat, % A_Space
If SubStr(A_LoopField, 1, 1) != "-"
r .= "(" (regWhole ? "\b" : "") A_LoopField (regWhole ? "\b" : "") ")|"
Return
Compute_cp:
DllCall("User32\SendMessage", "Ptr", cid, "UInt", 0x00B0, "UIntP", slcs, "UIntP", slce, "Ptr"), slcs++, slce++
cp := InStr("~WheelUp,~+f", A_ThisHotkey) ? 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
#IfWinActive, The Text Filter
F1::
ControlGetText, Hays, Edit2, A
If SubStr(Hays, 1, 17) = "H e l p _ P a g e"
ControlSetText, Edit2, %B4Help%, A
Else
{ B4Help := Hays
ControlSetText, Edit2, %HelpPage%, A
}
Return
~Wheelup::
~Wheeldown::
MouseGetPos,,,, moc
If not StrLen(moc) or not InStr("Edit1|Edit2", moc)
{ ControlFocus, Edit2, A
Goto, NextMatch
}Else Return
!a::
ControlGetText, Hays, Edit2, A
If SubStr(Hays, 1, 19) = "Assorted Matches:`t("
{ If SubStr(Hays, 20, 12) = "Alphabetical"
ControlSetText, Edit2, %AssHays%, A
Else
ControlSetText, Edit2, %AAssHays%, A
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
If SubStr(r, 0) = "|"
r := SubStr(r, 1, StrLen(r)-1)
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 := AssHays := "", umNoSort := []
For k, v in UniqMatches
UniqHays .= rn StrRepeat(A_Space, 3) A_Index ".`t" k, AssHays .= rn A_Index ". " AssHays%v%, umNoSort[v] ? umNoSort[v].Insert(k) : umNoSort[v] := k
AAssHays := "Assorted Matches:`t(Alphabetical Order)" UniqHays rn StrRepeat("-", 50) AssHays
UniqHays := AssHays := ""
For k, v in umNoSort
UniqHays .= rn StrRepeat(A_Space, 3) k ".`t" v, AssHays .= rn A_Index ". " AssHays%k%
AssHays := "Assorted Matches:`t(Chronological Order)" UniqHays rn StrRepeat("-", 50) AssHays
ControlSetText, Edit2, %AssHays%, A
}
Progress, Off
Return
#IfWinActive
Re: Text Filter
I think there is a problem with this line
I had to comment out as follows:
Code: Select all
Send, ^a ;SendMessage, 0xB1, 0, StrLen(Needle%pn%),, ahk_id %hEdit1% ;EM_SETSEL
Code: Select all
Send, ^a
Code: Select all
;Send, ^a ;SendMessage, 0xB1, 0, StrLen(Needle%pn%),, ahk_id %hEdit1% ;EM_SETSEL
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
@carno
could you describe the problem you encountered ?
could you describe the problem you encountered ?
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
added three more elements to the shorthand syntax:
1, extra qualifier (within a single word);
2, escape character (between words);
3, a single character representing any "non-word" one (between words).
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, "sameto" can match "some are more equal than others") yet sometimes we may want to further narrow down the result. if "slh" brings you both "she likes him" and "she loves him", an extra qualifier to pinpoint one may be useful. it could simply be a "v" for this example hence "slv/h" (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 "she loves him" only. likewise, you may sometimes want to tell the system exactly what the word should be ending with, for instance, if "ioy" brings you both "i owe you" and "i own you", "ioe//y" (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 "i owe you" only. and no matter how rare (and impractical) it may be, you may have multiple of these qualifiers for a word, such as, "cm/c/e//d//" can match the word "complicated" whereas "td/i/u//s//" can match the word "tedious".
a backslash "\" 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 double backslash "\\" 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 consecutive "word" characters that need to be escaped, enclose them in the \Q \E pair, similar idea as in regex. one thing to note though, escaped character may affect the word immediately after it, for instance, "z\xy" may bring you "zebra xylophone" rather than "zombie x yesterday".
an apostrophe "'" 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.
that's it for now.
1, extra qualifier (within a single word);
2, escape character (between words);
3, a single character representing any "non-word" one (between words).
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, "sameto" can match "some are more equal than others") yet sometimes we may want to further narrow down the result. if "slh" brings you both "she likes him" and "she loves him", an extra qualifier to pinpoint one may be useful. it could simply be a "v" for this example hence "slv/h" (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 "she loves him" only. likewise, you may sometimes want to tell the system exactly what the word should be ending with, for instance, if "ioy" brings you both "i owe you" and "i own you", "ioe//y" (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 "i owe you" only. and no matter how rare (and impractical) it may be, you may have multiple of these qualifiers for a word, such as, "cm/c/e//d//" can match the word "complicated" whereas "td/i/u//s//" can match the word "tedious".
a backslash "\" 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 double backslash "\\" 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 consecutive "word" characters that need to be escaped, enclose them in the \Q \E pair, similar idea as in regex. one thing to note though, escaped character may affect the word immediately after it, for instance, "z\xy" may bring you "zebra xylophone" rather than "zombie x yesterday".
an apostrophe "'" 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.
that's it for now.
Code: Select all
HelpPage=
(
H e l p _ P a g e
F1 - to toggle this help page
Basic syntax by example:
coexisting words/strings/patterns -unwanted
for instance, d.*d -the and -oo \ws
(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.)
Feature keys:
Alt+a - to show assorted matches and toggle between chronological and alphabetical order.
WheelDown - to find the next match (downward) from the caret position (given that, the mouse pointer is currently outside both text/edit boxes.)
WheelUp - to find the next match (upward) from the caret position (given that, the mouse pointer is currently outside both text/edit boxes.)
Esc - to quit/exit/leave. same as closing the window.
Tab - to change focus between the text/edit boxes (just try it.)
these below only work when the big text/edit box is in focus:
f - to find the next match (downward) from the caret position.
Shift+f - to find the next match (upward) from the caret position.
(note: "the line" refers to the current line, that's where the caret is on.)
Enter - to copy the line.
Space - to page down
Shift+Space - to page up
s - to move the caret to the beginning/start of the line.
e - to move the caret to the end of the line.
t - to move the caret to the top of the text.
b - to move the caret to the bottom of the text.
(side note: "caret" may be known as "cursor" to some people.)
these below only work when the small text/edit box is in focus:
Enter - to commit a level (which makes the current result becoming the base/source of the next level.) same as clicking the button Go.
Backtick (``) - 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.
The improvised shorthand feature:
this feature can be triggered through "\/" (a backslash followed by a slash), a "regex like" syntax style, which toggle it on or off. so, enter "\/tr" will bring you those lines contained "the road", "two roads", as well as "them really" out of the poem, whereas enter "oo \/a?a" or "\/a?a\/ oo" will return you these two lines "And looked down one as far as I could" and "Then took the other, as just as fair," in which, the "?" 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 "\/tr yw" or "\/yw tr" will show this line "Two roads diverged in a yellow wood," where the space is still a separator as always, even though the shorthand feature is toggled on.
three more elements of the shorthand syntax:
1, extra qualifier (within a single word);
2, escape character (between words);
3, a single character representing any "non-word" one (between words).
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, "sameto" can match "some are more equal than others") yet sometimes we may want to further narrow down the result. if "slh" brings you both "she likes him" and "she loves him", an extra qualifier to pinpoint one may be useful. it could simply be a "v" for this example hence "slv/h" (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 "she loves him" only. likewise, you may sometimes want to tell the system exactly what the word should be ending with, for instance, if "ioy" brings you both "i owe you" and "i own you", "ioe//y" (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 "i owe you" only. and no matter how rare (and impractical) it may be, you may have multiple of these qualifiers for a word, such as, "cm/c/e//d//" can match the word "complicated" whereas "td/i/u//s//" can match the word "tedious".
a backslash "\" 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 double backslash "\\" 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 consecutive "word" characters that need to be escaped, enclose them in the \Q \E pair, similar idea as in regex. one thing to note though, escaped character may affect the word immediately after it, for instance, "z\xy" may bring you "zebra xylophone" rather than "zombie x yesterday".
an apostrophe "'" 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.
End of this help page.
)
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 := 1, regWhole := regLinum := regWwrap := 0
theGui:
Gui, tf:New
Gui, +Delimiter`n
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 - 257
Gui, Add, ComboBox, w%w% ys vNeedleCB gtfFpatHdlr +hwndhEdit1
Gui, Add, Button, h38 ys Default, Go
Gui, Add, Button, h38 ys, Back
h := A_ScreenHeight - 143, w := A_ScreenWidth - 30
begWwrap := regWwrap ? "" : "HScroll"
Gui, Font, s18, Consolas
Gui, Add, Edit, ReadOnly x10 h%h% w%w% %begWwrap% VScroll +hwndhEdit2
Gui, Show,, The Text Filter,, The Text Filter - Level %n% ( Base %blc% Lines )
ControlGet, cid, hwnd,, Edit2, A
RenewGui:
GuiControl,, Edit2, % Haystack%n%
ControlFocus, Edit1, A
SetWinTitle:
StrReplace(Haystack%n%, "`n",, blc), blc += StrLen(Haystack%n%) and SubStr(Haystack%n%, 0) != "`n" ? 1 : 0
WinSetTitle, The Text Filter,, The Text Filter - Level %n% ( Base %blc% Lines )
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:
regWwrap := Wwrap()
Needle%n% := Fpat()
Gui, tf:Destroy
Gosub, theGui
ControlSetText, Edit1, % Needle%n%, A
Send, {End} ;SendMessage, 0xB1, cp:=StrLen(Needle%n%), cp,, ahk_id %hEdit1% ;EM_SETSEL
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
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 ;SendMessage, 0xB1, 0, StrLen(Needle%pn%),, ahk_id %hEdit1% ;EM_SETSEL
}
}
CommitLevel = 0
Sleep, 500
Progress, Off
}Else Haystack%n% := theHaystack
Goto, RenewGui
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
}
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
{ Gosub, RenewGui
ControlSetText, Edit1, % Needle%n%
Send, ^a ;SendMessage, 0xB1, 0, StrLen(Needle%n%),, ahk_id %hEdit1% ;EM_SETSEL
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
tfGuiEscape:
tfGuiClose:
ExitApp
Fpat() {
ControlGetText, Fpat, Edit1 ;GuiControlGet, 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
{ r .= xx ? pb "*?" xx st : 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
r .= xx ? pb "*?" xx st : st, xx := A_Space, rr := 0
Else If (c = "'")
flush(r, xx, pb, yb), r .= "\W"
Else If (c = "\")
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)
flush(r, xx, pb, yb), r .= c
Else If RegExMatch(cc,"\w")
skip_w := skip_w ? skip_w : True, flush(r, xx, pb, yb)
Else skip_c++, flush(r, xx, pb, yb), r .= c cc
Else xx .= c
mpos++
If (mpos > StrLen(t)) ;exceeded
{ If rr
r .= xx ? pb "*?" xx st : st, rr := xx := ""
Break
}
}
}Else r := t
;msgbox % t "`n`n" r
Return r
}
flush(ByRef r, ByRef xx, pb, ByRef yb) {
r .= xx ? pb "*?" xx pb "*?" : (yb ? (pb "+?", 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
Return foco
}
#If, WinActive("The Text Filter") and FocusedControl() = "Edit1"
`::
Tab::ControlFocus, Edit2, A
~Bs::
~Del::
If regFayt
Goto, tfFpatHdlr
Else Return
#If, WinActive("The Text Filter") and FocusedControl() = "Edit2"
Tab::ControlFocus, Edit1, A
~Space::PgDn
~+Space::PgUp
~s::Home
~e::End
~t::^Home
~b::^End
`::
~Enter::
ControlGetText, Hays, Edit2, A
DllCall("User32\SendMessage", "Ptr", cid, "UInt", 0x00B0, "UIntP", slcs, "UIntP", slce, "Ptr")
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 := RegExReplace((mpos > pmax ? SubStr(Hays, slcs) : SubStr(Hays, slcs, mpos - slcs)), "^\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
{ ControlGet, sPat, Selected,, Edit2, A
r := StrLen(sPat) ? (regCase ? "i)" : "") (regWhole ? "\b" : "") escrx(sPat) (regWhole ? "\b" : "") : ""
}
If StrLen(r)
{ If SubStr(r, 0) = "|"
r := SubStr(r, 1, StrLen(r)-1)
ControlGettext, Hays, Edit2, A
If RegExMatch(Hays, r)
{ StartHere:
Gosub, Compute_cp
If RegExMatch(A_ThisHotkey, "WheelUp|\+f")
{ Gosub, ReverseWay
mpos -= 1
}Else mpos := RegExMatch(Hays, r, nm, cp) - 1
If mpos >= 0
{ cp := mpos + StrLen(nm)
SendMessage, 0xB1, mpos, cp,, ahk_id %hEdit2% ;EM_SETSEL
SendMessage, 0xB7, 0, 0,, ahk_id %hEdit2% ;EM_SCROLLCARET
}Else If (mpos < 0) and not RegExMatch(A_ThisHotkey, "WheelUp|\+f")
{ SendMessage, 0xB1, 0, 0,, ahk_id %hEdit2% ;EM_SETSEL ;Send, ^{Home}
Goto, StartHere
}
}Else MsgBox, Target Not Found
}
Return
MakerFnm:
sPat := tw4sh(sPat), r := (regCase ? "i" : "") "m`a)"
Loop, Parse, sPat, % A_Space
If SubStr(A_LoopField, 1, 1) != "-"
r .= "(" (regWhole ? "\b" : "") A_LoopField (regWhole ? "\b" : "") ")|"
Return
Compute_cp:
DllCall("User32\SendMessage", "Ptr", cid, "UInt", 0x00B0, "UIntP", slcs, "UIntP", slce, "Ptr"), slcs++, slce++
cp := RegExMatch(A_ThisHotkey, "WheelUp|\+f") ? 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
#IfWinActive, The Text Filter
F1::
ControlGetText, Hays, Edit2, A
If SubStr(Hays, 1, 17) = "H e l p _ P a g e"
ControlSetText, Edit2, %B4Help%, A
Else
{ B4Help := Hays
ControlSetText, Edit2, %HelpPage%, A
}
Return
~Wheelup::
~Wheeldown::
MouseGetPos,,,, moc
If not StrLen(moc) or not InStr("Edit1|Edit2", moc)
{ ControlFocus, Edit2, A
Goto, NextMatch
}Else Return
!a::
ControlGetText, Hays, Edit2, A
If SubStr(Hays, 1, 19) = "Assorted Matches:`t("
{ If SubStr(Hays, 20, 12) = "Alphabetical"
ControlSetText, Edit2, %AssHays%, A
Else
ControlSetText, Edit2, %AAssHays%, A
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
If SubStr(r, 0) = "|"
r := SubStr(r, 1, StrLen(r)-1)
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 := AssHays := "", umNoSort := []
For k, v in UniqMatches
UniqHays .= rn StrRepeat(A_Space, 3) A_Index ".`t" k, AssHays .= rn A_Index ". " AssHays%v%, umNoSort[v] ? umNoSort[v].Insert(k) : umNoSort[v] := k
AAssHays := "Assorted Matches:`t(Alphabetical Order)" UniqHays rn StrRepeat("-", 50) AssHays
UniqHays := AssHays := ""
For k, v in umNoSort
UniqHays .= rn StrRepeat(A_Space, 3) k ".`t" v, AssHays .= rn A_Index ". " AssHays%k%
AssHays := "Assorted Matches:`t(Chronological Order)" UniqHays rn StrRepeat("-", 50) AssHays
ControlSetText, Edit2, %AssHays%, A
}
Progress, Off
Return
#IfWinActive
Re: Text Filter
Uploaded Text Filter Sci 1.1. Updated Pic. Tested on Win10 x64 120 dpi (125%). Made blind attempt (no tests) for other Dpi-s. App has still many quirks, but there will be no updates soon. Despite that, bug reports are welcome. Instructions: Read comments in the script after ::. My favorite: ^+o.
Edit: Due to serious bug fresh upload!
bye!
Edit: Due to serious bug fresh upload!
bye!
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
@rommmcekrommmcek wrote: ↑21 Mar 2021, 14:01Uploaded Text Filter Sci 1.1. Updated Pic. Tested on Win10 x64 120 dpi (125%). Made blind attempt (no tests) for other Dpi-s. App has still many quirks, but there will be no updates soon. Despite that, bug reports are welcome. Instructions: Read comments in the script after ::. My favorite: ^+o.
Edit: Due to serious bug fresh upload!
bye!
THANK YOU.
i gained one more reason to learn scintilla, even though it still looks pretty hard.
i noticed that your zip file didn't include scilexer32aa.dll, as i guess scilexer-x86.dll which i happened to have one may do the job, i then renamed it and it seemed working fine.
will see if i can apply scintilla later on.
my first impression though, the response time is quite noticeably slower now. (it may be only for me, as i'm using a very low-graded pc.)
chao!
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
added a new feature, the matches highlighting. this is implemented through richedit, not scintilla. it works quite good to me so far.
since it's in rich text format now, the help page can be colored and with better paragraph alignments. so, i made a rtf file for it, attached, which should be placed at the same folder of this script. it can still run fine without it though.
rtf help_page -
that's it for now.
it looks like this
it looks like this
rtf help_page -
Code: Select all
Version = Planet-Seven-D
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 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
\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
Gui, +Delimiter`n
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, Edit, ReadOnly x10 h%h% w%w% %begWwrap% VScroll +hwndhEdit2
Gui, Add, Custom, ClassRICHEDIT50W x10 h%h% w%w% %begWwrap% +VScroll +hwndHRE +0x0004 ;ES_MULTILINE
Gui, Show,, The Text Filter,, The Text Filter (Version: %Version%) - Level %n% ( Base %blc% Lines )
RE := GetTomDoc(HRE)
;ControlGet, cid, hwnd,, Edit2, A
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 GuiControl,, RICHEDIT50W1, % Haystack%n% ;GuiControl,, Edit2, % Haystack%n%
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 SubStr(r, 0) = "|"
r := SubStr(r, 1, StrLen(r)-1)
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:
StrReplace(Haystack%n%, "`n",, blc), blc += StrLen(Haystack%n%) and SubStr(Haystack%n%, 0) != "`n" ? 1 : 0
WinSetTitle, The Text Filter,, The Text Filter (Version: %Version%) - Level %n% ( Base %blc% Lines )
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} ;SendMessage, 0xB1, cp:=StrLen(Needle%n%), cp,, ahk_id %hEdit1% ;EM_SETSEL
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
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 ;SendMessage, 0xB1, 0, StrLen(Needle%pn%),, ahk_id %hEdit1% ;EM_SETSEL
}
}
CommitLevel = 0
Sleep, 500
Progress, Off
}Else Haystack%n% := theHaystack
Goto, RenewGui
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
{ Gosub, RenewGui
ControlSetText, Edit1, % Needle%n%
Send, ^a ;SendMessage, 0xB1, 0, StrLen(Needle%n%),, ahk_id %hEdit1% ;EM_SETSEL
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
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 ;GuiControlGet, 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 = "\")
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
;msgbox % t "`n`n" r
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 ;ControlFocus, Edit2, A
#If, WinActive("The Text Filter") and FocusedControl() = "RICHEDIT50W1" ;"Edit2"
Tab::ControlFocus, Edit1, A
~Space::PgDn
~+Space::PgUp
~s::Home
~e::End
~t::^Home
~b::^End
`::
~Enter::
ControlGetText, Hays, RICHEDIT50W1, A ;ControlGetText, Hays, Edit2, A
StringReplace, Hays, Hays, `r`n, `n, All ;for RichEdit
slcs := RE.Selection.Start, slce := RE.Selection.End ;DllCall("User32\SendMessage", "Ptr", cid, "UInt", 0x00B0, "UIntP", slcs, "UIntP", slce, "Ptr")
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 := RegExReplace((mpos > pmax ? SubStr(Hays, slcs) : SubStr(Hays, slcs, mpos - slcs)), "^\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 ;ControlGet, sPat, Selected,, Edit2, A
r := StrLen(sPat) ? (regCase ? "i)" : "") (regWhole ? "\b" : "") escrx(sPat) (regWhole ? "\b" : "") : ""
}
If StrLen(r)
{ If SubStr(r, 0) = "|"
r := SubStr(r, 1, StrLen(r)-1)
ControlGettext, Hays, RICHEDIT50W1, A ;ControlGettext, Hays, Edit2, A
StringReplace, Hays, Hays, `r`n, `n, All ;for RichEdit
If RegExMatch(Hays, r)
{ StartHere:
Gosub, Compute_cp
If RegExMatch(A_ThisHotkey, "WheelUp|\+f")
{ Gosub, ReverseWay
mpos -= 1
}Else mpos := RegExMatch(Hays, r, nm, cp) - 1
If mpos >= 0
{ cp := mpos + StrLen(nm)
RE.Range(mpos, cp).Select
;SendMessage, 0xB1, mpos, cp,, ahk_id %hEdit2% ;EM_SETSEL
;SendMessage, 0xB7, 0, 0,, ahk_id %hEdit2% ;EM_SCROLLCARET
}Else If (mpos < 0) and not RegExMatch(A_ThisHotkey, "WheelUp|\+f")
{ RE.Range(0, 0).Select ;SendMessage, 0xB1, 0, 0,, ahk_id %hEdit2% ;EM_SETSEL ;Send, ^{Home}
Goto, StartHere
}
}Else MsgBox, Target Not Found
}
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)
r := (regCase ? "i" : "") "m`a)" r
Return
Compute_cp:
slcs := RE.Selection.Start, slce := RE.Selection.End, slcs++, slce++ ;DllCall("User32\SendMessage", "Ptr", cid, "UInt", 0x00B0, "UIntP", slcs, "UIntP", slce, "Ptr"), slcs++, slce++
cp := RegExMatch(A_ThisHotkey, "WheelUp|\+f") ? 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
#IfWinActive, The Text Filter
F1::
ControlGetText, Hays, RICHEDIT50W1, A ;ControlGetText, Hays, Edit2, 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 ;ControlSetText, Edit2, %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)
;ControlSetText, RICHEDIT50W1, %HelpPage%, A ;ControlSetText, Edit2, %HelpPage%, A
}
Return
~Wheelup::
~Wheeldown::
MouseGetPos,,,, moc
If not StrLen(moc) or not InStr("Edit1|RICHEDIT50W1", moc) ;InStr("Edit1|Edit2", moc)
{ ControlFocus, RICHEDIT50W1, A ;ControlFocus, Edit2, A
Goto, NextMatch
}Else Return
!a::
fromAssortment := True
ControlGetText, Hays, RICHEDIT50W1, A ;ControlGetText, Hays, Edit2, A
If SubStr(Hays, 1, 19) = "Assorted Matches:`t("
{ If SubStr(Hays, 20, 12) = "Alphabetical"
ControlSetText, RICHEDIT50W1, %AssHays%, A ;ControlSetText, Edit2, %AssHays%, A
Else
ControlSetText, RICHEDIT50W1, %AAssHays%, A ;ControlSetText, Edit2, %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
If SubStr(r, 0) = "|"
r := SubStr(r, 1, StrLen(r)-1)
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 := AssHays := "", umNoSort := []
For k, v in UniqMatches
UniqHays .= rn StrRepeat(A_Space, 3) A_Index ".`t" k, AssHays .= rn A_Index ". " AssHays%v%, umNoSort[v] ? umNoSort[v].Insert(k) : umNoSort[v] := k
AAssHays := "Assorted Matches:`t(Alphabetical Order)" UniqHays rn StrRepeat("-", 50) AssHays
UniqHays := AssHays := ""
For k, v in umNoSort
UniqHays .= rn StrRepeat(A_Space, 3) k ".`t" v, AssHays .= rn A_Index ". " AssHays%k%
AssHays := "Assorted Matches:`t(Chronological Order)" UniqHays rn StrRepeat("-", 50) AssHays
StringReplace, AssHays, AssHays, `r`n, `n, All ;for RichEdit
StringReplace, AAssHays, AAssHays, `r`n, `n, All ;for RichEdit
ControlSetText, RICHEDIT50W1, %AssHays%, A ;ControlSetText, Edit2, %AssHays%, A
Gosub, RenewGui
}
Progress, Off
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
#IfWinActive
Last edited by SundayProgrammer on 08 Apr 2021, 03:36, edited 5 times in total.
Re: Text Filter
Thank you @SundayProgrammer for this update.
Maybe just at the exist a delete of 'tfWork.rtf'
Maybe just at the exist a delete of 'tfWork.rtf'
Re: Text Filter
Thank you, this good thing. I've had a similar work with RTF. I struggled with scintilla when it was too slow for large documents.SundayProgrammer wrote: ↑01 Apr 2021, 01:51added a new feature, the matches highlighting. this is implemented through richedit, not scintilla. it works quite good to me so far.
since it's in rich text format now, the help page can be colored and with better paragraph alignments. so, i made a rtf file for it, attached, which should be placed at the same folder of this script. it can still run fine without it though.it looks like this
it looks like this
rtf help_page - tfHelp.rtf
that's it for now.Code: Select all
SetWorkingDir %A_ScriptDir% RE_Dll := DllCall("LoadLibrary", "Str", "Msftedit.dll", "Ptr") HelpPage= ( H e l p _ P a g e F1 - to toggle this help page Basic syntax by example: coexisting words/strings/patterns -unwanted for instance, d.*d -the and -oo \ws (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.) Feature keys: Alt+a - to show assorted matches and toggle between chronological and alphabetical order. WheelDown - to find the next match (downward) from the caret position (given that, the mouse pointer is currently outside both text/edit boxes.) WheelUp - to find the next match (upward) from the caret position (given that, the mouse pointer is currently outside both text/edit boxes.) Alt+v - to paste clipboard content into the big text/edit box. Esc - to quit/exit/leave. same as closing the window. Tab - to change focus between the text/edit boxes (just try it.) these below only work when the big text/edit box is in focus: f - to find the next match (downward) from the caret position. Shift+f - to find the next match (upward) from the caret position. (note: "the line" refers to the current line, that's where the caret is on.) Enter - to copy the line. Space - to page down Shift+Space - to page up s - to move the caret to the beginning/start of the line. e - to move the caret to the end of the line. t - to move the caret to the top of the text. b - to move the caret to the bottom of the text. (side note: "caret" may be known as "cursor" to some people.) these below only work when the small text/edit box is in focus: Enter - to commit a level (which makes the current result becoming the base/source of the next level.) same as clicking the button Go. Backtick (``) - 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. The improvised shorthand feature: this feature can be triggered through "\/" (a backslash followed by a slash), a "regex like" syntax style, which toggle it on or off. so, enter "\/tr" will bring you those lines contained "the road", "two roads", as well as "them really" out of the poem, whereas enter "oo \/a?a" or "\/a?a\/ oo" will return you these two lines "And looked down one as far as I could" and "Then took the other, as just as fair," in which, the "?" 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 "\/tr yw" or "\/yw tr" will show this line "Two roads diverged in a yellow wood," where the space is still a separator as always, even though the shorthand feature is toggled on. three more elements of the shorthand syntax: 1, extra qualifier (within a single word); 2, escape character (between words); 3, a single character representing any "non-word" one (between words). 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, "sameto" can match "some are more equal than others") yet sometimes we may want to further narrow down the result. if "slh" brings you both "she likes him" and "she loves him", an extra qualifier to pinpoint one may be useful. it could simply be a "v" for this example hence "slv/h" (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 "she loves him" only. likewise, you may sometimes want to tell the system exactly what the word should be ending with, for instance, if "ioy" brings you both "i owe you" and "i own you", "ioe//y" (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 "i owe you" only. and no matter how rare (and impractical) it may be, you may have multiple of these qualifiers for a word, such as, "cm/c/e//d//" can match the word "complicated" whereas "td/i/u//s//" can match the word "tedious". a backslash "\" 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 double backslash "\\" 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 consecutive "word" characters that need to be escaped, enclose them in the \Q \E pair, similar idea as in regex. one thing to note though, escaped character may affect the word immediately after it, for instance, "z\xy" may bring you "zebra xylophone" rather than "zombie x yesterday". an apostrophe "'" 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. End of this help page. ) 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 := fromButtonRefresh := 0 theGui: Gui, tf:New Gui, +Delimiter`n 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, Edit, ReadOnly x10 h%h% w%w% %begWwrap% VScroll +hwndhEdit2 Gui, Add, Custom, ClassRICHEDIT50W x10 h%h% w%w% %begWwrap% +VScroll +hwndHRE +0x0004 ;ES_MULTILINE Gui, Show,, The Text Filter,, The Text Filter - Level %n% ( Base %blc% Lines ) RE := GetTomDoc(HRE) ;ControlGet, cid, hwnd,, Edit2, A 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 ControlGetText, Hays, RICHEDIT50W1, A If not (fromButtonRefresh and SubStr(Hays, 1, 19) = "Assorted Matches:`t(") GuiControl,, RICHEDIT50W1, % Haystack%n% ;GuiControl,, Edit2, % Haystack%n% fromButtonRefresh := False ControlGetText, Hays, RICHEDIT50W1, A StringReplace, Hays, Hays, `r`n, `n, All ;for RichEdit ControlGetText, sPat, Edit1, A If StrLen(sPat) { Gosub, MakerFnm If SubStr(r, 0) = "|" r := SubStr(r, 1, StrLen(r)-1) 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) mlen := StrLen(nm), RE.Range(mpos - 1, mpos + mlen - 1).Font.BackColor := 0x00FFFF, npos := mpos 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: StrReplace(Haystack%n%, "`n",, blc), blc += StrLen(Haystack%n%) and SubStr(Haystack%n%, 0) != "`n" ? 1 : 0 WinSetTitle, The Text Filter,, The Text Filter - Level %n% ( Base %blc% Lines ) 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: regWwrap := Wwrap() Needle%n% := Fpat() Gui, tf:Destroy Gosub, theGui ControlSetText, Edit1, % Needle%n%, A Send, {End} ;SendMessage, 0xB1, cp:=StrLen(Needle%n%), cp,, ahk_id %hEdit1% ;EM_SETSEL 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 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 ;SendMessage, 0xB1, 0, StrLen(Needle%pn%),, ahk_id %hEdit1% ;EM_SETSEL } } CommitLevel = 0 Sleep, 500 Progress, Off }Else Haystack%n% := theHaystack Goto, RenewGui 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: fromButtonRefresh := True 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 { Gosub, RenewGui ControlSetText, Edit1, % Needle%n% Send, ^a ;SendMessage, 0xB1, 0, StrLen(Needle%n%),, ahk_id %hEdit1% ;EM_SETSEL 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 tfGuiEscape: tfGuiClose: ExitApp 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 ;GuiControlGet, 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 { r .= xx ? pb "*?" xx st : 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 r .= xx ? pb "*?" xx st : st, xx := A_Space, rr := 0 Else If (c = "'") flush(r, xx, pb, yb), r .= "\W" Else If (c = "\") 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) flush(r, xx, pb, yb), r .= c Else If RegExMatch(cc, "\w") skip_w := skip_w ? skip_w : True, flush(r, xx, pb, yb) Else skip_c++, flush(r, xx, pb, yb), r .= c cc Else xx .= c mpos++ If (mpos > StrLen(t)) ;exceeded { If rr r .= xx ? pb "*?" xx st : st, rr := xx := "" Break } } }Else r := t ;msgbox % t "`n`n" r Return r } flush(ByRef r, ByRef xx, pb, ByRef yb) { r .= xx ? pb "*?" xx pb "*?" : (yb ? (pb "+?", 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 ;ControlFocus, Edit2, A #If, WinActive("The Text Filter") and FocusedControl() = "RICHEDIT50W1" ;"Edit2" Tab::ControlFocus, Edit1, A ~Space::PgDn ~+Space::PgUp ~s::Home ~e::End ~t::^Home ~b::^End `:: ~Enter:: ControlGetText, Hays, RICHEDIT50W1, A ;ControlGetText, Hays, Edit2, A slcs := RE.Selection.Start, slce := RE.Selection.End ;DllCall("User32\SendMessage", "Ptr", cid, "UInt", 0x00B0, "UIntP", slcs, "UIntP", slce, "Ptr") 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 := RegExReplace((mpos > pmax ? SubStr(Hays, slcs) : SubStr(Hays, slcs, mpos - slcs)), "^\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 ;ControlGet, sPat, Selected,, Edit2, A r := StrLen(sPat) ? (regCase ? "i)" : "") (regWhole ? "\b" : "") escrx(sPat) (regWhole ? "\b" : "") : "" } If StrLen(r) { If SubStr(r, 0) = "|" r := SubStr(r, 1, StrLen(r)-1) ControlGettext, Hays, RICHEDIT50W1, A ;ControlGettext, Hays, Edit2, A StringReplace, Hays, Hays, `r`n, `n, All ;for RichEdit If RegExMatch(Hays, r) { StartHere: Gosub, Compute_cp If RegExMatch(A_ThisHotkey, "WheelUp|\+f") { Gosub, ReverseWay mpos -= 1 }Else mpos := RegExMatch(Hays, r, nm, cp) - 1 If mpos >= 0 { cp := mpos + StrLen(nm) RE.Range(mpos, cp).Select ;SendMessage, 0xB1, mpos, cp,, ahk_id %hEdit2% ;EM_SETSEL ;SendMessage, 0xB7, 0, 0,, ahk_id %hEdit2% ;EM_SCROLLCARET }Else If (mpos < 0) and not RegExMatch(A_ThisHotkey, "WheelUp|\+f") { RE.Range(0, 0).Select ;SendMessage, 0xB1, 0, 0,, ahk_id %hEdit2% ;EM_SETSEL ;Send, ^{Home} Goto, StartHere } }Else MsgBox, Target Not Found } Return MakerFnm: sPat := tw4sh(sPat), r := (regCase ? "i" : "") "m`a)" Loop, Parse, sPat, % A_Space If SubStr(A_LoopField, 1, 1) != "-" r .= "(" (regWhole ? "\b" : "") A_LoopField (regWhole ? "\b" : "") ")|" Return Compute_cp: slcs := RE.Selection.Start, slce := RE.Selection.End, slcs++, slce++ ;DllCall("User32\SendMessage", "Ptr", cid, "UInt", 0x00B0, "UIntP", slcs, "UIntP", slce, "Ptr"), slcs++, slce++ cp := RegExMatch(A_ThisHotkey, "WheelUp|\+f") ? 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 #IfWinActive, The Text Filter F1:: ControlGetText, Hays, RICHEDIT50W1, A ;ControlGetText, Hays, Edit2, A If SubStr(Hays, 1, 17) = "H e l p _ P a g e" ControlSetText, RICHEDIT50W1, %B4Help%, A ;ControlSetText, Edit2, %B4Help%, A Else { B4Help := Hays IfExist, tfHelp.rtf { RE.New If ComObjCreate("WScript.Shell").Exec("cmd.exe /c copy/b/v/y tfHelp.rtf tfWork.rtf").StdOut.ReadAll() RE.Open("tfWork.rtf", 0x01, 0) } Else ControlSetText, RICHEDIT50W1, %HelpPage%, A ;ControlSetText, Edit2, %HelpPage%, A } Return ~Wheelup:: ~Wheeldown:: MouseGetPos,,,, moc If not StrLen(moc) or not InStr("Edit1|RICHEDIT50W1", moc) ;InStr("Edit1|Edit2", moc) { ControlFocus, RICHEDIT50W1, A ;ControlFocus, Edit2, A Goto, NextMatch }Else Return !a:: ControlGetText, Hays, RICHEDIT50W1, A ;ControlGetText, Hays, Edit2, A If SubStr(Hays, 1, 19) = "Assorted Matches:`t(" { If SubStr(Hays, 20, 12) = "Alphabetical" ControlSetText, RICHEDIT50W1, %AssHays%, A ;ControlSetText, Edit2, %AssHays%, A Else ControlSetText, RICHEDIT50W1, %AAssHays%, A ;ControlSetText, Edit2, %AAssHays%, A 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 If SubStr(r, 0) = "|" r := SubStr(r, 1, StrLen(r)-1) 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 := AssHays := "", umNoSort := [] For k, v in UniqMatches UniqHays .= rn StrRepeat(A_Space, 3) A_Index ".`t" k, AssHays .= rn A_Index ". " AssHays%v%, umNoSort[v] ? umNoSort[v].Insert(k) : umNoSort[v] := k AAssHays := "Assorted Matches:`t(Alphabetical Order)" UniqHays rn StrRepeat("-", 50) AssHays UniqHays := AssHays := "" For k, v in umNoSort UniqHays .= rn StrRepeat(A_Space, 3) k ".`t" v, AssHays .= rn A_Index ". " AssHays%k% AssHays := "Assorted Matches:`t(Chronological Order)" UniqHays rn StrRepeat("-", 50) AssHays StringReplace, AssHays, AssHays, `r`n, `n, All ;for RichEdit StringReplace, AAssHays, AAssHays, `r`n, `n, All ;for RichEdit ControlSetText, RICHEDIT50W1, %AssHays%, A ;ControlSetText, Edit2, %AssHays%, A } Progress, Off 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 #IfWinActive
Re: Text Filter
Scintilla is much faster then RichEdit, but for very large files still to slow moreover, even compiled/optimized binary (SciTE4Autohotkey) is not fast enough in such cases. That's why I'm marking only the visible text.
@SundayProgrammer: If you can do the same, RichEdit would be real time too!
@SundayProgrammer: If you can do the same, RichEdit would be real time too!
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
that's a good idea. but my lazy take would be skipping it when the search result is still too big. coz i think people will further narrow it down, as it probably still far from pinpointing what they're looking for. let's say make it at 100 kilobytes. under that, do highlighting. over that, skip highlighting.rommmcek wrote: ↑01 Apr 2021, 13:15Scintilla is much faster then RichEdit, but for very large files still to slow moreover, even compiled/optimized binary (SciTE4Autohotkey) is not fast enough in such cases. That's why I'm marking only the visible text.
@SundayProgrammer: If you can do the same, RichEdit would be real time too!
okay.
i ended up taking richedit not because of its speed (as i didn't know which one is actually faster), but its size, as no extra library is needed. and it's not too hard for me to understand how it works. and its speed is acceptable, to me at least.
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
as an afterthought, i've changed the lazy plan a little bit. now, the default behavior is to highlight no more than a thousand matches (which can improve the response time when too many matches are found.) but it can be overrode 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 one second or longer. therefore, highlighting will cover the whole thing even if the total number of matches is over one thousand. this long-press-to-override is not a toggle, it's just a one time thing, so do it every time you want more than the default.SundayProgrammer wrote: ↑01 Apr 2021, 14:52that's a good idea. but my lazy take would be skipping it when the search result is still too big. coz i think people will further narrow it down, as it probably still far from pinpointing what they're looking for. let's say make it at 100 kilobytes. under that, do highlighting. over that, skip highlighting.rommmcek wrote: ↑01 Apr 2021, 13:15Scintilla is much faster then RichEdit, but for very large files still to slow moreover, even compiled/optimized binary (SciTE4Autohotkey) is not fast enough in such cases. That's why I'm marking only the visible text.
@SundayProgrammer: If you can do the same, RichEdit would be real time too!
okay.
tfWork.rtf will now be deleted at guiclose if it exists.
the script is updated.
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
made some adjustments.
1, highlighting after word wrap toggling wasn't done automatically, and now got fixed.
2. highlighting after alt+a wasn't done automatically, and now got fixed.
3. indentation for line numbering got improvement.
the script is updated.
1, highlighting after word wrap toggling wasn't done automatically, and now got fixed.
2. highlighting after alt+a wasn't done automatically, and now got fixed.
3. indentation for line numbering got improvement.
the script is updated.
Re: Text Filter
Thank you for the updates.
Some remarks if I may.
- In the help, I don't see anything about the long press for example. I know that maintaining a help file is not your strong side (like you said )
- Is there any way/possibility to be informed when a new help file is available within the app? Because now I download the file every time that a new version of the script is available
- Is it possible to have a scroll bar in the dialog? Because I have a #MaxHotkeysPerInterval error
- An idea for improving the help so that you don't need to use an external file. If it's possible to integrate it into a dialogue; the use of markdown syntax. But I don't know if AH can use the markdown syntax
- Maybe an ini file so that we can change the default check of the options without having to change the main script. Maybe also in this file having the possibility to change the font of the text box
Sorry for all of these remarks
I still LOVE your script
Some remarks if I may.
- In the help, I don't see anything about the long press for example. I know that maintaining a help file is not your strong side (like you said )
- Is there any way/possibility to be informed when a new help file is available within the app? Because now I download the file every time that a new version of the script is available
- Is it possible to have a scroll bar in the dialog? Because I have a #MaxHotkeysPerInterval error
- An idea for improving the help so that you don't need to use an external file. If it's possible to integrate it into a dialogue; the use of markdown syntax. But I don't know if AH can use the markdown syntax
- Maybe an ini file so that we can change the default check of the options without having to change the main script. Maybe also in this file having the possibility to change the font of the text box
Sorry for all of these remarks
I still LOVE your script
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
thank you for your input. they are all valuable indeed. like, i can't think of any suggestions that you made before and not being implemented. that should reflect their weight, i suppose.ozzii wrote: ↑03 Apr 2021, 03:44Thank you for the updates.
Some remarks if I may.
- In the help, I don't see anything about the long press for example. I know that maintaining a help file is not your strong side (like you said )
- Is there any way/possibility to be informed when a new help file is available within the app? Because now I download the file every time that a new version of the script is available
- Is it possible to have a scroll bar in the dialog? Because I have a #MaxHotkeysPerInterval error
- An idea for improving the help so that you don't need to use an external file. If it's possible to integrate it into a dialogue; the use of markdown syntax. But I don't know if AH can use the markdown syntax
- Maybe an ini file so that we can change the default check of the options without having to change the main script. Maybe also in this file having the possibility to change the font of the text box
Sorry for all of these remarks
I still LOVE your script
i can do coding or debugging for many hours continuously, but every time i do documentation i got tired very quickly. i think it's because it's not interesting nor challenging by nature, even though i completely agree that it's very vital to do so.
i can feel your frustration from the workload in updating the script at your end as a user. i understand that it's quite inconvenient. i would probably feel the same in putting on your shoes.
will keep all your suggestions in my list and have them done the soonest possible. however, i keep on having new ideas these days which made me busy enough unfortunately. (or maybe "fortunately" in other perspective.) anyway, just keep going.
for the "...dialog...error" problem, could you further describe it? i don't think i got what's it all about yet.
thank you again, and wish you a happy easter holiday!
Re: Text Filter
I sympathize.SundayProgrammer wrote: but every time i do documentation i got tired very quickly
But remembering all the possibilities/shortcuts of your script is a real PITA because you've done so much work and your script has so many features.
I think that a simple text with enumeration will work. Like a copy/past of your text when you add a feature and put it in the post.
In that way, we can't miss a shortcut.
But it's your call, like always, because you are maintaining the script.
I will say fortunately for you and thank you for keeping my suggestions in mind (even if all/some/none are/not implemented).SundayProgrammer wrote: will keep all your suggestions in my list and have them done the soonest possible. however, i keep on having new ideas these days which made me busy enough unfortunately. (or maybe "fortunately" in other perspective.) anyway, just keep going.
Well, maybe another script is interfering with yours. I will do some more test.SundayProgrammer wrote: for the "...dialog...error" problem, could you further describe it? i don't think i got what's it all about yet.
No, thank you... And happy Easter holiday to you too.SundayProgrammer wrote: thank you again, and wish you a happy easter holiday!
-
- Posts: 143
- Joined: 25 Dec 2020, 12:26
Re: Text Filter
the script is updated.
1, from now on, the tfHelp.rtf file is no longer needed. the script can automatically produce one whenever needed.
2, i have summarized the releases from the old posts and made a brief change log and gave each major update a version name. and put it in the original post → viewtopic.php?p=374710&sid=149731e72968a7efb4ca0bffb9b63757#p374710 ← click this link
3, there is a version name next to the window title from now on.
that's it for now.
1, from now on, the tfHelp.rtf file is no longer needed. the script can automatically produce one whenever needed.
2, i have summarized the releases from the old posts and made a brief change log and gave each major update a version name. and put it in the original post → viewtopic.php?p=374710&sid=149731e72968a7efb4ca0bffb9b63757#p374710 ← click this link
3, there is a version name next to the window title from now on.
that's it for now.
Re: Text Filter
SundayProgrammer wrote: 1, from now on, the tfHelp.rtf file is no longer needed. the script can automatically produce one whenever needed.
SundayProgrammer wrote: 2, i have summarized the releases from the old posts and made a brief change log and gave each major update a version name. and put it in the original post → viewtopic.php?p=374710&sid=149731e72968a7efb4ca0bffb9b63757#p374710 ← click this link
Return to “Scripts and Functions (v1)”
Who is online
Users browsing this forum: EIijah_2cm and 77 guests