#AutoIt3Wrapper_Res_Fileversion=1.0.0.1 #AutoIt3Wrapper_Res_FileVersion_AutoIncrement=y #Region ### Program Info ======================================================================### ; Name ..........: Functions Docs ; Purpose .......: Display a function's header for any custom function. Like a personal helpfile. ; Version .......: 1.0.0.0 ; Date ..........: May 5, 2020 ; Modified ......: ; Author/s ......: Seadoggie01 #EndRegion ### Program Info ===================================================================### #Region ### Includes ### ;~ #include #include #include #include #include #include #include #include #EndRegion ### Includes ### #Region ### Global Consts ### ; GUI's min width and height Global Const $__g_MINWIDTH = 750 Global Const $__g_MINHEIGHT = 275 ; Possibly should allow the user to change these. idc rn. Global Const $__g_sDebugLog = @AppDataDir & "\FunctionDocs.log" Global Const $__g_sFunctionDocsConfig = @AppDataDir & "\FunctionDocs.ini" Global Const $__g_sSqlLiteDatabase = @AppDataDir & "\FunctionDocs.dat" Global Const $__g_sSepChar = Chr(5) AutoItSetOption("GUIDataSeparatorChar", $__g_sSepChar) If @error Then Exit #EndRegion ### Global Consts ### #Region ### Global RegEx ### ; Global so I can find these easily :D ; The RegEx used to find UDF headers and first line of function. ; Note: This won't work if a function has a header and the function itself is commented out. ; This was unexpected, but happy coincidenc. Why document a function that isn't available... right? Right? Global Const $__g_sUdfHeaderRegEx = "(?mi)((?:^;.*$\r?\n)+Func.*)" ; RegEx used to split UDF headers into an array like ["Name:", "Value", "Name2", "Value2" ...] Global Const $__g_sUdfSplitterRegEx = "(?mi)^; ([a-z][a-z ()]+?) ?\.*: *((?:;?.*\r?\n)?(?:;\s{2,}.*\r?\n)*)" ; RegEx used to get the function's name (in case the UDF header is non-standard, this always works... I think) Global Const $__g_sUdfFuncNameRegEx = "(?mi)^Func\s*(.*)\(" #EndRegion ### Global RegEx ### #Region ### Globals ### ; The paths to search for AutoIt files Global $__g_aSearchPaths[0] ; The tree view items (Search paths, Files, and Functions) Global $__g_aTreeViewItems[0] ; The function description list view items Global $aIdFuncHeaderItems[0] #EndRegion ### Globals ### #Region ### ToDos ### #ToDo: Show the file the function was pulled from... maybe a combo box? #ToDo: Redirect input to AutoItHelper.exe if not a Personal function #ToDo: Remove old functions/files after search paths are changed #ToDo: Add an About Message #ToDo: Transparent GUI option #ToDo: Low priority: make this an include? #EndRegion ### ToDos ### #Region ### START Koda GUI section ### Form=u:\documents\autoit files\forms\function docs.kxf ; My Personal Koda Instructions: ; * Add 20 px to height after Koda... it doesn't calculate the menu size for some reason. ; * Don't put GUISetState(@SW_SHOW) in... it needs to wait ; * Set the header of the ListView to "Header" & $__g_sSepChar & "Description" Global $idGUI = GUICreate("Function Docs", 727, 355 + 20, 192, 124, BitOR($WS_MAXIMIZEBOX,$WS_MINIMIZEBOX,$WS_SIZEBOX,$WS_THICKFRAME,$WS_SYSMENU,$WS_GROUP,$WS_TABSTOP)) Global $idFileMI = GUICtrlCreateMenu("&File") Global $idSearchMI = GUICtrlCreateMenuItem("Update Func Docs", $idFileMI) Global $idCloseMI = GUICtrlCreateMenuItem("Close", $idFileMI) Global $MenuItem1 = GUICtrlCreateMenu("Options") Global $idWinTopMI = GUICtrlCreateMenuItem("Always On Top", $MenuItem1) Global $idPathsMI = GUICtrlCreateMenu("&Paths") Global $idEditPathsMI = GUICtrlCreateMenuItem("Edit", $idPathsMI) Global $idFuncInput = GUICtrlCreateInput("", 95, 45, 225, 21) GUICtrlSetResizing(-1, $GUI_DOCKLEFT+$GUI_DOCKTOP+$GUI_DOCKWIDTH+$GUI_DOCKHEIGHT) Global $Label1 = GUICtrlCreateLabel("Function Name", 15, 50, 76, 17) GUICtrlSetFont(-1, 9, 400, 0, "MS Sans Serif") GUICtrlSetResizing(-1, $GUI_DOCKLEFT+$GUI_DOCKTOP+$GUI_DOCKWIDTH+$GUI_DOCKHEIGHT) Global $idSearchBttn = GUICtrlCreateButton("Search", 326, 45, 75, 20, $BS_DEFPUSHBUTTON) GUICtrlSetResizing(-1, $GUI_DOCKLEFT+$GUI_DOCKTOP+$GUI_DOCKWIDTH+$GUI_DOCKHEIGHT) Global $Label2 = GUICtrlCreateLabel("Function Documentation", 10, 10, 210, 28) GUICtrlSetFont(-1, 14, 400, 0, "MS Sans Serif") GUICtrlSetResizing(-1, $GUI_DOCKLEFT+$GUI_DOCKTOP+$GUI_DOCKWIDTH+$GUI_DOCKHEIGHT) Global $idFuncHeaderList = GUICtrlCreateListView("Header" & $__g_sSepChar & "Description", 15, 75, 495, 225) GUICtrlSetResizing(-1, $GUI_DOCKLEFT+$GUI_DOCKTOP+$GUI_DOCKBOTTOM) Global $idProgress = GUICtrlCreateProgress(360, 305, 150, 17) GUICtrlSetResizing(-1, $GUI_DOCKLEFT+$GUI_DOCKBOTTOM+$GUI_DOCKWIDTH+$GUI_DOCKHEIGHT) Global $idStatusLabel = GUICtrlCreateLabel("", 15, 305, 341, 17) GUICtrlSetResizing(-1, $GUI_DOCKLEFT+$GUI_DOCKBOTTOM+$GUI_DOCKWIDTH+$GUI_DOCKHEIGHT) GUIStartGroup() Global $Label4 = GUICtrlCreateLabel("Function File List", 535, 15, 176, 17) GUICtrlSetFont(-1, 10, 400, 0, "MS Sans Serif") GUICtrlSetResizing(-1, $GUI_DOCKRIGHT+$GUI_DOCKTOP+$GUI_DOCKHEIGHT) Global $idFileTreeView = GUICtrlCreateTreeView(535, 45, 176, 277) GUICtrlSetResizing(-1, $GUI_DOCKRIGHT+$GUI_DOCKTOP+$GUI_DOCKBOTTOM) GUIStartGroup() #EndRegion ### END Koda GUI section ### __FunctionDocs_Init() ; Use a Pythonic startup system... only run the GUI if the program name is this program, otherwise, we're an include and we can skip everything else. ; -- Can't be used as an include yet... I'm working on making it work first, then also maybe as an include :) If StringInStr(@ScriptName, "FunctionDocs") Then __FunctionDocs_Main() ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name ..........: __FunctionDocs_Init ; Description ...: Enforces a single instance and processes Command line options if needed ; Syntax ........: __FunctionDocs_Init() ; Parameters ....: None ; Return values .: None ; Author ........: Seadoggie01 ; Modified ......: March 30, 2020 (Just comments though) ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func __FunctionDocs_Init() ; If there are command line options If $CmdLine[0] Then ; If there is already an instance running If _Singleton("Seadoggie_FuncDocs", 1) = 0 Then ; Destroy the GUI I just created so I input the data in the other instance GUIDelete($idGUI) ; Activate the other GUI WinActivate("Function Docs", "") ; Perform the search by setting the text ControlSetText("Function Docs", "", $idFuncInput, $CmdLine[1]) ; Give focus to the search button ControlFocus("Function Docs", "", $idSearchBttn) ; And send a space to the control if we can't click on it... never clicks on my computer If Not ControlClick("Funcion Docs", "", $idSearchBttn) Then ControlSend("Function Docs", "", $idSearchBttn, " ") ; Then quit Exit Else ; Make it look like the user actually typed the function in GUICtrlSetData($idFuncInput, $CmdLine[1]) ; Use command line data to search __FunctionDocs_FuncSearch($CmdLine[1]) EndIf EndIf ; Don't show the progress bar GUICtrlSetState($idProgress, $GUI_HIDE) ; Show the GUI GUISetState(@SW_SHOW, $idGUI) GUIRegisterMsg($WM_GETMINMAXINFO, "__WM_GETMINMAXINFO") Local $aDefaultPos = WinGetPos($idGUI) Local $iWinState = IniRead($__g_sFunctionDocsConfig, "GUI", "State", -1) If $iWinState = -1 Then Local $iX = Int(IniRead($__g_sFunctionDocsConfig, "GUI", "X", $aDefaultPos[0])) Local $iY = Int(IniRead($__g_sFunctionDocsConfig, "GUI", "Y", $aDefaultPos[1])) Local $iWidth = Int(IniRead($__g_sFunctionDocsConfig, "GUI", "Width", $aDefaultPos[2])) Local $iHeight = Int(IniRead($__g_sFunctionDocsConfig, "GUI", "Height", $aDefaultPos[3])) WinMove($idGUI, "", $iX, $iY, $iWidth, $iHeight) Else WinSetState($idGUI, "", @SW_MAXIMIZE) EndIf If IniRead($__g_sFunctionDocsConfig, "GUI", "Always On Top", -1) = "True" Then WinSetOnTop($idGUI, "", 1) GUICtrlSetState($idWinTopMI, $GUI_CHECKED) EndIf EndFunc ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name ..........: __FunctionDocs_Main ; Description ...: Manages the FunctionDocs' GUI ; Syntax ........: __FunctionDocs_Main() ; Parameters ....: None ; Return values .: None ; Author ........: Seadoggie01 ; Modified ......: April 20, 2020 ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func __FunctionDocs_Main() ; Load the search paths $__g_aSearchPaths = SearchPaths() LoadTreeView() ; Resize the columns... Sets to widest item width or ; (If it's the last column) the edge of the ListView, which ever is bigger _GUICtrlListView_SetColumnWidth($idFuncHeaderList, 0, $LVSCW_AUTOSIZE_USEHEADER) _GUICtrlListView_SetColumnWidth($idFuncHeaderList, 1, $LVSCW_AUTOSIZE_USEHEADER) Local $vMsg, $iTemp, $iSelected, $sText While True $vMsg = GUIGetMsg() Switch $vMsg Case $idWinTopMI If IniRead($__g_sFunctionDocsConfig, "GUI", "Always On Top", "-1") = "True" Then IniWrite($__g_sFunctionDocsConfig, "GUI", "Always On Top", "False") WinSetOnTop($idGUI, "", 0) GUICtrlSetState($idWinTopMI, $GUI_CHECKED) Else IniWrite($__g_sFunctionDocsConfig, "GUI", "Always On Top", "True") WinSetOnTop($idGUI, "", 1) GUICtrlSetState($idWinTopMI, $GUI_UNCHECKED) EndIf Case $idSearchMI __FunctionDocs_UpdateDocs() Case $idEditPathsMI ; Open the folder list editor to edit the search paths _FolderList_Editor($__g_aSearchPaths, "Function Docs Paths", $idGUI) ; Ignore error, don't care if user cancels If Not @error And ($IDYES = MsgBox($MB_YESNO, "Update Documentation?", "Would you like to update the documentation so searches include these folders?")) Then __FunctionDocs_UpdateDocs() Case $idSearchBttn ; If there is something to search for If GUICtrlRead($idFuncInput) <> "" Then ; Perform the search __FunctionDocs_FuncSearch(GUICtrlRead($idFuncInput)) ; Update the selected item to prevent a double search $iSelected = _GUICtrlTreeView_GetSelection($idFileTreeView) Else Debug("Empty input") EndIf Case $GUI_EVENT_CLOSE, $idCloseMI ExitLoop Case Else $iTemp = _GUICtrlTreeView_GetSelection($idFileTreeView) If $iTemp <> $iSelected and $iTemp <> 0 Then $sText = _GUICtrlTreeView_GetText($idFileTreeView, $iTemp) If Not $sText = "" And Not StringInStr($sText, ".") And Not StringInStr($sText, "\") Then $iSelected = $iTemp __FunctionDocs_FuncSearch($sText, StringReplace(_GUICtrlTreeView_GetTree($idFileTreeView, _GUICtrlTreeView_GetParentHandle($idFileTreeView, $iSelected)), $__g_sSepChar, "\")) EndIf EndIf EndSwitch WEnd ; Save the search paths SearchPaths($__g_aSearchPaths) Local $iWinState = WinGetState($idGUI) If BitAND($iWinState, $WIN_STATE_MAXIMIZED) Then GUISetState(@SW_HIDE) IniWrite($__g_sFunctionDocsConfig, "GUI", "State", $WIN_STATE_MAXIMIZED) Else If BitAND($iWinState, $WIN_STATE_MINIMIZED) Then GUISetState(@SW_RESTORE) ; Get the window's position Local $aPos = WinGetPos($idGUI) GUISetState(@SW_HIDE) IniWrite($__g_sFunctionDocsConfig, "GUI", "State", -1) ; Save the window's position (provided it isn't negative, which means minimized(?) If $aPos[0] >= 0 Then IniWrite($__g_sFunctionDocsConfig, "GUI", "X", $aPos[0]) If $aPos[1] >= 0 Then IniWrite($__g_sFunctionDocsConfig, "GUI", "Y", $aPos[1]) If $aPos[2] >= 0 Then IniWrite($__g_sFunctionDocsConfig, "GUI", "Width", $aPos[2]) If $aPos[3] >= 0 Then IniWrite($__g_sFunctionDocsConfig, "GUI", "Height", $aPos[3]) EndIf GUIDelete($idGUI) EndFunc ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name ..........: __FunctionDocs_UpdateDocs ; Description ...: Processes each of the search paths using __FunctionDocs_ProcessFolder while displaying the path on the GUI ; Syntax ........: __FunctionDocs_UpdateDocs() ; Parameters ....: None ; Return values .: None ; Author ........: Seadoggie01 ; Modified ......: March 30, 2020 ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func __FunctionDocs_UpdateDocs() ; For each folder For $i=0 To UBound($__g_aSearchPaths) - 1 ; Search them for au3 files with functions __FunctionsDoc_ProcessFolder($__g_aSearchPaths[$i]) ErrMsg("__FunctionsDoc_ProcessFolder with " & $__g_aSearchPaths) Next LoadTreeView() GUICtrlSetData($idStatusLabel, "Done") EndFunc ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name ..........: __FunctionsDoc_ProcessFolder ; Description ...: Searches a folder for files and passes files that have been modified to __FunctionDocs_ProcessFile ; Syntax ........: __FunctionsDoc_ProcessFolder($sFolder) ; Parameters ....: $sFolder - a string value. ; Return values .: None ; Author ........: Seadoggie01 ; Modified ......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func __FunctionsDoc_ProcessFolder($sFolder) GUICtrlSetData($idStatusLabel, "Searching: " & $sFolder) ; Append a backslash to the folder if needed If StringRight($sFolder, 1) <> "\" Then $sFolder &= "\" ; Recursively search for au3 files Local $aFiles = _FileListToArrayRec($sFolder, "*.au3", $FLTAR_FILES, $FLTAR_RECUR, Default, $FLTAR_FULLPATH) If @error Then Return SetError(1, @error, False) Local $iModified GUICtrlSetData($idStatusLabel, "Processing: " & $sFolder) GUICtrlSetData($idProgress, 0) ; Show the progress bar GUICtrlSetState($idProgress, $GUI_SHOW) ; For each file (1-based array!) For $i=1 To UBound($aFiles) - 1 ; Update the progress bar GUICtrlSetData($idProgress, ($i+1)/UBound($aFiles)*100) ; Get the last modified date $iModified = FileGetTime($aFiles[$i], Default, 1) ; If the file is in the config and the modified dates match If ProcessedFileGet($aFiles[$i]) = $iModified Then ; We've read it already Debug("Already processed: " & $aFiles[$i]) ; If the file failed to load and hasn't been modified since ElseIf IniRead($__g_sFunctionDocsConfig, "Processed Issue Files", $aFiles[$i], -1) = $iModified Then ; We tried already Debug("Already failed: " & $aFiles[$i], "-") Else ; Process the file __FunctionDocs_ProcessAu3File($aFiles[$i]) If ErrMsg("__FunctionDocs_ProcessAu3File - " & $aFiles[$i]) Then FailedFileAdd($aFiles[$i]) EndIf Next ; Hide the progress bar GUICtrlSetState($idProgress, $GUI_HIDE) EndFunc ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name ..........: __FunctionDocs_FuncSearch ; Description ...: A GUI wrapper function for what to do when a search is performed ; Syntax ........: __FunctionDocs_FuncSearch($sFunctionName) ; Parameters ....: $sFunctionName - a string value. ; Return values .: None ; Author ........: Seadoggie01 ; Modified ......: April 20, 2020 ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func __FunctionDocs_FuncSearch($sFunctionName, $sFile = "") Local $aInfo = __FunctionDocs_FunctionInfo($sFunctionName, $sFile) If @error Then MsgBox(0, "Failed", "Couldn't find your function") Return ElseIf @extended Then ; Multiple results, ask the user to select the file to pull the info from $sFile = _InputBox_ComboBox("Multiple Results", "Select a file to retrieve documentation from:", $aInfo, 0, Default, Default, BitOR($WS_MAXIMIZEBOX,$WS_MINIMIZEBOX,$WS_SIZEBOX), Default, $idGUI) If @error Then Return $aInfo = __FunctionDocs_FunctionInfo($sFunctionName, $sFile) If @error Then Return MsgBox($MB_ICONERROR, "Function Failure", "Failed to find the documentation for that function!") EndIf __FunctionDocs_ListViewSet($aInfo) ; Resize the columns _GUICtrlListView_SetColumnWidth($idFuncHeaderList, 0, $LVSCW_AUTOSIZE_USEHEADER) _GUICtrlListView_SetColumnWidth($idFuncHeaderList, 1, $LVSCW_AUTOSIZE_USEHEADER) ; Update the tree view's selection ControlTreeView($idGUI, "", $idFileTreeView, "Select", __FilePath($sFile) & "|" & __FileName($sFile) & "|" & $sFunctionName) EndFunc ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name ..........: __FunctionDocs_ListViewSet ; Description ...: Updates the ListView's data ; Syntax ........: __FunctionDocs_ListViewSet($aData) ; Parameters ....: $aData - an array. ; Return values .: None ; Author ........: Seadoggie01 ; Modified ......: April 20, 2020 ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func __FunctionDocs_ListViewSet($aData) ; Pause updating of the list view (like Application.ScreenUpdating = False in Excel VBA) _GUICtrlListView_BeginUpdate($idFuncHeaderList) ; Delete all the old items _GUICtrlListView_DeleteAllItems($idFuncHeaderList) ; Resize the array of list view items ReDim $aIdFuncHeaderItems[UBound($aData)] Local $aDescription, $iIndex = 0 ; For each line of data For $iLine = 0 To UBound($aData) - 1 ; Split the description into an array using newlines $aDescription = StringSplit($aData[$iLine][1], @CRLF, 3) ; Create the base item (has a header name) $aIdFuncHeaderItems[$iIndex] = GUICtrlCreateListViewItem($aData[$iLine][0] & $__g_sSepChar & $aDescription[0], $idFuncHeaderList) $iIndex += 1 ReDim $aIdFuncHeaderItems[UBound($aIdFuncHeaderItems) + UBound($aDescription) - 1] ; For each remaining description part For $iDescPart = 1 To UBound($aDescription) - 1 ; Add the remaining lines without a header name $aIdFuncHeaderItems[$iIndex] = GUICtrlCreateListViewItem($__g_sSepChar & $aDescription[$iDescPart], $idFuncHeaderList) $iIndex += 1 Next Next ; Show all the changes now _GUICtrlListView_EndUpdate($idFuncHeaderList) EndFunc ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name ..........: __FunctionDocs_FunctionInfo ; Description ...: Reads all stored data to get the information for a function. ; Syntax ........: __FunctionDocs_FunctionInfo($sFunctionName) ; Parameters ....: $sFunctionName - a string value. ; Return values .: Success - a 0-based 2D array of function header data ; Failure - False and sets @error: ; |1 - Unable to get list of files that have been processed ; |2 - The function name doesn't match any that have been processed ; Author ........: Seadoggie01 ; Modified ......: April 20, 2020 ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func __FunctionDocs_FunctionInfo($sFunctionName, ByRef $sFile) If $sFile <> "" Then Local $vRet = ProcessedFileFunctionGet($sFile, $sFunctionName) Return SetError(@error, @extended, $vRet) Else Local $aFiles = ProcessedFileGetAll() If @error Then Return SetError(1, 0, False) Local $aTemp, $aInfo, $aMatches[0] ; For each file For $i=0 To UBound($aFiles) - 1 ; Try to read the function's info from this file's (stored) data $aTemp = ProcessedFileFunctionGet($aFiles[$i], $sFunctionName) ; If we found the information, return the data If Not @error Then _ArrayAdd($aMatches, $aFiles[$i]) $aInfo = $aTemp EndIf Next Switch UBound($aMatches) Case 0 ; It doesn't exist in any of the files Return SetError(2, 0, False) Case 1 $sFile = $aMatches[0] Return $aInfo Case Else ; Many matches Return SetExtended(1, $aMatches) EndSwitch EndIf EndFunc ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name ..........: __FunctionDocs_ProcessAu3File ; Description ...: Gets the UDF headers from a single Au3 file, splits them, and stores them ; Syntax ........: __FunctionDocs_ProcessAu3File($sFullPath) ; Parameters ....: $sFullPath - a string value. ; Return values .: Success - True ; Failure - False and sets @error: ; |1 - Regular expression #1 failed ; |2 - Regular expression #2 failed ; |3 - Regular expression #3 failed ; Author ........: Seadoggie01 ; Modified ......: March 30, 2020 ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func __FunctionDocs_ProcessAu3File($sFullPath) ; Read the file Local $sText = FileRead($sFullPath) ; Get all of the function headers from the file ; (This gets everything from the first line of the UDF header to the first line of the function) Local $aHeaders = StringRegExp($sText, $__g_sUdfHeaderRegEx, 3) If @error Then Return SetError(1, 0, False) Local $aHeaderParts, $sFunctionName, $aTemp ; For each function's header For $iHeaders=0 To UBound($aHeaders) - 1 ; Split the header into parts (["Description:", "", ...]) $aHeaderParts = StringRegExp($aHeaders[$iHeaders], $__g_sUdfSplitterRegEx, 3) If @error Then Return SetError(2, $iHeaders, False) ; Find the function name from the final line $aTemp = StringRegExp($aHeaders[$iHeaders], $__g_sUdfFuncNameRegEx, 3) If @error Then Return SetError(3, $iHeaders, False) $sFunctionName = $aTemp[0] ; For each header part (ie: Name, description, syntax, etc) For $iParts=0 To UBound($aHeaderParts) - 1 ; Strip out the semi-colons and the leading spaces $aHeaderParts[$iParts] = StringRegExpReplace($aHeaderParts[$iParts], "(?im)(^;\s*)", "") Next ; Turn the 1D aray into a 2d array (Assumes that we got an even number of matches) Local $aFuncHead = _1dArrayTo2d($aHeaderParts, 2) ; For each piece of the Function header For $iFuncHead =0 To UBound($aFuncHead) - 1 ; Save the name and description HeaderPartSave($sFullPath, $sFunctionName, $aFuncHead[$iFuncHead][0], $aFuncHead[$iFuncHead][1]) Next ProcessedFileFuntionAdd($sFullPath, $sFunctionName) Next ; Save the we successfully processed this file and the current date ProcessedFileSave($sFullPath) Return True EndFunc ; #FUNCTION# ==================================================================================================================== ; Name ..........: _1dArrayTo2d ; Description ...: Turns a 1D array into a 2D array based on $iColumns ; Syntax ........: _1dArrayTo2d(Byref $aArray1d, $iColumns[, $iStart = 0]) ; Parameters ....: $aArray1d - [in/out] an array of unknowns. ; $iColumns - an integer value. ; $iStart - [optional] an integer value. Default is 0. ; Return values .: Success - the 2D array ; Failure - False and sets @error ; |1 - the 1D array is not divisible by $iColumns equally, resulting in an un-even array ; Author ........: Seadoggie01 ; Modified ......: March 30, 2020 ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func _1dArrayTo2d(ByRef $aArray1d, $iColumns, $iStart = 0) ; If the conversion would leave blank cells If Mod(UBound($aArray1d), $iColumns) - $iStart <> 0 Then Return SetError(1, 0, False) Local $aArray2d[UBound($aArray1d)/$iColumns][$iColumns] If $iStart <> 0 Then Debug("$aArray2d[" & UBound($aArray2d) & "][" & UBound($aArray2d,2) & "]") Debug("$aArray1d[" & UBound($aArray1d) & "]") EndIf For $i=$iStart To UBound($aArray1d) - 1 If $iStart <> 0 Then Debug("$aArray2d[" & $i/$iColumns & "][" & Mod($i, $iColumns) - $iStart & "] = $aArray1d[" & $i & "]") $aArray2d[$i/$iColumns][Mod($i, $iColumns) - $iStart] = $aArray1d[$i] Next Return $aArray2d EndFunc ; #FUNCTION# ==================================================================================================================== ; Name ..........: SearchPaths ; Description ...: Gets/Sets the paths to search ; Syntax ........: SearchPaths([$aPaths = Default]) ; Parameters ....: $aPaths - [optional] an array of unknowns. Default is Default. ; Return values .: Success - An array of paths if $aPaths = Default, otherwise returns True ; Author ........: Seadoggie01 ; Modified ......: March 27, 2020 ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func SearchPaths($aPaths = Default) Local $aTemp[0][2], $aRet[0] If IsKeyword($aPaths) Then $aTemp = IniReadSection($__g_sFunctionDocsConfig, "Search Paths") If @error Then Debug("Unable to read Ini section. Error: " & @error, "!") MsgBox(0, "No Paths", "Please select a path to search for documentation.", $idGUI) ; Create a 0-length array to use as the folder list $aTemp = StringSplit("","",3) Do _FolderList_Editor($aTemp, "Function Docs Paths", $idGUI) Until Not @error Return $aTemp Else ReDim $aRet[UBound($aTemp) - 1] For $i = 1 To UBound($aTemp) - 1 $aRet[$i-1] = $aTemp[$i][0] Next Return $aRet EndIf Else ReDim $aTemp[UBound($aPaths)][2] For $i = 0 To UBound($aPaths) - 1 $aTemp[$i][0] = $aPaths[$i] Next If Not IniWriteSection($__g_sFunctionDocsConfig, "Search Paths", $aTemp, 0) Then Debug("Failed to save Ini data", "!") Return True EndIf EndFunc ; #FUNCTION# ==================================================================================================================== ; Name ..........: Debug ; Description ...: Prints a message to the console ; Syntax ........: Debug($sMsg[, $sPrefix = "+"]) ; Parameters ....: $sMsg - a string value. ; $sPrefix - [optional] a string value. Default is "+". ; Return values .: None ; Author ........: Seadoggie01 ; Modified ......: March 27, 2020 ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func Debug($sMsg, $sPrefix = "+") If @Compiled Then FileWrite($__g_sDebugLog, $sMsg) ConsoleWrite($sPrefix & " " & $sMsg & @CRLF) EndFunc ; #FUNCTION# ==================================================================================================================== ; Name ..........: ErrMsg ; Description ...: Sends a message to Debug if there is an error ; Syntax ........: ErrMsg($sMsg[, $iError = @error[, $iExtended = @extended]]) ; Parameters ....: $sMsg - a string value. ; $iError - [optional] an integer value. Default is @error. ; $iExtended - [optional] an integer value. Default is @extended. ; Return values .: $iError ; Author ........: Seadoggie01 ; Modified ......: March 30, 2020 ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func ErrMsg($sMsg, $iError = @error, $iExtended = @extended) If $iError Then $sMsg &= "Error: " & $iError If $iExtended <> 0 Then $sMsg &= @CRLF & @TAB & "Extended: " & $iExtended Debug($sMsg, "!") EndIf Return $iError EndFunc ; #FUNCTION# ==================================================================================================================== ; Name ..........: _FolderList_Editor ; Description ...: Opens a GUI for the user to edit a list of folders ; Syntax ........: _FolderList_Editor(Byref $aPaths[, $sTitle = "Paths"]) ; Parameters ....: $aPaths - [in/out] an array of paths to edit. ; $sTitle - [optional] a string value. Default is "Paths". ; Return values .: Success - True ; Failure - False and sets @error: ; |1 - User cancelled editing (Paths aren't saved) ; Author ........: Seadoggie01 ; Modified ......: March 26, 2020 ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func _FolderList_Editor(ByRef $aPaths, $sTitle = "Paths", $hParent = Default) ; Just GUI variables Local $hPathGUI, $idPathList, $Label1, $idAddBttn, $idEditBttn, $idDeleteBttn, $idSaveBttn, $idCancelBttn #forceref $hPathGUI, $idPathList, $Label1, $idAddBttn, $idEditBttn, $idDeleteBttn, $idSaveBttn, $idCancelBttn If Not IsArray($aPaths) Then Return SetError(2, 0, False) If UBound($aPaths, 0) <> 1 Then Return SetError(2, 1, False) $hPathGUI = GUICreate("Path Editor", 343, 381, 192, 124, -1, -1, $hParent) $idPathList = GUICtrlCreateListView("Paths", 20, 40, 211, 292) $Label1 = GUICtrlCreateLabel($sTitle, 20, 10, 210, 30, BitOR($SS_CENTER, $SS_CENTERIMAGE)) GUICtrlSetFont(-1, 12, 400, 0, "Arial") $idAddBttn = GUICtrlCreateButton("Add Path", 240, 50, 75, 25) $idEditBttn = GUICtrlCreateButton("Edit Path", 240, 90, 75, 25) $idDeleteBttn = GUICtrlCreateButton("Delete", 240, 130, 75, 25) $idSaveBttn = GUICtrlCreateButton("Save", 240, 340, 75, 25) $idCancelBttn = GUICtrlCreateButton("Cancel", 20, 340, 75, 25) Local $aIdPaths[UBound($aPaths)] For $i=0 To UBound($aPaths) - 1 $aIdPaths[$i] = GUICtrlCreateListViewItem($aPaths[$i], $idPathList) Next _GUICtrlListView_SetColumnWidth($idPathList, 0, $LVSCW_AUTOSIZE_USEHEADER );$LVSCW_AUTOSIZE) GUISetState(@SW_SHOW, $hPathGUI) ; Make sure to use my GUI for messages GUISwitch($hPathGUI) Local $vReturn = True, $iError = 0, $sFolder, $iIndex, $idSelected While True Switch GUIGetMsg() Case $idAddBttn $sFolder = FileSelectFolder("Select a folder to add...", "", "", "", $hPathGUI) If Not @error Then ReDim $aIdPaths[UBound($aIdPaths) + 1] $aIdPaths[UBound($aIdPaths) - 1] = GUICtrlCreateListViewItem($sFolder, $idPathList) EndIf Case $idDeleteBttn $idSelected = GUICtrlRead($idPathList) If $idSelected <> 0 Then GUICtrlDelete($idSelected) $iIndex = 0 For $i=0 To UBound($aIdPaths) - 1 If $aIdPaths[$i] = $idSelected Then ; Skip it by not incrementing the index... overwrite next time. Else $aIdPaths[$iIndex] = $aIdPaths[$i] $iIndex += 1 EndIf Next ; Resize the paths ReDim $aIdPaths[UBound($aIdPaths) - 1] EndIf Case $idSaveBttn ExitLoop Case $idEditBttn $idSelected = GUICtrlRead($idPathList) If $idSelected <> 0 Then $sFolder = FileSelectFolder("Select the folder to change to...", "", "", StringReplace(GUICtrlRead($idSelected), $__g_sSepChar, ""), $hPathGUI) If Not @error Then GUICtrlSetData($idSelected, $sFolder) EndIf EndIf Case $idCancelBttn, $GUI_EVENT_CLOSE If MsgBox($MB_YESNO, "Close", "Are you sure you want to exit without saving?") = $IDYES Then $vReturn = False $iError = 1 ExitLoop EndIf EndSwitch WEnd ; Hide the GUI (Delete can take a little time, looks cleaner) GUISetState(@SW_HIDE, $hPathGUI) ; If the user asked to save If $vReturn Then ; Update all the paths ReDim $aPaths[UBound($aIdPaths)] For $i=0 To UBound($aIdPaths) - 1 ; Read the list view item to get the path (pipes can't be in a path, so this is safe) $aPaths[$i] = StringReplace(GUICtrlRead($aIdPaths[$i]), $__g_sSepChar, "") Next EndIf ; Destroy the GUI GUIDelete($hPathGUI) Return SetError($iError, 0, $vReturn) EndFunc ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name ..........: __WM_GETMINMAXINFO ; Description ...: Forces the GUI not to get smaller/larger than requested. ; Syntax ........: __WM_GETMINMAXINFO($hwnd, $Msg, $wParam, $lParam) ; Parameters ....: $hwnd - a handle value. ; $Msg - an unknown value. ; $wParam - an unknown value. ; $lParam - an unknown value. ; Return values .: None ; Author ........: Melba23 ; Modified ......: April 2, 2020 (commented Max lines) ; Remarks .......: I totally copied this off the forums. No idea how it works, but it does. Thanks Melba23! :D ; Related .......: ; Link ..........: https://www.autoitscript.com/forum/topic/157977-gui-minimum-size/?tab=comments#comment-1145682 ; Example .......: No ; =============================================================================================================================== Func __WM_GETMINMAXINFO($hwnd, $Msg, $wParam, $lParam) #forceref $hwnd, $Msg, $wParam, $lParam Local $tagMaxinfo = DllStructCreate("int;int;int;int;int;int;int;int;int;int", $lParam) DllStructSetData($tagMaxinfo, 7, $__g_MINWIDTH) ; min X DllStructSetData($tagMaxinfo, 8, $__g_MINHEIGHT) ; min Y ;~ DllStructSetData($tagMaxinfo, 9, $GUIMAXWID ); max X ;~ DllStructSetData($tagMaxinfo, 10, $GUIMAXHT ) ; max Y Return 0 EndFunc ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name ..........: __FileName ; Description ...: Get a file name from the full path of a file. ; Syntax ........: __FileName($sFullPath) ; Parameters ....: $sFullPath - a string value. ; Return values .: the file's name ; Author ........: Seadoggie01 ; Modified ......: April 2, 2020 ; Remarks .......: Assumes a valid file is passed. Gets everything to the right of the last "\". ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func __FileName($sFullPath) Return StringRight($sFullPath, StringLen($sFullPath) - StringInStr($sFullPath, "\", 0, -1)) EndFunc Func __FilePath($sFullPath) Return StringLeft($sFullPath, StringInStr($sFullPath, "\", 0, -1) - 1) EndFunc ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name ..........: __ArrayContaints ; Description ...: Checks if an item is present in an 0-based 1D array ; Syntax ........: __ArrayContaints($aArray, $vItem) ; Parameters ....: $aArray - an array. ; $vItem - a variant value. ; Return values .: Success - True and sets @extended to index of match ; Failure - False ; Author ........: Seadoggie01 ; Modified ......: April 2, 2020 ; Remarks .......: Uses = to check matches. ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func __ArrayContaints($aArray, $vItem) For $i=0 To UBound($aArray) - 1 If $aArray[$i] = $vItem Then Return SetExtended($i, True) Next Return False EndFunc ; #FUNCTION# ==================================================================================================================== ; Name ..........: _InputBox_ComboBox ; Description ...: Creates an input box that allows the user to select an option. ; Syntax ........: _InputBox_ComboBox($sTitle, $sPrompt, $vOptions[, $vSelected = Default[, $iLeft = -1[, $iTop = -1[, $iStyle = -1[, $iExStyle = -1[, $hParent = 0]]]]]]) ; Parameters ....: $sTitle - a string value. ; $sPrompt - a string value. ; $vOptions - an array of choices or a GUIDataSeperatorChar seperated string of options. ; $vSelected - [optional] a variant value. Default is Default. ; $iLeft - [optional] an integer value. Default is -1. ; $iTop - [optional] an integer value. Default is -1. ; $iStyle - [optional] an integer value. Default is -1. ; $iExStyle - [optional] an integer value. Default is -1. ; $hParent - [optional] a handle value. Default is 0. ; Return values .: Success - the text of the selected item ; Failure - False and sets @error: ; |1 - GUI was closed ; Author ........: Seadoggie01 ; Modified ......: April 20, 2020 ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func _InputBox_ComboBox($sTitle, $sPrompt, $vOptions, $vSelected = Default, $iLeft = Default, $iTop = Default, $iStyle = Default, $iExStyle = Default, $hParent = Default) Local Const $sDelimiter = AutoItSetOption("GUIDataSeparatorChar") If $iLeft = Default Then $iLeft = -1 If $iTop = Default Then $iTop = -1 If $iStyle = Default Then $iStyle = -1 If $iExStyle = Default Then $iExStyle = -1 If $hParent = Default Then $hParent = 0 Local Const $iGUIWidth = 350 Local $hGUI = GUICreate($sTitle, $iGUIWidth, 120, $iLeft, $iTop, $iStyle, $iExStyle, $hParent) GUICtrlCreateLabel($sPrompt, 5, 10, $iGUIWidth - 10, 20) Local $hCombo = GUICtrlCreateCombo("", 5, 30, $iGUIWidth - 10, 20) Local $hButton = GUICtrlCreateButton("OK", $iGUIWidth/2 - 25, 60, 50, 20) Local $sOptions If IsArray($vOptions) Then For $i=0 To UBound($vOptions) - 1 $sOptions &= $vOptions[$i] & $sDelimiter Next ; Remove the last pipe $sOptions = StringReplace($sOptions, $sDelimiter, "", -1) Else $sOptions = $vOptions EndIf ; If there is a pre-selected item If $vSelected <> Default Then ; If the selected item is a number If IsNumber($vSelected) Then ; Split the options $vOptions = StringSplit($sOptions, $sDelimiter, 3) ; If there are enough items, then select the requested item If UBound($vOptions) > $vSelected Then GUICtrlSetData($hCombo, $sOptions, $vOptions[$vSelected]) Else GUICtrlSetData($hCombo, $sOptions, $vSelected) EndIf Else GUICtrlSetData($hCombo, $sOptions) EndIf GUISetState(@SW_SHOW, $hGUI) Local $aAccelKeys[1][2] = [["{ENTER}", $hButton]] GUISetAccelerators($aAccelKeys) While True Switch GUIGetMsg() Case $hButton $vSelected = GUICtrlRead($hCombo) If $vSelected <> "" Then ExitLoop Case $GUI_EVENT_CLOSE $vSelected = "" ExitLoop EndSwitch WEnd GUISetState(@SW_HIDE) GUIDelete($hGUI) If $vSelected = "" Then Return SetError(1, 0, "") Else Return $vSelected EndIf EndFunc Func LoadTreeView() _GUICtrlTreeView_BeginUpdate($idFileTreeView) _GUICtrlTreeView_DeleteAll($idFileTreeView) ReDim $__g_aTreeViewItems[0] Local $aSearchItems[UBound($__g_aSearchPaths)] For $i=0 To UBound($aSearchItems) - 1 $aSearchItems[$i] = _GUICtrlTreeView_Add($idFileTreeView, 0, $__g_aSearchPaths[$i]) Next _ArrayAdd($__g_aTreeViewItems, $aSearchItems) Local $aFiles = ProcessedFileGetAll() Local $aFuncs, $idFileItem, $bFound ; For each file For $i = 0 To UBound($aFiles) - 1 $bFound=False ; For each search path For $iPath = 0 To UBound($__g_aSearchPaths) - 1 ; If the file contains the search path If StringInStr(StringReplace($aFiles[$i], __FileName($aFiles[$i]), "", -1), $__g_aSearchPaths[$iPath]) Then ; Add the item and exit the (current) loop $idFileItem = _GUICtrlTreeView_AddChild($idFileTreeView, $aSearchItems[$iPath], __FileName($aFiles[$i])) _ArrayAdd($__g_aTreeViewItems, $idFileItem) $bFound = True ExitLoop EndIf Next If Not $bFound Then ContinueLoop $aFuncs = ProcessedFileFunctionGetAll($aFiles[$i]) If @error Then ContinueLoop ; For each function For $sFunc In $aFuncs ; Add it to the array and create a treeview item _ArrayAdd($__g_aTreeViewItems, _GUICtrlTreeView_AddChild($idFileTreeView, $idFileItem, $sFunc)) Next Next _GUICtrlTreeView_EndUpdate($idFileTreeView) EndFunc ;~~~ Functions below contain Ini Functions... they load/store data from Ini files #ToDo: should convert to allow for SQLite database with global flag. Below Func names WILL change. Func HeaderPartSave($sAu3FullPath, $sFunctionName, $sHeaderName, $sHeaderDesc) ; Remove all leading/trailing whitespace $sHeaderDesc = StringStripWS($sHeaderDesc, 3) ; Replace all newlines with \@CRLF $sHeaderDesc = StringReplace($sHeaderDesc, @CRLF, "\@CRLF") $sHeaderDesc = StringReplace($sHeaderDesc, @CR, "\@CRLF") $sHeaderDesc = StringReplace($sHeaderDesc, @LF, "\@CRLF") IniWrite($__g_sFunctionDocsConfig, $sAu3FullPath & "|" & $sFunctionName, $sHeaderName, $sHeaderDesc) EndFunc Func FailedFileAdd($sFullPath) IniWrite($__g_sFunctionDocsConfig, "Processed Issue Files", $sFullPath, FileGetTime($sFullPath, Default, 1)) EndFunc Func FailedFileRemove($sFullPath) IniDelete($__g_sFunctionDocsConfig, "Processed Issue Files", $sFullPath) EndFunc Func ProcessedFileSave($sFullPath) IniWrite($__g_sFunctionDocsConfig, "Processed Files", $sFullPath, FileGetTime($sFullPath, Default, 1)) ; Also remove that it failed, if it did FailedFileRemove($sFullPath) EndFunc Func ProcessedFileGet($sFile) Return IniRead($__g_sFunctionDocsConfig, "Processed Files", $sFile, -1) EndFunc Func ProcessedFileGetAll() Local $a1Bound = IniReadSection($__g_sFunctionDocsConfig, "Processed Files") If @error Then Return SetError(1, 0, False) Local $aFiles[UBound($a1Bound) - 1] For $i=1 To UBound($a1Bound) - 1 $aFiles[$i-1] = $a1Bound[$i][0] Next Return $aFiles EndFunc Func ProcessedFileFuntionAdd($sFile, $sFunctionName) IniWrite($__g_sFunctionDocsConfig, $sFile, $sFunctionName, FileGetTime($sFile, Default, 1)) IniWrite($__g_sFunctionDocsConfig, $sFile & "|" & $sFunctionName, "Updated", FileGetTime($sFile, Default, 1)) EndFunc Func ProcessedFileFunctionGetAll($sFile) Local $aFunctions = IniReadSection($__g_sFunctionDocsConfig, $sFile) If @error Then Return SetError(1, 0, False) Local $aFuncs[UBound($aFunctions) - 1] For $i=1 To UBound($aFunctions) - 1 $aFuncs[$i-1] = $aFunctions[$i][0] Next Return $aFuncs EndFunc Func ProcessedFileFunctionGet($sFile, $sFunctionName) Local $vRet = IniRead($__g_sFunctionDocsConfig, $sFile & "|" & $sFunctionName, "Updated", -1) If $vRet = -1 Then Return SetError(1, 0, False) Local $aInfo1based = IniReadSection($__g_sFunctionDocsConfig, $sFile & "|" & $sFunctionName) Local $aInfo[UBound($aInfo1based)-1][2] For $i=0 To UBound($aInfo) - 1 $aInfo[$i][0] = $aInfo1based[$i+1][0] ; Swap all of the newlines back in $aInfo[$i][1] = StringReplace($aInfo1based[$i+1][1], "\@CRLF", @CRLF) Next Return $aInfo EndFunc ; Config file breakdown: ; * [SearchPaths] ; - : garbage ; * [Processed Files] ; - : ; * [] ; - : ; * [|] ; - Updated : ; - :