This is a script for converting AutoHotkey v1 scripts to AutoHotkey v2 scripts. There are quite a few changes mainly based around the transition from traditional to expression syntax. Although at the moment `= is allowed in place of the past = for assignment, it may not be supported at some point. For this reason the converter will always change = assignment to :=.
Also, I don't know where style is going from here, or a number of possible changes that may be made (ex. deref characters). This script and its output may change greatly overtime if there is demand to keep it up.
I went for a simple approach to the conversion. I'm sure there are better, or more exact ways to convert scripts. Please let me know if you have ideas on how to improve it.
This is not complete even for the changes made thus far, so if anyone needs features I will add them on request.
Here is the main code. It runs on AHKv2 Alpha and needs format.ahk which Lexikos put in the Lib folder of the zip. To use:
[*:3hgzhp00]Run the script [*:3hgzhp00]Chose the script to convert [*:3hgzhp00]The new script will be in the same folder with "New" after the file name [*:3hgzhp00]Enjoy!
; ============================================================================= ; Script Converter ; for converting scripts from v1 AutoHotkey to v2 ; Use: ; Run the script ; Chose the file you want to convert in the file select dialog ; A msgbox will popup telling you the script finished converting ; If you gave the file MyScript.ahk, the output file will be MyScriptNew.ahk ; Thats it, feel free to add to it and post changes here: http://www.autohotkey.com/forum/viewtopic.php?t=70266 ; Uses format.ahk ; ============================================================================= Remove `= ( #AllowSameLineComments #MaxMem SoundGetWaveVolume SoundSetWaveVolume #NoEnv #Delimiter SetFormat A_FormatInteger A_FormatFloat ) Convert `= ( EnvAdd,InputVar,Value,TimeUnits | *EnvAdd EnvDiv,InputVar,Value | {1} /= {2} EnvMult,InputVar,Valut | {1} *= {2} EnvSub,InputVar,Value,TimeUnits | {1} -= {2}[, {3}] IfEqual,InputVar,value | If {1} = {2} IfNotEqual,InputVar,value | If {1} != {2} IfGreater,InputVar,value | If {1} > {2} IfGreaterOrEqual,InputVar,value | If {1} >= {2} IfLess,InputVar,value | If {1} < {2} IfLessOrEqual,InputVar,value | If {1} <= {2} StringLen,OutputVar,InputVar | {1} := StrLen({2}) StringGetPos,OutputVar,InputVar,SearchText,Side, Offset | {1} := InStr({2}, {3}[][, false, {5}]) StringMid,OutputVar,InputVar,StartChar,Count,L | {1} := SubStr({2}, {3}[, {4}][]) StringLeft,OutputVar,InputVar,Count | {1} := SubStr({2}, 1, {3}) StringRight,OutputVar,InputVar,Count | {1} := SubStr({2}, -{3}+1, {3}) StringTrimLeft,OutputVar,InputVar,Count | {1} := SubStr({2}, 1, -{3}) StringTrimRight,OutputVar,InputVar,Count | {1} := SubStr({2}, {3}+1) WinGetActiveStats,TitleVar,WidthVar,HeightVar,XVar,YVar | *ActiveStats WinGetActiveTitle,OutputVar | WinGetTitle, {1}, A DriveSpaceFree,OutputVar,PathVar | DriveGet, {1}, SpaceFree, {2} ) Directives `= (Join`r`n #Warn UseUnsetLocal #Warn UseUnsetGlobal ) SubStrFunction `= (Join`r`n ; This function may be removed if StartingPos is always > 0. CheckStartingPos(p) { return p - (p <= 0) } ) ; ============================================================================= ; Main Part of program ; Many changes can be made without altering this ; ============================================================================= if !Args { FileSelectFile, FN,, %A_MyDocuments% If !FN ExitApp FNOut := SubStr(FN, 1, StrLen(FN)-4) . "_new.ahk" } else If Args.MaxIndex() = 1 ; Allow a command line param for the file name ex. Run Convert.ahk "MyInputFile.ahk" { FN := Trim(Args[1]) FNOut := SubStr(FN, 1, StrLen(FN)-4) . "_new.ahk" } else if Mod(Args.MaxIndex(), 2) = 0 ; Parse arguments with linux like syntax, ex. Run Convert.ahk --input "Inputfile.ahk" -o "OutputFile.ahk" { for i, P in Args { If Mod(i,2) ; Odd parameter, identifier { If (P = "-o") || (P = "--output") Mode := 1 else If (P = "-i") || (P = "--input") Mode := 2 else Mode := 0 } else if Mode != 0 { If Mode = 1 FNOut := Trim(P) else if Mode = 2 FN := Trim(P) } } } If !FN { Msgbox, 48, Conversion Error, The commandline parameters passed are invalid. Please make sure they are correct and try again. Now exiting. ExitApp } If !FNOut FNOut := SubStr(FN, 1, StrLen(FN)-4) . "_new.ahk" Output := FileOpen(FNOut, "w") Loop, Read, %FN% { Skip := false Line := A_LoopReadLine FirstChar := SubStr( Trim(Line), 1, 1 ) FirstTwo := SubStr(LTrim(Line), 1, 2) CommandMatch := -1 If (Trim(Line) == "") || ( FirstChar == ";" ) { ; Do nothing, but we still want to add the line to the output file } else if FirstTwo == "/*" InCommentBlock := true else if FirstTwo == "*/" InCommentBlock := false else if InCommentBlock { ; Do nothing, but skip all the following } else If InStr(Line, "SendMode") && InStr(Line, "Input") Skip := true else if ( FirstChar == "(" ) { If RegExMatch(Line, "i)join(.+?)(LTrim|RTrim|Comment|%|,|``)?", Join) JoinBy := Join1 else JoinBy := "``n" Cont := 1 If InStr(LastLine, ":= """"") { Output.Seek(-4, 1) ; Remove the newline characters and double quotes } else { Output.Seek(-2, 1) Output.Write(" % ") } continue ; Don't add to the output file } else if ( FirstChar == ")" ) { Cont := 0 continue } else if Cont { Line := ToExp(Line . JoinBy) If Cont > 1 Line := ". " . Line Cont++ } ; Replace = with := expression equivilents else If RegExMatch(Line, "i)^([\s]*[a-z_][a-z_0-9]*[\s]*)=([^;]*)", Equation) ; Thanks Lexikos Line := RTrim(Equation1) . " := " . ToExp(Equation2) else If RegExMatch(Line, "i)^(\s*if\s+[a-z_][a-z_0-9]*[\s]*)=([^{;]*)(\s*{?)", Equation) Line := format_v("{variable} = {equation}{otb}", {variable: RTrim(Equation1), equation: ToExp(Equation2), otb: Equation3} ) else ; Command replacing ; To add commands to be checked for, modify the list at the top of this file { CommandMatch := 0 Line := RegExReplace(Line, ",\s+", ",") FirstDelim := RegExMatch(Line, "[,\s]") Command := Trim( SubStr(Line, 1, FirstDelim-1) ) Params := SubStr(Line, FirstDelim+1) ; Now we format the parameters into their v2 equivilents Loop, Parse, Convert, `n { StringSplit, Part, A_LoopField, | ListDelim := RegExMatch(Part1, "[,\s]") ListCommand := Trim( SubStr(Part1, 1, ListDelim-1) ) If (ListCommand = Command) { CommandMatch := 1 ListParams := RTrim( SubStr(Part1, ListDelim+1) ) ListParam := Array() Param := Array() ; Parameters in expression form Loop, Parse, ListParams, `, ListParam[A_Index] := A_LoopField Loop, Parse, Params, `, If InStr(ListParam[A_Index], "var") Param[A_Index] := A_LoopField else Param[A_Index] := ToExp(A_LoopField) Part2 := Trim(Part2) If ( SubStr(Part2, 1, 1) == "*" ) { FuncName := SubStr(Part2, 2) If IsFunc(FuncName) Line := %FuncName%(Param) } else { If ParamDif := (ListParam.MaxIndex() - Param.MaxIndex() ) ; Remove all unused optional parameters Part2 := RegExReplace(Part2, "\[[^\]]*\]", "", Count, ParamDif, 1) StringReplace, Part2, Part2, [,, All StringReplace, Part2, Part2, ],, All Line := format_v(Part2, Param) } } } } ; Remove lines we can't use If CommandMatch = 0 && !InCommentBlock Loop, Parse, Remove, `n, `r If InStr(A_LoopReadLine, A_LoopField) Skip := true ; TEMPORARY If !FoundSubStr && !InCommentBlock && InStr(Line, "SubStr") { FoundSubStr := true Line .= " `; WARNING: SubStr conversion may change in the near future" } ; Put the directives after the first non-comment line If !FoundNonComment && !InCommentBlock && A_Index != 1 && FirstChar != ";" && FirstTwo != "*/" { Output.Write(Directives . "`r`n") FoundNonComment := true } If Skip Line := format_v("; REMOVED: {line}", {line: Line}) Output.Write(Line . "`r`n") LastLine := Line } ; The following will be uncommented at a a later time ;If FoundSubStr ; Output.Write(SubStrFunction) Output.Close() If !Args.MaxIndex() MsgBox, Done! ExitApp ; ============================================================================= ; 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 Text := Trim(Text, " `t") If Text = "" TOut := (qu . qu) ; Two double quotes else if InStr(Text, "%") { TOut := "" Loop % StrLen(Text) { Symbol := Chr(NumGet(Text, (A_Index-1)*2, "UChar")) 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" { TOut := Text+0 } else { StringReplace, TOut, Text, % qu, % qu . qu, All TOut := qu . TOut . qu } return (TOut) } ; ============================================================================= ; 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 ; ============================================================================= ActiveStats(p) { If p[1] Out .= format_v("WinGetTitle, {1}, A", p) Count := p.MaxIndex() loop 5 p[A_Index] := ( p[A_Index] ? " " . p[A_Index] : "" ) if Count > 1 ; Width and/or Height and/or X and/or Y but not Title Out .= (p[1] ? "`r`n" : "") . format_v("WinGetPos{2},{3},{4},{5}, A", p) return Out } EnvAdd(p) { If p[3] return format_v("{1} := DateAdd({1}, {2}, {3})", p) else return format_v("{1} += {2}", p) }
Click here to see an example conversion