scr1.ahk
#Include %A_ScriptDir%\scr2.ahk cc()
scr2.ahk
cc(){ msgbox }
and I change the following line of TillaGoto:
iIncludeMode := 0x11100111
I middle-click on the line cc() and it doesn't take me to the function...
#Include %A_ScriptDir%\scr2.ahk cc()
cc(){ msgbox }
iIncludeMode := 0x11100111
;Check if it's external label If sLabels%i%_File { ;It's external. Check if it's Notepad++ or SciTE If RegExMatch(sEditorPath, "i)scite\.exe$") s := """-open:%f"" -goto:%l" Else If RegExMatch(sEditorPath, "i)notepad\+\+\.exe$") s := "-n%l ""%f""" ;s := sRunFile ;Replace parameters StringReplace s, s, @%l, % sLabels%i%_Line StringReplace s, s, @%f, % GetFile(sLabels%i%_File, True) StringReplace s, s, \,\\,All s = "%sEditorPath%" %s% ;Shell it Run %s% ...
;Get the process path sEditorPath := GetProcessPath(hNPP)
/* TheGood TillaGoto - Go to functions and labels in your script */ ;______________________________________ ;CONFIGURATION ;Appearance iGUIWidth := 300 ;Specify the width of the GUI. iGUIHeight := 40 ;Specify, in number of rows, the height of the listbox. iMargin := 2 ;Specify the width of the GUI's margins. iTransparency := 255 ;Specify the transparency of the GUI. Preferably divisible by 15. Put 255 for no ;transparency at all (consumes less resources). Put 0 to disable fade-in effect. bPosLeft := True ;Set to True to position the GUI on the left side instead of the right side. ;Behaviour bEffectOpen = SD ;CENTER=C, BLEND=B, SLIDE=S (HOR_POSITIVE=L || HOR_NEGATIVE=R || VER_POSITIVE=D || VER_NEGATIVE=U) bEffectTimeOpen := 100 ;Time for the effect when showing GUI bEffectClose = SU ;Same as for EffectOpten, for example SU or C or B bEffectTimeClose := 50 ;Time for the effect when closing Gui bFilterComments := True ;Set to True to filter out the functions/labels/hotkeys found in comments. ;Note: this feature greatly reduces performance in large scripts. Therefore, if ;you start experiencing lag, you might want to turn it off (at the expense of ;not filtering out functions/labels/hotkeys found in comments). ;Warning: if turned off, functions must not have comments between the closing ;parenthesis of the declaration and the opening curly bracket. Similarly, labels ;must not have comments on the same line. bQuickMode := True ;Set to True to make TillaGoto go straight to showing the GUI and exit on close. uHotkey := "F1" ;Specify the hotkey you want to use to call up the GUI bMatchEverywhere := True ;Set to False for matching to occur only at the beginning of the label/function ;name. Set to True for matching to occur anywhere in the label/function name. As ;well, multiple words can be specified. For example, typing "Dog Cat" will match ;any label/function containing those words anywhere in their name. This is useful ;to search for functions (or labels) only by typing "() FunctionName". ;Mouse configuration bUseMButton := False ;Set to True to enable the middle mouse button as a hotkey to call up the GUI. ;More importantly, this also allows you to go to a function/label simply by ;pressing the middle mouse button on the function/label name. ;Set to False to disable it. iCancelWait := 300 ;Specify in milliseconds the amount of time the middle mouse button should be ;depressed while the GUI is showing for the GUI to close without selection. ;If the middle mouse button is pressed for any amount shorter than that, the ;selection is validated. ;Include files scanning feature iIncludeMode := 0x01111111 ;This setting affects the behaviour of TillaGoto when scanning for script ;labels, functions and hotkeys in #Include files and library files. To turn ;off the feature completely, specify 0. Otherwise, iIncludeMode can be any ;combination of the following values: ;0x00000001 - Scan #Include files ;0x00000010 - Scan library directories files ;0x00000100 - Retrieve functions upon scanning ;0x00001000 - Retrieve labels upon scanning ;0x00010000 - Retrieve hotkeys upon scanning ;0x00100000 - Filter comments upon scanning (similar to bFilterComments) ;0x01000000 - Recurse (ie. include #Include files of #Include files and so on) ;0x10000000 - Append the name of the file to the functions/labels/hotkeys name sPathMatching := "\*?.*(?= - (Notepad\+\+|SciTE4AutoHotkey))" ;Regular expression which should match the ;path of the currently edited file. Necessary only if iIncludeMode <> 0. ;Window matching configuration sActiveWindow := "SciTE4AutoHotkey" ;Regular expression which should match the window ;of the editor containing the Scintilla control. It is preconfigured for ;Notepad++ and SciTE4AutoHotkey. sScintillaClass := "Scintilla" ;Class name of the Scintilla control. Exclude instance number. ;______________________________________ ;DO NOT CHANGE ANYTHING BELOW THIS LINE #Include %A_ScriptDir%\RemoteBuf.ahk #EscapeChar @ #SingleInstance Force SetTitleMatchMode, RegEx ;Create GUI Gui, +AlwaysOnTop +Border +ToolWindow +LastFound -Caption Gui, Font, s8, Courier New Gui, Margin, %iMargin%, %iMargin% Gui, Add, Edit, w%iGUIWidth% h20 vtxtSearch gtxtSearch_Event hwndhtxtsearch, Gui, Add, ListBox, Sort wp r%iGUIHeight% vlblList glblList_Event hwndhlblList +HScroll, hGui := WinExist() ;Get scrollbar width SysGet, SM_CXVSCROLL, 2 ;Catch WM_INPUT, WM_KEYDOWN and WM_MOUSEWHEEL OnMessage(255, "GUIInteract") OnMessage(256, "GUIInteract") OnMessage(522, "GUIInteract") ;Register the mouse with RIDEV_INPUTSINK HID_Register(1, 2, hGui, 0x00000100) ;Check if we're in quick mode If bQuickMode { ;Check if Notepad++ is active hNPP := WinActive(sActiveWindow) ;Check if it's SciTE4AutoHotkey's toolbar (thanks HotKeyIt) If Not hNPP And WinActive("AHKToolbar4SciTE") { hNPP := WinExist(sActiveWindow) WinActivate, ahk_id %hNPP% } Else If Not hNPP ExitApp ;Get the process path sEditorPath := GetProcessPath(hNPP) bExitOnClose := True Gosub SummonGUI } Else bExitOnClose := False ;Main monitoring loop Loop { Sleep, 200 ;Check if Notepad++ is active h := WinActive(sActiveWindow) ;Skip the loop if Notepad++ is not active If Not h And Not WinActive("ahk_id " hGui) { ;Turn off hotkeys Hotkey, %uHotkey%, SummonGUI, Off ;Hide GUI if showing If bShowing Gosub, GuiEscape hNPP := 0 ;Reset value Continue ;Check if we just found a new window } Else If (h <> hNPP) And Not WinActive("ahk_id " hGui) { ;Remember the newfound Notepad++ window and script hNPP := h ;Get the process path sEditorPath := GetProcessPath(hNPP) ;Turn on hotkeys Hotkey, %uHotkey%, SummonGUI, On } } ;------------\ ;GUI related | ;------------/ ;User summoned the GUI SummonGUI: ;Switch thread to full speed SetBatchLines, -1 ;Check if we're already showing If bShowing { If bWheeled Goto SelectItem bWheeled := True ;So that if the user presses the hotkey again, ;the first item selected will be validated ControlFocus,, ahk_id %htxtSearch% Return } ;Get handle to focused control ControlGetFocus, cSci, ahk_id %hNPP% ;Check if it fits the class name If InStr(cSci, sScintillaClass) ControlGet, hSci, Hwnd,, %cSci%, ahk_id %hNPP% Else Return ;Get the filename WinGetActiveTitle, t RegExMatch(t, sPathMatching, sScriptPath) Gosub, AnalyseScript ;Check if we're doing CheckOnClick If bCheckClick { bCheckClick := False If CheckTextClick(clickX, clickY) Return } ;Check if text is selected s := Sci_GetSelText(hSci) If (s <> "") And Not InStr(s, "@n") { ;Copy the selected text in the textbox GuiControl,, txtSearch, %s% ;Create a list based on sel CreateList(s) ;Check if it's just one match. If so, go to it. LB_GETCOUNT. SendMessage, 395, 0, 0,, ahk_id %hlblList% If (ErrorLevel = 1) Goto SelectItem ;Select all. EM_SETSEL SendMessage, 177, 0, -1,, ahk_id %htxtSearch% } Else { ;Otherwise, empty the textbox and show the whole list GuiControl,, txtSearch, CreateList() } ControlFocus,, ahk_id %htxtSearch% ;Get window info WinGetPos, iX, iY,,, ahk_id %hNPP% ControlGetPos, sX, sY, sW, sH, %cSci%, ahk_id %hNPP% iX += sX + (Not bPosLeft ? sW - (iGUIWidth + (iMargin * 2)) - SM_CXVSCROLL - 2 : 2) iY += sY + 2 Gui, Show, w0 h0 WinSet, Transparent, 0, ahk_id %hGui% Gui, Show, AutoSize x%iX% y%iY% bShowing := True AnimateWindow(hGui,bEffectTimeOpen,"A" . bEffectOpen) If Not iTransparency Or (iTransparency = 255) ;Turn off if opaque WinSet, Transparent, OFF, ahk_id %hGui% Else WinSet, Transparent, %iTransparency%, ahk_id %hGui% WinActivate, ahk_id %hGui% ControlFocus,, ahk_id %htxtSearch% Return GuiEscape: bShowing := False bWheeled := False AnimateWindow(hGui,bEffectTimeClose,"H". bEffectClose) Gui, Show, w0 h0 Gui,Cancel Gui,Hide If bExitOnClose ExitApp EmptyMem() Return AnimateWindow(hwnd,time,options){ local H:=0x10000, A:=0x20000,C:=0x10, B:= 0x80000,S:=0x40000,R:= 0x1, L:=0x2, D:=0x4, U:=0x8,O:="HACBSLURD",opt:="",Format:="" opt := 0x0 + 0 Loop,parse,Options If InStr(O,A_LoopField) opt |= %A_LoopField% If opt DllCall("AnimateWindow", "UInt", hwnd, "Int", time, "UInt", opt) WinSet,Redraw,,ahk_id %hwnd% } ;Incremental searching txtSearch_Event: If bShowing { GuiControlGet, s,, txtSearch CreateList(s) } Return lblList_Event: If (A_GuiEvent <> "DoubleClick") Return SelectItem: ;Get selected item index. LB_GETCURSEL SendMessage, 0x188, 0, 0,, ahk_id %hlblList% s := GetListBoxItem(hlblList, ErrorLevel) ;Get type and index bIsFunc := RegExMatch(s, "\(\)( -.*)?$") i := GetIndex(s, bIsFunc) If bIsFunc { ;Check if it's external If sFuncs%i%_File { ;It's external. Check if it's Notepad++ or SciTE If RegExMatch(sEditorPath, "i)scite\.exe$") s := """-open:%f"" -goto:%l" Else If RegExMatch(sEditorPath, "i)notepad\+\+\.exe$") s := "-n%l ""%f""" ;Prep the parameters StringReplace s, s, @%l, % sFuncs%i%_Line t := GetFile(sFuncs%i%_File, True) ;Check if backslash is necessary (for SciTE) If RegExMatch(sEditorPath, "i)scite\.exe$") StringReplace t, t, \, \\, All StringReplace s, s, @%f, %t% s = "%sEditorPath%" %s% ;Shell it and get out Run %s% } Else ShowLine(sFuncs%i%_Line) } Else { ;Check if it's external label If sLabels%i%_File { ;It's external. Check if it's Notepad++ or SciTE If RegExMatch(sEditorPath, "i)scite\.exe$") s := """-open:%f"" -goto:%l" Else If RegExMatch(sEditorPath, "i)notepad\+\+\.exe$") s := "-n%l ""%f""" ;s := sRunFile ;Replace parameters StringReplace s, s, @%l, % sLabels%i%_Line StringReplace s, s, @%f, % GetFile(sLabels%i%_File, True) StringReplace s, s, \,\\,All s = "%sEditorPath%" %s% ;Shell it Run %s% } Else ShowLine(sLabels%i%_Line) } Goto GuiEscape ;Done Return GetIndex(sSearch, bIsFunc) { Global If bIsFunc { Loop %sFuncs0% If (sFuncs%A_Index% = sSearch) Return A_Index } Else { Loop %sLabels0% If (sLabels%A_Index% = sSearch) Return A_Index } Return 0 } GUIInteract(wParam, lParam, msg, hwnd) { Local iCount, flags, bDown, bUp, sControl, cX, cY Static bIgnoreUp := False Critical ;Check which message it is If (msg = 256) { ;WM_KEYDOWN IfEqual wParam, 13, Gosub SelectItem ;Enter ;Check if it's the textbox If (hwnd = htxtSearch) { If (wParam = 38) { ControlFocus,, ahk_id %hlblList% If Not WrapSel(True) SendInput {Up} } Else If (wParam = 40) { ControlFocus,, ahk_id %hlblList% If Not WrapSel(False) SendInput {Down} } } Else If (hwnd = hlblList) { ;Make up/down wrap around If (wParam = 38) Or (wParam = 40) Return WrapSel(wParam = 38) ? True : "" } } Else If (msg = 522) And (hwnd = htxtSearch) { ;WM_MOUSEWHEEL bWheeled := True ;Sign it if needed wParam := wParam > 0x7FFFFFFF ? -(~wParam) - 1 : wParam ;Get notches turned wParam := (wParam >> 16) / 120 If (wParam > 0) { Loop % Abs(wParam) { ;% If Not WrapSel(True) ControlSend,, {Up}, ahk_id %hlblList% } } Else { Loop % Abs(wParam) { ;% If Not WrapSel(False) ControlSend,, {Down}, ahk_id %hlblList% } } } Else If (msg = 255) { ;WM_INPUT ;Get flags flags := HID_GetInputInfo(lParam, 20 | 0x0100) If (flags = -1) ;Check if we got an error Return ;Check if middle mouse button is down/up bDown := flags & 0x0010 bUp := flags & 0x0020 ;To save time for most cases this branch will be executed If Not (bDown Or bUp) Return If bDown And bShowing { bIgnoreUp := True SetTimer, GuiEscape, -%iCancelWait% } Else If bUp And bShowing Gosub SelectItem Else If bUp And bUseMButton And Not bIgnoreUp And WinActive(sActiveWindow) { ;Get mouse data MouseGetPos, clickX, clickY,, sControl If InStr(sControl, sScintillaClass) { ControlGet, hSci, Hwnd,, %sControl%, ahk_id %hNPP% ControlGetPos, cX, cY,,, %sControl%, ahk_id %hNPP% clickX -= cX, clickY -= cY bCheckClick := True } Critical Off Gosub SummonGUI } If bUp And bIgnoreUp bIgnoreUp := False } } WrapSel(bUp) { Local iCount, iSel ;Get selected item index and count. LB_GETCOUNT. LB_GETCURSEL. SendMessage, 395, 0, 0,, ahk_id %hlblList% iCount := ErrorLevel SendMessage, 392, 0, 0,, ahk_id %hlblList% iSel := ErrorLevel ;Select the first/last item. LB_SETCURSEL If bUp And (iSel = 0) { SendMessage 390, iCount - 1, 0,, ahk_id %hlblList% Return 1 } Else If Not bUp And (iSel = iCount - 1) { SendMessage 390, 0, 0,, ahk_id %hlblList% Return 1 } Return 0 } ;-------------------\ ;Scanning Functions | ;-------------------/ ;Retrieves labels and functions of the script AnalyseScript: ;Reset counters sLabels0 := 0 sFuncs0 := 0 ;Get full text sScript := Sci_GetText(hSci) ;Ban comments if necessary If bFilterComments FilterComments(sScript) ;Get labels and functions GetScriptLabels(sScript) GetScriptHotkeys(sScript) GetScriptFunctions(sScript) ;Check if we're doing #Include files If (iIncludeMode & 0x00000001) { ;Get the script's dir and set the default include path to it StringLeft sScriptDir, sScriptPath, InStr(sScriptPath, "\", False, 0) - 1 SetWorkingDir, %sScriptDir% ;Loop through each #Include file i := 1 Loop { ;Get the next include directive i := RegExMatch(sScript, "im)^[[:blank:]]*#Include([[:blank:]]+i\*)?[[:blank:]]+\K.*?(?=\r)", t, i) ;Make sure we've got something If Not i Break ;Replace path variables StringReplace t, t, % "%A_ScriptDir%", %sScriptDir% StringReplace t, t, % "%A_AppData%", %A_AppData% StringReplace t, t, % "%A_AppDataCommon%", %A_AppDataCommon% ;Check if it's a directory or file s := FileExist(t) If InStr(s, "D") ;It's a folder. Change working directory SetWorkingDir, %t% Else If s { ;It's a file ScanScriptFile(t, iIncludeMode & 0x01000000) SetWorkingDir, %sScriptDir% ;Put the working dir's path back to here } ;Start at next line i := InStr(sScript, "@n", False, i) + 1 } } ;Check if we're also scanning library functions If (iIncludeMode & 0x00000010) { Loop, %A_MyDocuments%\AutoHotkey\Lib\*.ahk, 1, 1 ScanScriptFile(A_LoopFileLongPath, iIncludeMode & 0x01000000, bFuncsOnly) ;Get path of running AutoHotkey StringLeft sLibPattern, A_AhkPath, InStr(A_AhkPath, "\", False, 0) sLibPattern .= "Lib\*.ahk" Loop, %sLibPattern%, 1, 1 ScanScriptFile(A_LoopFileLongPath, iIncludeMode & 0x01000000, bFuncsOnly) } Return ScanScriptFile(sPath, bRecurse = False, bFuncsOnly = False) { Local sFile, s, i, sInclude, sScriptDir ;Make sure it's not the same as the script If (sPath = sScriptPath) Return ;Load file FileRead, sFile, %sPath% ;Remove comments if necessary If (iIncludeMode & 0x00100000) FilterComments(sFile, True) ;Get the script's dir and set the default include path to it StringLeft sScriptDir, sPath, InStr(sPath, "\", False, 0) - 1 SetWorkingDir, %sScriptDir% sPaths0 += 1 sPaths%sPaths0% := A_WorkingDir (StrLen(sScriptDir) <> 2 ? "\" : "") SubStr(sPath, StrLen(sScriptDir) + 1) ;Scan for stuff If (iIncludeMode & 0x00000100) GetScriptFunctions(sFile, True) If Not bFuncsOnly { If (iIncludeMode & 0x00001000) GetScriptLabels(sFile, True) If (iIncludeMode & 0x00010000) GetScriptHotkeys(sFile, True) } ;Check if we're recursing If bRecurse { ;Loop through each #Include file i := 1 Loop { ;Get the next include directive i := RegExMatch(sFile, "im)^[[:blank:]]*#Include([[:blank:]]+i\*)?[[:blank:]]+\K.*?(?=\r)" , sInclude, i) ;Make sure we've got something If Not i Break ;Replace path variables StringReplace sInclude, sInclude, % "%A_ScriptDir%", %sScriptDir% StringReplace sInclude, sInclude, % "%A_AppData%", %A_AppData% StringReplace sInclude, sInclude, % "%A_AppDataCommon%", %A_AppDataCommon% ;Check if it's a directory or file s := FileExist(sInclude) If InStr(s, "D") ;It's a folder. Change working directory SetWorkingDir, %sInclude% Else If s { ;It's a file ScanScriptFile(sInclude, bRecurse) SetWorkingDir, %sScriptDir% ;Put the working dir's path back to here } ;Start at next line i := InStr(sFile, "@n", False, i) + 1 } } } ;This sub analyses the script and add the labels in it to the array GetScriptLabels(ByRef s, bMarkInclude = False) { Local i, t, u ;Get the current file we're working on If bMarkInclude u := " -" GetFile(sPaths0) ;Reset counter i := 1 Loop { ;Get next label i := RegExMatch(s, "m)^[[:blank:]]*\K[a-zA-Z0-9#_@\$\?\[\]]+:[[:blank:]]*$", t, i) ;Make sure we found something If Not i Break ;We found a label. Trim everything after the last colon StringLeft t, t, InStr(t, ":", False, 0) sLabels0 += 1 ;Increase counter If bMarkInclude { sLabels%sLabels0%_File := sPaths0 sLabels%sLabels0%_Line := LineFromPosEx(s, i) If (iIncludeMode & 0x10000000) t .= u } Else { sLabels%sLabels0%_File := 0 sLabels%sLabels0%_Line := LineFromPos(i) } sLabels%sLabels0% := t ;Add to array ;Set i to the beginning of the next line i := InStr(s, "@n", False, i) + 1 If (i = 1) Break } } ;This sub analyses the script and add the hotkeys in it to the array (uses the same array as labels) GetScriptHotkeys(ByRef s, bMarkInclude = False) { Local i, t, u ;Get the current file we're working on If bMarkInclude u := " -" GetFile(sPaths0) i := 1 Loop { ;Get next hotkey i := RegExMatch(s, "m)^[[:blank:]]*\K[[:blank:]a-zA-Z0-9\Q#!^+&<>*~$`-=\[]';/\.,\E]+::", t, i) ;Make sure we found something If Not i Break ;We found a hotkey. sLabels0 += 1 ;Increase counter If bMarkInclude { sLabels%sLabels0%_File := sPaths0 sLabels%sLabels0%_Line := LineFromPosEx(s, i) If (iIncludeMode & 0x10000000) t .= u } Else { sLabels%sLabels0%_File := 0 sLabels%sLabels0%_Line := LineFromPos(i) } sLabels%sLabels0% := t ;Add to array ;Set i to the beginning of the next line i := InStr(s, "@n", False, i) + 1 If (i = 1) Break } } ;This sub analyses the script and add the functions in it to the array GetScriptFunctions(ByRef s, bMarkInclude = False) { Local i, t, u ;Get the current file we're working on If bMarkInclude u := " -" GetFile(sPaths0) ;Loop through the functions i := 1 Loop { ;Get the next function i := RegExMatch(s, "m)^[[:blank:]]*\K[a-zA-Z0-9#_@\$\?\[\]]+(?=\(.*?\)\s*?\{)", t, i) ;Check if we found something If Not i Break ;Make sure it's a valid function If t Not In If,While { ;Increment counter sFuncs0 += 1 t .= "()" If bMarkInclude { sFuncs%sFuncs0%_File := sPaths0 sFuncs%sFuncs0%_Line := LineFromPosEx(s, i) If (iIncludeMode & 0x10000000) t .= u } Else { sFuncs%sFuncs0%_File := 0 sFuncs%sFuncs0%_Line := LineFromPos(i) } sFuncs%sFuncs0% := t } ;Get the next function i := InStr(s, "@n", False, i) + 1 If (i = 1) Break } } FilterComments(ByRef s, bRespectLines = False) { Local i, j, len, sCommentFlag, blank i := 1 Loop { ;Get next block start i := RegExMatch(s, "m)^[[:blank:]]*/\*", "", i) If Not i Break ;Get end of block, starting search at next line j := InStr(s, "@n", False, i) + 1 j := RegExMatch(s, "Pm)^[[:blank:]]*\*/", len, j) ;Make sure there's an end of block If Not j len := StrLen(s) - i Else len += (j - i) VarSetCapacity(blank, len, 32) ;Check if we need to respect line numbers If bRespectLines { ;Get number of lines that would be erased l1 := LineFromPosEx(s, i) l2 := LineFromPosEx(s, j) Loop % (l2 - l1) ;% NumPut(0x0D0A, blank, (A_Index - 1) * 2, "UShort") } ;Blank out DllCall("RtlMoveMemory", UInt, &s + i - 1, UInt, &blank, UInt, len) If Not j Break Else i += len } ;Get the comment flag used i := RegExMatch(s, "im)^[[:blank:]]*#CommentFlag\K.*?(?=\r)", sCommentFlag) If Not i sCommentFlag := ";" Else sCommentFlag = %sCommentFlag% ;Trim ;Check if the very first line is a comment If (SubStr(s, 1, StrLen(sCommentFlag)) = sCommentFlag) { len := InStr(s, "@r") - 1 VarSetCapacity(blank, len, 32) DllCall("RtlMoveMemory", UInt, &s, UInt, &blank, UInt, len) } i := 1 Loop { ;Get next comment i := RegExMatch(s, "iP)[[:blank:]\n]\K\Q" sCommentFlag "\E.*?(?=\r)", len, i) ;Check if we found anything If Not i Break ;Blank out comment VarSetCapacity(blank, len, 32) DllCall("RtlMoveMemory", UInt, &s + (i - 1), UInt, &blank, UInt, len) i += len + 2 } } ;------------------\ ;ListBox Functions | ;------------------/ CreateList(filter = "") { Global sLabels0, sFuncs0, bMatchEverywhere, hlblList ;Clear GuiControl,, lblList,| ;Disable redraw GuiControl, -Redraw, lblList ;Autotrim filter = %filter% If (filter = "") { ;Split cases for speed Loop %sLabels0% GuiControl,, lblList, % sLabels%A_Index% Loop %sFuncs0% GuiControl,, lblList, % sFuncs%A_Index% } Else { ;Split cases for speed If bMatchEverywhere { ;Parse words StringSplit, words, filter, %A_Space% ;Split cases for speed If (words0 > 1) { Loop %sLabels0% { bMatch := True i := A_Index Loop %words0% { bMatch := bMatch And InStr(sLabels%i%, words%A_Index%) If Not bMatch Break } If bMatch GuiControl,, lblList, % sLabels%A_Index% } Loop %sFuncs0% { bMatch := True i := A_Index Loop %words0% { bMatch := bMatch And InStr(sFuncs%i%, words%A_Index%) If Not bMatch Break } If bMatch GuiControl,, lblList, % sFuncs%A_Index% } ;It's one word } Else { Loop %sLabels0% If InStr(sLabels%A_Index%, filter) GuiControl,, lblList, % sLabels%A_Index% Loop %sFuncs0% If InStr(sFuncs%A_Index%, filter) GuiControl,, lblList, % sFuncs%A_Index% } } Else { Loop %sLabels0% If (InStr(sLabels%A_Index%, filter) = 1) GuiControl,, lblList, % sLabels%A_Index% Loop %sFuncs0% If (InStr(sFuncs%A_Index%, filter) = 1) GuiControl,, lblList, % sFuncs%A_Index% } } ;Add hscrollbar if necessary ListBoxAdjustHSB(hlblList) ;Select the first item. LB_SETCURSEL SendMessage 390, 0, 0,, ahk_id %hlblList% ;Redraw GuiControl, +Redraw, lblList } GetFile(i, bWholePath = False) { Local s If bWholePath Return sPaths%i% Else { s := SubStr(sPaths%i%, InStr(sPaths%i%, "\", False, 0) + 1) StringTrimRight s, s, 4 ;Remove ".ahk" Return s } } ListBoxAdjustHSB(hLB) { ;Declare variables (for clarity's sake) dwExtent := 0 dwMaxExtent := 0 hDCListBox := 0 hFontOld := 0 hFontNew := 0 VarSetCapacity(lptm, 53) ;Use GetDC to retrieve handle to the display context for the list box and store it in hDCListBox hDCListBox := DllCall("GetDC", "Uint", hLB) ;Send the list box a WM_GETFONT message to retrieve the handle to the ;font that the list box is using, and store this handle in hFontNew SendMessage 49, 0, 0,, ahk_id %hLB% hFontNew := ErrorLevel ;Use SelectObject to select the font into the display context. ;Retain the return value from the SelectObject call in hFontOld hFontOld := DllCall("SelectObject", "Uint", hDCListBox, "Uint", hFontNew) ;Call GetTextMetrics to get additional information about the font being used ;(eg. to get tmAveCharWidth's value) DllCall("GetTextMetrics", "Uint", hDCListBox, "Uint", &lptm) tmAveCharWidth := NumGet(lptm, 20) ;Get item count using LB_GETCOUNT SendMessage 395, 0, 0,, ahk_id %hLB% ;Loop through the items Loop %ErrorLevel% { ;Get list box item text s := GetListBoxItem(hLB, A_Index - 1) ;For each string, the value of the extent to be used is calculated as follows: DllCall("GetTextExtentPoint32", "Uint", hDCListBox, "str", s, "int", StrLen(s), "int64P", nSize) dwExtent := (nSize & 0xFFFFFFFF) + tmAveCharWidth ;Keep if it's the highest to date If (dwExtent > dwMaxExtent) dwMaxExtent := dwExtent } ;After all the extents have been calculated, select the old font back into hDCListBox and then release it: DllCall("SelectObject", "Uint", hDCListBox, "Uint", hFontOld) DllCall("ReleaseDC", "Uint", hLB, "Uint", hDCListBox) ;Adjust the horizontal bar using LB_SETHORIZONTALEXTENT SendMessage 404, dwMaxExtent, 0,, ahk_id %hLB% } GetListBoxItem(hLB, i) { ;Get length of item. 394 = LB_GETTEXTLEN SendMessage 394, %i%, 0,, ahk_id %hLB% ;Check for error If (ErrorLevel = 0xFFFFFFFF) Return "" ;Prepare variable VarSetCapacity(sText, ErrorLevel, 0) ;Retrieve item. 393 = LB_GETTEXT SendMessage 393, %i%, &sText,, ahk_id %hLB% ;Check for error If (ErrorLevel = 0xFFFFFFFF) Return "" ;Done Return sText } ;--------------------\ ;Scintilla Functions | ;--------------------/ Sci_GetText(hSci) { ;Used constants SCI_GETLENGTH := 2006 SCI_GETTEXT := 2182 ;Retrieve text length SendMessage SCI_GETLENGTH, 0, 0,, ahk_id %hSci% iLength := ErrorLevel ;Open remote buffer (add 1 for 0 at the end of the string) RemoteBuf_Open(hBuf, hSci, iLength + 1) ;Fill buffer with text SendMessage SCI_GETTEXT, iLength + 1, RemoteBuf_Get(hBuf),, ahk_id %hSci% ;Read buffer VarSetCapacity(sText, iLength) RemoteBuf_Read(hBuf, sText, iLength + 1) ;We're done with the remote buffer RemoteBuf_Close(hBuf) Return sText } Sci_GetSelText(hSci) { ;Used constants SCI_GETSELTEXT := 2161 ;Get length SendMessage SCI_GETSELTEXT, 0, 0,, ahk_id %hSci% iLength := ErrorLevel ;Check if it's none If (iLength = 1) Return "" ;Open remote buffer RemoteBuf_Open(hBuf, hSci, iLength) ;Fill buffer SendMessage, SCI_GETSELTEXT, 0, RemoteBuf_Get(hBuf),, ahk_id %hSci% ;Prep var VarSetCapacity(sText, iLength) RemoteBuf_Read(hBuf, sText, iLength) ;Done RemoteBuf_Close(hBuf) Return sText } Sci_GetLineText(hSci, iLine) { ;Used constants SCI_GETLINE := 2153 SCI_LINELENGTH := 2350 ;Retrieve line length SendMessage SCI_LINELENGTH, iLine, 0,, ahk_id %hSci% iLength := ErrorLevel ;Open remote buffer (add 1 for 0 at the end of the string) RemoteBuf_Open(hBuf, hSci, iLength + 1) ;Fill buffer with text SendMessage SCI_GETLINE, iLine, RemoteBuf_Get(hBuf),, ahk_id %hSci% ;Read buffer VarSetCapacity(sText, iLength) RemoteBuf_Read(hBuf, sText, iLength + 1) ;We're done with the remote buffer RemoteBuf_Close(hBuf) ;Trim off ending characters sText := RegExReplace(sText, "\R") Return sText } LineFromPos(pos) { Global ;SCI_LINEFROMPOSITION SendMessage, 2166, pos - 1, 0,, ahk_id %hSci% Return ErrorLevel + 1 } LineFromPosEx(ByRef s, pos) { i := 0, j := 1 Loop { i := InStr(s, "@n", False, i + 1) If (Not i) Or (i >= pos) Break j += 1 } Return j } CheckTextClick(x, y) { Local pos, line, linetext, i ;SCI_POSITIONFROMPOINTCLOSE SendMessage, 2023, x, y,, ahk_id %hSci% pos := ErrorLevel ;Check for error If (pos = -1) Return False Else { ;SCI_LINEFROMPOSITION SendMessage, 2166, pos, 0,, ahk_id %hSci% line := ErrorLevel ;SCI_POSITIONFROMLINE SendMessage, 2167, line, 0,, ahk_id %hSci% pos -= ErrorLevel ;Get line text linetext := Sci_GetLineText(hSci, line) ;Trim after the first illegal character i := RegExMatch(linetext, "[^a-zA-Z0-9#_@\$\?\[\]]", "", pos + 1) If i StringLeft, linetext, linetext, i - 1 ;Trim before the first illegal character i := RegExMatch(StringReverse(linetext), "[^a-zA-Z0-9#_@\$\?\[\]]", "", StrLen(linetext) - pos + 1) If i StringTrimLeft, linetext, linetext, StrLen(linetext) - i + 1 ;Check if it's a clean match linetext .= "()" Loop %sFuncs0% { If (linetext = sFuncs%A_Index%) { ShowLine(sFuncs%A_Index%_Line) Return True } } StringTrimRight, linetext, linetext, 2 linetext .= ":" Loop %sLabels0% { If (linetext = sLabels%A_Index%) { ShowLine(sLabels%A_Index%_Line) Return True } } } Return False } StringReverse(s) { Loop, Parse, s ret := A_LoopField ret Return ret } ShowLine(line) { Global ;Get the first visible line SendMessage, 2152, 0, 0,, ahk_id %hSci% If (ErrorLevel < line - 1) { ;Get the number of lines on screen. SCI_LINESONSCREEN SendMessage, 2370, 0, 0,, ahk_id %hSci% ;Go to the line wanted + lines on screen. SCI_GOTOLINE SendMessage, 2024, line - 1 + ErrorLevel, 0,, ahk_id %hSci% } SendMessage, 2024, line - 1, 0,, ahk_id %hSci% } ;--------------\ ;HID Functions | ;--------------/ HID_Register(UsagePage = False, Usage = False, Handle = False, Flags = 0) { RIDEV_REMOVE := 0x00000001 RIDEV_EXCLUDE := 0x00000010 ;Prep var VarSetCapacity(uDev, 12) ;Check if hwnd needs to be null bNull := (Flags & RIDEV_REMOVE) Or (Flags & RIDEV_EXCLUDE) NumPut(UsagePage, uDev, 0, "UShort") NumPut(Usage, uDev, 2, "UShort") NumPut(Flags, uDev, 4) NumPut(bNull ? 0 : Handle, uDev, 8) ;Call r := DllCall("RegisterRawInputDevices", "UInt", &uDev, "UInt", 1, "UInt", 12) ;Check for error If Not r { MsgBox % "RegisterRawInputDevices call failed.@nReturn value: " r "@nErrorLevel: " ErrorLevel . "@nLine: " A_LineNumber "@nLast Error: " A_LastError ;% Return -1 } Return 0 } HID_GetInputInfo(InputHandle, Flag) { Static uRawInput, iLastHandle := 0 RID_INPUT := 0x10000003 ;Check if it's the same handle If (InputHandle = iLastHandle) ;We can retrieve the data without having to call again Return NumGet(uRawInput, Flag, HID_NumIsShort(Flag) ? (HID_NumIsSigned(Flag) ? "Short" : "UShort") : (HID_NumIsSigned(Flag) ? "Int" : "UInt")) Else { ;We need to get a fresh copy ;Get raw data size r := DllCall("GetRawInputData", "UInt", InputHandle, "UInt" , RID_INPUT, "UInt", 0, "UInt*", iSize, "UInt", 16) If (r = -1) Or ErrorLevel { ;MsgBox % "GetRawInputData call failed.@nReturn value: " r "@nErrorLevel: " ErrorLevel ;. "@nLine: " A_LineNumber "@nLast Error: " A_LastError Return -1 } ;Prep var VarSetCapacity(uRawInput, iSize) ;Get raw data r := DllCall("GetRawInputData", "UInt", InputHandle, "UInt" , RID_INPUT, "UInt", &uRawInput, "UInt*", iSize, "UInt", 16) If (r = -1) Or ErrorLevel { ;MsgBox % "GetRawInputData call failed.@nReturn value: " r "@nErrorLevel: " ErrorLevel ;. "@nLine: " A_LineNumber "@nLast Error: " A_LastError ErrorLevel := -1 ;Set errorlevel to fail Return -1 } Else If (r <> iSize) { ;MsgBox GetRawInputData did not return the correct size.@nSize returned: %r%@nSize allocated: %iSize% ErrorLevel := -1 ;Set errorlevel to fail Return -1 } ;Keep handle reference of current uRawInput iLastHandle := InputHandle ;Retrieve data Return NumGet(uRawInput, Flag, HID_NumIsShort(Flag) ? (HID_NumIsSigned(Flag) ? "Short" : "UShort") : (HID_NumIsSigned(Flag) ? "Int" : "UInt")) } Return 0 } ;Internal use only HID_NumIsShort(ByRef Flag) { If (Flag & 0x0100) { Flag ^= 0x0100 ;Remove it Return True } Return False } ;Internal use only HID_NumIsSigned(ByRef Flag) { If (Flag & 0x1000) { Flag ^= 0x1000 ;Remove it Return True } Return False } ;----------------\ ;Other Functions | ;--------------/ ;Based on Laszlo's code (which in turn is based on Shimanov's code) ;http://www.autohotkey.com/forum/viewtopic.php?p=70690#70690 GetProcessPath(hwnd) { WinGet, PID, PID, ahk_id %hwnd% hProc := DllCall("OpenProcess", UInt, 0x418, Int, 0, UInt, PID) VarSetCapacity(sPath, 255) DllCall("psapi.dll\GetModuleFileNameExA", UInt, hProc, UInt, 0, Str, sPath, UInt, 255) DllCall("CloseHandle", hProc) Return sPath } ;EmptyMem() by heresy ;http://www.autohotkey.com/forum/viewtopic.php?t=32876 EmptyMem(PID="AHK Rocks"){ pid:=(pid="AHK Rocks") ? DllCall("GetCurrentProcessId") : pid h:=DllCall("OpenProcess", "UInt", 0x001F0FFF, "Int", 0, "Int", pid) DllCall("SetProcessWorkingSetSize", "UInt", h, "Int", -1, "Int", -1) DllCall("CloseHandle", "Int", h) }
Whoops, I don't think I set it up for middleclicking yet...I don't know what I'm doing wrong, but if I have two files:
scr1.ahk#Include %A_ScriptDir%\scr2.ahk cc()
scr2.ahkcc(){ msgbox }
and I change the following line of TillaGoto:iIncludeMode := 0x11100111
I middle-click on the line cc() and it doesn't take me to the function...
There is a problem opening external file as parameter %s% is empty for labels and hotkeys.
What is %sRunFile%, it is not used anywhere.
This looks to solve the problem for me:;Check if it's external label If sLabels%i%_File { ;It's external. Check if it's Notepad++ or SciTE If RegExMatch(sEditorPath, "i)scite\.exe$") s := """-open:%f"" -goto:%l" Else If RegExMatch(sEditorPath, "i)notepad\+\+\.exe$") s := "-n%l ""%f""" ;s := sRunFile ;Replace parameters StringReplace s, s, @%l, % sLabels%i%_Line StringReplace s, s, @%f, % GetFile(sLabels%i%_File, True) StringReplace s, s, \,\\,All s = "%sEditorPath%" %s% ;Shell it Run %s% ...
In quick mode it does not work at all because sEditorPath is not initialised. Add this to If bQuickMode:!:;Get the process path sEditorPath := GetProcessPath(hNPP)
About the line history feature:- Fixed sPathMatching (it was missing a closing parenthesis)
- Fixed sEditorPath for Quick Mode (thanks HotKeyIt)
- Added the ability to middle-click on external functions and labels (thanks fincs)
- Fixed external file opening for labels and hotkeys (thanks HotKeyIt!)
- Added a line history feature allowing you to quickly go back and forth between recent jumps (related hotkeys are uGoBack and uGoForward)
[*:26yn12h1] You can go back and forth between the points you recently jumped to by pressing the hotkeys specified in uGoBack and uGoForward (default is Alt+Left and Alt+Right)
[*:26yn12h1] You can also go back and forth between the points you recently jumped to by doing Shift + Mouse wheel
- Fixed AbsolutePath() to be more accurate
- Fixed middleclick not working when appending name of file to external functions (thanks fincs!)
- Changed the external file launching procedure so that the requested line is at the top!
Important note for SciTE/SciTE4AutoHotkey users: the values of check.if.already.open and title.full.path (found in the file SciTEGlobal.properties) must be set to 1 if you wish to use the #Include file scanning feature. In SciTE4AutoHotkey, that is the default value. But not in SciTE.
GetFile(i, bWholePath = False) { Local s If bWholePath Return sPaths%i% Else { s := SubStr(sPaths%i%, InStr(sPaths%i%, "\", False, 0) + 1) ;StringTrimRight s, s, 4 ;Remove ".ahk" Return s } }
- Fixed library files being scanned for things other than functions
- Fixed the possibility of having the same file scanned multiple times
- Fixed file name being trimmed even if it doesn't end with ".ahk" (thanks HotKeyIt)
Thanks! I'm glad you like it!truly awesome. thanks for your work!
AbsolutePath(sPath) {
If DllCall("shlwapi\PathIsRelativeA", "int", &sPath) {
i := InStr(sPath, "\", False, 1)
If Not i
Return A_WorkingDir (SubStr(A_WorkingDir, 0) <> "\" ? "\" : "") sPath
Else Return A_WorkingDir (SubStr(A_WorkingDir, 0) <> "\" ? "\" : "") SubStr(sPath, i + 1)
} Else Return sPath
}
Can you elaborate a bit more on what you mean? Do you mean that the subdirectories of your libraby folders aren't scanned? What is the problem?I think that should be 1 because else my subdirs are not considered
AbsolutePath(sPath) { If DllCall("shlwapi\PathIsRelativeA", "int", &sPath) { VarSetCapacity(sAbs, 260) DllCall("GetFullPathName", "str", sPath, "uint", 260, "str", sAbs, "int", 0) Return sAbs } Else Return sPath }