Jump to content

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

SciTE4ahk custom intellisense generator


  • Please log in to reply
2 replies to this topic
XeroByte
  • Members
  • 20 posts
  • Last active: Nov 11 2015 01:31 AM
  • Joined: 04 Nov 2013

Hi all,

 

I've gained so much from this community. i would finally like to contribute by offering a script i made that makes my life a lot easier.

 

The problem:

I use SciTE4AutoHotkey (v3.0.06.01) and i rely a lot on the intellisense/calltips to remind me what the commands are and what parameters are required. this is fine for the built-in ahk commands & functions, but i write a lot of my own and then promptly forget about them, what parameters they use, and altogether how to use them.

Basically - i wanted intellisense/calltips in SciTE for my own custom written functions.

 

My solution:

I discovered that the user.ahk.api file (inside the SciTE\user directory) can be used for exactly this purpose - but i wasn't going to manually input all my functions & labels - so i built the following script to generate the file by scanning recursively through the specified ahk file and recursively scanning all includes and it will collect all the functions and labels and add them to the user.ahk.api file.

It will also include all the comments that are directly after the label or function (all the lines beginning with a semicolon ;  not the multi-line type comments), This is great to use for a short explanation and/or usage notes. These comments will appear with the intellisense calltips, along with the name of the file that the function/label was found in (this is helpful when trying to locate a function when you use many different includes).

 

If you already use the user.ahk.api file - please back it up before trying my script.

 

It relies on Titan's grep function which I have included at the bottom of the script.

 

Here are the options when calling the function (all the parameters are explained below):

BuildUserAhkApi(AhkScriptPath, [OverwriteAhkApi, RecurseIncludes, Labels, WrapWidth, AhkApiPath, RecursionCall])

I call it like this from my main script (in the autorun section - so it refreshes the API file every time i reload the script) 

BuildUserAhkApi(A_ScriptFullPath)

But you can only do that if you change the default AhkApiPath inside the function. Otherwise you can call it like this

BuildUserAhkApi(A_ScriptFullPath, 1, 1, 1, 265, "[insert your path to]\SciTE\user\user.ahk.api")
 
Please note that SciTE needs to be restarted for it to reload the API file.

 

The function parameters are (in order) as follows:

 

AhkScriptPath: (required)

The full path to the script (or folder containing multiple scripts) you would like to scan for custom functions (and optionally label names) to add to the user.ahk.api file for intellisense/calltips

if you are calling this function from the same script that you would like to scan - you could use the built in A_ScriptFullPath variable.

OverwriteAhkApi: (optional) Default - On

turning this option on means that the function will overwrite the current file user.ahk.api file, turning it off will cause the function to append the results to the current user.ahk.api file

RecurseIncludes: (optional)

Default - On

Turning this option on will enable the function to scan all the includes as well, turning it off will cause the function to only scan the script specified in AhkScriptPath

Labels: (optional) Default - On

Turning this option on enables the function to scan for labels as well

WrapWidth: (optional - Dependent on the TF Library) Default - 265 (characters)

