I tried to post them agian on Github.
But I decided to focus on the convert function, as it is the heart of the script.
I still cant get it to work, (I think I almost fixed it, but I find It quite complicated )
I began writing my own fuction convert2, with the focus on converting v1 gui and menu code to V2 beta, as this was not yet Implemented.
It is not at all complete, but already works quite well for simple code, you can test it out
It would be nice if the convert function would be fixed. Then I would probably be able to figure out how to update it to change it so It`s converts to V2 beta.
Code: Select all
#Requires AutoHotKey v2.0-beta.1
#SingleInstance Force
XButton1::
{
ClipSaved := ClipboardAll() ; Save the entire clipboard to a variable of your choice.
A_Clipboard := ""
Send "^c"
if !ClipWait(3){
DebugWindow( "error`n",Clear:=0)
return
}
Clipboard1 := A_Clipboard
A_Clipboard := ClipSaved ; Restore the original clipboard. Note the use of A_Clipboard (not ClipboardAll).
ClipSaved := "" ; Free the memory in case the clipboard was very large.
ConvertedCode := Convert2(Clipboard1)
;DebugWindow(ConvertedCode "`n",Clear:=0) ; For AHK Studio Users
MsgBox(ConvertedCode)
A_Clipboard := ConvertedCode
return
}
DebugWindow(Text,Clear:=0,LineBreak:=0,Sleep:=0,AutoHide:=0){
x:=ComObjActive("{DBD5A90A-A85C-11E4-B0C7-43449580656B}")
x.DebugWindow(Text,Clear,LineBreak,Sleep,AutoHide)
}
Convert2(ScriptString){
ScriptStringResult:=""
; Default Gui name
GuiNameDefault := "MyGui"
GuiList := "|"
MenuList := "|"
Loop Parse ScriptString, "`n", "`r"
{
Line := A_LoopField
if RegExMatch(Line, "^.*?[^``];(.*)$")
{
Comment := RegExReplace(Line, "i)^.*?[^``];(.*)$", "$1", &RegExCount1)
Line := RegExReplace(Line, "i)^(.*?[^``])\s*;(.*)$", "$1", &RegExCount1)
}
else{
Comment := ""
}
if RegExMatch(Line, "i)^\s*Gui\s*[,\s]\s*.*$"){
ControlLabel:=""
ControlName:=""
ControlObject:=""
if RegExMatch(Line, "i)^\s*Gui\s*[\s,]\s*[^,\s]*:.*$")
{
GuiNameLine := RegExReplace(Line, "i)^\s*Gui\s*[\s,]\s*([^,\s]*):.*$", "$1", &RegExCount1)
Line := RegExReplace(Line, "i)^(\s*Gui\s*[\s,]\s*)([^,\s]*):(.*)$", "$1$3", &RegExCount1)
}
Else{
GuiNameLine:= GuiNameDefault
}
if (RegExMatch(GuiNameLine, "^\d$")){
GuiNameLine := "Gui" GuiNameLine
}
Var1 := RegExReplace(Line, "i)^\s*Gui\s*[,\s]\s*([^,]*).*$", "$1", &RegExCount1)
Var2 := RegExReplace(Line, "i)^\s*Gui\s*,\s*([^,]*)\s*,\s*([^,]*).*", "$2", &RegExCount2)
Var3 := RegExReplace(Line, "i)^\s*Gui\s*,\s*([^,]*),\s*([^,]*)\s*,\s*([^,]*).*$", "$3", &RegExCount3)
Var4 := RegExReplace(Line, "i)^\s*Gui\s*,\s*([^,]*),\s*([^,]*)\s*,\s*([^,]*),([^;]*).*", "$4", &RegExCount4)
Var1 := Trim(Var1)
Var2 := Trim(Var2)
Var3 := Trim(Var3)
Var4 := Trim(Var4)
if RegExMatch(Var3, "\bg[\w]*\b"){
ControlLabel:= RegExReplace(Var3, "^.*\bg([\w]*)\b.*$", "$1")
Var3:= RegExReplace(Var3, "^(.*)\bg([\w]*)\b(.*)$", "$1$3")
}
else if (RegExMatch(Var3, "\bDefault\b") and RegExCount4){
ControlLabel:= var2 RegExReplace(Var4, "\s", "")
}
if RegExMatch(Var3, "\vg[\w]*\b"){
ControlName:= RegExReplace(Var3, "^.*\vg([\w]*)\b.*$", "$1")
}
if !InStr(GuiList, "|" GuiNameLine "|"){
GuiList.= GuiNameLine "|"
ScriptStringResult.= GuiNameLine ":= Gui()`n"
}
if(RegExMatch(Var1, "i)^tab[23]?$")){
ScriptStringResult.= "Tab.UseTab(" Var2 ")`n"
continue
}
if(Var1="Show"){
if (RegExCount3){
ScriptStringResult.= GuiNameLine ".Name :=" ToStringExpr(Var3) "`n"
Var3:=""
RegExCount3:=0
}
Var1 := "Show"
}
if(RegExMatch(Var2, "i)^tab[23]?$")){
ScriptStringResult.= "Tab := "
}
if(var1 = "Submit"){
ScriptStringResult.= "oSaved := "
}
if(var1 = "Add" and (var2="Button" or ControlLabel!="")){
ControlObject := "my" var2
ScriptStringResult.= ControlObject " := "
}
ScriptStringResult.= GuiNameLine "."
if (Var1="Menu"){
ScriptStringResult.= "MenuBar := " Var2
}
else{
if (RegExCount1){
if (RegExMatch(Var1, "^\s*[-\+]\w*")){
ScriptStringResult.= "Opt(" ToStringExpr(Var1)
}
Else{
ScriptStringResult.= Var1 "("
}
}
if (RegExCount2){
ScriptStringResult.= ToStringExpr(Var2)
}
if (RegExCount3){
ScriptStringResult.= ", " ToStringExpr(Var3)
}
else if (RegExCount4){
ScriptStringResult.= ", "
}
if (RegExCount4){
if(RegExMatch(Var2, "i)^tab[23]?$") or Var2="ListView"){
ScriptStringResult.= ", ["
oVar4 :=""
Loop Parse Var4, "|", " "
{
oVar4.= oVar4="" ? ToStringExpr(A_LoopField) : ", " ToStringExpr(A_LoopField)
}
ScriptStringResult.= oVar4 "]"
}
else{
ScriptStringResult.= ", " ToStringExpr(Var4)
}
}
if (RegExCount1){
ScriptStringResult.= ")"
}
}
ScriptStringResult.= Comment!="" ? " `;" Comment : ""
if(ControlObject!=""){
ScriptStringResult.= "`n" ControlObject ".OnEvent(`"Click`", " ControlLabel ")"
}
}
else if RegExMatch(Line, "i)^\s*Menu\s*[,\s]\s*.*$"){
menuNameLine := RegExReplace(Line, "i)^\s*Menu\s*[,\s]\s*([^,]*).*$", "$1", &RegExCount1)
Var2 := RegExReplace(Line, "i)^\s*Menu\s*[,\s]\s*([^,]*)\s*,\s*([^,]*).*", "$2", &RegExCount2)
Var3 := RegExReplace(Line, "i)^\s*Menu\s*[,\s]\s*([^,]*),\s*([^,]*)\s*,\s*([^,]*).*$", "$3", &RegExCount3)
Var4 := RegExReplace(Line, "i)^\s*Menu\s*[,\s]\s*([^,]*),\s*([^,]*)\s*,\s*([^,]*),\s*:?([^;,]*).*", "$4", &RegExCount4)
Var5 := RegExReplace(Line, "i)^\s*Menu\s*[,\s]\s*([^,]*),\s*([^,]*)\s*,\s*([^,]*),\s*:?([^;,]*)\s*,\s*([^,]*).*", "$5", &RegExCount5)
menuNameLine := Trim(menuNameLine)
Var2 := Trim(Var2)
Var3 := Trim(Var3)
Var4 := Trim(Var4)
if (Var2="Add" and RegExCount3 and !RegExCount4){
Var4 := Var3
RegExCount4 := RegExCount3
}
if (Var3="Icon"){
Var3 := "SetIcon"
}
if !InStr(menuList, "|" menuNameLine "|"){
menuList.= menuNameLine "|"
if (menuNameLine="Tray"){
ScriptStringResult.= menuNameLine ":= A_TrayMenu`n"
}
else{
ScriptStringResult.= menuNameLine ":= Menu()`n"
}
}
ScriptStringResult.= menuNameLine "."
if (RegExCount2){
ScriptStringResult.= Var2 "("
}
if (RegExCount3){
ScriptStringResult.= ToStringExpr(Var3)
}
else if (RegExCount4){
ScriptStringResult.= ", "
}
if (RegExCount4){
if (Var2="Add"){
ScriptStringResult.= ", " Var4
}
else{
ScriptStringResult.= ", " ToStringExpr(Var4)
}
}
if (RegExCount5){
ScriptStringResult.= ", " ToStringExpr(Var5)
}
if (RegExCount1){
ScriptStringResult.= ")"
}
ScriptStringResult.= Comment!="" ? " `;" Comment : ""
}
else{
ScriptStringResult.= A_LoopField
}
ScriptStringResult.= "`n"
}
return ScriptStringResult
}
;~ Gui, Add, Text,xm, X:
;~ MyGui.Add("Text",, "WinSearch:")
; =============================================================================
; Convert traditional statements to expressions
; Don't pass whole commands, instead pass one parameter at a time
; =============================================================================
ToExp(Text)
{
static qu := "`"" ; Constant for double quotes
static bt := "``" ; Constant for backtick to escape
Text := Trim(Text, " `t")
DeRef := 0
If (Text = "") ; If text is empty
return (qu . qu) ; Two double quotes
else if (SubStr(Text, 1, 2) = "`% ") ; if this param was a forced expression
return SubStr(Text, 3) ; then just return it without the %
Text := StrReplace(Text, qu, bt . qu) ; first escape literal quotes
Text := StrReplace(Text, bt . ",", ",") ; then remove escape char for comma
;msgbox text=%text%
if InStr(Text, "`%") ; deref %var% -> var
{
;msgbox %text%
TOut := ""
;Loop % StrLen(Text)
Loop Parse Text
{
;Symbol := Chr(NumGet(Text, (A_Index-1)*2, "UChar"))
Symbol := A_LoopField
If Symbol == "`%"
{
If (DeRef := !DeRef) && (A_Index != 1)
TOut .= qu . " . "
else If (!DeRef) && (A_Index != StrLen(Text))
TOut .= " . " . qu
}
else
{
If A_Index = 1
TOut .= qu
TOut .= Symbol
}
}
If Symbol != "`%"
TOut .= (qu) ; One double quote
}
else if Text is "number"
{
;msgbox %text%
TOut := Text+0
}
else ; wrap anything else in quotes
{
;msgbox text=%text%`ntout=%tout%
TOut := qu . Text . qu
}
return (TOut)
}
; same as above, except numbers are excluded.
; that is, a number will be turned into a quoted number. 3 -> "3"
ToStringExpr(Text)
{
static qu := "`"" ; Constant for double quotes
static bt := "``" ; Constant for backtick to escape
Text := Trim(Text, " `t")
DeRef := 0
If (Text = "") ; If text is empty
return (qu . qu) ; Two double quotes
else if (SubStr(Text, 1, 2) = "`% ") ; if this param was a forced expression
return SubStr(Text, 3) ; then just return it without the %
Text := StrReplace(Text, qu, bt . qu) ; first escape literal quotes
Text := StrReplace(Text, bt . ",", ",") ; then remove escape char for comma
;msgbox text=%text%
if InStr(Text, "`%") ; deref %var% -> var
{
TOut := ""
;Loop % StrLen(Text)
Loop Parse Text
{
;Symbol := Chr(NumGet(Text, (A_Index-1)*2, "UChar"))
Symbol := A_LoopField
If Symbol == "`%"
{
If (DeRef := !DeRef) && (A_Index != 1)
TOut .= qu . " . "
else If (!DeRef) && (A_Index != StrLen(Text))
TOut .= " . " . qu
}
else
{
If A_Index = 1
TOut .= qu
TOut .= Symbol
}
}
If Symbol != "`%"
TOut .= (qu) ; One double quote
}
;else if type(Text+0) != "String"
;{
;msgbox %text%
;TOut := Text+0
;}
else ; wrap anything else in quotes
{
;msgbox text=%text%`ntout=%tout%
TOut := qu . Text . qu
}
return (TOut)
}
; change "text" -> text
RemoveSurroundingQuotes(text)
{
if (SubStr(text, 1, 1) = "`"") && (SubStr(text, -1) = "`"")
return SubStr(text, 2, -1)
return text
}
; change %text% -> text
RemoveSurroundingPercents(text)
{
if (SubStr(text, 1, 1) = "`%") && (SubStr(text, -1) = "`%")
return SubStr(text, 2, -1)
return text
}
; check if a param is empty
IsEmpty(param)
{
if (param = '') || (param = '""') ; if its an empty string, or a string containing two double quotes
return true
return false
}
; =============================================================================
; Command formatting functions
; They all accept an array of parameters and return command(s) in text form
; These are only called in one place in the script and are called dynamicly
; =============================================================================
_WinGetActiveStats(p) {
Out := format_v("{1} := WinGetTitle(`"A`")", p) . "`r`n"
Out .= format_v("WinGetPos {4}, {5}, {2}, {3}, `"A`"", p)
return Out
}
_EnvAdd(p) {
if !IsEmpty(p[3])
return format_v("{1} := DateAdd({1}, {2}, {3})", p)
else
return format_v("{1} += {2}", p)
}
_EnvSub(p) {
if !IsEmpty(p[3])
return format_v("{1} := DateDiff({1}, {2}, {3})", p)
else
return format_v("{1} -= {2}", p)
}
_StringGetPos(p)
{
;msgbox, % p.Length() "`n" p[1] "`n" p[2] "`n" p[3] "`n" p[4] "`n" p[5]
if IsEmpty(p[4]) && IsEmpty(p[5])
return format_v("{1} := InStr({2}, {3}) - 1", p)
; modelled off of: https://github.com/Lexikos/AutoHotkey_L/blob/master/source/script.cpp#L14181
else
{
p[5] := p[5] ? p[5] : 0 ; 5th param is 'Offset' aka starting position. set default value if none specified
p4FirstChar := SubStr(p[4], 1, 1)
p4LastChar := SubStr(p[4], -1)
;msgbox, % p[4] "`np4FirstChar=" p4FirstChar "`np4LastChar=" p4LastChar
if (p4FirstChar = "`"") && (p4LastChar = "`"") ; remove start/end quotes, would be nice if a non-expr was passed in
{
p4noquotes := SubStr(p[4], 2, -1)
p4char1 := SubStr(p4noquotes, 1, 1)
occurences := SubStr(p4noquotes, 2)
;msgbox, % p[4]
p[4] := occurences ? occurences : 1
if (StrUpper(p4char1) = "R") || (p4noquotes = "1")
return format_v("{1} := InStr({2}, {3}, (A_StringCaseSense=`"On`") ? true : false, -1*(({5})+1), {4}) - 1", p)
else
return format_v("{1} := InStr({2}, {3}, (A_StringCaseSense=`"On`") ? true : false, ({5})+1, {4}) - 1", p)
}
else
{
; else then a variable was passed (containing the "L#|R#" string),
; or literal text converted to expr, something like: "L" . A_Index
; output something anyway even though it won't work, so that they can see something to fix
return format_v("{1} := InStr({2}, {3}, (A_StringCaseSense=`"On`") ? true : false, ({5})+1, {4}) - 1", p)
}
}
}
_StringMid(p)
{
if IsEmpty(p[4]) && IsEmpty(p[5])
return format_v("{1} := SubStr({2}, {3})", p)
else if IsEmpty(p[5])
return format_v("{1} := SubStr({2}, {3}, {4})", p)
else
{
;msgbox, % p[5] "`n" SubStr(p[5], 1, 2)
; any string that starts with 'L' is accepted
if (StrUpper(SubStr(p[5], 2, 1) = "L"))
return format_v("{1} := SubStr(SubStr({2}, 1, {3}), -{4})", p)
else
{
out := format_v("if (SubStr({5}, 1, 1) = `"L`")", p) . "`r`n"
out .= format_v(" {1} := SubStr(SubStr({2}, 1, {3}), -{4})", p) . "`r`n"
out .= format_v("else", p) . "`r`n"
out .= format_v(" {1} := SubStr({2}, {3}, {4})", p)
return out
}
}
}
_StrReplace(p)
{
; v1
; StringReplace, OutputVar, InputVar, SearchText [, ReplaceText, ReplaceAll?]
; v2 obsolete
; StrReplace, OutputVar, Haystack, SearchText [, ReplaceText, OutputVarCount, Limit = -1]
; v2
; OutputVar := StrReplace(Haystack, SearchText , ReplaceText, OutputVarCount, Limit := -1)
if IsEmpty(p[4]) && IsEmpty(p[5])
return format_v("{1} := StrReplace({2}, {3},,, 1)", p)
else if IsEmpty(p[5])
return format_v("{1} := StrReplace({2}, {3}, {4},, 1)", p)
else
{
p5char1 := SubStr(p[5], 1, 1)
; MsgBox(p[5] "`n" p5char1)
if (p[5] = "UseErrorLevel") ; UseErrorLevel also implies ReplaceAll
return format_v("{1} := StrReplace({2}, {3}, {4}, ErrorLevel)", p)
else if (p5char1 = "1") || (StrUpper(p5char1) = "A")
; if the first char of the ReplaceAll param starts with '1' or 'A'
; then all of those imply 'replace all'
; https://github.com/Lexikos/AutoHotkey_L/blob/master/source/script2.cpp#L7033
return format_v("{1} := StrReplace({2}, {3}, {4})", p)
}
}
; =============================================================================
format_v(f, v)
{
local out, arg, i, j, s, m, key, buf, c, type, p, O_
out := "" ; To make #Warn happy.
VarSetStrCapacity(&arg, 8), j := 1, VarSetStrCapacity(&s, StrLen(f)*2.4) ; Arbitrary estimate (120% * size of Unicode char).
;~ O_ := A_AhkVersion >= "2" ? "" : "O)" ; Seems useful enough to support v1.
O_ := "" ; Always run with V2 not compatible anymore with V1
while i := RegExMatch(f, O_ "\{((\w+)(?::([^*`%{}]*([scCdiouxXeEfgGaAp])))?|[{}])\}", &m, j) ; For each {placeholder}.
{
out .= SubStr(f, j, i-j) ; Append the delimiting literal text.
j := i + m.Len[0] ; Calculate next search pos.
if (m.1 = "{" || m.1 = "}") { ; {{} or {}}.
out .= m.2
continue
}
key := (Type(m.2) = "String") ? m.2 : m.2+0 ; +0 to convert to pure number.
if !v.HasKey(key) {
out .= m.0 ; Append original {} string to show the error.
continue
}
if m.3 = "" {
out .= v[key] ; No format specifier, so just output the value.
;if InStr(out, "var")
; msgbox, %out%
continue
}
if (type := m.4) = "s"
NumPut("UPtr", (p := v.GetAddress(key)) ? p : &(s := v[key] ""), arg)
else if InStr("cdioux", type) ; Integer types.
NumPut("UPtr", v[key], arg, "int64") ; 64-bit in case of something like {1:I64i}.
else if InStr("efga", type) ; Floating-point types.
NumPut("UPtr", v[key], arg, "double")
else if (type = "p") ; Pointer type.
NumPut("UPtr", v[key], arg)
else { ; Note that this doesn't catch errors like "{1:si}".
out .= m.0 ; Output m unaltered to show the error.
continue
}
; MsgBox % "key=" key ",fmt=" m.3 ",typ=" m.4 . (m.4="s" ? ",str=" NumGet(arg) ";" (&s) : "")
if (c := DllCall("msvcrt\_vscwprintf", "wstr", "`%" m.3, "ptr", &arg, "cdecl")) >= 0 ; Determine required buffer size.
&& DllCall("msvcrt\_vsnwprintf", "wstr", &buf, "ptr", VarSetStrCapacity(&buf, ++c*2)//2, "wstr", "`%" m.3, "ptr", &arg, "cdecl") >= 0 { ; Format string into buf.
out .= buf ; Append formatted string.
continue
}
}
out .= SubStr(f, j) ; Append remainder of format string.
return out
}
IsFunc(FunctionName){
Try{
return %FunctionName%.MaxParams
}
Catch{
return 0
}
return
}