Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

TillaGoto - Go to functions, labels & hks in your script


  • Please log in to reply
135 replies to this topic
fincs
  • Moderators
  • 1662 posts
  • Last active:
  • Joined: 05 May 2007
I don't know what I'm doing wrong, but if I have two files:

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

HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008
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)

My complete version: (Note it uses AnimateWindow)
/* 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#[email protected]\$\?\[\]]+:[[: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#[email protected]\$\?\[\]]+(?=\(.*?\)\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#[email protected]\$\?\[\]]", "", pos + 1)
        If i
            StringLeft, linetext, linetext, i - 1
        
        ;Trim before the first illegal character
        i := RegExMatch(StringReverse(linetext), "[^a-zA-Z0-9#[email protected]\$\?\[\]]", "", 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 [email protected] 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 [email protected] 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 [email protected] 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 [email protected] 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)
}


TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007

I don't know what I'm doing wrong, but if I have two files:

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

Whoops, I don't think I set it up for middleclicking yet...
External functions will only show up in the GUI.
I gtg right now, but I'll look into it later.

TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007

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)


Thanks!
You're right, I forgot to fix up the editor path for labels and hotkeys (I was only testing with functions!).
And I'll also add the fix for bQuickMode

TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007
New release:

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

About the line history feature:

[*: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



fincs
  • Moderators
  • 1662 posts
  • Last active:
  • Joined: 05 May 2007
Great! I'm now testing it :)

EDIT: I've found yet another bug :(
If you have the "Append the name of the file to the functions/labels/hotkeys name"
feature enabled you can't access the functions/labels/hotkeys of the current
script via middleclick.

TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007
:shock: Thanks fincs! That was a huge bug lol. I fixed it! :D

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



fincs
  • Moderators
  • 1662 posts
  • Last active:
  • Joined: 05 May 2007
:D

TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007
After tinkering with SciTE, I realized something important. I added a notice for SciTE users on the main post:

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.



HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008
It works, thank you very much, this script is so useful :D

I suggest to remove cutting off .ahk, I do not use an extention for my #include scripts as they are not stand alone:
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
    }
}


TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007
New release:

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



philou
  • Members
  • 68 posts
  • Last active: Jan 04 2011 01:12 PM
  • Joined: 26 Jul 2006
truly awesome. thanks for your work!

TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007

truly awesome. thanks for your work!

Thanks! I'm glad you like it! :D

HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008
I think that should be 1 because else my subdirs are not considered:

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
}



TheGood
  • Members
  • 589 posts
  • Last active: Mar 22 2014 03:22 PM
  • Joined: 30 Jul 2007

I think that should be 1 because else my subdirs are not considered

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 don't understand how the modification you made should fix it. AbsolutePath() has to return the absolute path of the given script (in case the user wants to open the file).

Edit: I see, do you mean relative paths such as "..\..\myscript.ahk" ?

Edit2:

HotKeyIt, can you replace the AbsolutePath() function with the following and tell me if it works? It relies on APIs now, which should be much more reliable. I'll push it through in the next release.

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
}