This will only have an effect if you have included the TF library (specifically the TF_Wrap() function, but it ensures the intellisense tooltips are wrapped so they don't extend off the screen, or too far.

 

AhkApiPath: (optional if already set up in the function) Default - FOR EASE OF USE - THIS SHOULD BE CUSTOMIZED BY EDITING WHERE IT SAYS " ReplaceThisWithFullPathTo " IN THE TOP OF THE FUNCTION

The full path to the user.ahk.api file that is located in the SciTE\user directory, eg: mine is: AhkApiPath:="C:\Dropbox\AutoHotKey\SciTE\user\user.ahk.api"

 

RecursionCall: (DO NOT USE THIS PARAMETER) Default - Off

This parameter should not be set - it is for use by the function itself and needs to be left off when calling the function.

----------------------------------------------------------

 

The function returns a formatted list of all the custom functions that were scanned. for regular use it is not necessary to store this value since the function automatically writes the results to the user.ahk.api file.

 

And here is the function - I am open to any and all suggestions, improvements & bug reports:

BuildUserAhkApi(AhkScriptPath, OverwriteAhkApi:="1", RecurseIncludes:="1", Labels:="1", WrapWidth:="265", AhkApiPath:="ReplaceThisWithFullPathTo\SciTE\user\user.ahk.api", RecursionCall:="0"){
	; Written by XeroByte
	; Generates the User.ahk.api file to add custom function & label intellisense!
	; to initate: use BuildUserAhkApi(A_ScriptFullPath,1) from the main script
	; Requires: grep() by Titan/Polyethelene https://github.com/camerb/AHKs/blob/master/thirdParty/titan/grep.ahk
	; Reqiures: isDir() Function
	; Optionally include TF_Wrap() from the TF Library https://github.com/hi5/TF/blob/master/tf.ahk
	TF_Wrap := "TF_Wrap" ; This is for a workaround to make the script still work even without the TF library - need to call the function dynamically.
	if(isDir(AhkScriptPath)){
		Loop, %AhkScriptPath%\*.ahk,0,1
			AhkApiText .= BuildUserAhkApi(A_LoopFileLongPath, 0, RecurseIncludes, Labels, WrapWidth, AhkApiPath, 1)
	}else{
		FileRead, ThisScriptTxt, %AhkScriptPath%
		; Retrieve Functions
			grep(ThisScriptTxt, "m)^\s*[a-zA-Z0-9_-]*\([^\)]*\)\s*\{(\s*;.*?$)*", MatchCollection,1,0,"§")
			loop, parse, MatchCollection, §
			{
				if(RegExMatch(A_LoopField,"iS)^\s*if\([^\)]*\)")>0)
					continue
				StringReplace, CustomFunc, A_LoopField, \, \\, All
				CustomFunc := RegExReplace(CustomFunc,"mS)(^\s*|\s*$)")
				CustomFunc := RegExReplace(CustomFunc,"S)\)\s*\{",")")
				if(IsFunc("TF_Wrap"))
					CustomFunc := %TF_Wrap%(CustomFunc, WrapWidth)
				CustomFunc := RegExReplace(CustomFunc,"S)\R", "\n")
				CustomFunc := RegExReplace(CustomFunc,"S)\t", "\t")
				CustomFunc := RegExReplace(CustomFunc,"S)([a-zA-Z0-9_-]*)\(","$1 (", ,1)
				AhkApiText .= CustomFunc . "\n; Location: " . SubStr(AhkScriptPath,InStr(AhkScriptPath,"\",0,0)+1) . "`n"
			}
			AhkApiText .= "`n"
		; Retrieve Labels
		if(Labels){
			grep(ThisScriptTxt, "mS)^\s*[a-zA-Z0-9_-]+\:\s(\s*;.*?$)*", MatchCollection,1,0,"§")
			loop, parse, MatchCollection, §
			{		
				StringReplace, CustomFunc, A_LoopField, \, \\, All
				CustomFunc := RegExReplace(CustomFunc,"mS)(^\s*|\s*$)")
				if(IsFunc("TF_Wrap"))
					CustomFunc := %TF_Wrap%(CustomFunc, WrapWidth)
				CustomFunc := RegExReplace(CustomFunc,"S)\R", "\n")
				CustomFunc := RegExReplace(CustomFunc,"S)\t", "\t")
				StringReplace, CustomFunc, CustomFunc, :, %A_Space%
				AhkApiText .= CustomFunc . "\n; Location: " . SubStr(AhkScriptPath,InStr(AhkScriptPath,"\",0,0)+1) . "`n"
			}
			AhkApiText .= "`n"
		}
		; Recurse into includes
		if(RecurseIncludes){
			grep(ThisScriptTxt, "imS)^\s*\#include (.*)\s*$", IncludeCollection,1,1,"§")
			AhkScriptFolder := substr(AhkScriptPath,1,InStr(AhkScriptPath,"\",0,0))
			loop, parse, IncludeCollection, §
				AhkApiText .= BuildUserAhkApi((instr(A_LoopField,":")) ? A_LoopField : AhkScriptFolder . A_LoopField, 0, 1, Labels, WrapWidth, AhkApiPath, 1)
		}
	}
	; If this function call is the original function call (and not an autocall by the recursion).
	if(!RecursionCall){
		if(OverwriteAhkApi)
			FileDelete, %AhkApiPath%
		AhkApiText := RegExReplace(AhkApiText, "(\R){2,}","$1$1")
		FileAppend, %AhkApiText%, %AhkApiPath%
		ToolTip, Imported Custom Funcs & Labels from`n %AhkScriptPath%
		Sleep, 2000
		ToolTip
	}
	return AhkApiText
}

isDir(FilePattern){
	att := FileExist(FilePattern)
	return att = "" ? "" : InStr(att, "D") = 0 ? 0 : 1
}

grep(h, n, ByRef v, s = 1, e = 0, d = "") {
	v =
	StringReplace, h, h, %d%, , All
	Loop
		If s := RegExMatch(h, n, c, s)
			p .= d . s, s += StrLen(c), v .= d . (e ? c%e% : c)
		Else Return, SubStr(p, 2), v := SubStr(v, 2)
}

I hope somebody out there enjoys my script as much as i do  :p  Please comment

 

EDIT: It seems that the EOT character i used in the script won't show here in the forums, so i have replaced it with the § symbol. This should be fine, but if you encounter any problems, you can replace all occurrences of § with the original EOT symbol that you can produce by using the alt code [Alt] [numpad 0] [numpad 4].
EDIT: Now you can pass in a directory and it will add all the ahk scripts in the directory
EDIT: Added the TF_Wrap option

Edited by XeroByte, 08 November 2014 - 12:53 PM.


MarkyMarks
  • Members
  • 3 posts
  • Last active: Feb 23 2015 02:07 AM
  • Joined: 07 Nov 2014

thanks!! this is great. does this work in newer SciTE versions?

also it doesn't update until i after restart the running SciTE program is this normal?



XeroByte
  • Members
  • 20 posts
  • Last active: Nov 11 2015 01:31 AM
  • Joined: 04 Nov 2013

Thanks for your feedback  :D

 

This script works for SciTE4Autohotkey up to and including the latest version (v3.0.06.01), but i expect it should also work in any upcoming updates.

 

Yes it is normal to require restarting SciTE. SciTE only loads the user.ahk.api file when it starts up, which means that it needs to be restarted to display any changes that have been made while it has been open.