HugoV wrote:
Thanks for posting, I can use this from time to time.
Enjoy! And feel free to tweak the resulting codes, since I'm sure there's a more intuitive/friendly way to deal with unicode characters. I only picked the HTML style for consistency and immediate accessibility via any web browser.
edit:]
Code:
;<<<<<<<<<<<<<<< [VxE]'s Hyperactive Goto >>>>>>>>>>>>
;
; Discretely links itself to an editor window. When the user needs
; to quickly jump to a label, function, gui block, or a comment,
; HyGo displays a treeview, which the user can navigate, then double
; click on the desired item, and the script will make the editor window
; jump to the desired item.
;
; Note: "Edit1" MUST be the editor's primary control for its text.
; Flow Map:
; 1 set script settings
; 2 Initialize constants
; 3 build gui 1 ( the 'hot spot' )
; 4 Wait until an editor window is active
; 5 Position and then show gui 1
; 6 If the current editor window becomes inactive, hide gui 1 and goto step 4
; ---
; 7 A WM_MouseMove message triggers step 8
; 8 Build gui 2, then show and activate gui 2
; 9 wait until gui 2 is no longer active, then destroy gui 2
; ---
; 10 gui 2's treeview triggers step 11 when double-clicked
; 11 if the Treeview item has a line number remembered, scroll the editor to that line
Gosub, HyGo_Initialize_Script_Settings ; --- Step 1
Gosub, HyGo_Initialize_Constants ; --- Step 2
Gosub, HyGo_Build_Gui_1 ; --- Step 3
Loop
{
HyGo_Recycle := 1
HyGo_Active_Editor_Window := WinWaitActive( 9, "Editor_Window" ) ; --- Step 4
ControlGet, Edit, HWND,, Edit1
Gui, 1:Default
Gui, Show, % "Hide " HyGo_Gui_Docking( HyGo_Active_Editor_Window, 1 ) ; --- Step 5
DllCall("AnimateWindow", "UInt", 1Gui_Hwnd, "Int", 600, "UInt", 0x80000)
While HyGo_Recycle
Sleep 20
}
Return
HyGo_Initialize_Constants: ; --- Step 2
Gui_Name = Hyper Goto
Gui_Width = 220
Gui_Height = 0.86 Rel
Gui_Font = Lucidia Sans Unicode
Gui_Font_Size = 9
Gui_Title_Color = 80A040
Gui_Font_Color = E0E040
Gui_BGColor = Black
Editor_Window1 = Ahk_Class Notepad
Editor_Window2 = Ahk_Class tednpad
; Editor_Window3; Editor_Window4; Editor_Window5; Editor_Window6
; Editor_Window7; Editor_Window8; Editor_Window9
HyGo_Docking_Screen_Or_Window = Window
HyGo_Docking_Left_Center_Right = Left
HyGo_Docking_Top_Center_Bottom = Center
HyGo_Docking_Inside_Outside = Outside
Return
HyGo_Build_And_Show_Gui_2: ; --- Step 8
DllCall("AnimateWindow", "UInt", 1Gui_Hwnd, "Int", 50, "UInt", 0x90000)
Gosub, HyGo_Build_Gui_2
Gui, Show, % "Hide " HyGo_Gui_Docking( HyGo_Active_Editor_Window, 2 )
DllCall("AnimateWindow", "UInt", 2Gui_Hwnd, "Int", 300, "UInt", HyGo_Gui_Anim("Show") )
WinActivate
WinWaitActive
Gosub, HyGo_Expand_Treeview_To_Selection
WinWaitNotActive
DllCall("AnimateWindow", "UInt", 2Gui_Hwnd, "Int", 300, "UInt", HyGo_Gui_Anim("Hide") )
Gui, 2:Destroy ; --- Step 9
HyGo_Gui_2_Is_Shown := HyGo_Recycle := 0
Return
HyGo_Scroll_Editor_Window_To_The_Line: ; --- Step 11
IfNotEqual, A_GuiEvent, DoubleClick, Return
If ( zH := HyGo_Memory_%A_EventInfo% )
{
ControlSend,, {Left}{Right}, Ahk_ID %HyGo_Active_Editor_Window%
Edit_ScrollToLine( Edit, zH - 2, "Ahk_ID " HyGo_Active_Editor_Window )
}
Return
HyGo_Initialize_Script_Settings: ; --- Step 1
#Persistent
#SingleInstance, Force
SetWinDelay, -1
SetBatchLines, -1
HyGo_Gui_2_Is_Shown := 0
OnMessage(0x200, "WM_MOUSEMOVE")
Return
2GuiClose:
WinActivate, Ahk_ID %HyGo_Active_Editor_Window%
return
HyGo_Expand_Treeview_To_Selection:
If ( zW := InStr( HyGo_List_Of_Items "`n", "`n" . SelectedText . "`n" ) )
{
zH := InStr( SubStr( HyGo_List_Of_Items, 1, zW-1 ), "`n", 0, 0 )
zH := SubStr( HyGo_List_Of_Items, zH+1, zW - zH - 1 )
Tv_Modify( zH, "Vis" )
return
}
ControlGet, CurrentLine, CurrentLine,,, Ahk_ID %Edit%
If ( zW := HyGo_History_%CurrentLine% )
Tv_Modify( zW, "Vis" )
Return
HyGo_Build_Gui_1: ; --- Step 3
Gui, 1:Default
Gui, +AlwaysOnTop +LastFound +ToolWindow -Caption
1Gui_HWND := WinExist()
Gui, Color, %Gui_BGColor%
Gui, Font, % "S" Round( Gui_Font_Size * 1.7 ) " C" Gui_Title_Color, Comic Sans MS
Gui, Font,, %Gui_Font%
Gui, Margin, 0, 0
Gui, Add, Text, x3 y5 w0 h0 section, ; Section Anchor
If ( Gui_IsVertical := ( HyGo_Docking_Left_Center_Right != "Center" ) )
Loop, Parse, Gui_Name
If Asc(A_LoopField) > 64 && Asc(A_LoopField) < 91
Gui, Add, Text, xs, %A_LoopField%
Else Gui, Add, Text, % "xs+" Round(Gui_Font_Size/5), %A_LoopField%
Else Loop, Parse, Gui_Name
Gui, Add, text, % "ys x+" Round(Gui_Font_Size/5), %Gui_Name%
Gui, Margin, 3, 5
Gui, Show, +NoActivate Hide, HyGo Hotspot
WinGetPos,,, 1Gui_Width, 1Gui_Height
WinSet, Region, 0-0 W%1Gui_Width% H%1Gui_Height% R12-12
If HyGo_Docking_Left_Center_Right != Center
HyGo_Gui_Anim( (HyGo_Docking_Left_Center_Right = "Right")
= ( HyGo_Docking_Inside_Outside = "Inside") ? "Left" : "Right" )
If HyGo_Docking_Top_Center_Bottom != Center
HyGo_Gui_Anim( HyGo_Docking_Top_Center_Bottom = "Top" ? "Up" : "Down" )
If ( HyGo_Docking_Top_Center_Bottom = HyGo_Docking_Left_Center_Right )
HyGo_Gui_Anim("Center")
HyGo_Gui_Anim("Slide")
Return
HyGo_Build_Gui_2:
Gui, 3:+LastFound
Gui, 3:Margin, 1, 1
Gui, 3:Add, Text, % HyGo_Gui_Docking( HyGo_Active_Editor_Window, "" )
Gui, 3:Show, Hide
WinGetPos,,, zW, zH
2Gui_Width += zW := 2Gui_Width - zW
2Gui_Height += zH := 2Gui_Height - zH
Gui, 3:Destroy
Gui, 2:Default
Gui, +LastFound +Owner1
2Gui_Hwnd := WinExist()
Gui, Margin, 1, 1
Gui, Font, C%Gui_Font_Color% S%Gui_Font_Size%, Comic Sans MS
Gui, Font,, %Gui_Font%
Gui, Add, TreeView,
( LTrim Join`s
W%2Gui_Width%
H%2Gui_Height%
BackGround%Gui_BGColor%
C%Gui_Font_Color%
GHyGo_Scroll_Editor_Window_To_The_Line
)
2Gui_Width -= zW
2Gui_Height -= zH
ControlGetText, Ed_text,, Ahk_ID %Edit%
ControlGet, TotalLines, LineCount,,, Ahk_ID %Edit%
ControlGet, SelectedText, Selected,,, Ahk_ID %Edit%
Tv_Hotkeys := TV_Add( "Hotkeys" )
Tv_Functions := TV_Add( "Functions" )
Tv_Subroutines := TV_Add( "Subroutines" )
TV_Goto_Gosub := TV_Add( "Goto & Gosub" )
TV_Timers := TV_Add( "Timers" )
BlockComment := 0
Loop, Parse, HyGo_List_Of_Items, `n
{
If A_LoopField is INTEGER
VarSetCapacity( HyGo_Memory_%A_LoopField%, 0)
}
HyGo_List_Of_Items := ""
Loop, Parse, Ed_text, `n, `r
{
line = %A_LoopField%
If line = */
BlockComment := 0
If ( BlockComment += line = "/*" )
Continue
If InStr( line, ";" ) && Pos := RegexMatch( " " . line, "\s;" )
StringLeft, line, line, Pos - 1
line = %line%
If ( InStr( line, "Gosub" ) || InStr( line, "Goto" ) )
&& RegexMatch( line, "go(to|sub)[\s,]\s*\K.*$", zH )
{
If !InStr( HyGo_List_Of_Items "`n", "`nGo " zH "`n" )
{
StringReplace, zH, zH, %A_Space%, _
HyGo_%zH% := TV_Add( zH, TV_Goto_Gosub )
}
zW := HyGo_%zH%
zW := TV_Add( zH, zW )
HyGo_Memory_%zW% := A_Index
HyGo_History_%A_Index% := zW
HyGo_List_Of_Items .= "`n" zW "`n" zH
}
If InStr( line, "SetTimer" ) && RegexMatch( line, "SetTimer[\s,]\s*\K.*$", zH )
{
StringReplace, zH, zH, `,, %A_Space%every
If ErrorLevel
zH .= " every 250"
zH .= "ms"
zW := TV_Add( zH, TV_Timers )
HyGo_Memory_%zW% := A_Index
HyGo_History_%A_Index% := zW
HyGo_List_Of_Items .= "`n" zW "`n" zH
}
If InStr( line, ":" ) && 1 = RegexMatch( line, "[^\s,]+:$" )
{
zW := TV_Add( zH := SubStr( line, 1, -1 ), Tv_Subroutines )
HyGo_Memory_%zW% := A_Index
HyGo_History_%A_Index% := zW
HyGo_List_Of_Items .= "`n" zW "`n" zH
}
If InStr( line, "::" ) && 1 = RegexMatch( line, "[^\s]+( up)?::$" )
{
zW := TV_Add( zH := SubStr( line, 1, InStr( line, "::" ) - 1 ), Tv_Hotkeys )
HyGo_Memory_%zW% := A_Index
HyGo_History_%A_Index% := zW
HyGo_List_Of_Items .= "`n" zW "`n" zH
}
If InStr( line, "Hotkey" ) && 1 = RegexMatch( line, "Hotkey[\s\,]\s*(.*)\,(.*)[\,$](.*)", z )
If z2 NOT IN on,off,toggle,alttab
If z1 NOT IN ifwinactive,ifwinexist
If !InStr( HyGo_List_Of_Items "`n", "`n" z1 "::Goto " z2 "`n" )
{
zW := TV_Add( zH := z1 "::Goto " z2 , Tv_Hotkeys )
HyGo_Memory_%zW% := A_Index
HyGo_History_%A_Index% := zW
HyGo_List_Of_Items .= "`n" zW "`n" zH
}
If ( PendingFunction ) && line != ""
If InStr( line, "{" ) = 1
{
zW := TV_Add( PendingFunction, Tv_Functions )
HyGo_Memory_%zW% := zH
HyGo_History_%zH% := zW
HyGo_List_Of_Items .= "`n" zW "`n" PendingFunction
PendingFunction := ""
}
Else PendingFunction := ""
If InStr( line, "(" ) && !InStr( line, "If(" ) && !InStr( line, "while(" )
&& 1 = RegexMatch( line, "[^\s]+\(.*\)", zW )
If InStr( line, "{" ) > StrLen( zW )
{
zW := TV_Add( zH := SubStr( line, 1, InStr( line, "(" ) - 1 ), Tv_Functions )
HyGo_Memory_%zW% := A_Index
HyGo_History_%A_Index% := zW
HyGo_List_Of_Items .= "`n" zW "`n" zH
}
Else
PendingFunction := SubStr( line, 1, InStr( line, "(" ) - 1 ), zH := A_Index
If !Mod(A_Index-1, 17)
Tooltip % Round( 100 * A_Index / TotalLines, 2 ) "%", 19, 3
}
Tooltip
Tv_Modify( Tv_Hotkeys, "Sort" )
Tv_Modify( Tv_Functions, "Sort" )
Tv_Modify( Tv_Subroutines, "Sort" )
Tv_Modify( TV_Goto_Gosub, "Sort" )
Tv_Modify( TV_Timers, "Sort" )
Return
; Sets a timer, so as to start the subroutine in a new thread, and
; sets a flag, so as not to set the timer more than once per event.
WM_MOUSEMOVE(wparam, lparam, msg, hwnd)
{
Global HyGo_Gui_2_Is_Shown
If ( A_Gui = 1 && HyGo_Gui_2_Is_Shown = 0 )
{
SetTimer, HyGo_Build_And_Show_Gui_2, -10
HyGo_Gui_2_Is_Shown := 1
}
}
; Internal function for use with a DllCall to "AnimateWindow". Stores preferred modes
; and intelligently inverts the directions for showing and hiding. This makes it easy for
; a gui window to 'roll out' and 'roll in' in opposite directions (away from, then towards
; the same imaginary line or point ).
HyGo_Gui_Anim( Mode )
{
Static AnimCode:=0, UpDown:=0, LeftRight:=0, Center:=0
If Mode = Show
return 0x20000 + AnimCode + UpDown + LeftRight + Center
If Mode = Hide
return 0x10000 + AnimCode + (LeftRight>0) * (3-LeftRight)
+ (UpDown > 0) * (12-UpDown) + Center
If Mode = Slide
AnimCode ^= 0x40000
Else If Mode = Blend
AnimCode ^= 0x80000
Else If Mode = Center
Center ^= 16, LeftRight *= !Center, UpDown *= !Center
Else If Mode = Up
UpDown := 4
Else If Mode = Down
UpDown := 8
Else If Mode = Left
LeftRight := 2
Else If Mode = Right
LeftRight := 1
Return AnimCode + UpDown + LeftRight + Center
}
; Internal function for positioning guis relative to either the screen or a window
HyGo_Gui_Docking( HWND, GuiN )
{
Global HyGo_Docking_Screen_Or_Window
, HyGo_Docking_Left_Center_Right
, HyGo_Docking_Top_Center_Bottom
, HyGo_Docking_Inside_Outside
, Gui_Width, Gui_Height
, 1Gui_Width, 1Gui_Height
, 2Gui_Width, 2Gui_Height
WinGetPos, BoxLeft, BoxTop, BoxRight, BoxBottom, Ahk_ID %HWND%
If InStr( HyGo_Docking_Screen_Or_Window, "Screen" ) = 1
{
StringTrimLeft, MonCount, HyGo_Docking_Screen_Or_Window, 6
MonCount = %MonCount%
If MonCount is NOT INTEGER
{
SysGet, MonCount, 80
WinMidX := BoxLeft + BoxRight / 2
WinMidY := BoxTop + BoxBottom / 2
Loop, % MonCount
{
SysGet, Box, Monitor, %A_Index%
If ( BoxLeft <= WinMidX && WinMidX <= BoxRight )
&& ( BoxTop <= WinMidY && WinMidY <= BoxBottom )
Break
}
}
}
Else BoxRight += BoxLeft, BoxBottom += BoxTop
; Now, we have our box that shares one edge with our gui window
; we'll next figure out the X and Y of our gui's top left corner
; If the gui is to be docked inside, then the docking edge will be the
; same as the gui's edge, otherwise, they will be opposite
If HyGo_Docking_Inside_Outside NOT IN outside,inside
{
WinGet, MinMax, MinMax, Ahk_ID %HWND%
HyGo_Docking_Inside_Outside := MonCount || MinMax = 1 ? "Inside" : "Outside"
}
If !GuiN
{
GuiW := Gui_Width
GuiH := Gui_Height
If InStr( Gui_Width, "R" )
Loop, Parse, Gui_Width, %A_Tab% `,
If ( A_LoopField + 1 )
GuiW := Round( A_LoopField * ( BoxRight - BoxLeft ) )
If InStr( Gui_Height, "R" )
Loop, Parse, Gui_Height, %A_Tab% `,
If ( A_LoopField + 1 )
GuiH := Round( A_LoopField * ( BoxBottom - BoxTop ) )
return "W" (2Gui_Width := GuiW) " H" (2Gui_Height := GuiH)
}
If HyGo_Docking_Inside_Outside = Outside
{
If HyGo_Docking_Left_Center_Right = Right
GuiX := BoxRight
Else If HyGo_Docking_Left_Center_Right = Left
GuiX := BoxLeft - %GuiN%Gui_Width
Else GuiX := Round( BoxLeft / 2 + BoxRight / 2 - %GuiN%Gui_Width / 2 )
If HyGo_Docking_Top_Center_Bottom = Bottom
GuiY := BoxBottom
Else If HyGo_Docking_Top_Center_Bottom = Top
GuiY := BoxTop - %GuiN%Gui_Height
Else GuiY := Round( BoxTop / 2 + BoxBottom / 2 - %GuiN%Gui_Height / 2 )
} Else {
If HyGo_Docking_Left_Center_Right = Right
GuiX := BoxRight - %GuiN%Gui_Width
Else If HyGo_Docking_Left_Center_Right = Left
GuiX := BoxLeft
Else GuiX := Round( BoxLeft / 2 + BoxRight / 2 - %GuiN%Gui_Width / 2 )
If HyGo_Docking_Top_Center_Bottom = Bottom
GuiY := BoxBottom - %GuiN%Gui_Height
Else If HyGo_Docking_Top_Center_Bottom = Top
GuiY := BoxTop
Else GuiY := Round( BoxTop / 2 + BoxBottom / 2 - %GuiN%Gui_Height / 2 )
If ( HyGo_Docking_Left_Center_Right = "Left" ) && GuiN = 1
GuiX -= %GuiN%Gui_Width // 3
If ( HyGo_Docking_Left_Center_Right = "Right" ) && GuiN = 1
GuiX -= %GuiN%Gui_Width
If ( HyGo_Docking_Top_Center_Bottom = "Top" )
&& ( HyGo_Docking_Left_Center_Right != "Center" ) && GuiN = 1
GuiY += 53
}
return " X" GuiX " Y" GuiY
}
WinWaitActive( ArrayLength = 1, WinTitleArray="", WinTextArray="", ExTitleArray="", ExTextArray="" )
{
Local FoundWinHWND, Suffix:=1
While !FoundWinHWND := WinActive( %WinTitleArray%%Suffix%, %WinTextArray%%Suffix%
, %ExTitleArray%%Suffix%, %ExTextArray%%Suffix% )
{
Suffix := ArrayLength > 1 ? 1 + Mod( Suffix, ArrayLength ) : Suffix ? "" : 1
Sleep 20
}
return FoundWinHWND
}
; Excerpt from [VxE]'s Edit control manipulation library. This function causes
; the indicated edit control to scroll until the indicated line is the topmost visible
; line of the edit control. If LineNum is not a number, it will scroll to the caret's line
Edit_ScrollToLine( EditNNorHWND="Edit1", LineNum="Caret", Title="", Text="", ExTitle="", ExText="" )
{
If EditNNorHWND is NOT INTEGER
ControlGet, EditNNorHWND, HWND,, %EditNNorHWND%
, %Title%, %Text%, %ExTitle%, %ExText%
ExText := !Floor( LineNum += 1 )
SendMessage, 277, 6 + ExText, 0,, Ahk_ID %EditNNorHWND%
SendMessage, 182 + ExText, 0, !ExText * LineNum,, Ahk_ID %EditNNorHWND%
return LineNum
}